Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2007 VMware, Inc.
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21.  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  22.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28.  /*
  29.   * Authors:
  30.   *   Zack Rusin <zackr@vmware.com>
  31.   */
  32.  
  33. #include "util/u_debug.h"
  34. #include "util/u_memory.h"
  35.  
  36. #include "cso_hash.h"
  37.  
  38. #ifndef MAX
  39. #define MAX(a, b) ((a > b) ? (a) : (b))
  40. #endif
  41.  
  42. static const int MinNumBits = 4;
  43.  
  44. static const unsigned char prime_deltas[] = {
  45.    0,  0,  1,  3,  1,  5,  3,  3,  1,  9,  7,  5,  3,  9, 25,  3,
  46.    1, 21,  3, 21,  7, 15,  9,  5,  3, 29, 15,  0,  0,  0,  0,  0
  47. };
  48.  
  49. static int primeForNumBits(int numBits)
  50. {
  51.    return (1 << numBits) + prime_deltas[numBits];
  52. }
  53.  
  54. /*
  55.     Returns the smallest integer n such that
  56.     primeForNumBits(n) >= hint.
  57. */
  58. static int countBits(int hint)
  59. {
  60.    int numBits = 0;
  61.    int bits = hint;
  62.  
  63.    while (bits > 1) {
  64.       bits >>= 1;
  65.       numBits++;
  66.    }
  67.  
  68.    if (numBits >= (int)sizeof(prime_deltas)) {
  69.       numBits = sizeof(prime_deltas) - 1;
  70.    } else if (primeForNumBits(numBits) < hint) {
  71.       ++numBits;
  72.    }
  73.    return numBits;
  74. }
  75.  
  76. struct cso_node {
  77.    struct cso_node *next;
  78.    unsigned key;
  79.    void *value;
  80. };
  81.  
  82. struct cso_hash_data {
  83.    struct cso_node *fakeNext;
  84.    struct cso_node **buckets;
  85.    int size;
  86.    int nodeSize;
  87.    short userNumBits;
  88.    short numBits;
  89.    int numBuckets;
  90. };
  91.  
  92. struct cso_hash {
  93.    union {
  94.       struct cso_hash_data *d;
  95.       struct cso_node      *e;
  96.    } data;
  97. };
  98.  
  99. static void *cso_data_allocate_node(struct cso_hash_data *hash)
  100. {
  101.    return MALLOC(hash->nodeSize);
  102. }
  103.  
  104. static void cso_free_node(struct cso_node *node)
  105. {
  106.    FREE(node);
  107. }
  108.  
  109. static struct cso_node *
  110. cso_hash_create_node(struct cso_hash *hash,
  111.                       unsigned akey, void *avalue,
  112.                       struct cso_node **anextNode)
  113. {
  114.    struct cso_node *node = cso_data_allocate_node(hash->data.d);
  115.  
  116.    if (!node)
  117.       return NULL;
  118.  
  119.    node->key = akey;
  120.    node->value = avalue;
  121.  
  122.    node->next = (struct cso_node*)(*anextNode);
  123.    *anextNode = node;
  124.    ++hash->data.d->size;
  125.    return node;
  126. }
  127.  
  128. static void cso_data_rehash(struct cso_hash_data *hash, int hint)
  129. {
  130.    if (hint < 0) {
  131.       hint = countBits(-hint);
  132.       if (hint < MinNumBits)
  133.          hint = MinNumBits;
  134.       hash->userNumBits = (short)hint;
  135.       while (primeForNumBits(hint) < (hash->size >> 1))
  136.          ++hint;
  137.    } else if (hint < MinNumBits) {
  138.       hint = MinNumBits;
  139.    }
  140.  
  141.    if (hash->numBits != hint) {
  142.       struct cso_node *e = (struct cso_node *)(hash);
  143.       struct cso_node **oldBuckets = hash->buckets;
  144.       int oldNumBuckets = hash->numBuckets;
  145.       int  i = 0;
  146.  
  147.       hash->numBits = (short)hint;
  148.       hash->numBuckets = primeForNumBits(hint);
  149.       hash->buckets = MALLOC(sizeof(struct cso_node*) * hash->numBuckets);
  150.       for (i = 0; i < hash->numBuckets; ++i)
  151.          hash->buckets[i] = e;
  152.  
  153.       for (i = 0; i < oldNumBuckets; ++i) {
  154.          struct cso_node *firstNode = oldBuckets[i];
  155.          while (firstNode != e) {
  156.             unsigned h = firstNode->key;
  157.             struct cso_node *lastNode = firstNode;
  158.             struct cso_node *afterLastNode;
  159.             struct cso_node **beforeFirstNode;
  160.            
  161.             while (lastNode->next != e && lastNode->next->key == h)
  162.                lastNode = lastNode->next;
  163.  
  164.             afterLastNode = lastNode->next;
  165.             beforeFirstNode = &hash->buckets[h % hash->numBuckets];
  166.             while (*beforeFirstNode != e)
  167.                beforeFirstNode = &(*beforeFirstNode)->next;
  168.             lastNode->next = *beforeFirstNode;
  169.             *beforeFirstNode = firstNode;
  170.             firstNode = afterLastNode;
  171.          }
  172.       }
  173.       FREE(oldBuckets);
  174.    }
  175. }
  176.  
  177. static void cso_data_might_grow(struct cso_hash_data *hash)
  178. {
  179.    if (hash->size >= hash->numBuckets)
  180.       cso_data_rehash(hash, hash->numBits + 1);
  181. }
  182.  
  183. static void cso_data_has_shrunk(struct cso_hash_data *hash)
  184. {
  185.    if (hash->size <= (hash->numBuckets >> 3) &&
  186.        hash->numBits > hash->userNumBits) {
  187.       int max = MAX(hash->numBits-2, hash->userNumBits);
  188.       cso_data_rehash(hash,  max);
  189.    }
  190. }
  191.  
  192. static struct cso_node *cso_data_first_node(struct cso_hash_data *hash)
  193. {
  194.    struct cso_node *e = (struct cso_node *)(hash);
  195.    struct cso_node **bucket = hash->buckets;
  196.    int n = hash->numBuckets;
  197.    while (n--) {
  198.       if (*bucket != e)
  199.          return *bucket;
  200.       ++bucket;
  201.    }
  202.    return e;
  203. }
  204.  
  205. static struct cso_node **cso_hash_find_node(struct cso_hash *hash, unsigned akey)
  206. {
  207.    struct cso_node **node;
  208.  
  209.    if (hash->data.d->numBuckets) {
  210.       node = (struct cso_node **)(&hash->data.d->buckets[akey % hash->data.d->numBuckets]);
  211.       assert(*node == hash->data.e || (*node)->next);
  212.       while (*node != hash->data.e && (*node)->key != akey)
  213.          node = &(*node)->next;
  214.    } else {
  215.       node = (struct cso_node **)((const struct cso_node * const *)(&hash->data.e));
  216.    }
  217.    return node;
  218. }
  219.  
  220. struct cso_hash_iter cso_hash_insert(struct cso_hash *hash,
  221.                                        unsigned key, void *data)
  222. {
  223.    cso_data_might_grow(hash->data.d);
  224.  
  225.    {
  226.       struct cso_node **nextNode = cso_hash_find_node(hash, key);
  227.       struct cso_node *node = cso_hash_create_node(hash, key, data, nextNode);
  228.       if (!node) {
  229.          struct cso_hash_iter null_iter = {hash, 0};
  230.          return null_iter;
  231.       }
  232.  
  233.       {
  234.          struct cso_hash_iter iter = {hash, node};
  235.          return iter;
  236.       }
  237.    }
  238. }
  239.  
  240. struct cso_hash * cso_hash_create(void)
  241. {
  242.    struct cso_hash *hash = MALLOC_STRUCT(cso_hash);
  243.    if (!hash)
  244.       return NULL;
  245.  
  246.    hash->data.d = MALLOC_STRUCT(cso_hash_data);
  247.    if (!hash->data.d) {
  248.       FREE(hash);
  249.       return NULL;
  250.    }
  251.  
  252.    hash->data.d->fakeNext = 0;
  253.    hash->data.d->buckets = 0;
  254.    hash->data.d->size = 0;
  255.    hash->data.d->nodeSize = sizeof(struct cso_node);
  256.    hash->data.d->userNumBits = (short)MinNumBits;
  257.    hash->data.d->numBits = 0;
  258.    hash->data.d->numBuckets = 0;
  259.  
  260.    return hash;
  261. }
  262.  
  263. void cso_hash_delete(struct cso_hash *hash)
  264. {
  265.    struct cso_node *e_for_x = (struct cso_node *)(hash->data.d);
  266.    struct cso_node **bucket = (struct cso_node **)(hash->data.d->buckets);
  267.    int n = hash->data.d->numBuckets;
  268.    while (n--) {
  269.       struct cso_node *cur = *bucket++;
  270.       while (cur != e_for_x) {
  271.          struct cso_node *next = cur->next;
  272.          cso_free_node(cur);
  273.          cur = next;
  274.       }
  275.    }
  276.    FREE(hash->data.d->buckets);
  277.    FREE(hash->data.d);
  278.    FREE(hash);
  279. }
  280.  
  281. struct cso_hash_iter cso_hash_find(struct cso_hash *hash,
  282.                                      unsigned key)
  283. {
  284.    struct cso_node **nextNode = cso_hash_find_node(hash, key);
  285.    struct cso_hash_iter iter = {hash, *nextNode};
  286.    return iter;
  287. }
  288.  
  289. unsigned cso_hash_iter_key(struct cso_hash_iter iter)
  290. {
  291.    if (!iter.node || iter.hash->data.e == iter.node)
  292.       return 0;
  293.    return iter.node->key;
  294. }
  295.  
  296. void * cso_hash_iter_data(struct cso_hash_iter iter)
  297. {
  298.    if (!iter.node || iter.hash->data.e == iter.node)
  299.       return 0;
  300.    return iter.node->value;
  301. }
  302.  
  303. static struct cso_node *cso_hash_data_next(struct cso_node *node)
  304. {
  305.    union {
  306.       struct cso_node *next;
  307.       struct cso_node *e;
  308.       struct cso_hash_data *d;
  309.    } a;
  310.    int start;
  311.    struct cso_node **bucket;
  312.    int n;
  313.  
  314.    a.next = node->next;
  315.    if (!a.next) {
  316.       debug_printf("iterating beyond the last element\n");
  317.       return 0;
  318.    }
  319.    if (a.next->next)
  320.       return a.next;
  321.  
  322.    start = (node->key % a.d->numBuckets) + 1;
  323.    bucket = a.d->buckets + start;
  324.    n = a.d->numBuckets - start;
  325.    while (n--) {
  326.       if (*bucket != a.e)
  327.          return *bucket;
  328.       ++bucket;
  329.    }
  330.    return a.e;
  331. }
  332.  
  333.  
  334. static struct cso_node *cso_hash_data_prev(struct cso_node *node)
  335. {
  336.    union {
  337.       struct cso_node *e;
  338.       struct cso_hash_data *d;
  339.    } a;
  340.    int start;
  341.    struct cso_node *sentinel;
  342.    struct cso_node **bucket;
  343.  
  344.    a.e = node;
  345.    while (a.e->next)
  346.       a.e = a.e->next;
  347.  
  348.    if (node == a.e)
  349.       start = a.d->numBuckets - 1;
  350.    else
  351.       start = node->key % a.d->numBuckets;
  352.  
  353.    sentinel = node;
  354.    bucket = a.d->buckets + start;
  355.    while (start >= 0) {
  356.       if (*bucket != sentinel) {
  357.          struct cso_node *prev = *bucket;
  358.          while (prev->next != sentinel)
  359.             prev = prev->next;
  360.          return prev;
  361.       }
  362.  
  363.       sentinel = a.e;
  364.       --bucket;
  365.       --start;
  366.    }
  367.    debug_printf("iterating backward beyond first element\n");
  368.    return a.e;
  369. }
  370.  
  371. struct cso_hash_iter cso_hash_iter_next(struct cso_hash_iter iter)
  372. {
  373.    struct cso_hash_iter next = {iter.hash, cso_hash_data_next(iter.node)};
  374.    return next;
  375. }
  376.  
  377. int cso_hash_iter_is_null(struct cso_hash_iter iter)
  378. {
  379.    if (!iter.node || iter.node == iter.hash->data.e)
  380.       return 1;
  381.    return 0;
  382. }
  383.  
  384. void * cso_hash_take(struct cso_hash *hash,
  385.                       unsigned akey)
  386. {
  387.    struct cso_node **node = cso_hash_find_node(hash, akey);
  388.    if (*node != hash->data.e) {
  389.       void *t = (*node)->value;
  390.       struct cso_node *next = (*node)->next;
  391.       cso_free_node(*node);
  392.       *node = next;
  393.       --hash->data.d->size;
  394.       cso_data_has_shrunk(hash->data.d);
  395.       return t;
  396.    }
  397.    return 0;
  398. }
  399.  
  400. struct cso_hash_iter cso_hash_iter_prev(struct cso_hash_iter iter)
  401. {
  402.    struct cso_hash_iter prev = {iter.hash,
  403.                                  cso_hash_data_prev(iter.node)};
  404.    return prev;
  405. }
  406.  
  407. struct cso_hash_iter cso_hash_first_node(struct cso_hash *hash)
  408. {
  409.    struct cso_hash_iter iter = {hash, cso_data_first_node(hash->data.d)};
  410.    return iter;
  411. }
  412.  
  413. int cso_hash_size(struct cso_hash *hash)
  414. {
  415.    return hash->data.d->size;
  416. }
  417.  
  418. struct cso_hash_iter cso_hash_erase(struct cso_hash *hash, struct cso_hash_iter iter)
  419. {
  420.    struct cso_hash_iter ret = iter;
  421.    struct cso_node *node = iter.node;
  422.    struct cso_node **node_ptr;
  423.  
  424.    if (node == hash->data.e)
  425.       return iter;
  426.  
  427.    ret = cso_hash_iter_next(ret);
  428.    node_ptr = (struct cso_node**)(&hash->data.d->buckets[node->key % hash->data.d->numBuckets]);
  429.    while (*node_ptr != node)
  430.       node_ptr = &(*node_ptr)->next;
  431.    *node_ptr = node->next;
  432.    cso_free_node(node);
  433.    --hash->data.d->size;
  434.    return ret;
  435. }
  436.  
  437. boolean cso_hash_contains(struct cso_hash *hash, unsigned key)
  438. {
  439.    struct cso_node **node = cso_hash_find_node(hash, key);
  440.    return (*node != hash->data.e);
  441. }
  442.