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>