PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/Zend/zend_hash.h

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