basisu_containers_impl.h 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311
  1. // basisu_containers_impl.h
  2. // Do not include directly
  3. #ifdef _MSC_VER
  4. #pragma warning (disable:4127) // warning C4127: conditional expression is constant
  5. #endif
  6. namespace basisu
  7. {
  8. bool elemental_vector::increase_capacity(uint32_t min_new_capacity, bool grow_hint, uint32_t element_size, object_mover pMover, bool nofail)
  9. {
  10. assert(m_size <= m_capacity);
  11. if (sizeof(void *) == sizeof(uint64_t))
  12. assert(min_new_capacity < (0x400000000ULL / element_size));
  13. else
  14. assert(min_new_capacity < (0x7FFF0000U / element_size));
  15. if (m_capacity >= min_new_capacity)
  16. return true;
  17. size_t new_capacity = min_new_capacity;
  18. if ((grow_hint) && (!helpers::is_power_of_2((uint64_t)new_capacity)))
  19. {
  20. new_capacity = (size_t)helpers::next_pow2((uint64_t)new_capacity);
  21. assert(new_capacity && (new_capacity > m_capacity));
  22. if (new_capacity < min_new_capacity)
  23. {
  24. if (nofail)
  25. return false;
  26. fprintf(stderr, "vector too large\n");
  27. abort();
  28. }
  29. }
  30. const size_t desired_size = element_size * new_capacity;
  31. size_t actual_size = 0;
  32. if (!pMover)
  33. {
  34. void* new_p = realloc(m_p, desired_size);
  35. if (!new_p)
  36. {
  37. if (nofail)
  38. return false;
  39. char buf[256];
  40. #ifdef _MSC_VER
  41. sprintf_s(buf, sizeof(buf), "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
  42. #else
  43. sprintf(buf, "vector: realloc() failed allocating %u bytes", (uint32_t)desired_size);
  44. #endif
  45. fprintf(stderr, "%s", buf);
  46. abort();
  47. }
  48. #ifdef _MSC_VER
  49. actual_size = _msize(new_p);
  50. #elif HAS_MALLOC_USABLE_SIZE
  51. actual_size = malloc_usable_size(new_p);
  52. #else
  53. actual_size = desired_size;
  54. #endif
  55. m_p = new_p;
  56. }
  57. else
  58. {
  59. void* new_p = malloc(desired_size);
  60. if (!new_p)
  61. {
  62. if (nofail)
  63. return false;
  64. char buf[256];
  65. #ifdef _MSC_VER
  66. sprintf_s(buf, sizeof(buf), "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
  67. #else
  68. sprintf(buf, "vector: malloc() failed allocating %u bytes", (uint32_t)desired_size);
  69. #endif
  70. fprintf(stderr, "%s", buf);
  71. abort();
  72. }
  73. #ifdef _MSC_VER
  74. actual_size = _msize(new_p);
  75. #elif HAS_MALLOC_USABLE_SIZE
  76. actual_size = malloc_usable_size(new_p);
  77. #else
  78. actual_size = desired_size;
  79. #endif
  80. (*pMover)(new_p, m_p, m_size);
  81. if (m_p)
  82. free(m_p);
  83. m_p = new_p;
  84. }
  85. if (actual_size > desired_size)
  86. m_capacity = static_cast<uint32_t>(actual_size / element_size);
  87. else
  88. m_capacity = static_cast<uint32_t>(new_capacity);
  89. return true;
  90. }
  91. #if BASISU_HASHMAP_TEST
  92. #define HASHMAP_TEST_VERIFY(c) do { if (!(c)) handle_hashmap_test_verify_failure(__LINE__); } while(0)
  93. static void handle_hashmap_test_verify_failure(int line)
  94. {
  95. fprintf(stderr, "HASHMAP_TEST_VERIFY() faild on line %i\n", line);
  96. abort();
  97. }
  98. class counted_obj
  99. {
  100. public:
  101. counted_obj(uint32_t v = 0) :
  102. m_val(v)
  103. {
  104. m_count++;
  105. }
  106. counted_obj(const counted_obj& obj) :
  107. m_val(obj.m_val)
  108. {
  109. m_count++;
  110. }
  111. ~counted_obj()
  112. {
  113. assert(m_count > 0);
  114. m_count--;
  115. }
  116. static uint32_t m_count;
  117. uint32_t m_val;
  118. operator size_t() const { return m_val; }
  119. bool operator== (const counted_obj& rhs) const { return m_val == rhs.m_val; }
  120. bool operator== (const uint32_t rhs) const { return m_val == rhs; }
  121. };
  122. uint32_t counted_obj::m_count;
  123. static uint32_t urand32()
  124. {
  125. uint32_t a = rand();
  126. uint32_t b = rand() << 15;
  127. uint32_t c = rand() << (32 - 15);
  128. return a ^ b ^ c;
  129. }
  130. static int irand32(int l, int h)
  131. {
  132. assert(l < h);
  133. if (l >= h)
  134. return l;
  135. uint32_t range = static_cast<uint32_t>(h - l);
  136. uint32_t rnd = urand32();
  137. uint32_t rnd_range = static_cast<uint32_t>((((uint64_t)range) * ((uint64_t)rnd)) >> 32U);
  138. int result = l + rnd_range;
  139. assert((result >= l) && (result < h));
  140. return result;
  141. }
  142. void hash_map_test()
  143. {
  144. {
  145. basisu::hash_map<uint64_t, uint64_t> k;
  146. basisu::hash_map<uint64_t, uint64_t> l;
  147. std::swap(k, l);
  148. k.begin();
  149. k.end();
  150. k.clear();
  151. k.empty();
  152. k.erase(0);
  153. k.insert(0, 1);
  154. k.find(0);
  155. k.get_equals();
  156. k.get_hasher();
  157. k.get_table_size();
  158. k.reset();
  159. k.reserve(1);
  160. k = l;
  161. k.set_equals(l.get_equals());
  162. k.set_hasher(l.get_hasher());
  163. k.get_table_size();
  164. }
  165. uint32_t seed = 0;
  166. for (; ; )
  167. {
  168. seed++;
  169. typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;
  170. my_hash_map m;
  171. const uint32_t n = irand32(0, 100000);
  172. printf("%u\n", n);
  173. srand(seed); // r1.seed(seed);
  174. basisu::vector<int> q;
  175. uint32_t count = 0;
  176. for (uint32_t i = 0; i < n; i++)
  177. {
  178. uint32_t v = urand32() & 0x7FFFFFFF;
  179. my_hash_map::insert_result res = m.insert(counted_obj(v), counted_obj(v ^ 0xdeadbeef));
  180. if (res.second)
  181. {
  182. count++;
  183. q.push_back(v);
  184. }
  185. }
  186. HASHMAP_TEST_VERIFY(m.size() == count);
  187. srand(seed);
  188. my_hash_map cm(m);
  189. m.clear();
  190. m = cm;
  191. cm.reset();
  192. for (uint32_t i = 0; i < n; i++)
  193. {
  194. uint32_t v = urand32() & 0x7FFFFFFF;
  195. my_hash_map::const_iterator it = m.find(counted_obj(v));
  196. HASHMAP_TEST_VERIFY(it != m.end());
  197. HASHMAP_TEST_VERIFY(it->first == v);
  198. HASHMAP_TEST_VERIFY(it->second == (v ^ 0xdeadbeef));
  199. }
  200. for (uint32_t t = 0; t < 2; t++)
  201. {
  202. const uint32_t nd = irand32(1, q.size() + 1);
  203. for (uint32_t i = 0; i < nd; i++)
  204. {
  205. uint32_t p = irand32(0, q.size());
  206. int k = q[p];
  207. if (k >= 0)
  208. {
  209. q[p] = -k - 1;
  210. bool s = m.erase(counted_obj(k));
  211. HASHMAP_TEST_VERIFY(s);
  212. }
  213. }
  214. typedef basisu::hash_map<uint32_t, empty_type> uint_hash_set;
  215. uint_hash_set s;
  216. for (uint32_t i = 0; i < q.size(); i++)
  217. {
  218. int v = q[i];
  219. if (v >= 0)
  220. {
  221. my_hash_map::const_iterator it = m.find(counted_obj(v));
  222. HASHMAP_TEST_VERIFY(it != m.end());
  223. HASHMAP_TEST_VERIFY(it->first == (uint32_t)v);
  224. HASHMAP_TEST_VERIFY(it->second == ((uint32_t)v ^ 0xdeadbeef));
  225. s.insert(v);
  226. }
  227. else
  228. {
  229. my_hash_map::const_iterator it = m.find(counted_obj(-v - 1));
  230. HASHMAP_TEST_VERIFY(it == m.end());
  231. }
  232. }
  233. uint32_t found_count = 0;
  234. for (my_hash_map::const_iterator it = m.begin(); it != m.end(); ++it)
  235. {
  236. HASHMAP_TEST_VERIFY(it->second == ((uint32_t)it->first ^ 0xdeadbeef));
  237. uint_hash_set::const_iterator fit(s.find((uint32_t)it->first));
  238. HASHMAP_TEST_VERIFY(fit != s.end());
  239. HASHMAP_TEST_VERIFY(fit->first == it->first);
  240. found_count++;
  241. }
  242. HASHMAP_TEST_VERIFY(found_count == s.size());
  243. }
  244. HASHMAP_TEST_VERIFY(counted_obj::m_count == m.size() * 2);
  245. }
  246. }
  247. #endif // BASISU_HASHMAP_TEST
  248. } // namespace basisu