#ifndef XRPL_PROTOCOL_STVAR_H_INCLUDED #define XRPL_PROTOCOL_STVAR_H_INCLUDED #include #include #include #include #include namespace ripple { namespace detail { struct defaultObject_t { explicit defaultObject_t() = default; }; struct nonPresentObject_t { explicit nonPresentObject_t() = default; }; extern defaultObject_t defaultObject; extern nonPresentObject_t nonPresentObject; // Concept to constrain STVar constructors, which // instantiate ST* types from SerializedTypeID // clang-format off template concept ValidConstructSTArgs = (std::is_same_v< std::tuple...>, std::tuple> || std::is_same_v< std::tuple...>, std::tuple>); // clang-format on // "variant" that can hold any type of serialized object // and includes a small-object allocation optimization. class STVar { private: // The largest "small object" we can accomodate static std::size_t constexpr max_size = 72; std::aligned_storage::type d_; STBase* p_ = nullptr; public: ~STVar(); STVar(STVar const& other); STVar(STVar&& other); STVar& operator=(STVar const& rhs); STVar& operator=(STVar&& rhs); STVar(STBase&& t) { p_ = t.move(max_size, &d_); } STVar(STBase const& t) { p_ = t.copy(max_size, &d_); } STVar(defaultObject_t, SField const& name); STVar(nonPresentObject_t, SField const& name); STVar(SerialIter& sit, SField const& name, int depth = 0); STBase& get() { return *p_; } STBase& operator*() { return get(); } STBase* operator->() { return &get(); } STBase const& get() const { return *p_; } STBase const& operator*() const { return get(); } STBase const* operator->() const { return &get(); } template friend STVar make_stvar(Args&&... args); private: STVar() = default; STVar(SerializedTypeID id, SField const& name); void destroy(); template void construct(Args&&... args) { if constexpr (sizeof(T) > max_size) p_ = new T(std::forward(args)...); else p_ = new (&d_) T(std::forward(args)...); } /** Construct requested Serializable Type according to id. * The variadic args are: (SField), or (SerialIter, SField). * depth is ignored in former case. */ template requires ValidConstructSTArgs void constructST(SerializedTypeID id, int depth, Args&&... arg); bool on_heap() const { return static_cast(p_) != static_cast(&d_); } }; template inline STVar make_stvar(Args&&... args) { STVar st; st.construct(std::forward(args)...); return st; } inline bool operator==(STVar const& lhs, STVar const& rhs) { return lhs.get().isEquivalent(rhs.get()); } inline bool operator!=(STVar const& lhs, STVar const& rhs) { return !(lhs == rhs); } } // namespace detail } // namespace ripple #endif