LCOV - code coverage report
Current view: top level - refarray - ref_array.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 151 193 78.2 %
Date: 2014-04-01 Functions: 14 15 93.3 %

          Line data    Source code
       1             : /*
       2             :     REF ARRAY
       3             : 
       4             :     Implementation of the dynamic array with reference count.
       5             : 
       6             :     Copyright (C) Dmitri Pal <dpal@redhat.com> 2009
       7             : 
       8             :     This program is free software; you can redistribute it and/or modify
       9             :     it under the terms of the GNU Lesser General Public License as published by
      10             :     the Free Software Foundation; either version 3 of the License, or
      11             :     (at your option) any later version.
      12             :     This program is distributed in the hope that it will be useful,
      13             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      15             :     GNU General Public License for more details.
      16             :     You should have received a copy of the GNU Lesser General Public License
      17             :     along with this program.  If not, see <http://www.gnu.org/licenses/>.
      18             : */
      19             : 
      20             : #include "config.h"
      21             : #include <errno.h>  /* for errors */
      22             : #include <stdint.h>
      23             : #include <malloc.h>
      24             : #include <string.h>
      25             : #include <stdio.h>
      26             : 
      27             : #include "ref_array.h"
      28             : #include "trace.h"
      29             : 
      30             : /* The structure used in referenced array */
      31             : struct ref_array {
      32             :     void *storage;      /* The storage buffer */
      33             :     size_t elsize;      /* Size of one element in the buffer */
      34             :     uint32_t size;      /* Size of the storage in items */
      35             :     uint32_t grow_by;   /* What increment use to reallocate memory */
      36             :     uint32_t len;       /* Number of the elements in the array */
      37             :     uint32_t refcount;  /* Reference count */
      38             :     ref_array_fn cb;    /* Cleanup callback */
      39             :     void *cb_data;      /* Caller's callback data */
      40             : };
      41             : 
      42             : /****************************************************/
      43             : /* INTERNAL FUNCTIONS                               */
      44             : /****************************************************/
      45     1052555 : static int ref_array_grow(struct ref_array *ra)
      46             : {
      47     1052555 :     int error = EOK;
      48     1052555 :     void *newbuf = NULL;
      49             : 
      50             :     TRACE_FLOW_ENTRY();
      51             : 
      52             :     TRACE_INFO_NUMBER("Current length: ", ra->len);
      53             :     TRACE_INFO_NUMBER("Current size: ", ra->size);
      54             : 
      55             :     /* Grow buffer if needed */
      56     1052555 :     newbuf = realloc(ra->storage, (ra->size + ra->grow_by) * ra->elsize);
      57     1052555 :     if (newbuf == NULL) {
      58             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
      59           0 :         return ENOMEM;
      60             :     }
      61             : 
      62     1052555 :     ra->storage = newbuf;
      63     1052555 :     ra->size += ra->grow_by;
      64             : 
      65             :     TRACE_INFO_NUMBER("Final size: ", ra->size);
      66             :     TRACE_FLOW_RETURN(error);
      67     1052555 :     return error;
      68             : 
      69             : }
      70             : 
      71             : 
      72             : /****************************************************/
      73             : /* PUBLIC FUNCTIONS                                 */
      74             : /****************************************************/
      75             : 
      76             : /* Create referenced array */
      77      300248 : int ref_array_create(struct ref_array **ra,
      78             :                      size_t elemsz,
      79             :                      uint32_t grow_by,
      80             :                      ref_array_fn cb,
      81             :                      void *data)
      82             : {
      83      300248 :     struct ref_array *new_ra = NULL;
      84             : 
      85             :     TRACE_FLOW_ENTRY();
      86             : 
      87      300248 :     if (!ra) {
      88             :         TRACE_ERROR_NUMBER("Uninitialized argument.", EINVAL);
      89           0 :         return EINVAL;
      90             :     }
      91             : 
      92      300248 :     if ((!elemsz) || (!grow_by)) {
      93             :         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
      94           0 :         return EINVAL;
      95             :     }
      96             : 
      97      300248 :     new_ra = (struct ref_array *)malloc(sizeof(struct ref_array));
      98             : 
      99      300248 :     if (!new_ra) {
     100             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     101           0 :         return ENOMEM;
     102             :     }
     103             : 
     104      300248 :     new_ra->storage = NULL;
     105      300248 :     new_ra->elsize = elemsz;
     106      300248 :     new_ra->size = 0;
     107      300248 :     new_ra->grow_by = grow_by;
     108      300248 :     new_ra->len = 0;
     109      300248 :     new_ra->refcount = 1;
     110      300248 :     new_ra->cb = cb;
     111      300248 :     new_ra->cb_data = data;
     112             : 
     113      300248 :     *ra = new_ra;
     114             : 
     115             :     TRACE_FLOW_EXIT();
     116      300248 :     return EOK;
     117             : }
     118             : 
     119             : /* Get new reference to an array */
     120           1 : struct ref_array *ref_array_getref(struct ref_array *ra)
     121             : {
     122             :     TRACE_FLOW_ENTRY();
     123             : 
     124             :     /* Check if array is not NULL */
     125           1 :     if (ra) {
     126             :         TRACE_INFO_NUMBER("Increasing reference count. Current: ", ra->refcount);
     127             :         /* Increase reference count */
     128           1 :         ra->refcount++;
     129             :         TRACE_INFO_NUMBER("Increased reference count. New: ", ra->refcount);
     130             : 
     131             :     }
     132             :     else {
     133             :         TRACE_ERROR_STRING("Uninitialized array.", "Returning NULL");
     134             :     }
     135             : 
     136             :     TRACE_FLOW_EXIT();
     137           1 :     return ra;
     138             : }
     139             : 
     140             : /* Delete the array */
     141      331892 : void ref_array_destroy(struct ref_array *ra)
     142             : {
     143             :     int idx;
     144             : 
     145             :     TRACE_FLOW_ENTRY();
     146             : 
     147             :     /* Check if array is not NULL */
     148      331892 :     if (!ra) {
     149             :         TRACE_INFO_STRING("Uninitialized array.", "Might be Ok...");
     150      332384 :         return;
     151             :     }
     152             : 
     153             :     TRACE_INFO_NUMBER("Current reference count: ", ra->refcount);
     154      331400 :     if (ra->refcount) {
     155             :         /* Decrease reference count */
     156      331400 :         ra->refcount--;
     157      331400 :         if (ra->refcount == 0) {
     158             :             TRACE_INFO_NUMBER("It is time to delete array. Count:", ra->refcount);
     159      331399 :             if (ra->cb) {
     160      941506 :                 for (idx = 0; idx < ra->len; idx++) {
     161      744391 :                     ra->cb((unsigned char *)(ra->storage) + idx * ra->elsize,
     162             :                             REF_ARRAY_DESTROY, ra->cb_data);
     163             :                 }
     164             :             }
     165      331399 :             free(ra->storage);
     166      331399 :             free(ra);
     167             :         }
     168             :     }
     169             :     else {
     170             :         /* Should never be here...
     171             :          * This can happen if the caller by mistake would try to
     172             :          * destroy the object from within the callback. Brrr....
     173             :          */
     174             :         TRACE_ERROR_STRING("Reference count is 0.", "Coding error???");
     175             :     }
     176             : 
     177             :     TRACE_FLOW_EXIT();
     178             : }
     179             : 
     180             : /* Add new element to the array */
     181     1794802 : int ref_array_append(struct ref_array *ra, void *element)
     182             : {
     183     1794802 :     int error = EOK;
     184             : 
     185             :     TRACE_FLOW_ENTRY();
     186             : 
     187     1794802 :     if ((!ra) || (!element)) {
     188             :         TRACE_ERROR_NUMBER("Uninitialized argument.", EINVAL);
     189           0 :         return EINVAL;
     190             :     }
     191             : 
     192             :     /* Do we have enough room for a new element? */
     193     1794802 :     if (ra->size == ra->len) {
     194     1052540 :         error = ref_array_grow(ra);
     195     1052540 :         if (error) {
     196             :             TRACE_ERROR_NUMBER("Failed to grow array.", error);
     197           0 :             return error;
     198             :         }
     199             :     }
     200             : 
     201             :     /* Copy element */
     202     1794802 :     memcpy((unsigned char *)(ra->storage) + ra->len * ra->elsize,
     203             :            element,
     204             :            ra->elsize);
     205             : 
     206     1794802 :     ra->len++;
     207             : 
     208             :     TRACE_INFO_NUMBER("Length after append: ", ra->len);
     209             : 
     210             :     TRACE_FLOW_EXIT();
     211     1794802 :     return error;
     212             : }
     213             : 
     214             : /* Get element */
     215     1593574 : void *ref_array_get(struct ref_array *ra, uint32_t idx, void *acptr)
     216             : {
     217             :     TRACE_FLOW_ENTRY();
     218             : 
     219     1593574 :     if (!ra) {
     220             :         TRACE_ERROR_STRING("Uninitialized argument.", "");
     221           0 :         return NULL;
     222             :     }
     223             : 
     224     1593574 :     if (idx >= ra->len) {
     225             :         TRACE_INFO_NUMBER("Invalid idx.", idx);
     226       67760 :         return NULL;
     227             :     }
     228             : 
     229             :     TRACE_INFO_NUMBER("Index: ", idx);
     230             : 
     231     1525814 :     if (acptr) {
     232             : 
     233             :         TRACE_INFO_STRING("Copying data.", "");
     234     2338320 :         memcpy(acptr,
     235     1558880 :                (unsigned char *)(ra->storage) + idx * ra->elsize,
     236             :                ra->elsize);
     237             : 
     238             :     }
     239             : 
     240             :     TRACE_FLOW_EXIT();
     241     1525814 :     return (unsigned char *)(ra->storage) + idx * ra->elsize;
     242             : }
     243             : 
     244             : 
     245             : /* Get length */
     246       31283 : int ref_array_getlen(struct ref_array *ra, uint32_t *len)
     247             : {
     248             :     TRACE_FLOW_ENTRY();
     249             : 
     250       31283 :     if ((!ra) || (!len)) {
     251             :         TRACE_ERROR_STRING("Uninitialized argument.", "");
     252           0 :         return EINVAL;
     253             :     }
     254             : 
     255       31283 :     *len = ra->len;
     256             : 
     257             :     TRACE_FLOW_EXIT();
     258       31283 :     return EOK;
     259             : }
     260             : 
     261             : /* Alternative function to get length */
     262      250649 : uint32_t ref_array_len(struct ref_array *ra)
     263             : {
     264             :     TRACE_FLOW_ENTRY();
     265             : 
     266      250649 :     if (!ra) {
     267             :         TRACE_ERROR_STRING("Uninitialized argument.", "");
     268           0 :         errno = EINVAL;
     269           0 :         return 0;
     270             :     }
     271             : 
     272             :     TRACE_FLOW_EXIT();
     273      250649 :     return ra->len;
     274             : }
     275             : 
     276             : 
     277             : /* Insert a new element into the array */
     278          18 : int ref_array_insert(struct ref_array *ra,
     279             :                      uint32_t idx,
     280             :                      void *element)
     281             : {
     282          18 :     int error = EOK;
     283             :     uint32_t i;
     284             : 
     285             :     TRACE_FLOW_ENTRY();
     286             : 
     287          18 :     if ((!ra) || (!element)) {
     288             :         TRACE_ERROR_NUMBER("Uninitialized argument.", EINVAL);
     289           0 :         return EINVAL;
     290             :     }
     291             : 
     292          18 :     if (idx > ra->len) {
     293             :         TRACE_ERROR_NUMBER("Index is out of range", ERANGE);
     294           1 :         return ERANGE;
     295             :     }
     296             : 
     297             :     /* Do we have enough room for a new element? */
     298          17 :     if (ra->size == ra->len) {
     299          15 :         error = ref_array_grow(ra);
     300          15 :         if (error) {
     301             :             TRACE_ERROR_NUMBER("Failed to grow array.", error);
     302           0 :             return error;
     303             :         }
     304             :     }
     305             : 
     306             :     /* Shift elements right */
     307          52 :     for (i = ra->len; i >= (idx + 1); i--) {
     308         105 :         memcpy((unsigned char *)(ra->storage) + i * ra->elsize,
     309          70 :                (unsigned char *)(ra->storage) + (i - 1) * ra->elsize,
     310             :                ra->elsize);
     311             :     }
     312             : 
     313             :     /* Overwrite element */
     314          17 :     memcpy((unsigned char *)(ra->storage) + idx * ra->elsize,
     315             :            element,
     316             :            ra->elsize);
     317             : 
     318          17 :     ra->len++;
     319             : 
     320             :     TRACE_FLOW_EXIT();
     321          17 :     return error;
     322             : 
     323             : }
     324             : 
     325             : 
     326             : /* Replace element in the array */
     327         150 : int ref_array_replace(struct ref_array *ra,
     328             :                       uint32_t idx,
     329             :                       void *element)
     330             : {
     331         150 :     int error = EOK;
     332             : 
     333             :     TRACE_FLOW_ENTRY();
     334             : 
     335         150 :     if ((!ra) || (!element)) {
     336             :         TRACE_ERROR_NUMBER("Uninitialized argument.", EINVAL);
     337           0 :         return EINVAL;
     338             :     }
     339             : 
     340         150 :     if (idx > ra->len) {
     341             :         TRACE_ERROR_NUMBER("Index is out of range", ERANGE);
     342           1 :         return ERANGE;
     343             :     }
     344             : 
     345             :     /* Clear old element */
     346         149 :     if (ra->cb)
     347          92 :         ra->cb((unsigned char *)(ra->storage) + idx * ra->elsize,
     348             :                REF_ARRAY_DELETE, ra->cb_data);
     349             : 
     350             :     /* Overwrite element */
     351         149 :     memcpy((unsigned char *)(ra->storage) + idx * ra->elsize,
     352             :            element,
     353             :            ra->elsize);
     354             : 
     355             : 
     356             :     TRACE_FLOW_EXIT();
     357         149 :     return error;
     358             : }
     359             : 
     360             : 
     361             : /* Remove element from the array */
     362           7 : int ref_array_remove(struct ref_array *ra,
     363             :                      uint32_t idx)
     364             : {
     365           7 :     int error = EOK;
     366             :     uint32_t i;
     367             : 
     368             :     TRACE_FLOW_ENTRY();
     369             : 
     370           7 :     if (!ra) {
     371             :         TRACE_ERROR_NUMBER("Uninitialized argument.", EINVAL);
     372           0 :         return EINVAL;
     373             :     }
     374             : 
     375           7 :     if (idx >= ra->len) {
     376             :         TRACE_ERROR_NUMBER("Index is out of range", ERANGE);
     377           1 :         return ERANGE;
     378             :     }
     379             : 
     380             :     /* Clear old element */
     381           6 :     if (ra->cb)
     382           6 :         ra->cb((unsigned char *)(ra->storage) + idx * ra->elsize,
     383             :                REF_ARRAY_DELETE, ra->cb_data);
     384             : 
     385             :     /* Shift elements left */
     386          36 :     for (i = idx + 1; i < ra->len; i++) {
     387          90 :         memcpy((unsigned char *)(ra->storage) + (i - 1) * ra->elsize,
     388          60 :                (unsigned char *)(ra->storage) +  i * ra->elsize,
     389             :                ra->elsize);
     390             :     }
     391             : 
     392           6 :     ra->len--;
     393             : 
     394             :     TRACE_FLOW_EXIT();
     395           6 :     return error;
     396             : }
     397             : 
     398             : /* Reset array */
     399      264715 : void ref_array_reset(struct ref_array *ra)
     400             : {
     401             :     int idx;
     402             : 
     403             :     TRACE_FLOW_ENTRY();
     404             : 
     405             :     /* Check if array is not NULL */
     406      264715 :     if (!ra) {
     407             :         TRACE_ERROR_STRING("Uninitialized array.", "Coding error???");
     408      264715 :         return;
     409             :     }
     410             : 
     411      264715 :     if (ra->cb) {
     412      334333 :         for (idx = 0; idx < ra->len; idx++) {
     413      201975 :             ra->cb((unsigned char *)(ra->storage) + idx * ra->elsize,
     414             :                     REF_ARRAY_DESTROY, ra->cb_data);
     415             :         }
     416             :     }
     417             : 
     418      264715 :     free(ra->storage);
     419      264715 :     ra->storage = NULL;
     420      264715 :     ra->size = 0;
     421      264715 :     ra->len = 0;
     422             : 
     423             :     TRACE_FLOW_EXIT();
     424             : }
     425             : 
     426             : /* Swap two elements in the array */
     427           7 : int ref_array_swap(struct ref_array *ra,
     428             :                    uint32_t idx1,
     429             :                    uint32_t idx2)
     430             : {
     431           7 :     int error = EOK;
     432           7 :     void *temp = NULL;
     433             : 
     434             :     TRACE_FLOW_ENTRY();
     435             : 
     436           7 :     if (!ra) {
     437             :         TRACE_ERROR_NUMBER("Uninitialized argument.", EINVAL);
     438           0 :         return EINVAL;
     439             :     }
     440             : 
     441          14 :     if ((idx1 >= ra->len) ||
     442           7 :         (idx2 >= ra->len)) {
     443             :         TRACE_ERROR_NUMBER("Index is out of range", ERANGE);
     444           0 :         return ERANGE;
     445             :     }
     446             : 
     447           7 :     if (idx1 == idx2) {
     448             :         TRACE_FLOW_STRING("ref_array_swap", "Noop return");
     449           0 :         return EOK;
     450             :     }
     451             : 
     452           7 :     temp = malloc(ra->elsize);
     453           7 :     if (!temp) {
     454             :         TRACE_FLOW_STRING("Failed to allocate memory for temp storage.", "");
     455           0 :         return ENOMEM;
     456             :     }
     457             : 
     458          21 :     memcpy(temp,
     459          14 :            (unsigned char *)(ra->storage) +  idx2 * ra->elsize,
     460             :            ra->elsize);
     461          21 :     memcpy((unsigned char *)(ra->storage) +  idx2 * ra->elsize,
     462          14 :            (unsigned char *)(ra->storage) +  idx1 * ra->elsize,
     463             :            ra->elsize);
     464           7 :     memcpy((unsigned char *)(ra->storage) +  idx1 * ra->elsize,
     465             :            temp,
     466             :            ra->elsize);
     467             : 
     468           7 :     free(temp);
     469             : 
     470             :     TRACE_FLOW_EXIT();
     471           7 :     return error;
     472             : }
     473             : 
     474             : /* Copy array */
     475       31151 : int ref_array_copy(struct ref_array *ra,
     476             :                    ref_array_copy_cb copy_cb,
     477             :                    ref_array_fn cb,
     478             :                    void *data,
     479             :                    struct ref_array **copy_ra)
     480             : {
     481       31151 :     int error = EOK;
     482             :     int idx;
     483       31151 :     struct ref_array *new_ra = NULL;
     484             :     void *src;
     485             :     void *dst;
     486             : 
     487             :     TRACE_FLOW_ENTRY();
     488             : 
     489             :     /* Check if array is not NULL */
     490       31151 :     if ((!ra) || (!copy_ra)) {
     491             :         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
     492           0 :         return EINVAL;
     493             :     }
     494             : 
     495       31151 :     new_ra = (struct ref_array *)malloc(sizeof(struct ref_array));
     496       31151 :     if (!new_ra) {
     497             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     498           0 :         return ENOMEM;
     499             :     }
     500             : 
     501       31151 :     new_ra->storage = calloc(ra->size, ra->elsize);
     502       31151 :     if (!(new_ra->storage)) {
     503             :         TRACE_ERROR_NUMBER("Failed to allocate memory.", ENOMEM);
     504           0 :         free(new_ra);
     505           0 :         return ENOMEM;
     506             :     }
     507             : 
     508       31151 :     new_ra->elsize = ra->elsize;
     509       31151 :     new_ra->size = ra->size;
     510       31151 :     new_ra->grow_by = ra->grow_by;
     511       31151 :     new_ra->len = 0;
     512       31151 :     new_ra->refcount = 1;
     513       31151 :     new_ra->cb = cb;
     514       31151 :     new_ra->cb_data = data;
     515             : 
     516       63480 :     for (idx = 0; idx < ra->len; idx++) {
     517       32329 :         if (copy_cb) {
     518       32324 :             src = (void *)((unsigned char *)(ra->storage) + idx * ra->elsize);
     519       64648 :             dst = (void *)((unsigned char *)(new_ra->storage) +
     520       32324 :                                              idx * new_ra->elsize);
     521             : 
     522       32324 :             error = copy_cb(src, (void *)(dst));
     523       32324 :             if (error) {
     524             :                 TRACE_ERROR_NUMBER("Failed to copy data.", error);
     525           0 :                 ref_array_destroy(new_ra);
     526           0 :                 return error;
     527             :             }
     528             :         }
     529             :         else {
     530          15 :             memcpy((unsigned char *)(new_ra->storage) + idx * new_ra->elsize,
     531          10 :                    (unsigned char *)(ra->storage) + idx * ra->elsize,
     532             :                    new_ra->elsize);
     533             :         }
     534       32329 :         (new_ra->len)++;
     535             :     }
     536             : 
     537             : 
     538       31151 :     *copy_ra = new_ra;
     539             : 
     540             :     TRACE_FLOW_EXIT();
     541       31151 :     return error;
     542             : }
     543             : 
     544             : 
     545             : 
     546             : /* Debug function */
     547           0 : void ref_array_debug(struct ref_array *ra, int num)
     548             : {
     549             :     int i,j;
     550             : 
     551           0 :     printf("\nARRAY DUMP START\n");
     552           0 :     printf("Length = %u\n", ra->len);
     553           0 :     printf("Size = %u\n", ra->size);
     554           0 :     printf("Element = %u\n", (unsigned int)(ra->elsize));
     555           0 :     printf("Grow by = %u\n", ra->grow_by);
     556           0 :     printf("Count = %u\n", ra->refcount);
     557           0 :     printf("ARRAY:\n");
     558           0 :     for (i = 0; i < ra->len; i++)  {
     559           0 :         for (j = 0; j < ra->elsize; j++) {
     560           0 :             printf("%02x", *((unsigned char *)(ra->storage) + i * ra->elsize + j));
     561             :         }
     562           0 :         if (num == 0) {
     563           0 :             printf("\n%s\n", *((char **)((unsigned char *)(ra->storage) + i * ra->elsize)));
     564             :         }
     565           0 :         else if (num > 0) {
     566           0 :             printf("\n%d\n", *((uint32_t *)((unsigned char *)(ra->storage) + i * ra->elsize)));
     567             :         }
     568             :         else {
     569           0 :             printf("\nIt is an object.\n");
     570             :         }
     571             :     }
     572           0 :     printf("\nARRAY DUMP END\n\n");
     573           0 : }

Generated by: LCOV version 1.10