Path: blob/master/thirdparty/basis_universal/transcoder/basisu_containers_impl.h
21100 views
// basisu_containers_impl.h1// Do not include directly23#include <ctype.h>4#include <exception>56#ifdef _MSC_VER7#pragma warning (disable:4127) // warning C4127: conditional expression is constant8#endif910namespace basisu11{12// A container operation has internally panicked in an unrecoverable way.13// Either an allocation has failed, or a range or consistency check has failed.14#ifdef _MSC_VER15__declspec(noreturn)16#else17[[noreturn]]18#endif19void container_abort(const char* pMsg, ...)20{21assert(0);2223va_list args;24va_start(args, pMsg);2526char buf[1024] = {};2728#ifdef _MSC_VER29vsprintf_s(buf, sizeof(buf), pMsg, args);30#else31vsnprintf(buf, sizeof(buf), pMsg, args);32#endif33va_end(args);3435fputs(buf, stderr);3637std::terminate();38}3940bool elemental_vector::increase_capacity(size_t min_new_capacity, bool grow_hint, size_t element_size, object_mover pMover, bool nofail_flag)41{42assert(m_size <= m_capacity);43assert(min_new_capacity >= m_size);44assert(element_size);4546// Basic sanity check min_new_capacity47if (!can_fit_into_size_t((uint64_t)min_new_capacity * element_size))48{49assert(0);5051if (nofail_flag)52return false;5354container_abort("elemental_vector::increase_capacity: requesting too many elements\n");55}5657// Check for sane library limits58if (sizeof(void*) == sizeof(uint64_t))59{60// 16 GB61assert(min_new_capacity < (0x400000000ULL / element_size));62}63else64{65// ~1.99 GB66assert(min_new_capacity < (0x7FFF0000U / element_size));67}6869// If vector is already large enough just return.70if (m_capacity >= min_new_capacity)71return true;7273uint64_t new_capacity_u64 = min_new_capacity;7475if ((grow_hint) && (!helpers::is_power_of_2(new_capacity_u64)))76{77new_capacity_u64 = helpers::next_pow2(new_capacity_u64);7879if (!can_fit_into_size_t(new_capacity_u64))80{81assert(0);8283if (nofail_flag)84return false;8586container_abort("elemental_vector::increase_capacity: vector too large\n");87}88}8990const uint64_t desired_size_u64 = element_size * new_capacity_u64;9192if (!can_fit_into_size_t(desired_size_u64))93{94assert(0);9596if (nofail_flag)97return false;9899container_abort("elemental_vector::increase_capacity: vector too large\n");100}101102const size_t desired_size = static_cast<size_t>(desired_size_u64);103104size_t actual_size = 0;105BASISU_NOTE_UNUSED(actual_size);106107if (!pMover)108{109void* new_p = realloc(m_p, desired_size);110if (!new_p)111{112assert(0);113114if (nofail_flag)115return false;116117container_abort("elemental_vector::increase_capacity: realloc() failed allocating %zu bytes", desired_size);118}119120#if BASISU_VECTOR_DETERMINISTIC121actual_size = desired_size;122#elif defined(_MSC_VER)123actual_size = _msize(new_p);124#elif HAS_MALLOC_USABLE_SIZE125actual_size = malloc_usable_size(new_p);126#else127actual_size = desired_size;128#endif129m_p = new_p;130}131else132{133void* new_p = malloc(desired_size);134if (!new_p)135{136assert(0);137if (nofail_flag)138return false;139140container_abort("elemental_vector::increase_capacity: malloc() failed allocating %zu bytes", desired_size);141}142143#if BASISU_VECTOR_DETERMINISTIC144actual_size = desired_size;145#elif defined(_MSC_VER)146actual_size = _msize(new_p);147#elif HAS_MALLOC_USABLE_SIZE148actual_size = malloc_usable_size(new_p);149#else150actual_size = desired_size;151#endif152153(*pMover)(new_p, m_p, m_size);154155if (m_p)156free(m_p);157158m_p = new_p;159}160161#if BASISU_VECTOR_DETERMINISTIC162m_capacity = static_cast<size_t>(new_capacity_u64);163#else164if (actual_size > desired_size)165m_capacity = static_cast<size_t>(actual_size / element_size);166else167m_capacity = static_cast<size_t>(new_capacity_u64);168#endif169170return true;171}172173#if BASISU_HASHMAP_TEST174175#define HASHMAP_TEST_VERIFY(c) do { if (!(c)) handle_hashmap_test_verify_failure(__LINE__); } while(0)176177static void handle_hashmap_test_verify_failure(int line)178{179container_abort("HASHMAP_TEST_VERIFY() faild on line %i\n", line);180}181182class counted_obj183{184public:185counted_obj(uint32_t v = 0) :186m_val(v)187{188m_count++;189}190191counted_obj(const counted_obj& obj) :192m_val(obj.m_val)193{194if (m_val != UINT64_MAX)195m_count++;196}197198counted_obj(counted_obj&& obj) :199m_val(obj.m_val)200{201obj.m_val = UINT64_MAX;202}203204counted_obj& operator= (counted_obj&& rhs)205{206if (this != &rhs)207{208m_val = rhs.m_val;209rhs.m_val = UINT64_MAX;210}211return *this;212}213214~counted_obj()215{216if (m_val != UINT64_MAX)217{218assert(m_count > 0);219m_count--;220}221}222223static uint32_t m_count;224225uint64_t m_val;226227operator size_t() const { return (size_t)m_val; }228229bool operator== (const counted_obj& rhs) const { return m_val == rhs.m_val; }230bool operator== (const uint32_t rhs) const { return m_val == rhs; }231232};233234uint32_t counted_obj::m_count;235236static uint32_t urand32()237{238uint32_t a = rand();239uint32_t b = rand() << 15;240uint32_t c = rand() << (32 - 15);241return a ^ b ^ c;242}243244static int irand32(int l, int h)245{246assert(l < h);247if (l >= h)248return l;249250uint32_t range = static_cast<uint32_t>(h - l);251252uint32_t rnd = urand32();253254uint32_t rnd_range = static_cast<uint32_t>((((uint64_t)range) * ((uint64_t)rnd)) >> 32U);255256int result = l + rnd_range;257assert((result >= l) && (result < h));258return result;259}260261void hash_map_test()262{263{264basisu::hash_map<uint32_t> s;265uint_vec k;266267for (uint32_t i = 0; i < 1000000; i++)268{269s.insert(i);270k.push_back(i);271}272273for (uint32_t i = 0; i < k.size(); i++)274{275uint32_t r = rand() ^ (rand() << 15);276277uint32_t j = i + (r % (k.size() - i));278279std::swap(k[i], k[j]);280}281282basisu::hash_map<uint32_t> s1(s);283284for (uint32_t i = 0; i < 1000000; i++)285{286auto res = s.find(i);287HASHMAP_TEST_VERIFY(res != s.end());288HASHMAP_TEST_VERIFY(res->first == i);289s.erase(i);290}291292for (uint32_t it = 0; it < 1000000; it++)293{294uint32_t i = k[it];295296auto res = s1.find(i);297HASHMAP_TEST_VERIFY(res != s.end());298HASHMAP_TEST_VERIFY(res->first == i);299s1.erase(i);300}301302for (uint32_t i = 0; i < 1000000; i++)303{304auto res = s.find(i);305HASHMAP_TEST_VERIFY(res == s.end());306307auto res1 = s1.find(i);308HASHMAP_TEST_VERIFY(res1 == s1.end());309}310311HASHMAP_TEST_VERIFY(s.empty());312HASHMAP_TEST_VERIFY(s1.empty());313}314315{316typedef basisu::hash_map< uint32_t, basisu::vector<uint32_t> > hm;317hm q;318319basisu::vector<uint32_t> a, b;320a.push_back(1);321b.push_back(2);322b.push_back(3);323324basisu::vector<uint32_t> c(b);325326hm::insert_result ir;327q.try_insert(ir, 1, std::move(a));328q.try_insert(ir, 2, std::move(b));329q.try_insert(ir, std::make_pair(3, c));330}331332{333typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;334my_hash_map m;335counted_obj a, b;336m.insert(std::move(a), std::move(b));337}338339{340basisu::hash_map<uint64_t, uint64_t> k;341basisu::hash_map<uint64_t, uint64_t> l;342std::swap(k, l);343344k.begin();345k.end();346k.clear();347k.empty();348k.erase(0);349k.insert(0, 1);350k.find(0);351k.get_equals();352k.get_hasher();353k.get_table_size();354k.reset();355k.reserve(1);356k = l;357k.set_equals(l.get_equals());358k.set_hasher(l.get_hasher());359k.get_table_size();360}361362uint32_t seed = 0;363for (; ; )364{365seed++;366367typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;368my_hash_map m;369370const uint32_t n = irand32(1, 100000);371372printf("%u\n", n);373374srand(seed); // r1.seed(seed);375376basisu::vector<int> q;377378uint32_t count = 0;379for (uint32_t i = 0; i < n; i++)380{381uint32_t v = urand32() & 0x7FFFFFFF;382my_hash_map::insert_result res = m.insert(counted_obj(v), counted_obj(v ^ 0xdeadbeef));383if (res.second)384{385count++;386q.push_back(v);387}388}389390HASHMAP_TEST_VERIFY(m.size() == count);391392srand(seed);393394my_hash_map cm(m);395m.clear();396m = cm;397cm.reset();398399for (uint32_t i = 0; i < n; i++)400{401uint32_t v = urand32() & 0x7FFFFFFF;402my_hash_map::const_iterator it = m.find(counted_obj(v));403HASHMAP_TEST_VERIFY(it != m.end());404HASHMAP_TEST_VERIFY(it->first == v);405HASHMAP_TEST_VERIFY(it->second == (v ^ 0xdeadbeef));406}407408for (uint32_t t = 0; t < 2; t++)409{410const uint32_t nd = irand32(1, q.size_u32() + 1);411for (uint32_t i = 0; i < nd; i++)412{413uint32_t p = irand32(0, q.size_u32());414415int k = q[p];416if (k >= 0)417{418q[p] = -k - 1;419420bool s = m.erase(counted_obj(k));421HASHMAP_TEST_VERIFY(s);422}423}424425typedef basisu::hash_map<uint32_t, empty_type> uint_hash_set;426uint_hash_set s;427428for (uint32_t i = 0; i < q.size(); i++)429{430int v = q[i];431432if (v >= 0)433{434my_hash_map::const_iterator it = m.find(counted_obj(v));435HASHMAP_TEST_VERIFY(it != m.end());436HASHMAP_TEST_VERIFY(it->first == (uint32_t)v);437HASHMAP_TEST_VERIFY(it->second == ((uint32_t)v ^ 0xdeadbeef));438439s.insert(v);440}441else442{443my_hash_map::const_iterator it = m.find(counted_obj(-v - 1));444HASHMAP_TEST_VERIFY(it == m.end());445}446}447448uint32_t found_count = 0;449for (my_hash_map::const_iterator it = m.begin(); it != m.end(); ++it)450{451HASHMAP_TEST_VERIFY(it->second == ((uint32_t)it->first ^ 0xdeadbeef));452453uint_hash_set::const_iterator fit(s.find((uint32_t)it->first));454HASHMAP_TEST_VERIFY(fit != s.end());455456HASHMAP_TEST_VERIFY(fit->first == it->first);457458found_count++;459}460461HASHMAP_TEST_VERIFY(found_count == s.size());462}463464HASHMAP_TEST_VERIFY(counted_obj::m_count == m.size() * 2);465}466}467468#endif // BASISU_HASHMAP_TEST469470// String formatting471472bool fmt_variant::to_string(std::string& res, std::string& fmt) const473{474res.resize(0);475476// Scan for allowed formatting characters.477for (size_t i = 0; i < fmt.size(); i++)478{479const char c = fmt[i];480481if (isdigit(c) || (c == '.') || (c == ' ') || (c == '#') || (c == '+') || (c == '-'))482continue;483484if (isalpha(c))485{486if ((i + 1) == fmt.size())487continue;488}489490return false;491}492493if (fmt.size() && (fmt.back() == 'c'))494{495if ((m_type == variant_type::cI32) || (m_type == variant_type::cU32))496{497if (m_u32 > 255)498return false;499500// Explictly allowing caller to pass in a char of 0, which is ignored.501if (m_u32)502res.push_back((uint8_t)m_u32);503return true;504}505else506return false;507}508509switch (m_type)510{511case variant_type::cInvalid:512{513return false;514}515case variant_type::cI32:516{517if (fmt.size())518{519int e = fmt.back();520if (isalpha(e))521{522if ((e != 'x') && (e != 'X') && (e != 'i') && (e != 'd') && (e != 'u'))523return false;524}525else526{527fmt += "i";528}529530res = string_format((std::string("%") + fmt).c_str(), m_i32);531}532else533{534res = string_format("%i", m_i32);535}536break;537}538case variant_type::cU32:539{540if (fmt.size())541{542int e = fmt.back();543if (isalpha(e))544{545if ((e != 'x') && (e != 'X') && (e != 'i') && (e != 'd') && (e != 'u'))546return false;547}548else549{550fmt += "u";551}552553res = string_format((std::string("%") + fmt).c_str(), m_u32);554}555else556{557res = string_format("%u", m_u32);558}559break;560}561case variant_type::cI64:562{563if (fmt.size())564{565int e = fmt.back();566if (isalpha(e))567{568if (e == 'x')569{570fmt.pop_back();571fmt += PRIx64;572}573else if (e == 'X')574{575fmt.pop_back();576fmt += PRIX64;577}578else579return false;580}581else582{583fmt += PRId64;584}585586res = string_format((std::string("%") + fmt).c_str(), m_i64);587}588else589{590res = string_format("%" PRId64, m_i64);591}592break;593}594case variant_type::cU64:595{596if (fmt.size())597{598int e = fmt.back();599if (isalpha(e))600{601if (e == 'x')602{603fmt.pop_back();604fmt += PRIx64;605}606else if (e == 'X')607{608fmt.pop_back();609fmt += PRIX64;610}611else612return false;613}614else615{616fmt += PRIu64;617}618619res = string_format((std::string("%") + fmt).c_str(), m_u64);620}621else622{623res = string_format("%" PRIu64, m_u64);624}625break;626}627case variant_type::cFlt:628{629if (fmt.size())630{631int e = fmt.back();632if (isalpha(e))633{634if ((e != 'f') && (e != 'g') && (e != 'e') && (e != 'E'))635return false;636}637else638{639fmt += "f";640}641642res = string_format((std::string("%") + fmt).c_str(), m_flt);643}644else645{646res = string_format("%f", m_flt);647}648break;649}650case variant_type::cDbl:651{652if (fmt.size())653{654int e = fmt.back();655if (isalpha(e))656{657if ((e != 'f') && (e != 'g') && (e != 'e') && (e != 'E'))658return false;659}660else661{662fmt += "f";663}664665res = string_format((std::string("%") + fmt).c_str(), m_dbl);666}667else668{669res = string_format("%f", m_dbl);670}671break;672}673case variant_type::cStrPtr:674{675if (fmt.size())676return false;677if (!m_pStr)678return false;679res = m_pStr;680break;681}682case variant_type::cBool:683{684if (fmt.size())685return false;686res = m_bool ? "true" : "false";687break;688}689case variant_type::cStdStr:690{691if (fmt.size())692return false;693res = m_str;694break;695}696default:697{698return false;699}700}701702return true;703}704705bool fmt_variants(std::string& res, const char* pFmt, const fmt_variant_vec& variants)706{707res.resize(0);708709// Must specify a format string710if (!pFmt)711{712assert(0);713return false;714}715716// Check format string's length717const size_t fmt_len = strlen(pFmt);718if (!fmt_len)719{720if (variants.size())721{722assert(0);723return false;724}725return true;726}727728// Wildly estimate output length729res.reserve(fmt_len + 32);730731std::string var_fmt;732var_fmt.reserve(16);733734std::string tmp;735tmp.reserve(16);736737size_t variant_index = 0;738bool inside_brackets = false;739const char* p = pFmt;740741while (*p)742{743const uint8_t c = *p++;744745if (inside_brackets)746{747if (c == '}')748{749inside_brackets = false;750751if (variant_index >= variants.size())752{753assert(0);754return false;755}756757if (!variants[variant_index].to_string(tmp, var_fmt))758{759assert(0);760return false;761}762763res += tmp;764765variant_index++;766}767else768{769// Check for forbidden formatting characters.770if ((c == '*') || (c == 'n') || (c == '%'))771{772assert(0);773return false;774}775776var_fmt.push_back(c);777}778}779else if (c == '{')780{781// Check for escaped '{'782if (*p == '{')783{784res.push_back((char)c);785p++;786}787else788{789inside_brackets = true;790var_fmt.resize(0);791}792}793else794{795res.push_back((char)c);796}797}798799if (inside_brackets)800{801assert(0);802return false;803}804805if (variant_index != variants.size())806{807assert(0);808return false;809}810811return true;812}813814} // namespace basisu815816817