CHash_impl.h 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /**
  2. * @file CHash_impl.h
  3. * @author Ambroz Bizjak <ambrop7@gmail.com>
  4. *
  5. * @section LICENSE
  6. *
  7. * Redistribution and use in source and binary forms, with or without
  8. * modification, are permitted provided that the following conditions are met:
  9. * 1. Redistributions of source code must retain the above copyright
  10. * notice, this list of conditions and the following disclaimer.
  11. * 2. Redistributions in binary form must reproduce the above copyright
  12. * notice, this list of conditions and the following disclaimer in the
  13. * documentation and/or other materials provided with the distribution.
  14. * 3. Neither the name of the author nor the
  15. * names of its contributors may be used to endorse or promote products
  16. * derived from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  19. * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  24. * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  27. * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. */
  29. #include "CHash_header.h"
  30. static void CHash_assert_valid_entry (CHashArg arg, CHashRef entry)
  31. {
  32. ASSERT(entry.link != CHashNullLink())
  33. ASSERT(entry.ptr == CHASH_PARAM_DEREF(arg, entry.link))
  34. }
  35. static CHashLink CHashNullLink (void)
  36. {
  37. return CHASH_PARAM_NULL;
  38. }
  39. static CHashRef CHashNullRef (void)
  40. {
  41. CHashRef entry = {NULL, CHashNullLink()};
  42. return entry;
  43. }
  44. static int CHashIsNullLink (CHashLink link)
  45. {
  46. return (link == CHashNullLink());
  47. }
  48. static int CHashIsNullRef (CHashRef ref)
  49. {
  50. return CHashIsNullLink(ref.link);
  51. }
  52. static CHashRef CHashDerefMayNull (CHashArg arg, CHashLink link)
  53. {
  54. if (link == CHashNullLink()) {
  55. return CHashNullRef();
  56. }
  57. CHashRef entry = {CHASH_PARAM_DEREF(arg, link), link};
  58. ASSERT(entry.ptr)
  59. return entry;
  60. }
  61. static CHashRef CHashDerefNonNull (CHashArg arg, CHashLink link)
  62. {
  63. ASSERT(link != CHashNullLink())
  64. CHashRef entry = {CHASH_PARAM_DEREF(arg, link), link};
  65. ASSERT(entry.ptr)
  66. return entry;
  67. }
  68. static int CHash_Init (CHash *o, size_t num_buckets)
  69. {
  70. if (num_buckets == 0) {
  71. num_buckets = 1;
  72. }
  73. o->num_buckets = num_buckets;
  74. o->buckets = (CHashLink *)BAllocArray(o->num_buckets, sizeof(o->buckets[0]));
  75. if (!o->buckets) {
  76. return 0;
  77. }
  78. for (size_t i = 0; i < o->num_buckets; i++) {
  79. o->buckets[i] = CHashNullLink();
  80. }
  81. return 1;
  82. }
  83. static void CHash_Free (CHash *o)
  84. {
  85. BFree(o->buckets);
  86. }
  87. static int CHash_Insert (CHash *o, CHashArg arg, CHashRef entry, CHashRef *out_existing)
  88. {
  89. CHash_assert_valid_entry(arg, entry);
  90. size_t index = CHASH_PARAM_ENTRYHASH(arg, entry) % o->num_buckets;
  91. CHashLink link = o->buckets[index];
  92. while (link != CHashNullLink()) {
  93. CHashRef cur = CHashDerefNonNull(arg, link);
  94. if (CHASH_PARAM_COMPARE_ENTRIES(arg, cur, entry)) {
  95. if (out_existing) {
  96. *out_existing = cur;
  97. return 0;
  98. }
  99. }
  100. link = CHash_next(cur);
  101. }
  102. CHash_next(entry) = o->buckets[index];
  103. o->buckets[index] = entry.link;
  104. return 1;
  105. }
  106. static void CHash_InsertMulti (CHash *o, CHashArg arg, CHashRef entry)
  107. {
  108. CHash_assert_valid_entry(arg, entry);
  109. size_t index = CHASH_PARAM_ENTRYHASH(arg, entry) % o->num_buckets;
  110. CHashRef prev = CHashNullRef();
  111. CHashLink link = o->buckets[index];
  112. while (link != CHashNullLink()) {
  113. CHashRef cur = CHashDerefNonNull(arg, link);
  114. if (CHASH_PARAM_COMPARE_ENTRIES(arg, cur, entry)) {
  115. break;
  116. }
  117. prev = cur;
  118. link = CHash_next(cur);
  119. }
  120. if (link == CHashNullLink() || prev.link == CHashNullLink()) {
  121. CHash_next(entry) = o->buckets[index];
  122. o->buckets[index] = entry.link;
  123. } else {
  124. CHash_next(entry) = link;
  125. CHash_next(prev) = entry.link;
  126. }
  127. }
  128. static void CHash_Remove (CHash *o, CHashArg arg, CHashRef entry)
  129. {
  130. CHash_assert_valid_entry(arg, entry);
  131. size_t index = CHASH_PARAM_ENTRYHASH(arg, entry) % o->num_buckets;
  132. CHashRef prev = CHashNullRef();
  133. CHashLink link = o->buckets[index];
  134. while (link != entry.link) {
  135. CHashRef cur = CHashDerefNonNull(arg, link);
  136. prev = cur;
  137. link = CHash_next(cur);
  138. ASSERT(link != CHashNullLink())
  139. }
  140. if (prev.link == CHashNullLink()) {
  141. o->buckets[index] = CHash_next(entry);
  142. } else {
  143. CHash_next(prev) = CHash_next(entry);
  144. }
  145. }
  146. static CHashRef CHash_Lookup (const CHash *o, CHashArg arg, CHashKey key)
  147. {
  148. size_t index = CHASH_PARAM_KEYHASH(arg, key) % o->num_buckets;
  149. CHashLink link = o->buckets[index];
  150. while (link != CHashNullLink()) {
  151. CHashRef cur = CHashDerefNonNull(arg, link);
  152. if (CHASH_PARAM_COMPARE_KEY_ENTRY(arg, key, cur)) {
  153. return cur;
  154. }
  155. link = CHash_next(cur);
  156. }
  157. return CHashNullRef();
  158. }
  159. static CHashRef CHash_GetNextEqual (const CHash *o, CHashArg arg, CHashRef entry)
  160. {
  161. CHash_assert_valid_entry(arg, entry);
  162. CHashLink next = CHash_next(entry);
  163. if (next == CHashNullLink()) {
  164. return CHashNullRef();
  165. }
  166. CHashRef next_ref = CHashDerefNonNull(arg, next);
  167. if (!CHASH_PARAM_COMPARE_ENTRIES(arg, next_ref, entry)) {
  168. return CHashNullRef();
  169. }
  170. return next_ref;
  171. }
  172. #include "CHash_footer.h"