cxxrtl: implement `value.get()` and `value.set()` for signed types.

This commit is contained in:
Catherine 2024-01-05 21:31:08 +00:00
parent 22370ad21e
commit 5aaf1f1d39
1 changed files with 22 additions and 4 deletions

View File

@ -28,6 +28,7 @@
#include <cstddef> #include <cstddef>
#include <cstdint> #include <cstdint>
#include <cstring>
#include <cassert> #include <cassert>
#include <limits> #include <limits>
#include <type_traits> #include <type_traits>
@ -145,7 +146,7 @@ struct value : public expr_base<value<Bits>> {
// These functions ensure that a conversion is never out of range, and should be always used, if at all // These functions ensure that a conversion is never out of range, and should be always used, if at all
// possible, instead of direct manipulation of the `data` member. For very large types, .slice() and // possible, instead of direct manipulation of the `data` member. For very large types, .slice() and
// .concat() can be used to split them into more manageable parts. // .concat() can be used to split them into more manageable parts.
template<class IntegerT> template<class IntegerT, typename std::enable_if<!std::is_signed<IntegerT>::value, int>::type = 0>
CXXRTL_ALWAYS_INLINE CXXRTL_ALWAYS_INLINE
IntegerT get() const { IntegerT get() const {
static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed, static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed,
@ -158,15 +159,32 @@ struct value : public expr_base<value<Bits>> {
return result; return result;
} }
template<class IntegerT> template<class IntegerT, typename std::enable_if<std::is_signed<IntegerT>::value, int>::type = 0>
CXXRTL_ALWAYS_INLINE CXXRTL_ALWAYS_INLINE
void set(IntegerT other) { IntegerT get() const {
auto unsigned_result = get<typename std::make_unsigned<IntegerT>::type>();
IntegerT result;
memcpy(&result, &unsigned_result, sizeof(IntegerT));
return result;
}
template<class IntegerT, typename std::enable_if<!std::is_signed<IntegerT>::value, int>::type = 0>
CXXRTL_ALWAYS_INLINE
void set(IntegerT value) {
static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed, static_assert(std::numeric_limits<IntegerT>::is_integer && !std::numeric_limits<IntegerT>::is_signed,
"set<T>() requires T to be an unsigned integral type"); "set<T>() requires T to be an unsigned integral type");
static_assert(std::numeric_limits<IntegerT>::digits >= Bits, static_assert(std::numeric_limits<IntegerT>::digits >= Bits,
"set<T>() requires the value to be at least as wide as T is"); "set<T>() requires the value to be at least as wide as T is");
for (size_t n = 0; n < chunks; n++) for (size_t n = 0; n < chunks; n++)
data[n] = (other >> (n * chunk::bits)) & chunk::mask; data[n] = (value >> (n * chunk::bits)) & chunk::mask;
}
template<class IntegerT, typename std::enable_if<std::is_signed<IntegerT>::value, int>::type = 0>
CXXRTL_ALWAYS_INLINE
void set(IntegerT value) {
typename std::make_unsigned<IntegerT>::type unsigned_value;
memcpy(&unsigned_value, &value, sizeof(IntegerT));
set(unsigned_value);
} }
// Operations with compile-time parameters. // Operations with compile-time parameters.