17[[nodiscard]]
constexpr T
copy(T value)
noexcept
22template<std::
signed_
integral OutType, std::
floating_po
int InType>
23[[nodiscard]]
constexpr OutType narrow_cast(InType value)
noexcept
26 return static_cast<OutType
>(value);
29template<std::
signed_
integral OutType, std::
signed_
integral InType>
30[[nodiscard]]
constexpr OutType narrow_cast(InType value)
noexcept
34 tt_axiom(value >= smin && value <= smax);
35 return static_cast<OutType
>(value);
38template<std::
signed_
integral OutType, std::
unsigned_
integral InType>
39[[nodiscard]]
constexpr OutType narrow_cast(InType value)
noexcept
42 tt_axiom(value <= umax);
43 return static_cast<OutType
>(value);
46template<std::
unsigned_
integral OutType, std::
floating_po
int InType>
47[[nodiscard]]
constexpr OutType narrow_cast(InType value)
noexcept
49 tt_axiom(value >= InType{0});
51 return static_cast<OutType
>(value);
54template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
55[[nodiscard]]
constexpr OutType narrow_cast(InType value)
noexcept
57 tt_axiom(value >= InType{0});
58 if constexpr (
sizeof(OutType) <
sizeof(InType)) {
60 tt_axiom(value <= smax);
62 return static_cast<OutType
>(value);
65template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
66[[nodiscard]]
constexpr OutType narrow_cast(InType value)
noexcept
69 tt_axiom(value <= umax);
70 return static_cast<OutType
>(value);
73template<std::
floating_po
int OutType, tt::arithmetic InType>
74[[nodiscard]]
constexpr OutType narrow_cast(InType value)
noexcept
76 return static_cast<OutType
>(value);
79template<tt::lvalue_reference BaseType, tt::derived_from<std::remove_reference_t<BaseType>> DerivedType>
80[[nodiscard]]
constexpr BaseType narrow_cast(DerivedType &value)
noexcept
83 !std::is_const_v<DerivedType> || std::is_const_v<std::remove_reference_t<BaseType>>,
84 "narrow_cast must not cast away const");
85 return static_cast<BaseType
>(value);
88template<tt::lvalue_reference DerivedType, tt::strict_base_of<std::remove_reference_t<DerivedType>> BaseType>
89[[nodiscard]]
constexpr DerivedType narrow_cast(BaseType &value)
noexcept
92 !std::is_const_v<BaseType> || std::is_const_v<std::remove_reference_t<DerivedType>>,
93 "narrow_cast must not cast away const");
94 tt_axiom(
dynamic_cast<std::remove_reference_t<DerivedType> *
>(&value) !=
nullptr);
95 return static_cast<DerivedType
>(value);
98template<tt::po
inter BaseType, tt::derived_from<std::remove_po
inter_t<BaseType>> DerivedType>
99[[nodiscard]]
constexpr BaseType narrow_cast(DerivedType *value)
noexcept
102 !std::is_const_v<DerivedType> || std::is_const_v<std::remove_pointer_t<BaseType>>,
103 "narrow_cast must not cast away const");
104 return static_cast<BaseType
>(value);
107template<tt::po
inter DerivedType, tt::strict_base_of<std::remove_po
inter_t<DerivedType>> BaseType>
108[[nodiscard]]
constexpr DerivedType narrow_cast(BaseType *value)
noexcept
111 !std::is_const_v<BaseType> || std::is_const_v<std::remove_pointer_t<DerivedType>>,
112 "narrow_cast must not cast away const");
113 tt_axiom(
dynamic_cast<DerivedType
>(value) !=
nullptr);
114 return static_cast<DerivedType
>(value);
119template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
120[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
122 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of low_bit_cast must be half the size of the input");
123 return static_cast<OutType
>(value);
128template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
129[[nodiscard]]
constexpr OutType high_bit_cast(InType value)
noexcept
131 static_assert(
sizeof(OutType) * 2 ==
sizeof(InType),
"Return value of high_bit_cast must be half the size of the input");
132 return static_cast<OutType
>(value >>
sizeof(OutType) * CHAR_BIT);
137template<std::
signed_
integral OutType, std::
signed_
integral InType>
138[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
140 using UInType = std::make_unsigned_t<InType>;
141 using UOutType = std::make_unsigned_t<OutType>;
142 return static_cast<OutType
>(low_bit_cast<UOutType>(
static_cast<UInType
>(value)));
147template<std::
signed_
integral OutType, std::
signed_
integral InType>
148[[nodiscard]]
constexpr OutType high_bit_cast(InType value)
noexcept
150 using UInType = std::make_unsigned_t<InType>;
151 using UOutType = std::make_unsigned_t<OutType>;
152 return static_cast<OutType
>(high_bit_cast<UOutType>(
static_cast<UInType
>(value)));
157template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
158[[nodiscard]]
constexpr OutType low_bit_cast(InType value)
noexcept
160 using UInType = std::make_unsigned_t<InType>;
161 return low_bit_cast<OutType>(
static_cast<UInType
>(value));
166template<std::
unsigned_
integral OutType, std::
signed_
integral InType>
167[[nodiscard]]
constexpr OutType high_bit_cast(InType value)
noexcept
169 using UInType = std::make_unsigned_t<InType>;
170 return high_bit_cast<OutType>(
static_cast<UInType
>(value));
175template<std::
unsigned_
integral OutType, std::
unsigned_
integral InType>
176[[nodiscard]]
constexpr OutType merge_bit_cast(InType hi, InType lo)
noexcept
178 static_assert(
sizeof(OutType) ==
sizeof(InType) * 2,
"Return value of merge_bit_cast must be double the size of the input");
180 OutType r =
static_cast<OutType
>(hi);
181 r <<=
sizeof(InType) * CHAR_BIT;
182 r |=
static_cast<OutType
>(lo);
188template<std::
signed_
integral OutType, std::
signed_
integral InType>
189[[nodiscard]]
constexpr OutType merge_bit_cast(InType hi, InType lo)
noexcept
191 using UInType = std::make_unsigned_t<InType>;
192 using UOutType = std::make_unsigned_t<OutType>;
193 return static_cast<OutType
>(merge_bit_cast<UOutType>(
static_cast<UInType
>(hi),
static_cast<UInType
>(lo)));
198template<std::
signed_
integral OutType, std::
unsigned_
integral InType>
199[[nodiscard]]
constexpr OutType merge_bit_cast(InType hi, InType lo)
noexcept
201 using UOutType = std::make_unsigned_t<OutType>;
202 return narrow_cast<OutType>(merge_bit_cast<UOutType>(hi, lo));