123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814 |
- // basisu_containers_impl.h
- // Do not include directly
- #include <ctype.h>
- #ifdef _MSC_VER
- #pragma warning (disable:4127) // warning C4127: conditional expression is constant
- #endif
- namespace basisu
- {
- // A container operation has internally panicked in an unrecoverable way.
- // Either an allocation has failed, or a range or consistency check has failed.
- #ifdef _MSC_VER
- __declspec(noreturn)
- #else
- [[noreturn]]
- #endif
- void container_abort(const char* pMsg, ...)
- {
- assert(0);
- va_list args;
- va_start(args, pMsg);
- char buf[1024] = {};
- #ifdef _MSC_VER
- vsprintf_s(buf, sizeof(buf), pMsg, args);
- #else
- vsnprintf(buf, sizeof(buf), pMsg, args);
- #endif
- va_end(args);
- fputs(buf, stderr);
- std::terminate();
- }
- bool elemental_vector::increase_capacity(size_t min_new_capacity, bool grow_hint, size_t element_size, object_mover pMover, bool nofail_flag)
- {
- assert(m_size <= m_capacity);
- assert(min_new_capacity >= m_size);
- assert(element_size);
-
- // Basic sanity check min_new_capacity
- if (!can_fit_into_size_t((uint64_t)min_new_capacity * element_size))
- {
- assert(0);
-
- if (nofail_flag)
- return false;
- container_abort("elemental_vector::increase_capacity: requesting too many elements\n");
- }
- // Check for sane library limits
- if (sizeof(void*) == sizeof(uint64_t))
- {
- // 16 GB
- assert(min_new_capacity < (0x400000000ULL / element_size));
- }
- else
- {
- // ~1.99 GB
- assert(min_new_capacity < (0x7FFF0000U / element_size));
- }
- // If vector is already large enough just return.
- 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);
- if (!can_fit_into_size_t(new_capacity_u64))
- {
- assert(0);
- if (nofail_flag)
- return false;
- container_abort("elemental_vector::increase_capacity: vector too large\n");
- }
- }
- const uint64_t desired_size_u64 = element_size * new_capacity_u64;
- if (!can_fit_into_size_t(desired_size_u64))
- {
- assert(0);
- if (nofail_flag)
- return false;
- container_abort("elemental_vector::increase_capacity: vector too large\n");
- }
- const size_t desired_size = static_cast<size_t>(desired_size_u64);
-
- size_t actual_size = 0;
- BASISU_NOTE_UNUSED(actual_size);
- if (!pMover)
- {
- void* new_p = realloc(m_p, desired_size);
- if (!new_p)
- {
- assert(0);
- if (nofail_flag)
- return false;
- container_abort("elemental_vector::increase_capacity: realloc() failed allocating %zu bytes", desired_size);
- }
- #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)
- {
- assert(0);
- if (nofail_flag)
- return false;
- container_abort("elemental_vector::increase_capacity: malloc() failed allocating %zu bytes", desired_size);
- }
- #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 BASISU_VECTOR_DETERMINISTIC
- m_capacity = static_cast<size_t>(new_capacity_u64);
- #else
- if (actual_size > desired_size)
- m_capacity = static_cast<size_t>(actual_size / element_size);
- else
- m_capacity = static_cast<size_t>(new_capacity_u64);
- #endif
- 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)
- {
- container_abort("HASHMAP_TEST_VERIFY() faild on line %i\n", line);
- }
- 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)
- {
- if (m_val != UINT64_MAX)
- m_count++;
- }
- counted_obj(counted_obj&& obj) :
- m_val(obj.m_val)
- {
- obj.m_val = UINT64_MAX;
- }
- counted_obj& operator= (counted_obj&& rhs)
- {
- if (this != &rhs)
- {
- m_val = rhs.m_val;
- rhs.m_val = UINT64_MAX;
- }
- return *this;
- }
- ~counted_obj()
- {
- if (m_val != UINT64_MAX)
- {
- assert(m_count > 0);
- m_count--;
- }
- }
- static uint32_t m_count;
- uint64_t m_val;
- operator size_t() const { return (size_t)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<uint32_t>(h - l);
- uint32_t rnd = urand32();
- uint32_t rnd_range = static_cast<uint32_t>((((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<uint32_t> s;
- uint_vec k;
- for (uint32_t i = 0; i < 1000000; i++)
- {
- s.insert(i);
- k.push_back(i);
- }
-
- for (uint32_t i = 0; i < k.size(); i++)
- {
- uint32_t r = rand() ^ (rand() << 15);
- uint32_t j = i + (r % (k.size() - i));
- std::swap(k[i], k[j]);
- }
- basisu::hash_map<uint32_t> s1(s);
- for (uint32_t i = 0; i < 1000000; i++)
- {
- auto res = s.find(i);
- HASHMAP_TEST_VERIFY(res != s.end());
- HASHMAP_TEST_VERIFY(res->first == i);
- s.erase(i);
- }
- for (uint32_t it = 0; it < 1000000; it++)
- {
- uint32_t i = k[it];
- auto res = s1.find(i);
- HASHMAP_TEST_VERIFY(res != s.end());
- HASHMAP_TEST_VERIFY(res->first == i);
- s1.erase(i);
- }
- for (uint32_t i = 0; i < 1000000; i++)
- {
- auto res = s.find(i);
- HASHMAP_TEST_VERIFY(res == s.end());
- auto res1 = s1.find(i);
- HASHMAP_TEST_VERIFY(res1 == s1.end());
- }
- HASHMAP_TEST_VERIFY(s.empty());
- HASHMAP_TEST_VERIFY(s1.empty());
- }
- {
- typedef basisu::hash_map< uint32_t, basisu::vector<uint32_t> > hm;
- hm q;
-
- basisu::vector<uint32_t> a, b;
- a.push_back(1);
- b.push_back(2);
- b.push_back(3);
- basisu::vector<uint32_t> c(b);
- hm::insert_result ir;
- q.try_insert(ir, 1, std::move(a));
- q.try_insert(ir, 2, std::move(b));
- q.try_insert(ir, std::make_pair(3, c));
- }
- {
- typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;
- my_hash_map m;
- counted_obj a, b;
- m.insert(std::move(a), std::move(b));
- }
- {
- basisu::hash_map<uint64_t, uint64_t> k;
- basisu::hash_map<uint64_t, uint64_t> 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<counted_obj, counted_obj> my_hash_map;
- my_hash_map m;
- const uint32_t n = irand32(1, 100000);
- printf("%u\n", n);
- srand(seed); // r1.seed(seed);
- basisu::vector<int> 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_u32() + 1);
- for (uint32_t i = 0; i < nd; i++)
- {
- uint32_t p = irand32(0, q.size_u32());
- 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<uint32_t, empty_type> 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
- // String formatting
- bool fmt_variant::to_string(std::string& res, std::string& fmt) const
- {
- res.resize(0);
- // Scan for allowed formatting characters.
- for (size_t i = 0; i < fmt.size(); i++)
- {
- const char c = fmt[i];
- if (isdigit(c) || (c == '.') || (c == ' ') || (c == '#') || (c == '+') || (c == '-'))
- continue;
- if (isalpha(c))
- {
- if ((i + 1) == fmt.size())
- continue;
- }
- return false;
- }
- if (fmt.size() && (fmt.back() == 'c'))
- {
- if ((m_type == variant_type::cI32) || (m_type == variant_type::cU32))
- {
- if (m_u32 > 255)
- return false;
- // Explictly allowing caller to pass in a char of 0, which is ignored.
- if (m_u32)
- res.push_back((uint8_t)m_u32);
- return true;
- }
- else
- return false;
- }
- switch (m_type)
- {
- case variant_type::cInvalid:
- {
- return false;
- }
- case variant_type::cI32:
- {
- if (fmt.size())
- {
- int e = fmt.back();
- if (isalpha(e))
- {
- if ((e != 'x') && (e != 'X') && (e != 'i') && (e != 'd') && (e != 'u'))
- return false;
- }
- else
- {
- fmt += "i";
- }
- res = string_format((std::string("%") + fmt).c_str(), m_i32);
- }
- else
- {
- res = string_format("%i", m_i32);
- }
- break;
- }
- case variant_type::cU32:
- {
- if (fmt.size())
- {
- int e = fmt.back();
- if (isalpha(e))
- {
- if ((e != 'x') && (e != 'X') && (e != 'i') && (e != 'd') && (e != 'u'))
- return false;
- }
- else
- {
- fmt += "u";
- }
- res = string_format((std::string("%") + fmt).c_str(), m_u32);
- }
- else
- {
- res = string_format("%u", m_u32);
- }
- break;
- }
- case variant_type::cI64:
- {
- if (fmt.size())
- {
- int e = fmt.back();
- if (isalpha(e))
- {
- if (e == 'x')
- {
- fmt.pop_back();
- fmt += PRIx64;
- }
- else if (e == 'X')
- {
- fmt.pop_back();
- fmt += PRIX64;
- }
- else
- return false;
- }
- else
- {
- fmt += PRId64;
- }
- res = string_format((std::string("%") + fmt).c_str(), m_i64);
- }
- else
- {
- res = string_format("%" PRId64, m_i64);
- }
- break;
- }
- case variant_type::cU64:
- {
- if (fmt.size())
- {
- int e = fmt.back();
- if (isalpha(e))
- {
- if (e == 'x')
- {
- fmt.pop_back();
- fmt += PRIx64;
- }
- else if (e == 'X')
- {
- fmt.pop_back();
- fmt += PRIX64;
- }
- else
- return false;
- }
- else
- {
- fmt += PRIu64;
- }
- res = string_format((std::string("%") + fmt).c_str(), m_u64);
- }
- else
- {
- res = string_format("%" PRIu64, m_u64);
- }
- break;
- }
- case variant_type::cFlt:
- {
- if (fmt.size())
- {
- int e = fmt.back();
- if (isalpha(e))
- {
- if ((e != 'f') && (e != 'g') && (e != 'e') && (e != 'E'))
- return false;
- }
- else
- {
- fmt += "f";
- }
- res = string_format((std::string("%") + fmt).c_str(), m_flt);
- }
- else
- {
- res = string_format("%f", m_flt);
- }
- break;
- }
- case variant_type::cDbl:
- {
- if (fmt.size())
- {
- int e = fmt.back();
- if (isalpha(e))
- {
- if ((e != 'f') && (e != 'g') && (e != 'e') && (e != 'E'))
- return false;
- }
- else
- {
- fmt += "f";
- }
- res = string_format((std::string("%") + fmt).c_str(), m_dbl);
- }
- else
- {
- res = string_format("%f", m_dbl);
- }
- break;
- }
- case variant_type::cStrPtr:
- {
- if (fmt.size())
- return false;
- if (!m_pStr)
- return false;
- res = m_pStr;
- break;
- }
- case variant_type::cBool:
- {
- if (fmt.size())
- return false;
- res = m_bool ? "true" : "false";
- break;
- }
- case variant_type::cStdStr:
- {
- if (fmt.size())
- return false;
- res = m_str;
- break;
- }
- default:
- {
- return false;
- }
- }
- return true;
- }
- bool fmt_variants(std::string& res, const char* pFmt, const fmt_variant_vec& variants)
- {
- res.resize(0);
- // Must specify a format string
- if (!pFmt)
- {
- assert(0);
- return false;
- }
- // Check format string's length
- const size_t fmt_len = strlen(pFmt);
- if (!fmt_len)
- {
- if (variants.size())
- {
- assert(0);
- return false;
- }
- return true;
- }
- // Wildly estimate output length
- res.reserve(fmt_len + 32);
- std::string var_fmt;
- var_fmt.reserve(16);
- std::string tmp;
- tmp.reserve(16);
- size_t variant_index = 0;
- bool inside_brackets = false;
- const char* p = pFmt;
- while (*p)
- {
- const uint8_t c = *p++;
- if (inside_brackets)
- {
- if (c == '}')
- {
- inside_brackets = false;
- if (variant_index >= variants.size())
- {
- assert(0);
- return false;
- }
- if (!variants[variant_index].to_string(tmp, var_fmt))
- {
- assert(0);
- return false;
- }
- res += tmp;
- variant_index++;
- }
- else
- {
- // Check for forbidden formatting characters.
- if ((c == '*') || (c == 'n') || (c == '%'))
- {
- assert(0);
- return false;
- }
- var_fmt.push_back(c);
- }
- }
- else if (c == '{')
- {
- // Check for escaped '{'
- if (*p == '{')
- {
- res.push_back((char)c);
- p++;
- }
- else
- {
- inside_brackets = true;
- var_fmt.resize(0);
- }
- }
- else
- {
- res.push_back((char)c);
- }
- }
- if (inside_brackets)
- {
- assert(0);
- return false;
- }
- if (variant_index != variants.size())
- {
- assert(0);
- return false;
- }
- return true;
- }
- } // namespace basisu
|