From d9f77a3fdc744e7434a10bcb7c449cb4040afebe Mon Sep 17 00:00:00 2001 From: Gregory Tsipenyuk Date: Mon, 5 Aug 2024 11:36:51 -0400 Subject: [PATCH] Add TypedFieldAmount to declare Amount fields. Remove VT template parameter. Deduce value type from ValueType alias. --- include/xrpl/protocol/SField.h | 57 +++-- include/xrpl/protocol/SOTemplate.h | 11 +- include/xrpl/protocol/STObject.h | 338 +++++++++++++++-------------- src/libxrpl/protocol/SField.cpp | 14 +- src/libxrpl/protocol/STObject.cpp | 3 +- 5 files changed, 234 insertions(+), 189 deletions(-) diff --git a/include/xrpl/protocol/SField.h b/include/xrpl/protocol/SField.h index 1c34a9b8438..4483f6bf3b4 100644 --- a/include/xrpl/protocol/SField.h +++ b/include/xrpl/protocol/SField.h @@ -304,15 +304,8 @@ class SField enum class SFieldMPT { None, Yes, No }; -// clang-format off -template -concept ValidFields = (std::is_same_v && - (F == SFieldMPT::No || F == SFieldMPT::Yes)) || - (!std::is_same_v && F == SFieldMPT::None); - /** A field with a type known at compile time. */ -template - requires ValidFields +template struct TypedField : SField { using type = T; @@ -322,25 +315,49 @@ struct TypedField : SField }; /** Indicate std::optional field semantics. */ -template - requires ValidFields +template struct OptionaledField { - TypedField const* f; + TypedField const* f; + + explicit OptionaledField(TypedField const& f_) : f(&f_) + { + } +}; + +template +inline OptionaledField +operator~(TypedField const& f) +{ + return OptionaledField(f); +} + +// Amount fields + +/** A field with a type known at compile time. */ +template +struct TypedFieldAmount : public TypedField +{ + template + explicit TypedFieldAmount(private_access_tag_t pat, Args&&... args); +}; - explicit OptionaledField(TypedField const& f_) : f(&f_) +/** Indicate std::optional field semantics. */ +template +struct OptionaledFieldAmount : public OptionaledField +{ + explicit OptionaledFieldAmount(TypedFieldAmount const& f_) + : OptionaledField(f_) { } }; -template - requires ValidFields -inline OptionaledField -operator~(TypedField const& f) +template +inline OptionaledFieldAmount +operator~(TypedFieldAmount const& f) { - return OptionaledField(f); + return OptionaledFieldAmount(f); } -// clang-format on //------------------------------------------------------------------------------ @@ -359,8 +376,8 @@ using SF_UINT384 = TypedField>; using SF_UINT512 = TypedField>; using SF_ACCOUNT = TypedField; -using SF_AMOUNT = TypedField; -using SF_EITHER_AMOUNT = TypedField; +using SF_AMOUNT = TypedFieldAmount; +using SF_EITHER_AMOUNT = TypedFieldAmount; using SF_ISSUE = TypedField; using SF_CURRENCY = TypedField; using SF_VL = TypedField; diff --git a/include/xrpl/protocol/SOTemplate.h b/include/xrpl/protocol/SOTemplate.h index 2ea726c6e29..0ea420a483b 100644 --- a/include/xrpl/protocol/SOTemplate.h +++ b/include/xrpl/protocol/SOTemplate.h @@ -75,10 +75,15 @@ class SOElement { init(fieldName); } + SOElement(TypedFieldAmount const& fieldName, SOEStyle style) + : sField_(fieldName), style_(style), supportMpt_(soeMPTNotSupported) + { + init(fieldName); + } SOElement( - TypedField const& fieldName, + TypedFieldAmount const& fieldName, SOEStyle style, - SOETxMPTAmount supportMpt = SOETxMPTAmount::soeMPTNotSupported) + SOETxMPTAmount supportMpt = soeMPTNotSupported) : sField_(fieldName), style_(style), supportMpt_(supportMpt) { init(fieldName); @@ -99,7 +104,7 @@ class SOElement bool supportMPT() const { - return supportMpt_ == SOETxMPTAmount::soeMPTSupported; + return supportMpt_ == soeMPTSupported; } }; diff --git a/include/xrpl/protocol/STObject.h b/include/xrpl/protocol/STObject.h index 2a08447a91b..e2f9f32dc13 100644 --- a/include/xrpl/protocol/STObject.h +++ b/include/xrpl/protocol/STObject.h @@ -44,6 +44,9 @@ namespace ripple { +template +using ValueType = std::conditional::type; + class STArray; inline void @@ -55,11 +58,11 @@ throwFieldNotFound(SField const& field) class STObject : public STBase, public CountedObject { // Proxy value for a STBase derived class - template + template class Proxy; - template + template class ValueProxy; - template + template class OptionalProxy; struct Transform @@ -239,8 +242,7 @@ class STObject : public STBase, public CountedObject STEitherAmount const& getFieldAmount(SField const& field) const; STAmount const& - getFieldAmount( - TypedField const& field) const; + getFieldAmount(TypedFieldAmount const& field) const; STPathSet const& getFieldPathSet(SField const& field) const; const STVector256& @@ -257,14 +259,15 @@ class STObject : public STBase, public CountedObject @return The value of the specified field. @throws STObject::FieldErr if the field is not present. */ - template + template typename T::value_type - operator[](TypedField const& f) const; + operator[](TypedField const& f) const; - /** Overload for amount fields that don't support MPT + /** Overload for amount fields */ - STAmount - operator[](TypedField const& f) const; + template + typename ValueType::value_type + operator[](TypedFieldAmount const& f) const; /** Get the value of a field as a std::optional @@ -274,14 +277,16 @@ class STObject : public STBase, public CountedObject @return std::nullopt if the field is not present, else the value of the specified field. */ - template + template std::optional> - operator[](OptionaledField const& of) const; + operator[](OptionaledField const& of) const; - /** Overload for amount fields that don't support MPT + /** Overload for amount fields */ - std::optional - operator[](OptionaledField const& of) const; + template + std::optional< + std::decay_t::value_type>> + operator[](OptionaledFieldAmount const& of) const; /** Get a modifiable field value. @param A TypedField built from an SField value representing the desired @@ -290,14 +295,15 @@ class STObject : public STBase, public CountedObject @return A modifiable reference to the value of the specified field. @throws STObject::FieldErr if the field is not present. */ - template - ValueProxy - operator[](TypedField const& f); + template + ValueProxy + operator[](TypedField const& f); - /** Overload for amount fields that don't support MPT + /** Overload for amount fields */ - ValueProxy - operator[](TypedField const& f); + template + ValueProxy + operator[](TypedFieldAmount const& f); /** Return a modifiable field value as std::optional @@ -308,14 +314,15 @@ class STObject : public STBase, public CountedObject reference to the value of the specified field. Returns std::nullopt if the field is not present. */ - template - OptionalProxy - operator[](OptionaledField const& of); + template + OptionalProxy + operator[](OptionaledField const& of); - /** Overload for amount fields that don't support MPT + /** Overload for amount fields */ - OptionalProxy - operator[](OptionaledField const& of); + template + OptionalProxy + operator[](OptionaledFieldAmount const& of); /** Get the value of a field. @param A TypedField built from an SField value representing the desired @@ -324,14 +331,15 @@ class STObject : public STBase, public CountedObject @return The value of the specified field. @throws STObject::FieldErr if the field is not present. */ - template + template typename T::value_type - at(TypedField const& f) const; + at(TypedField const& f) const; - /** Overload for amount fields that don't support MPT + /** Overload for amount fields */ - STAmount - at(TypedField const& f) const; + template + typename ValueType::value_type + at(TypedFieldAmount const& f) const; /** Get the value of a field as std::optional @@ -341,14 +349,16 @@ class STObject : public STBase, public CountedObject @return std::nullopt if the field is not present, else the value of the specified field. */ - template + template std::optional> - at(OptionaledField const& of) const; + at(OptionaledField const& of) const; - /** Overload for amount fields that don't support MPT + /** Overload for amount fields */ - std::optional - at(OptionaledField const& of) const; + template + std::optional< + std::decay_t::value_type>> + at(OptionaledFieldAmount const& of) const; /** Get a modifiable field value. @param A TypedField built from an SField value representing the desired @@ -357,14 +367,15 @@ class STObject : public STBase, public CountedObject @return A modifiable reference to the value of the specified field. @throws STObject::FieldErr if the field is not present. */ - template - ValueProxy - at(TypedField const& f); + template + ValueProxy + at(TypedField const& f); /** Overload for amount fields that don't support MPT */ - ValueProxy - at(TypedField const& f); + template + ValueProxy + at(TypedFieldAmount const& f); /** Return a modifiable field value as std::optional @@ -375,14 +386,15 @@ class STObject : public STBase, public CountedObject reference to the value of the specified field. Returns std::nullopt if the field is not present. */ - template - OptionalProxy - at(OptionaledField const& of); + template + OptionalProxy + at(OptionaledField const& of); /** Overload for amount fields that don't support MPT */ - OptionalProxy - at(OptionaledField const& of); + template + OptionalProxy + at(OptionaledFieldAmount const& of); /** Set a field. if the field already exists, it is replaced. @@ -473,13 +485,13 @@ class STObject : public STBase, public CountedObject static std::vector getSortedFields(STObject const& objToSort, WhichFields whichFields); - template + template typename T::value_type - atImpl(TypedField const& f) const; + atImpl(TypedField const& f) const; - template + template std::optional> - atImpl(OptionaledField const& of) const; + atImpl(OptionaledField const& of) const; // Implementation for getting (most) fields that return by value. // @@ -527,19 +539,19 @@ class STObject : public STBase, public CountedObject //------------------------------------------------------------------------------ -template +template class STObject::Proxy { protected: - using value_type = VT; + using value_type = ValueType::value_type; STObject* st_; SOEStyle style_; - TypedField const* f_; + TypedField const* f_; Proxy(Proxy const&) = default; - Proxy(STObject* st, TypedField const* f); + Proxy(STObject* st, TypedField const* f); value_type value() const; @@ -552,11 +564,11 @@ class STObject::Proxy assign(U&& u); }; -template -class STObject::ValueProxy : private Proxy +template +class STObject::ValueProxy : private Proxy { private: - using value_type = VT; + using value_type = ValueType::value_type; public: ValueProxy(ValueProxy const&) = default; @@ -572,14 +584,14 @@ class STObject::ValueProxy : private Proxy private: friend class STObject; - ValueProxy(STObject* st, TypedField const* f); + ValueProxy(STObject* st, TypedField const* f); }; -template -class STObject::OptionalProxy : private Proxy +template +class STObject::OptionalProxy : private Proxy { private: - using value_type = VT; + using value_type = ValueType::value_type; using optional_type = std::optional::type>; @@ -694,7 +706,7 @@ class STObject::OptionalProxy : private Proxy private: friend class STObject; - OptionalProxy(STObject* st, TypedField const* f); + OptionalProxy(STObject* st, TypedField const* f); bool engaged() const noexcept; @@ -711,8 +723,8 @@ class STObject::FieldErr : public std::runtime_error using std::runtime_error::runtime_error; }; -template -STObject::Proxy::Proxy(STObject* st, TypedField const* f) +template +STObject::Proxy::Proxy(STObject* st, TypedField const* f) : st_(st), f_(f) { if (st_->mType) @@ -729,9 +741,9 @@ STObject::Proxy::Proxy(STObject* st, TypedField const* f) } } -template +template auto -STObject::Proxy::value() const -> value_type +STObject::Proxy::value() const -> value_type { auto const t = find(); if (t) @@ -750,8 +762,7 @@ STObject::Proxy::value() const -> value_type template <> inline auto -STObject::Proxy::value() const - -> STAmount +STObject::Proxy::value() const -> STAmount { auto const t = find(); if (t) @@ -768,17 +779,17 @@ STObject::Proxy::value() const return STAmount{}; } -template +template inline T const* -STObject::Proxy::find() const +STObject::Proxy::find() const { return dynamic_cast(st_->peekAtPField(*f_)); } -template +template template void -STObject::Proxy::assign(U&& u) +STObject::Proxy::assign(U&& u) { if (style_ == soeDEFAULT && u == value_type{}) { @@ -796,71 +807,68 @@ STObject::Proxy::assign(U&& u) //------------------------------------------------------------------------------ -template +template template -std::enable_if_t, STObject::ValueProxy&> -STObject::ValueProxy::operator=(U&& u) +std::enable_if_t, STObject::ValueProxy&> +STObject::ValueProxy::operator=(U&& u) { this->assign(std::forward(u)); return *this; } -template -STObject::ValueProxy::operator value_type() const +template +STObject::ValueProxy::operator value_type() const { return this->value(); } -template -STObject::ValueProxy::ValueProxy( - STObject* st, - TypedField const* f) - : Proxy(st, f) +template +STObject::ValueProxy::ValueProxy(STObject* st, TypedField const* f) + : Proxy(st, f) { } //------------------------------------------------------------------------------ -template -STObject::OptionalProxy::operator bool() const noexcept +template +STObject::OptionalProxy::operator bool() const noexcept { return engaged(); } -template +template auto -STObject::OptionalProxy::operator*() const -> value_type +STObject::OptionalProxy::operator*() const -> value_type { return this->value(); } -template -STObject::OptionalProxy::operator typename STObject:: - OptionalProxy::optional_type() const +template +STObject::OptionalProxy::operator typename STObject::OptionalProxy:: + optional_type() const { return optional_value(); } -template -typename STObject::OptionalProxy::optional_type -STObject::OptionalProxy::operator~() const +template +typename STObject::OptionalProxy::optional_type +STObject::OptionalProxy::operator~() const { return optional_value(); } -template +template auto -STObject::OptionalProxy::operator=(std::nullopt_t const&) +STObject::OptionalProxy::operator=(std::nullopt_t const&) -> OptionalProxy& { disengage(); return *this; } -template +template auto -STObject::OptionalProxy::operator=(optional_type&& v) - -> OptionalProxy& +STObject::OptionalProxy::operator=(optional_type&& v) -> OptionalProxy& { if (v) this->assign(std::move(*v)); @@ -869,9 +877,9 @@ STObject::OptionalProxy::operator=(optional_type&& v) return *this; } -template +template auto -STObject::OptionalProxy::operator=(optional_type const& v) +STObject::OptionalProxy::operator=(optional_type const& v) -> OptionalProxy& { if (v) @@ -881,33 +889,33 @@ STObject::OptionalProxy::operator=(optional_type const& v) return *this; } -template +template template -std::enable_if_t, STObject::OptionalProxy&> -STObject::OptionalProxy::operator=(U&& u) +std::enable_if_t, STObject::OptionalProxy&> +STObject::OptionalProxy::operator=(U&& u) { this->assign(std::forward(u)); return *this; } -template -STObject::OptionalProxy::OptionalProxy( +template +STObject::OptionalProxy::OptionalProxy( STObject* st, - TypedField const* f) - : Proxy(st, f) + TypedField const* f) + : Proxy(st, f) { } -template +template bool -STObject::OptionalProxy::engaged() const noexcept +STObject::OptionalProxy::engaged() const noexcept { return this->style_ == soeDEFAULT || this->find() != nullptr; } -template +template void -STObject::OptionalProxy::disengage() +STObject::OptionalProxy::disengage() { if (this->style_ == soeREQUIRED || this->style_ == soeDEFAULT) Throw( @@ -918,18 +926,18 @@ STObject::OptionalProxy::disengage() this->st_->makeFieldAbsent(*this->f_); } -template +template auto -STObject::OptionalProxy::optional_value() const -> optional_type +STObject::OptionalProxy::optional_value() const -> optional_type { if (!engaged()) return std::nullopt; return this->value(); } -template -typename STObject::OptionalProxy::value_type -STObject::OptionalProxy::value_or(value_type val) const +template +typename STObject::OptionalProxy::value_type +STObject::OptionalProxy::value_or(value_type val) const { return engaged() ? this->value() : val; } @@ -1034,64 +1042,67 @@ STObject::getPIndex(int offset) return &v_[offset].get(); } -template +template typename T::value_type -STObject::operator[](TypedField const& f) const +STObject::operator[](TypedField const& f) const { return at(f); } -inline STAmount -STObject::operator[](TypedField const& f) const +template +typename ValueType::value_type +STObject::operator[](TypedFieldAmount const& f) const { return at(f); } -template +template std::optional> -STObject::operator[](OptionaledField const& of) const +STObject::operator[](OptionaledField const& of) const { return at(of); } -inline std::optional -STObject::operator[]( - OptionaledField const& of) const +template +std::optional::value_type>> +STObject::operator[](OptionaledFieldAmount const& of) const { return at(of); } -template +template inline auto -STObject::operator[](TypedField const& f) -> ValueProxy +STObject::operator[](TypedField const& f) -> ValueProxy { return at(f); } +template inline auto -STObject::operator[](TypedField const& f) - -> ValueProxy +STObject::operator[](TypedFieldAmount const& f) + -> ValueProxy { return at(f); } -template +template inline auto -STObject::operator[](OptionaledField const& of) -> OptionalProxy +STObject::operator[](OptionaledField const& of) -> OptionalProxy { return at(of); } +template inline auto -STObject::operator[](OptionaledField const& of) - -> OptionalProxy +STObject::operator[](OptionaledFieldAmount const& of) + -> OptionalProxy { return at(of); } -template +template typename T::value_type -STObject::atImpl(TypedField const& f) const +STObject::atImpl(TypedField const& f) const { auto const b = peekAtPField(f); if (!b) @@ -1116,22 +1127,26 @@ STObject::atImpl(TypedField const& f) const return dv; } -template +template typename T::value_type -STObject::at(TypedField const& f) const +STObject::at(TypedField const& f) const { return atImpl(f); } -inline STAmount -STObject::at(TypedField const& f) const +template +typename ValueType::value_type +STObject::at(TypedFieldAmount const& f) const { - return get(atImpl(f)); + if constexpr (M == SFieldMPT::Yes) + return atImpl(f); + else + return get(atImpl(f)); } -template +template std::optional> -STObject::atImpl(OptionaledField const& of) const +STObject::atImpl(OptionaledField const& of) const { auto const b = peekAtPField(*of.f); if (!b) @@ -1149,45 +1164,50 @@ STObject::atImpl(OptionaledField const& of) const return u->value(); } -template +template std::optional> -STObject::at(OptionaledField const& of) const +STObject::at(OptionaledField const& of) const { return atImpl(of); } -inline std::optional -STObject::at(OptionaledField const& of) const +template +std::optional::value_type>> +STObject::at(OptionaledFieldAmount const& of) const { - return get(atImpl(of)); + if constexpr (M == SFieldMPT::Yes) + return atImpl(of); + else + return get(atImpl(of)); } -template +template inline auto -STObject::at(TypedField const& f) -> ValueProxy +STObject::at(TypedField const& f) -> ValueProxy { - return ValueProxy(this, &f); + return ValueProxy(this, &f); } +template inline auto -STObject::at(TypedField const& f) - -> ValueProxy +STObject::at(TypedFieldAmount const& f) -> ValueProxy { - return ValueProxy(this, &f); + return ValueProxy(this, &f); } -template +template inline auto -STObject::at(OptionaledField const& of) -> OptionalProxy +STObject::at(OptionaledField const& of) -> OptionalProxy { - return OptionalProxy(this, of.f); + return OptionalProxy(this, of.f); } +template inline auto -STObject::at(OptionaledField const& of) - -> OptionalProxy +STObject::at(OptionaledFieldAmount const& of) + -> OptionalProxy { - return OptionalProxy(this, of.f); + return OptionalProxy(this, of.f); } template diff --git a/src/libxrpl/protocol/SField.cpp b/src/libxrpl/protocol/SField.cpp index b3b92475578..38c2148c980 100644 --- a/src/libxrpl/protocol/SField.cpp +++ b/src/libxrpl/protocol/SField.cpp @@ -38,15 +38,19 @@ struct SField::private_access_tag_t static SField::private_access_tag_t access; -// clang-format off -template - requires ValidFields +template template -TypedField::TypedField(private_access_tag_t pat, Args&&... args) +TypedField::TypedField(private_access_tag_t pat, Args&&... args) : SField(pat, std::forward(args)...) { } -// clang-format on + +template +template +TypedFieldAmount::TypedFieldAmount(private_access_tag_t pat, Args&&... args) + : TypedField(pat, std::forward(args)...) +{ +} // Construct all compile-time SFields, and register them in the knownCodeToField // database: diff --git a/src/libxrpl/protocol/STObject.cpp b/src/libxrpl/protocol/STObject.cpp index 299811d093f..6542424e372 100644 --- a/src/libxrpl/protocol/STObject.cpp +++ b/src/libxrpl/protocol/STObject.cpp @@ -646,8 +646,7 @@ STObject::getFieldAmount(SField const& field) const } STAmount const& -STObject::getFieldAmount( - TypedField const& field) const +STObject::getFieldAmount(TypedFieldAmount const& field) const { static STEitherAmount const empty{}; return get(getFieldByConstRef(field, empty));