1
0

xf86drmHash.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /* xf86drmHash.c -- Small hash table support for integer -> integer mapping
  2. * Created: Sun Apr 18 09:35:45 1999 by faith@precisioninsight.com
  3. *
  4. * SPDX-FileCopyrightText: 1999 Precision Insight, Inc., Cedar Park, Texas.
  5. * SPDX-License-Identifier: MIT
  6. * SPDX-FileContributor: Rickard E. (Rik) Faith <faith@valinux.com>
  7. *
  8. * DESCRIPTION
  9. *
  10. * This file contains a straightforward implementation of a fixed-sized
  11. * hash table using self-organizing linked lists [Knuth73, pp. 398-399] for
  12. * collision resolution. There are two potentially interesting things
  13. * about this implementation:
  14. *
  15. * 1) The table is power-of-two sized. Prime sized tables are more
  16. * traditional, but do not have a significant advantage over power-of-two
  17. * sized table, especially when double hashing is not used for collision
  18. * resolution.
  19. *
  20. * 2) The hash computation uses a table of random integers [Hanson97,
  21. * pp. 39-41].
  22. *
  23. * FUTURE ENHANCEMENTS
  24. *
  25. * With a table size of 512, the current implementation is sufficient for a
  26. * few hundred keys. Since this is well above the expected size of the
  27. * tables for which this implementation was designed, the implementation of
  28. * dynamic hash tables was postponed until the need arises. A common (and
  29. * naive) approach to dynamic hash table implementation simply creates a
  30. * new hash table when necessary, rehashes all the data into the new table,
  31. * and destroys the old table. The approach in [Larson88] is superior in
  32. * two ways: 1) only a portion of the table is expanded when needed,
  33. * distributing the expansion cost over several insertions, and 2) portions
  34. * of the table can be locked, enabling a scalable thread-safe
  35. * implementation.
  36. *
  37. * REFERENCES
  38. *
  39. * [Hanson97] David R. Hanson. C Interfaces and Implementations:
  40. * Techniques for Creating Reusable Software. Reading, Massachusetts:
  41. * Addison-Wesley, 1997.
  42. *
  43. * [Knuth73] Donald E. Knuth. The Art of Computer Programming. Volume 3:
  44. * Sorting and Searching. Reading, Massachusetts: Addison-Wesley, 1973.
  45. *
  46. * [Larson88] Per-Ake Larson. "Dynamic Hash Tables". CACM 31(4), April
  47. * 1988, pp. 446-457.
  48. *
  49. */
  50. #include <stdio.h>
  51. #include <stdlib.h>
  52. #include "libdrm_macros.h"
  53. #include "xf86drm.h"
  54. #include "xf86drmHash.h"
  55. #define HASH_MAGIC 0xdeadbeef
  56. static unsigned long HashHash(unsigned long key)
  57. {
  58. unsigned long hash = 0;
  59. unsigned long tmp = key;
  60. static int init = 0;
  61. static unsigned long scatter[256];
  62. int i;
  63. if (!init) {
  64. void *state;
  65. state = drmRandomCreate(37);
  66. for (i = 0; i < 256; i++) scatter[i] = drmRandom(state);
  67. drmRandomDestroy(state);
  68. ++init;
  69. }
  70. while (tmp) {
  71. hash = (hash << 1) + scatter[tmp & 0xff];
  72. tmp >>= 8;
  73. }
  74. hash %= HASH_SIZE;
  75. return hash;
  76. }
  77. drm_public void *drmHashCreate(void)
  78. {
  79. HashTablePtr table;
  80. table = drmMalloc(sizeof(*table));
  81. if (!table) return NULL;
  82. table->magic = HASH_MAGIC;
  83. return table;
  84. }
  85. drm_public int drmHashDestroy(void *t)
  86. {
  87. HashTablePtr table = (HashTablePtr)t;
  88. HashBucketPtr bucket;
  89. HashBucketPtr next;
  90. int i;
  91. if (table->magic != HASH_MAGIC) return -1; /* Bad magic */
  92. for (i = 0; i < HASH_SIZE; i++) {
  93. for (bucket = table->buckets[i]; bucket;) {
  94. next = bucket->next;
  95. drmFree(bucket);
  96. bucket = next;
  97. }
  98. }
  99. drmFree(table);
  100. return 0;
  101. }
  102. /* Find the bucket and organize the list so that this bucket is at the
  103. top. */
  104. static HashBucketPtr HashFind(HashTablePtr table,
  105. unsigned long key, unsigned long *h)
  106. {
  107. unsigned long hash = HashHash(key);
  108. HashBucketPtr prev = NULL;
  109. HashBucketPtr bucket;
  110. if (h) *h = hash;
  111. for (bucket = table->buckets[hash]; bucket; bucket = bucket->next) {
  112. if (bucket->key == key) {
  113. if (prev) {
  114. /* Organize */
  115. prev->next = bucket->next;
  116. bucket->next = table->buckets[hash];
  117. table->buckets[hash] = bucket;
  118. ++table->partials;
  119. } else {
  120. ++table->hits;
  121. }
  122. return bucket;
  123. }
  124. prev = bucket;
  125. }
  126. ++table->misses;
  127. return NULL;
  128. }
  129. drm_public int drmHashLookup(void *t, unsigned long key, void **value)
  130. {
  131. HashTablePtr table = (HashTablePtr)t;
  132. HashBucketPtr bucket;
  133. if (!table || table->magic != HASH_MAGIC) return -1; /* Bad magic */
  134. bucket = HashFind(table, key, NULL);
  135. if (!bucket) return 1; /* Not found */
  136. *value = bucket->value;
  137. return 0; /* Found */
  138. }
  139. drm_public int drmHashInsert(void *t, unsigned long key, void *value)
  140. {
  141. HashTablePtr table = (HashTablePtr)t;
  142. HashBucketPtr bucket;
  143. unsigned long hash;
  144. if (table->magic != HASH_MAGIC) return -1; /* Bad magic */
  145. if (HashFind(table, key, &hash)) return 1; /* Already in table */
  146. bucket = drmMalloc(sizeof(*bucket));
  147. if (!bucket) return -1; /* Error */
  148. bucket->key = key;
  149. bucket->value = value;
  150. bucket->next = table->buckets[hash];
  151. table->buckets[hash] = bucket;
  152. return 0; /* Added to table */
  153. }
  154. drm_public int drmHashDelete(void *t, unsigned long key)
  155. {
  156. HashTablePtr table = (HashTablePtr)t;
  157. unsigned long hash;
  158. HashBucketPtr bucket;
  159. if (table->magic != HASH_MAGIC) return -1; /* Bad magic */
  160. bucket = HashFind(table, key, &hash);
  161. if (!bucket) return 1; /* Not found */
  162. table->buckets[hash] = bucket->next;
  163. drmFree(bucket);
  164. return 0;
  165. }
  166. drm_public int drmHashNext(void *t, unsigned long *key, void **value)
  167. {
  168. HashTablePtr table = (HashTablePtr)t;
  169. while (table->p0 < HASH_SIZE) {
  170. if (table->p1) {
  171. *key = table->p1->key;
  172. *value = table->p1->value;
  173. table->p1 = table->p1->next;
  174. return 1;
  175. }
  176. table->p1 = table->buckets[table->p0];
  177. ++table->p0;
  178. }
  179. return 0;
  180. }
  181. drm_public int drmHashFirst(void *t, unsigned long *key, void **value)
  182. {
  183. HashTablePtr table = (HashTablePtr)t;
  184. if (table->magic != HASH_MAGIC) return -1; /* Bad magic */
  185. table->p0 = 0;
  186. table->p1 = table->buckets[0];
  187. return drmHashNext(table, key, value);
  188. }