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
#if defined(_MSC_BUILD)
8
#include <intrin.h>
9
#endif
10
#include <version>
11
#include <exception>
12
13
#define HI_OS_WINDOWS 'W'
14
#define HI_OS_ANDROID 'A'
15
#define HI_OS_LINUX 'L'
16
#define HI_OS_MACOS 'M'
17
#define HI_OS_IOS 'I'
18
19
// W don't use HI_GENERIC for the operating system, because too many things
20
// like mmap-file-io, vulkan, window, main-loop depend on this.
21
#if defined(_WIN32)
22
#define HI_OPERATING_SYSTEM HI_OS_WINDOWS
23
#elif defined(__ANDROID__)
24
#define HI_OPERATING_SYSTEM HI_OS_ANDROID
25
#elif defined(__linux__)
26
#define HI_OPERATING_SYSTEM HI_OS_LINUX
27
#elif defined(__APPLE__) and defined(__MACH__)
28
#include <TargetConditionals.h>
29
#if TARGET_IPHONE_SIMULATOR or TARGET_OS_IPHONE or TARGET_OS_MACCATALYST
30
#define HI_OPERATING_SYSTEM HI_OS_IOS
31
#else
32
#define HI_OPERATING_SYSTEM HI_OS_MACOS
33
#endif
34
#else
35
#error "Unknown operating system"
36
#endif
37
38
#define HI_CC_MSVC 'm'
39
#define HI_CC_GCC 'g'
40
#define HI_CC_CLANG 'c'
41
#define HI_CC_OTHER '-'
42
43
#if defined(HI_GENERIC)
44
#define HI_COMPILER HI_CC_OTHER
45
#elif defined(__clang__)
46
#define HI_COMPILER HI_CC_CLANG
47
#elif defined(_MSC_BUILD)
48
#define HI_COMPILER HI_CC_MSVC
49
#elif defined(__GNUC__)
50
#define HI_COMPILER HI_CC_GCC
51
#else
52
#define HI_COMPILER HI_CC_OTHER
53
#endif
54
55
#define HI_STL_MS 'm'
56
#define HI_STL_GNU 'g'
57
#define HI_STL_LLVM 'l'
58
#define HI_STL_OTHER '-'
59
60
#if defined(HI_GENERIC)
61
#define HI_STD_LIBRARY HI_STL_OTHER
62
#elif defined(__GLIBCXX__)
63
#define HI_STD_LIBRARY HI_STL_GNU
64
#elif defined(_LIBCPP_VERSION)
65
#define HI_STD_LIBRARY HI_STL_LLVM
66
#elif defined(_CPPLIB_VER)
67
#define HI_STD_LIBRARY HI_STL_MS
68
#else
69
#define HI_STD_LIBRARY HI_STL_OTHER
70
#endif
71
72
#define HI_CPU_X86 'i'
73
#define HI_CPU_X86_64 'I'
74
#define HI_CPU_ARM 'a'
75
#define HI_CPU_ARM64 'A'
76
#define HI_CPU_OTHER '-'
77
78
79
#if defined(HI_GENERIC)
80
#define HI_PROCESSOR HI_CPU_OTHER
81
82
// MSVC platform detection.
83
// - _M_AMD64 determines if the processor is 64 bit, both x86-64 and arm64.
84
// - _M_IX86 is not defined on x86-64, but _M_IX86_FP is.
85
#elif defined(_M_IX86_FP)
86
#if defined(_M_AMD64)
87
#define HI_PROCESSOR HI_CPU_X86_64
88
#else
89
#define HI_PROCESSOR HI_CPU_X86
90
#endif
91
92
#elif defined(_M_ARM_FP)
93
#if defined(_M_AMD64)
94
#define HI_PROCESSOR HI_CPU_ARM64
95
#else
96
#define HI_PROCESSOR HI_CPU_ARM
97
#endif
98
99
// clang/gcc platform detection
100
#elif defined(__amd64__) or defined(__amd64) or defined(__x86_64__) or defined(__x86_64) or defined(_M_AMD64) or defined(_M_X64)
101
#define HI_PROCESSOR HI_CPU_X86_64
102
#elif defined(__aarch64__) or defined(_M_ARM64)
103
#define HI_PROCESSOR HI_CPU_ARM64
104
#elif defined(__i386__) or defined(_M_IX86)
105
#define HI_PROCESSOR HI_CPU_X86
106
#elif defined(__arm__) or defined(__arm) or defined(_ARM) or defined(_M_ARM)
107
#define HI_PROCESSOR HI_CPU_ARM
108
109
// Fallback if CPU is not detected.
110
#else
111
#define HI_PROCESSOR HI_CPU_OTHER
112
#endif
113
114
#ifndef hi_keywords
115
#define hi_keywords
116
#define hi_export
117
#define hi_export_module(...)
118
#if defined(__clang__) or defined(__GNUC__)
119
#define hi_target(...) [[gnu::target(__VA_ARGS__)]]
120
#define hi_no_inline [[gnu::noinline]]
121
#define hi_force_inline [[gnu::always_inline]]
122
#define hi_restrict __restrict__
123
#define hi_warning_push() _Pragma("warning(push)")
124
#define hi_warning_pop() _Pragma("warning(push)")
125
#define hi_warning_ignore_msvc(...)
126
#define hi_warning_ignore_clang(...) _Pragma(hi_stringify(clang diagnostic ignored __VA_ARGS__))
127
#define hi_warning_ignore_gcc(...)
128
#define hi_no_sanitize_address
129
#define hi_assume(...) __builtin_assume(not not(__VA_ARGS__))
130
#define hi_assert_break() __builtin_trap()
131
#define hi_debug_break() __builtin_debugtrap()
132
#elif defined(_MSC_BUILD)
133
#define hi_target(...)
134
#define hi_no_inline [[msvc::noinline]]
135
#define hi_force_inline [[msvc::forceinline]]
136
#define hi_restrict __restrict
137
#define hi_warning_push() _Pragma("warning( push )")
138
#define hi_warning_pop() _Pragma("warning( pop )")
139
#define hi_warning_ignore_msvc(...) _Pragma(hi_stringify(warning(disable : __VA_ARGS__)))
140
#define hi_warning_ignore_clang(...)
141
#define hi_warning_ignore_gcc(...)
142
#define hi_no_sanitize_address __declspec(no_sanitize_address)
143
#define hi_assume(...) __assume(not not(__VA_ARGS__))
144
#define hi_assert_break() __int2c()
145
#define hi_debug_break() __debugbreak()
146
#else
147
#define hi_target(...)
148
#define hi_no_inline
149
#define hi_force_inline
150
#define hi_restrict
151
#define hi_warning_push()
152
#define hi_warning_pop()
153
#define hi_warning_ignore_msvc(...)
154
#define hi_warning_ignore_clang(...)
155
#define hi_warning_ignore_gcc(...)
156
#define hi_no_sanitize_address
157
#define hi_assume(...) static_assert(std::convertible_to<decltype(not not(__VA_ARGS__)), bool>)
158
#define hi_assert_break() std::terminate()
159
#define hi_debug_break() std::terminate()
160
#endif
161
#endif
162
169
#define hi_return_if_valid(expression) \
170
do { \
171
if constexpr (requires { expression; }) { \
172
return expression; \
173
} \
174
} while (false)
175
176
// One clang-format off is not enough to stop clang-format to format.
177
// clang-format off
178
#define hi_num_va_args_impl( \
179
_1, _2, _3, _4, _5, _6, _7, _8, _9,_10, \
180
_11,_12,_13,_14,_15,_16,_17,_18,_19,_20, \
181
_21,_22,_23,_24,_25,_26,_27,_28,_29,_30, \
182
_31,_32,_33,_34,_35,_36,_37,_38,_39,_40, \
183
_41,_42,_43,_44,_45,_46,_47,_48,_49,_50, \
184
_51,_52,_53,_54,_55,_56,_57,_58,_59,_60, \
185
_61,_62,_63,N,...) N
186
#define hi_num_va_args_(...) hi_num_va_args_impl(__VA_ARGS__)
187
// clang-format on
188
194
// clang-format off
195
#define hi_num_va_args(...) hi_num_va_args_(__VA_ARGS__ __VA_OPT__(,) \
196
63,62,61,60, \
197
59,58,57,56,55,54,53,52,51,50, \
198
49,48,47,46,45,44,43,42,41,40, \
199
39,38,37,36,35,34,33,32,31,30, \
200
29,28,27,26,25,24,23,22,21,20, \
201
19,18,17,16,15,14,13,12,11,10, \
202
9,8,7,6,5,4,3,2,1,0)
203
// clang-format on
204
205
#define hi_parans ()
206
207
#define hi_expand1(...) __VA_ARGS__
208
#define hi_expand2(...) hi_expand1(hi_expand1(hi_expand1(hi_expand1(__VA_ARGS__))))
209
#define hi_expand3(...) hi_expand2(hi_expand2(hi_expand2(hi_expand2(__VA_ARGS__))))
210
#define hi_expand4(...) hi_expand3(hi_expand3(hi_expand3(hi_expand3(__VA_ARGS__))))
211
216
#define hi_expand(...) hi_expand4(hi_expand4(hi_expand4(hi_expand4(__VA_ARGS__))))
217
218
#define hi_for_each_again() hi_for_each_helper
219
#define hi_for_each_helper(macro, first_arg, ...) macro(first_arg) __VA_OPT__(hi_for_each_again hi_parans(macro, __VA_ARGS__))
220
226
#define hi_for_each(macro, ...) __VA_OPT__(hi_expand(hi_for_each_helper(macro, __VA_ARGS__)))
227
228
#ifndef hi_stringify
229
#define hi_stringify_(x) #x
230
#define hi_stringify(x) hi_stringify_(x)
231
#endif
232
233
#define hi_cat_(a, b) a##b
234
#define hi_cat(a, b) hi_cat_(a, b)
235
236
#define hi_return_on_self_assignment(other) \
237
if (&(other) == this) [[unlikely]] \
238
return *this;
239
249
#define hi_get_overloaded_macro2(_1, _2, name, ...) name
250
251
#define ssizeof(x) (static_cast<ssize_t>(sizeof(x)))
252
267
#define hi_assert_abort(...) \
268
do { \
269
::hi::set_debug_message(__FILE__ ":" hi_stringify(__LINE__) ":" __VA_ARGS__); \
270
hi_assert_break(); \
271
} while (false)
272
283
#define hi_check(expression, message, ...) \
284
do { \
285
if (not(expression)) { \
286
if constexpr (__VA_OPT__(not ) false) { \
287
throw parse_error(std::format(message __VA_OPT__(, ) __VA_ARGS__)); \
288
} else { \
289
throw parse_error(message); \
290
} \
291
} \
292
} while (false)
293
305
#define hi_check_bounds(x, ...) \
306
do { \
307
if (not ::hi::bound_check(x, __VA_ARGS__)) { \
308
throw parse_error("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
309
} \
310
} while (false)
311
324
#define hi_check_subspan(span, offset, ...) \
325
[&](auto _hi_check_subspan_span, size_t _hi_check_subspan_offset, auto... _hi_check_subspan_count) { \
326
if constexpr (sizeof...(_hi_check_subspan_count) == 0) { \
327
if (_hi_check_subspan_offset < _hi_check_subspan_span.size()) { \
328
return _hi_check_subspan_span.subspan(_hi_check_subspan_offset); \
329
} \
330
} else if constexpr (sizeof...(_hi_check_subspan_count) == 1) { \
331
if (_hi_check_subspan_offset + wide_cast<size_t>(_hi_check_subspan_count...) <= _hi_check_subspan_span.size()) { \
332
return _hi_check_subspan_span.subspan(_hi_check_subspan_offset, _hi_check_subspan_count...); \
333
} \
334
} \
335
throw parse_error( \
336
"assert bounds on: " hi_stringify(span) ".subspan(" hi_stringify(offset __VA_OPT__(", ") __VA_ARGS__) ")"); \
337
}(span, offset __VA_OPT__(, ) __VA_ARGS__)
338
349
#define hi_check_at(span, index) \
350
[&](auto _hi_check_subspan_span, size_t _hi_check_subspan_index) { \
351
if (_hi_check_subspan_index < _hi_check_subspan_span.size()) { \
352
return _hi_check_subspan_span[_hi_check_subspan_index]; \
353
} else { \
354
throw parse_error("assert bounds on: " hi_stringify(span) "[" hi_stringify(index) "]"); \
355
} \
356
}(span, index)
357
358
#define hi_hresult_check(expression) \
359
([](HRESULT result) { \
360
if (FAILED(result)) { \
361
throw ::hi::io_error(std::format("Call to '{}' failed with {:08x}", #expression, result)); \
362
} \
363
return result; \
364
}(expression))
365
372
#define hi_assert(expression, ...) \
373
do { \
374
if (not(expression)) { \
375
hi_assert_abort("assert: " __VA_ARGS__ " not (" hi_stringify(expression) ")"); \
376
} \
377
} while (false)
378
385
#define hi_assert_or_return(x, y) \
386
if (!(x)) { \
387
[[unlikely]] return y; \
388
}
389
398
#define hi_assert_bounds(x, ...) \
399
do { \
400
if (not ::hi::bound_check(x, __VA_ARGS__)) { \
401
hi_assert_abort("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
402
} \
403
} while (false)
404
411
#define hi_assert_not_null(x, ...) \
412
do { \
413
if (x == nullptr) { \
414
hi_assert_abort("assert not-null: " __VA_ARGS__ " (" hi_stringify(x) ")"); \
415
} \
416
} while (false)
417
425
#ifndef NDEBUG
426
#define hi_axiom(expression, ...) hi_assert(expression __VA_OPT__(, ) __VA_ARGS__)
427
#else
428
#define hi_axiom(expression, ...) hi_assume(expression)
429
#endif
430
440
#ifndef NDEBUG
441
#define hi_axiom_bounds(x, ...) hi_assert_bounds(x, __VA_ARGS__)
442
#else
443
#define hi_axiom_bounds(x, ...) hi_assume(not ::hi::bound_check(x, __VA_ARGS__))
444
#endif
445
452
#ifndef NDEBUG
453
#define hi_axiom_not_null(expression, ...) hi_assert_not_null(expression __VA_OPT__(, ) __VA_ARGS__)
454
#else
455
#define hi_axiom_not_null(expression, ...) hi_assume(expression != nullptr)
456
#endif
457
463
#ifndef NDEBUG
464
#define hi_no_default(...) \
465
[[unlikely]] hi_assert_abort("Reached no-default:" __VA_ARGS__); \
466
std::terminate()
467
#else
468
#define hi_no_default(...) std::unreachable()
469
#endif
470
476
#define hi_static_no_default(...) \
477
[]<bool Flag = false>() \
478
{ \
479
static_assert(Flag, "No default: " __VA_ARGS__); \
480
} \
481
()
482
488
#define hi_not_implemented(...) \
489
[[unlikely]] hi_assert_abort("Not implemented: " __VA_ARGS__); \
490
std::terminate()
491
497
#define hi_static_not_implemented(...) hi_static_no_default("Not implemented: " __VA_ARGS__)
498
505
#define hi_print(fmt, ...) console_output(std::format(fmt __VA_OPT__(, ) __VA_ARGS__))
506
507
#define hi_format_argument_check(arg) \
508
static_assert( \
509
::std::is_default_constructible_v<std::formatter<std::decay_t<decltype(arg)>>>, \
510
"std::format, argument '" #arg "' does not have a specialized std::formatter<>.");
511
524
#define hi_format_check(fmt, ...) \
525
static_assert(::hi::format_count(fmt) != -1, "std::format, Unexpected '{' inside argument-format."); \
526
static_assert(::hi::format_count(fmt) != -2, "std::format, Unexpected '}' without corresponding '{'."); \
527
static_assert(::hi::format_count(fmt) != -3, "std::format, Missing '}' at end of format string."); \
528
static_assert( \
529
::hi::format_count(fmt) == hi_num_va_args(__VA_ARGS__), "std::format, invalid number of arguments for format string."); \
530
hi_for_each(hi_format_argument_check, __VA_ARGS__)
531
532
#define hi_log(level, fmt, ...) \
533
hi_format_check(fmt __VA_OPT__(, ) __VA_ARGS__); \
534
::hi::log_global.add<level, __FILE__, __LINE__, fmt>(__VA_ARGS__)
535
536
#define hi_log_debug(fmt, ...) hi_log(::hi::global_state_type::log_debug, fmt __VA_OPT__(, ) __VA_ARGS__)
537
#define hi_log_info(fmt, ...) hi_log(::hi::global_state_type::log_info, fmt __VA_OPT__(, ) __VA_ARGS__)
538
#define hi_log_statistics(fmt, ...) hi_log(::hi::global_state_type::log_statistics, fmt __VA_OPT__(, ) __VA_ARGS__)
539
#define hi_log_trace(fmt, ...) hi_log(::hi::global_state_type::log_trace, fmt __VA_OPT__(, ) __VA_ARGS__)
540
#define hi_log_audit(fmt, ...) hi_log(::hi::global_state_type::log_audit, fmt __VA_OPT__(, ) __VA_ARGS__)
541
#define hi_log_warning(fmt, ...) hi_log(::hi::global_state_type::log_warning, fmt __VA_OPT__(, ) __VA_ARGS__)
542
#define hi_log_error(fmt, ...) hi_log(::hi::global_state_type::log_error, fmt __VA_OPT__(, ) __VA_ARGS__)
543
#define hi_log_fatal(fmt, ...) \
544
hi_log(::hi::global_state_type::log_fatal, fmt __VA_OPT__(, ) __VA_ARGS__); \
545
hi_assert_abort(); \
546
std::terminate()
547
548
#define hi_log_info_once(name, fmt, ...) \
549
do { \
550
if (++::hi::global_counter<name> == 1) { \
551
hi_log(::hi::global_state_type::log_info, fmt __VA_OPT__(, ) __VA_ARGS__); \
552
} \
553
} while (false)
554
555
#define hi_log_error_once(name, fmt, ...) \
556
do { \
557
if (++::hi::global_counter<name> == 1) { \
558
hi_log(::hi::global_state_type::log_error, fmt __VA_OPT__(, ) __VA_ARGS__); \
559
} \
560
} while (false)
561
572
#define hi_num_valid_arguments(ATTRIBUTES, NAME, CHECK_CALLABLE) \
573
template<size_t I, typename First, typename... Rest> \
574
ATTRIBUTES size_t _ ## NAME() \
575
{ \
576
if constexpr (I > 1) { \
577
return _ ## NAME<I - 1, Rest..., First>(); \
578
} else if constexpr (I == 1) { \
579
return _ ## NAME<0, Rest...>(); \
580
} else if constexpr (requires (First &&f, Rest &&...r) { CHECK_CALLABLE(std::forward<First>(f), std::forward<Rest>(r)...); }) { \
581
return sizeof...(Rest) + 1; \
582
} else if constexpr (sizeof...(Rest)) { \
583
return _ ## NAME<sizeof...(Rest) + 1, First, Rest...>(); \
584
} else { \
585
return 0; \
586
} \
587
} \
588
template<typename... Args> \
589
ATTRIBUTES size_t NAME() \
590
{ \
591
if constexpr (sizeof...(Args) != 0) { \
592
return _ ## NAME<0, Args...>(); \
593
} else { \
594
return 0; \
595
} \
596
}
597
608
// To use the right arguments, we first need to rotate them before we can
609
// remove the ones we don't need. Since we can only remove arguments on the left
610
// side.
611
#define hi_call_left_arguments(ATTRIBUTES, NAME, CALLABLE) \
612
template<size_t N, size_t R, typename First, typename... Rest>\
613
ATTRIBUTES auto _ ## NAME(First &&first, Rest &&...rest)\
614
{\
615
if constexpr (R != 0) { \
616
return _ ## NAME<N, R - 1, Rest..., First>(std::forward<Rest>(rest)..., std::forward<First>(first)); \
617
} else if constexpr (N != sizeof...(Rest) + 1) {\
618
return _ ## NAME<N, 0, Rest...>(std::forward<Rest>(rest)...);\
619
} else { \
620
return CALLABLE(std::forward<First>(first), std::forward<Rest>(rest)...);\
621
}\
622
}\
623
template<size_t N, typename... Args>\
624
ATTRIBUTES auto NAME(Args &&...args)\
625
{\
626
static_assert(N <= sizeof...(Args)); \
627
if constexpr (N == sizeof...(Args)) { \
628
return CALLABLE(std::forward<Args>(args)...); \
629
} else {\
630
return _ ## NAME<N, N, Args...>(std::forward<Args>(args)...); \
631
}\
632
}
633
644
#define hi_call_right_arguments(ATTRIBUTES, NAME, CALLABLE) \
645
template<size_t Skip>\
646
ATTRIBUTES auto NAME()\
647
{\
648
static_assert(Skip == 0); \
649
return CALLABLE();\
650
}\
651
template<size_t Skip, typename First, typename... Rest>\
652
ATTRIBUTES auto NAME(First &&first, Rest &&...rest)\
653
{\
654
static_assert(Skip <= (sizeof...(Rest) + 1)); \
655
if constexpr (Skip != 0) {\
656
return NAME<Skip - 1, Rest...>(std::forward<Rest>(rest)...);\
657
} else {\
658
return CALLABLE(std::forward<First>(first), std::forward<Rest>(rest)...);\
659
}\
660
}
661
Generated on Mon Apr 22 2024 12:51:37 for HikoGUI by
1.10.0