Annotation of embedaddon/strongswan/src/libstrongswan/collections/hashtable.c, revision 1.1
1.1 ! misho 1: /*
! 2: * Copyright (C) 2008-2014 Tobias Brunner
! 3: * HSR Hochschule fuer Technik Rapperswil
! 4: *
! 5: * This program is free software; you can redistribute it and/or modify it
! 6: * under the terms of the GNU General Public License as published by the
! 7: * Free Software Foundation; either version 2 of the License, or (at your
! 8: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
! 9: *
! 10: * This program is distributed in the hope that it will be useful, but
! 11: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
! 12: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
! 13: * for more details.
! 14: */
! 15:
! 16:
! 17: #include "hashtable.h"
! 18:
! 19: #include <utils/chunk.h>
! 20:
! 21: /** The maximum capacity of the hash table (MUST be a power of 2) */
! 22: #define MAX_CAPACITY (1 << 30)
! 23:
! 24: typedef struct pair_t pair_t;
! 25:
! 26: /**
! 27: * This pair holds a pointer to the key and value it represents.
! 28: */
! 29: struct pair_t {
! 30: /**
! 31: * Key of a hash table item.
! 32: */
! 33: const void *key;
! 34:
! 35: /**
! 36: * Value of a hash table item.
! 37: */
! 38: void *value;
! 39:
! 40: /**
! 41: * Cached hash (used in case of a resize).
! 42: */
! 43: u_int hash;
! 44:
! 45: /**
! 46: * Next pair in an overflow list.
! 47: */
! 48: pair_t *next;
! 49: };
! 50:
! 51: /**
! 52: * Creates an empty pair object.
! 53: */
! 54: static inline pair_t *pair_create(const void *key, void *value, u_int hash)
! 55: {
! 56: pair_t *this;
! 57:
! 58: INIT(this,
! 59: .key = key,
! 60: .value = value,
! 61: .hash = hash,
! 62: );
! 63:
! 64: return this;
! 65: }
! 66:
! 67: typedef struct private_hashtable_t private_hashtable_t;
! 68:
! 69: /**
! 70: * Private data of a hashtable_t object.
! 71: *
! 72: */
! 73: struct private_hashtable_t {
! 74: /**
! 75: * Public part of hash table.
! 76: */
! 77: hashtable_t public;
! 78:
! 79: /**
! 80: * The number of items in the hash table.
! 81: */
! 82: u_int count;
! 83:
! 84: /**
! 85: * The current capacity of the hash table (always a power of 2).
! 86: */
! 87: u_int capacity;
! 88:
! 89: /**
! 90: * The current mask to calculate the row index (capacity - 1).
! 91: */
! 92: u_int mask;
! 93:
! 94: /**
! 95: * The load factor.
! 96: */
! 97: float load_factor;
! 98:
! 99: /**
! 100: * The actual table.
! 101: */
! 102: pair_t **table;
! 103:
! 104: /**
! 105: * The hashing function.
! 106: */
! 107: hashtable_hash_t hash;
! 108:
! 109: /**
! 110: * The equality function.
! 111: */
! 112: hashtable_equals_t equals;
! 113: };
! 114:
! 115: typedef struct private_enumerator_t private_enumerator_t;
! 116:
! 117: /**
! 118: * hash table enumerator implementation
! 119: */
! 120: struct private_enumerator_t {
! 121:
! 122: /**
! 123: * implements enumerator interface
! 124: */
! 125: enumerator_t enumerator;
! 126:
! 127: /**
! 128: * associated hash table
! 129: */
! 130: private_hashtable_t *table;
! 131:
! 132: /**
! 133: * current row index
! 134: */
! 135: u_int row;
! 136:
! 137: /**
! 138: * number of remaining items in hashtable
! 139: */
! 140: u_int count;
! 141:
! 142: /**
! 143: * current pair
! 144: */
! 145: pair_t *current;
! 146:
! 147: /**
! 148: * previous pair (used by remove_at)
! 149: */
! 150: pair_t *prev;
! 151: };
! 152:
! 153: /*
! 154: * See header.
! 155: */
! 156: u_int hashtable_hash_ptr(const void *key)
! 157: {
! 158: return chunk_hash(chunk_from_thing(key));
! 159: }
! 160:
! 161: /*
! 162: * See header.
! 163: */
! 164: u_int hashtable_hash_str(const void *key)
! 165: {
! 166: return chunk_hash(chunk_from_str((char*)key));
! 167: }
! 168:
! 169: /*
! 170: * See header.
! 171: */
! 172: bool hashtable_equals_ptr(const void *key, const void *other_key)
! 173: {
! 174: return key == other_key;
! 175: }
! 176:
! 177: /*
! 178: * See header.
! 179: */
! 180: bool hashtable_equals_str(const void *key, const void *other_key)
! 181: {
! 182: return streq(key, other_key);
! 183: }
! 184:
! 185: /**
! 186: * This function returns the next-highest power of two for the given number.
! 187: * The algorithm works by setting all bits on the right-hand side of the most
! 188: * significant 1 to 1 and then increments the whole number so it rolls over
! 189: * to the nearest power of two. Note: returns 0 for n == 0
! 190: */
! 191: static u_int get_nearest_powerof2(u_int n)
! 192: {
! 193: u_int i;
! 194:
! 195: --n;
! 196: for (i = 1; i < sizeof(u_int) * 8; i <<= 1)
! 197: {
! 198: n |= n >> i;
! 199: }
! 200: return ++n;
! 201: }
! 202:
! 203: /**
! 204: * Init hash table parameters
! 205: */
! 206: static void init_hashtable(private_hashtable_t *this, u_int capacity)
! 207: {
! 208: capacity = max(1, min(capacity, MAX_CAPACITY));
! 209: this->capacity = get_nearest_powerof2(capacity);
! 210: this->mask = this->capacity - 1;
! 211: this->load_factor = 0.75;
! 212:
! 213: this->table = calloc(this->capacity, sizeof(pair_t*));
! 214: }
! 215:
! 216: /**
! 217: * Double the size of the hash table and rehash all the elements.
! 218: */
! 219: static void rehash(private_hashtable_t *this)
! 220: {
! 221: pair_t **old_table;
! 222: u_int row, old_capacity;
! 223:
! 224: if (this->capacity >= MAX_CAPACITY)
! 225: {
! 226: return;
! 227: }
! 228:
! 229: old_capacity = this->capacity;
! 230: old_table = this->table;
! 231:
! 232: init_hashtable(this, old_capacity << 1);
! 233:
! 234: for (row = 0; row < old_capacity; row++)
! 235: {
! 236: pair_t *pair, *next;
! 237: u_int new_row;
! 238:
! 239: pair = old_table[row];
! 240: while (pair)
! 241: { /* insert pair at the front of new bucket*/
! 242: next = pair->next;
! 243: new_row = pair->hash & this->mask;
! 244: pair->next = this->table[new_row];
! 245: this->table[new_row] = pair;
! 246: pair = next;
! 247: }
! 248: }
! 249: free(old_table);
! 250: }
! 251:
! 252: METHOD(hashtable_t, put, void*,
! 253: private_hashtable_t *this, const void *key, void *value)
! 254: {
! 255: void *old_value = NULL;
! 256: pair_t *pair;
! 257: u_int hash, row;
! 258:
! 259: hash = this->hash(key);
! 260: row = hash & this->mask;
! 261: pair = this->table[row];
! 262: while (pair)
! 263: { /* search existing bucket for key */
! 264: if (this->equals(key, pair->key))
! 265: {
! 266: old_value = pair->value;
! 267: pair->value = value;
! 268: pair->key = key;
! 269: break;
! 270: }
! 271: pair = pair->next;
! 272: }
! 273: if (!pair)
! 274: { /* insert at the front of bucket */
! 275: pair = pair_create(key, value, hash);
! 276: pair->next = this->table[row];
! 277: this->table[row] = pair;
! 278: this->count++;
! 279: }
! 280: if (this->count >= this->capacity * this->load_factor)
! 281: {
! 282: rehash(this);
! 283: }
! 284: return old_value;
! 285: }
! 286:
! 287: static void *get_internal(private_hashtable_t *this, const void *key,
! 288: hashtable_equals_t equals)
! 289: {
! 290: void *value = NULL;
! 291: pair_t *pair;
! 292:
! 293: if (!this->count)
! 294: { /* no need to calculate the hash */
! 295: return NULL;
! 296: }
! 297:
! 298: pair = this->table[this->hash(key) & this->mask];
! 299: while (pair)
! 300: {
! 301: if (equals(key, pair->key))
! 302: {
! 303: value = pair->value;
! 304: break;
! 305: }
! 306: pair = pair->next;
! 307: }
! 308: return value;
! 309: }
! 310:
! 311: METHOD(hashtable_t, get, void*,
! 312: private_hashtable_t *this, const void *key)
! 313: {
! 314: return get_internal(this, key, this->equals);
! 315: }
! 316:
! 317: METHOD(hashtable_t, get_match, void*,
! 318: private_hashtable_t *this, const void *key, hashtable_equals_t match)
! 319: {
! 320: return get_internal(this, key, match);
! 321: }
! 322:
! 323: METHOD(hashtable_t, remove_, void*,
! 324: private_hashtable_t *this, const void *key)
! 325: {
! 326: void *value = NULL;
! 327: pair_t *pair, *prev = NULL;
! 328: u_int row;
! 329:
! 330: row = this->hash(key) & this->mask;
! 331: pair = this->table[row];
! 332: while (pair)
! 333: {
! 334: if (this->equals(key, pair->key))
! 335: {
! 336: if (prev)
! 337: {
! 338: prev->next = pair->next;
! 339: }
! 340: else
! 341: {
! 342: this->table[row] = pair->next;
! 343: }
! 344: value = pair->value;
! 345: this->count--;
! 346: free(pair);
! 347: break;
! 348: }
! 349: prev = pair;
! 350: pair = pair->next;
! 351: }
! 352: return value;
! 353: }
! 354:
! 355: METHOD(hashtable_t, remove_at, void,
! 356: private_hashtable_t *this, private_enumerator_t *enumerator)
! 357: {
! 358: if (enumerator->table == this && enumerator->current)
! 359: {
! 360: pair_t *current = enumerator->current;
! 361: if (enumerator->prev)
! 362: {
! 363: enumerator->prev->next = current->next;
! 364: }
! 365: else
! 366: {
! 367: this->table[enumerator->row] = current->next;
! 368: }
! 369: enumerator->current = enumerator->prev;
! 370: free(current);
! 371: this->count--;
! 372: }
! 373: }
! 374:
! 375: METHOD(hashtable_t, get_count, u_int,
! 376: private_hashtable_t *this)
! 377: {
! 378: return this->count;
! 379: }
! 380:
! 381: METHOD(enumerator_t, enumerate, bool,
! 382: private_enumerator_t *this, va_list args)
! 383: {
! 384: const void **key;
! 385: void **value;
! 386:
! 387: VA_ARGS_VGET(args, key, value);
! 388:
! 389: while (this->count && this->row < this->table->capacity)
! 390: {
! 391: this->prev = this->current;
! 392: if (this->current)
! 393: {
! 394: this->current = this->current->next;
! 395: }
! 396: else
! 397: {
! 398: this->current = this->table->table[this->row];
! 399: }
! 400: if (this->current)
! 401: {
! 402: if (key)
! 403: {
! 404: *key = this->current->key;
! 405: }
! 406: if (value)
! 407: {
! 408: *value = this->current->value;
! 409: }
! 410: this->count--;
! 411: return TRUE;
! 412: }
! 413: this->row++;
! 414: }
! 415: return FALSE;
! 416: }
! 417:
! 418: METHOD(hashtable_t, create_enumerator, enumerator_t*,
! 419: private_hashtable_t *this)
! 420: {
! 421: private_enumerator_t *enumerator;
! 422:
! 423: INIT(enumerator,
! 424: .enumerator = {
! 425: .enumerate = enumerator_enumerate_default,
! 426: .venumerate = _enumerate,
! 427: .destroy = (void*)free,
! 428: },
! 429: .table = this,
! 430: .count = this->count,
! 431: );
! 432:
! 433: return &enumerator->enumerator;
! 434: }
! 435:
! 436: static void destroy_internal(private_hashtable_t *this,
! 437: void (*fn)(void*,const void*))
! 438: {
! 439: pair_t *pair, *next;
! 440: u_int row;
! 441:
! 442: for (row = 0; row < this->capacity; row++)
! 443: {
! 444: pair = this->table[row];
! 445: while (pair)
! 446: {
! 447: if (fn)
! 448: {
! 449: fn(pair->value, pair->key);
! 450: }
! 451: next = pair->next;
! 452: free(pair);
! 453: pair = next;
! 454: }
! 455: }
! 456: free(this->table);
! 457: free(this);
! 458: }
! 459:
! 460: METHOD(hashtable_t, destroy, void,
! 461: private_hashtable_t *this)
! 462: {
! 463: destroy_internal(this, NULL);
! 464: }
! 465:
! 466: METHOD(hashtable_t, destroy_function, void,
! 467: private_hashtable_t *this, void (*fn)(void*,const void*))
! 468: {
! 469: destroy_internal(this, fn);
! 470: }
! 471:
! 472: /*
! 473: * Described in header.
! 474: */
! 475: hashtable_t *hashtable_create(hashtable_hash_t hash, hashtable_equals_t equals,
! 476: u_int capacity)
! 477: {
! 478: private_hashtable_t *this;
! 479:
! 480: INIT(this,
! 481: .public = {
! 482: .put = _put,
! 483: .get = _get,
! 484: .get_match = _get_match,
! 485: .remove = _remove_,
! 486: .remove_at = (void*)_remove_at,
! 487: .get_count = _get_count,
! 488: .create_enumerator = _create_enumerator,
! 489: .destroy = _destroy,
! 490: .destroy_function = _destroy_function,
! 491: },
! 492: .hash = hash,
! 493: .equals = equals,
! 494: );
! 495:
! 496: init_hashtable(this, capacity);
! 497:
! 498: return &this->public;
! 499: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>