Path: blob/master/thirdparty/basis_universal/transcoder/basisu_containers_impl.h
9905 views
// basisu_containers_impl.h1// Do not include directly23#include <ctype.h>45#ifdef _MSC_VER6#pragma warning (disable:4127) // warning C4127: conditional expression is constant7#endif89namespace basisu10{11// A container operation has internally panicked in an unrecoverable way.12// Either an allocation has failed, or a range or consistency check has failed.13#ifdef _MSC_VER14__declspec(noreturn)15#else16[[noreturn]]17#endif18void container_abort(const char* pMsg, ...)19{20assert(0);2122va_list args;23va_start(args, pMsg);2425char buf[1024] = {};2627#ifdef _MSC_VER28vsprintf_s(buf, sizeof(buf), pMsg, args);29#else30vsnprintf(buf, sizeof(buf), pMsg, args);31#endif32va_end(args);3334fputs(buf, stderr);3536std::terminate();37}3839bool elemental_vector::increase_capacity(size_t min_new_capacity, bool grow_hint, size_t element_size, object_mover pMover, bool nofail_flag)40{41assert(m_size <= m_capacity);42assert(min_new_capacity >= m_size);43assert(element_size);4445// Basic sanity check min_new_capacity46if (!can_fit_into_size_t((uint64_t)min_new_capacity * element_size))47{48assert(0);4950if (nofail_flag)51return false;5253container_abort("elemental_vector::increase_capacity: requesting too many elements\n");54}5556// Check for sane library limits57if (sizeof(void*) == sizeof(uint64_t))58{59// 16 GB60assert(min_new_capacity < (0x400000000ULL / element_size));61}62else63{64// ~1.99 GB65assert(min_new_capacity < (0x7FFF0000U / element_size));66}6768// If vector is already large enough just return.69if (m_capacity >= min_new_capacity)70return true;7172uint64_t new_capacity_u64 = min_new_capacity;7374if ((grow_hint) && (!helpers::is_power_of_2(new_capacity_u64)))75{76new_capacity_u64 = helpers::next_pow2(new_capacity_u64);7778if (!can_fit_into_size_t(new_capacity_u64))79{80assert(0);8182if (nofail_flag)83return false;8485container_abort("elemental_vector::increase_capacity: vector too large\n");86}87}8889const uint64_t desired_size_u64 = element_size * new_capacity_u64;9091if (!can_fit_into_size_t(desired_size_u64))92{93assert(0);9495if (nofail_flag)96return false;9798container_abort("elemental_vector::increase_capacity: vector too large\n");99}100101const size_t desired_size = static_cast<size_t>(desired_size_u64);102103size_t actual_size = 0;104BASISU_NOTE_UNUSED(actual_size);105106if (!pMover)107{108void* new_p = realloc(m_p, desired_size);109if (!new_p)110{111assert(0);112113if (nofail_flag)114return false;115116container_abort("elemental_vector::increase_capacity: realloc() failed allocating %zu bytes", desired_size);117}118119#if BASISU_VECTOR_DETERMINISTIC120actual_size = desired_size;121#elif defined(_MSC_VER)122actual_size = _msize(new_p);123#elif HAS_MALLOC_USABLE_SIZE124actual_size = malloc_usable_size(new_p);125#else126actual_size = desired_size;127#endif128m_p = new_p;129}130else131{132void* new_p = malloc(desired_size);133if (!new_p)134{135assert(0);136if (nofail_flag)137return false;138139container_abort("elemental_vector::increase_capacity: malloc() failed allocating %zu bytes", desired_size);140}141142#if BASISU_VECTOR_DETERMINISTIC143actual_size = desired_size;144#elif defined(_MSC_VER)145actual_size = _msize(new_p);146#elif HAS_MALLOC_USABLE_SIZE147actual_size = malloc_usable_size(new_p);148#else149actual_size = desired_size;150#endif151152(*pMover)(new_p, m_p, m_size);153154if (m_p)155free(m_p);156157m_p = new_p;158}159160#if BASISU_VECTOR_DETERMINISTIC161m_capacity = static_cast<size_t>(new_capacity_u64);162#else163if (actual_size > desired_size)164m_capacity = static_cast<size_t>(actual_size / element_size);165else166m_capacity = static_cast<size_t>(new_capacity_u64);167#endif168169return true;170}171172#if BASISU_HASHMAP_TEST173174#define HASHMAP_TEST_VERIFY(c) do { if (!(c)) handle_hashmap_test_verify_failure(__LINE__); } while(0)175176static void handle_hashmap_test_verify_failure(int line)177{178container_abort("HASHMAP_TEST_VERIFY() faild on line %i\n", line);179}180181class counted_obj182{183public:184counted_obj(uint32_t v = 0) :185m_val(v)186{187m_count++;188}189190counted_obj(const counted_obj& obj) :191m_val(obj.m_val)192{193if (m_val != UINT64_MAX)194m_count++;195}196197counted_obj(counted_obj&& obj) :198m_val(obj.m_val)199{200obj.m_val = UINT64_MAX;201}202203counted_obj& operator= (counted_obj&& rhs)204{205if (this != &rhs)206{207m_val = rhs.m_val;208rhs.m_val = UINT64_MAX;209}210return *this;211}212213~counted_obj()214{215if (m_val != UINT64_MAX)216{217assert(m_count > 0);218m_count--;219}220}221222static uint32_t m_count;223224uint64_t m_val;225226operator size_t() const { return (size_t)m_val; }227228bool operator== (const counted_obj& rhs) const { return m_val == rhs.m_val; }229bool operator== (const uint32_t rhs) const { return m_val == rhs; }230231};232233uint32_t counted_obj::m_count;234235static uint32_t urand32()236{237uint32_t a = rand();238uint32_t b = rand() << 15;239uint32_t c = rand() << (32 - 15);240return a ^ b ^ c;241}242243static int irand32(int l, int h)244{245assert(l < h);246if (l >= h)247return l;248249uint32_t range = static_cast<uint32_t>(h - l);250251uint32_t rnd = urand32();252253uint32_t rnd_range = static_cast<uint32_t>((((uint64_t)range) * ((uint64_t)rnd)) >> 32U);254255int result = l + rnd_range;256assert((result >= l) && (result < h));257return result;258}259260void hash_map_test()261{262{263basisu::hash_map<uint32_t> s;264uint_vec k;265266for (uint32_t i = 0; i < 1000000; i++)267{268s.insert(i);269k.push_back(i);270}271272for (uint32_t i = 0; i < k.size(); i++)273{274uint32_t r = rand() ^ (rand() << 15);275276uint32_t j = i + (r % (k.size() - i));277278std::swap(k[i], k[j]);279}280281basisu::hash_map<uint32_t> s1(s);282283for (uint32_t i = 0; i < 1000000; i++)284{285auto res = s.find(i);286HASHMAP_TEST_VERIFY(res != s.end());287HASHMAP_TEST_VERIFY(res->first == i);288s.erase(i);289}290291for (uint32_t it = 0; it < 1000000; it++)292{293uint32_t i = k[it];294295auto res = s1.find(i);296HASHMAP_TEST_VERIFY(res != s.end());297HASHMAP_TEST_VERIFY(res->first == i);298s1.erase(i);299}300301for (uint32_t i = 0; i < 1000000; i++)302{303auto res = s.find(i);304HASHMAP_TEST_VERIFY(res == s.end());305306auto res1 = s1.find(i);307HASHMAP_TEST_VERIFY(res1 == s1.end());308}309310HASHMAP_TEST_VERIFY(s.empty());311HASHMAP_TEST_VERIFY(s1.empty());312}313314{315typedef basisu::hash_map< uint32_t, basisu::vector<uint32_t> > hm;316hm q;317318basisu::vector<uint32_t> a, b;319a.push_back(1);320b.push_back(2);321b.push_back(3);322323basisu::vector<uint32_t> c(b);324325hm::insert_result ir;326q.try_insert(ir, 1, std::move(a));327q.try_insert(ir, 2, std::move(b));328q.try_insert(ir, std::make_pair(3, c));329}330331{332typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;333my_hash_map m;334counted_obj a, b;335m.insert(std::move(a), std::move(b));336}337338{339basisu::hash_map<uint64_t, uint64_t> k;340basisu::hash_map<uint64_t, uint64_t> l;341std::swap(k, l);342343k.begin();344k.end();345k.clear();346k.empty();347k.erase(0);348k.insert(0, 1);349k.find(0);350k.get_equals();351k.get_hasher();352k.get_table_size();353k.reset();354k.reserve(1);355k = l;356k.set_equals(l.get_equals());357k.set_hasher(l.get_hasher());358k.get_table_size();359}360361uint32_t seed = 0;362for (; ; )363{364seed++;365366typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;367my_hash_map m;368369const uint32_t n = irand32(1, 100000);370371printf("%u\n", n);372373srand(seed); // r1.seed(seed);374375basisu::vector<int> q;376377uint32_t count = 0;378for (uint32_t i = 0; i < n; i++)379{380uint32_t v = urand32() & 0x7FFFFFFF;381my_hash_map::insert_result res = m.insert(counted_obj(v), counted_obj(v ^ 0xdeadbeef));382if (res.second)383{384count++;385q.push_back(v);386}387}388389HASHMAP_TEST_VERIFY(m.size() == count);390391srand(seed);392393my_hash_map cm(m);394m.clear();395m = cm;396cm.reset();397398for (uint32_t i = 0; i < n; i++)399{400uint32_t v = urand32() & 0x7FFFFFFF;401my_hash_map::const_iterator it = m.find(counted_obj(v));402HASHMAP_TEST_VERIFY(it != m.end());403HASHMAP_TEST_VERIFY(it->first == v);404HASHMAP_TEST_VERIFY(it->second == (v ^ 0xdeadbeef));405}406407for (uint32_t t = 0; t < 2; t++)408{409const uint32_t nd = irand32(1, q.size_u32() + 1);410for (uint32_t i = 0; i < nd; i++)411{412uint32_t p = irand32(0, q.size_u32());413414int k = q[p];415if (k >= 0)416{417q[p] = -k - 1;418419bool s = m.erase(counted_obj(k));420HASHMAP_TEST_VERIFY(s);421}422}423424typedef basisu::hash_map<uint32_t, empty_type> uint_hash_set;425uint_hash_set s;426427for (uint32_t i = 0; i < q.size(); i++)428{429int v = q[i];430431if (v >= 0)432{433my_hash_map::const_iterator it = m.find(counted_obj(v));434HASHMAP_TEST_VERIFY(it != m.end());435HASHMAP_TEST_VERIFY(it->first == (uint32_t)v);436HASHMAP_TEST_VERIFY(it->second == ((uint32_t)v ^ 0xdeadbeef));437438s.insert(v);439}440else441{442my_hash_map::const_iterator it = m.find(counted_obj(-v - 1));443HASHMAP_TEST_VERIFY(it == m.end());444}445}446447uint32_t found_count = 0;448for (my_hash_map::const_iterator it = m.begin(); it != m.end(); ++it)449{450HASHMAP_TEST_VERIFY(it->second == ((uint32_t)it->first ^ 0xdeadbeef));451452uint_hash_set::const_iterator fit(s.find((uint32_t)it->first));453HASHMAP_TEST_VERIFY(fit != s.end());454455HASHMAP_TEST_VERIFY(fit->first == it->first);456457found_count++;458}459460HASHMAP_TEST_VERIFY(found_count == s.size());461}462463HASHMAP_TEST_VERIFY(counted_obj::m_count == m.size() * 2);464}465}466467#endif // BASISU_HASHMAP_TEST468469// String formatting470471bool fmt_variant::to_string(std::string& res, std::string& fmt) const472{473res.resize(0);474475// Scan for allowed formatting characters.476for (size_t i = 0; i < fmt.size(); i++)477{478const char c = fmt[i];479480if (isdigit(c) || (c == '.') || (c == ' ') || (c == '#') || (c == '+') || (c == '-'))481continue;482483if (isalpha(c))484{485if ((i + 1) == fmt.size())486continue;487}488489return false;490}491492if (fmt.size() && (fmt.back() == 'c'))493{494if ((m_type == variant_type::cI32) || (m_type == variant_type::cU32))495{496if (m_u32 > 255)497return false;498499// Explictly allowing caller to pass in a char of 0, which is ignored.500if (m_u32)501res.push_back((uint8_t)m_u32);502return true;503}504else505return false;506}507508switch (m_type)509{510case variant_type::cInvalid:511{512return false;513}514case variant_type::cI32:515{516if (fmt.size())517{518int e = fmt.back();519if (isalpha(e))520{521if ((e != 'x') && (e != 'X') && (e != 'i') && (e != 'd') && (e != 'u'))522return false;523}524else525{526fmt += "i";527}528529res = string_format((std::string("%") + fmt).c_str(), m_i32);530}531else532{533res = string_format("%i", m_i32);534}535break;536}537case variant_type::cU32:538{539if (fmt.size())540{541int e = fmt.back();542if (isalpha(e))543{544if ((e != 'x') && (e != 'X') && (e != 'i') && (e != 'd') && (e != 'u'))545return false;546}547else548{549fmt += "u";550}551552res = string_format((std::string("%") + fmt).c_str(), m_u32);553}554else555{556res = string_format("%u", m_u32);557}558break;559}560case variant_type::cI64:561{562if (fmt.size())563{564int e = fmt.back();565if (isalpha(e))566{567if (e == 'x')568{569fmt.pop_back();570fmt += PRIx64;571}572else if (e == 'X')573{574fmt.pop_back();575fmt += PRIX64;576}577else578return false;579}580else581{582fmt += PRId64;583}584585res = string_format((std::string("%") + fmt).c_str(), m_i64);586}587else588{589res = string_format("%" PRId64, m_i64);590}591break;592}593case variant_type::cU64:594{595if (fmt.size())596{597int e = fmt.back();598if (isalpha(e))599{600if (e == 'x')601{602fmt.pop_back();603fmt += PRIx64;604}605else if (e == 'X')606{607fmt.pop_back();608fmt += PRIX64;609}610else611return false;612}613else614{615fmt += PRIu64;616}617618res = string_format((std::string("%") + fmt).c_str(), m_u64);619}620else621{622res = string_format("%" PRIu64, m_u64);623}624break;625}626case variant_type::cFlt:627{628if (fmt.size())629{630int e = fmt.back();631if (isalpha(e))632{633if ((e != 'f') && (e != 'g') && (e != 'e') && (e != 'E'))634return false;635}636else637{638fmt += "f";639}640641res = string_format((std::string("%") + fmt).c_str(), m_flt);642}643else644{645res = string_format("%f", m_flt);646}647break;648}649case variant_type::cDbl:650{651if (fmt.size())652{653int e = fmt.back();654if (isalpha(e))655{656if ((e != 'f') && (e != 'g') && (e != 'e') && (e != 'E'))657return false;658}659else660{661fmt += "f";662}663664res = string_format((std::string("%") + fmt).c_str(), m_dbl);665}666else667{668res = string_format("%f", m_dbl);669}670break;671}672case variant_type::cStrPtr:673{674if (fmt.size())675return false;676if (!m_pStr)677return false;678res = m_pStr;679break;680}681case variant_type::cBool:682{683if (fmt.size())684return false;685res = m_bool ? "true" : "false";686break;687}688case variant_type::cStdStr:689{690if (fmt.size())691return false;692res = m_str;693break;694}695default:696{697return false;698}699}700701return true;702}703704bool fmt_variants(std::string& res, const char* pFmt, const fmt_variant_vec& variants)705{706res.resize(0);707708// Must specify a format string709if (!pFmt)710{711assert(0);712return false;713}714715// Check format string's length716const size_t fmt_len = strlen(pFmt);717if (!fmt_len)718{719if (variants.size())720{721assert(0);722return false;723}724return true;725}726727// Wildly estimate output length728res.reserve(fmt_len + 32);729730std::string var_fmt;731var_fmt.reserve(16);732733std::string tmp;734tmp.reserve(16);735736size_t variant_index = 0;737bool inside_brackets = false;738const char* p = pFmt;739740while (*p)741{742const uint8_t c = *p++;743744if (inside_brackets)745{746if (c == '}')747{748inside_brackets = false;749750if (variant_index >= variants.size())751{752assert(0);753return false;754}755756if (!variants[variant_index].to_string(tmp, var_fmt))757{758assert(0);759return false;760}761762res += tmp;763764variant_index++;765}766else767{768// Check for forbidden formatting characters.769if ((c == '*') || (c == 'n') || (c == '%'))770{771assert(0);772return false;773}774775var_fmt.push_back(c);776}777}778else if (c == '{')779{780// Check for escaped '{'781if (*p == '{')782{783res.push_back((char)c);784p++;785}786else787{788inside_brackets = true;789var_fmt.resize(0);790}791}792else793{794res.push_back((char)c);795}796}797798if (inside_brackets)799{800assert(0);801return false;802}803804if (variant_index != variants.size())805{806assert(0);807return false;808}809810return true;811}812813} // namespace basisu814815816