mirror of
https://github.com/XRPLF/rippled.git
synced 2025-11-20 19:15:54 +00:00
Rewrite Units.h and same safe_cast.h restrictions to use concepts
This commit is contained in:
@@ -28,9 +28,8 @@ namespace ripple {
|
|||||||
// the destination can hold all values of the source. This is particularly
|
// the destination can hold all values of the source. This is particularly
|
||||||
// handy when the source or destination is an enumeration type.
|
// handy when the source or destination is an enumeration type.
|
||||||
|
|
||||||
template <class Dest, class Src>
|
template <class Src, class Dest>
|
||||||
static constexpr bool is_safetocasttovalue_v =
|
concept SafeToCast = (std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
|
||||||
(std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
|
|
||||||
(std::is_signed<Src>::value || std::is_unsigned<Dest>::value) &&
|
(std::is_signed<Src>::value || std::is_unsigned<Dest>::value) &&
|
||||||
(std::is_signed<Src>::value != std::is_signed<Dest>::value
|
(std::is_signed<Src>::value != std::is_signed<Dest>::value
|
||||||
? sizeof(Dest) > sizeof(Src)
|
? sizeof(Dest) > sizeof(Src)
|
||||||
@@ -78,7 +77,7 @@ inline constexpr std::
|
|||||||
unsafe_cast(Src s) noexcept
|
unsafe_cast(Src s) noexcept
|
||||||
{
|
{
|
||||||
static_assert(
|
static_assert(
|
||||||
!is_safetocasttovalue_v<Dest, Src>,
|
!SafeToCast<Src, Dest>,
|
||||||
"Only unsafe if casting signed to unsigned or "
|
"Only unsafe if casting signed to unsigned or "
|
||||||
"destination is too small");
|
"destination is too small");
|
||||||
return static_cast<Dest>(s);
|
return static_cast<Dest>(s);
|
||||||
|
|||||||
@@ -50,25 +50,32 @@ struct unitlessTag;
|
|||||||
class BipsTag;
|
class BipsTag;
|
||||||
class TenthBipsTag;
|
class TenthBipsTag;
|
||||||
|
|
||||||
template <class T>
|
// These names don't have to be too descriptive, because we're in the "unit"
|
||||||
using enable_if_unit_t = typename std::enable_if_t<
|
// namespace.
|
||||||
std::is_class_v<T> && std::is_object_v<typename T::unit_type> &&
|
|
||||||
std::is_object_v<typename T::value_type>>;
|
|
||||||
|
|
||||||
/** `is_usable_unit_v` is checked to ensure that only values with
|
template <class T>
|
||||||
|
concept Valid = std::is_class_v<T> && std::is_object_v<typename T::unit_type> &&
|
||||||
|
std::is_object_v<typename T::value_type>;
|
||||||
|
|
||||||
|
/** `Usable` is checked to ensure that only values with
|
||||||
known valid type tags can be used (sometimes transparently) in
|
known valid type tags can be used (sometimes transparently) in
|
||||||
non-unit contexts. At the time of implementation, this includes
|
non-unit contexts. At the time of implementation, this includes
|
||||||
all known tags, but more may be added in the future, and they
|
all known tags, but more may be added in the future, and they
|
||||||
should not be added automatically unless determined to be
|
should not be added automatically unless determined to be
|
||||||
appropriate.
|
appropriate.
|
||||||
*/
|
*/
|
||||||
template <class T, class = enable_if_unit_t<T>>
|
template <class T>
|
||||||
constexpr bool is_usable_unit_v =
|
concept Usable = Valid<T> &&
|
||||||
std::is_same_v<typename T::unit_type, feelevelTag> ||
|
(std::is_same_v<typename T::unit_type, feelevelTag> ||
|
||||||
std::is_same_v<typename T::unit_type, unitlessTag> ||
|
std::is_same_v<typename T::unit_type, unitlessTag> ||
|
||||||
std::is_same_v<typename T::unit_type, dropTag> ||
|
std::is_same_v<typename T::unit_type, dropTag> ||
|
||||||
std::is_same_v<typename T::unit_type, BipsTag> ||
|
std::is_same_v<typename T::unit_type, BipsTag> ||
|
||||||
std::is_same_v<typename T::unit_type, TenthBipsTag>;
|
std::is_same_v<typename T::unit_type, TenthBipsTag>);
|
||||||
|
|
||||||
|
template <class Other, class VU>
|
||||||
|
concept Compatible = Valid<VU> && std::is_arithmetic_v<Other> &&
|
||||||
|
std::is_arithmetic_v<typename VU::value_type> &&
|
||||||
|
std::is_convertible_v<Other, typename VU::value_type>;
|
||||||
|
|
||||||
template <class UnitTag, class T>
|
template <class UnitTag, class T>
|
||||||
class ValueUnit : private boost::totally_ordered<ValueUnit<UnitTag, T>>,
|
class ValueUnit : private boost::totally_ordered<ValueUnit<UnitTag, T>>,
|
||||||
@@ -85,25 +92,6 @@ public:
|
|||||||
private:
|
private:
|
||||||
value_type value_;
|
value_type value_;
|
||||||
|
|
||||||
protected:
|
|
||||||
template <class Other>
|
|
||||||
static constexpr bool is_compatible_v =
|
|
||||||
std::is_arithmetic_v<Other> && std::is_arithmetic_v<value_type> &&
|
|
||||||
std::is_convertible_v<Other, value_type>;
|
|
||||||
|
|
||||||
template <class OtherValue, class = enable_if_unit_t<OtherValue>>
|
|
||||||
static constexpr bool is_compatiblevalue_v =
|
|
||||||
is_compatible_v<typename OtherValue::value_type> &&
|
|
||||||
std::is_same_v<UnitTag, typename OtherValue::unit_type>;
|
|
||||||
|
|
||||||
template <class Other>
|
|
||||||
using enable_if_compatible_t =
|
|
||||||
typename std::enable_if_t<is_compatible_v<Other>>;
|
|
||||||
|
|
||||||
template <class OtherValue>
|
|
||||||
using enable_if_compatiblevalue_t =
|
|
||||||
typename std::enable_if_t<is_compatiblevalue_v<OtherValue>>;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ValueUnit() = default;
|
ValueUnit() = default;
|
||||||
constexpr ValueUnit(ValueUnit const& other) = default;
|
constexpr ValueUnit(ValueUnit const& other) = default;
|
||||||
@@ -135,12 +123,9 @@ public:
|
|||||||
/** Instances with the same unit, and a type that is
|
/** Instances with the same unit, and a type that is
|
||||||
"safe" to convert to this one can be converted
|
"safe" to convert to this one can be converted
|
||||||
implicitly */
|
implicitly */
|
||||||
template <
|
template <Compatible<ValueUnit> Other>
|
||||||
class Other,
|
|
||||||
class = std::enable_if_t<
|
|
||||||
is_compatible_v<Other> &&
|
|
||||||
is_safetocasttovalue_v<value_type, Other>>>
|
|
||||||
constexpr ValueUnit(ValueUnit<unit_type, Other> const& value)
|
constexpr ValueUnit(ValueUnit<unit_type, Other> const& value)
|
||||||
|
requires SafeToCast<Other, value_type>
|
||||||
: ValueUnit(safe_cast<value_type>(value.value()))
|
: ValueUnit(safe_cast<value_type>(value.value()))
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
@@ -255,7 +240,7 @@ public:
|
|||||||
return value_ == other.value_;
|
return value_ == other.value_;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Other, class = enable_if_compatible_t<Other>>
|
template <Compatible<ValueUnit> Other>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
operator==(ValueUnit<unit_type, Other> const& other) const
|
operator==(ValueUnit<unit_type, Other> const& other) const
|
||||||
{
|
{
|
||||||
@@ -268,7 +253,7 @@ public:
|
|||||||
return value_ == other;
|
return value_ == other;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Other, class = enable_if_compatible_t<Other>>
|
template <Compatible<ValueUnit> Other>
|
||||||
constexpr bool
|
constexpr bool
|
||||||
operator!=(ValueUnit<unit_type, Other> const& other) const
|
operator!=(ValueUnit<unit_type, Other> const& other) const
|
||||||
{
|
{
|
||||||
@@ -310,12 +295,13 @@ public:
|
|||||||
return static_cast<double>(value_) / reference.value();
|
return static_cast<double>(value_) / reference.value();
|
||||||
}
|
}
|
||||||
|
|
||||||
// `is_usable_unit_v` is checked to ensure that only values with
|
// `Usable` is checked to ensure that only values with
|
||||||
// known valid type tags can be converted to JSON. At the time
|
// known valid type tags can be converted to JSON. At the time
|
||||||
// of implementation, that includes all known tags, but more may
|
// of implementation, that includes all known tags, but more may
|
||||||
// be added in the future.
|
// be added in the future.
|
||||||
std::enable_if_t<is_usable_unit_v<ValueUnit>, Json::Value>
|
Json::Value
|
||||||
jsonClipped() const
|
jsonClipped() const
|
||||||
|
requires Usable<ValueUnit>
|
||||||
{
|
{
|
||||||
if constexpr (std::is_integral_v<value_type>)
|
if constexpr (std::is_integral_v<value_type>)
|
||||||
{
|
{
|
||||||
@@ -372,43 +358,27 @@ to_string(ValueUnit<UnitTag, T> const& amount)
|
|||||||
return std::to_string(amount.value());
|
return std::to_string(amount.value());
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Source, class = enable_if_unit_t<Source>>
|
template <Valid Source>
|
||||||
constexpr bool can_muldiv_source_v =
|
constexpr bool can_muldiv_source_v =
|
||||||
std::is_convertible_v<typename Source::value_type, std::uint64_t>;
|
std::is_convertible_v<typename Source::value_type, std::uint64_t>;
|
||||||
|
|
||||||
template <class Dest, class = enable_if_unit_t<Dest>>
|
template <Valid Dest>
|
||||||
constexpr bool can_muldiv_dest_v =
|
constexpr bool can_muldiv_dest_v =
|
||||||
can_muldiv_source_v<Dest> && // Dest is also a source
|
can_muldiv_source_v<Dest> && // Dest is also a source
|
||||||
std::is_convertible_v<std::uint64_t, typename Dest::value_type> &&
|
std::is_convertible_v<std::uint64_t, typename Dest::value_type> &&
|
||||||
sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
|
sizeof(typename Dest::value_type) >= sizeof(std::uint64_t);
|
||||||
|
|
||||||
template <
|
template <Valid Source1, Valid Source2>
|
||||||
class Source1,
|
|
||||||
class Source2,
|
|
||||||
class = enable_if_unit_t<Source1>,
|
|
||||||
class = enable_if_unit_t<Source2>>
|
|
||||||
constexpr bool can_muldiv_sources_v =
|
constexpr bool can_muldiv_sources_v =
|
||||||
can_muldiv_source_v<Source1> && can_muldiv_source_v<Source2> &&
|
can_muldiv_source_v<Source1> && can_muldiv_source_v<Source2> &&
|
||||||
std::is_same_v<typename Source1::unit_type, typename Source2::unit_type>;
|
std::is_same_v<typename Source1::unit_type, typename Source2::unit_type>;
|
||||||
|
|
||||||
template <
|
template <Valid Source1, Valid Source2, Valid Dest>
|
||||||
class Source1,
|
|
||||||
class Source2,
|
|
||||||
class Dest,
|
|
||||||
class = enable_if_unit_t<Source1>,
|
|
||||||
class = enable_if_unit_t<Source2>,
|
|
||||||
class = enable_if_unit_t<Dest>>
|
|
||||||
constexpr bool can_muldiv_v =
|
constexpr bool can_muldiv_v =
|
||||||
can_muldiv_sources_v<Source1, Source2> && can_muldiv_dest_v<Dest>;
|
can_muldiv_sources_v<Source1, Source2> && can_muldiv_dest_v<Dest>;
|
||||||
// Source and Dest can be the same by default
|
// Source and Dest can be the same by default
|
||||||
|
|
||||||
template <
|
template <Valid Source1, Valid Source2, Valid Dest>
|
||||||
class Source1,
|
|
||||||
class Source2,
|
|
||||||
class Dest,
|
|
||||||
class = enable_if_unit_t<Source1>,
|
|
||||||
class = enable_if_unit_t<Source2>,
|
|
||||||
class = enable_if_unit_t<Dest>>
|
|
||||||
constexpr bool can_muldiv_commute_v = can_muldiv_v<Source1, Source2, Dest> &&
|
constexpr bool can_muldiv_commute_v = can_muldiv_v<Source1, Source2, Dest> &&
|
||||||
!std::is_same_v<typename Source1::unit_type, typename Dest::unit_type>;
|
!std::is_same_v<typename Source1::unit_type, typename Dest::unit_type>;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user