Map.h 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. /* vim: set expandtab ts=4 sw=4: */
  2. /*
  3. * You may redistribute this program and/or modify it under the terms of
  4. * the GNU General Public License as published by the Free Software Foundation,
  5. * either version 3 of the License, or (at your option) any later version.
  6. *
  7. * This program is distributed in the hope that it will be useful,
  8. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. * GNU General Public License for more details.
  11. *
  12. * You should have received a copy of the GNU General Public License
  13. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  14. */
  15. #ifndef Map_H
  16. #define Map_H
  17. #endif // This header can be used multiple times as long as the name is different.
  18. #include "util/Bits.h"
  19. #if defined(Map_KEY_TYPE)
  20. Assert_compileTime(!(sizeof(Map_KEY_TYPE) % 4));
  21. #define Map_ENABLE_KEYS
  22. #elif !defined(Map_ENABLE_HANDLES)
  23. #error must define Map_KEY_TYPE or Map_ENABLE_HANDLES or both
  24. #endif
  25. #ifndef Map_VALUE_TYPE
  26. #error must define Map_VALUE_TYPE
  27. #endif
  28. #ifndef Map_NAME
  29. #error must give this map type a name by defining Map_NAME
  30. #endif
  31. #define Map_CONTEXT Map_GLUE(Map_, Map_NAME)
  32. #define Map_FUNCTION(name) Map_GLUE(Map_GLUE(Map_GLUE(Map_, Map_NAME),_), name)
  33. #define Map_GLUE(x, y) Map_GLUE2(x, y)
  34. #define Map_GLUE2(x, y) x ## y
  35. #ifdef Map_ENABLE_KEYS
  36. // Hashcode calculator.
  37. static inline uint32_t Map_FUNCTION(hash)(Map_KEY_TYPE* key);
  38. #ifndef Map_USE_HASH
  39. #include "util/Hash.h"
  40. // Get the last 4 bytes of the key by default.
  41. static inline uint32_t Map_FUNCTION(hash)(Map_KEY_TYPE* key)
  42. {
  43. return Hash_compute((uint8_t*)key, sizeof(Map_KEY_TYPE));
  44. }
  45. #endif
  46. static inline int Map_FUNCTION(compare)(Map_KEY_TYPE* keyA, Map_KEY_TYPE* keyB);
  47. #ifndef Map_USE_COMPARATOR
  48. // Get the last 4 bytes of the key by default.
  49. static inline int Map_FUNCTION(compare)(Map_KEY_TYPE* keyA, Map_KEY_TYPE* keyB)
  50. {
  51. return Bits_memcmp(keyA, keyB, sizeof(Map_KEY_TYPE));
  52. }
  53. #endif
  54. #endif
  55. struct Map_CONTEXT
  56. {
  57. #ifdef Map_ENABLE_KEYS
  58. uint32_t* hashCodes;
  59. Map_KEY_TYPE* keys;
  60. #endif
  61. #ifdef Map_ENABLE_HANDLES
  62. uint32_t* handles;
  63. uint32_t nextHandle;
  64. #endif
  65. Map_VALUE_TYPE* values;
  66. uint32_t count;
  67. uint32_t capacity;
  68. struct Allocator* allocator;
  69. };
  70. static inline struct Map_CONTEXT* Map_FUNCTION(new)(struct Allocator* allocator)
  71. {
  72. return Allocator_clone(allocator, (&(struct Map_CONTEXT) {
  73. .allocator = allocator
  74. }));
  75. }
  76. /**
  77. * This is a very hot loop,
  78. * a large amount of code relies on this being fast so it is a good target for optimization.
  79. */
  80. #ifdef Map_ENABLE_KEYS
  81. static inline int Map_FUNCTION(indexForKey)(Map_KEY_TYPE* key, struct Map_CONTEXT* map)
  82. {
  83. uint32_t hashCode = (Map_FUNCTION(hash)(key));
  84. for (uint32_t i = 0; i < map->count; i++) {
  85. if (map->hashCodes[i] == hashCode
  86. && Map_FUNCTION(compare)(key, &map->keys[i]) == 0)
  87. {
  88. return i;
  89. }
  90. }
  91. return -1;
  92. }
  93. #endif
  94. #ifdef Map_ENABLE_HANDLES
  95. static inline int Map_FUNCTION(indexForHandle)(uint32_t handle, struct Map_CONTEXT* map)
  96. {
  97. uint32_t base = 0;
  98. for (uint32_t bufferLen = map->count; bufferLen != 0; bufferLen /= 2) {
  99. uint32_t currentHandle = map->handles[base + (bufferLen / 2)];
  100. if (handle >= currentHandle) {
  101. if (currentHandle == handle) {
  102. return base + (bufferLen / 2);
  103. }
  104. base += (bufferLen / 2) + 1;
  105. bufferLen--;
  106. }
  107. }
  108. return -1;
  109. }
  110. #endif
  111. /**
  112. * @param key the key of the entry to remove.
  113. * @param map the map to remove from.
  114. * @return 0 if the entry is removed, -1 if it could not be found.
  115. */
  116. static inline int Map_FUNCTION(remove)(int index, struct Map_CONTEXT* map)
  117. {
  118. if (index >= 0 && index < (int) map->count - 1) {
  119. #ifdef Map_ENABLE_HANDLES
  120. // If we use handels then we need to keep the map sorted.
  121. #ifdef Map_ENABLE_KEYS
  122. Bits_memmove(&map->hashCodes[index],
  123. &map->hashCodes[index + 1],
  124. (map->count - index - 1) * sizeof(uint32_t));
  125. Bits_memmove(&map->keys[index],
  126. &map->keys[index + 1],
  127. (map->count - index - 1) * sizeof(Map_KEY_TYPE));
  128. #endif
  129. Bits_memmove(&map->handles[index],
  130. &map->handles[index + 1],
  131. (map->count - index - 1) * sizeof(uint32_t));
  132. Bits_memmove(&map->values[index],
  133. &map->values[index + 1],
  134. (map->count - index - 1) * sizeof(Map_VALUE_TYPE));
  135. map->count--;
  136. #else
  137. // No handles, we can just fold the top entry down on one to remove.
  138. map->count--;
  139. map->hashCodes[index] = map->hashCodes[map->count];
  140. Bits_memcpy(&map->keys[index], &map->keys[map->count], sizeof(Map_KEY_TYPE));
  141. Bits_memcpy(&map->values[index], &map->values[map->count], sizeof(Map_VALUE_TYPE));
  142. #endif
  143. return 0;
  144. } else if (index == (int) map->count - 1) {
  145. map->count--;
  146. return 0;
  147. }
  148. return -1;
  149. }
  150. #ifdef Map_ENABLE_KEYS
  151. static inline int Map_FUNCTION(put)(Map_KEY_TYPE* key,
  152. Map_VALUE_TYPE* value,
  153. struct Map_CONTEXT* map)
  154. #else
  155. static inline int Map_FUNCTION(put)(Map_VALUE_TYPE* value,
  156. struct Map_CONTEXT* map)
  157. #endif
  158. {
  159. if (map->count == map->capacity) {
  160. #ifdef Map_ENABLE_KEYS
  161. map->hashCodes = Allocator_realloc(map->allocator,
  162. map->hashCodes,
  163. sizeof(uint32_t) * (map->count + 10));
  164. map->keys = Allocator_realloc(map->allocator,
  165. map->keys,
  166. sizeof(Map_KEY_TYPE) * (map->count + 10));
  167. #endif
  168. #ifdef Map_ENABLE_HANDLES
  169. map->handles = Allocator_realloc(map->allocator,
  170. map->handles,
  171. sizeof(uint32_t) * (map->count + 10));
  172. #endif
  173. map->values = Allocator_realloc(map->allocator,
  174. map->values,
  175. sizeof(Map_VALUE_TYPE) * (map->count + 10));
  176. map->capacity += 10;
  177. }
  178. int i = -1;
  179. #ifdef Map_ENABLE_KEYS
  180. i = Map_FUNCTION(indexForKey)(key, map);
  181. #endif
  182. if (i < 0) {
  183. i = map->count;
  184. map->count++;
  185. #ifdef Map_ENABLE_HANDLES
  186. map->handles[i] = map->nextHandle++;
  187. #endif
  188. #ifdef Map_ENABLE_KEYS
  189. map->hashCodes[i] = (Map_FUNCTION(hash)(key));
  190. Bits_memcpy(&map->keys[i], key, sizeof(Map_KEY_TYPE));
  191. #endif
  192. }
  193. Bits_memcpy(&map->values[i], value, sizeof(Map_VALUE_TYPE));
  194. return i;
  195. }
  196. #undef Map
  197. #undef Map_Entry
  198. #undef Map_FUNCTION
  199. #undef Map_USE_HASH
  200. #undef Map_NAME
  201. #undef Map_VALUE_TYPE
  202. #undef Map_ENABLE_HANDLES
  203. #undef Map_KEY_TYPE
  204. #undef Map_ENABLE_KEYS
  205. #undef Map_USE_COMPARATOR