HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
Namespaces | Concepts | Macros | Functions
assert.hpp File Reference

Utilities to assert and bound check. More...

#include "architecture.hpp"
#include "debugger.hpp"
#include "utility.hpp"
#include "type_traits.hpp"
#include "exception.hpp"
#include <exception>
#include <ranges>

Go to the source code of this file.

Namespaces

namespace  hi
 geometry/margins.hpp
 
namespace  hi::v1
 The HikoGUI API version 1.
 

Concepts

concept  hi::v1::bound_check_range_helper
 

Macros

#define hi_check(expression, message, ...)
 Check if the expression is valid, or throw a parse_error.
 
#define hi_check_bounds(x, ...)
 Assert if a value is within bounds, or throw a parse_error.
 
#define hi_check_subspan(span, offset, ...)
 Get a subspan, or throw a parse_error.
 
#define hi_check_at(span, index)
 Get an element from a span, or throw a parse_error.
 
#define hi_hresult_check(expression)
 
#define hi_assert(expression, ...)
 Assert if expression is true.
 
#define hi_assert_or_return(x, y)
 Assert if an expression is true.
 
#define hi_assert_bounds(x, ...)
 Assert if a value is within bounds.
 
#define hi_assert_not_null(x, ...)
 Assert if an expression is not nullptr.
 
#define hi_axiom(expression, ...)   hi_assert(expression __VA_OPT__(, ) __VA_ARGS__)
 Specify an axiom; an expression that is true.
 
#define hi_axiom_bounds(x, ...)   hi_assert_bounds(x, __VA_ARGS__)
 Specify an axiom that the value is within bounds.
 
#define hi_axiom_not_null(expression, ...)   hi_assert_not_null(expression __VA_OPT__(, ) __VA_ARGS__)
 Assert if an expression is not nullptr.
 
#define hi_no_default(...)   [[unlikely]] hi_debug_abort("Reached no-default:" __VA_ARGS__)
 This part of the code should not be reachable, unless a programming bug.
 
#define hi_static_no_default(...)
 This part of the code should not be reachable, unless a programming bug.
 
#define hi_not_implemented(...)   [[unlikely]] hi_debug_abort("Not implemented: " __VA_ARGS__);
 This part of the code has not been implemented yet.
 
#define hi_static_not_implemented(...)   hi_static_no_default("Not implemented: " __VA_ARGS__)
 This part of the code has not been implemented yet.
 

Functions

 hi_warning_push ()
 
 hi_warning_ignore_msvc (26472)
 
constexpr bool hi::v1::bound_check (std::unsigned_integral auto index, std::unsigned_integral auto upper) noexcept
 Check if an unsigned index is less than the bound.
 
constexpr bool hi::v1::bound_check (std::unsigned_integral auto index, std::signed_integral auto upper) noexcept
 
constexpr bool hi::v1::bound_check (std::integral auto index, std::integral auto lower, std::integral auto upper) noexcept
 Check if an index is between the lower (inclusive) and upper (exclusive).
 
constexpr bool hi::v1::bound_check (std::integral auto index, bound_check_range_helper auto &&range) noexcept
 Check if an index is within a range.
 
 hi_warning_pop ()
 

Detailed Description

Utilities to assert and bound check.

Macro Definition Documentation

◆ hi_assert

#define hi_assert ( expression,
... )
Value:
do { \
if (not(expression)) { \
hi_debug_abort("assert: " __VA_ARGS__ " (" hi_stringify(expression) ")"); \
} \
} while (false)

Assert if expression is true.

Independent of built type this macro will always check and abort on fail.

Parameters
expressionThe expression to test.
...A string-literal explaining the reason why this assert exists.

◆ hi_assert_bounds

#define hi_assert_bounds ( x,
... )
Value:
do { \
if (not ::hi::bound_check(x, __VA_ARGS__)) { \
hi_debug_abort("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
} \
} while (false)
#define hi_for_each(macro,...)
Evaluate a macro for each argument.
Definition utility.hpp:94

Assert if a value is within bounds.

Independent of built type this macro will always check and abort on fail.

Lower-bound is inclusive and Upper-bound is exclusive.

Parameters
xThe value to check if it is within bounds.
...One upper-bound; or a lower-bound and upper-bound.

◆ hi_assert_not_null

#define hi_assert_not_null ( x,
... )
Value:
do { \
if (x == nullptr) { \
hi_debug_abort("assert not-null: " __VA_ARGS__ " (" hi_stringify(x) ")"); \
} \
} while (false)

Assert if an expression is not nullptr.

If the expression is not a nullptr then return from the function.

Parameters
xThe expression to test
...A string-literal as the reason why the not-null check exists.

◆ hi_assert_or_return

#define hi_assert_or_return ( x,
y )
Value:
if (!(x)) { \
[[unlikely]] return y; \
}

Assert if an expression is true.

If the expression is false then return from the function.

Parameters
xThe expression to test
yThe value to return from the current function.

◆ hi_axiom

#define hi_axiom ( expression,
... )   hi_assert(expression __VA_OPT__(, ) __VA_ARGS__)

Specify an axiom; an expression that is true.

An axiom is checked in debug mode, and is used as an optimization in release mode.

Parameters
expressionThe expression that is true.
...A string-literal as the reason why the axiom exists.

◆ hi_axiom_bounds

#define hi_axiom_bounds ( x,
... )   hi_assert_bounds(x, __VA_ARGS__)

Specify an axiom that the value is within bounds.

An axiom is checked in debug mode, and is used as an optimization in release mode.

Lower-bound is inclusive and Upper-bound is exclusive.

Parameters
xThe value to check if it is within bounds.
...One upper-bound; or a lower-bound and upper-bound.

◆ hi_axiom_not_null

#define hi_axiom_not_null ( expression,
... )   hi_assert_not_null(expression __VA_OPT__(, ) __VA_ARGS__)

Assert if an expression is not nullptr.

If the expression is not a nullptr then return from the function.

Parameters
expressionThe expression to test
...A string-literal as the reason why the not-null check exists.

◆ hi_check

#define hi_check ( expression,
message,
... )
Value:
do { \
if (not(expression)) { \
if constexpr (__VA_OPT__(not ) false) { \
throw parse_error(std::format(message __VA_OPT__(, ) __VA_ARGS__)); \
} else { \
throw parse_error(message); \
} \
} \
} while (false)

Check if the expression is valid, or throw a parse_error.

This function is used to check if an expression is correct during the parsing of data.

Parameters
expressionThe expression to check.
messageThe message to set in the parse_error.
...Optional format parameters for the message.
Exceptions
parse_errorWhen the expression yields false.

◆ hi_check_at

#define hi_check_at ( span,
index )
Value:
[&](auto _hi_check_subspan_span, size_t _hi_check_subspan_index) { \
if (_hi_check_subspan_index < _hi_check_subspan_span.size()) { \
return _hi_check_subspan_span[_hi_check_subspan_index]; \
} else { \
throw parse_error("assert bounds on: " hi_stringify(span) "[" hi_stringify(index) "]"); \
} \
}(span, index)

Get an element from a span, or throw a parse_error.

This function is used to get an element of span with bounds checks during parsing of data.

Parameters
spanThe span to take the subspan of.
indexThe index to the element in the span.
Returns
A reference to the element.
Exceptions
parse_errorWhen the index is not contained in the given span.

◆ hi_check_bounds

#define hi_check_bounds ( x,
... )
Value:
do { \
if (not ::hi::bound_check(x, __VA_ARGS__)) { \
throw parse_error("assert bounds: " hi_stringify(x) " between " hi_for_each(hi_stringify, (__VA_ARGS__))); \
} \
} while (false)

Assert if a value is within bounds, or throw a parse_error.

This function is used to check if a value is within bounds during parsing of data.

Lower-bound is inclusive and Upper-bound is exclusive.

Parameters
xThe value to check if it is within bounds.
...One upper-bound; or a lower-bound and upper-bound.
Exceptions
parse_errorWhen the expression yields false.

◆ hi_check_subspan

#define hi_check_subspan ( span,
offset,
... )
Value:
[&](auto _hi_check_subspan_span, size_t _hi_check_subspan_offset, auto... _hi_check_subspan_count) { \
if constexpr (sizeof...(_hi_check_subspan_count) == 0) { \
if (_hi_check_subspan_offset < _hi_check_subspan_span.size()) { \
return _hi_check_subspan_span.subspan(_hi_check_subspan_offset); \
} \
} else if constexpr (sizeof...(_hi_check_subspan_count) == 1) { \
if (_hi_check_subspan_offset + wide_cast<size_t>(_hi_check_subspan_count...) <= _hi_check_subspan_span.size()) { \
return _hi_check_subspan_span.subspan(_hi_check_subspan_offset, _hi_check_subspan_count...); \
} \
} \
throw parse_error( \
"assert bounds on: " hi_stringify(span) ".subspan(" hi_stringify(offset __VA_OPT__(", ") __VA_ARGS__) ")"); \
}(span, offset __VA_OPT__(, ) __VA_ARGS__)

Get a subspan, or throw a parse_error.

This function is used to get a subspan of data with bounds checks during parsing of data.

Parameters
spanThe span to take the subspan of.
offsetThe offset within the span to start the subspan.
...Optional count for the number of elements in the subspan. When not specified the subspan is up to the end of the span.
Returns
A subspan.
Exceptions
parse_errorWhen the subspan does not fit the given span.

◆ hi_hresult_check

#define hi_hresult_check ( expression)
Value:
([](HRESULT result) { \
if (FAILED(result)) { \
throw ::hi::io_error(std::format("Call to '{}' failed with {:08x}", #expression, result)); \
} \
return result; \
}(expression))

◆ hi_no_default

#define hi_no_default ( ...)    [[unlikely]] hi_debug_abort("Reached no-default:" __VA_ARGS__)

This part of the code should not be reachable, unless a programming bug.

This function should be used in unreachable else statements or switch-default labels,

Parameters
...A string-literal as the reason why the no-default exists.

◆ hi_not_implemented

#define hi_not_implemented ( ...)    [[unlikely]] hi_debug_abort("Not implemented: " __VA_ARGS__);

This part of the code has not been implemented yet.

This aborts the program.

Parameters
...A string-literal as the reason why this it not implemented.

◆ hi_static_no_default

#define hi_static_no_default ( ...)
Value:
[]<bool Flag = false>() \
{ \
static_assert(Flag, "No default: " __VA_ARGS__); \
} \
()

This part of the code should not be reachable, unless a programming bug.

This function should be used in unreachable constexpr else statements.

Parameters
...A string-literal as the reason why the no-default exists.

◆ hi_static_not_implemented

#define hi_static_not_implemented ( ...)    hi_static_no_default("Not implemented: " __VA_ARGS__)

This part of the code has not been implemented yet.

This function should be used in unreachable constexpr else statements.

Parameters
...A string-literal as the reason why this it not implemented.

Function Documentation

◆ hi_warning_ignore_msvc()

hi_warning_ignore_msvc ( 26472 )

Get a bit from an array of unsigned integers. The integers are arranged in little-endian order.

Parameters
lhsThe array of integers from which to take the bit.
indexThe index of the bit
Returns
The value of the bit, either 0 or 1, with the same type as the integers of the array.

Set a bit from an array of unsigned integers. The integers are arranged in little-endian order.

Parameters
rThe array of integers on which to set the bit.
indexThe index of the bit
valueThe value of the bit, either 0 or 1.

Shift logical left with carry chain.

Parameters
lhsThe original value
rhsThe count by how much to shift lhs left.
carryThe carry data to or with the lower bits.
Returns
(result, carry); the carry which can be used to pass into the next iteration.

Shift logical right with carry chain.

Parameters
lhsThe original value
rhsThe count by how much to shift lhs right.
carryThe carry data to or with the lower bits.
Returns
(result, carry); the carry which can be used to pass into the next iteration.

Shift arithmetic right with carry chain.

Parameters
lhsThe original value
rhsThe count by how much to shift lhs right.
Returns
(result, carry); the carry which can be used to pass into the next iteration.

Add two numbers with carry chain.

Parameters
lhsThe left hand side
rhsThe right hand side
carryFrom the previous add in the chain
Returns
(result, carry) pair

Multiply with carry. The carry is a high-word of the multiplication result and has the same size as the inputs. The accumulator is used when doing long-multiplication from the previous row. This function does not overflow even if all the arguments are at max.

Parameters
lhsThe left hand side.
rhsThe right hand side.
carryThe carry-input; carry-output from the previous mul_carry().
accumulatorThe column value during a long multiply.
Returns
low, high of the result.

Wide divide. Can be used to divide a wide unsigned integer by a unsigned integer, as long as the result fits in an unsigned integer.

Parameters
lhs_loThe low side of a wide left-hand-side
lhs_hiThe high side of a wide left-hand-side
rhsThe right hand side
Returns
The result.

Bit scan reverse.

Parameters
lhsThe array of unsigned integers to find the highest set bit off.
nThe number of unsigned integers in the array.
Returns
index of leading one, or -1 when rhs is zero.

Invert unsigned integers using a carry-chain Technically this is not an carry chain.

Parameters
rThe result of the inversion.
rhsThe right hand side operand.
nThe number of digits of r and rhs.

shift logical right using a carry-chain

Parameters
rThe result of the logical-shift-right.
lhsThe left hand side operand of the lsr.
rhsThe right hand side operand of the lsr, the number of bits to shift.
nThe number of digits of r, lhs and rhs.

shift logical right using a carry-chain

Parameters
rThe result of the logical-shift-right.
lhsThe left hand side operand of the lsr.
rhsThe right hand side operand of the lsr, the number of bits to shift.
nThe number of digits of r, lhs and rhs.

shift arithmetic right using a carry-chain This sign-extends the left most bit.

Parameters
rThe result of the logical-shift-right.
lhsThe left hand side operand of the lsr.
rhsThe right hand side operand of the lsr, the number of bits to shift.
nThe number of digits of r, lhs and rhs.

and-operation unsigned integers using a carry-chain

Parameters
rThe result of the and-operation.
lhsThe left hand side operand of the and-operation.
rhsThe right hand side operand of the and-operation.
nThe number of digits of r, lhs and rhs.

or-operation unsigned integers using a carry-chain

Parameters
rThe result of the and-operation.
lhsThe left hand side operand of the or-operation.
rhsThe right hand side operand of the or-operation.
nThe number of digits of r, lhs and rhs.

xor-operation unsigned integers using a carry-chain

Parameters
rThe result of the and-operation.
lhsThe left hand side operand of the xor-operation.
rhsThe right hand side operand of the xor-operation.
nThe number of digits of r, lhs and rhs.

Negate unsigned integers using a carry-chain This is a two's compliment negate.

Parameters
rThe result of the addition.
rhsThe left hand side operand of the addition.
nThe number of digits of r, lhs and rhs.

Add unsigned integers using a carry-chain

Parameters
rThe result of the addition.
lhsThe left hand side operand of the addition.
rhsThe right hand side operand of the addition.
nThe number of digits of r, lhs and rhs.

Subtract unsigned integers using a carry-chain

Parameters
rThe result of the addition.
lhsThe left hand side operand of the addition.
rhsThe right hand side operand of the addition.
nThe number of digits of r, lhs and rhs.

Multiply unsigned integers using a carry-chain

Note
r May not alias with lhs or rhs.
Parameters
rThe result of the multiplication.
lhsThe left hand side operand.
rhsThe right hand side operand.
nThe number of digits of r, lhs and rhs.

Divide unsigned integers using a carry-chain This function does a bit-wise division.

Note
quotient and remainder may not alias with lhs or rhs or with each other.
Parameters
quotientThe result of the division.
remainderThe remainder of the division.
lhsThe left hand side operand.
rhsThe right hand side operand.
nThe number of digits of quotient, remainder, lhs and rhs.

signed divide unsigned integers using a carry-chain This function does a bit-wise division. This function will allocate memory when one or both operands are negative.

Note
quotient and remainder may not alias with lhs or rhs or with each other.
Parameters
quotientThe result of the division.
remainderThe remainder of the division. The remainder has same sign as lhs.
lhsThe left hand side operand.
rhsThe right hand side operand.
nThe number of digits of quotient, remainder, lhs and rhs.