Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
godotengine
GitHub Repository: godotengine/godot
Path: blob/master/thirdparty/basis_universal/transcoder/basisu_containers_impl.h
21100 views
1
// basisu_containers_impl.h
2
// Do not include directly
3
4
#include <ctype.h>
5
#include <exception>
6
7
#ifdef _MSC_VER
8
#pragma warning (disable:4127) // warning C4127: conditional expression is constant
9
#endif
10
11
namespace basisu
12
{
13
// A container operation has internally panicked in an unrecoverable way.
14
// Either an allocation has failed, or a range or consistency check has failed.
15
#ifdef _MSC_VER
16
__declspec(noreturn)
17
#else
18
[[noreturn]]
19
#endif
20
void container_abort(const char* pMsg, ...)
21
{
22
assert(0);
23
24
va_list args;
25
va_start(args, pMsg);
26
27
char buf[1024] = {};
28
29
#ifdef _MSC_VER
30
vsprintf_s(buf, sizeof(buf), pMsg, args);
31
#else
32
vsnprintf(buf, sizeof(buf), pMsg, args);
33
#endif
34
va_end(args);
35
36
fputs(buf, stderr);
37
38
std::terminate();
39
}
40
41
bool elemental_vector::increase_capacity(size_t min_new_capacity, bool grow_hint, size_t element_size, object_mover pMover, bool nofail_flag)
42
{
43
assert(m_size <= m_capacity);
44
assert(min_new_capacity >= m_size);
45
assert(element_size);
46
47
// Basic sanity check min_new_capacity
48
if (!can_fit_into_size_t((uint64_t)min_new_capacity * element_size))
49
{
50
assert(0);
51
52
if (nofail_flag)
53
return false;
54
55
container_abort("elemental_vector::increase_capacity: requesting too many elements\n");
56
}
57
58
// Check for sane library limits
59
if (sizeof(void*) == sizeof(uint64_t))
60
{
61
// 16 GB
62
assert(min_new_capacity < (0x400000000ULL / element_size));
63
}
64
else
65
{
66
// ~1.99 GB
67
assert(min_new_capacity < (0x7FFF0000U / element_size));
68
}
69
70
// If vector is already large enough just return.
71
if (m_capacity >= min_new_capacity)
72
return true;
73
74
uint64_t new_capacity_u64 = min_new_capacity;
75
76
if ((grow_hint) && (!helpers::is_power_of_2(new_capacity_u64)))
77
{
78
new_capacity_u64 = helpers::next_pow2(new_capacity_u64);
79
80
if (!can_fit_into_size_t(new_capacity_u64))
81
{
82
assert(0);
83
84
if (nofail_flag)
85
return false;
86
87
container_abort("elemental_vector::increase_capacity: vector too large\n");
88
}
89
}
90
91
const uint64_t desired_size_u64 = element_size * new_capacity_u64;
92
93
if (!can_fit_into_size_t(desired_size_u64))
94
{
95
assert(0);
96
97
if (nofail_flag)
98
return false;
99
100
container_abort("elemental_vector::increase_capacity: vector too large\n");
101
}
102
103
const size_t desired_size = static_cast<size_t>(desired_size_u64);
104
105
size_t actual_size = 0;
106
BASISU_NOTE_UNUSED(actual_size);
107
108
if (!pMover)
109
{
110
void* new_p = realloc(m_p, desired_size);
111
if (!new_p)
112
{
113
assert(0);
114
115
if (nofail_flag)
116
return false;
117
118
container_abort("elemental_vector::increase_capacity: realloc() failed allocating %zu bytes", desired_size);
119
}
120
121
#if BASISU_VECTOR_DETERMINISTIC
122
actual_size = desired_size;
123
#elif defined(_MSC_VER)
124
actual_size = _msize(new_p);
125
#elif HAS_MALLOC_USABLE_SIZE
126
actual_size = malloc_usable_size(new_p);
127
#else
128
actual_size = desired_size;
129
#endif
130
m_p = new_p;
131
}
132
else
133
{
134
void* new_p = malloc(desired_size);
135
if (!new_p)
136
{
137
assert(0);
138
if (nofail_flag)
139
return false;
140
141
container_abort("elemental_vector::increase_capacity: malloc() failed allocating %zu bytes", desired_size);
142
}
143
144
#if BASISU_VECTOR_DETERMINISTIC
145
actual_size = desired_size;
146
#elif defined(_MSC_VER)
147
actual_size = _msize(new_p);
148
#elif HAS_MALLOC_USABLE_SIZE
149
actual_size = malloc_usable_size(new_p);
150
#else
151
actual_size = desired_size;
152
#endif
153
154
(*pMover)(new_p, m_p, m_size);
155
156
if (m_p)
157
free(m_p);
158
159
m_p = new_p;
160
}
161
162
#if BASISU_VECTOR_DETERMINISTIC
163
m_capacity = static_cast<size_t>(new_capacity_u64);
164
#else
165
if (actual_size > desired_size)
166
m_capacity = static_cast<size_t>(actual_size / element_size);
167
else
168
m_capacity = static_cast<size_t>(new_capacity_u64);
169
#endif
170
171
return true;
172
}
173
174
#if BASISU_HASHMAP_TEST
175
176
#define HASHMAP_TEST_VERIFY(c) do { if (!(c)) handle_hashmap_test_verify_failure(__LINE__); } while(0)
177
178
static void handle_hashmap_test_verify_failure(int line)
179
{
180
container_abort("HASHMAP_TEST_VERIFY() faild on line %i\n", line);
181
}
182
183
class counted_obj
184
{
185
public:
186
counted_obj(uint32_t v = 0) :
187
m_val(v)
188
{
189
m_count++;
190
}
191
192
counted_obj(const counted_obj& obj) :
193
m_val(obj.m_val)
194
{
195
if (m_val != UINT64_MAX)
196
m_count++;
197
}
198
199
counted_obj(counted_obj&& obj) :
200
m_val(obj.m_val)
201
{
202
obj.m_val = UINT64_MAX;
203
}
204
205
counted_obj& operator= (counted_obj&& rhs)
206
{
207
if (this != &rhs)
208
{
209
m_val = rhs.m_val;
210
rhs.m_val = UINT64_MAX;
211
}
212
return *this;
213
}
214
215
~counted_obj()
216
{
217
if (m_val != UINT64_MAX)
218
{
219
assert(m_count > 0);
220
m_count--;
221
}
222
}
223
224
static uint32_t m_count;
225
226
uint64_t m_val;
227
228
operator size_t() const { return (size_t)m_val; }
229
230
bool operator== (const counted_obj& rhs) const { return m_val == rhs.m_val; }
231
bool operator== (const uint32_t rhs) const { return m_val == rhs; }
232
233
};
234
235
uint32_t counted_obj::m_count;
236
237
static uint32_t urand32()
238
{
239
uint32_t a = rand();
240
uint32_t b = rand() << 15;
241
uint32_t c = rand() << (32 - 15);
242
return a ^ b ^ c;
243
}
244
245
static int irand32(int l, int h)
246
{
247
assert(l < h);
248
if (l >= h)
249
return l;
250
251
uint32_t range = static_cast<uint32_t>(h - l);
252
253
uint32_t rnd = urand32();
254
255
uint32_t rnd_range = static_cast<uint32_t>((((uint64_t)range) * ((uint64_t)rnd)) >> 32U);
256
257
int result = l + rnd_range;
258
assert((result >= l) && (result < h));
259
return result;
260
}
261
262
void hash_map_test()
263
{
264
{
265
basisu::hash_map<uint32_t> s;
266
uint_vec k;
267
268
for (uint32_t i = 0; i < 1000000; i++)
269
{
270
s.insert(i);
271
k.push_back(i);
272
}
273
274
for (uint32_t i = 0; i < k.size(); i++)
275
{
276
uint32_t r = rand() ^ (rand() << 15);
277
278
uint32_t j = i + (r % (k.size() - i));
279
280
std::swap(k[i], k[j]);
281
}
282
283
basisu::hash_map<uint32_t> s1(s);
284
285
for (uint32_t i = 0; i < 1000000; i++)
286
{
287
auto res = s.find(i);
288
HASHMAP_TEST_VERIFY(res != s.end());
289
HASHMAP_TEST_VERIFY(res->first == i);
290
s.erase(i);
291
}
292
293
for (uint32_t it = 0; it < 1000000; it++)
294
{
295
uint32_t i = k[it];
296
297
auto res = s1.find(i);
298
HASHMAP_TEST_VERIFY(res != s.end());
299
HASHMAP_TEST_VERIFY(res->first == i);
300
s1.erase(i);
301
}
302
303
for (uint32_t i = 0; i < 1000000; i++)
304
{
305
auto res = s.find(i);
306
HASHMAP_TEST_VERIFY(res == s.end());
307
308
auto res1 = s1.find(i);
309
HASHMAP_TEST_VERIFY(res1 == s1.end());
310
}
311
312
HASHMAP_TEST_VERIFY(s.empty());
313
HASHMAP_TEST_VERIFY(s1.empty());
314
}
315
316
{
317
typedef basisu::hash_map< uint32_t, basisu::vector<uint32_t> > hm;
318
hm q;
319
320
basisu::vector<uint32_t> a, b;
321
a.push_back(1);
322
b.push_back(2);
323
b.push_back(3);
324
325
basisu::vector<uint32_t> c(b);
326
327
hm::insert_result ir;
328
q.try_insert(ir, 1, std::move(a));
329
q.try_insert(ir, 2, std::move(b));
330
q.try_insert(ir, std::make_pair(3, c));
331
}
332
333
{
334
typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;
335
my_hash_map m;
336
counted_obj a, b;
337
m.insert(std::move(a), std::move(b));
338
}
339
340
{
341
basisu::hash_map<uint64_t, uint64_t> k;
342
basisu::hash_map<uint64_t, uint64_t> l;
343
std::swap(k, l);
344
345
k.begin();
346
k.end();
347
k.clear();
348
k.empty();
349
k.erase(0);
350
k.insert(0, 1);
351
k.find(0);
352
k.get_equals();
353
k.get_hasher();
354
k.get_table_size();
355
k.reset();
356
k.reserve(1);
357
k = l;
358
k.set_equals(l.get_equals());
359
k.set_hasher(l.get_hasher());
360
k.get_table_size();
361
}
362
363
uint32_t seed = 0;
364
for (; ; )
365
{
366
seed++;
367
368
typedef basisu::hash_map<counted_obj, counted_obj> my_hash_map;
369
my_hash_map m;
370
371
const uint32_t n = irand32(1, 100000);
372
373
printf("%u\n", n);
374
375
srand(seed); // r1.seed(seed);
376
377
basisu::vector<int> q;
378
379
uint32_t count = 0;
380
for (uint32_t i = 0; i < n; i++)
381
{
382
uint32_t v = urand32() & 0x7FFFFFFF;
383
my_hash_map::insert_result res = m.insert(counted_obj(v), counted_obj(v ^ 0xdeadbeef));
384
if (res.second)
385
{
386
count++;
387
q.push_back(v);
388
}
389
}
390
391
HASHMAP_TEST_VERIFY(m.size() == count);
392
393
srand(seed);
394
395
my_hash_map cm(m);
396
m.clear();
397
m = cm;
398
cm.reset();
399
400
for (uint32_t i = 0; i < n; i++)
401
{
402
uint32_t v = urand32() & 0x7FFFFFFF;
403
my_hash_map::const_iterator it = m.find(counted_obj(v));
404
HASHMAP_TEST_VERIFY(it != m.end());
405
HASHMAP_TEST_VERIFY(it->first == v);
406
HASHMAP_TEST_VERIFY(it->second == (v ^ 0xdeadbeef));
407
}
408
409
for (uint32_t t = 0; t < 2; t++)
410
{
411
const uint32_t nd = irand32(1, q.size_u32() + 1);
412
for (uint32_t i = 0; i < nd; i++)
413
{
414
uint32_t p = irand32(0, q.size_u32());
415
416
int k = q[p];
417
if (k >= 0)
418
{
419
q[p] = -k - 1;
420
421
bool s = m.erase(counted_obj(k));
422
HASHMAP_TEST_VERIFY(s);
423
}
424
}
425
426
typedef basisu::hash_map<uint32_t, empty_type> uint_hash_set;
427
uint_hash_set s;
428
429
for (uint32_t i = 0; i < q.size(); i++)
430
{
431
int v = q[i];
432
433
if (v >= 0)
434
{
435
my_hash_map::const_iterator it = m.find(counted_obj(v));
436
HASHMAP_TEST_VERIFY(it != m.end());
437
HASHMAP_TEST_VERIFY(it->first == (uint32_t)v);
438
HASHMAP_TEST_VERIFY(it->second == ((uint32_t)v ^ 0xdeadbeef));
439
440
s.insert(v);
441
}
442
else
443
{
444
my_hash_map::const_iterator it = m.find(counted_obj(-v - 1));
445
HASHMAP_TEST_VERIFY(it == m.end());
446
}
447
}
448
449
uint32_t found_count = 0;
450
for (my_hash_map::const_iterator it = m.begin(); it != m.end(); ++it)
451
{
452
HASHMAP_TEST_VERIFY(it->second == ((uint32_t)it->first ^ 0xdeadbeef));
453
454
uint_hash_set::const_iterator fit(s.find((uint32_t)it->first));
455
HASHMAP_TEST_VERIFY(fit != s.end());
456
457
HASHMAP_TEST_VERIFY(fit->first == it->first);
458
459
found_count++;
460
}
461
462
HASHMAP_TEST_VERIFY(found_count == s.size());
463
}
464
465
HASHMAP_TEST_VERIFY(counted_obj::m_count == m.size() * 2);
466
}
467
}
468
469
#endif // BASISU_HASHMAP_TEST
470
471
// String formatting
472
473
bool fmt_variant::to_string(std::string& res, std::string& fmt) const
474
{
475
res.resize(0);
476
477
// Scan for allowed formatting characters.
478
for (size_t i = 0; i < fmt.size(); i++)
479
{
480
const char c = fmt[i];
481
482
if (isdigit(c) || (c == '.') || (c == ' ') || (c == '#') || (c == '+') || (c == '-'))
483
continue;
484
485
if (isalpha(c))
486
{
487
if ((i + 1) == fmt.size())
488
continue;
489
}
490
491
return false;
492
}
493
494
if (fmt.size() && (fmt.back() == 'c'))
495
{
496
if ((m_type == variant_type::cI32) || (m_type == variant_type::cU32))
497
{
498
if (m_u32 > 255)
499
return false;
500
501
// Explictly allowing caller to pass in a char of 0, which is ignored.
502
if (m_u32)
503
res.push_back((uint8_t)m_u32);
504
return true;
505
}
506
else
507
return false;
508
}
509
510
switch (m_type)
511
{
512
case variant_type::cInvalid:
513
{
514
return false;
515
}
516
case variant_type::cI32:
517
{
518
if (fmt.size())
519
{
520
int e = fmt.back();
521
if (isalpha(e))
522
{
523
if ((e != 'x') && (e != 'X') && (e != 'i') && (e != 'd') && (e != 'u'))
524
return false;
525
}
526
else
527
{
528
fmt += "i";
529
}
530
531
res = string_format((std::string("%") + fmt).c_str(), m_i32);
532
}
533
else
534
{
535
res = string_format("%i", m_i32);
536
}
537
break;
538
}
539
case variant_type::cU32:
540
{
541
if (fmt.size())
542
{
543
int e = fmt.back();
544
if (isalpha(e))
545
{
546
if ((e != 'x') && (e != 'X') && (e != 'i') && (e != 'd') && (e != 'u'))
547
return false;
548
}
549
else
550
{
551
fmt += "u";
552
}
553
554
res = string_format((std::string("%") + fmt).c_str(), m_u32);
555
}
556
else
557
{
558
res = string_format("%u", m_u32);
559
}
560
break;
561
}
562
case variant_type::cI64:
563
{
564
if (fmt.size())
565
{
566
int e = fmt.back();
567
if (isalpha(e))
568
{
569
if (e == 'x')
570
{
571
fmt.pop_back();
572
fmt += PRIx64;
573
}
574
else if (e == 'X')
575
{
576
fmt.pop_back();
577
fmt += PRIX64;
578
}
579
else
580
return false;
581
}
582
else
583
{
584
fmt += PRId64;
585
}
586
587
res = string_format((std::string("%") + fmt).c_str(), m_i64);
588
}
589
else
590
{
591
res = string_format("%" PRId64, m_i64);
592
}
593
break;
594
}
595
case variant_type::cU64:
596
{
597
if (fmt.size())
598
{
599
int e = fmt.back();
600
if (isalpha(e))
601
{
602
if (e == 'x')
603
{
604
fmt.pop_back();
605
fmt += PRIx64;
606
}
607
else if (e == 'X')
608
{
609
fmt.pop_back();
610
fmt += PRIX64;
611
}
612
else
613
return false;
614
}
615
else
616
{
617
fmt += PRIu64;
618
}
619
620
res = string_format((std::string("%") + fmt).c_str(), m_u64);
621
}
622
else
623
{
624
res = string_format("%" PRIu64, m_u64);
625
}
626
break;
627
}
628
case variant_type::cFlt:
629
{
630
if (fmt.size())
631
{
632
int e = fmt.back();
633
if (isalpha(e))
634
{
635
if ((e != 'f') && (e != 'g') && (e != 'e') && (e != 'E'))
636
return false;
637
}
638
else
639
{
640
fmt += "f";
641
}
642
643
res = string_format((std::string("%") + fmt).c_str(), m_flt);
644
}
645
else
646
{
647
res = string_format("%f", m_flt);
648
}
649
break;
650
}
651
case variant_type::cDbl:
652
{
653
if (fmt.size())
654
{
655
int e = fmt.back();
656
if (isalpha(e))
657
{
658
if ((e != 'f') && (e != 'g') && (e != 'e') && (e != 'E'))
659
return false;
660
}
661
else
662
{
663
fmt += "f";
664
}
665
666
res = string_format((std::string("%") + fmt).c_str(), m_dbl);
667
}
668
else
669
{
670
res = string_format("%f", m_dbl);
671
}
672
break;
673
}
674
case variant_type::cStrPtr:
675
{
676
if (fmt.size())
677
return false;
678
if (!m_pStr)
679
return false;
680
res = m_pStr;
681
break;
682
}
683
case variant_type::cBool:
684
{
685
if (fmt.size())
686
return false;
687
res = m_bool ? "true" : "false";
688
break;
689
}
690
case variant_type::cStdStr:
691
{
692
if (fmt.size())
693
return false;
694
res = m_str;
695
break;
696
}
697
default:
698
{
699
return false;
700
}
701
}
702
703
return true;
704
}
705
706
bool fmt_variants(std::string& res, const char* pFmt, const fmt_variant_vec& variants)
707
{
708
res.resize(0);
709
710
// Must specify a format string
711
if (!pFmt)
712
{
713
assert(0);
714
return false;
715
}
716
717
// Check format string's length
718
const size_t fmt_len = strlen(pFmt);
719
if (!fmt_len)
720
{
721
if (variants.size())
722
{
723
assert(0);
724
return false;
725
}
726
return true;
727
}
728
729
// Wildly estimate output length
730
res.reserve(fmt_len + 32);
731
732
std::string var_fmt;
733
var_fmt.reserve(16);
734
735
std::string tmp;
736
tmp.reserve(16);
737
738
size_t variant_index = 0;
739
bool inside_brackets = false;
740
const char* p = pFmt;
741
742
while (*p)
743
{
744
const uint8_t c = *p++;
745
746
if (inside_brackets)
747
{
748
if (c == '}')
749
{
750
inside_brackets = false;
751
752
if (variant_index >= variants.size())
753
{
754
assert(0);
755
return false;
756
}
757
758
if (!variants[variant_index].to_string(tmp, var_fmt))
759
{
760
assert(0);
761
return false;
762
}
763
764
res += tmp;
765
766
variant_index++;
767
}
768
else
769
{
770
// Check for forbidden formatting characters.
771
if ((c == '*') || (c == 'n') || (c == '%'))
772
{
773
assert(0);
774
return false;
775
}
776
777
var_fmt.push_back(c);
778
}
779
}
780
else if (c == '{')
781
{
782
// Check for escaped '{'
783
if (*p == '{')
784
{
785
res.push_back((char)c);
786
p++;
787
}
788
else
789
{
790
inside_brackets = true;
791
var_fmt.resize(0);
792
}
793
}
794
else
795
{
796
res.push_back((char)c);
797
}
798
}
799
800
if (inside_brackets)
801
{
802
assert(0);
803
return false;
804
}
805
806
if (variant_index != variants.size())
807
{
808
assert(0);
809
return false;
810
}
811
812
return true;
813
}
814
815
} // namespace basisu
816
817