HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
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
281inline void weak_terminate() noexcept
282{
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
T terminate(T... args)