Files
rippled/include/xrpl/protocol/detail/STVar.h
2025-10-23 11:04:30 -04:00

168 lines
3.3 KiB
C++

#ifndef XRPL_PROTOCOL_STVAR_H_INCLUDED
#define XRPL_PROTOCOL_STVAR_H_INCLUDED
#include <xrpl/protocol/SField.h>
#include <xrpl/protocol/STBase.h>
#include <xrpl/protocol/Serializer.h>
#include <cstddef>
#include <type_traits>
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 <typename... Args>
concept ValidConstructSTArgs =
(std::is_same_v<
std::tuple<std::remove_cvref_t<Args>...>,
std::tuple<SField>> ||
std::is_same_v<
std::tuple<std::remove_cvref_t<Args>...>,
std::tuple<SerialIter, SField>>);
// 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<max_size>::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 <class T, class... Args>
friend STVar
make_stvar(Args&&... args);
private:
STVar() = default;
STVar(SerializedTypeID id, SField const& name);
void
destroy();
template <class T, class... Args>
void
construct(Args&&... args)
{
if constexpr (sizeof(T) > max_size)
p_ = new T(std::forward<Args>(args)...);
else
p_ = new (&d_) T(std::forward<Args>(args)...);
}
/** Construct requested Serializable Type according to id.
* The variadic args are: (SField), or (SerialIter, SField).
* depth is ignored in former case.
*/
template <typename... Args>
requires ValidConstructSTArgs<Args...>
void
constructST(SerializedTypeID id, int depth, Args&&... arg);
bool
on_heap() const
{
return static_cast<void const*>(p_) != static_cast<void const*>(&d_);
}
};
template <class T, class... Args>
inline STVar
make_stvar(Args&&... args)
{
STVar st;
st.construct<T>(std::forward<Args>(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