Annotation of embedaddon/strongswan/src/libstrongswan/collections/array.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (C) 2014 Tobias Brunner
                      3:  * HSR Hochschule fuer Technik Rapperswil
                      4:  *
                      5:  * Copyright (C) 2013 Martin Willi
                      6:  * Copyright (C) 2013 revosec AG
                      7:  *
                      8:  * This program is free software; you can redistribute it and/or modify it
                      9:  * under the terms of the GNU General Public License as published by the
                     10:  * Free Software Foundation; either version 2 of the License, or (at your
                     11:  * option) any later version.  See <http://www.fsf.org/copyleft/gpl.txt>.
                     12:  *
                     13:  * This program is distributed in the hope that it will be useful, but
                     14:  * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
                     15:  * or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
                     16:  * for more details.
                     17:  */
                     18: 
                     19: #define _GNU_SOURCE /* for qsort_r() */
                     20: #include <stdlib.h>
                     21: 
                     22: #include "array.h"
                     23: 
                     24: #ifndef HAVE_QSORT_R
                     25: #include <threading/thread_value.h>
                     26: #endif
                     27: 
                     28: /**
                     29:  * Data is an allocated block, with potentially unused head and tail:
                     30:  *
                     31:  *   "esize" each (or sizeof(void*) if esize = 0)
                     32:  *  /-\ /-\ /-\ /-\ /-\ /-\
                     33:  *
                     34:  * +---------------+-------------------------------+---------------+
                     35:  * | h | e | a | d | e | l | e | m | e | n | t | s | t | a | i | l |
                     36:  * +---------------+-------------------------------+---------------+
                     37:  *
                     38:  * \--------------/ \-----------------------------/ \-------------/
                     39:  *      unused                    used                   unused
                     40:  *      "head"                   "count"                 "tail"
                     41:  *
                     42:  */
                     43: struct array_t {
                     44:        /** number of elements currently in array (not counting head/tail) */
                     45:        uint32_t count;
                     46:        /** size of each element, 0 for a pointer based array */
                     47:        uint16_t esize;
                     48:        /** allocated but unused elements at array front */
                     49:        uint8_t head;
                     50:        /** allocated but unused elements at array end */
                     51:        uint8_t tail;
                     52:        /** array elements */
                     53:        void *data;
                     54: };
                     55: 
                     56: #ifndef HAVE_QSORT_R
                     57:        /* store data to replicate qsort_r in thread local storage */
                     58:        static thread_value_t *sort_data;
                     59: #endif
                     60: 
                     61: /** maximum number of unused head/tail elements before cleanup */
                     62: #define ARRAY_MAX_UNUSED 32
                     63: 
                     64: /**
                     65:  * Get the actual size of a number of elements
                     66:  */
                     67: static size_t get_size(array_t *array, uint32_t num)
                     68: {
                     69:        if (array->esize)
                     70:        {
                     71:                return (size_t)array->esize * num;
                     72:        }
                     73:        return sizeof(void*) * num;
                     74: }
                     75: 
                     76: /**
                     77:  * Increase allocated but unused tail room to at least "room"
                     78:  */
                     79: static void make_tail_room(array_t *array, uint8_t room)
                     80: {
                     81:        if (array->tail < room)
                     82:        {
                     83:                array->data = realloc(array->data,
                     84:                                                get_size(array, array->count + array->head + room));
                     85:                array->tail = room;
                     86:        }
                     87: }
                     88: 
                     89: /**
                     90:  * Increase allocated but unused head room to at least "room"
                     91:  */
                     92: static void make_head_room(array_t *array, uint8_t room)
                     93: {
                     94:        if (array->head < room)
                     95:        {
                     96:                uint8_t increase = room - array->head;
                     97: 
                     98:                array->data = realloc(array->data,
                     99:                                                get_size(array, array->count + array->tail + room));
                    100:                memmove(array->data + get_size(array, increase), array->data,
                    101:                                get_size(array, array->count + array->tail + array->head));
                    102:                array->head = room;
                    103:        }
                    104: }
                    105: 
                    106: /**
                    107:  * Make space for an item at index using tail room
                    108:  */
                    109: static void insert_tail(array_t *array, int idx)
                    110: {
                    111:        make_tail_room(array, 1);
                    112:        /* move up all elements after idx by one */
                    113:        memmove(array->data + get_size(array, array->head + idx + 1),
                    114:                        array->data + get_size(array, array->head + idx),
                    115:                        get_size(array, array->count - idx));
                    116: 
                    117:        array->tail--;
                    118:        array->count++;
                    119: }
                    120: 
                    121: /**
                    122:  * Make space for an item at index using head room
                    123:  */
                    124: static void insert_head(array_t *array, int idx)
                    125: {
                    126:        make_head_room(array, 1);
                    127:        /* move down all elements before idx by one */
                    128:        memmove(array->data + get_size(array, array->head - 1),
                    129:                        array->data + get_size(array, array->head),
                    130:                        get_size(array, idx));
                    131: 
                    132:        array->head--;
                    133:        array->count++;
                    134: }
                    135: 
                    136: /**
                    137:  * Remove an item, increase tail
                    138:  */
                    139: static void remove_tail(array_t *array, int idx)
                    140: {
                    141:        /* move all items after idx one down */
                    142:        memmove(array->data + get_size(array, idx + array->head),
                    143:                        array->data + get_size(array, idx + array->head + 1),
                    144:                        get_size(array, array->count - 1 - idx));
                    145:        array->count--;
                    146:        array->tail++;
                    147: }
                    148: 
                    149: /**
                    150:  * Remove an item, increase head
                    151:  */
                    152: static void remove_head(array_t *array, int idx)
                    153: {
                    154:        /* move all items before idx one up */
                    155:        memmove(array->data + get_size(array, array->head + 1),
                    156:                        array->data + get_size(array, array->head), get_size(array, idx));
                    157:        array->count--;
                    158:        array->head++;
                    159: }
                    160: 
                    161: array_t *array_create(u_int esize, uint8_t reserve)
                    162: {
                    163:        array_t *array;
                    164: 
                    165:        INIT(array,
                    166:                .esize = esize,
                    167:                .tail = reserve,
                    168:        );
                    169:        if (array->tail)
                    170:        {
                    171:                array->data = malloc(get_size(array, array->tail));
                    172:        }
                    173:        return array;
                    174: }
                    175: 
                    176: int array_count(array_t *array)
                    177: {
                    178:        if (array)
                    179:        {
                    180:                return array->count;
                    181:        }
                    182:        return 0;
                    183: }
                    184: 
                    185: void array_compress(array_t *array)
                    186: {
                    187:        if (array)
                    188:        {
                    189:                uint32_t tail;
                    190: 
                    191:                tail = array->tail;
                    192:                if (array->head)
                    193:                {
                    194:                        memmove(array->data, array->data + get_size(array, array->head),
                    195:                                        get_size(array, array->count + array->tail));
                    196:                        tail += array->head;
                    197:                        array->head = 0;
                    198:                }
                    199:                if (tail)
                    200:                {
                    201:                        array->data = realloc(array->data, get_size(array, array->count));
                    202:                        array->tail = 0;
                    203:                }
                    204:        }
                    205: }
                    206: 
                    207: typedef struct {
                    208:        /** public enumerator interface */
                    209:        enumerator_t public;
                    210:        /** enumerated array */
                    211:        array_t *array;
                    212:        /** current index +1, initialized at 0 */
                    213:        int idx;
                    214: } array_enumerator_t;
                    215: 
                    216: METHOD(enumerator_t, enumerate, bool,
                    217:        array_enumerator_t *this, va_list args)
                    218: {
                    219:        void *pos, **out;
                    220: 
                    221:        VA_ARGS_VGET(args, out);
                    222: 
                    223:        if (this->idx >= this->array->count)
                    224:        {
                    225:                return FALSE;
                    226:        }
                    227: 
                    228:        pos = this->array->data +
                    229:                  get_size(this->array, this->idx + this->array->head);
                    230:        if (this->array->esize)
                    231:        {
                    232:                /* for element based arrays we return a pointer to the element */
                    233:                *out = pos;
                    234:        }
                    235:        else
                    236:        {
                    237:                /* for pointer based arrays we return the pointer directly */
                    238:                *out = *(void**)pos;
                    239:        }
                    240:        this->idx++;
                    241:        return TRUE;
                    242: }
                    243: 
                    244: enumerator_t* array_create_enumerator(array_t *array)
                    245: {
                    246:        array_enumerator_t *enumerator;
                    247: 
                    248:        if (!array)
                    249:        {
                    250:                return enumerator_create_empty();
                    251:        }
                    252: 
                    253:        INIT(enumerator,
                    254:                .public = {
                    255:                        .enumerate = enumerator_enumerate_default,
                    256:                        .venumerate = _enumerate,
                    257:                        .destroy = (void*)free,
                    258:                },
                    259:                .array = array,
                    260:        );
                    261:        return &enumerator->public;
                    262: }
                    263: 
                    264: void array_remove_at(array_t *array, enumerator_t *public)
                    265: {
                    266:        array_enumerator_t *enumerator = (array_enumerator_t*)public;
                    267: 
                    268:        if (enumerator->idx)
                    269:        {
                    270:                array_remove(array, --enumerator->idx, NULL);
                    271:        }
                    272: }
                    273: 
                    274: void array_insert_create(array_t **array, int idx, void *ptr)
                    275: {
                    276:        if (*array == NULL)
                    277:        {
                    278:                *array = array_create(0, 0);
                    279:        }
                    280:        array_insert(*array, idx, ptr);
                    281: }
                    282: 
                    283: void array_insert_create_value(array_t **array, u_int esize,
                    284:                                                           int idx, void *val)
                    285: {
                    286:        if (*array == NULL)
                    287:        {
                    288:                *array = array_create(esize, 0);
                    289:        }
                    290:        array_insert(*array, idx, val);
                    291: }
                    292: 
                    293: void array_insert_enumerator(array_t *array, int idx, enumerator_t *enumerator)
                    294: {
                    295:        void *ptr;
                    296: 
                    297:        while (enumerator->enumerate(enumerator, &ptr))
                    298:        {
                    299:                array_insert(array, idx, ptr);
                    300:        }
                    301:        enumerator->destroy(enumerator);
                    302: }
                    303: 
                    304: void array_insert(array_t *array, int idx, void *data)
                    305: {
                    306:        if (idx < 0 || idx <= array_count(array))
                    307:        {
                    308:                void *pos;
                    309: 
                    310:                if (idx < 0)
                    311:                {
                    312:                        idx = array_count(array);
                    313:                }
                    314: 
                    315:                if (array->head && !array->tail)
                    316:                {
                    317:                        insert_head(array, idx);
                    318:                }
                    319:                else if (array->tail && !array->head)
                    320:                {
                    321:                        insert_tail(array, idx);
                    322:                }
                    323:                else if (idx > array_count(array) / 2)
                    324:                {
                    325:                        insert_tail(array, idx);
                    326:                }
                    327:                else
                    328:                {
                    329:                        insert_head(array, idx);
                    330:                }
                    331: 
                    332:                pos = array->data + get_size(array, array->head + idx);
                    333:                if (array->esize)
                    334:                {
                    335:                        memcpy(pos, data, get_size(array, 1));
                    336:                }
                    337:                else
                    338:                {
                    339:                        /* pointer based array, copy pointer value */
                    340:                        *(void**)pos = data;
                    341:                }
                    342:        }
                    343: }
                    344: 
                    345: bool array_get(array_t *array, int idx, void *data)
                    346: {
                    347:        if (!array)
                    348:        {
                    349:                return FALSE;
                    350:        }
                    351:        if (idx >= 0 && idx >= array_count(array))
                    352:        {
                    353:                return FALSE;
                    354:        }
                    355:        if (idx < 0)
                    356:        {
                    357:                if (array_count(array) == 0)
                    358:                {
                    359:                        return FALSE;
                    360:                }
                    361:                idx = array_count(array) - 1;
                    362:        }
                    363:        if (data)
                    364:        {
                    365:                memcpy(data, array->data + get_size(array, array->head + idx),
                    366:                           get_size(array, 1));
                    367:        }
                    368:        return TRUE;
                    369: }
                    370: 
                    371: bool array_remove(array_t *array, int idx, void *data)
                    372: {
                    373:        if (!array_get(array, idx, data))
                    374:        {
                    375:                return FALSE;
                    376:        }
                    377:        if (idx < 0)
                    378:        {
                    379:                idx = array_count(array) - 1;
                    380:        }
                    381:        if (idx > array_count(array) / 2)
                    382:        {
                    383:                remove_tail(array, idx);
                    384:        }
                    385:        else
                    386:        {
                    387:                remove_head(array, idx);
                    388:        }
                    389:        if (array->head + array->tail > ARRAY_MAX_UNUSED)
                    390:        {
                    391:                array_compress(array);
                    392:        }
                    393:        return TRUE;
                    394: }
                    395: 
                    396: typedef struct {
                    397:        /** the array */
                    398:        array_t *array;
                    399:        /** comparison function */
                    400:        int (*cmp)(const void*,const void*,void*);
                    401:        /** optional user arg */
                    402:        void *arg;
                    403: } sort_data_t;
                    404: 
                    405: #ifdef HAVE_QSORT_R_GNU
                    406: static int compare_elements(const void *a, const void *b, void *arg)
                    407: #elif defined(HAVE_QSORT_R_BSD)
                    408: static int compare_elements(void *arg, const void *a, const void *b)
                    409: #else /* !HAVE_QSORT_R */
                    410: static int compare_elements(const void *a, const void *b)
                    411: #endif
                    412: {
                    413: #ifdef HAVE_QSORT_R
                    414:        sort_data_t *data = (sort_data_t*)arg;
                    415: #else
                    416:        sort_data_t *data = sort_data->get(sort_data);
                    417: #endif
                    418: 
                    419:        if (data->array->esize)
                    420:        {
                    421:                return data->cmp(a, b, data->arg);
                    422:        }
                    423:        return data->cmp(*(void**)a, *(void**)b, data->arg);
                    424: }
                    425: 
                    426: void array_sort(array_t *array, int (*cmp)(const void*,const void*,void*),
                    427:                                void *user)
                    428: {
                    429:        if (array)
                    430:        {
                    431:                sort_data_t data = {
                    432:                        .array = array,
                    433:                        .cmp = cmp,
                    434:                        .arg = user,
                    435:                };
                    436:                void *start;
                    437: 
                    438:                start = array->data + get_size(array, array->head);
                    439: 
                    440: #ifdef HAVE_QSORT_R_GNU
                    441:                qsort_r(start, array->count, get_size(array, 1), compare_elements,
                    442:                                &data);
                    443: #elif defined(HAVE_QSORT_R_BSD)
                    444:                qsort_r(start, array->count, get_size(array, 1), &data,
                    445:                                compare_elements);
                    446: #else /* !HAVE_QSORT_R */
                    447:                sort_data->set(sort_data, &data);
                    448:                qsort(start, array->count, get_size(array, 1), compare_elements);
                    449: #endif
                    450:        }
                    451: }
                    452: 
                    453: typedef struct {
                    454:        /** the array */
                    455:        array_t *array;
                    456:        /** the key */
                    457:        const void *key;
                    458:        /** comparison function */
                    459:        int (*cmp)(const void*,const void*);
                    460: } bsearch_data_t;
                    461: 
                    462: static int search_elements(const void *a, const void *b)
                    463: {
                    464:        bsearch_data_t *data = (bsearch_data_t*)a;
                    465: 
                    466:        if (data->array->esize)
                    467:        {
                    468:                return data->cmp(data->key, b);
                    469:        }
                    470:        return data->cmp(data->key, *(void**)b);
                    471: }
                    472: 
                    473: int array_bsearch(array_t *array, const void *key,
                    474:                                  int (*cmp)(const void*,const void*), void *out)
                    475: {
                    476:        int idx = -1;
                    477: 
                    478:        if (array)
                    479:        {
                    480:                bsearch_data_t data = {
                    481:                        .array = array,
                    482:                        .key = key,
                    483:                        .cmp = cmp,
                    484:                };
                    485:                void *start, *item;
                    486: 
                    487:                start = array->data + get_size(array, array->head);
                    488: 
                    489:                item = bsearch(&data, start, array->count, get_size(array, 1),
                    490:                                           search_elements);
                    491:                if (item)
                    492:                {
                    493:                        if (out)
                    494:                        {
                    495:                                memcpy(out, item, get_size(array, 1));
                    496:                        }
                    497:                        idx = (item - start) / get_size(array, 1);
                    498:                }
                    499:        }
                    500:        return idx;
                    501: }
                    502: 
                    503: void array_invoke(array_t *array, array_callback_t cb, void *user)
                    504: {
                    505:        if (array)
                    506:        {
                    507:                void *obj;
                    508:                int i;
                    509: 
                    510:                for (i = array->head; i < array->count + array->head; i++)
                    511:                {
                    512:                        obj = array->data + get_size(array, i);
                    513:                        if (!array->esize)
                    514:                        {
                    515:                                /* dereference if we store store pointers */
                    516:                                obj = *(void**)obj;
                    517:                        }
                    518:                        cb(obj, i - array->head, user);
                    519:                }
                    520:        }
                    521: }
                    522: 
                    523: void array_invoke_offset(array_t *array, size_t offset)
                    524: {
                    525:        if (array)
                    526:        {
                    527:                void (*method)(void *data);
                    528:                void *obj;
                    529:                int i;
                    530: 
                    531:                for (i = array->head; i < array->count + array->head; i++)
                    532:                {
                    533:                        obj = array->data + get_size(array, i);
                    534:                        if (!array->esize)
                    535:                        {
                    536:                                /* dereference if we store store pointers */
                    537:                                obj = *(void**)obj;
                    538:                        }
                    539:                        method = *(void**)(obj + offset);
                    540:                        method(obj);
                    541:                }
                    542:        }
                    543: }
                    544: 
                    545: void array_destroy(array_t *array)
                    546: {
                    547:        if (array)
                    548:        {
                    549:                free(array->data);
                    550:                free(array);
                    551:        }
                    552: }
                    553: 
                    554: void array_destroy_function(array_t *array, array_callback_t cb, void *user)
                    555: {
                    556:        array_invoke(array, cb, user);
                    557:        array_destroy(array);
                    558: }
                    559: 
                    560: void array_destroy_offset(array_t *array, size_t offset)
                    561: {
                    562:        array_invoke_offset(array, offset);
                    563:        array_destroy(array);
                    564: }
                    565: 
                    566: void arrays_init()
                    567: {
                    568: #ifndef HAVE_QSORT_R
                    569:        sort_data =  thread_value_create(NULL);
                    570: #endif
                    571: }
                    572: 
                    573: void arrays_deinit()
                    574: {
                    575: #ifndef HAVE_QSORT_R
                    576:        sort_data->destroy(sort_data);
                    577: #endif
                    578: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>