Skip to content

Commit e6d7a00

Browse files
committed
Add to_integer and to_floating casts.
1 parent 6a36249 commit e6d7a00

File tree

7 files changed

+92
-1
lines changed

7 files changed

+92
-1
lines changed

include/bitcoin/system/constraints.hpp

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -216,7 +216,7 @@ using if_integral_integer = bool_if<
216216

217217
template <typename Type>
218218
using if_non_integral_integer = bool_if<
219-
!is_integral<Type> &&
219+
!is_integral<Type> &&
220220
is_integer<Type>>;
221221

222222
template <typename Type>
@@ -251,6 +251,10 @@ using if_little_endian_integral_integer = bool_if<
251251
is_integral_integer<Integer> &&
252252
is_little_endian>;
253253

254+
template <typename Integer>
255+
using if_floating_point = bool_if<
256+
is_floating_point<Integer>>;
257+
254258
/// std::array/std::vector
255259

256260
template <typename Type>

include/bitcoin/system/impl/math/cast.ipp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,31 @@ constexpr Unsigned to_unsigned(Unsigned value) NOEXCEPT
206206
return value;
207207
}
208208

209+
// Floating point casts.
210+
// ----------------------------------------------------------------------------
211+
212+
template <typename Integer, typename Float,
213+
if_integral_integer<Integer>,
214+
if_floating_point<Float>>
215+
constexpr Integer to_integer(Float value) NOEXCEPT
216+
{
217+
// Floating point conversion in c++ requires explicit or implicit cast.
218+
BC_PUSH_WARNING(NO_CASTS_FOR_ARITHMETIC_CONVERSION)
219+
return static_cast<Integer>(value);
220+
BC_POP_WARNING()
221+
}
222+
223+
template <typename Float, typename Integer,
224+
if_floating_point<Float>,
225+
if_integral_integer<Integer>>
226+
constexpr Float to_floating(Integer value) NOEXCEPT
227+
{
228+
// Floating point conversion in c++ requires explicit or implicit cast.
229+
BC_PUSH_WARNING(NO_CASTS_FOR_ARITHMETIC_CONVERSION)
230+
return static_cast<Float>(value);
231+
BC_POP_WARNING()
232+
}
233+
209234
} // namespace system
210235
} // namespace libbitcoin
211236

include/bitcoin/system/math/cast.hpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,21 @@ constexpr to_unsigned_type<Signed> to_unsigned(Signed value) NOEXCEPT;
139139
template <typename Unsigned, if_unsigned_integer<Unsigned> = true>
140140
constexpr Unsigned to_unsigned(Unsigned value) NOEXCEPT;
141141

142+
/// Floating point casts.
143+
/// ---------------------------------------------------------------------------
144+
145+
/// Cast floating point to integral integer, overflow unguarded.
146+
template <typename Integer = size_t, typename Float,
147+
if_integral_integer<Integer> = true,
148+
if_floating_point<Float> = true>
149+
constexpr Integer to_integer(Float value) NOEXCEPT;
150+
151+
/// Cast integral integer to floating point, overflow unguarded.
152+
template <typename Float = double, typename Integer,
153+
if_floating_point<Float> = true,
154+
if_integral_integer<Integer> = true>
155+
constexpr Float to_floating(Integer value) NOEXCEPT;
156+
142157
} // namespace system
143158
} // namespace libbitcoin
144159

include/bitcoin/system/typelets.hpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,11 @@ constexpr bool is_integer = std::numeric_limits<std::decay_t<Type>>::is_integer
7474
template <typename Type>
7575
constexpr bool is_integral_integer = is_integral<Type> /*&& is_integer<Type>*/;
7676

77+
/// numeric_limits may be specialized by non-integrals (such as uintx).
78+
template <typename Type>
79+
constexpr bool is_floating_point =
80+
std::is_floating_point_v<std::decay_t<Type>>;
81+
7782
/// Constrained to is_integral types.
7883
template <typename Type, std::enable_if_t<is_integral_size<Type>, bool> = true>
7984
constexpr size_t bits = to_bits(sizeof(Type));

test/constraints.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -622,6 +622,13 @@ static_assert(is_defined<if_not_same_signed_integral_integer<int, size_t>>);
622622
////static_assert(is_defined<if_big_endian_integral_integer<uint8_t>>);
623623
////static_assert(is_defined<if_little_endian_integral_integer<uint8_t>>);
624624

625+
////static_assert(!is_defined<if_floating_point<int>>);
626+
////static_assert(!is_defined<if_floating_point<bool>>);
627+
static_assert(is_defined<if_floating_point<float>>);
628+
static_assert(is_defined<if_floating_point<const float>>);
629+
static_assert(is_defined<if_floating_point<double>>);
630+
static_assert(is_defined<if_floating_point<long double>>);
631+
625632
// std_array/std_vector
626633

627634
static_assert(is_defined<if_std_array<std_array<uint8_t, 0>>>);

test/math/cast.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,20 @@ static_assert(is_same_type<decltype(to_unsigned(0u)), unsigned>);
6262
static_assert(is_same_type<decltype(to_unsigned(1)), unsigned>);
6363
static_assert(is_same_type<decltype(to_unsigned(1u)), unsigned>);
6464

65+
static_assert(to_integer(1.0f) == 1_size);
66+
static_assert(to_integer<int>(1.0f) == 1u);
67+
static_assert(to_integer<unsigned>(2.0) == 2u);
68+
static_assert(is_same_type<decltype(to_integer(1.0f)), size_t>);
69+
static_assert(is_same_type<decltype(to_integer<int>(1.0f)), int>);
70+
static_assert(is_same_type<decltype(to_integer<unsigned>(1.0)), unsigned>);
71+
72+
static_assert(to_floating(1u) == 1.0);
73+
static_assert(to_floating<float>(1u) == 1.0f);
74+
static_assert(to_floating<double>(2u) == 2.0);
75+
static_assert(is_same_type<decltype(to_floating(1u)), double>);
76+
static_assert(is_same_type<decltype(to_floating<float>(1u)), float>);
77+
static_assert(is_same_type<decltype(to_floating<double>(2u)), double>);
78+
6579
// Verify compiler "usual arithmetic conversion" expectations.
6680
// ----------------------------------------------------------------------------
6781
// Shift works like a unary op (right operand is not incorporated).

test/typelets.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,27 @@ static_assert(!is_integral_integer<bool>);
209209
static_assert(!is_integral_integer<std::string>);
210210
static_assert(is_same_type<decltype(is_integral_integer<int32_t>), const bool>);
211211

212+
static_assert(!is_floating_point<uintx>);
213+
static_assert(!is_floating_point<uint128_t>);
214+
static_assert(!is_floating_point<uint8_t>);
215+
static_assert(!is_floating_point<uint16_t>);
216+
static_assert(!is_floating_point<uint32_t>);
217+
static_assert(!is_floating_point<uint64_t>);
218+
static_assert(!is_floating_point<size_t>);
219+
static_assert(!is_floating_point<int8_t>);
220+
static_assert(!is_floating_point<int16_t>);
221+
static_assert(!is_floating_point<int32_t>);
222+
static_assert(!is_floating_point<int64_t>);
223+
static_assert(!is_floating_point<char>);
224+
static_assert(!is_floating_point<wchar_t>);
225+
static_assert(!is_floating_point<bool>);
226+
static_assert(!is_floating_point<std::string>);
227+
static_assert(is_floating_point<float>);
228+
static_assert(is_floating_point<const float>);
229+
static_assert(is_floating_point<double>);
230+
static_assert(is_floating_point<long double>);
231+
static_assert(is_same_type<decltype(is_floating_point<float>), const bool>);
232+
212233
// These may be unexpected, which is why we generally avoid them.
213234
static_assert(sizeof(bool) >= 1u);
214235
////static_assert(bits<bool> >= 1u);

0 commit comments

Comments
 (0)