HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
src
hikogui
macros.hpp
1
// Copyright Take Vos 2023.
2
// Distributed under the Boost Software License, Version 1.0.
3
// (See accompanying file LICENSE_1_0.txt or copy at https://www.boost.org/LICENSE_1_0.txt)
4
5
#pragma once
6
7
#include <version>
8
#include <exception>
9
10
#define HI_OS_WINDOWS 'W'
11
#define HI_OS_ANDROID 'A'
12
#define HI_OS_LINUX 'L'
13
#define HI_OS_MACOS 'M'
14
#define HI_OS_IOS 'I'
15
16
// W don't use HI_GENERIC for the operating system, because too many things
17
// like mmap-file-io, vulkan, window, main-loop depend on this.
18
#if defined(_WIN32)
19
#define HI_OPERATING_SYSTEM HI_OS_WINDOWS
20
#elif defined(__ANDROID__)
21
#define HI_OPERATING_SYSTEM HI_OS_ANDROID
22
#elif defined(__linux__)
23
#define HI_OPERATING_SYSTEM HI_OS_LINUX
24
#elif defined(__APPLE__) and defined(__MACH__)
25
#include <TargetConditionals.h>
26
#if TARGET_IPHONE_SIMULATOR or TARGET_OS_IPHONE or TARGET_OS_MACCATALYST
27
#define HI_OPERATING_SYSTEM HI_OS_IOS
28
#else
29
#define HI_OPERATING_SYSTEM HI_OS_MACOS
30
#endif
31
#else
32
#error "Unknown operating system"
33
#endif
34
35
#define HI_CC_MSVC 'm'
36
#define HI_CC_GCC 'g'
37
#define HI_CC_CLANG 'c'
38
#define HI_CC_OTHER '-'
39
40
#if defined(HI_GENERIC)
41
#define HI_COMPILER HI_CC_OTHER
42
#elif defined(__clang__)
43
#define HI_COMPILER HI_CC_CLANG
44
#elif defined(_MSC_BUILD)
45
#define HI_COMPILER HI_CC_MSVC
46
#elif defined(__GNUC__)
47
#define HI_COMPILER HI_CC_GCC
48
#else
49
#define HI_COMPILER HI_CC_OTHER
50
#endif
51
52
#define HI_STL_MS 'm'
53
#define HI_STL_GNU 'g'
54
#define HI_STL_LLVM 'l'
55
#define HI_STL_OTHER '-'
56
57
#if defined(HI_GENERIC)
58
#define HI_STD_LIBRARY HI_STL_OTHER
59
#elif defined(__GLIBCXX__)
60
#define HI_STD_LIBRARY HI_STL_GNU
61
#elif defined(_LIBCPP_VERSION)
62
#define HI_STD_LIBRARY HI_STL_LLVM
63
#elif defined(_CPPLIB_VER)
64
#define HI_STD_LIBRARY HI_STL_MS
65
#else
66
#define HI_STD_LIBRARY HI_STL_OTHER
67
#endif
68
69
#define HI_CPU_X86 'i'
70
#define HI_CPU_X86_64 'I'
71
#define HI_CPU_ARM 'a'
72
#define HI_CPU_ARM64 'A'
73
#define HI_CPU_OTHER '-'
74
75
#if defined(HI_GENERIC)
76
#define HI_PROCESSOR HI_CPU_OTHER
77
#elif defined(__amd64__) or defined(__amd64) or defined(__x86_64__) or defined(__x86_64) or defined(_M_AMD64) or defined(_M_X64)
78
#define HI_PROCESSOR HI_CPU_X86_64
79
#elif defined(__aarch64__) or defined(_M_ARM64)
80
#define HI_PROCESSOR HI_CPU_ARM64
81
#elif defined(__i386__) or defined(_M_IX86)
82
#define HI_PROCESSOR HI_CPU_X86
83
#elif defined(__arm__) or defined(__arm) or defined(_ARM) or defined(_M_ARM)
84
#define HI_PROCESSOR HI_CPU_ARM
85
#else
86
#define HI_PROCESSOR HI_CPU_OTHER
87
#endif
88
89
// All the HI_HAS_* macros tell us if the compiler will generate code with these instructions.
90
// Therefor we can use intrinsics for these instructions without checking the cpu-id.
91
// Which instrinsics are available is handled by a different macro.
92
93
#if HI_PROCESSOR == HI_CPU_X86_64
94
#define HI_HAS_X86_64 1
95
#define HI_HAS_X86 1
96
#elif HI_PROCESSOR == HI_CPU_X86
97
#define HI_HAS_X86 1
98
#endif
99
100
// Detect microarchitecture level.
101
#if defined(HI_HAS_X86)
102
#if HI_COMPILER == HI_CC_MSVC
103
// MSVC /arch:SSE (x86)
104
#if _M_IX86_FP >= 1 || defined(HI_HAS_X86_64)
105
#define HI_HAS_SSE 1
106
#define HI_HAS_MMX 1
107
108
#define HI_HAS_SCE 1
109
#define HI_HAS_OSFXSR 1
110
#define HI_HAS_FXSR 1
111
#define HI_HAS_FPU 1
112
#define HI_HAS_CX8 1
113
#define HI_HAS_CMOV 1
114
115
// MSVC /arch:SSE2 (x86)
116
#if _M_IX86_FP >= 2 || defined(HI_HAS_X86_64)
117
#define HI_HAS_SSE2 1
118
119
// MSVC /arch:AVX
120
#if defined(__AVX__)
121
// x86-64-v2
122
#define HI_HAS_SSSE3 1
123
#define HI_HAS_SSE4_1 1
124
#define HI_HAS_SSE4_2 1
125
#define HI_HAS_SSE3 1
126
#define HI_HAS_POPCNT 1
127
#define HI_HAS_LAHF 1
128
#define HI_HAS_CX16 1
129
130
#define HI_HAS_AVX 1
131
132
// MSVC /arch:AVX2
133
#if defined(__AVX2__)
134
// x86-64-v3
135
#define HI_HAS_AVX 1
136
#define HI_HAS_AVX2 1
137
#define HI_HAS_BMI1 1
138
#define HI_HAS_BMI2 1
139
#define HI_HAS_F16C 1
140
#define HI_HAS_FMA 1
141
#define HI_HAS_LZCNT 1
142
#define HI_HAS_MOVBE 1
143
#define HI_HAS_OSXSAVE 1
144
145
// MSVC /arch:AVX512
146
#if defined(__AVX512F__) && defined(__AVX512BW__) && defined(__AVX512CD__) && defined(__AVX512DQ__) && defined(__AVX512VL__)
147
// x86-64-v4
148
#define HI_HAS_AVX512F 1
149
#define HI_HAS_AVX512BW 1
150
#define HI_HAS_AVX512CD 1
151
#define HI_HAS_AVX512DQ 1
152
#define HI_HAS_AVX512VL 1
153
154
#endif
// defined(__AVX512__)
155
#endif
// defined(__AVX2__)
156
#endif
// defined(__AVX__)
157
#endif
// _M_IX86_FP >= 2
158
#endif
// _M_IX86_FP >= 1
159
160
#elif HI_COMPILER == HI_CC_CLANG || HI_COMPILER == HI_CC_GCC
161
#if defined(__MMX__)
162
#define HI_HAS_MMX 1
163
#endif
164
#if defined(__SSE__)
165
#define HI_HAS_SSE 1
166
#endif
167
#if defined(__SSE2__)
168
#define HI_HAS_SSE2 1
169
#endif
170
#if defined(__SSE3__)
171
#define HI_HAS_SSE3 1
172
#endif
173
#if defined(__SSSE3__)
174
#define HI_HAS_SSSE3 1
175
#endif
176
#if defined(__SSE4_1__)
177
#define HI_HAS_SSE4_1 1
178
#endif
179
#if defined(__SSE4_2__)
180
#define HI_HAS_SSE4_2 1
181
#endif
182
#if defined(__POPCNT__)
183
#define HI_HAS_POPCNT 1
184
#endif
185
#if defined(__LAHF_SAHF__)
186
#define HI_HAS_LAHF 1
187
#endif
188
#if defined(__GCC_HAVE_SYNC_COMPARE_AND_SWAP_16)
189
#define HI_HAS_CX16 1
190
#endif
191
#if defined(__AVX__)
192
#define HI_HAS_AVX 1
193
#endif
194
#if defined(__AVX2__)
195
#define HI_HAS_AVX2 1
196
#endif
197
#if defined(__BMI__)
198
#define HI_HAS_BMI1 1
199
#endif
200
#if defined(__BMI2__)
201
#define HI_HAS_BMI2 1
202
#endif
203
#if defined(__F16C__)
204
#define HI_HAS_F16C 1
205
#endif
206
#if defined(__FMA__)
207
#define HI_HAS_FMA 1
208
#endif
209
#if defined(__LZCNT__)
210
#define HI_HAS_LZCNT 1
211
#endif
212
#if defined(__MOVBE__)
213
#define HI_HAS_MOVBE 1
214
#endif
215
#if defined(__XSAVE__)
216
#define HI_HAS_XSAVE 1
217
#endif
218
#if defined(__AVX512BW__)
219
#define HI_HAS_AVX512BW 1
220
#endif
221
#if defined(__AVX512CD__)
222
#define HI_HAS_AVX512CD 1
223
#endif
224
#if defined(__AVX512DQ__)
225
#define HI_HAS_AVX512DQ 1
226
#endif
227
#if defined(__AVX512F__)
228
#define HI_HAS_AVX512F 1
229
#endif
230
#if defined(__AVX512VL__)
231
#define HI_HAS_AVX512VL 1
232
#endif
233
#if defined(__SHA__)
234
#define HI_HAS_SHA 1
235
#endif
236
#if defined(__AES__)
237
#define HI_HAS_AES 1
238
#endif
239
#if defined(__PCLMUL__)
240
#define HI_HAS_PCLMUL 1
241
#endif
242
#if defined(__RDRND__)
243
#define HI_HAS_RDRND 1
244
#endif
245
#if defined(__RDSEED__)
246
#define HI_HAS_RDSEED 1
247
#endif
248
249
#else
// HI_COMPILER == HI_CC_CLANG || HI_COMPILER == HI_CC_GCC
250
#error "Unknown compiler for x86"
251
#endif
252
253
#endif
// defined(HI_HAS_X86)
254
255
// clang-format off
256
#if defined(HI_HAS_SSE2) && defined(HI_HAS_SSE) && defined(HI_HAS_SCE) && \
257
defined(HI_HAS_OSFXSR) && defined(HI_HAS_MMX) && defined(HI_HAS_FXSR) && \
258
defined(HI_HAS_FPU) && defined(HI_HAS_CX8) && defined(HI_HAS_CMOV)
259
#define HI_HAS_X86_64_V1 1
260
#endif
261
262
#if defined(HI_HAS_X86_64_V1) && defined(HI_HAS_SSSE3) && defined(HI_HAS_SSE4_1) && \
263
defined(HI_HAS_SSE4_2) && defined(HI_HAS_SSE3) && defined(HI_HAS_POPCNT) && \
264
defined(HI_HAS_LAHF) && defined(HI_HAS_CX16)
265
#define HI_HAS_X86_64_V2 1
266
#endif
267
268
#if defined(HI_HAS_X86_64_V2) && defined(HI_HAS_AVX) && defined(HI_HAS_AVX2) && \
269
defined(HI_HAS_BMI1) && defined(HI_HAS_BMI2) && defined(HI_HAS_F16C) && \
270
defined(HI_HAS_FMA) && defined(HI_HAS_LZCNT) && defined(HI_HAS_MOVBE) && \
271
defined(HI_HAS_OSXSAVE)
272
#define HI_HAS_X86_64_V3 1
273
#endif
274
275
#if defined(HI_HAS_X86_64_V3) && defined(HI_HAS_AVX512F) && defined(HI_HAS_AVX512BW) && \
276
defined(HI_HAS_AVX512CD) && defined(HI_HAS_AVX512DQ) && defined(HI_HAS_AVX512VL)
277
#define HI_HAS_X86_64_V4 1
278
#endif
279
// clang-format on
280
281
inline
void
weak_terminate() noexcept
282
{
283
std::terminate
();
284
}
285
295
#if HI_COMPILER == HI_CC_CLANG
296
#define hi_assert_break() __builtin_trap()
297
#elif HI_COMPILER == HI_CC_MSVC
298
#define hi_assert_break() __int2c()
299
#elif HI_COMPILER == HI_CC_GCC
300
#define hi_assert_break() __builtin_trap()
301
#else
302
#define hi_assert_break() weak_terminate()
303
#endif
304
314
#if HI_COMPILER == HI_CC_CLANG
315
#define hi_debug_break() __builtin_debugtrap()
316
#elif HI_COMPILER == HI_CC_MSVC
317
#define hi_debug_break() __debugbreak()
318
#elif HI_COMPILER == HI_CC_GCC
319
#define hi_debug_break() __builtin_trap()
320
#else
321
#define hi_debug_break() weak_terminate()
322
#endif
323
335
#if HI_COMPILER == HI_CC_CLANG
336
#define hi_target(...) [[gnu::target(__VA_ARGS__)]]
337
#elif HI_COMPILER == HI_CC_MSVC
338
#define hi_target(...)
339
#elif HI_COMPILER == HI_CC_GCC
340
#define hi_target(...) [[gnu::target(__VA_ARGS__)]]
341
#else
342
#define hi_target(...)
343
#endif
344
349
#if HI_COMPILER == HI_CC_CLANG
350
#define hi_assume(...) __builtin_assume(not not(__VA_ARGS__))
351
#elif HI_COMPILER == HI_CC_MSVC
352
#define hi_assume(...) __assume(not not(__VA_ARGS__))
353
#elif HI_COMPILER == HI_CC_GCC
354
#define hi_assume(...) \
355
do { \
356
if (not(__VA_ARGS__)) { \
357
std::unreachable(); \
358
} \
359
} while (false)
360
#else
361
#define hi_assume(...) static_assert(std::convertible_to<decltype(not not(__VA_ARGS__)), bool>)
362
#endif
363
376
#if defined(NDEBUG)
377
#if HI_COMPILER == HI_CC_CLANG
378
#define hi_force_inline __attribute__((always_inline))
379
#elif HI_COMPILER == HI_CC_MSVC
380
#define hi_force_inline __forceinline
381
#elif HI_COMPILER == HI_CC_GCC
382
#define hi_force_inline __attribute__((always_inline))
383
#else
384
#define hi_force_inline
385
#endif
386
#else
387
#define hi_force_inline
388
#endif
389
392
#if HI_COMPILER == HI_CC_CLANG
393
#define hi_no_inline __attribute__((noinline))
394
#elif HI_COMPILER == HI_CC_MSVC
395
#define hi_no_inline __declspec(noinline)
396
#elif HI_COMPILER == HI_CC_GCC
397
#define hi_no_inline __attribute__((noinline))
398
#else
399
#define hi_no_inline
400
#endif
401
404
#if HI_COMPILER == HI_CC_CLANG
405
#define hi_restrict __restrict__
406
#elif HI_COMPILER == HI_CC_MSVC
407
#define hi_restrict __restrict
408
#elif HI_COMPILER == HI_CC_GCC
409
#define hi_restrict __restrict__
410
#else
411
#define hi_restrict
412
#endif
413
416
#if HI_COMPILER == HI_CC_CLANG
417
#define hi_no_sanitize_address
418
#elif HI_COMPILER == HI_CC_MSVC
419
#define hi_no_sanitize_address __declspec(no_sanitize_address)
420
#elif HI_COMPILER == HI_CC_GCC
421
#define hi_no_sanitize_address
422
#else
423
#define hi_no_sanitize_address
424
#endif
425
426
// Even when HI_GENERIC is set, we want the warning for the specific compilers
427
// to be properly suppressed.
428
#if defined(__clang__)
429
#define hi_warning_push() _Pragma("warning(push)")
430
#define hi_warning_pop() _Pragma("warning(push)")
431
#define hi_warning_ignore_msvc(...)
432
#define hi_warning_ignore_clang(...) _Pragma(hi_stringify(clang diagnostic ignored __VA_ARGS__))
433
#define hi_warning_ignore_gcc(...)
434
#elif defined(_MSC_BUILD)
435
#define hi_warning_push() _Pragma("warning( push )")
436
#define hi_warning_pop() _Pragma("warning( pop )")
437
#define hi_msvc_pragma(...) _Pragma(__VA_ARGS__)
438
#define hi_warning_ignore_msvc(...) _Pragma(hi_stringify(warning(disable : __VA_ARGS__)))
439
#define hi_warning_ignore_clang(...)
440
#define hi_warning_ignore_gcc(...)
441
#elif defined(__GNUC__)
442
#define hi_warning_push() _Pragma("warning(push)")
443
#define hi_warning_pop() _Pragma("warning(pop)")
444
#define hi_warning_ignore_msvc(...)
445
#define hi_warning_ignore_clang(...)
446
#define hi_warning_ignore_gcc(...) _Pragma(hi_stringify(clang diagnostic ignored __VA_ARGS__))
447
#else
448
#define hi_warning_push()
449
#define hi_warning_pop()
450
#define hi_warning_ignore_msvc(...)
451
#define hi_warning_ignore_clang(...)
452
#define hi_warning_ignore_gcc(...)
453
#endif
454
455
458
#ifndef hi_export_module
459
#define hi_export_module(x)
460
#endif
461
464
#ifndef hi_export
465
#define hi_export
466
#endif
467
470
#ifndef hi_inline
471
#define hi_inline inline
472
#endif
473
480
#define hi_return_if_valid(expression) \
481
do { \
482
if constexpr (requires { expression; }) { \
483
return expression; \
484
} \
485
} while (false)
486
487
// One clang-format off is not enough to stop clang-format to format.
488
// clang-format off
489
#define hi_num_va_args_impl( \
490
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
491
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
492
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
493
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
494
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
495
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
496
_61,_62,_63,N,...) N
497
#define hi_num_va_args_(...) hi_num_va_args_impl(__VA_ARGS__)
498
// clang-format on
499
505
// clang-format off
506
#define hi_num_va_args(...) hi_num_va_args_(__VA_ARGS__ __VA_OPT__(,) \
507
63,62,61,60, \
508
59,58,57,56,55,54,53,52,51,50, \
509
49,48,47,46,45,44,43,42,41,40, \
510
39,38,37,36,35,34,33,32,31,30, \
511
29,28,27,26,25,24,23,22,21,20, \
512
19,18,17,16,15,14,13,12,11,10, \
513
9,8,7,6,5,4,3,2,1,0)
514
// clang-format on
515
516
#define hi_parans ()
517
518
#define hi_expand1(...) __VA_ARGS__
519
#define hi_expand2(...) hi_expand1(hi_expand1(hi_expand1(hi_expand1(__VA_ARGS__))))
520
#define hi_expand3(...) hi_expand2(hi_expand2(hi_expand2(hi_expand2(__VA_ARGS__))))
521
#define hi_expand4(...) hi_expand3(hi_expand3(hi_expand3(hi_expand3(__VA_ARGS__))))
522
527
#define hi_expand(...) hi_expand4(hi_expand4(hi_expand4(hi_expand4(__VA_ARGS__))))
528
529
#define hi_for_each_again() hi_for_each_helper
530
#define hi_for_each_helper(macro, first_arg, ...) macro(first_arg) __VA_OPT__(hi_for_each_again hi_parans(macro, __VA_ARGS__))
531
537
#define hi_for_each(macro, ...) __VA_OPT__(hi_expand(hi_for_each_helper(macro, __VA_ARGS__)))
538
539
#define hi_stringify_(x) #x
540
#define hi_stringify(x) hi_stringify_(x)
541
542
#define hi_cat_(a, b) a##b
543
#define hi_cat(a, b) hi_cat_(a, b)
544
545
#define hi_return_on_self_assignment(other) \
546
if (&(other) == this) [[unlikely]] \
547
return *this;
548
558
#define hi_get_overloaded_macro2(_1, _2, name, ...) name
559
560
#define ssizeof(x) (static_cast<ssize_t>(sizeof(x)))
561
576
#define hi_assert_abort(...) \
577
do { \
578
::hi::set_debug_message(__FILE__ ":" hi_stringify(__LINE__) ":" __VA_ARGS__); \
579
hi_assert_break(); \
580
} while (false)
581
592
#define hi_check(expression, message, ...) \
593
do { \
594
if (not(expression)) { \
595
if constexpr (__VA_OPT__(not ) false) { \
596
throw parse_error(std::format(message __VA_OPT__(, ) __VA_ARGS__)); \
597
} else { \
598
throw parse_error(message); \
599
} \
600
} \
601
} while (false)
602
614
#define hi_check_bounds(x, ...) \
615
do { \
616
if (not ::hi::bound_check(x, __VA_ARGS__)) { \
617
throw parse_error("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
618
} \
619
} while (false)
620
633
#define hi_check_subspan(span, offset, ...) \
634
[&](auto _hi_check_subspan_span, size_t _hi_check_subspan_offset, auto... _hi_check_subspan_count) { \
635
if constexpr (sizeof...(_hi_check_subspan_count) == 0) { \
636
if (_hi_check_subspan_offset < _hi_check_subspan_span.size()) { \
637
return _hi_check_subspan_span.subspan(_hi_check_subspan_offset); \
638
} \
639
} else if constexpr (sizeof...(_hi_check_subspan_count) == 1) { \
640
if (_hi_check_subspan_offset + wide_cast<size_t>(_hi_check_subspan_count...) <= _hi_check_subspan_span.size()) { \
641
return _hi_check_subspan_span.subspan(_hi_check_subspan_offset, _hi_check_subspan_count...); \
642
} \
643
} \
644
throw parse_error( \
645
"assert bounds on: " hi_stringify(span) ".subspan(" hi_stringify(offset __VA_OPT__(", ") __VA_ARGS__) ")"); \
646
}(span, offset __VA_OPT__(, ) __VA_ARGS__)
647
658
#define hi_check_at(span, index) \
659
[&](auto _hi_check_subspan_span, size_t _hi_check_subspan_index) { \
660
if (_hi_check_subspan_index < _hi_check_subspan_span.size()) { \
661
return _hi_check_subspan_span[_hi_check_subspan_index]; \
662
} else { \
663
throw parse_error("assert bounds on: " hi_stringify(span) "[" hi_stringify(index) "]"); \
664
} \
665
}(span, index)
666
667
#define hi_hresult_check(expression) \
668
([](HRESULT result) { \
669
if (FAILED(result)) { \
670
throw ::hi::io_error(std::format("Call to '{}' failed with {:08x}", #expression, result)); \
671
} \
672
return result; \
673
}(expression))
674
681
#define hi_assert(expression, ...) \
682
do { \
683
if (not(expression)) { \
684
hi_assert_abort("assert: " __VA_ARGS__ " not (" hi_stringify(expression) ")"); \
685
} \
686
} while (false)
687
694
#define hi_assert_or_return(x, y) \
695
if (!(x)) { \
696
[[unlikely]] return y; \
697
}
698
707
#define hi_assert_bounds(x, ...) \
708
do { \
709
if (not ::hi::bound_check(x, __VA_ARGS__)) { \
710
hi_assert_abort("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
711
} \
712
} while (false)
713
720
#define hi_assert_not_null(x, ...) \
721
do { \
722
if (x == nullptr) { \
723
hi_assert_abort("assert not-null: " __VA_ARGS__ " (" hi_stringify(x) ")"); \
724
} \
725
} while (false)
726
734
#ifndef NDEBUG
735
#define hi_axiom(expression, ...) hi_assert(expression __VA_OPT__(, ) __VA_ARGS__)
736
#else
737
#define hi_axiom(expression, ...) hi_assume(expression)
738
#endif
739
749
#ifndef NDEBUG
750
#define hi_axiom_bounds(x, ...) hi_assert_bounds(x, __VA_ARGS__)
751
#else
752
#define hi_axiom_bounds(x, ...) hi_assume(not ::hi::bound_check(x, __VA_ARGS__))
753
#endif
754
761
#ifndef NDEBUG
762
#define hi_axiom_not_null(expression, ...) hi_assert_not_null(expression __VA_OPT__(, ) __VA_ARGS__)
763
#else
764
#define hi_axiom_not_null(expression, ...) hi_assume(expression != nullptr)
765
#endif
766
772
#ifndef NDEBUG
773
#define hi_no_default(...) \
774
[[unlikely]] hi_assert_abort("Reached no-default:" __VA_ARGS__); \
775
std::terminate()
776
#else
777
#define hi_no_default(...) std::unreachable()
778
#endif
779
785
#define hi_static_no_default(...) \
786
[]<bool Flag = false>() \
787
{ \
788
static_assert(Flag, "No default: " __VA_ARGS__); \
789
} \
790
()
791
797
#define hi_not_implemented(...) \
798
[[unlikely]] hi_assert_abort("Not implemented: " __VA_ARGS__); \
799
std::terminate()
800
806
#define hi_static_not_implemented(...) hi_static_no_default("Not implemented: " __VA_ARGS__)
807
814
#define hi_print(fmt, ...) console_output(std::format(fmt __VA_OPT__(, ) __VA_ARGS__))
815
816
#define hi_format_argument_check(arg) \
817
static_assert( \
818
::std::is_default_constructible_v<std::formatter<std::decay_t<decltype(arg)>>>, \
819
"std::format, argument '" #arg "' does not have a specialized std::formatter<>.");
820
833
#define hi_format_check(fmt, ...) \
834
static_assert(::hi::format_count(fmt) != -1, "std::format, Unexpected '{' inside argument-format."); \
835
static_assert(::hi::format_count(fmt) != -2, "std::format, Unexpected '}' without corresponding '{'."); \
836
static_assert(::hi::format_count(fmt) != -3, "std::format, Missing '}' at end of format string."); \
837
static_assert( \
838
::hi::format_count(fmt) == hi_num_va_args(__VA_ARGS__), "std::format, invalid number of arguments for format string."); \
839
hi_for_each(hi_format_argument_check, __VA_ARGS__)
840
841
#define hi_log(level, fmt, ...) \
842
hi_format_check(fmt __VA_OPT__(, ) __VA_ARGS__); \
843
::hi::log_global.add<level, __FILE__, __LINE__, fmt>(__VA_ARGS__)
844
845
#define hi_log_debug(fmt, ...) hi_log(::hi::global_state_type::log_debug, fmt __VA_OPT__(, ) __VA_ARGS__)
846
#define hi_log_info(fmt, ...) hi_log(::hi::global_state_type::log_info, fmt __VA_OPT__(, ) __VA_ARGS__)
847
#define hi_log_statistics(fmt, ...) hi_log(::hi::global_state_type::log_statistics, fmt __VA_OPT__(, ) __VA_ARGS__)
848
#define hi_log_trace(fmt, ...) hi_log(::hi::global_state_type::log_trace, fmt __VA_OPT__(, ) __VA_ARGS__)
849
#define hi_log_audit(fmt, ...) hi_log(::hi::global_state_type::log_audit, fmt __VA_OPT__(, ) __VA_ARGS__)
850
#define hi_log_warning(fmt, ...) hi_log(::hi::global_state_type::log_warning, fmt __VA_OPT__(, ) __VA_ARGS__)
851
#define hi_log_error(fmt, ...) hi_log(::hi::global_state_type::log_error, fmt __VA_OPT__(, ) __VA_ARGS__)
852
#define hi_log_fatal(fmt, ...) \
853
hi_log(::hi::global_state_type::log_fatal, fmt __VA_OPT__(, ) __VA_ARGS__); \
854
hi_assert_abort(); \
855
std::terminate()
856
857
#define hi_log_info_once(name, fmt, ...) \
858
do { \
859
if (++::hi::global_counter<name> == 1) { \
860
hi_log(::hi::global_state_type::log_info, fmt __VA_OPT__(, ) __VA_ARGS__); \
861
} \
862
} while (false)
863
864
#define hi_log_error_once(name, fmt, ...) \
865
do { \
866
if (++::hi::global_counter<name> == 1) { \
867
hi_log(::hi::global_state_type::log_error, fmt __VA_OPT__(, ) __VA_ARGS__); \
868
} \
869
} while (false)
870
881
#define hi_num_valid_arguments(ATTRIBUTES, NAME, CHECK_CALLABLE) \
882
template<size_t I, typename First, typename... Rest> \
883
ATTRIBUTES size_t _ ## NAME() \
884
{ \
885
if constexpr (I > 1) { \
886
return _ ## NAME<I - 1, Rest..., First>(); \
887
} else if constexpr (I == 1) { \
888
return _ ## NAME<0, Rest...>(); \
889
} else if constexpr (requires (First &&f, Rest &&...r) { CHECK_CALLABLE(std::forward<First>(f), std::forward<Rest>(r)...); }) { \
890
return sizeof...(Rest) + 1; \
891
} else if constexpr (sizeof...(Rest)) { \
892
return _ ## NAME<sizeof...(Rest) + 1, First, Rest...>(); \
893
} else { \
894
return 0; \
895
} \
896
} \
897
template<typename... Args> \
898
ATTRIBUTES size_t NAME() \
899
{ \
900
if constexpr (sizeof...(Args) != 0) { \
901
return _ ## NAME<0, Args...>(); \
902
} else { \
903
return 0; \
904
} \
905
}
906
917
// To use the right arguments, we first need to rotate them before we can
918
// remove the ones we don't need. Since we can only remove arguments on the left
919
// side.
920
#define hi_call_left_arguments(ATTRIBUTES, NAME, CALLABLE) \
921
template<size_t N, size_t R, typename First, typename... Rest>\
922
ATTRIBUTES auto _ ## NAME(First &&first, Rest &&...rest)\
923
{\
924
if constexpr (R != 0) { \
925
return _ ## NAME<N, R - 1, Rest..., First>(std::forward<Rest>(rest)..., std::forward<First>(first)); \
926
} else if constexpr (N != sizeof...(Rest) + 1) {\
927
return _ ## NAME<N, 0, Rest...>(std::forward<Rest>(rest)...);\
928
} else { \
929
return CALLABLE(std::forward<First>(first), std::forward<Rest>(rest)...);\
930
}\
931
}\
932
template<size_t N, typename... Args>\
933
ATTRIBUTES auto NAME(Args &&...args)\
934
{\
935
static_assert(N <= sizeof...(Args)); \
936
if constexpr (N == sizeof...(Args)) { \
937
return CALLABLE(std::forward<Args>(args)...); \
938
} else {\
939
return _ ## NAME<N, N, Args...>(std::forward<Args>(args)...); \
940
}\
941
}
942
953
#define hi_call_right_arguments(ATTRIBUTES, NAME, CALLABLE) \
954
template<size_t Skip>\
955
ATTRIBUTES auto NAME()\
956
{\
957
static_assert(Skip == 0); \
958
return CALLABLE();\
959
}\
960
template<size_t Skip, typename First, typename... Rest>\
961
ATTRIBUTES auto NAME(First &&first, Rest &&...rest)\
962
{\
963
static_assert(Skip <= (sizeof...(Rest) + 1)); \
964
if constexpr (Skip != 0) {\
965
return NAME<Skip - 1, Rest...>(std::forward<Rest>(rest)...);\
966
} else {\
967
return CALLABLE(std::forward<First>(first), std::forward<Rest>(rest)...);\
968
}\
969
}
970
std::terminate
T terminate(T... args)
Generated on Mon Apr 22 2024 12:51:58 for HikoGUI by
1.10.0