From 27259f8ebad5e3372db5c4d8cb35b522e43fe28f Mon Sep 17 00:00:00 2001 From: Hudd <haddayn@gmail.com> Date: Mon, 11 Mar 2024 21:35:51 +0400 Subject: [PATCH] types: add narrow_cast --- types/include/aw/types/support/narrow.h | 54 +++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 types/include/aw/types/support/narrow.h diff --git a/types/include/aw/types/support/narrow.h b/types/include/aw/types/support/narrow.h new file mode 100644 index 00000000..7ca61b29 --- /dev/null +++ b/types/include/aw/types/support/narrow.h @@ -0,0 +1,54 @@ +#ifndef aw_types_support_narrow_h +#define aw_types_support_narrow_h + +#include <type_traits> +#include <utility> +#include <cassert> + +namespace aw { +/*! + * Narrowing cast. + * Identical to static_cast but makes it easier to grep the code. + */ +template <typename To, typename From> +constexpr To narrow_cast(From&& from) noexcept +{ + return static_cast<To>(std::forward<From>(from)); +} + +template <typename T, typename U> +constexpr bool same_sign(const T& t, const U& u) +{ + return (t < T{}) == (u < U{}); +} + +/*! + * Checked narrowing cast. Inspired by GSL. + */ +template <class To, class From> + requires std::is_arithmetic_v<To> +constexpr To narrow(From from) +{ + auto to = narrow_cast<To>(from); + + assert(static_cast<From>(to) == from); + + if constexpr(std::is_signed_v<To> != std::is_signed_v<From>) + assert(same_sign(to, from)); + + return to; +} + +template <class To, class From> + requires (!std::is_arithmetic_v<To>) +constexpr To narrow(From from) +{ + auto to = narrow_cast<To>(from); + + assert(static_cast<From>(to) == from); + + return to; +} +} // namespace aw + +#endif // aw_types_support_narrow_h