diff --git a/include/xrpl/protocol/TypedLedgerEntries.h b/include/xrpl/protocol/TypedLedgerEntries.h index c54341222e..0b7ea19674 100644 --- a/include/xrpl/protocol/TypedLedgerEntries.h +++ b/include/xrpl/protocol/TypedLedgerEntries.h @@ -30,6 +30,12 @@ namespace ripple { +enum class LedgerEntryConstness +{ + NonConst, + Const, +}; + // This is a proxy that returns a strongly-typed object instead of an STObject template class STArrayProxy @@ -380,6 +386,23 @@ struct GetInnerObjectStruct> using Struct = void; }; +template +using AddConstAwareness = std::conditional_t< + Constness == LedgerEntryConstness::NonConst, + T, + std::add_const_t +>; + +template +using MatchConstness = std::conditional_t< + std::is_const_v, + std::add_const_t, + Type +>; + +template +concept STObjectLike = std::same_as, STObject>; + // This type returns the value directly if the field is a typed field. template < SFieldNames FieldName, @@ -389,9 +412,9 @@ template < typename InnerObjectTypesArray> struct GetFieldValue { - template + template static auto - get(STObject& object, TFieldType const& field) + get(Object&& object, TFieldType const& field) { return object[field]; } @@ -409,9 +432,9 @@ struct GetFieldValue< AggregateFieldTypes::NONE, InnerObjectTypesArray> { - template + template static auto - get(STObject& object, TFieldType const& field) + get(Object&& object, TFieldType const& field) { return object[~field]; } @@ -435,12 +458,12 @@ struct GetFieldValue< typename GetInnerObjectStruct::Struct; // If the type is defined in inner_objects.macro, we return the defined type // otherwise, we return the untyped STObject - template + template static std::conditional_t< !std::is_void_v, InnerObjectType, STObject const&> - get(STObject& object, TFieldType const& field) + get(Object& object, TFieldType const& field) { if constexpr (!std::is_void_v) { @@ -468,12 +491,12 @@ struct GetFieldValue< { using InnerObjectType = typename GetInnerObjectStruct::Struct; - template + template static std::conditional_t< !std::is_void_v, std::optional, STObject const*> - get(STObject& object, TFieldType const& field) + get(Object& object, TFieldType const& field) { if constexpr (!std::is_void_v) { @@ -512,17 +535,21 @@ struct GetFieldValue< typename GetInnerObjectStruct:: Struct; - template + template static std::conditional_t< !std::is_void_v, - STArrayProxy, - STArray&> - get(STObject& object, TFieldType const& field) + MatchConstness, Object>, + MatchConstness&> + get(Object& object, TFieldType const& field) { if constexpr (!std::is_void_v) { return STArrayProxy{&object.peekFieldArray(field)}; } + else if constexpr (std::is_const_v) + { + return object.getFieldArray(field); + } else { return object.peekFieldArray(field); @@ -549,12 +576,12 @@ struct GetFieldValue< // If we know what type the STArray holds (i.e. the field is defined by // ARRAY_SFIELD and the item type is not Invalid), we return an // STArrayProxy, otherwise, we return an untyped STArray - template + template static std::conditional_t< !std::is_void_v, STArrayProxy, - STArray*> - get(STObject& object, TFieldType const& field) + MatchConstness*> + get(Object& object, TFieldType const& field) { if constexpr (!std::is_void_v) { @@ -565,6 +592,14 @@ struct GetFieldValue< } return STArrayProxy{nullptr}; } + else if constexpr (std::is_const_v) + { + if (object.isFieldPresent(field)) + { + return &object.getFieldArray(field); + } + return nullptr; + } else { if (object.isFieldPresent(field)) @@ -767,7 +802,8 @@ struct GetFieldValue< #pragma pop_macro("INNER_OBJECT_BEGIN") #pragma pop_macro("INNER_OBJECT_END") -template +template struct LedgerEntry { }; @@ -817,8 +853,19 @@ struct LedgerEntry soeStyle, \ detail::GetFieldType::Value, \ InnerObjectTypesArray>:: \ - get(std::declval(), field)); \ + get(std::declval&>(), field)); \ Field_##field##Type f##field() \ + { \ + return GetFieldValue< \ + SFieldNames::field_##field, \ + detail::GetFieldType::ItemField, \ + soeStyle, \ + detail::GetFieldType::Value, \ + InnerObjectTypesArray>::get(*getObject(), field); \ + } \ + Field_##field##Type f##field() const \ { \ return GetFieldValue< \ SFieldNames::field_##field, \ @@ -829,16 +876,22 @@ struct LedgerEntry } #define LEDGER_ENTRY(tag, value, name, rpcName, fields) \ - template <> \ - struct LedgerEntry \ + template \ + struct LedgerEntry \ { \ private: \ - using CLS = LedgerEntry; \ - std::variant, STLedgerEntry*> object_; \ - LedgerEntry(STLedgerEntry& object) : object_(&object) \ + using CLS = LedgerEntry; \ + std::variant< \ + std::shared_ptr>, \ + AddConstAwareness*> object_; \ + LedgerEntry(AddConstAwareness& object) \ + : object_(&object) \ { \ } \ - LedgerEntry(std::shared_ptr const& object) \ + LedgerEntry( \ + std::shared_ptr< \ + AddConstAwareness \ + > const& object) \ : object_(object) \ { \ } \ @@ -857,42 +910,82 @@ struct LedgerEntry Throw("Object type mismatch!"); \ } \ } \ - STLedgerEntry* \ + AddConstAwareness* \ getObject() \ { \ - if (std::holds_alternative>( \ + if (std::holds_alternative< \ + std::shared_ptr< \ + AddConstAwareness \ + >>( \ object_)) \ { \ - return std::get>(object_) \ - .get(); \ + return std::get< \ + std::shared_ptr< \ + AddConstAwareness \ + >>(object_).get(); \ } \ else \ { \ - return std::get(object_); \ + return std::get< \ + AddConstAwareness* \ + >(object_); \ } \ } \ STLedgerEntry const* \ getObject() const \ { \ - if (std::holds_alternative>( \ - object_)) \ + if (std::holds_alternative< \ + std::shared_ptr< \ + AddConstAwareness> \ + >(object_)) \ { \ - return std::get>(object_) \ - .get(); \ + return std::get< \ + std::shared_ptr< \ + AddConstAwareness> \ + >(object_).get(); \ } \ else \ { \ - return std::get(object_); \ + return std::get< \ + AddConstAwareness* \ + >(object_); \ } \ } \ + operator std::shared_ptr< \ + AddConstAwareness>&() \ + { \ + return std::get< \ + std::shared_ptr< \ + AddConstAwareness> \ + >(object_); \ + } \ + operator std::shared_ptr< \ + AddConstAwareness \ + > const&() const \ + { \ + return std::get< \ + std::shared_ptr< \ + AddConstAwareness> \ + >(object_); \ + } \ + operator bool() const { return isValid(); } \ + bool operator==(std::nullptr_t) const { return !isValid(); } \ + bool operator!=(std::nullptr_t) const { return isValid(); } \ + bool operator!() const { return !isValid(); } \ + auto operator->() const { return getObject(); } \ + auto operator->() { return getObject(); } \ + auto& operator*() { return *getObject(); } \ + auto const& operator*() const { return *getObject(); } \ static LedgerEntry \ - fromObject(STLedgerEntry& object) \ + fromObject(AddConstAwareness& object) \ { \ ensureType(object); \ return LedgerEntry{object}; \ } \ static LedgerEntry \ - fromObject(std::shared_ptr const& object) \ + fromObject(std::shared_ptr< \ + AddConstAwareness \ + > const& object) \ { \ ensureType(*object); \ return LedgerEntry{object}; \ @@ -900,7 +993,10 @@ struct LedgerEntry static LedgerEntry \ create(uint256 const& key) \ { \ - return LedgerEntry{std::make_shared(tag, key)}; \ + return LedgerEntry{ \ + std::make_shared< \ + AddConstAwareness \ + >(tag, key)}; \ } \ fields \ }; @@ -931,6 +1027,9 @@ using InnerObjectType = typename detail:: // This gives a ledger entry type that the LedgerEntryType corresponds to. template -using LedgerObjectType = detail::LedgerEntry; +using LedgerObjectType = detail::LedgerEntry; + +template +using ConstLedgerObjectType = detail::LedgerEntry; } // namespace ripple #endif // TYPED_LEDGER_ENTRIES_H