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
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();
Utilities to interact with the debugger this application runs under.
#define hi_debug_abort(...)
Debug-break and abort the application.
Definition debugger.hpp:50
hi_warning_ignore_msvc(26472)
Definition int_carry.hpp:27
Utilities for throwing exceptions and terminating the application.
Utilities used by the HikoGUI library itself.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
Functions and macros for handling architectural difference between compilers, CPUs and operating syst...
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
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