Skip to content

Commit

Permalink
Better conversion to native types
Browse files Browse the repository at this point in the history
  • Loading branch information
chrysante committed Apr 3, 2023
1 parent f727f23 commit 7db02b4
Show file tree
Hide file tree
Showing 2 changed files with 34 additions and 11 deletions.
29 changes: 18 additions & 11 deletions include/APMath/APInt.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
#define APMATH_APINT_H_

#include <climits>
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <initializer_list>
Expand Down Expand Up @@ -254,29 +253,27 @@ class APInt {
std::span<Limb const> limbs() const { return { limbPtr(), numLimbs() }; }

/// Convert to native integral type
/// Truncates if `*this` is wider than `T`.
template <typename T>
T to() const {
static_assert(std::is_arithmetic_v<T>);
assert(bitwidth() <= sizeof(T) * CHAR_BIT);
return static_cast<T>(limbPtr()[0]);
}
typename std::enable_if<std::is_integral<T>::value, T>::type to() const;

/// Compute a 64 bit of of this integer.
/// Note that this is not a cryptographic hash.
/// Compute a 64 bit hash of this integer.
///
/// Note that this is meant for use with unordered containers and is not a cryptographic hash.
std::size_t hash() const;

/// Try to convert \p str to `APInt`
///
/// \param str All characters except ones representing digits in the
/// specified base and an initial '-' are ignored. Result is exactly as wide
/// as necessary to represent the parsed integer.
/// specified base and an initial '-' are ignored.
///
/// \param base The base the number is represented in. Must be between 0 and
/// 36 (inclusive)
///
/// \param bitwidth The desired bitwidth of the result. A value of zero
/// means the result will be exactly as wide as required to represent the
/// number.
/// number. If a non-zero bitwidth is specified and the number does not fit,
/// `std::nullopt` is returned.
static std::optional<APInt> parse(std::string_view str,
int base = 10,
size_t bitwidth = 0);
Expand Down Expand Up @@ -333,6 +330,16 @@ class APInt {

} // namespace APMath

template <typename T>
typename std::enable_if<std::is_integral<T>::value, T>::type
APMath::APInt::to() const {
T result;
std::size_t const numBytes = std::min(numLimbs() * sizeof(Limb),
sizeof(T));
std::memcpy(&result, limbPtr(), numBytes);
return result;
}

inline std::size_t APMath::internal::ceilDiv(std::size_t a, std::size_t b) {
return a / b + !!(a % b);
}
Expand Down
16 changes: 16 additions & 0 deletions test/APInt.t.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -405,3 +405,19 @@ TEST_CASE("String parse - 2") {
auto b = APInt::parse("-127", 10, 8).value();
CHECK(b == 129); // 129 == -127 in 8 bit two's complement
}

TEST_CASE("Conversion to native") {
APInt a(-123, 32);
CHECK(a.to<int32_t>() == -123);
APInt b(1024 + 255, 8);
CHECK(b.to<int32_t>() == 255);
APInt c = APInt::parse("1 0000 0000 0000 0123", 16, 128).value();
CHECK(c.to<int64_t>() == 0x123);
#ifdef __SIZEOF_INT128__
CHECK(c.to<__uint128_t>() - 0x124 == ~uint64_t(0));
#endif
APInt d(0x1'0000'0123, 64);
CHECK(d.to<int32_t>() == 0x123);
APInt e(0x1'0000'0123, 32);
CHECK(e.to<int64_t>() == 0x123);
}

0 comments on commit 7db02b4

Please sign in to comment.