tizen 2.3.1 release
[framework/graphics/cairo.git] / src / cairo-array.c
1 /* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2 /* cairo - a vector graphics library with display and print output
3  *
4  * Copyright © 2004 Red Hat, Inc
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it either under the terms of the GNU Lesser General Public
8  * License version 2.1 as published by the Free Software Foundation
9  * (the "LGPL") or, at your option, under the terms of the Mozilla
10  * Public License Version 1.1 (the "MPL"). If you do not alter this
11  * notice, a recipient may use your version of this file under either
12  * the MPL or the LGPL.
13  *
14  * You should have received a copy of the LGPL along with this library
15  * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17  * You should have received a copy of the MPL along with this library
18  * in the file COPYING-MPL-1.1
19  *
20  * The contents of this file are subject to the Mozilla Public License
21  * Version 1.1 (the "License"); you may not use this file except in
22  * compliance with the License. You may obtain a copy of the License at
23  * http://www.mozilla.org/MPL/
24  *
25  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26  * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27  * the specific language governing rights and limitations.
28  *
29  * The Original Code is the cairo graphics library.
30  *
31  * The Initial Developer of the Original Code is University of Southern
32  * California.
33  *
34  * Contributor(s):
35  *      Kristian Høgsberg <krh@redhat.com>
36  *      Carl Worth <cworth@cworth.org>
37  */
38
39 #include "cairoint.h"
40 #include "cairo-array-private.h"
41 #include "cairo-error-private.h"
42
43 /**
44  * _cairo_array_init:
45  *
46  * Initialize a new #cairo_array_t object to store objects each of size
47  * @element_size.
48  *
49  * The #cairo_array_t object provides grow-by-doubling storage. It
50  * never interprets the data passed to it, nor does it provide any
51  * sort of callback mechanism for freeing resources held onto by
52  * stored objects.
53  *
54  * When finished using the array, _cairo_array_fini() should be
55  * called to free resources allocated during use of the array.
56  **/
57 void
58 _cairo_array_init (cairo_array_t *array, unsigned int element_size)
59 {
60     array->size = 0;
61     array->num_elements = 0;
62     array->element_size = element_size;
63     array->elements = NULL;
64 }
65
66 /**
67  * _cairo_array_fini:
68  * @array: A #cairo_array_t
69  *
70  * Free all resources associated with @array. After this call, @array
71  * should not be used again without a subsequent call to
72  * _cairo_array_init() again first.
73  **/
74 void
75 _cairo_array_fini (cairo_array_t *array)
76 {
77     free (array->elements);
78 }
79
80 /**
81  * _cairo_array_grow_by:
82  * @array: a #cairo_array_t
83  *
84  * Increase the size of @array (if needed) so that there are at least
85  * @additional free spaces in the array. The actual size of the array
86  * is always increased by doubling as many times as necessary.
87  **/
88 cairo_status_t
89 _cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
90 {
91     char *new_elements;
92     unsigned int old_size = array->size;
93     unsigned int required_size = array->num_elements + additional;
94     unsigned int new_size;
95
96     /* check for integer overflow */
97     if (required_size > INT_MAX || required_size < array->num_elements)
98         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
99
100     if (CAIRO_INJECT_FAULT ())
101         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
102
103     if (required_size <= old_size)
104         return CAIRO_STATUS_SUCCESS;
105
106     if (old_size == 0)
107         new_size = 1;
108     else
109         new_size = old_size * 2;
110
111     while (new_size < required_size)
112         new_size = new_size * 2;
113
114     array->size = new_size;
115     new_elements = _cairo_realloc_ab (array->elements,
116                                       array->size, array->element_size);
117
118     if (unlikely (new_elements == NULL)) {
119         array->size = old_size;
120         return _cairo_error (CAIRO_STATUS_NO_MEMORY);
121     }
122
123     array->elements = new_elements;
124
125     return CAIRO_STATUS_SUCCESS;
126 }
127
128 /**
129  * _cairo_array_truncate:
130  * @array: a #cairo_array_t
131  *
132  * Truncate size of the array to @num_elements if less than the
133  * current size. No memory is actually freed. The stored objects
134  * beyond @num_elements are simply "forgotten".
135  **/
136 void
137 _cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
138 {
139     if (num_elements < array->num_elements)
140         array->num_elements = num_elements;
141 }
142
143 /**
144  * _cairo_array_index:
145  * @array: a #cairo_array_t
146  * Returns: A pointer to the object stored at @index.
147  *
148  * If the resulting value is assigned to a pointer to an object of the same
149  * element_size as initially passed to _cairo_array_init() then that
150  * pointer may be used for further direct indexing with []. For
151  * example:
152  *
153  * <informalexample><programlisting>
154  *      cairo_array_t array;
155  *      double *values;
156  *
157  *      _cairo_array_init (&array, sizeof(double));
158  *      ... calls to _cairo_array_append() here ...
159  *
160  *      values = _cairo_array_index (&array, 0);
161  *      for (i = 0; i < _cairo_array_num_elements (&array); i++)
162  *          ... use values[i] here ...
163  * </programlisting></informalexample>
164  **/
165 void *
166 _cairo_array_index (cairo_array_t *array, unsigned int index)
167 {
168     /* We allow an index of 0 for the no-elements case.
169      * This makes for cleaner calling code which will often look like:
170      *
171      *    elements = _cairo_array_index (array, 0);
172      *    for (i=0; i < num_elements; i++) {
173      *        ... use elements[i] here ...
174      *    }
175      *
176      * which in the num_elements==0 case gets the NULL pointer here,
177      * but never dereferences it.
178      */
179     if (index == 0 && array->num_elements == 0)
180         return NULL;
181
182     assert (index < array->num_elements);
183
184     return array->elements + index * array->element_size;
185 }
186
187 /**
188  * _cairo_array_index_const:
189  * @array: a #cairo_array_t
190  * Returns: A pointer to the object stored at @index.
191  *
192  * If the resulting value is assigned to a pointer to an object of the same
193  * element_size as initially passed to _cairo_array_init() then that
194  * pointer may be used for further direct indexing with []. For
195  * example:
196  *
197  * <informalexample><programlisting>
198  *      cairo_array_t array;
199  *      const double *values;
200  *
201  *      _cairo_array_init (&array, sizeof(double));
202  *      ... calls to _cairo_array_append() here ...
203  *
204  *      values = _cairo_array_index_const (&array, 0);
205  *      for (i = 0; i < _cairo_array_num_elements (&array); i++)
206  *          ... read values[i] here ...
207  * </programlisting></informalexample>
208  **/
209 const void *
210 _cairo_array_index_const (const cairo_array_t *array, unsigned int index)
211 {
212     /* We allow an index of 0 for the no-elements case.
213      * This makes for cleaner calling code which will often look like:
214      *
215      *    elements = _cairo_array_index_const (array, 0);
216      *    for (i=0; i < num_elements; i++) {
217      *        ... read elements[i] here ...
218      *    }
219      *
220      * which in the num_elements==0 case gets the NULL pointer here,
221      * but never dereferences it.
222      */
223     if (index == 0 && array->num_elements == 0)
224         return NULL;
225
226     assert (index < array->num_elements);
227
228     return array->elements + index * array->element_size;
229 }
230
231 /**
232  * _cairo_array_copy_element:
233  * @array: a #cairo_array_t
234  *
235  * Copy a single element out of the array from index @index into the
236  * location pointed to by @dst.
237  **/
238 void
239 _cairo_array_copy_element (const cairo_array_t *array,
240                            unsigned int         index,
241                            void                *dst)
242 {
243     void *src = _cairo_array_index_const (array, index);
244     if(src != NULL)
245         memcpy (dst, src, array->element_size);
246 }
247
248 /**
249  * _cairo_array_append:
250  * @array: a #cairo_array_t
251  *
252  * Append a single item onto the array by growing the array by at
253  * least one element, then copying element_size bytes from @element
254  * into the array. The address of the resulting object within the
255  * array can be determined with:
256  *
257  * _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
258  *
259  * Return value: %CAIRO_STATUS_SUCCESS if successful or
260  * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
261  * operation.
262  **/
263 cairo_status_t
264 _cairo_array_append (cairo_array_t      *array,
265                      const void         *element)
266 {
267     return _cairo_array_append_multiple (array, element, 1);
268 }
269
270 /**
271  * _cairo_array_append_multiple:
272  * @array: a #cairo_array_t
273  *
274  * Append one or more items onto the array by growing the array by
275  * @num_elements, then copying @num_elements * element_size bytes from
276  * @elements into the array.
277  *
278  * Return value: %CAIRO_STATUS_SUCCESS if successful or
279  * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
280  * operation.
281  **/
282 cairo_status_t
283 _cairo_array_append_multiple (cairo_array_t     *array,
284                               const void        *elements,
285                               unsigned int       num_elements)
286 {
287     cairo_status_t status;
288     void *dest;
289
290     status = _cairo_array_allocate (array, num_elements, &dest);
291     if (unlikely (status))
292         return status;
293
294     memcpy (dest, elements, num_elements * array->element_size);
295
296     return CAIRO_STATUS_SUCCESS;
297 }
298
299 /**
300  * _cairo_array_allocate:
301  * @array: a #cairo_array_t
302  *
303  * Allocate space at the end of the array for @num_elements additional
304  * elements, providing the address of the new memory chunk in
305  * @elements. This memory will be unitialized, but will be accounted
306  * for in the return value of _cairo_array_num_elements().
307  *
308  * Return value: %CAIRO_STATUS_SUCCESS if successful or
309  * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
310  * operation.
311  **/
312 cairo_status_t
313 _cairo_array_allocate (cairo_array_t     *array,
314                        unsigned int       num_elements,
315                        void             **elements)
316 {
317     cairo_status_t status;
318
319     status = _cairo_array_grow_by (array, num_elements);
320     if (unlikely (status))
321         return status;
322
323     assert (array->num_elements + num_elements <= array->size);
324
325     *elements = array->elements + array->num_elements * array->element_size;
326
327     array->num_elements += num_elements;
328
329     return CAIRO_STATUS_SUCCESS;
330 }
331
332 /**
333  * _cairo_array_num_elements:
334  * @array: a #cairo_array_t
335  * Returns: The number of elements stored in @array.
336  *
337  * This space was left intentionally blank, but gtk-doc filled it.
338  **/
339 unsigned int
340 _cairo_array_num_elements (const cairo_array_t *array)
341 {
342     return array->num_elements;
343 }
344
345 /**
346  * _cairo_array_size:
347  * @array: a #cairo_array_t
348  * Returns: The number of elements for which there is currently space
349  * allocated in @array.
350  *
351  * This space was left intentionally blank, but gtk-doc filled it.
352  **/
353 unsigned int
354 _cairo_array_size (const cairo_array_t *array)
355 {
356     return array->size;
357 }
358
359 /**
360  * _cairo_user_data_array_init:
361  * @array: a #cairo_user_data_array_t
362  *
363  * Initializes a #cairo_user_data_array_t structure for future
364  * use. After initialization, the array has no keys. Call
365  * _cairo_user_data_array_fini() to free any allocated memory
366  * when done using the array.
367  **/
368 void
369 _cairo_user_data_array_init (cairo_user_data_array_t *array)
370 {
371     _cairo_array_init (array, sizeof (cairo_user_data_slot_t));
372 }
373
374 /**
375  * _cairo_user_data_array_fini:
376  * @array: a #cairo_user_data_array_t
377  *
378  * Destroys all current keys in the user data array and deallocates
379  * any memory allocated for the array itself.
380  **/
381 void
382 _cairo_user_data_array_fini (cairo_user_data_array_t *array)
383 {
384     unsigned int num_slots;
385
386     num_slots = array->num_elements;
387     if (num_slots) {
388         cairo_user_data_slot_t *slots;
389
390         slots = _cairo_array_index (array, 0);
391         while (num_slots--) {
392             cairo_user_data_slot_t *s = &slots[num_slots];
393             if (s->user_data != NULL && s->destroy != NULL)
394                 s->destroy (s->user_data);
395         }
396     }
397
398     _cairo_array_fini (array);
399 }
400
401 /**
402  * _cairo_user_data_array_get_data:
403  * @array: a #cairo_user_data_array_t
404  * @key: the address of the #cairo_user_data_key_t the user data was
405  * attached to
406  *
407  * Returns user data previously attached using the specified
408  * key.  If no user data has been attached with the given key this
409  * function returns %NULL.
410  *
411  * Return value: the user data previously attached or %NULL.
412  **/
413 void *
414 _cairo_user_data_array_get_data (cairo_user_data_array_t     *array,
415                                  const cairo_user_data_key_t *key)
416 {
417     int i, num_slots;
418     cairo_user_data_slot_t *slots;
419
420     /* We allow this to support degenerate objects such as cairo_surface_nil. */
421     if (array == NULL)
422         return NULL;
423
424     num_slots = array->num_elements;
425     slots = _cairo_array_index (array, 0);
426     for (i = 0; i < num_slots; i++) {
427         if (slots[i].key == key)
428             return slots[i].user_data;
429     }
430
431     return NULL;
432 }
433
434 /**
435  * _cairo_user_data_array_set_data:
436  * @array: a #cairo_user_data_array_t
437  * @key: the address of a #cairo_user_data_key_t to attach the user data to
438  * @user_data: the user data to attach
439  * @destroy: a #cairo_destroy_func_t which will be called when the
440  * user data array is destroyed or when new user data is attached using the
441  * same key.
442  *
443  * Attaches user data to a user data array.  To remove user data,
444  * call this function with the key that was used to set it and %NULL
445  * for @data.
446  *
447  * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
448  * slot could not be allocated for the user data.
449  **/
450 cairo_status_t
451 _cairo_user_data_array_set_data (cairo_user_data_array_t     *array,
452                                  const cairo_user_data_key_t *key,
453                                  void                        *user_data,
454                                  cairo_destroy_func_t         destroy)
455 {
456     cairo_status_t status;
457     int i, num_slots;
458     cairo_user_data_slot_t *slots, *slot, new_slot;
459
460     if (user_data) {
461         new_slot.key = key;
462         new_slot.user_data = user_data;
463         new_slot.destroy = destroy;
464     } else {
465         new_slot.key = NULL;
466         new_slot.user_data = NULL;
467         new_slot.destroy = NULL;
468     }
469
470     slot = NULL;
471     num_slots = array->num_elements;
472     slots = _cairo_array_index (array, 0);
473     for (i = 0; i < num_slots; i++) {
474         if (slots[i].key == key) {
475             slot = &slots[i];
476             if (slot->destroy && slot->user_data)
477                 slot->destroy (slot->user_data);
478             break;
479         }
480         if (user_data && slots[i].user_data == NULL) {
481             slot = &slots[i];   /* Have to keep searching for an exact match */
482         }
483     }
484
485     if (slot) {
486         *slot = new_slot;
487         return CAIRO_STATUS_SUCCESS;
488     }
489
490     status = _cairo_array_append (array, &new_slot);
491     if (unlikely (status))
492         return status;
493
494     return CAIRO_STATUS_SUCCESS;
495 }
496
497 cairo_status_t
498 _cairo_user_data_array_copy (cairo_user_data_array_t    *dst,
499                              const cairo_user_data_array_t      *src)
500 {
501     /* discard any existing user-data */
502     if (dst->num_elements != 0) {
503         _cairo_user_data_array_fini (dst);
504         _cairo_user_data_array_init (dst);
505     }
506
507     return _cairo_array_append_multiple (dst,
508                                          _cairo_array_index_const (src, 0),
509                                          src->num_elements);
510 }
511
512 void
513 _cairo_user_data_array_foreach (cairo_user_data_array_t     *array,
514                                 void (*func) (const void *key,
515                                               void *elt,
516                                               void *closure),
517                                 void *closure)
518 {
519     cairo_user_data_slot_t *slots;
520     int i, num_slots;
521
522     num_slots = array->num_elements;
523     slots = _cairo_array_index (array, 0);
524     for (i = 0; i < num_slots; i++) {
525         if (slots[i].user_data != NULL)
526             func (slots[i].key, slots[i].user_data, closure);
527     }
528 }