PageRenderTime 77ms CodeModel.GetById 31ms RepoModel.GetById 0ms app.codeStats 0ms

/gambas3-3.2.0/main/share/gb_hash_temp.h

#
C Header | 524 lines | 363 code | 120 blank | 41 comment | 51 complexity | a1a415d6ff6ec5eacdb800e862641885 MD5 | raw file
Possible License(s): GPL-2.0, GPL-3.0, LGPL-2.1
  1. /***************************************************************************
  2. gb_hash_temp.h
  3. (c) 2000-2012 Beno?Žt Minisini <gambas@users.sourceforge.net>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 2, or (at your option)
  7. any later version.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. GNU General Public License for more details.
  12. You should have received a copy of the GNU General Public License
  13. along with this program; if not, write to the Free Software
  14. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  15. MA 02110-1301, USA.
  16. ***************************************************************************/
  17. #define __GB_HASH_C
  18. #include <ctype.h>
  19. #include "gb_common.h"
  20. #include "gb_common_case.h"
  21. #include "gb_common_string.h"
  22. #include "gb_alloc.h"
  23. #include "gb_hash.h"
  24. #define NODE_value(_node) ((void *)((char *)_node) + sizeof(HASH_NODE))
  25. //#define NODE_length(_table, _node) (*((ushort *)(((char *)_node) + sizeof(HASH_NODE) + (_table)->s_value)))
  26. #define NODE_key(_table, _node) ((HASH_KEY *)(((char *)_node) + sizeof(HASH_NODE) + (_table)->s_value))
  27. static void hash_table_resize(HASH_TABLE *hash_table);
  28. static HASH_NODE **hash_table_lookup_node(HASH_TABLE *hash_table, const char *key, int len);
  29. static HASH_NODE *hash_node_new(HASH_TABLE *hash_table, const char *key, int len);
  30. static void hash_node_destroy(HASH_NODE *hash_node);
  31. #ifdef KEEP_ORDER
  32. #else
  33. static void hash_nodes_destroy(HASH_NODE *hash_node);
  34. #endif
  35. // Put a random number in that if you want to be safe on the Internet
  36. uint HASH_seed = 0x9A177BA5;
  37. static const int primes[] =
  38. {
  39. 11, 19, 37, 73, 109, 163, 251, 367, 557, 823, 1237, 1861, 2777, 4177, 6247, 9371,
  40. 14057, 21089, 31627, 47431, 71143, 106721, 160073, 240101, 360163, 540217, 810343,
  41. 1215497, 1823231, 2734867, 4102283, 6153409, 9230113, 13845163
  42. };
  43. //static const uint seed[] = { 0x9A177BA5, 0x9A177BA4, 0x9A177BA7, 0x9A177BA6, 0x9A177BA1, 0x9A177BA0, 0x9A177BA3, 0x9A177BA2, 0x9A177BAD };
  44. static const int nprimes = sizeof (primes) / sizeof (primes[0]);
  45. static int spaced_primes_closest(int num)
  46. {
  47. int i;
  48. for (i = 0; i < nprimes; i++)
  49. if (primes[i] > num)
  50. return primes[i];
  51. return primes[nprimes - 1];
  52. }
  53. // Fast hashing functions. Sometimes Microsoft Research produces useful things.
  54. static uint key_hash_binary(const char *key, int len)
  55. {
  56. static const void *jump[] = { &&__LEN_0, &&__LEN_1, &&__LEN_2, &&__LEN_3, &&__LEN_4, &&__LEN_5, &&__LEN_6, &&__LEN_7, &&__LEN_8 };
  57. uint seed = HASH_seed;
  58. uint hash = seed ^ len;
  59. if (len > 8)
  60. {
  61. key += len - 8;
  62. len = 8;
  63. }
  64. goto *jump[len];
  65. __LEN_8:
  66. hash = hash * seed + key[7];
  67. __LEN_7:
  68. hash = hash * seed + key[6];
  69. __LEN_6:
  70. hash = hash * seed + key[5];
  71. __LEN_5:
  72. hash = hash * seed + key[4];
  73. __LEN_4:
  74. hash = hash * seed + key[3];
  75. __LEN_3:
  76. hash = hash * seed + key[2];
  77. __LEN_2:
  78. hash = hash * seed + key[1];
  79. __LEN_1:
  80. hash = hash * seed + key[0];
  81. __LEN_0:
  82. return hash;
  83. }
  84. static uint key_hash_text(const char *key, int len)
  85. {
  86. static const void *jump[] = { &&__LEN_0, &&__LEN_1, &&__LEN_2, &&__LEN_3, &&__LEN_4, &&__LEN_5, &&__LEN_6, &&__LEN_7, &&__LEN_8 };
  87. uint seed = HASH_seed;
  88. uint hash = seed ^ len;
  89. if (len > 8)
  90. {
  91. key += len - 8;
  92. len = 8;
  93. }
  94. goto *jump[len];
  95. __LEN_8:
  96. hash = hash * seed + ((uint)key[7] & ~0x20U);
  97. __LEN_7:
  98. hash = hash * seed + ((uint)key[6] & ~0x20U);
  99. __LEN_6:
  100. hash = hash * seed + ((uint)key[5] & ~0x20U);
  101. __LEN_5:
  102. hash = hash * seed + ((uint)key[4] & ~0x20U);
  103. __LEN_4:
  104. hash = hash * seed + ((uint)key[3] & ~0x20U);
  105. __LEN_3:
  106. hash = hash * seed + ((uint)key[2] & ~0x20U);
  107. __LEN_2:
  108. hash = hash * seed + ((uint)key[1] & ~0x20U);
  109. __LEN_1:
  110. hash = hash * seed + ((uint)key[0] & ~0x20U);
  111. __LEN_0:
  112. return hash;
  113. }
  114. #define get_hash_func(_hash) ((_hash)->mode ? key_hash_text : key_hash_binary)
  115. void HASH_TABLE_create(HASH_TABLE **hash, size_t s_value, HASH_FLAG mode)
  116. {
  117. HASH_TABLE *hash_table;
  118. /*int i;*/
  119. ALLOC_ZERO(&hash_table, sizeof(HASH_TABLE), "HASH_TABLE_create");
  120. hash_table->size = HASH_TABLE_MIN_SIZE;
  121. hash_table->s_value = s_value;
  122. ALLOC_ZERO(&hash_table->nodes, sizeof(HASH_NODE *) * hash_table->size, "HASH_TABLE_create");
  123. if (mode == HF_IGNORE_CASE)
  124. hash_table->mode = mode;
  125. else
  126. hash_table->mode = HF_NORMAL;
  127. *hash = hash_table;
  128. }
  129. void HASH_TABLE_delete(HASH_TABLE **hash)
  130. {
  131. HASH_TABLE *hash_table = *hash;
  132. if (hash_table == NULL)
  133. return;
  134. #ifdef KEEP_ORDER
  135. HASH_NODE *node, *next;
  136. node = hash_table->sfirst;
  137. hash_table->sfirst = NULL;
  138. hash_table->slast = NULL;
  139. while (node)
  140. {
  141. next = node->snext;
  142. FREE(&node, "HASH_TABLE_delete");
  143. node = next;
  144. }
  145. #else
  146. int i;
  147. for (i = 0; i < hash_table->size; i++)
  148. hash_nodes_destroy(hash_table->nodes[i]);
  149. #endif
  150. FREE(&hash_table->nodes, "HASH_TABLE_delete");
  151. FREE(hash, "HASH_TABLE_delete");
  152. }
  153. int HASH_TABLE_size(HASH_TABLE *hash_table)
  154. {
  155. return hash_table->nnodes;
  156. }
  157. static HASH_NODE **hash_table_lookup_node(HASH_TABLE *hash_table, const char *key, int len)
  158. {
  159. HASH_NODE **node;
  160. HASH_KEY *node_key;
  161. uint hash;
  162. //int n;
  163. if (hash_table->mode)
  164. {
  165. hash = key_hash_text(key, len);
  166. node = &hash_table->nodes[hash % hash_table->size];
  167. //n = 0;
  168. while (*node)
  169. {
  170. node_key = NODE_key(hash_table, *node);
  171. //n++;
  172. if (node_key->len == len && STRING_equal_ignore_case_same(key, node_key->key, len))
  173. break;
  174. node = &(*node)->next;
  175. }
  176. }
  177. else
  178. {
  179. hash = key_hash_binary(key, len);
  180. node = &hash_table->nodes[hash % hash_table->size];
  181. //n = 0;
  182. while (*node)
  183. {
  184. node_key = NODE_key(hash_table, *node);
  185. //n++;
  186. if (node_key->len == len && STRING_equal_same(key, node_key->key, len))
  187. break;
  188. node = &(*node)->next;
  189. }
  190. }
  191. //fprintf(stderr, "hash_table_lookup_node %p: %d %d -> %d\n", hash_table, hash_table->size, hash_table->nnodes, n);
  192. return node;
  193. }
  194. void *HASH_TABLE_lookup(HASH_TABLE *hash_table, const char *key, int len)
  195. {
  196. HASH_NODE *node;
  197. if (len == 0)
  198. return NULL;
  199. node = *hash_table_lookup_node(hash_table, key, len);
  200. hash_table->last = node;
  201. return node ? NODE_value(node) : NULL;
  202. }
  203. void *HASH_TABLE_insert(HASH_TABLE *hash_table, const char *key, int len)
  204. {
  205. HASH_NODE **node;
  206. void *value;
  207. node = hash_table_lookup_node(hash_table, key, len);
  208. if (UNLIKELY(*node != NULL))
  209. return NODE_value(*node);
  210. *node = hash_node_new(hash_table, key, len);
  211. hash_table->nnodes++;
  212. /*if (!hash_table->frozen)*/
  213. value = NODE_value(*node);
  214. hash_table_resize(hash_table);
  215. return value;
  216. }
  217. void HASH_TABLE_remove(HASH_TABLE *hash_table, const char *key, int len)
  218. {
  219. HASH_NODE **node, *dest;
  220. node = hash_table_lookup_node(hash_table, key, len);
  221. if (LIKELY(*node != NULL))
  222. {
  223. dest = *node;
  224. (*node) = dest->next;
  225. #ifdef KEEP_ORDER
  226. if (dest->sprev)
  227. dest->sprev->snext = dest->snext;
  228. else
  229. hash_table->sfirst = dest->snext;
  230. if (dest->snext)
  231. dest->snext->sprev = dest->sprev;
  232. else
  233. hash_table->slast = dest->sprev;
  234. #endif
  235. hash_node_destroy(dest);
  236. hash_table->nnodes--;
  237. hash_table->last = NULL;
  238. /*if (!hash_table->frozen)*/
  239. hash_table_resize(hash_table);
  240. }
  241. }
  242. void *HASH_TABLE_next(HASH_TABLE *hash_table, HASH_ENUM *iter)
  243. {
  244. #ifdef KEEP_ORDER
  245. if (iter->node == NULL)
  246. iter->node = hash_table->sfirst;
  247. else
  248. iter->node = iter->next;
  249. hash_table->last = iter->node;
  250. if (iter->node)
  251. {
  252. iter->next = iter->node->snext;
  253. return NODE_value(iter->node);
  254. }
  255. else
  256. return NULL;
  257. #else
  258. HASH_NODE *enum_node = iter->node;
  259. int enum_i = iter->index;
  260. if (enum_node)
  261. enum_node = enum_node->next;
  262. while (enum_node == NULL)
  263. {
  264. enum_i++;
  265. if (enum_i >= hash_table->size)
  266. break;
  267. enum_node = hash_table->nodes[enum_i];
  268. };
  269. iter->node = enum_node;
  270. iter->index = enum_i;
  271. hash_table->last = enum_node;
  272. if (enum_node)
  273. return NODE_value(enum_node);
  274. else
  275. return NULL;
  276. #endif
  277. }
  278. #if 0
  279. static void dump_hash_table(HASH_TABLE *hash_table)
  280. {
  281. int i;
  282. HASH_NODE *node;
  283. HASH_KEY *node_key;
  284. for (i = 0; i < hash_table->size; i++)
  285. {
  286. fprintf(stderr, "%5d: ", i);
  287. for (node = hash_table->nodes[i]; node; node = node->next)
  288. {
  289. node_key = NODE_key(hash_table, node);
  290. fprintf(stderr, "%.*s ", node_key->len, node_key->key);
  291. }
  292. fprintf(stderr, "\n");
  293. }
  294. fprintf(stderr, "\n");
  295. }
  296. #endif
  297. static void hash_table_resize(HASH_TABLE *hash_table)
  298. {
  299. HASH_NODE **old_nodes;
  300. HASH_NODE **new_nodes;
  301. HASH_NODE *node;
  302. HASH_NODE *next;
  303. HASH_KEY *node_key;
  304. int hash_val;
  305. int new_size;
  306. int i;
  307. HASH_FUNC hash_func = get_hash_func(hash_table);
  308. if (!((hash_table->size >= 3 * hash_table->nnodes && hash_table->size > HASH_TABLE_MIN_SIZE) ||
  309. (3 * hash_table->size <= hash_table->nnodes && hash_table->size < HASH_TABLE_MAX_SIZE)))
  310. return;
  311. new_size = MinMax(spaced_primes_closest(hash_table->nnodes), HASH_TABLE_MIN_SIZE, HASH_TABLE_MAX_SIZE);
  312. //fprintf(stderr, "**** hash_table_resize %p %d: %d -> %d\n", hash_table, hash_table->nnodes, hash_table->size, new_size);
  313. //fprintf(stderr, "BEFORE:\n");
  314. //dump_hash_table(hash_table);
  315. old_nodes = hash_table->nodes;
  316. ALLOC_ZERO(&new_nodes, new_size * sizeof(HASH_NODE *), "hash_table_resize");
  317. for (i = 0; i < hash_table->size; i++)
  318. for (node = hash_table->nodes[i]; node; node = next)
  319. {
  320. next = node->next;
  321. node_key = NODE_key(hash_table, node);
  322. hash_val = (*hash_func)(node_key->key, node_key->len) % new_size;
  323. node->next = new_nodes[hash_val];
  324. new_nodes[hash_val] = node;
  325. }
  326. FREE(&old_nodes, "hash_table_resize");
  327. hash_table->nodes = new_nodes;
  328. hash_table->size = new_size;
  329. //fprintf(stderr, "AFTER:\n");
  330. //dump_hash_table(hash_table);
  331. }
  332. static HASH_NODE *hash_node_new(HASH_TABLE *hash_table, const char *key, int len)
  333. {
  334. HASH_NODE *hash_node;
  335. int size;
  336. HASH_KEY *node_key;
  337. if (len > 65535)
  338. len = 65535;
  339. size = sizeof(HASH_NODE) + hash_table->s_value + sizeof(HASH_KEY) + len;
  340. ALLOC_ZERO(&hash_node, size, "hash_node_new");
  341. node_key = NODE_key(hash_table, hash_node);
  342. memcpy(node_key->key, key, len);
  343. node_key->len = len;
  344. //node_key->hash = hash_table->mode ? key_hash_text(key, len) : key_hash_binary(key, len);
  345. #ifdef KEEP_ORDER
  346. if (UNLIKELY(!hash_table->sfirst))
  347. {
  348. hash_table->sfirst = hash_node;
  349. hash_table->slast = hash_node;
  350. }
  351. else
  352. {
  353. hash_node->sprev = hash_table->slast;
  354. hash_node->sprev->snext = hash_node;
  355. hash_table->slast = hash_node;
  356. }
  357. #endif
  358. return hash_node;
  359. }
  360. static void hash_node_destroy(HASH_NODE *hash_node)
  361. {
  362. FREE(&hash_node, "hash_node_destroy");
  363. }
  364. #ifdef KEEP_ORDER
  365. #else
  366. static void hash_nodes_destroy(HASH_NODE *hash_node)
  367. {
  368. HASH_NODE *node = hash_node;
  369. HASH_NODE *next;
  370. for(;;)
  371. {
  372. if (UNLIKELY(node == NULL))
  373. return;
  374. next = node->next;
  375. FREE(&node, "hash_nodes_destroy");
  376. node = next;
  377. }
  378. }
  379. #endif
  380. void HASH_TABLE_get_key(HASH_TABLE *hash_table, HASH_NODE *node, char **key, int *len)
  381. {
  382. HASH_KEY *node_key;
  383. if (LIKELY(node != NULL))
  384. {
  385. node_key = NODE_key(hash_table, node);
  386. *key = node_key->key;
  387. *len = node_key->len;
  388. }
  389. else
  390. *len = 0;
  391. }
  392. bool HASH_TABLE_get_last_key(HASH_TABLE *hash_table, char **key, int *len)
  393. {
  394. if (hash_table->last == NULL)
  395. return TRUE;
  396. HASH_TABLE_get_key(hash_table, hash_table->last, key, len);
  397. return FALSE;
  398. }