zend_hash.h 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Zend Engine |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 1998-2016 Zend Technologies Ltd. (http://www.zend.com) |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 2.00 of the Zend license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available through the world-wide-web at the following url: |
  10. | http://www.zend.com/license/2_00.txt. |
  11. | If you did not receive a copy of the Zend license and are unable to |
  12. | obtain it through the world-wide-web, please send a note to |
  13. | license@zend.com so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Andi Gutmans <andi@zend.com> |
  16. | Zeev Suraski <zeev@zend.com> |
  17. +----------------------------------------------------------------------+
  18. */
  19. /* $Id$ */
  20. #ifndef ZEND_HASH_H
  21. #define ZEND_HASH_H
  22. #include <sys/types.h>
  23. #include "zend.h"
  24. #define HASH_KEY_IS_STRING 1
  25. #define HASH_KEY_IS_LONG 2
  26. #define HASH_KEY_NON_EXISTENT 3
  27. #define HASH_KEY_NON_EXISTANT HASH_KEY_NON_EXISTENT /* Keeping old define (with typo) for backward compatibility */
  28. #define HASH_UPDATE (1<<0)
  29. #define HASH_ADD (1<<1)
  30. #define HASH_NEXT_INSERT (1<<2)
  31. #define HASH_DEL_KEY 0
  32. #define HASH_DEL_INDEX 1
  33. #define HASH_DEL_KEY_QUICK 2
  34. #define HASH_UPDATE_KEY_IF_NONE 0
  35. #define HASH_UPDATE_KEY_IF_BEFORE 1
  36. #define HASH_UPDATE_KEY_IF_AFTER 2
  37. #define HASH_UPDATE_KEY_ANYWAY 3
  38. typedef ulong (*hash_func_t)(const char *arKey, uint nKeyLength);
  39. typedef int (*compare_func_t)(const void *, const void * TSRMLS_DC);
  40. typedef void (*sort_func_t)(void *, size_t, register size_t, compare_func_t TSRMLS_DC);
  41. typedef void (*dtor_func_t)(void *pDest);
  42. typedef void (*copy_ctor_func_t)(void *pElement);
  43. typedef void (*copy_ctor_param_func_t)(void *pElement, void *pParam);
  44. struct _hashtable;
  45. typedef struct bucket {
  46. ulong h; /* Used for numeric indexing */
  47. uint nKeyLength;
  48. void *pData;
  49. void *pDataPtr;
  50. struct bucket *pListNext;
  51. struct bucket *pListLast;
  52. struct bucket *pNext;
  53. struct bucket *pLast;
  54. const char *arKey;
  55. } Bucket;
  56. typedef struct _hashtable {
  57. uint nTableSize;
  58. uint nTableMask;
  59. uint nNumOfElements;
  60. ulong nNextFreeElement;
  61. Bucket *pInternalPointer; /* Used for element traversal */
  62. Bucket *pListHead;
  63. Bucket *pListTail;
  64. Bucket **arBuckets;
  65. dtor_func_t pDestructor;
  66. zend_bool persistent;
  67. unsigned char nApplyCount;
  68. zend_bool bApplyProtection;
  69. #if ZEND_DEBUG
  70. int inconsistent;
  71. #endif
  72. } HashTable;
  73. typedef struct _zend_hash_key {
  74. const char *arKey;
  75. uint nKeyLength;
  76. ulong h;
  77. } zend_hash_key;
  78. typedef zend_bool (*merge_checker_func_t)(HashTable *target_ht, void *source_data, zend_hash_key *hash_key, void *pParam);
  79. typedef Bucket* HashPosition;
  80. BEGIN_EXTERN_C()
  81. /* startup/shutdown */
  82. ZEND_API int _zend_hash_init(HashTable *ht, uint nSize, dtor_func_t pDestructor, zend_bool persistent ZEND_FILE_LINE_DC);
  83. ZEND_API int _zend_hash_init_ex(HashTable *ht, uint nSize, dtor_func_t pDestructor, zend_bool persistent, zend_bool bApplyProtection ZEND_FILE_LINE_DC);
  84. ZEND_API void zend_hash_destroy(HashTable *ht);
  85. ZEND_API void zend_hash_clean(HashTable *ht);
  86. #define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent) _zend_hash_init((ht), (nSize), (pDestructor), (persistent) ZEND_FILE_LINE_CC)
  87. #define zend_hash_init_ex(ht, nSize, pHashFunction, pDestructor, persistent, bApplyProtection) _zend_hash_init_ex((ht), (nSize), (pDestructor), (persistent), (bApplyProtection) ZEND_FILE_LINE_CC)
  88. /* additions/updates/changes */
  89. ZEND_API int _zend_hash_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC);
  90. #define zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest) \
  91. _zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC)
  92. #define zend_hash_add(ht, arKey, nKeyLength, pData, nDataSize, pDest) \
  93. _zend_hash_add_or_update(ht, arKey, nKeyLength, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC)
  94. ZEND_API int _zend_hash_quick_add_or_update(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC);
  95. #define zend_hash_quick_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest) \
  96. _zend_hash_quick_add_or_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC)
  97. #define zend_hash_quick_add(ht, arKey, nKeyLength, h, pData, nDataSize, pDest) \
  98. _zend_hash_quick_add_or_update(ht, arKey, nKeyLength, h, pData, nDataSize, pDest, HASH_ADD ZEND_FILE_LINE_CC)
  99. ZEND_API int _zend_hash_index_update_or_next_insert(HashTable *ht, ulong h, void *pData, uint nDataSize, void **pDest, int flag ZEND_FILE_LINE_DC);
  100. #define zend_hash_index_update(ht, h, pData, nDataSize, pDest) \
  101. _zend_hash_index_update_or_next_insert(ht, h, pData, nDataSize, pDest, HASH_UPDATE ZEND_FILE_LINE_CC)
  102. #define zend_hash_next_index_insert(ht, pData, nDataSize, pDest) \
  103. _zend_hash_index_update_or_next_insert(ht, 0, pData, nDataSize, pDest, HASH_NEXT_INSERT ZEND_FILE_LINE_CC)
  104. ZEND_API int zend_hash_add_empty_element(HashTable *ht, const char *arKey, uint nKeyLength);
  105. #define ZEND_HASH_APPLY_KEEP 0
  106. #define ZEND_HASH_APPLY_REMOVE 1<<0
  107. #define ZEND_HASH_APPLY_STOP 1<<1
  108. typedef int (*apply_func_t)(void *pDest TSRMLS_DC);
  109. typedef int (*apply_func_arg_t)(void *pDest, void *argument TSRMLS_DC);
  110. typedef int (*apply_func_args_t)(void *pDest TSRMLS_DC, int num_args, va_list args, zend_hash_key *hash_key);
  111. ZEND_API void zend_hash_graceful_destroy(HashTable *ht);
  112. ZEND_API void zend_hash_graceful_reverse_destroy(HashTable *ht);
  113. ZEND_API void zend_hash_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC);
  114. ZEND_API void zend_hash_apply_with_argument(HashTable *ht, apply_func_arg_t apply_func, void * TSRMLS_DC);
  115. ZEND_API void zend_hash_apply_with_arguments(HashTable *ht TSRMLS_DC, apply_func_args_t apply_func, int, ...);
  116. /* This function should be used with special care (in other words,
  117. * it should usually not be used). When used with the ZEND_HASH_APPLY_STOP
  118. * return value, it assumes things about the order of the elements in the hash.
  119. * Also, it does not provide the same kind of reentrancy protection that
  120. * the standard apply functions do.
  121. */
  122. ZEND_API void zend_hash_reverse_apply(HashTable *ht, apply_func_t apply_func TSRMLS_DC);
  123. /* Deletes */
  124. ZEND_API int zend_hash_del_key_or_index(HashTable *ht, const char *arKey, uint nKeyLength, ulong h, int flag);
  125. #define zend_hash_del(ht, arKey, nKeyLength) \
  126. zend_hash_del_key_or_index(ht, arKey, nKeyLength, 0, HASH_DEL_KEY)
  127. #define zend_hash_quick_del(ht, arKey, nKeyLength, h) \
  128. zend_hash_del_key_or_index(ht, arKey, nKeyLength, h, HASH_DEL_KEY_QUICK)
  129. #define zend_hash_index_del(ht, h) \
  130. zend_hash_del_key_or_index(ht, NULL, 0, h, HASH_DEL_INDEX)
  131. #define zend_get_hash_value \
  132. zend_hash_func
  133. /* Data retreival */
  134. ZEND_API int zend_hash_find(const HashTable *ht, const char *arKey, uint nKeyLength, void **pData);
  135. ZEND_API int zend_hash_quick_find(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h, void **pData);
  136. ZEND_API int zend_hash_index_find(const HashTable *ht, ulong h, void **pData);
  137. /* Misc */
  138. ZEND_API int zend_hash_exists(const HashTable *ht, const char *arKey, uint nKeyLength);
  139. ZEND_API int zend_hash_quick_exists(const HashTable *ht, const char *arKey, uint nKeyLength, ulong h);
  140. ZEND_API int zend_hash_index_exists(const HashTable *ht, ulong h);
  141. ZEND_API ulong zend_hash_next_free_element(const HashTable *ht);
  142. /* traversing */
  143. #define zend_hash_has_more_elements_ex(ht, pos) \
  144. (zend_hash_get_current_key_type_ex(ht, pos) == HASH_KEY_NON_EXISTENT ? FAILURE : SUCCESS)
  145. ZEND_API int zend_hash_move_forward_ex(HashTable *ht, HashPosition *pos);
  146. ZEND_API int zend_hash_move_backwards_ex(HashTable *ht, HashPosition *pos);
  147. ZEND_API int zend_hash_get_current_key_ex(const HashTable *ht, char **str_index, uint *str_length, ulong *num_index, zend_bool duplicate, HashPosition *pos);
  148. ZEND_API void zend_hash_get_current_key_zval_ex(const HashTable *ht, zval *key, HashPosition *pos);
  149. ZEND_API int zend_hash_get_current_key_type_ex(HashTable *ht, HashPosition *pos);
  150. ZEND_API int zend_hash_get_current_data_ex(HashTable *ht, void **pData, HashPosition *pos);
  151. ZEND_API void zend_hash_internal_pointer_reset_ex(HashTable *ht, HashPosition *pos);
  152. ZEND_API void zend_hash_internal_pointer_end_ex(HashTable *ht, HashPosition *pos);
  153. ZEND_API int zend_hash_update_current_key_ex(HashTable *ht, int key_type, const char *str_index, uint str_length, ulong num_index, int mode, HashPosition *pos);
  154. typedef struct _HashPointer {
  155. HashPosition pos;
  156. ulong h;
  157. } HashPointer;
  158. ZEND_API int zend_hash_get_pointer(const HashTable *ht, HashPointer *ptr);
  159. ZEND_API int zend_hash_set_pointer(HashTable *ht, const HashPointer *ptr);
  160. #define zend_hash_has_more_elements(ht) \
  161. zend_hash_has_more_elements_ex(ht, NULL)
  162. #define zend_hash_move_forward(ht) \
  163. zend_hash_move_forward_ex(ht, NULL)
  164. #define zend_hash_move_backwards(ht) \
  165. zend_hash_move_backwards_ex(ht, NULL)
  166. #define zend_hash_get_current_key(ht, str_index, num_index, duplicate) \
  167. zend_hash_get_current_key_ex(ht, str_index, NULL, num_index, duplicate, NULL)
  168. #define zend_hash_get_current_key_zval(ht, key) \
  169. zend_hash_get_current_key_zval_ex(ht, key, NULL)
  170. #define zend_hash_get_current_key_type(ht) \
  171. zend_hash_get_current_key_type_ex(ht, NULL)
  172. #define zend_hash_get_current_data(ht, pData) \
  173. zend_hash_get_current_data_ex(ht, pData, NULL)
  174. #define zend_hash_internal_pointer_reset(ht) \
  175. zend_hash_internal_pointer_reset_ex(ht, NULL)
  176. #define zend_hash_internal_pointer_end(ht) \
  177. zend_hash_internal_pointer_end_ex(ht, NULL)
  178. #define zend_hash_update_current_key(ht, key_type, str_index, str_length, num_index) \
  179. zend_hash_update_current_key_ex(ht, key_type, str_index, str_length, num_index, HASH_UPDATE_KEY_ANYWAY, NULL)
  180. /* Copying, merging and sorting */
  181. ZEND_API void zend_hash_copy(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size);
  182. ZEND_API void _zend_hash_merge(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, void *tmp, uint size, int overwrite ZEND_FILE_LINE_DC);
  183. ZEND_API void zend_hash_merge_ex(HashTable *target, HashTable *source, copy_ctor_func_t pCopyConstructor, uint size, merge_checker_func_t pMergeSource, void *pParam);
  184. ZEND_API int zend_hash_sort(HashTable *ht, sort_func_t sort_func, compare_func_t compare_func, int renumber TSRMLS_DC);
  185. ZEND_API int zend_hash_compare(HashTable *ht1, HashTable *ht2, compare_func_t compar, zend_bool ordered TSRMLS_DC);
  186. ZEND_API int zend_hash_minmax(const HashTable *ht, compare_func_t compar, int flag, void **pData TSRMLS_DC);
  187. #define zend_hash_merge(target, source, pCopyConstructor, tmp, size, overwrite) \
  188. _zend_hash_merge(target, source, pCopyConstructor, tmp, size, overwrite ZEND_FILE_LINE_CC)
  189. ZEND_API int zend_hash_num_elements(const HashTable *ht);
  190. ZEND_API int zend_hash_rehash(HashTable *ht);
  191. ZEND_API void zend_hash_reindex(HashTable *ht, zend_bool only_integer_keys);
  192. ZEND_API void _zend_hash_splice(HashTable *ht, uint nDataSize, copy_ctor_func_t pCopyConstructor, uint offset, uint length, void **list, uint list_count, HashTable *removed ZEND_FILE_LINE_DC);
  193. #define zend_hash_splice(ht, nDataSize, pCopyConstructor, offset, length, list, list_count, removed) \
  194. _zend_hash_splice(ht, nDataSize, pCopyConstructor, offset, length, list, list_count, removed ZEND_FILE_LINE_CC)
  195. /*
  196. * DJBX33A (Daniel J. Bernstein, Times 33 with Addition)
  197. *
  198. * This is Daniel J. Bernstein's popular `times 33' hash function as
  199. * posted by him years ago on comp.lang.c. It basically uses a function
  200. * like ``hash(i) = hash(i-1) * 33 + str[i]''. This is one of the best
  201. * known hash functions for strings. Because it is both computed very
  202. * fast and distributes very well.
  203. *
  204. * The magic of number 33, i.e. why it works better than many other
  205. * constants, prime or not, has never been adequately explained by
  206. * anyone. So I try an explanation: if one experimentally tests all
  207. * multipliers between 1 and 256 (as RSE did now) one detects that even
  208. * numbers are not useable at all. The remaining 128 odd numbers
  209. * (except for the number 1) work more or less all equally well. They
  210. * all distribute in an acceptable way and this way fill a hash table
  211. * with an average percent of approx. 86%.
  212. *
  213. * If one compares the Chi^2 values of the variants, the number 33 not
  214. * even has the best value. But the number 33 and a few other equally
  215. * good numbers like 17, 31, 63, 127 and 129 have nevertheless a great
  216. * advantage to the remaining numbers in the large set of possible
  217. * multipliers: their multiply operation can be replaced by a faster
  218. * operation based on just one shift plus either a single addition
  219. * or subtraction operation. And because a hash function has to both
  220. * distribute good _and_ has to be very fast to compute, those few
  221. * numbers should be preferred and seems to be the reason why Daniel J.
  222. * Bernstein also preferred it.
  223. *
  224. *
  225. * -- Ralf S. Engelschall <rse@engelschall.com>
  226. */
  227. static inline ulong zend_inline_hash_func(const char *arKey, uint nKeyLength)
  228. {
  229. register ulong hash = 5381;
  230. /* variant with the hash unrolled eight times */
  231. for (; nKeyLength >= 8; nKeyLength -= 8) {
  232. hash = ((hash << 5) + hash) + *arKey++;
  233. hash = ((hash << 5) + hash) + *arKey++;
  234. hash = ((hash << 5) + hash) + *arKey++;
  235. hash = ((hash << 5) + hash) + *arKey++;
  236. hash = ((hash << 5) + hash) + *arKey++;
  237. hash = ((hash << 5) + hash) + *arKey++;
  238. hash = ((hash << 5) + hash) + *arKey++;
  239. hash = ((hash << 5) + hash) + *arKey++;
  240. }
  241. switch (nKeyLength) {
  242. case 7: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  243. case 6: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  244. case 5: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  245. case 4: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  246. case 3: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  247. case 2: hash = ((hash << 5) + hash) + *arKey++; /* fallthrough... */
  248. case 1: hash = ((hash << 5) + hash) + *arKey++; break;
  249. case 0: break;
  250. EMPTY_SWITCH_DEFAULT_CASE()
  251. }
  252. return hash;
  253. }
  254. ZEND_API ulong zend_hash_func(const char *arKey, uint nKeyLength);
  255. #if ZEND_DEBUG
  256. /* debug */
  257. void zend_hash_display_pListTail(const HashTable *ht);
  258. void zend_hash_display(const HashTable *ht);
  259. #endif
  260. END_EXTERN_C()
  261. #define ZEND_INIT_SYMTABLE(ht) \
  262. ZEND_INIT_SYMTABLE_EX(ht, 2, 0)
  263. #define ZEND_INIT_SYMTABLE_EX(ht, n, persistent) \
  264. zend_hash_init(ht, n, NULL, ZVAL_PTR_DTOR, persistent)
  265. #define ZEND_HANDLE_NUMERIC_EX(key, length, idx, func) do { \
  266. register const char *tmp = key; \
  267. \
  268. if (*tmp == '-') { \
  269. tmp++; \
  270. } \
  271. if (*tmp >= '0' && *tmp <= '9') { /* possibly a numeric index */ \
  272. const char *end = key + length - 1; \
  273. \
  274. if ((*end != '\0') /* not a null terminated string */ \
  275. || (*tmp == '0' && length > 2) /* numbers with leading zeros */ \
  276. || (end - tmp > MAX_LENGTH_OF_LONG - 1) /* number too long */ \
  277. || (SIZEOF_LONG == 4 && \
  278. end - tmp == MAX_LENGTH_OF_LONG - 1 && \
  279. *tmp > '2')) { /* overflow */ \
  280. break; \
  281. } \
  282. idx = (*tmp - '0'); \
  283. while (++tmp != end && *tmp >= '0' && *tmp <= '9') { \
  284. idx = (idx * 10) + (*tmp - '0'); \
  285. } \
  286. if (tmp == end) { \
  287. if (*key == '-') { \
  288. if (idx-1 > LONG_MAX) { /* overflow */ \
  289. break; \
  290. } \
  291. idx = 0 - idx; \
  292. } else if (idx > LONG_MAX) { /* overflow */ \
  293. break; \
  294. } \
  295. func; \
  296. } \
  297. } \
  298. } while (0)
  299. #define ZEND_HANDLE_NUMERIC(key, length, func) do { \
  300. ulong idx; \
  301. \
  302. ZEND_HANDLE_NUMERIC_EX(key, length, idx, return func); \
  303. } while (0)
  304. static inline int zend_symtable_update(HashTable *ht, const char *arKey, uint nKeyLength, void *pData, uint nDataSize, void **pDest) \
  305. {
  306. ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_update(ht, idx, pData, nDataSize, pDest));
  307. return zend_hash_update(ht, arKey, nKeyLength, pData, nDataSize, pDest);
  308. }
  309. static inline int zend_symtable_del(HashTable *ht, const char *arKey, uint nKeyLength)
  310. {
  311. ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_del(ht, idx));
  312. return zend_hash_del(ht, arKey, nKeyLength);
  313. }
  314. static inline int zend_symtable_find(HashTable *ht, const char *arKey, uint nKeyLength, void **pData)
  315. {
  316. ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_find(ht, idx, pData));
  317. return zend_hash_find(ht, arKey, nKeyLength, pData);
  318. }
  319. static inline int zend_symtable_exists(HashTable *ht, const char *arKey, uint nKeyLength)
  320. {
  321. ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_index_exists(ht, idx));
  322. return zend_hash_exists(ht, arKey, nKeyLength);
  323. }
  324. static inline int zend_symtable_update_current_key_ex(HashTable *ht, const char *arKey, uint nKeyLength, int mode, HashPosition *pos)
  325. {
  326. ZEND_HANDLE_NUMERIC(arKey, nKeyLength, zend_hash_update_current_key_ex(ht, HASH_KEY_IS_LONG, NULL, 0, idx, mode, pos));
  327. return zend_hash_update_current_key_ex(ht, HASH_KEY_IS_STRING, arKey, nKeyLength, 0, mode, pos);
  328. }
  329. #define zend_symtable_update_current_key(ht,arKey,nKeyLength,mode) \
  330. zend_symtable_update_current_key_ex(ht, arKey, nKeyLength, mode, NULL)
  331. #endif /* ZEND_HASH_H */
  332. /*
  333. * Local variables:
  334. * tab-width: 4
  335. * c-basic-offset: 4
  336. * indent-tabs-mode: t
  337. * End:
  338. */