20hi_warning_ignore_msvc(26472);
25hi_warning_ignore_msvc(26467);
28hi_warning_ignore_msvc(26496);
31hi_warning_ignore_msvc(26466);
34hi_warning_ignore_msvc(26474);
36namespace hi::inline
v1 {
38[[nodiscard]]
constexpr T
copy(T value)
noexcept
45template<
typename Out, std::derived_from<std::remove_po
inter_t<Out>> In>
46[[nodiscard]]
constexpr Out up_cast(In *rhs)
noexcept
47 requires std::is_pointer_v<Out> and
48 (std::is_const_v<std::remove_pointer_t<Out>> == std::is_const_v<In> or std::is_const_v<std::remove_pointer_t<Out>>)
50 if constexpr (std::is_same_v<std::remove_const_t<In>, remove_cvptr_t<Out>>) {
53 return static_cast<Out
>(rhs);
60[[nodiscard]]
constexpr Out up_cast(nullptr_t)
noexcept
61 requires std::is_pointer_v<Out>
68template<
typename Out, std::derived_from<std::remove_reference_t<Out>> In>
69[[nodiscard]]
constexpr Out up_cast(In& rhs)
noexcept
70 requires std::is_reference_v<Out> and
71 (std::is_const_v<std::remove_reference_t<Out>> == std::is_const_v<In> or std::is_const_v<std::remove_reference_t<Out>>)
73 if constexpr (std::is_same_v<std::remove_const_t<In>, std::remove_cvref_t<Out>>) {
76 return static_cast<Out
>(rhs);
87template<
typename Out, base_of<std::remove_po
inter_t<Out>> In>
88[[nodiscard]]
constexpr Out down_cast(In *rhs)
noexcept
89 requires std::is_pointer_v<Out> and
90 (std::is_const_v<std::remove_pointer_t<Out>> == std::is_const_v<In> or std::is_const_v<std::remove_pointer_t<Out>>)
92 if constexpr (std::is_same_v<std::remove_const_t<In>, remove_cvptr_t<Out>>) {
95 hi_axiom(rhs ==
nullptr or
dynamic_cast<Out
>(rhs) !=
nullptr);
96 return static_cast<Out
>(rhs);
104template<
typename Out>
105[[nodiscard]]
constexpr Out down_cast(nullptr_t)
noexcept
106 requires std::is_pointer_v<Out>
117template<
typename Out, base_of<std::remove_reference_t<Out>> In>
118[[nodiscard]]
constexpr Out down_cast(In& rhs)
noexcept
119 requires std::is_reference_v<Out> and
120 (std::is_const_v<std::remove_reference_t<Out>> == std::is_const_v<In> or std::is_const_v<std::remove_reference_t<Out>>)
122 if constexpr (std::is_same_v<std::remove_const_t<In>, std::remove_cvref_t<Out>>) {
126 return static_cast<Out
>(rhs);
132template<arithmetic Out, arithmetic In>
133[[nodiscard]]
constexpr Out wide_cast(In rhs)
noexcept
134 requires(type_in_range_v<Out, In>)
136 return static_cast<Out
>(rhs);
141template<arithmetic Out>
142[[nodiscard]]
constexpr Out wide_cast(
bool rhs)
noexcept
144 return static_cast<Out
>(rhs);
149template<arithmetic Out, arithmetic In>
150[[nodiscard]]
constexpr bool narrow_validate(Out out, In in)
noexcept
153 auto r = (in ==
static_cast<In
>(out));
158 r &= (in < In{}) == (out < Out{});
172template<std::
integral Out, arithmetic In>
173[[nodiscard]]
constexpr Out saturate_cast(In rhs)
noexcept
175 if constexpr (std::is_floating_point_v<In>) {
186 return static_cast<Out
>(rhs);
198template<
typename Out,
typename In>
199[[nodiscard]]
constexpr Out narrow_cast(In
const& rhs)
noexcept;
209template<arithmetic Out, arithmetic In>
210[[nodiscard]]
constexpr Out narrow_cast(In
const& rhs)
noexcept
212 if constexpr (type_in_range_v<Out, In>) {
213 return static_cast<Out
>(rhs);
215 hilet r =
static_cast<Out
>(rhs);
216 hi_axiom(detail::narrow_validate(r, rhs));
221template<arithmetic Out, arithmetic In>
222[[nodiscard]]
constexpr Out round_cast(In rhs)
noexcept
224 if constexpr (std::is_floating_point_v<In>) {
227 return narrow_cast<Out>(rhs);
231template<arithmetic Out, arithmetic In>
232[[nodiscard]]
constexpr Out floor_cast(In rhs)
noexcept
234 if constexpr (std::is_floating_point_v<In>) {
237 return narrow_cast<Out>(rhs);
241template<arithmetic Out, arithmetic In>
242[[nodiscard]]
constexpr Out ceil_cast(In rhs)
noexcept
244 if constexpr (std::is_floating_point_v<In>) {
247 return narrow_cast<Out>(rhs);
253template<std::
integral In>
254[[nodiscard]]
constexpr std::make_unsigned_t<In> to_unsigned(In rhs)
noexcept
256 return static_cast<std::make_unsigned_t<In>
>(rhs);
261template<std::
integral In>
262[[nodiscard]]
constexpr std::make_signed_t<In> to_signed(In rhs)
noexcept
264 return static_cast<std::make_signed_t<In>
>(rhs);
269template<std::
integral Out, std::
integral In>
270[[nodiscard]]
constexpr Out
truncate(In rhs)
noexcept
272 return static_cast<Out
>(to_unsigned(rhs));
275template<std::
integral Out, std::
integral In>
276[[nodiscard]]
constexpr Out sign_cast(In rhs)
noexcept
277 requires(
sizeof(Out) ==
sizeof(In))
279 return static_cast<Out
>(rhs);
282template<std::
signed_
integral Out, std::
signed_
integral In>
283[[nodiscard]]
constexpr Out saturate_cast(In rhs)
noexcept
285 if constexpr (
sizeof(Out) >=
sizeof(In)) {{
286 return static_cast<Out
>(rhs);
290 return static_cast<out
>(std::clamp(rhs, lo,
hi));
304template<std::
integral Out, std::
integral In>
305[[nodiscard]]
constexpr Out char_cast(In rhs)
noexcept
307 using in_unsigned_type = std::make_unsigned_t<In>;
308 using out_unsigned_type = std::make_unsigned_t<Out>;
311 auto in_unsigned =
static_cast<in_unsigned_type
>(rhs);
312 auto out_unsigned = narrow_cast<out_unsigned_type>(in_unsigned);
313 return static_cast<Out
>(out_unsigned);
326template<std::
integral Out>
327[[nodiscard]]
constexpr Out char_cast(std::byte rhs)
noexcept
329 return char_cast<Out>(
static_cast<uint8_t
>(rhs));
334template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
335[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
337 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of low_bit_cast must be half the size of the input");
338 return static_cast<OutType
>(value);
343template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
344[[nodiscard]]
constexpr OutType high_bit_cast(InType value)
noexcept
346 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of high_bit_cast must be half the size of the input");
347 return static_cast<OutType
>(value >>
sizeof(OutType) * CHAR_BIT);
352template<std::
signed_
integral OutType, std::
signed_
integral InType>
353[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
355 using UInType = std::make_unsigned_t<InType>;
356 using UOutType = std::make_unsigned_t<OutType>;
357 return static_cast<OutType
>(low_bit_cast<UOutType>(
static_cast<UInType
>(value)));
362template<std::
signed_
integral OutType, std::
signed_
integral InType>
363[[nodiscard]]
constexpr OutType high_bit_cast(InType value)
noexcept
365 using UInType = std::make_unsigned_t<InType>;
366 using UOutType = std::make_unsigned_t<OutType>;
367 return static_cast<OutType
>(high_bit_cast<UOutType>(
static_cast<UInType
>(value)));
372template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
373[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
375 using UInType = std::make_unsigned_t<InType>;
376 return low_bit_cast<OutType>(
static_cast<UInType
>(value));
381template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
382[[nodiscard]]
constexpr OutType high_bit_cast(InType value)
noexcept
384 using UInType = std::make_unsigned_t<InType>;
385 return high_bit_cast<OutType>(
static_cast<UInType
>(value));
390template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
391[[nodiscard]]
constexpr OutType merge_bit_cast(InType
hi, InType lo)
noexcept
393 static_assert(
sizeof(OutType) ==
sizeof(InType) * 2,
"Return value of merge_bit_cast must be double the size of the input");
395 OutType r =
static_cast<OutType
>(
hi);
396 r <<=
sizeof(InType) * CHAR_BIT;
397 r |=
static_cast<OutType
>(lo);
403template<std::
signed_
integral OutType, std::
signed_
integral InType>
404[[nodiscard]]
constexpr OutType merge_bit_cast(InType
hi, InType lo)
noexcept
406 using UInType = std::make_unsigned_t<InType>;
407 using UOutType = std::make_unsigned_t<OutType>;
408 return static_cast<OutType
>(merge_bit_cast<UOutType>(
static_cast<UInType
>(
hi),
static_cast<UInType
>(lo)));
413template<std::
signed_
integral OutType, std::
unsigned_
integral InType>
414[[nodiscard]]
constexpr OutType merge_bit_cast(InType
hi, InType lo)
noexcept
416 using UOutType = std::make_unsigned_t<OutType>;
417 return narrow_cast<OutType>(merge_bit_cast<UOutType>(
hi, lo));
420[[nodiscard]]
constexpr auto to_underlying(scoped_enum
auto rhs)
noexcept
422 return static_cast<std::underlying_type_t<decltype(rhs)
>>(rhs);
426[[nodiscard]]
constexpr bool to_bool(T&& rhs)
noexcept
427 requires(
requires(T&& x) {
static_cast<bool>(std::forward<T>(x)); })
429 return static_cast<bool>(std::forward<T>(rhs));
434 requires std::is_pointer_v<T>
436 return reinterpret_cast<T
>(value);
445template<
typename T,
byte_like Byte>
446[[nodiscard]] copy_cv_t<T, Byte>& implicit_cast(std::span<Byte> bytes)
448 using value_type = copy_cv_t<T, Byte>;
450 static_assert(std::is_trivially_default_constructible_v<value_type>);
451 static_assert(std::is_trivially_destructible_v<value_type>);
453 if (
sizeof(value_type) > bytes.size()) {
458 if constexpr (
alignof(value_type) != 1) {
459 if (std::bit_cast<std::uintptr_t>(bytes.data()) %
alignof(value_type) != 0) {
464 return *
reinterpret_cast<value_type *
>(bytes.data());
467template<
typename T,
byte_like Byte>
468[[nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(std::span<Byte> bytes,
size_t n)
470 using value_type = copy_cv_t<T, Byte>;
472 static_assert(std::is_trivially_default_constructible_v<value_type>);
473 static_assert(std::is_trivially_destructible_v<value_type>);
475 if (
sizeof(value_type) *
n > bytes.size()) {
480 if constexpr (
alignof(value_type) != 1) {
481 if (std::bit_cast<std::uintptr_t>(bytes.data()) %
alignof(value_type) != 0) {
486 return {
reinterpret_cast<value_type *
>(bytes.data()), n};
489template<
typename T,
byte_like Byte>
490[[nodiscard]] copy_cv_t<T, Byte>& implicit_cast(
size_t& offset, std::span<Byte> bytes)
492 using value_type = copy_cv_t<T, Byte>;
494 static_assert(std::is_trivially_default_constructible_v<value_type>);
495 static_assert(std::is_trivially_destructible_v<value_type>);
497 if (
sizeof(value_type) + offset > bytes.size()) {
502 hilet data = bytes.data() + offset;
504 if constexpr (
alignof(value_type) != 1) {
505 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
510 offset +=
sizeof(value_type);
511 return *
reinterpret_cast<value_type *
>(data);
514template<
typename T,
byte_like Byte>
515[[nodiscard]] std::span<copy_cv_t<T, Byte>> implicit_cast(
size_t& offset, std::span<Byte> bytes,
size_t n)
517 using value_type = copy_cv_t<T, Byte>;
519 static_assert(std::is_trivially_default_constructible_v<value_type>);
520 static_assert(std::is_trivially_destructible_v<value_type>);
522 if (
sizeof(value_type) *
n + offset > bytes.size()) {
527 hilet data = bytes.data() + offset;
529 if constexpr (
alignof(value_type) != 1) {
530 if (std::bit_cast<std::uintptr_t>(data) %
alignof(value_type) != 0) {
535 offset +=
sizeof(value_type) * n;
536 return {
reinterpret_cast<value_type *
>(data), n};
Utilities to assert and bound check.
#define hi_axiom(expression,...)
Specify an axiom; an expression that is true.
Definition assert.hpp:238
#define hi_axiom_not_null(expression,...)
Assert if an expression is not nullptr.
Definition assert.hpp:257
Safe numeric comparison between different types.
Utilities used by the HikoGUI library itself.
#define hilet
Invariant should be the default for variables.
Definition utility.hpp:23
@ truncate
After the file has been opened, truncate it.
DOXYGEN BUG.
Definition algorithm.hpp:13
geometry/margins.hpp
Definition cache.hpp:11
constexpr auto three_way_compare(Lhs const &lhs, Rhs const &rhs) noexcept
Safely compare two arithmetic values to each other.
Definition compare.hpp:123