basisu_containers_impl.h 8.1 KB

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