// basisu_containers_impl.h // Do not include directly #ifdef _MSC_VER #pragma warning (disable:4127) // warning C4127: conditional expression is constant #endif namespace basisu { bool elemental_vector::increase_capacity(uint32_t min_new_capacity, bool grow_hint, uint32_t element_size, object_mover pMover, bool nofail) { assert(m_size <= m_capacity); if (sizeof(void *) == sizeof(uint64_t)) assert(min_new_capacity < (0x400000000ULL / element_size)); else assert(min_new_capacity < (0x7FFF0000U / element_size)); if (m_capacity >= min_new_capacity) return true; uint64_t new_capacity_u64 = min_new_capacity; if ((grow_hint) && (!helpers::is_power_of_2(new_capacity_u64))) new_capacity_u64 = helpers::next_pow2(new_capacity_u64); size_t new_capacity = (size_t)new_capacity_u64; if (new_capacity != new_capacity_u64) { if (nofail) return false; fprintf(stderr, "elemental_vector::increase_capacity: vector too large\n"); abort(); } const uint64_t desired_size_u64 = (uint64_t)element_size * new_capacity; const size_t desired_size = (size_t)desired_size_u64; if (desired_size_u64 != desired_size) { if (nofail) return false; fprintf(stderr, "elemental_vector::increase_capacity: vector too large\n"); abort(); } size_t actual_size = 0; if (!pMover) { void* new_p = realloc(m_p, desired_size); if (!new_p) { if (nofail) return false; char buf[256]; snprintf(buf, sizeof(buf), "elemental_vector::increase_capacity: realloc() failed allocating %zu bytes", desired_size); fprintf(stderr, "%s", buf); abort(); } #if BASISU_VECTOR_DETERMINISTIC actual_size = desired_size; #elif defined(_MSC_VER) actual_size = _msize(new_p); #elif HAS_MALLOC_USABLE_SIZE actual_size = malloc_usable_size(new_p); #else actual_size = desired_size; #endif m_p = new_p; } else { void* new_p = malloc(desired_size); if (!new_p) { if (nofail) return false; char buf[256]; snprintf(buf, sizeof(buf), "elemental_vector::increase_capacity: malloc() failed allocating %zu bytes", desired_size); fprintf(stderr, "%s", buf); abort(); } #if BASISU_VECTOR_DETERMINISTIC actual_size = desired_size; #elif defined(_MSC_VER) actual_size = _msize(new_p); #elif HAS_MALLOC_USABLE_SIZE actual_size = malloc_usable_size(new_p); #else actual_size = desired_size; #endif (*pMover)(new_p, m_p, m_size); if (m_p) free(m_p); m_p = new_p; } if (actual_size > desired_size) m_capacity = static_cast(actual_size / element_size); else m_capacity = static_cast(new_capacity); return true; } #if BASISU_HASHMAP_TEST #define HASHMAP_TEST_VERIFY(c) do { if (!(c)) handle_hashmap_test_verify_failure(__LINE__); } while(0) static void handle_hashmap_test_verify_failure(int line) { fprintf(stderr, "HASHMAP_TEST_VERIFY() faild on line %i\n", line); abort(); } class counted_obj { public: counted_obj(uint32_t v = 0) : m_val(v) { m_count++; } counted_obj(const counted_obj& obj) : m_val(obj.m_val) { m_count++; } ~counted_obj() { assert(m_count > 0); m_count--; } static uint32_t m_count; uint32_t m_val; operator size_t() const { return m_val; } bool operator== (const counted_obj& rhs) const { return m_val == rhs.m_val; } bool operator== (const uint32_t rhs) const { return m_val == rhs; } }; uint32_t counted_obj::m_count; static uint32_t urand32() { uint32_t a = rand(); uint32_t b = rand() << 15; uint32_t c = rand() << (32 - 15); return a ^ b ^ c; } static int irand32(int l, int h) { assert(l < h); if (l >= h) return l; uint32_t range = static_cast(h - l); uint32_t rnd = urand32(); uint32_t rnd_range = static_cast((((uint64_t)range) * ((uint64_t)rnd)) >> 32U); int result = l + rnd_range; assert((result >= l) && (result < h)); return result; } void hash_map_test() { { basisu::hash_map k; basisu::hash_map l; std::swap(k, l); k.begin(); k.end(); k.clear(); k.empty(); k.erase(0); k.insert(0, 1); k.find(0); k.get_equals(); k.get_hasher(); k.get_table_size(); k.reset(); k.reserve(1); k = l; k.set_equals(l.get_equals()); k.set_hasher(l.get_hasher()); k.get_table_size(); } uint32_t seed = 0; for (; ; ) { seed++; typedef basisu::hash_map my_hash_map; my_hash_map m; const uint32_t n = irand32(0, 100000); printf("%u\n", n); srand(seed); // r1.seed(seed); basisu::vector q; uint32_t count = 0; for (uint32_t i = 0; i < n; i++) { uint32_t v = urand32() & 0x7FFFFFFF; my_hash_map::insert_result res = m.insert(counted_obj(v), counted_obj(v ^ 0xdeadbeef)); if (res.second) { count++; q.push_back(v); } } HASHMAP_TEST_VERIFY(m.size() == count); srand(seed); my_hash_map cm(m); m.clear(); m = cm; cm.reset(); for (uint32_t i = 0; i < n; i++) { uint32_t v = urand32() & 0x7FFFFFFF; my_hash_map::const_iterator it = m.find(counted_obj(v)); HASHMAP_TEST_VERIFY(it != m.end()); HASHMAP_TEST_VERIFY(it->first == v); HASHMAP_TEST_VERIFY(it->second == (v ^ 0xdeadbeef)); } for (uint32_t t = 0; t < 2; t++) { const uint32_t nd = irand32(1, q.size() + 1); for (uint32_t i = 0; i < nd; i++) { uint32_t p = irand32(0, q.size()); int k = q[p]; if (k >= 0) { q[p] = -k - 1; bool s = m.erase(counted_obj(k)); HASHMAP_TEST_VERIFY(s); } } typedef basisu::hash_map uint_hash_set; uint_hash_set s; for (uint32_t i = 0; i < q.size(); i++) { int v = q[i]; if (v >= 0) { my_hash_map::const_iterator it = m.find(counted_obj(v)); HASHMAP_TEST_VERIFY(it != m.end()); HASHMAP_TEST_VERIFY(it->first == (uint32_t)v); HASHMAP_TEST_VERIFY(it->second == ((uint32_t)v ^ 0xdeadbeef)); s.insert(v); } else { my_hash_map::const_iterator it = m.find(counted_obj(-v - 1)); HASHMAP_TEST_VERIFY(it == m.end()); } } uint32_t found_count = 0; for (my_hash_map::const_iterator it = m.begin(); it != m.end(); ++it) { HASHMAP_TEST_VERIFY(it->second == ((uint32_t)it->first ^ 0xdeadbeef)); uint_hash_set::const_iterator fit(s.find((uint32_t)it->first)); HASHMAP_TEST_VERIFY(fit != s.end()); HASHMAP_TEST_VERIFY(fit->first == it->first); found_count++; } HASHMAP_TEST_VERIFY(found_count == s.size()); } HASHMAP_TEST_VERIFY(counted_obj::m_count == m.size() * 2); } } #endif // BASISU_HASHMAP_TEST } // namespace basisu