Skip to content

Commit 7f8432c

Browse files
authored
Merge pull request #74 from saxbophone/josh/47-other-cast-operators
47 other cast operators
2 parents 627a981 + f7a0c40 commit 7f8432c

File tree

2 files changed

+66
-3
lines changed

2 files changed

+66
-3
lines changed

arby/include/arby/Nat.hpp

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -257,11 +257,43 @@ namespace com::saxbophone::arby {
257257
return this->_cast_to<uintmax_t>();
258258
}
259259
/**
260-
* @returns Value of this Nat object cast to long long double
260+
* @returns Value of this Nat object cast to long double
261261
*/
262262
explicit constexpr operator long double() const {
263263
return this->_cast_to<long double>();
264264
}
265+
/**
266+
* @returns Value of this Nat object cast to float
267+
*/
268+
explicit constexpr operator float() const {
269+
return this->_cast_to<float>();
270+
}
271+
/**
272+
* @returns Value of this Nat object cast to double
273+
*/
274+
explicit constexpr operator double() const {
275+
return this->_cast_to<double>();
276+
}
277+
/**
278+
* @returns Value of this Nat object cast to any numeric type
279+
* @tparam To The data type to cast to
280+
*/
281+
template <typename To>
282+
explicit constexpr operator To() const {
283+
// prevent overflow of To if it's a bounded type
284+
if constexpr (std::numeric_limits<To>::is_bounded) {
285+
if (*this > std::numeric_limits<To>::max()) {
286+
throw std::range_error("value too large for destination type");
287+
}
288+
}
289+
// take a short-cut if destination type is bounded and is not bigger than largest digit value
290+
if constexpr (std::numeric_limits<To>::is_bounded and std::numeric_limits<To>::max() <= (BASE - 1)) {
291+
// at this point, out-of-bounds has already been checked. Just return last digit
292+
return _digits.empty() ? (To)0 : (To)_digits.back();
293+
} else {
294+
return this->_cast_to<To>();
295+
}
296+
}
265297
/**
266298
* @brief custom ostream operator that allows class Nat to be printed
267299
* with std::cout and friends

tests/Nat/casting.cpp

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,41 @@ TEST_CASE("Casting arby::Nat with value higher than UINT_MAX to uintmax_t throws
2121
CHECK_THROWS_AS((uintmax_t)value, std::range_error);
2222
}
2323

24-
TEST_CASE("Casting arby::Nat to long double", "[casting]") {
24+
TEMPLATE_TEST_CASE("Casting arby::Nat to various floating-point types", "[casting]", float, double, long double) {
2525
auto value = GENERATE(take(1000, random((uintmax_t)0, std::numeric_limits<uintmax_t>::max())));
2626

27-
CHECK((long double)arby::Nat(value) == (long double)value);
27+
// float is so imprecise for large values that we need to cast the input too
28+
CHECK((TestType)arby::Nat::from_float((TestType)value) == (TestType)value);
29+
}
30+
31+
TEMPLATE_TEST_CASE(
32+
"Casting arby::Nat with value higher than max to other type throws range_error", "[casting]",
33+
std::uint8_t, std::int8_t, std::uint16_t, std::int16_t, std::uint32_t, std::int32_t
34+
) {
35+
arby::Nat value = arby::Nat((uintmax_t)std::numeric_limits<TestType>::max()) + 1;
36+
37+
CHECK_THROWS_AS((TestType)value, std::range_error);
38+
}
39+
40+
TEST_CASE("Casting arby::Nat to other type - uint8_t", "[casting]",) {
41+
auto value = GENERATE(take(1000, random((std::uint16_t)0, (std::uint16_t)std::numeric_limits<std::uint8_t>::max())));
42+
43+
CHECK((std::uint8_t)arby::Nat((uintmax_t)value) == (std::uint8_t)value);
44+
}
45+
46+
TEST_CASE("Casting arby::Nat to other type - int8_t", "[casting]",) {
47+
auto value = GENERATE(take(1000, random((std::int16_t)0, (std::int16_t)std::numeric_limits<std::int8_t>::max())));
48+
49+
CHECK((std::int8_t)arby::Nat((uintmax_t)value) == (std::int8_t)value);
50+
}
51+
52+
TEMPLATE_TEST_CASE(
53+
"Casting arby::Nat to other type", "[casting]",
54+
std::uint16_t, std::int16_t, std::uint32_t, std::int32_t
55+
) {
56+
auto value = GENERATE(take(1000, random((TestType)0, std::numeric_limits<TestType>::max())));
57+
58+
CHECK((TestType)arby::Nat((uintmax_t)value) == (TestType)value);
2859
}
2960

3061
TEST_CASE("arby::Nat::from_float() with negative value throws std::domain_error") {

0 commit comments

Comments
 (0)