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#ifndef HI_ASSERT_HPP
6#define HI_ASSERT_HPP
7
8#define HI_OS_WINDOWS 'W'
9#define HI_OS_MACOS 'A'
10#define HI_OS_MOBILE 'M'
11#define HI_OS_OTHER 'O'
12
13#if defined(_WIN32)
14#define HI_OPERATING_SYSTEM HI_OS_WINDOWS
15#elif defined(TARGET_OS_MAC) and not defined(TARGET_OS_IPHONE)
16#define HI_OPERATING_SYSTEM HI_OS_MACOS
17#elif defined(TARGET_OS_IPHONE) or defined(__ANDROID__)
18#define HI_OPERATING_SYSTEM HI_OS_MOBILE
19#else
20#define HI_OPERATING_SYSTEM HI_OS_OTHER
21#endif
22
23#define HI_CC_MSVC 'm'
24#define HI_CC_GCC 'g'
25#define HI_CC_CLANG 'c'
26
27#if defined(__clang__)
28#define HI_COMPILER HI_CC_CLANG
29#elif defined(_MSC_BUILD)
30#define HI_COMPILER HI_CC_MSVC
31#elif defined(__GNUC__)
32#define HI_COMPILER HI_CC_GCC
33#else
34#error "Could not detect the compiler."
35#endif
36
37#define HI_CPU_X86 'i'
38#define HI_CPU_X64 'I'
39#define HI_CPU_ARM 'a'
40#define HI_CPU_ARM64 'A'
41#define HI_CPU_UNKNOWN '-'
42
43#if defined(__amd64__) or defined(__amd64) or defined(__x86_64__) or defined(__x86_64) or defined(_M_AMD64) or defined(_M_X64)
44#define HI_PROCESSOR HI_CPU_X64
45#elif defined(__aarch64__) or defined(_M_ARM64)
46#define HI_PROCESSOR HI_CPU_ARM64
47#elif defined(__i386__) or defined(_M_IX86)
48#define HI_PROCESSOR HI_CPU_X86
49#elif defined(__arm__) or defined(__arm) or defeind(_ARM) or defined(_M_ARM)
50#define HI_PROCESSOR HI_CPU_ARM
51#else
52#define HI_PROCESSOR HI_CPU_UNKNOWN
53#endif
54
55#if defined(__AVX512BW__) and defined(__AVX512CD__) and defined(__AVX512DQ__) and defined(__AVX512F__) and defined(__AVX512VL__)
56#define HI_X86_64_LEVEL 4
57#elif defined(__AVX2__)
58#define HI_X86_64_LEVEL 3
59#elif defined(__SSE4_2__) and defined(__SSSE3__)
60#define HI_X86_64_LEVEL 2
61#elif HI_PROCESSOR == HI_CPU_X64
62#define HI_X86_64_LEVEL 1
63#endif
64
65#if defined(HI_X86_64_MAX_LEVEL) and defined(HI_X86_64_LEVEL) and HI_X86_64_MAX_LEVEL < HI_X86_64_LEVEL
66#undef HI_X86_64_LEVEL
67#define HI_X86_64_LEVEL HI_X86_64_MAX_LEVEL
68#endif
69
70#if defined(HI_X86_64_LEVEL) and HI_X86_64_LEVEL >= 4
71#define HI_HAS_AVX512F 1
72#define HI_HAS_AVX512BW 1
73#define HI_HAS_AVX512CD 1
74#define HI_HAS_AVX512DQ 1
75#define HI_HAS_AVX512VL 1
76#endif
77
78#if defined(HI_X86_64_LEVEL) and HI_X86_64_LEVEL >= 3
79#define HI_HAS_AVX 1
80#define HI_HAS_AVX2 1
81#define HI_HAS_BMI1 1
82#define HI_HAS_BMI2 1
83#define HI_HAS_F16C 1
84#define HI_HAS_FMA 1
85#define HI_HAS_LZCNT 1
86#define HI_HAS_MOVBE 1
87#define HI_HAS_OSXSAVE 1
88#endif
89
90#if defined(HI_X86_64_LEVEL) and HI_X86_64_LEVEL >= 2
91#define HI_HAS_CMPXCHG16B 1
92#define HI_HAS_LAHF_SAHF 1
93#define HI_HAS_POPCNT 1
94#define HI_HAS_SSE3 1
95#define HI_HAS_SSE4_1 1
96#define HI_HAS_SSE4_2 1
97#define HI_HAS_SSSE3 1
98#endif
99
100#if defined(HI_X86_64_LEVEL) and HI_X86_64_LEVEL >= 1
101#define HI_HAS_CMOV 1
102#define HI_HAS_CX8 1
103#define HI_HAS_FPU 1
104#define HI_HAS_FXSR 1
105#define HI_HAS_MMX 1
106#define HI_HAS_OSFXSR 1
107#define HI_HAS_SCE 1
108#define HI_HAS_SSE 1
109#define HI_HAS_SSE2 1
110#endif
111
112#if HI_COMPILER == HI_CC_CLANG
113#define hi_assume(condition) __builtin_assume(to_bool(condition))
114#define hi_force_inline inline __attribute__((always_inline))
115#define hi_no_inline __attribute__((noinline))
116#define hi_restrict __restrict__
117#define hi_warning_push() _Pragma("warning(push)")
118#define hi_warning_pop() _Pragma("warning(push)")
119#define hi_warning_ignore_msvc(code)
120#define hi_warning_ignore_clang(a) _Pragma(hi_stringify(clang diagnostic ignored a))
121
122#elif HI_COMPILER == HI_CC_MSVC
123#define hi_assume(condition) __assume(condition)
124#define hi_force_inline __forceinline
125#define hi_no_inline __declspec(noinline)
126#define hi_restrict __restrict
127#define hi_warning_push() _Pragma("warning( push )")
128#define hi_warning_pop() _Pragma("warning( pop )")
129#define hi_msvc_pragma(a) _Pragma(a)
130#define hi_warning_ignore_msvc(code) _Pragma(hi_stringify(warning(disable : code)))
131#define hi_warning_ignore_clang(a)
132
133#elif HI_COMPILER == HI_CC_GCC
134#define hi_assume(condition) \
135 do { \
136 if (!(condition)) \
137 std::unreachable(); \
138 } while (false)
139#define hi_force_inline inline __attribute__((always_inline))
140#define hi_no_inline __attribute__((noinline))
141#define hi_restrict __restrict__
142#define hi_warning_push() _Pragma("warning(push)")
143#define hi_warning_pop() _Pragma("warning(pop)")
144#define hi_msvc_pragma(a)
145#define hi_warning_ignore_clang(a)
146#define msvc_pragma(a)
147
148#else
149#define hi_assume(condition) static_assert(sizeof(condition) == 1)
150#define hi_force_inline inline
151#define hi_no_inline
152#define hi_restrict
153#define hi_warning_push()
154#define hi_warning_pop()
155#define hi_msvc_pragma(a)
156#define hi_warning_ignore_clang(a)
157#define msvc_pragma(a)
158#endif
159
162#ifndef hi_export_module
163#define hi_export_module(x)
164#endif
165
168#ifndef hi_export
169#define hi_export
170#endif
171
178#ifndef hilet
179#define hilet auto const
180#endif
181
184#ifndef hi_forward
185#define hi_forward(x) std::forward<decltype(x)>(x)
186#endif
187
194#define hi_return_if_valid(expression) \
195 do { \
196 if constexpr (requires { expression; }) { \
197 return expression; \
198 } \
199 } while (false)
200
201// One clang-format off is not enough to stop clang-format to format.
202// clang-format off
203#define hi_num_va_args_impl( \
204 _1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
205 _11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
206 _21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
207 _31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
208 _41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
209 _51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
210 _61,_62,_63,N,...) N
211#define hi_num_va_args_(...) hi_num_va_args_impl(__VA_ARGS__)
212// clang-format on
213
219// clang-format off
220#define hi_num_va_args(...) hi_num_va_args_(__VA_ARGS__ __VA_OPT__(,) \
221 63,62,61,60, \
222 59,58,57,56,55,54,53,52,51,50, \
223 49,48,47,46,45,44,43,42,41,40, \
224 39,38,37,36,35,34,33,32,31,30, \
225 29,28,27,26,25,24,23,22,21,20, \
226 19,18,17,16,15,14,13,12,11,10, \
227 9,8,7,6,5,4,3,2,1,0)
228// clang-format on
229
230#define hi_parans ()
231
232#define hi_expand1(...) __VA_ARGS__
233#define hi_expand2(...) hi_expand1(hi_expand1(hi_expand1(hi_expand1(__VA_ARGS__))))
234#define hi_expand3(...) hi_expand2(hi_expand2(hi_expand2(hi_expand2(__VA_ARGS__))))
235#define hi_expand4(...) hi_expand3(hi_expand3(hi_expand3(hi_expand3(__VA_ARGS__))))
236
241#define hi_expand(...) hi_expand4(hi_expand4(hi_expand4(hi_expand4(__VA_ARGS__))))
242
243#define hi_for_each_again() hi_for_each_helper
244#define hi_for_each_helper(macro, first_arg, ...) macro(first_arg) __VA_OPT__(hi_for_each_again hi_parans(macro, __VA_ARGS__))
245
251#define hi_for_each(macro, ...) __VA_OPT__(hi_expand(hi_for_each_helper(macro, __VA_ARGS__)))
252
253#define hi_stringify_(x) #x
254#define hi_stringify(x) hi_stringify_(x)
255
256#define hi_cat_(a, b) a##b
257#define hi_cat(a, b) hi_cat_(a, b)
258
259#define hi_return_on_self_assignment(other) \
260 if (&(other) == this) [[unlikely]] \
261 return *this;
262
272#define hi_get_overloaded_macro2(_1, _2, name, ...) name
273
280#if defined(_WIN32)
281#define hi_debug_break() \
282 do { \
283 if (::hi::prepare_debug_break()) { \
284 __debugbreak(); \
285 } \
286 } while (false)
287#else
288#error Missing implementation of hi_debug_break().
289#endif
290
301#if defined(_WIN32)
302#define hi_debug_abort(...) \
303 do { \
304 ::hi::prepare_debug_break(__FILE__ ":" hi_stringify(__LINE__) ":" __VA_ARGS__); \
305 __debugbreak(); \
306 } while (false)
307#else
308#error Missing implementation of hi_debug_abort().
309#endif
310
321#define hi_check(expression, message, ...) \
322 do { \
323 if (not(expression)) { \
324 if constexpr (__VA_OPT__(not ) false) { \
325 throw parse_error(std::format(message __VA_OPT__(, ) __VA_ARGS__)); \
326 } else { \
327 throw parse_error(message); \
328 } \
329 } \
330 } while (false)
331
343#define hi_check_bounds(x, ...) \
344 do { \
345 if (not ::hi::bound_check(x, __VA_ARGS__)) { \
346 throw parse_error("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
347 } \
348 } while (false)
349
362#define hi_check_subspan(span, offset, ...) \
363 [&](auto _hi_check_subspan_span, size_t _hi_check_subspan_offset, auto... _hi_check_subspan_count) { \
364 if constexpr (sizeof...(_hi_check_subspan_count) == 0) { \
365 if (_hi_check_subspan_offset < _hi_check_subspan_span.size()) { \
366 return _hi_check_subspan_span.subspan(_hi_check_subspan_offset); \
367 } \
368 } else if constexpr (sizeof...(_hi_check_subspan_count) == 1) { \
369 if (_hi_check_subspan_offset + wide_cast<size_t>(_hi_check_subspan_count...) <= _hi_check_subspan_span.size()) { \
370 return _hi_check_subspan_span.subspan(_hi_check_subspan_offset, _hi_check_subspan_count...); \
371 } \
372 } \
373 throw parse_error( \
374 "assert bounds on: " hi_stringify(span) ".subspan(" hi_stringify(offset __VA_OPT__(", ") __VA_ARGS__) ")"); \
375 }(span, offset __VA_OPT__(, ) __VA_ARGS__)
376
387#define hi_check_at(span, index) \
388 [&](auto _hi_check_subspan_span, size_t _hi_check_subspan_index) { \
389 if (_hi_check_subspan_index < _hi_check_subspan_span.size()) { \
390 return _hi_check_subspan_span[_hi_check_subspan_index]; \
391 } else { \
392 throw parse_error("assert bounds on: " hi_stringify(span) "[" hi_stringify(index) "]"); \
393 } \
394 }(span, index)
395
396#define hi_hresult_check(expression) \
397 ([](HRESULT result) { \
398 if (FAILED(result)) { \
399 throw ::hi::io_error(std::format("Call to '{}' failed with {:08x}", #expression, result)); \
400 } \
401 return result; \
402 }(expression))
403
410#define hi_assert(expression, ...) \
411 do { \
412 if (not(expression)) { \
413 hi_debug_abort("assert: " __VA_ARGS__ " not (" hi_stringify(expression) ")"); \
414 } \
415 } while (false)
416
423#define hi_assert_or_return(x, y) \
424 if (!(x)) { \
425 [[unlikely]] return y; \
426 }
427
436#define hi_assert_bounds(x, ...) \
437 do { \
438 if (not ::hi::bound_check(x, __VA_ARGS__)) { \
439 hi_debug_abort("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
440 } \
441 } while (false)
442
449#define hi_assert_not_null(x, ...) \
450 do { \
451 if (x == nullptr) { \
452 hi_debug_abort("assert not-null: " __VA_ARGS__ " (" hi_stringify(x) ")"); \
453 } \
454 } while (false)
455
463#ifndef NDEBUG
464#define hi_axiom(expression, ...) hi_assert(expression __VA_OPT__(, ) __VA_ARGS__)
465#else
466#define hi_axiom(expression, ...) hi_assume(expression)
467#endif
468
478#ifndef NDEBUG
479#define hi_axiom_bounds(x, ...) hi_assert_bounds(x, __VA_ARGS__)
480#else
481#define hi_axiom_bounds(x, ...) hi_assume(not ::hi::bound_check(x, __VA_ARGS__))
482#endif
483
490#ifndef NDEBUG
491#define hi_axiom_not_null(expression, ...) hi_assert_not_null(expression __VA_OPT__(, ) __VA_ARGS__)
492#else
493#define hi_axiom_not_null(expression, ...) hi_assume(expression != nullptr)
494#endif
495
501#ifndef NDEBUG
502#define hi_no_default(...) \
503 [[unlikely]] hi_debug_abort("Reached no-default:" __VA_ARGS__); \
504 std::terminate()
505#else
506#define hi_no_default(...) std::unreachable()
507#endif
508
514#define hi_static_no_default(...) \
515 []<bool Flag = false>() \
516 { \
517 static_assert(Flag, "No default: " __VA_ARGS__); \
518 } \
519 ()
520
526#define hi_not_implemented(...) \
527 [[unlikely]] hi_debug_abort("Not implemented: " __VA_ARGS__); \
528 std::terminate()
529
535#define hi_static_not_implemented(...) hi_static_no_default("Not implemented: " __VA_ARGS__)
536
543#define hi_print(fmt, ...) console_output(std::format(fmt __VA_OPT__(, ) __VA_ARGS__))
544
545#define hi_format_argument_check(arg) \
546 static_assert( \
547 ::std::is_default_constructible_v<std::formatter<std::decay_t<decltype(arg)>>>, \
548 "std::format, argument '" #arg "' does not have a specialized std::formatter<>.");
549
562#define hi_format_check(fmt, ...) \
563 static_assert(::hi::format_count(fmt) != -1, "std::format, Unexpected '{' inside argument-format."); \
564 static_assert(::hi::format_count(fmt) != -2, "std::format, Unexpected '}' without corresponding '{'."); \
565 static_assert(::hi::format_count(fmt) != -3, "std::format, Missing '}' at end of format string."); \
566 static_assert( \
567 ::hi::format_count(fmt) == hi_num_va_args(__VA_ARGS__), "std::format, invalid number of arguments for format string."); \
568 hi_for_each(hi_format_argument_check, __VA_ARGS__)
569
570#define hi_log(level, fmt, ...) \
571 hi_format_check(fmt __VA_OPT__(, ) __VA_ARGS__); \
572 ::hi::log_global.add<level, __FILE__, __LINE__, fmt>(__VA_ARGS__)
573
574#define hi_log_debug(fmt, ...) hi_log(::hi::global_state_type::log_debug, fmt __VA_OPT__(, ) __VA_ARGS__)
575#define hi_log_info(fmt, ...) hi_log(::hi::global_state_type::log_info, fmt __VA_OPT__(, ) __VA_ARGS__)
576#define hi_log_statistics(fmt, ...) hi_log(::hi::global_state_type::log_statistics, fmt __VA_OPT__(, ) __VA_ARGS__)
577#define hi_log_trace(fmt, ...) hi_log(::hi::global_state_type::log_trace, fmt __VA_OPT__(, ) __VA_ARGS__)
578#define hi_log_audit(fmt, ...) hi_log(::hi::global_state_type::log_audit, fmt __VA_OPT__(, ) __VA_ARGS__)
579#define hi_log_warning(fmt, ...) hi_log(::hi::global_state_type::log_warning, fmt __VA_OPT__(, ) __VA_ARGS__)
580#define hi_log_error(fmt, ...) hi_log(::hi::global_state_type::log_error, fmt __VA_OPT__(, ) __VA_ARGS__)
581#define hi_log_fatal(fmt, ...) \
582 hi_log(::hi::global_state_type::log_fatal, fmt __VA_OPT__(, ) __VA_ARGS__); \
583 hi_debug_abort(); \
584 std::terminate()
585
586#define hi_log_info_once(name, fmt, ...) \
587 do { \
588 if (++::hi::global_counter<name> == 1) { \
589 hi_log(::hi::global_state_type::log_info, fmt __VA_OPT__(, ) __VA_ARGS__); \
590 } \
591 } while (false)
592
593#define hi_log_error_once(name, fmt, ...) \
594 do { \
595 if (++::hi::global_counter<name> == 1) { \
596 hi_log(::hi::global_state_type::log_error, fmt __VA_OPT__(, ) __VA_ARGS__); \
597 } \
598 } while (false)
599
600#endif