HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
assert.hpp
Go to the documentation of this file.
1// Copyright Take Vos 2020-2022.
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
7
8#pragma once
9
10#include "architecture.hpp"
11#include "debugger.hpp"
12#include "utility.hpp"
13#include "type_traits.hpp"
14#include "exception.hpp"
15#include <exception>
16#include <ranges>
17
18hi_warning_push();
19// "C26472: Don't use a static_cast for arithmetic", asserts use static_cast specifically for savety.
21
22namespace hi { inline namespace v1 {
23
30[[nodiscard]] constexpr bool bound_check(std::unsigned_integral auto index, std::unsigned_integral auto upper) noexcept
31{
32 using value_type = common_integer_t<decltype(index), decltype(upper)>;
33
34 hilet index_ = static_cast<value_type>(index);
35 hilet upper_ = static_cast<value_type>(upper);
36 return index_ < upper_;
37}
38
39[[nodiscard]] constexpr bool bound_check(std::unsigned_integral auto index, std::signed_integral auto upper) noexcept
40{
41 if (upper <= 0) {
42 return false;
43 }
44 return bound_check(index, static_cast<std::make_unsigned_t<decltype(upper)>>(upper));
45}
46
55[[nodiscard]] constexpr bool bound_check(std::integral auto index, std::integral auto lower, std::integral auto upper) noexcept
56{
57 using value_type = common_integer_t<decltype(index), decltype(lower), decltype(upper)>;
58
59 auto index_ = static_cast<value_type>(index);
60 auto lower_ = static_cast<value_type>(lower);
61 auto upper_ = static_cast<value_type>(upper);
62
63#ifndef NDEBUG
64 if (not (lower_ < upper_)) {
65 hi_debug_abort("bound_check() lower is greater than upper.");
66 }
67#else
68 hi_assume(lower_ < upper_);
69#endif
70
71 return index_ >= lower_ and index_ < upper_;
72}
73
74template<typename Context>
75concept bound_check_range_helper = requires(Context&& range) {
76 {
77 std::ranges::size(range)
78 } -> std::unsigned_integral;
79 };
80
87[[nodiscard]] constexpr bool bound_check(std::integral auto index, bound_check_range_helper auto&& range) noexcept
88{
89 static_assert(sizeof(index) <= sizeof(size_t));
90
91 if constexpr (std::is_signed_v<std::decay_t<decltype(index)>>) {
92 if (index < 0) {
93 return false;
94 }
95 }
96
97 return static_cast<size_t>(index) < std::ranges::size(range);
98}
99
110#define hi_check(expression, message, ...) \
111 do { \
112 if (not(expression)) { \
113 if constexpr (__VA_OPT__(not ) false) { \
114 throw parse_error(std::format(message __VA_OPT__(, ) __VA_ARGS__)); \
115 } else { \
116 throw parse_error(message); \
117 } \
118 } \
119 } while (false)
120
132#define hi_check_bounds(x, ...) \
133 do { \
134 if (not ::hi::bound_check(x, __VA_ARGS__)) { \
135 throw parse_error("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
136 } \
137 } while (false)
138
151#define hi_check_subspan(span, offset, ...) \
152 [&](auto _hi_check_subspan_span, size_t _hi_check_subspan_offset, auto... _hi_check_subspan_count) { \
153 if constexpr (sizeof...(_hi_check_subspan_count) == 0) { \
154 if (_hi_check_subspan_offset < _hi_check_subspan_span.size()) { \
155 return _hi_check_subspan_span.subspan(_hi_check_subspan_offset); \
156 } \
157 } else if constexpr (sizeof...(_hi_check_subspan_count) == 1) { \
158 if (_hi_check_subspan_offset + wide_cast<size_t>(_hi_check_subspan_count...) <= _hi_check_subspan_span.size()) { \
159 return _hi_check_subspan_span.subspan(_hi_check_subspan_offset, _hi_check_subspan_count...); \
160 } \
161 } \
162 throw parse_error( \
163 "assert bounds on: " hi_stringify(span) ".subspan(" hi_stringify(offset __VA_OPT__(", ") __VA_ARGS__) ")"); \
164 }(span, offset __VA_OPT__(, ) __VA_ARGS__)
165
176#define hi_check_at(span, index) \
177 [&](auto _hi_check_subspan_span, size_t _hi_check_subspan_index) { \
178 if (_hi_check_subspan_index < _hi_check_subspan_span.size()) { \
179 return _hi_check_subspan_span[_hi_check_subspan_index]; \
180 } else { \
181 throw parse_error("assert bounds on: " hi_stringify(span) "[" hi_stringify(index) "]"); \
182 } \
183 }(span, index)
184
185#define hi_hresult_check(expression) \
186 ([](HRESULT result) { \
187 if (FAILED(result)) { \
188 throw ::hi::io_error(std::format("Call to '{}' failed with {:08x}", #expression, result)); \
189 } \
190 return result; \
191 }(expression))
192
199#define hi_assert(expression, ...) \
200 do { \
201 if (not(expression)) { \
202 hi_debug_abort("assert: " __VA_ARGS__ " (" hi_stringify(expression) ")"); \
203 } \
204 } while (false)
205
212#define hi_assert_or_return(x, y) \
213 if (!(x)) { \
214 [[unlikely]] return y; \
215 }
216
225#define hi_assert_bounds(x, ...) \
226 do { \
227 if (not ::hi::bound_check(x, __VA_ARGS__)) { \
228 hi_debug_abort("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
229 } \
230 } while (false)
231
238#define hi_assert_not_null(x, ...) \
239 do { \
240 if (x == nullptr) { \
241 hi_debug_abort("assert not-null: " __VA_ARGS__ " (" hi_stringify(x) ")"); \
242 } \
243 } while (false)
244
245#ifndef NDEBUG
253#define hi_axiom(expression, ...) hi_assert(expression __VA_OPT__(, ) __VA_ARGS__)
254
264#define hi_axiom_bounds(x, ...) hi_assert_bounds(x, __VA_ARGS__)
265
272#define hi_axiom_not_null(expression, ...) hi_assert_not_null(expression __VA_OPT__(, ) __VA_ARGS__)
273
279#define hi_no_default(...) [[unlikely]] hi_debug_abort("Reached no-default:" __VA_ARGS__)
280
281#else
289#define hi_axiom(expression, ...) hi_assume(expression)
290
300#define hi_axiom_bounds(x, ...) hi_assume(not ::hi::bound_check(x, __VA_ARGS__))
301
308#define hi_axiom_not_null(expression, ...) hi_assume(expression != nullptr)
309
315#define hi_no_default(...) hi_unreachable()
316#endif
317
323#define hi_static_no_default(...) \
324 []<bool Flag = false>() \
325 { \
326 static_assert(Flag, "No default: " __VA_ARGS__); \
327 } \
328 ()
329
335#define hi_not_implemented(...) [[unlikely]] hi_debug_abort("Not implemented: " __VA_ARGS__);
336
342#define hi_static_not_implemented(...) hi_static_no_default("Not implemented: " __VA_ARGS__)
343
344}} // namespace hi::v1
345
346hi_warning_pop();
hi_warning_ignore_msvc(26472)
Definition int_carry.hpp:27
Utilities for throwing exceptions and terminating the application.
Functions and macros for handling architectural difference between compilers, CPUs and operating syst...
Utilities used by the HikoGUI library itself.
Utilities to interact with the debugger this application runs under.
#define hi_debug_abort(...)
Debug-break and abort the application.
Definition debugger.hpp:50
geometry/margins.hpp
Definition cache.hpp:11
The HikoGUI API version 1.
Definition cache.hpp:11
constexpr bool bound_check(std::unsigned_integral auto index, std::unsigned_integral auto upper) noexcept
Check if an unsigned index is less than the bound.
Definition assert.hpp:30
Definition assert.hpp:75