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