LCOV - code coverage report
Current view: directory - gfx/cairo/cairo/src - cairo-array.c (source / functions) Found Hit Coverage
Test: app.info Lines: 145 78 53.8 %
Date: 2012-06-02 Functions: 18 10 55.6 %

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

Generated by: LCOV version 1.7