vtv_set.h 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654
  1. /* Copyright (C) 2012-2013
  2. Free Software Foundation
  3. This file is part of GCC.
  4. GCC is free software; you can redistribute it and/or modify it
  5. under the terms of the GNU General Public License as published by
  6. the Free Software Foundation; either version 3, or (at your option)
  7. any later version.
  8. GCC is distributed in the hope that it will be useful, but WITHOUT
  9. ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  10. or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
  11. License for more details.
  12. Under Section 7 of GPL version 3, you are granted additional
  13. permissions described in the GCC Runtime Library Exception, version
  14. 3.1, as published by the Free Software Foundation.
  15. You should have received a copy of the GNU General Public License
  16. and a copy of the GCC Runtime Library Exception along with this
  17. program; see the files COPYING3 and COPYING.RUNTIME respectively.
  18. If not, see <http://www.gnu.org/licenses/>. */
  19. #ifndef _VTV_SET_H
  20. #define _VTV_SET_H 1
  21. /* Code in this file manages a collection of insert-only sets. We
  22. have only tested the case where Key is uintptr_t, though it
  23. theoretically should work for some other cases. All odd keys are
  24. reserved, and must not be inserted into any of the sets. This code
  25. is intended primarily for sets of pointers, and the code is
  26. optimized for small sets (including size 0 and 1), but regardless
  27. of the set size, insert() and contains() have close to O(1) speed
  28. in practice.
  29. TODO(gpike): fix this comment.
  30. Recommended multithreaded use of a set:
  31. For speed, we want to use a lock-free test for set membership. The
  32. code handles simultaneous reads and inserts, as long as at most one
  33. insertion is in progress at a time. After an insert, other threads
  34. may not immediately "see" the inserted key if they perform a
  35. lock-free read, so we recommend retrying, as explained below.
  36. Also, to make data corruption less likely, we recommend using a
  37. "normal" RW page as well as one or pages that are typically RO
  38. but that can be switched to RW and back as needed. The latter
  39. pages should contain sets. The former should contain a lock, L,
  40. and an int or similar, num_writers. Then, to insert, something
  41. like this would be safe:
  42. o Acquire L.
  43. o Increment num_writers; if that made it 1, change pages to RW.
  44. o Release L.
  45. o while (there are insertions to do in some set, S) {
  46. acquire L;
  47. do some insertions in S;
  48. release L;
  49. }
  50. o Acquire L.
  51. o Decrement num_writers; if that made it 0, change pages to RO.
  52. o Release L.
  53. And to check if the set contains some key, one could use
  54. set.contains(key) ||
  55. ({ Acquire L; bool b = set.contains(key); Release L; b; })
  56. In this scheme, the number of threads with reads in progress isn't
  57. tracked, so old sets can never be deleted. In addition, on some
  58. architectures the intentionally racy reads might cause contains()
  59. to return true when it should have returned false. This should be
  60. no problem on x86, and most other machines, where reading or
  61. writing an aligned uintptr_t is atomic. E.g., on those machines,
  62. if *p is 0 and one thread does *p = x while another reads *p, the
  63. read will see either 0 or x.
  64. To make the above easier, the insert_only_hash_sets class provides
  65. an interface to manipulate any number of hash sets. One shouldn't
  66. create objects of that class, as it has no member data and its
  67. methods are static.
  68. So the recommended model is to have a single lock, a single
  69. num_writers variable, and some number of sets. If lock contention
  70. becomes a problem then the sets can be divided into k groups, each
  71. of which has a lock and a num_writers variable; or each set can be
  72. represented as a set of values that equal 0 mod m, a set of values
  73. that equal 1 mod m, ..., plus a set of values that equal m-1 mod m.
  74. However, we expect most or all uses of this code to call contains()
  75. much more frequently than anything else, so lock contention is
  76. likely to be low. */
  77. #include <algorithm>
  78. #ifndef HASHTABLE_STATS
  79. #define HASHTABLE_STATS 0
  80. #endif
  81. #ifndef HASHTABLE_STATS_ATOMIC
  82. #define HASHTABLE_STATS_ATOMIC 0
  83. #endif
  84. #if HASHTABLE_STATS
  85. #if HASHTABLE_STATS_ATOMIC
  86. /* Stat counters, with atomics. */
  87. #include <bits/atomic_word.h>
  88. typedef _Atomic_word _AtomicStatCounter;
  89. void
  90. inc_by (_AtomicStatCounter &stat, int amount)
  91. {
  92. __atomic_add_fetch (&stat, amount, __ATOMIC_ACQ_REL);
  93. }
  94. #else
  95. /* Stat counters, but without atomics. */
  96. typedef int _AtomicStatCounter;
  97. void
  98. inc_by (_AtomicStatCounter& stat, int amount)
  99. {
  100. stat += amount;
  101. }
  102. #endif
  103. /* Number of calls to contains(), insert(), etc. */
  104. extern _AtomicStatCounter stat_insert;
  105. extern _AtomicStatCounter stat_contains;
  106. extern _AtomicStatCounter stat_resize;
  107. extern _AtomicStatCounter stat_create;
  108. /* Sum of set size over all calls to contains(). */
  109. extern _AtomicStatCounter stat_contains_sizes;
  110. /* contains() calls in a set whose capacity is more than 1. */
  111. extern _AtomicStatCounter stat_contains_in_non_trivial_set;
  112. /* Probes in a set whose capacity is more than 1. Ideally, this will
  113. be pretty close to stat_contains_in_non_trivial_set. That will
  114. happen if our hash function is good and/or important keys were
  115. inserted before unimportant keys. */
  116. extern _AtomicStatCounter stat_probes_in_non_trivial_set;
  117. /* number of calls to contains() with size=0, 1, etc. */
  118. extern _AtomicStatCounter stat_contains_size0;
  119. extern _AtomicStatCounter stat_contains_size1;
  120. extern _AtomicStatCounter stat_contains_size2;
  121. extern _AtomicStatCounter stat_contains_size3;
  122. extern _AtomicStatCounter stat_contains_size4;
  123. extern _AtomicStatCounter stat_contains_size5;
  124. extern _AtomicStatCounter stat_contains_size6;
  125. extern _AtomicStatCounter stat_contains_size7;
  126. extern _AtomicStatCounter stat_contains_size8;
  127. extern _AtomicStatCounter stat_contains_size9;
  128. extern _AtomicStatCounter stat_contains_size10;
  129. extern _AtomicStatCounter stat_contains_size11;
  130. extern _AtomicStatCounter stat_contains_size12;
  131. extern _AtomicStatCounter stat_contains_size13_or_more;
  132. extern _AtomicStatCounter stat_grow_from_size0_to_1;
  133. extern _AtomicStatCounter stat_grow_from_size1_to_2;
  134. extern _AtomicStatCounter stat_double_the_number_of_buckets;
  135. extern _AtomicStatCounter stat_insert_key_that_was_already_present;
  136. /* Hash collisions detected during insert_no_resize(). Only counts
  137. hasher(k) == hasher(k'); hasher(k) % tablesize == hasher(k') %
  138. tablesize is not sufficient. Will count collisions that are
  139. detected during table resizes etc., so the same two keys may add to
  140. this stat multiple times. */
  141. extern _AtomicStatCounter stat_insert_found_hash_collision;
  142. #include <string>
  143. struct insert_only_hash_sets_logger
  144. {
  145. static char *
  146. log (char c, char *buf)
  147. {
  148. *buf++ = c;
  149. return buf;
  150. }
  151. static char *
  152. log (const char *s, char *buf)
  153. { return strcpy (buf, s) + strlen (s); }
  154. static char *
  155. log (_AtomicStatCounter i, char *buf)
  156. {
  157. if (i < 10)
  158. return log ((char) ('0' + i), buf);
  159. else
  160. return log ((char) ('0' + i % 10), log (i / 10, buf));
  161. }
  162. static char *
  163. log (const char *label, _AtomicStatCounter i, char *buf)
  164. {
  165. buf = log (label, buf);
  166. buf = log (": ", buf);
  167. buf = log (i, buf);
  168. return log ('\n', buf);
  169. }
  170. };
  171. // Write stats to the given buffer, which should be at least 4000 bytes.
  172. static inline void
  173. insert_only_hash_tables_stats (char *buf)
  174. {
  175. buf = insert_only_hash_sets_logger::log ("insert", stat_insert, buf);
  176. buf = insert_only_hash_sets_logger::log ("contains", stat_contains, buf);
  177. buf = insert_only_hash_sets_logger::log ("resize", stat_resize, buf);
  178. buf = insert_only_hash_sets_logger::log ("create", stat_create, buf);
  179. buf = insert_only_hash_sets_logger::log ("insert_key_that_was_already_"
  180. "present",
  181. stat_insert_key_that_was_already_present,
  182. buf);
  183. buf = insert_only_hash_sets_logger::log ("contains_sizes",
  184. stat_contains_sizes, buf);
  185. buf = insert_only_hash_sets_logger::log ("contains_in_non_trivial_set",
  186. stat_contains_in_non_trivial_set,
  187. buf);
  188. buf = insert_only_hash_sets_logger::log ("probes_in_non_trivial_set",
  189. stat_probes_in_non_trivial_set,
  190. buf);
  191. buf = insert_only_hash_sets_logger::log ("contains_size0",
  192. stat_contains_size0, buf);
  193. buf = insert_only_hash_sets_logger::log ("contains_size1",
  194. stat_contains_size1, buf);
  195. buf = insert_only_hash_sets_logger::log ("contains_size2",
  196. stat_contains_size2, buf);
  197. buf = insert_only_hash_sets_logger::log ("contains_size3",
  198. stat_contains_size3, buf);
  199. buf = insert_only_hash_sets_logger::log ("contains_size4",
  200. stat_contains_size4, buf);
  201. buf = insert_only_hash_sets_logger::log ("contains_size5",
  202. stat_contains_size5, buf);
  203. buf = insert_only_hash_sets_logger::log ("contains_size6",
  204. stat_contains_size6, buf);
  205. buf = insert_only_hash_sets_logger::log ("contains_size7",
  206. stat_contains_size7, buf);
  207. buf = insert_only_hash_sets_logger::log ("contains_size8",
  208. stat_contains_size8, buf);
  209. buf = insert_only_hash_sets_logger::log ("contains_size9",
  210. stat_contains_size9, buf);
  211. buf = insert_only_hash_sets_logger::log ("contains_size10",
  212. stat_contains_size10, buf);
  213. buf = insert_only_hash_sets_logger::log ("contains_size11",
  214. stat_contains_size11, buf);
  215. buf = insert_only_hash_sets_logger::log ("contains_size12",
  216. stat_contains_size12, buf);
  217. buf = insert_only_hash_sets_logger::log ("contains_size13_or_more",
  218. stat_contains_size13_or_more, buf);
  219. buf = insert_only_hash_sets_logger::log ("grow_from_size0_to_1",
  220. stat_grow_from_size0_to_1, buf);
  221. buf = insert_only_hash_sets_logger::log ("grow_from_size1_to_2",
  222. stat_grow_from_size1_to_2, buf);
  223. buf = insert_only_hash_sets_logger::log ("insert_found_hash_collision",
  224. stat_insert_found_hash_collision,
  225. buf);
  226. buf = insert_only_hash_sets_logger::log ("double_the_number_of_buckets",
  227. stat_double_the_number_of_buckets,
  228. buf);
  229. *buf = '\0';
  230. }
  231. #else
  232. /* No stats. */
  233. #define inc_by(statname, amount) do { } while (false && (amount))
  234. #endif
  235. #define inc(statname) inc_by (statname, 1)
  236. template <typename Key, class HashFcn, class Alloc>
  237. class insert_only_hash_sets
  238. {
  239. public:
  240. typedef Key key_type;
  241. typedef size_t size_type;
  242. typedef Alloc alloc_type;
  243. enum { illegal_key = 1 };
  244. enum { min_capacity = 4 };
  245. #if HASHTABLE_STATS
  246. enum { stats = true };
  247. #else
  248. enum { stats = false };
  249. #endif
  250. /* Do not directly use insert_only_hash_set. Instead, use the
  251. static methods below to create and manipulate objects of the
  252. following class.
  253. Implementation details: each set is represented by a pointer
  254. plus, perhaps, out-of-line data, which would be an object of type
  255. insert_only_hash_set. For a pointer, s, the interpretation is: s
  256. == NULL means empty set, lsb(s) == 1 means a set with one
  257. element, which is (uintptr_t)s - 1, and otherwise s is a pointer
  258. of type insert_only_hash_set*. So, to increase the size of a set
  259. we have to change s and/or *s. To check if a set contains some
  260. key we have to examine s and possibly *s. */
  261. class insert_only_hash_set
  262. {
  263. public:
  264. /* Insert a key. The key must not be a reserved key. */
  265. static inline insert_only_hash_set *insert (key_type key,
  266. insert_only_hash_set *s);
  267. /* Create an empty set. */
  268. static inline insert_only_hash_set *create (size_type capacity);
  269. /* Return whether the given key is present. If key is illegal_key
  270. then either true or false may be returned, but for all other
  271. reserved keys false will be returned. */
  272. static bool
  273. contains (key_type key, const insert_only_hash_set *s)
  274. {
  275. if (stats)
  276. {
  277. inc (stat_contains);
  278. switch (size (s))
  279. {
  280. case 0: inc (stat_contains_size0); break;
  281. case 1: inc (stat_contains_size1); break;
  282. case 2: inc (stat_contains_size2); break;
  283. case 3: inc (stat_contains_size3); break;
  284. case 4: inc (stat_contains_size4); break;
  285. case 5: inc (stat_contains_size5); break;
  286. case 6: inc (stat_contains_size6); break;
  287. case 7: inc (stat_contains_size7); break;
  288. case 8: inc (stat_contains_size8); break;
  289. case 9: inc (stat_contains_size9); break;
  290. case 10: inc (stat_contains_size10); break;
  291. case 11: inc (stat_contains_size11); break;
  292. case 12: inc (stat_contains_size12); break;
  293. default: inc (stat_contains_size13_or_more); break;
  294. }
  295. inc_by (stat_contains_sizes, size (s));
  296. }
  297. return (singleton (s) ?
  298. singleton_key (key) == s :
  299. ((s != NULL) && s->contains (key)));
  300. }
  301. /* Return a set's size. */
  302. static size_type
  303. size (const insert_only_hash_set *s)
  304. { return (s == NULL) ? 0 : (singleton (s) ? 1 : s->num_entries); }
  305. static inline insert_only_hash_set *resize (size_type target_num_buckets,
  306. insert_only_hash_set *s);
  307. private:
  308. /* Return whether a set has size 1. */
  309. static bool
  310. singleton (const insert_only_hash_set *s)
  311. { return (uintptr_t) s & 1; }
  312. /* Return the representation of a singleton set containing the
  313. given key. */
  314. static insert_only_hash_set *
  315. singleton_key (key_type key)
  316. { return (insert_only_hash_set *) ((uintptr_t) key + 1); }
  317. /* Given a singleton set, what key does it contain? */
  318. static key_type
  319. extract_singleton_key (const insert_only_hash_set *s)
  320. {
  321. VTV_DEBUG_ASSERT (singleton (s));
  322. return (key_type) ((uintptr_t) s - 1);
  323. }
  324. volatile key_type &
  325. key_at_index (size_type index)
  326. { return buckets[index]; }
  327. key_type
  328. key_at_index (size_type index) const
  329. { return buckets[index]; }
  330. size_type
  331. next_index (size_type index, size_type indices_examined) const
  332. { return (index + indices_examined) & (num_buckets - 1); }
  333. inline void insert_no_resize (key_type key);
  334. inline bool contains (key_type key) const;
  335. inline insert_only_hash_set *resize_if_necessary (void);
  336. size_type num_buckets; /* Must be a power of 2 not less than
  337. min_capacity. */
  338. volatile size_type num_entries;
  339. volatile key_type buckets[0]; /* Actual array size is num_buckets. */
  340. };
  341. /* Create an empty set with the given capacity. Requires that n be
  342. 0 or a power of 2. If 1 < n < min_capacity then treat n as
  343. min_capacity. Sets *handle. Returns true unless the allocator
  344. fails. Subsequent operations on this set should use the same
  345. handle. */
  346. static inline bool create (size_type n, insert_only_hash_set **handle);
  347. /* Force the capacity of a set to be n, unless it was more than n
  348. already. Requires that n be 0 or a power of 2. Sets *handle
  349. unless the current capacity is n or more. Returns true unless
  350. the allocator fails. */
  351. static inline bool resize (size_type n, insert_only_hash_set **handle);
  352. /* Insert a key. *handle is unmodified unless (1) a resize occurs,
  353. or (2) the set was initially empty. Returns true unless the
  354. allocator fails during a resize. If the allocator fails during a
  355. resize then the set is reset to be the empty set. The key must
  356. not be a reserved key. */
  357. static inline bool insert (key_type key, insert_only_hash_set **handle);
  358. /* Check for the presence of a key. If key is illegal_key then
  359. either true or false may be returned, but for all other reserved
  360. keys false will be returned. */
  361. static inline bool
  362. contains (key_type key, /* const */ insert_only_hash_set **handle)
  363. { return insert_only_hash_set::contains (key, *handle); }
  364. /* Return the size of the given set. */
  365. static size_type
  366. size (const insert_only_hash_set **handle)
  367. { return insert_only_hash_set::size (*handle); }
  368. static bool
  369. is_reserved_key (key_type key)
  370. { return ((uintptr_t) key % 2) == 1; }
  371. };
  372. template <typename Key, class HashFcn, class Alloc>
  373. typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
  374. insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::resize
  375. (size_type n, insert_only_hash_set *s)
  376. {
  377. if (s == NULL)
  378. return create (n);
  379. size_type capacity = singleton (s) ? 1 : s->num_buckets;
  380. if (n <= capacity)
  381. return s;
  382. insert_only_hash_set *result =
  383. create (std::max<size_type> (n, min_capacity));
  384. if (result != NULL)
  385. {
  386. if (singleton (s))
  387. {
  388. result->insert_no_resize (extract_singleton_key (s));
  389. }
  390. else
  391. {
  392. for (size_type i = 0; i < s->num_buckets; i++)
  393. if (s->buckets[i] != (key_type) illegal_key)
  394. result->insert_no_resize (s->buckets[i]);
  395. }
  396. VTV_DEBUG_ASSERT (size (result) == size (s));
  397. }
  398. return result;
  399. }
  400. template <typename Key, class HashFcn, class Alloc>
  401. typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
  402. insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::insert
  403. (key_type key, insert_only_hash_set *s)
  404. {
  405. VTV_DEBUG_ASSERT (!is_reserved_key (key));
  406. inc_by (stat_grow_from_size0_to_1, s == NULL);
  407. if (s == NULL)
  408. return singleton_key (key);
  409. if (singleton (s))
  410. {
  411. const key_type old_key = extract_singleton_key (s);
  412. if (old_key == key)
  413. return s;
  414. /* Grow from size 1 to size 2. */
  415. inc (stat_grow_from_size1_to_2);
  416. s = create (2);
  417. if (s == NULL)
  418. return NULL;
  419. s->insert_no_resize (old_key);
  420. s->insert_no_resize (key);
  421. VTV_DEBUG_ASSERT (size (s) == 2);
  422. return s;
  423. }
  424. s = s->resize_if_necessary();
  425. if (s != NULL)
  426. s->insert_no_resize (key);
  427. return s;
  428. }
  429. template <typename Key, class HashFcn, class Alloc>
  430. typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
  431. insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set::create
  432. (size_type capacity)
  433. {
  434. if (capacity <= 1)
  435. return NULL;
  436. VTV_DEBUG_ASSERT (capacity > 1 && (capacity & (capacity - 1)) == 0);
  437. VTV_DEBUG_ASSERT (sizeof (insert_only_hash_set) == 2 * sizeof (size_type));
  438. capacity = std::max <size_type> (capacity, min_capacity);
  439. const size_t num_bytes = sizeof (insert_only_hash_set) +
  440. sizeof (key_type) * capacity;
  441. alloc_type alloc;
  442. insert_only_hash_set *result = (insert_only_hash_set *) alloc (num_bytes);
  443. result->num_buckets = capacity;
  444. result->num_entries = 0;
  445. for (size_type i = 0; i < capacity; i++)
  446. result->buckets[i] = (key_type) illegal_key;
  447. return result;
  448. }
  449. template <typename Key, class HashFcn, class Alloc>
  450. void
  451. insert_only_hash_sets<Key, HashFcn,
  452. Alloc>::insert_only_hash_set::insert_no_resize
  453. (key_type key)
  454. {
  455. HashFcn hasher;
  456. const size_type capacity = num_buckets;
  457. VTV_DEBUG_ASSERT (capacity >= min_capacity);
  458. VTV_DEBUG_ASSERT (!is_reserved_key (key));
  459. size_type index = hasher (key) & (capacity - 1);
  460. key_type k = key_at_index (index);
  461. size_type indices_examined = 0;
  462. while (k != key)
  463. {
  464. ++indices_examined;
  465. if (k == (key_type) illegal_key)
  466. {
  467. key_at_index (index) = key;
  468. ++num_entries;
  469. return;
  470. }
  471. else
  472. {
  473. inc_by (stat_insert_found_hash_collision,
  474. hasher (k) == hasher (key));
  475. }
  476. VTV_DEBUG_ASSERT (indices_examined < capacity);
  477. index = next_index (index, indices_examined);
  478. k = key_at_index (index);
  479. }
  480. }
  481. template<typename Key, class HashFcn, class Alloc>
  482. bool
  483. insert_only_hash_sets<Key, HashFcn, Alloc>::insert_only_hash_set::contains
  484. (key_type key) const
  485. {
  486. inc (stat_contains_in_non_trivial_set);
  487. HashFcn hasher;
  488. const size_type capacity = num_buckets;
  489. size_type index = hasher (key) & (capacity - 1);
  490. key_type k = key_at_index (index);
  491. size_type indices_examined = 0;
  492. inc (stat_probes_in_non_trivial_set);
  493. while (k != key)
  494. {
  495. ++indices_examined;
  496. if (/*UNLIKELY*/(k == (key_type) illegal_key
  497. || indices_examined == capacity))
  498. return false;
  499. index = next_index (index, indices_examined);
  500. k = key_at_index (index);
  501. inc (stat_probes_in_non_trivial_set);
  502. }
  503. return true;
  504. }
  505. template <typename Key, class HashFcn, class Alloc>
  506. typename insert_only_hash_sets <Key, HashFcn, Alloc>::insert_only_hash_set *
  507. insert_only_hash_sets<Key, HashFcn,
  508. Alloc>::insert_only_hash_set::resize_if_necessary (void)
  509. {
  510. VTV_DEBUG_ASSERT (num_buckets >= min_capacity);
  511. size_type unused = num_buckets - num_entries;
  512. if (unused < (num_buckets >> 2))
  513. {
  514. inc (stat_double_the_number_of_buckets);
  515. size_type new_num_buckets = num_buckets * 2;
  516. insert_only_hash_set *s = create (new_num_buckets);
  517. for (size_type i = 0; i < num_buckets; i++)
  518. if (buckets[i] != (key_type) illegal_key)
  519. s->insert_no_resize (buckets[i]);
  520. VTV_DEBUG_ASSERT (size (this) == size (s));
  521. return s;
  522. }
  523. else
  524. return this;
  525. }
  526. template<typename Key, class HashFcn, class Alloc>
  527. bool
  528. insert_only_hash_sets<Key, HashFcn, Alloc>::create (size_type n,
  529. insert_only_hash_set **handle)
  530. {
  531. inc (stat_create);
  532. *handle = insert_only_hash_set::create (n);
  533. return (n <= 1) || (*handle != NULL);
  534. }
  535. template<typename Key, class HashFcn, class Alloc>
  536. bool
  537. insert_only_hash_sets<Key, HashFcn, Alloc>::resize (size_type n,
  538. insert_only_hash_set **handle)
  539. {
  540. inc (stat_resize);
  541. *handle = insert_only_hash_set::resize (n, *handle);
  542. return (n <= 1) || (*handle != NULL);
  543. }
  544. template<typename Key, class HashFcn, class Alloc>
  545. bool
  546. insert_only_hash_sets<Key, HashFcn, Alloc>::insert (key_type key,
  547. insert_only_hash_set **handle)
  548. {
  549. inc (stat_insert);
  550. const size_type old_size = insert_only_hash_set::size (*handle);
  551. *handle = insert_only_hash_set::insert (key, *handle);
  552. if (*handle != NULL)
  553. {
  554. const size_type delta = insert_only_hash_set::size (*handle) - old_size;
  555. inc_by (stat_insert_key_that_was_already_present, delta == 0);
  556. }
  557. return *handle != NULL;
  558. }
  559. #endif /* VTV_SET_H */