utp_hash.h 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146
  1. /*
  2. * Copyright (c) 2010-2013 BitTorrent, Inc.
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a copy
  5. * of this software and associated documentation files (the "Software"), to deal
  6. * in the Software without restriction, including without limitation the rights
  7. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  8. * copies of the Software, and to permit persons to whom the Software is
  9. * furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  19. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  20. * THE SOFTWARE.
  21. */
  22. #ifndef __UTP_HASH_H__
  23. #define __UTP_HASH_H__
  24. #include <string.h> // memset
  25. #include <stdlib.h> // malloc
  26. #include "utp_types.h"
  27. #include "utp_templates.h"
  28. // TODO: make utp_link_t a template parameter to HashTable
  29. typedef uint32 utp_link_t;
  30. #ifdef _MSC_VER
  31. // Silence the warning about the C99-compliant zero-length array at the end of the structure
  32. #pragma warning (disable: 4200)
  33. #endif
  34. typedef uint32 (*utp_hash_compute_t)(const void *keyp, size_t keysize);
  35. typedef uint (*utp_hash_equal_t)(const void *key_a, const void *key_b, size_t keysize);
  36. // In memory the HashTable is laid out as follows:
  37. // ---------------------------- low
  38. // | hash table data members |
  39. // ---------------------------- _
  40. // | indices | ^
  41. // | . | | utp_link_t indices into the key-values.
  42. // | . | .
  43. // ---------------------------- - <----- bep
  44. // | keys and values | each key-value pair has size total_size
  45. // | . |
  46. // | . |
  47. // ---------------------------- high
  48. //
  49. // The code depends on the ability of the compiler to pad the length
  50. // of the hash table data members structure to
  51. // a length divisible by 32-bits with no remainder.
  52. //
  53. // Since the number of hash buckets (indices) should be odd, the code
  54. // asserts this and adds one to the hash bucket count to ensure that the
  55. // following key-value pairs array starts on a 32-bit boundary.
  56. //
  57. // The key-value pairs array should start on a 32-bit boundary, otherwise
  58. // processors like the ARM will silently mangle 32-bit data in these structures
  59. // (e.g., turning 0xABCD into 0XCDAB when moving a value from memory to register
  60. // when the memory address is 16 bits offset from a 32-bit boundary),
  61. // also, the value will be stored at an address two bytes lower than the address
  62. // value would ordinarily indicate.
  63. //
  64. // The key-value pair is of type T. The first field in T must
  65. // be the key, i.e., the first K bytes of T contains the key.
  66. // total_size = sizeof(T) and thus sizeof(T) >= sizeof(K)
  67. //
  68. // N is the number of buckets.
  69. //
  70. struct utp_hash_t {
  71. utp_link_t N;
  72. byte K;
  73. byte E;
  74. size_t count;
  75. utp_hash_compute_t hash_compute;
  76. utp_hash_equal_t hash_equal;
  77. utp_link_t allocated;
  78. utp_link_t used;
  79. utp_link_t free;
  80. utp_link_t inits[0];
  81. };
  82. #ifdef _MSC_VER
  83. #pragma warning (default: 4200)
  84. #endif
  85. struct utp_hash_iterator_t {
  86. utp_link_t bucket;
  87. utp_link_t elem;
  88. utp_hash_iterator_t() : bucket(0xffffffff), elem(0xffffffff) {}
  89. };
  90. uint utp_hash_mem(const void *keyp, size_t keysize);
  91. uint utp_hash_comp(const void *key_a, const void *key_b, size_t keysize);
  92. utp_hash_t *utp_hash_create(int N, int key_size, int total_size, int initial, utp_hash_compute_t hashfun = utp_hash_mem, utp_hash_equal_t eqfun = NULL);
  93. void *utp_hash_lookup(utp_hash_t *hash, const void *key);
  94. void *utp_hash_add(utp_hash_t **hashp, const void *key);
  95. void *utp_hash_del(utp_hash_t *hash, const void *key);
  96. void *utp_hash_iterate(utp_hash_t *hash, utp_hash_iterator_t *iter);
  97. void utp_hash_free_mem(utp_hash_t *hash);
  98. /*
  99. This HashTable requires that T have at least sizeof(K)+sizeof(utp_link_t) bytes.
  100. Usually done like this:
  101. struct K {
  102. int whatever;
  103. };
  104. struct T {
  105. K wtf;
  106. utp_link_t link; // also wtf
  107. };
  108. */
  109. template<typename K, typename T> class utpHashTable {
  110. utp_hash_t *hash;
  111. public:
  112. static uint compare(const void *k1, const void *k2, size_t ks) {
  113. return *((K*)k1) == *((K*)k2);
  114. }
  115. static uint32 compute_hash(const void *k, size_t ks) {
  116. return ((K*)k)->compute_hash();
  117. }
  118. void Init() { hash = NULL; }
  119. bool Allocated() { return (hash != NULL); }
  120. void Free() { utp_hash_free_mem(hash); hash = NULL; }
  121. void Create(int N, int initial) { hash = utp_hash_create(N, sizeof(K), sizeof(T), initial, &compute_hash, &compare); }
  122. T *Lookup(const K &key) { return (T*)utp_hash_lookup(hash, &key); }
  123. T *Add(const K &key) { return (T*)utp_hash_add(&hash, &key); }
  124. T *Delete(const K &key) { return (T*)utp_hash_del(hash, &key); }
  125. T *Iterate(utp_hash_iterator_t &iterator) { return (T*)utp_hash_iterate(hash, &iterator); }
  126. size_t GetCount() { return hash->count; }
  127. };
  128. #endif //__UTP_HASH_H__