Annotation of embedaddon/strongswan/src/libstrongswan/collections/array.c, revision 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>