Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
stenzek
GitHub Repository: stenzek/duckstation
Path: blob/master/dep/rapidyaml/include/c4/memory_util.hpp
4261 views
1
#ifndef _C4_MEMORY_UTIL_HPP_
2
#define _C4_MEMORY_UTIL_HPP_
3
4
#include "c4/config.hpp"
5
#include "c4/error.hpp"
6
#include "c4/compiler.hpp"
7
#include "c4/cpu.hpp"
8
#ifdef C4_MSVC
9
#include <intrin.h>
10
#endif
11
#include <string.h>
12
13
#if (defined(__GNUC__) && __GNUC__ >= 10) || defined(__has_builtin)
14
#define _C4_USE_LSB_INTRINSIC(which) __has_builtin(which)
15
#define _C4_USE_MSB_INTRINSIC(which) __has_builtin(which)
16
#elif defined(C4_MSVC)
17
#define _C4_USE_LSB_INTRINSIC(which) true
18
#define _C4_USE_MSB_INTRINSIC(which) true
19
#else
20
// let's try our luck
21
#define _C4_USE_LSB_INTRINSIC(which) true
22
#define _C4_USE_MSB_INTRINSIC(which) true
23
#endif
24
25
26
/** @file memory_util.hpp Some memory utilities. */
27
28
namespace c4 {
29
30
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wold-style-cast")
31
32
/** set the given memory to zero */
33
C4_ALWAYS_INLINE void mem_zero(void* mem, size_t num_bytes)
34
{
35
memset(mem, 0, num_bytes);
36
}
37
/** set the given memory to zero */
38
template<class T>
39
C4_ALWAYS_INLINE void mem_zero(T* mem, size_t num_elms)
40
{
41
memset(mem, 0, sizeof(T) * num_elms);
42
}
43
/** set the given memory to zero */
44
template<class T>
45
C4_ALWAYS_INLINE void mem_zero(T* mem)
46
{
47
memset(mem, 0, sizeof(T));
48
}
49
50
C4_ALWAYS_INLINE C4_CONST bool mem_overlaps(void const* a, void const* b, size_t sza, size_t szb)
51
{
52
// thanks @timwynants
53
return (((const char*)b + szb) > a && b < ((const char*)a+sza));
54
}
55
56
void mem_repeat(void* dest, void const* pattern, size_t pattern_size, size_t num_times);
57
58
59
//-----------------------------------------------------------------------------
60
//-----------------------------------------------------------------------------
61
//-----------------------------------------------------------------------------
62
63
template<class T>
64
C4_ALWAYS_INLINE C4_CONST bool is_aligned(T *ptr, uintptr_t alignment=alignof(T))
65
{
66
return (uintptr_t(ptr) & (alignment - uintptr_t(1))) == uintptr_t(0);
67
}
68
69
70
//-----------------------------------------------------------------------------
71
//-----------------------------------------------------------------------------
72
//-----------------------------------------------------------------------------
73
// least significant bit
74
75
/** @name msb Compute the least significant bit
76
* @note the input value must be nonzero
77
* @note the input type must be unsigned
78
*/
79
/** @{ */
80
81
// https://graphics.stanford.edu/~seander/bithacks.html#ZerosOnRightLinear
82
#define _c4_lsb_fallback \
83
unsigned c = 0; \
84
v = (v ^ (v - 1)) >> 1; /* Set v's trailing 0s to 1s and zero rest */ \
85
for(; v; ++c) \
86
v >>= 1; \
87
return (unsigned) c
88
89
// u8
90
template<class I>
91
C4_CONSTEXPR14
92
auto lsb(I v) noexcept
93
-> typename std::enable_if<sizeof(I) == 1u, unsigned>::type
94
{
95
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
96
C4_ASSERT(v != 0);
97
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
98
// upcast to use the intrinsic, it's cheaper.
99
#ifdef C4_MSVC
100
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
101
unsigned long bit;
102
_BitScanForward(&bit, (unsigned long)v);
103
return bit;
104
#else
105
_c4_lsb_fallback;
106
#endif
107
#else
108
return (unsigned)__builtin_ctz((unsigned)v);
109
#endif
110
#else
111
_c4_lsb_fallback;
112
#endif
113
}
114
115
// u16
116
template<class I>
117
C4_CONSTEXPR14
118
auto lsb(I v) noexcept
119
-> typename std::enable_if<sizeof(I) == 2u, unsigned>::type
120
{
121
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
122
C4_ASSERT(v != 0);
123
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
124
// upcast to use the intrinsic, it's cheaper.
125
// Then remember that the upcast makes it to 31bits
126
#ifdef C4_MSVC
127
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
128
unsigned long bit;
129
_BitScanForward(&bit, (unsigned long)v);
130
return bit;
131
#else
132
_c4_lsb_fallback;
133
#endif
134
#else
135
return (unsigned)__builtin_ctz((unsigned)v);
136
#endif
137
#else
138
_c4_lsb_fallback;
139
#endif
140
}
141
142
// u32
143
template<class I>
144
C4_CONSTEXPR14
145
auto lsb(I v) noexcept
146
-> typename std::enable_if<sizeof(I) == 4u, unsigned>::type
147
{
148
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
149
C4_ASSERT(v != 0);
150
#if _C4_USE_LSB_INTRINSIC(__builtin_ctz)
151
#ifdef C4_MSVC
152
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
153
unsigned long bit;
154
_BitScanForward(&bit, v);
155
return bit;
156
#else
157
_c4_lsb_fallback;
158
#endif
159
#else
160
return (unsigned)__builtin_ctz((unsigned)v);
161
#endif
162
#else
163
_c4_lsb_fallback;
164
#endif
165
}
166
167
// u64 in 64bits
168
template<class I>
169
C4_CONSTEXPR14
170
auto lsb(I v) noexcept
171
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long) == 8u, unsigned>::type
172
{
173
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
174
C4_ASSERT(v != 0);
175
#if _C4_USE_LSB_INTRINSIC(__builtin_ctzl)
176
#if defined(C4_MSVC)
177
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
178
unsigned long bit;
179
_BitScanForward64(&bit, v);
180
return bit;
181
#else
182
_c4_lsb_fallback;
183
#endif
184
#else
185
return (unsigned)__builtin_ctzl((unsigned long)v);
186
#endif
187
#else
188
_c4_lsb_fallback;
189
#endif
190
}
191
192
// u64 in 32bits
193
template<class I>
194
C4_CONSTEXPR14
195
auto lsb(I v) noexcept
196
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long long) == 8u && sizeof(unsigned long) != sizeof(unsigned long long), unsigned>::type
197
{
198
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
199
C4_ASSERT(v != 0);
200
#if _C4_USE_LSB_INTRINSIC(__builtin_ctzll)
201
#if defined(C4_MSVC)
202
#if !defined(C4_CPU_X86) && !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
203
unsigned long bit;
204
_BitScanForward64(&bit, v);
205
return bit;
206
#else
207
_c4_lsb_fallback;
208
#endif
209
#else
210
return (unsigned)__builtin_ctzll((unsigned long long)v);
211
#endif
212
#else
213
_c4_lsb_fallback;
214
#endif
215
}
216
217
#undef _c4_lsb_fallback
218
219
/** @} */
220
221
222
namespace detail {
223
template<class I, I val, unsigned num_bits, bool finished> struct _lsb11;
224
template<class I, I val, unsigned num_bits>
225
struct _lsb11<I, val, num_bits, false>
226
{
227
enum : unsigned { num = _lsb11<I, (val>>1), num_bits+I(1), (((val>>1)&I(1))!=I(0))>::num };
228
};
229
template<class I, I val, unsigned num_bits>
230
struct _lsb11<I, val, num_bits, true>
231
{
232
enum : unsigned { num = num_bits };
233
};
234
} // namespace detail
235
236
237
/** TMP version of lsb(); this needs to be implemented with template
238
* meta-programming because C++11 cannot use a constexpr function with
239
* local variables
240
* @see lsb */
241
template<class I, I number>
242
struct lsb11
243
{
244
static_assert(number != 0, "lsb: number must be nonzero");
245
enum : unsigned { value = detail::_lsb11<I, number, 0, ((number&I(1))!=I(0))>::num};
246
};
247
248
249
//-----------------------------------------------------------------------------
250
//-----------------------------------------------------------------------------
251
//-----------------------------------------------------------------------------
252
// most significant bit
253
254
255
/** @name msb Compute the most significant bit
256
* @note the input value must be nonzero
257
* @note the input type must be unsigned
258
*/
259
/** @{ */
260
261
262
#define _c4_msb8_fallback \
263
unsigned n = 0; \
264
if(v & I(0xf0)) v >>= 4, n |= I(4); \
265
if(v & I(0x0c)) v >>= 2, n |= I(2); \
266
if(v & I(0x02)) v >>= 1, n |= I(1); \
267
return n
268
269
#define _c4_msb16_fallback \
270
unsigned n = 0; \
271
if(v & I(0xff00)) v >>= 8, n |= I(8); \
272
if(v & I(0x00f0)) v >>= 4, n |= I(4); \
273
if(v & I(0x000c)) v >>= 2, n |= I(2); \
274
if(v & I(0x0002)) v >>= 1, n |= I(1); \
275
return n
276
277
#define _c4_msb32_fallback \
278
unsigned n = 0; \
279
if(v & I(0xffff0000)) v >>= 16, n |= 16; \
280
if(v & I(0x0000ff00)) v >>= 8, n |= 8; \
281
if(v & I(0x000000f0)) v >>= 4, n |= 4; \
282
if(v & I(0x0000000c)) v >>= 2, n |= 2; \
283
if(v & I(0x00000002)) v >>= 1, n |= 1; \
284
return n
285
286
#define _c4_msb64_fallback \
287
unsigned n = 0; \
288
if(v & I(0xffffffff00000000)) v >>= 32, n |= I(32); \
289
if(v & I(0x00000000ffff0000)) v >>= 16, n |= I(16); \
290
if(v & I(0x000000000000ff00)) v >>= 8, n |= I(8); \
291
if(v & I(0x00000000000000f0)) v >>= 4, n |= I(4); \
292
if(v & I(0x000000000000000c)) v >>= 2, n |= I(2); \
293
if(v & I(0x0000000000000002)) v >>= 1, n |= I(1); \
294
return n
295
296
297
// u8
298
template<class I>
299
C4_CONSTEXPR14
300
auto msb(I v) noexcept
301
-> typename std::enable_if<sizeof(I) == 1u, unsigned>::type
302
{
303
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
304
C4_ASSERT(v != 0);
305
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
306
// upcast to use the intrinsic, it's cheaper.
307
// Then remember that the upcast makes it to 31bits
308
#ifdef C4_MSVC
309
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
310
unsigned long bit;
311
_BitScanReverse(&bit, (unsigned long)v);
312
return bit;
313
#else
314
_c4_msb8_fallback;
315
#endif
316
#else
317
return 31u - (unsigned)__builtin_clz((unsigned)v);
318
#endif
319
#else
320
_c4_msb8_fallback;
321
#endif
322
}
323
324
// u16
325
template<class I>
326
C4_CONSTEXPR14
327
auto msb(I v) noexcept
328
-> typename std::enable_if<sizeof(I) == 2u, unsigned>::type
329
{
330
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
331
C4_ASSERT(v != 0);
332
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
333
// upcast to use the intrinsic, it's cheaper.
334
// Then remember that the upcast makes it to 31bits
335
#ifdef C4_MSVC
336
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
337
unsigned long bit;
338
_BitScanReverse(&bit, (unsigned long)v);
339
return bit;
340
#else
341
_c4_msb16_fallback;
342
#endif
343
#else
344
return 31u - (unsigned)__builtin_clz((unsigned)v);
345
#endif
346
#else
347
_c4_msb16_fallback;
348
#endif
349
}
350
351
// u32
352
template<class I>
353
C4_CONSTEXPR14
354
auto msb(I v) noexcept
355
-> typename std::enable_if<sizeof(I) == 4u, unsigned>::type
356
{
357
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
358
C4_ASSERT(v != 0);
359
#if _C4_USE_MSB_INTRINSIC(__builtin_clz)
360
#ifdef C4_MSVC
361
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
362
unsigned long bit;
363
_BitScanReverse(&bit, v);
364
return bit;
365
#else
366
_c4_msb32_fallback;
367
#endif
368
#else
369
return 31u - (unsigned)__builtin_clz((unsigned)v);
370
#endif
371
#else
372
_c4_msb32_fallback;
373
#endif
374
}
375
376
// u64 in 64bits
377
template<class I>
378
C4_CONSTEXPR14
379
auto msb(I v) noexcept
380
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long) == 8u, unsigned>::type
381
{
382
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
383
C4_ASSERT(v != 0);
384
#if _C4_USE_MSB_INTRINSIC(__builtin_clzl)
385
#ifdef C4_MSVC
386
#if !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
387
unsigned long bit;
388
_BitScanReverse64(&bit, v);
389
return bit;
390
#else
391
_c4_msb64_fallback;
392
#endif
393
#else
394
return 63u - (unsigned)__builtin_clzl((unsigned long)v);
395
#endif
396
#else
397
_c4_msb64_fallback;
398
#endif
399
}
400
401
// u64 in 32bits
402
template<class I>
403
C4_CONSTEXPR14
404
auto msb(I v) noexcept
405
-> typename std::enable_if<sizeof(I) == 8u && sizeof(unsigned long long) == 8u && sizeof(unsigned long) != sizeof(unsigned long long), unsigned>::type
406
{
407
C4_STATIC_ASSERT(std::is_unsigned<I>::value);
408
C4_ASSERT(v != 0);
409
#if _C4_USE_MSB_INTRINSIC(__builtin_clzll)
410
#ifdef C4_MSVC
411
#if !defined(C4_CPU_X86) && !defined(C4_CPU_ARM64) && !defined(C4_CPU_ARM)
412
unsigned long bit;
413
_BitScanReverse64(&bit, v);
414
return bit;
415
#else
416
_c4_msb64_fallback;
417
#endif
418
#else
419
return 63u - (unsigned)__builtin_clzll((unsigned long long)v);
420
#endif
421
#else
422
_c4_msb64_fallback;
423
#endif
424
}
425
426
#undef _c4_msb8_fallback
427
#undef _c4_msb16_fallback
428
#undef _c4_msb32_fallback
429
#undef _c4_msb64_fallback
430
431
/** @} */
432
433
434
namespace detail {
435
template<class I, I val, I num_bits, bool finished> struct _msb11;
436
template<class I, I val, I num_bits>
437
struct _msb11< I, val, num_bits, false>
438
{
439
enum : unsigned { num = _msb11<I, (val>>1), num_bits+I(1), ((val>>1)==I(0))>::num };
440
};
441
template<class I, I val, I num_bits>
442
struct _msb11<I, val, num_bits, true>
443
{
444
static_assert(val == 0, "bad implementation");
445
enum : unsigned { num = (unsigned)(num_bits-1) };
446
};
447
} // namespace detail
448
449
450
/** TMP version of msb(); this needs to be implemented with template
451
* meta-programming because C++11 cannot use a constexpr function with
452
* local variables
453
* @see msb */
454
template<class I, I number>
455
struct msb11
456
{
457
enum : unsigned { value = detail::_msb11<I, number, 0, (number==I(0))>::num };
458
};
459
460
461
462
#undef _C4_USE_LSB_INTRINSIC
463
#undef _C4_USE_MSB_INTRINSIC
464
465
//-----------------------------------------------------------------------------
466
//-----------------------------------------------------------------------------
467
//-----------------------------------------------------------------------------
468
469
// there is an implicit conversion below; it happens when E or B are
470
// narrower than int, and thus any operation will upcast the result to
471
// int, and then downcast to assign
472
C4_SUPPRESS_WARNING_GCC_CLANG_WITH_PUSH("-Wconversion")
473
474
/** integer power; this function is constexpr-14 because of the local
475
* variables */
476
template<class B, class E>
477
C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
478
{
479
C4_STATIC_ASSERT(std::is_integral<E>::value);
480
B r = B(1);
481
if(exponent >= 0)
482
{
483
for(E e = 0; e < exponent; ++e)
484
r *= base;
485
}
486
else
487
{
488
exponent *= E(-1);
489
for(E e = 0; e < exponent; ++e)
490
r /= base;
491
}
492
return r;
493
}
494
495
/** integer power; this function is constexpr-14 because of the local
496
* variables */
497
template<class B, B base, class E>
498
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
499
{
500
C4_STATIC_ASSERT(std::is_integral<E>::value);
501
B r = B(1);
502
if(exponent >= 0)
503
{
504
for(E e = 0; e < exponent; ++e)
505
r *= base;
506
}
507
else
508
{
509
exponent *= E(-1);
510
for(E e = 0; e < exponent; ++e)
511
r /= base;
512
}
513
return r;
514
}
515
516
/** integer power; this function is constexpr-14 because of the local
517
* variables */
518
template<class B, class Base, Base base, class E>
519
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<std::is_signed<E>::value, B>::type
520
{
521
C4_STATIC_ASSERT(std::is_integral<E>::value);
522
B r = B(1);
523
B bbase = B(base);
524
if(exponent >= 0)
525
{
526
for(E e = 0; e < exponent; ++e)
527
r *= bbase;
528
}
529
else
530
{
531
exponent *= E(-1);
532
for(E e = 0; e < exponent; ++e)
533
r /= bbase;
534
}
535
return r;
536
}
537
538
/** integer power; this function is constexpr-14 because of the local
539
* variables */
540
template<class B, class E>
541
C4_CONSTEXPR14 C4_CONST auto ipow(B base, E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
542
{
543
C4_STATIC_ASSERT(std::is_integral<E>::value);
544
B r = B(1);
545
for(E e = 0; e < exponent; ++e)
546
r *= base;
547
return r;
548
}
549
550
/** integer power; this function is constexpr-14 because of the local
551
* variables */
552
template<class B, B base, class E>
553
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
554
{
555
C4_STATIC_ASSERT(std::is_integral<E>::value);
556
B r = B(1);
557
for(E e = 0; e < exponent; ++e)
558
r *= base;
559
return r;
560
}
561
/** integer power; this function is constexpr-14 because of the local
562
* variables */
563
template<class B, class Base, Base base, class E>
564
C4_CONSTEXPR14 C4_CONST auto ipow(E exponent) noexcept -> typename std::enable_if<!std::is_signed<E>::value, B>::type
565
{
566
C4_STATIC_ASSERT(std::is_integral<E>::value);
567
B r = B(1);
568
B bbase = B(base);
569
for(E e = 0; e < exponent; ++e)
570
r *= bbase;
571
return r;
572
}
573
574
C4_SUPPRESS_WARNING_GCC_CLANG_POP
575
576
577
//-----------------------------------------------------------------------------
578
//-----------------------------------------------------------------------------
579
//-----------------------------------------------------------------------------
580
581
/** return a mask with all bits set [first_bit,last_bit[; this function
582
* is constexpr-14 because of the local variables */
583
template<class I>
584
C4_CONSTEXPR14 I contiguous_mask(I first_bit, I last_bit)
585
{
586
I r = 0;
587
for(I i = first_bit; i < last_bit; ++i)
588
{
589
r |= (I(1) << i);
590
}
591
return r;
592
}
593
594
595
namespace detail {
596
597
template<class I, I val, I first, I last, bool finished>
598
struct _ctgmsk11;
599
600
template<class I, I val, I first, I last>
601
struct _ctgmsk11< I, val, first, last, true>
602
{
603
enum : I { value = _ctgmsk11<I, val|(I(1)<<first), first+I(1), last, (first+1!=last)>::value };
604
};
605
606
template<class I, I val, I first, I last>
607
struct _ctgmsk11< I, val, first, last, false>
608
{
609
enum : I { value = val };
610
};
611
612
} // namespace detail
613
614
615
/** TMP version of contiguous_mask(); this needs to be implemented with template
616
* meta-programming because C++11 cannot use a constexpr function with
617
* local variables
618
* @see contiguous_mask */
619
template<class I, I first_bit, I last_bit>
620
struct contiguous_mask11
621
{
622
enum : I { value = detail::_ctgmsk11<I, I(0), first_bit, last_bit, (first_bit!=last_bit)>::value };
623
};
624
625
626
//-----------------------------------------------------------------------------
627
//-----------------------------------------------------------------------------
628
//-----------------------------------------------------------------------------
629
/** use Empty Base Class Optimization to reduce the size of a pair of
630
* potentially empty types*/
631
632
namespace detail {
633
typedef enum {
634
tpc_same,
635
tpc_same_empty,
636
tpc_both_empty,
637
tpc_first_empty,
638
tpc_second_empty,
639
tpc_general
640
} TightPairCase_e;
641
642
template<class First, class Second>
643
constexpr TightPairCase_e tpc_which_case()
644
{
645
return std::is_same<First, Second>::value ?
646
std::is_empty<First>::value ?
647
tpc_same_empty
648
:
649
tpc_same
650
:
651
std::is_empty<First>::value && std::is_empty<Second>::value ?
652
tpc_both_empty
653
:
654
std::is_empty<First>::value ?
655
tpc_first_empty
656
:
657
std::is_empty<Second>::value ?
658
tpc_second_empty
659
:
660
tpc_general
661
;
662
}
663
664
template<class First, class Second, TightPairCase_e Case>
665
struct tight_pair
666
{
667
private:
668
669
First m_first;
670
Second m_second;
671
672
public:
673
674
using first_type = First;
675
using second_type = Second;
676
677
tight_pair() : m_first(), m_second() {}
678
tight_pair(First const& f, Second const& s) : m_first(f), m_second(s) {}
679
680
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return m_first; }
681
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return m_first; }
682
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
683
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
684
};
685
686
template<class First, class Second>
687
struct tight_pair<First, Second, tpc_same_empty> : public First
688
{
689
static_assert(std::is_same<First, Second>::value, "bad implementation");
690
691
using first_type = First;
692
using second_type = Second;
693
694
tight_pair() : First() {}
695
tight_pair(First const& f, Second const& /*s*/) : First(f) {}
696
697
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
698
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
699
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return reinterpret_cast<Second &>(*this); }
700
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return reinterpret_cast<Second const&>(*this); }
701
};
702
703
template<class First, class Second>
704
struct tight_pair<First, Second, tpc_both_empty> : public First, public Second
705
{
706
using first_type = First;
707
using second_type = Second;
708
709
tight_pair() : First(), Second() {}
710
tight_pair(First const& f, Second const& s) : First(f), Second(s) {}
711
712
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
713
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
714
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast<Second &>(*this); }
715
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast<Second const&>(*this); }
716
};
717
718
template<class First, class Second>
719
struct tight_pair<First, Second, tpc_same> : public First
720
{
721
Second m_second;
722
723
using first_type = First;
724
using second_type = Second;
725
726
tight_pair() : First() {}
727
tight_pair(First const& f, Second const& s) : First(f), m_second(s) {}
728
729
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
730
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
731
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
732
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
733
};
734
735
template<class First, class Second>
736
struct tight_pair<First, Second, tpc_first_empty> : public First
737
{
738
Second m_second;
739
740
using first_type = First;
741
using second_type = Second;
742
743
tight_pair() : First(), m_second() {}
744
tight_pair(First const& f, Second const& s) : First(f), m_second(s) {}
745
746
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return static_cast<First &>(*this); }
747
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return static_cast<First const&>(*this); }
748
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return m_second; }
749
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return m_second; }
750
};
751
752
template<class First, class Second>
753
struct tight_pair<First, Second, tpc_second_empty> : public Second
754
{
755
First m_first;
756
757
using first_type = First;
758
using second_type = Second;
759
760
tight_pair() : Second(), m_first() {}
761
tight_pair(First const& f, Second const& s) : Second(s), m_first(f) {}
762
763
C4_ALWAYS_INLINE C4_CONSTEXPR14 First & first () { return m_first; }
764
C4_ALWAYS_INLINE C4_CONSTEXPR14 First const& first () const { return m_first; }
765
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second & second() { return static_cast<Second &>(*this); }
766
C4_ALWAYS_INLINE C4_CONSTEXPR14 Second const& second() const { return static_cast<Second const&>(*this); }
767
};
768
769
} // namespace detail
770
771
template<class First, class Second>
772
using tight_pair = detail::tight_pair<First, Second, detail::tpc_which_case<First,Second>()>;
773
774
C4_SUPPRESS_WARNING_GCC_CLANG_POP
775
776
} // namespace c4
777
778
#endif /* _C4_MEMORY_UTIL_HPP_ */
779
780