mirror of
https://github.com/XRPLF/rippled.git
synced 2025-12-06 17:27:55 +00:00
STVar: optimized storage for STObject (RIPD-825):
This introduces the STVar container, capable of holding any STBase-derived class and implementing a "small string" optimization. STObject is changed to store std::vector<STVar> instead of boost::ptr_vector<STBase>. This eliminates a significant number of needless dynamic memory allocations and deallocations during transaction processing when ledger entries are deserialized. It comes at the expense of larger overall storage requirements for STObject.
This commit is contained in:
@@ -22,6 +22,11 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
STAccount::STAccount (SerialIter& sit, SField::ref name)
|
||||
: STAccount(name, sit.getVLBuffer())
|
||||
{
|
||||
}
|
||||
|
||||
std::string STAccount::getText () const
|
||||
{
|
||||
Account u;
|
||||
|
||||
@@ -42,6 +42,82 @@ STAmount const saOne (noIssue(), 1u);
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STAmount::STAmount(SerialIter& sit, SField::ref name)
|
||||
: STBase(name)
|
||||
{
|
||||
std::uint64_t value = sit.get64 ();
|
||||
|
||||
// native
|
||||
if ((value & cNotNative) == 0)
|
||||
{
|
||||
// positive
|
||||
if ((value & cPosNative) != 0)
|
||||
{
|
||||
mValue = value & ~cPosNative;
|
||||
mOffset = 0;
|
||||
mIsNative = true;
|
||||
mIsNegative = false;
|
||||
return;
|
||||
}
|
||||
|
||||
// negative
|
||||
if (value == 0)
|
||||
throw std::runtime_error ("negative zero is not canonical");
|
||||
|
||||
mValue = value;
|
||||
mOffset = 0;
|
||||
mIsNative = true;
|
||||
mIsNegative = true;
|
||||
return;
|
||||
}
|
||||
|
||||
Issue issue;
|
||||
issue.currency.copyFrom (sit.get160 ());
|
||||
|
||||
if (isXRP (issue.currency))
|
||||
throw std::runtime_error ("invalid native currency");
|
||||
|
||||
issue.account.copyFrom (sit.get160 ());
|
||||
|
||||
if (isXRP (issue.account))
|
||||
throw std::runtime_error ("invalid native account");
|
||||
|
||||
// 10 bits for the offset, sign and "not native" flag
|
||||
int offset = static_cast<int> (value >> (64 - 10));
|
||||
|
||||
value &= ~ (1023ull << (64 - 10));
|
||||
|
||||
if (value)
|
||||
{
|
||||
bool isNegative = (offset & 256) == 0;
|
||||
offset = (offset & 255) - 97; // center the range
|
||||
|
||||
if (value < cMinValue ||
|
||||
value > cMaxValue ||
|
||||
offset < cMinOffset ||
|
||||
offset > cMaxOffset)
|
||||
{
|
||||
throw std::runtime_error ("invalid currency value");
|
||||
}
|
||||
|
||||
mIssue = issue;
|
||||
mValue = value;
|
||||
mOffset = offset;
|
||||
mIsNegative = isNegative;
|
||||
canonicalize();
|
||||
return;
|
||||
}
|
||||
|
||||
if (offset != 512)
|
||||
throw std::runtime_error ("invalid currency value");
|
||||
|
||||
mIssue = issue;
|
||||
mValue = 0;
|
||||
mOffset = 0;
|
||||
mIsNegative = false;
|
||||
canonicalize();
|
||||
}
|
||||
|
||||
STAmount::STAmount (SField::ref name, Issue const& issue,
|
||||
mantissa_type mantissa, exponent_type exponent,
|
||||
bool native, bool negative)
|
||||
@@ -140,58 +216,7 @@ STAmount::STAmount (Issue const& issue,
|
||||
std::unique_ptr<STAmount>
|
||||
STAmount::construct (SerialIter& sit, SField::ref name)
|
||||
{
|
||||
std::uint64_t value = sit.get64 ();
|
||||
|
||||
// native
|
||||
if ((value & cNotNative) == 0)
|
||||
{
|
||||
// positive
|
||||
if ((value & cPosNative) != 0)
|
||||
return std::make_unique<STAmount> (name, value & ~cPosNative, false);
|
||||
|
||||
// negative
|
||||
if (value == 0)
|
||||
throw std::runtime_error ("negative zero is not canonical");
|
||||
|
||||
return std::make_unique<STAmount> (name, value, true);
|
||||
}
|
||||
|
||||
Issue issue;
|
||||
issue.currency.copyFrom (sit.get160 ());
|
||||
|
||||
if (isXRP (issue.currency))
|
||||
throw std::runtime_error ("invalid native currency");
|
||||
|
||||
issue.account.copyFrom (sit.get160 ());
|
||||
|
||||
if (isXRP (issue.account))
|
||||
throw std::runtime_error ("invalid native account");
|
||||
|
||||
// 10 bits for the offset, sign and "not native" flag
|
||||
int offset = static_cast<int> (value >> (64 - 10));
|
||||
|
||||
value &= ~ (1023ull << (64 - 10));
|
||||
|
||||
if (value)
|
||||
{
|
||||
bool isNegative = (offset & 256) == 0;
|
||||
offset = (offset & 255) - 97; // center the range
|
||||
|
||||
if (value < cMinValue ||
|
||||
value > cMaxValue ||
|
||||
offset < cMinOffset ||
|
||||
offset > cMaxOffset)
|
||||
{
|
||||
throw std::runtime_error ("invalid currency value");
|
||||
}
|
||||
|
||||
return std::make_unique<STAmount> (name, issue, value, offset, isNegative);
|
||||
}
|
||||
|
||||
if (offset != 512)
|
||||
throw std::runtime_error ("invalid currency value");
|
||||
|
||||
return std::make_unique<STAmount> (name, issue);
|
||||
return std::make_unique<STAmount>(sit, name);
|
||||
}
|
||||
|
||||
STAmount
|
||||
@@ -202,16 +227,6 @@ STAmount::createFromInt64 (SField::ref name, std::int64_t value)
|
||||
: STAmount (name, static_cast<std::uint64_t> (-value), true);
|
||||
}
|
||||
|
||||
STAmount STAmount::deserialize (SerialIter& it)
|
||||
{
|
||||
auto s = construct (it, sfGeneric);
|
||||
|
||||
if (!s)
|
||||
throw std::runtime_error("Deserialization error");
|
||||
|
||||
return STAmount (*s);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
//
|
||||
// Operators
|
||||
|
||||
@@ -24,12 +24,47 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::unique_ptr<STBase>
|
||||
STArray::deserialize (SerialIter& sit, SField::ref field)
|
||||
STArray::STArray()
|
||||
{
|
||||
std::unique_ptr <STArray> ret (std::make_unique <STArray> (field));
|
||||
vector& value (ret->getValue ());
|
||||
// VFALCO NOTE We need to determine if this is
|
||||
// the right thing to do, and consider
|
||||
// making it optional.
|
||||
//v_.reserve(reserveSize);
|
||||
}
|
||||
|
||||
STArray::STArray (STArray&& other)
|
||||
: STBase(other.getFName())
|
||||
, v_(std::move(other.v_))
|
||||
{
|
||||
}
|
||||
|
||||
STArray& STArray::operator= (STArray&& other)
|
||||
{
|
||||
setFName(other.getFName());
|
||||
v_ = std::move(other.v_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
STArray::STArray (int n)
|
||||
{
|
||||
v_.reserve(n);
|
||||
}
|
||||
|
||||
STArray::STArray (SField::ref f)
|
||||
: STBase (f)
|
||||
{
|
||||
v_.reserve(reserveSize);
|
||||
}
|
||||
|
||||
STArray::STArray (SField::ref f, int n)
|
||||
: STBase (f)
|
||||
{
|
||||
v_.reserve(n);
|
||||
}
|
||||
|
||||
STArray::STArray (SerialIter& sit, SField::ref f)
|
||||
: STBase(f)
|
||||
{
|
||||
while (!sit.empty ())
|
||||
{
|
||||
int type, field;
|
||||
@@ -45,7 +80,7 @@ STArray::deserialize (SerialIter& sit, SField::ref field)
|
||||
throw std::runtime_error ("Illegal terminator in array");
|
||||
}
|
||||
|
||||
SField::ref fn = SField::getField (type, field);
|
||||
SField::ref const fn = SField::getField (type, field);
|
||||
|
||||
if (fn.isInvalid ())
|
||||
{
|
||||
@@ -60,10 +95,9 @@ STArray::deserialize (SerialIter& sit, SField::ref field)
|
||||
throw std::runtime_error ("Non-object in array");
|
||||
}
|
||||
|
||||
value.push_back (new STObject (fn));
|
||||
value.rbegin ()->set (sit, 1);
|
||||
v_.emplace_back(fn);
|
||||
v_.back().set (sit, 1);
|
||||
}
|
||||
return std::move (ret);
|
||||
}
|
||||
|
||||
std::string STArray::getFullText () const
|
||||
@@ -71,12 +105,12 @@ std::string STArray::getFullText () const
|
||||
std::string r = "[";
|
||||
|
||||
bool first = true;
|
||||
for (STObject const& o : value)
|
||||
for (auto const& obj : v_)
|
||||
{
|
||||
if (!first)
|
||||
r += ",";
|
||||
|
||||
r += o.getFullText ();
|
||||
r += obj.getFullText ();
|
||||
first = false;
|
||||
}
|
||||
|
||||
@@ -89,7 +123,7 @@ std::string STArray::getText () const
|
||||
std::string r = "[";
|
||||
|
||||
bool first = true;
|
||||
for (STObject const& o : value)
|
||||
for (STObject const& o : v_)
|
||||
{
|
||||
if (!first)
|
||||
r += ",";
|
||||
@@ -106,7 +140,7 @@ Json::Value STArray::getJson (int p) const
|
||||
{
|
||||
Json::Value v = Json::arrayValue;
|
||||
int index = 1;
|
||||
for (auto const& object: value)
|
||||
for (auto const& object: v_)
|
||||
{
|
||||
if (object.getSType () != STI_NOTPRESENT)
|
||||
{
|
||||
@@ -122,7 +156,7 @@ Json::Value STArray::getJson (int p) const
|
||||
|
||||
void STArray::add (Serializer& s) const
|
||||
{
|
||||
for (STObject const& object : value)
|
||||
for (STObject const& object : v_)
|
||||
{
|
||||
object.addFieldID (s);
|
||||
object.add (s);
|
||||
@@ -141,12 +175,12 @@ bool STArray::isEquivalent (const STBase& t) const
|
||||
return false;
|
||||
}
|
||||
|
||||
return value == v->value;
|
||||
return v_ == v->v_;
|
||||
}
|
||||
|
||||
void STArray::sort (bool (*compare) (const STObject&, const STObject&))
|
||||
{
|
||||
value.sort (compare);
|
||||
std::sort(v_.begin(), v_.end(), compare);
|
||||
}
|
||||
|
||||
} // ripple
|
||||
|
||||
@@ -145,28 +145,8 @@ STBase::addFieldID (Serializer& s) const
|
||||
s.addFieldID (fName->fieldType, fName->fieldValue);
|
||||
}
|
||||
|
||||
std::unique_ptr <STBase>
|
||||
STBase::deserialize (SField::ref name)
|
||||
{
|
||||
return std::make_unique<STBase>(name);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STBase*
|
||||
new_clone (const STBase& s)
|
||||
{
|
||||
STBase* const copy (s.duplicate ().release ());
|
||||
assert (typeid (*copy) == typeid (s));
|
||||
return copy;
|
||||
}
|
||||
|
||||
void
|
||||
delete_clone (const STBase* s)
|
||||
{
|
||||
boost::checked_delete (s);
|
||||
}
|
||||
|
||||
std::ostream&
|
||||
operator<< (std::ostream& out, const STBase& t)
|
||||
{
|
||||
|
||||
@@ -28,6 +28,12 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
template<>
|
||||
STInteger<unsigned char>::STInteger(SerialIter& sit, SField::ref name)
|
||||
: STInteger(name, sit.get8())
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STUInt8::getSType () const
|
||||
@@ -35,13 +41,6 @@ STUInt8::getSType () const
|
||||
return STI_UINT8;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<STBase>
|
||||
STUInt8::deserialize (SerialIter& sit, SField::ref name)
|
||||
{
|
||||
return std::make_unique <STUInt8> (name, sit.get8 ());
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
STUInt8::getText () const
|
||||
@@ -77,6 +76,12 @@ STUInt8::getJson (int) const
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
STInteger<std::uint16_t>::STInteger(SerialIter& sit, SField::ref name)
|
||||
: STInteger(name, sit.get16())
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STUInt16::getSType () const
|
||||
@@ -84,13 +89,6 @@ STUInt16::getSType () const
|
||||
return STI_UINT16;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<STBase>
|
||||
STUInt16::deserialize (SerialIter& sit, SField::ref name)
|
||||
{
|
||||
return std::make_unique <STUInt16> (name, sit.get16 ());
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
STUInt16::getText () const
|
||||
@@ -143,6 +141,12 @@ STUInt16::getJson (int) const
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
STInteger<std::uint32_t>::STInteger(SerialIter& sit, SField::ref name)
|
||||
: STInteger(name, sit.get32())
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STUInt32::getSType () const
|
||||
@@ -150,13 +154,6 @@ STUInt32::getSType () const
|
||||
return STI_UINT32;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<STBase>
|
||||
STUInt32::deserialize (SerialIter& sit, SField::ref name)
|
||||
{
|
||||
return std::make_unique <STUInt32> (name, sit.get32 ());
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
STUInt32::getText () const
|
||||
@@ -173,6 +170,12 @@ STUInt32::getJson (int) const
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template<>
|
||||
STInteger<std::uint64_t>::STInteger(SerialIter& sit, SField::ref name)
|
||||
: STInteger(name, sit.get64())
|
||||
{
|
||||
}
|
||||
|
||||
template <>
|
||||
SerializedTypeID
|
||||
STUInt64::getSType () const
|
||||
@@ -180,13 +183,6 @@ STUInt64::getSType () const
|
||||
return STI_UINT64;
|
||||
}
|
||||
|
||||
template <>
|
||||
std::unique_ptr<STBase>
|
||||
STUInt64::deserialize (SerialIter& sit, SField::ref name)
|
||||
{
|
||||
return std::make_unique <STUInt64> (name, sit.get64 ());
|
||||
}
|
||||
|
||||
template <>
|
||||
std::string
|
||||
STUInt64::getText () const
|
||||
|
||||
@@ -31,222 +31,150 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::unique_ptr<STBase>
|
||||
STObject::makeDefaultObject (SerializedTypeID id, SField::ref name)
|
||||
STObject::~STObject()
|
||||
{
|
||||
assert ((id == STI_NOTPRESENT) || (id == name.fieldType));
|
||||
|
||||
switch (id)
|
||||
{
|
||||
case STI_NOTPRESENT:
|
||||
return std::make_unique <STBase> (name);
|
||||
|
||||
case STI_UINT8:
|
||||
return std::make_unique <STUInt8> (name);
|
||||
|
||||
case STI_UINT16:
|
||||
return std::make_unique <STUInt16> (name);
|
||||
|
||||
case STI_UINT32:
|
||||
return std::make_unique <STUInt32> (name);
|
||||
|
||||
case STI_UINT64:
|
||||
return std::make_unique <STUInt64> (name);
|
||||
|
||||
case STI_AMOUNT:
|
||||
return std::make_unique <STAmount> (name);
|
||||
|
||||
case STI_HASH128:
|
||||
return std::make_unique <STHash128> (name);
|
||||
|
||||
case STI_HASH160:
|
||||
return std::make_unique <STHash160> (name);
|
||||
|
||||
case STI_HASH256:
|
||||
return std::make_unique <STHash256> (name);
|
||||
|
||||
case STI_VECTOR256:
|
||||
return std::make_unique <STVector256> (name);
|
||||
|
||||
case STI_VL:
|
||||
return std::make_unique <STBlob> (name);
|
||||
|
||||
case STI_ACCOUNT:
|
||||
return std::make_unique <STAccount> (name);
|
||||
|
||||
case STI_PATHSET:
|
||||
return std::make_unique <STPathSet> (name);
|
||||
|
||||
case STI_OBJECT:
|
||||
return std::make_unique <STObject> (name);
|
||||
|
||||
case STI_ARRAY:
|
||||
return std::make_unique <STArray> (name);
|
||||
|
||||
default:
|
||||
WriteLog (lsFATAL, STObject) <<
|
||||
"Object type: " << beast::lexicalCast <std::string> (id);
|
||||
assert (false);
|
||||
throw std::runtime_error ("Unknown object type");
|
||||
}
|
||||
#if 0
|
||||
// Turn this on to get a histogram on exit
|
||||
static beast::static_initializer<Log> log;
|
||||
(*log)(v_.size());
|
||||
#endif
|
||||
}
|
||||
|
||||
// VFALCO TODO Remove the 'depth' parameter
|
||||
std::unique_ptr<STBase>
|
||||
STObject::makeDeserializedObject (SerializedTypeID id, SField::ref name,
|
||||
SerialIter& sit, int depth)
|
||||
STObject::STObject(STObject&& other)
|
||||
: STBase(other.getFName())
|
||||
, v_(std::move(other.v_))
|
||||
, mType(other.mType)
|
||||
{
|
||||
switch (id)
|
||||
{
|
||||
case STI_NOTPRESENT:
|
||||
return STBase::deserialize (name);
|
||||
}
|
||||
|
||||
case STI_UINT8:
|
||||
return STUInt8::deserialize (sit, name);
|
||||
STObject::STObject (SField::ref name)
|
||||
: STBase (name)
|
||||
, mType (nullptr)
|
||||
{
|
||||
// VFALCO TODO See if this is the right thing to do
|
||||
//v_.reserve(reserveSize);
|
||||
}
|
||||
|
||||
case STI_UINT16:
|
||||
return STUInt16::deserialize (sit, name);
|
||||
STObject::STObject (SOTemplate const& type,
|
||||
SField::ref name)
|
||||
: STBase (name)
|
||||
{
|
||||
set (type);
|
||||
}
|
||||
|
||||
case STI_UINT32:
|
||||
return STUInt32::deserialize (sit, name);
|
||||
STObject::STObject (SOTemplate const& type,
|
||||
SerialIter & sit, SField::ref name)
|
||||
: STBase (name)
|
||||
{
|
||||
v_.reserve(type.peek().size());
|
||||
set (sit);
|
||||
setType (type);
|
||||
}
|
||||
|
||||
case STI_UINT64:
|
||||
return STUInt64::deserialize (sit, name);
|
||||
STObject::STObject (SField::ref name,
|
||||
boost::ptr_vector<STBase>& data)
|
||||
: STBase (name)
|
||||
, mType (nullptr)
|
||||
{
|
||||
v_.reserve(data.size());
|
||||
for (auto const& b : data)
|
||||
v_.emplace_back(b);
|
||||
}
|
||||
|
||||
case STI_AMOUNT:
|
||||
return STAmount::deserialize (sit, name);
|
||||
STObject::STObject (SerialIter& sit, SField::ref name)
|
||||
: STBase(name)
|
||||
, mType(nullptr)
|
||||
{
|
||||
set(sit, 0);
|
||||
}
|
||||
|
||||
case STI_HASH128:
|
||||
return STHash128::deserialize (sit, name);
|
||||
|
||||
case STI_HASH160:
|
||||
return STHash160::deserialize (sit, name);
|
||||
|
||||
case STI_HASH256:
|
||||
return STHash256::deserialize (sit, name);
|
||||
|
||||
case STI_VECTOR256:
|
||||
return STVector256::deserialize (sit, name);
|
||||
|
||||
case STI_VL:
|
||||
return STBlob::deserialize (sit, name);
|
||||
|
||||
case STI_ACCOUNT:
|
||||
return STAccount::deserialize (sit, name);
|
||||
|
||||
case STI_PATHSET:
|
||||
return STPathSet::deserialize (sit, name);
|
||||
|
||||
case STI_ARRAY:
|
||||
return STArray::deserialize (sit, name);
|
||||
|
||||
case STI_OBJECT:
|
||||
return STObject::deserialize (sit, name);
|
||||
|
||||
default:
|
||||
throw std::runtime_error ("Unknown object type");
|
||||
}
|
||||
STObject&
|
||||
STObject::operator= (STObject&& other)
|
||||
{
|
||||
setFName(other.getFName());
|
||||
mType = other.mType;
|
||||
v_ = std::move(other.v_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void STObject::set (const SOTemplate& type)
|
||||
{
|
||||
mData.clear ();
|
||||
v_.clear();
|
||||
v_.reserve(type.peek().size());
|
||||
mType = &type;
|
||||
|
||||
for (SOTemplate::value_type const& elem : type.peek ())
|
||||
for (auto const& elem : type.peek())
|
||||
{
|
||||
if (elem->flags != SOE_REQUIRED)
|
||||
giveObject (makeNonPresentObject (elem->e_field));
|
||||
v_.emplace_back(detail::nonPresentObject, elem->e_field);
|
||||
else
|
||||
giveObject (makeDefaultObject (elem->e_field));
|
||||
v_.emplace_back(detail::defaultObject, elem->e_field);
|
||||
}
|
||||
}
|
||||
|
||||
bool STObject::setType (const SOTemplate& type)
|
||||
{
|
||||
boost::ptr_vector<STBase> newData (type.peek ().size ());
|
||||
bool valid = true;
|
||||
|
||||
mType = &type;
|
||||
|
||||
STBase** array = mData.c_array();
|
||||
std::size_t count = mData.size ();
|
||||
|
||||
for (auto const& elem : type.peek ())
|
||||
decltype(v_) v;
|
||||
v.reserve(type.peek().size());
|
||||
for (auto const& e : type.peek())
|
||||
{
|
||||
// Loop through all the fields in the template
|
||||
bool match = false;
|
||||
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
if ((array[i] != nullptr) &&
|
||||
(array[i]->getFName () == elem->e_field))
|
||||
{
|
||||
// matching entry in the object, move to new vector
|
||||
match = true;
|
||||
|
||||
if ((elem->flags == SOE_DEFAULT) && array[i]->isDefault ())
|
||||
{
|
||||
WriteLog (lsWARNING, STObject) <<
|
||||
"setType( " << getFName ().getName () <<
|
||||
") invalid default " << elem->e_field.fieldName;
|
||||
valid = false;
|
||||
}
|
||||
|
||||
newData.push_back (array[i]);
|
||||
array[i] = nullptr;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!match)
|
||||
auto const iter = std::find_if(
|
||||
v_.begin(), v_.end(), [&](detail::STVar const& b)
|
||||
{ return b.get().getFName() == e->e_field; });
|
||||
if (iter != v_.end())
|
||||
{
|
||||
// no match found in the object for an entry in the template
|
||||
if (elem->flags == SOE_REQUIRED)
|
||||
if ((e->flags == SOE_DEFAULT) && iter->get().isDefault())
|
||||
{
|
||||
WriteLog (lsWARNING, STObject) <<
|
||||
"setType( " << getFName ().getName () <<
|
||||
") invalid missing " << elem->e_field.fieldName;
|
||||
") invalid default " << e->e_field.fieldName;
|
||||
valid = false;
|
||||
}
|
||||
|
||||
// Make a default object
|
||||
newData.push_back (makeNonPresentObject (elem->e_field).release ());
|
||||
v.emplace_back(std::move(*iter));
|
||||
v_.erase(iter);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (e->flags == SOE_REQUIRED)
|
||||
{
|
||||
WriteLog (lsWARNING, STObject) <<
|
||||
"setType( " << getFName ().getName () <<
|
||||
") invalid missing " << e->e_field.fieldName;
|
||||
valid = false;
|
||||
}
|
||||
v.emplace_back(detail::nonPresentObject, e->e_field);
|
||||
}
|
||||
}
|
||||
|
||||
for (std::size_t i = 0; i < count; ++i)
|
||||
for (auto const& e : v_)
|
||||
{
|
||||
// Anything left over in the object must be discardable
|
||||
if ((array[i] != nullptr) && !array[i]->getFName ().isDiscardable ())
|
||||
if (! e->getFName().isDiscardable())
|
||||
{
|
||||
WriteLog (lsWARNING, STObject) <<
|
||||
"setType( " << getFName ().getName () <<
|
||||
") invalid leftover " << array[i]->getFName ().getName ();
|
||||
") invalid leftover " << e->getFName ().getName ();
|
||||
valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
// Swap the template matching data in for the old data,
|
||||
// freeing any leftover junk
|
||||
mData.swap (newData);
|
||||
|
||||
v_.swap(v);
|
||||
return valid;
|
||||
}
|
||||
|
||||
bool STObject::isValidForType ()
|
||||
{
|
||||
boost::ptr_vector<STBase>::iterator it = mData.begin ();
|
||||
|
||||
for (SOTemplate::value_type const& elem : mType->peek ())
|
||||
auto it = v_.begin();
|
||||
for (SOTemplate::value_type const& elem : mType->peek())
|
||||
{
|
||||
if (it == mData.end ())
|
||||
if (it == v_.end())
|
||||
return false;
|
||||
|
||||
if (elem->e_field != it->getFName ())
|
||||
if (elem->e_field != it->get().getFName())
|
||||
return false;
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -263,9 +191,7 @@ bool STObject::set (SerialIter& sit, int depth)
|
||||
{
|
||||
bool reachedEndOfObject = false;
|
||||
|
||||
// Empty the destination buffer
|
||||
//
|
||||
mData.clear ();
|
||||
v_.clear();
|
||||
|
||||
// Consume data in the pipe until we run out or reach the end
|
||||
//
|
||||
@@ -302,24 +228,13 @@ bool STObject::set (SerialIter& sit, int depth)
|
||||
}
|
||||
|
||||
// Unflatten the field
|
||||
//
|
||||
giveObject (
|
||||
makeDeserializedObject (fn.fieldType, fn, sit, depth + 1));
|
||||
v_.emplace_back(sit, fn);
|
||||
}
|
||||
}
|
||||
|
||||
return reachedEndOfObject;
|
||||
}
|
||||
|
||||
|
||||
std::unique_ptr<STBase>
|
||||
STObject::deserialize (SerialIter& sit, SField::ref name)
|
||||
{
|
||||
std::unique_ptr <STObject> object (std::make_unique <STObject> (name));
|
||||
object->set (sit, 1);
|
||||
return std::move (object);
|
||||
}
|
||||
|
||||
bool STObject::hasMatchingEntry (const STBase& t)
|
||||
{
|
||||
const STBase* o = peekAtPField (t.getFName ());
|
||||
@@ -342,16 +257,16 @@ std::string STObject::getFullText () const
|
||||
}
|
||||
else ret = "{";
|
||||
|
||||
for (STBase const& elem : mData)
|
||||
for (auto const& elem : v_)
|
||||
{
|
||||
if (elem.getSType () != STI_NOTPRESENT)
|
||||
if (elem->getSType () != STI_NOTPRESENT)
|
||||
{
|
||||
if (!first)
|
||||
ret += ", ";
|
||||
else
|
||||
first = false;
|
||||
|
||||
ret += elem.getFullText ();
|
||||
ret += elem->getFullText ();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -361,32 +276,30 @@ std::string STObject::getFullText () const
|
||||
|
||||
void STObject::add (Serializer& s, bool withSigningFields) const
|
||||
{
|
||||
std::map<int, const STBase*> fields;
|
||||
|
||||
for (STBase const& elem : mData)
|
||||
std::map<int, STBase const*> fields;
|
||||
for (auto const& e : v_)
|
||||
{
|
||||
// pick out the fields and sort them
|
||||
if ((elem.getSType () != STI_NOTPRESENT) &&
|
||||
elem.getFName ().shouldInclude (withSigningFields))
|
||||
if ((e->getSType() != STI_NOTPRESENT) &&
|
||||
e->getFName().shouldInclude (withSigningFields))
|
||||
{
|
||||
fields.insert (std::make_pair (elem.getFName ().fieldCode, &elem));
|
||||
fields.insert (std::make_pair (
|
||||
e->getFName().fieldCode, &e.get()));
|
||||
}
|
||||
}
|
||||
|
||||
for (auto const& mapEntry : fields)
|
||||
// insert sorted
|
||||
for (auto const& e : fields)
|
||||
{
|
||||
// insert them in sorted order
|
||||
const STBase* field = mapEntry.second;
|
||||
auto const field = e.second;
|
||||
|
||||
// When we serialize an object inside another object,
|
||||
// the type associated by rule with this field name
|
||||
// must be OBJECT, or the object cannot be deserialized
|
||||
assert ((field->getSType() != STI_OBJECT) ||
|
||||
(field->getFName().fieldType == STI_OBJECT));
|
||||
|
||||
field->addFieldID (s);
|
||||
field->add (s);
|
||||
|
||||
if (dynamic_cast<const STArray*> (field) != nullptr)
|
||||
s.addFieldID (STI_ARRAY, 1);
|
||||
else if (dynamic_cast<const STObject*> (field) != nullptr)
|
||||
@@ -398,15 +311,15 @@ std::string STObject::getText () const
|
||||
{
|
||||
std::string ret = "{";
|
||||
bool first = false;
|
||||
for (STBase const& elem : mData)
|
||||
for (auto const& elem : v_)
|
||||
{
|
||||
if (!first)
|
||||
if (! first)
|
||||
{
|
||||
ret += ", ";
|
||||
first = false;
|
||||
}
|
||||
|
||||
ret += elem.getText ();
|
||||
ret += elem->getText ();
|
||||
}
|
||||
ret += "}";
|
||||
return ret;
|
||||
@@ -423,23 +336,23 @@ bool STObject::isEquivalent (const STBase& t) const
|
||||
return false;
|
||||
}
|
||||
|
||||
typedef boost::ptr_vector<STBase>::const_iterator const_iter;
|
||||
const_iter it1 = mData.begin (), end1 = mData.end ();
|
||||
const_iter it2 = v->mData.begin (), end2 = v->mData.end ();
|
||||
auto it1 = v_.begin (), end1 = v_.end ();
|
||||
auto it2 = v->v_.begin (), end2 = v->v_.end ();
|
||||
|
||||
while ((it1 != end1) && (it2 != end2))
|
||||
{
|
||||
if ((it1->getSType () != it2->getSType ()) || !it1->isEquivalent (*it2))
|
||||
if ((it1->get().getSType () != it2->get().getSType ()) ||
|
||||
!it1->get().isEquivalent (it2->get()))
|
||||
{
|
||||
if (it1->getSType () != it2->getSType ())
|
||||
if (it1->get().getSType () != it2->get().getSType ())
|
||||
{
|
||||
WriteLog (lsDEBUG, STObject) << "notEquiv type " <<
|
||||
it1->getFullText() << " != " << it2->getFullText();
|
||||
it1->get().getFullText() << " != " << it2->get().getFullText();
|
||||
}
|
||||
else
|
||||
{
|
||||
WriteLog (lsDEBUG, STObject) << "notEquiv " <<
|
||||
it1->getFullText() << " != " << it2->getFullText();
|
||||
it1->get().getFullText() << " != " << it2->get().getFullText();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@@ -473,11 +386,10 @@ int STObject::getFieldIndex (SField::ref field) const
|
||||
return mType->getIndex (field);
|
||||
|
||||
int i = 0;
|
||||
for (STBase const& elem : mData)
|
||||
for (auto const& elem : v_)
|
||||
{
|
||||
if (elem.getFName () == field)
|
||||
if (elem->getFName () == field)
|
||||
return i;
|
||||
|
||||
++i;
|
||||
}
|
||||
return -1;
|
||||
@@ -505,7 +417,7 @@ STBase& STObject::getField (SField::ref field)
|
||||
|
||||
SField::ref STObject::getFieldSType (int index) const
|
||||
{
|
||||
return mData[index].getFName ();
|
||||
return v_[index]->getFName ();
|
||||
}
|
||||
|
||||
const STBase* STObject::peekAtPField (SField::ref field) const
|
||||
@@ -525,7 +437,7 @@ STBase* STObject::getPField (SField::ref field, bool createOkay)
|
||||
if (index == -1)
|
||||
{
|
||||
if (createOkay && isFree ())
|
||||
return getPIndex (giveObject (makeDefaultObject (field)));
|
||||
return getPIndex(emplace_back(detail::defaultObject, field));
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
@@ -607,7 +519,7 @@ STBase* STObject::makeFieldPresent (SField::ref field)
|
||||
if (!isFree ())
|
||||
throw std::runtime_error ("Field not found");
|
||||
|
||||
return getPIndex (giveObject (makeNonPresentObject (field)));
|
||||
return getPIndex (emplace_back(detail::nonPresentObject, field));
|
||||
}
|
||||
|
||||
STBase* f = getPIndex (index);
|
||||
@@ -615,7 +527,8 @@ STBase* STObject::makeFieldPresent (SField::ref field)
|
||||
if (f->getSType () != STI_NOTPRESENT)
|
||||
return f;
|
||||
|
||||
mData.replace (index, makeDefaultObject (f->getFName ()).release ());
|
||||
v_[index] = detail::STVar(
|
||||
detail::defaultObject, f->getFName());
|
||||
return getPIndex (index);
|
||||
}
|
||||
|
||||
@@ -630,8 +543,8 @@ void STObject::makeFieldAbsent (SField::ref field)
|
||||
|
||||
if (f.getSType () == STI_NOTPRESENT)
|
||||
return;
|
||||
|
||||
mData.replace (index, makeNonPresentObject (f.getFName ()).release ());
|
||||
v_[index] = detail::STVar(
|
||||
detail::nonPresentObject, f.getFName());
|
||||
}
|
||||
|
||||
bool STObject::delField (SField::ref field)
|
||||
@@ -647,7 +560,7 @@ bool STObject::delField (SField::ref field)
|
||||
|
||||
void STObject::delField (int index)
|
||||
{
|
||||
mData.erase (mData.begin () + index);
|
||||
v_.erase (v_.begin () + index);
|
||||
}
|
||||
|
||||
std::string STObject::getFieldString (SField::ref field) const
|
||||
@@ -771,14 +684,14 @@ STObject::set (std::unique_ptr<STBase> v)
|
||||
getFieldIndex(v->getFName());
|
||||
if (i != -1)
|
||||
{
|
||||
mData.replace(i, v.release());
|
||||
v_[i] = std::move(*v);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (! isFree())
|
||||
throw std::runtime_error(
|
||||
"missing field in templated STObject");
|
||||
mData.push_back(v.release());
|
||||
v_.emplace_back(std::move(*v));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -862,14 +775,14 @@ Json::Value STObject::getJson (int options) const
|
||||
|
||||
// TODO(tom): this variable is never changed...?
|
||||
int index = 1;
|
||||
for (auto const& it: mData)
|
||||
for (auto const& elem : v_)
|
||||
{
|
||||
if (it.getSType () != STI_NOTPRESENT)
|
||||
if (elem->getSType () != STI_NOTPRESENT)
|
||||
{
|
||||
auto const& n = it.getFName ();
|
||||
auto const& n = elem->getFName ();
|
||||
auto key = n.hasName () ? std::string(n.getJsonName ()) :
|
||||
std::to_string (index);
|
||||
ret[key] = it.getJson (options);
|
||||
ret[key] = elem->getJson (options);
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
@@ -880,15 +793,15 @@ bool STObject::operator== (const STObject& obj) const
|
||||
// This is not particularly efficient, and only compares data elements
|
||||
// with binary representations
|
||||
int matches = 0;
|
||||
for (STBase const& t1 : mData)
|
||||
for (auto const& t1 : v_)
|
||||
{
|
||||
if ((t1.getSType () != STI_NOTPRESENT) && t1.getFName ().isBinary ())
|
||||
if ((t1->getSType () != STI_NOTPRESENT) && t1->getFName ().isBinary ())
|
||||
{
|
||||
// each present field must have a matching field
|
||||
bool match = false;
|
||||
for (STBase const& t2 : obj.mData)
|
||||
for (auto const& t2 : obj.v_)
|
||||
{
|
||||
if (t1.getFName () == t2.getFName ())
|
||||
if (t1->getFName () == t2->getFName ())
|
||||
{
|
||||
if (t2 != t1)
|
||||
return false;
|
||||
@@ -903,16 +816,16 @@ bool STObject::operator== (const STObject& obj) const
|
||||
{
|
||||
WriteLog (lsTRACE, STObject) <<
|
||||
"STObject::operator==: no match for " <<
|
||||
t1.getFName ().getName ();
|
||||
t1->getFName ().getName ();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int fields = 0;
|
||||
for (STBase const& t2 : obj.mData)
|
||||
for (auto const& t2 : obj.v_)
|
||||
{
|
||||
if ((t2.getSType () != STI_NOTPRESENT) && t2.getFName ().isBinary ())
|
||||
if ((t2->getSType () != STI_NOTPRESENT) && t2->getFName ().isBinary ())
|
||||
++fields;
|
||||
}
|
||||
|
||||
|
||||
@@ -50,14 +50,11 @@ STPathElement::get_hash (STPathElement const& element)
|
||||
return (hash_account ^ hash_currency ^ hash_issuer);
|
||||
}
|
||||
|
||||
std::unique_ptr<STBase>
|
||||
STPathSet::deserialize (SerialIter& sit, SField::ref name)
|
||||
STPathSet::STPathSet (SerialIter& sit, SField::ref name)
|
||||
: STBase(name)
|
||||
{
|
||||
std::vector<STPathElement> path;
|
||||
|
||||
auto pathset = std::make_unique <STPathSet> (name);
|
||||
|
||||
do
|
||||
for(;;)
|
||||
{
|
||||
int iType = sit.get8 ();
|
||||
|
||||
@@ -71,13 +68,11 @@ STPathSet::deserialize (SerialIter& sit, SField::ref name)
|
||||
throw std::runtime_error ("empty path");
|
||||
}
|
||||
|
||||
pathset->push_back (path);
|
||||
push_back (path);
|
||||
path.clear ();
|
||||
|
||||
if (iType == STPathElement::typeNone)
|
||||
{
|
||||
return std::move (pathset);
|
||||
}
|
||||
return;
|
||||
}
|
||||
else if (iType & ~STPathElement::typeAll)
|
||||
{
|
||||
@@ -108,7 +103,6 @@ STPathSet::deserialize (SerialIter& sit, SField::ref name)
|
||||
path.emplace_back (account, currency, issuer, hasCurrency);
|
||||
}
|
||||
}
|
||||
while (1);
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -127,7 +127,7 @@ STTx::getMentionedAccounts () const
|
||||
{
|
||||
std::vector<RippleAddress> accounts;
|
||||
|
||||
for (auto const& it : peekData ())
|
||||
for (auto const& it : *this)
|
||||
{
|
||||
if (auto sa = dynamic_cast<STAccount const*> (&it))
|
||||
{
|
||||
|
||||
183
src/ripple/protocol/impl/STVar.cpp
Normal file
183
src/ripple/protocol/impl/STVar.cpp
Normal file
@@ -0,0 +1,183 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#include <ripple/protocol/STAccount.h>
|
||||
#include <ripple/protocol/STAmount.h>
|
||||
#include <ripple/protocol/STArray.h>
|
||||
#include <ripple/protocol/STBase.h>
|
||||
#include <ripple/protocol/STBitString.h>
|
||||
#include <ripple/protocol/STBlob.h>
|
||||
#include <ripple/protocol/STInteger.h>
|
||||
#include <ripple/protocol/STObject.h>
|
||||
#include <ripple/protocol/STPathSet.h>
|
||||
#include <ripple/protocol/STVector256.h>
|
||||
#include <ripple/protocol/impl/STVar.h>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
defaultObject_t defaultObject;
|
||||
nonPresentObject_t nonPresentObject;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STVar::Log::~Log()
|
||||
{
|
||||
beast::debug_ostream os;
|
||||
for(auto const& e : map_)
|
||||
os << e.first << "," << e.second;
|
||||
}
|
||||
|
||||
void
|
||||
STVar::Log::operator() (std::size_t n)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(mutex_);
|
||||
auto const result = map_.emplace(n, 1);
|
||||
if (! result.second)
|
||||
++result.first->second;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
STVar::~STVar()
|
||||
{
|
||||
destroy();
|
||||
}
|
||||
|
||||
STVar::STVar (STVar const& other)
|
||||
: p_(nullptr)
|
||||
{
|
||||
if (other.p_ != nullptr)
|
||||
p_ = other.p_->copy(
|
||||
sizeof(d_), &d_);
|
||||
}
|
||||
|
||||
STVar::STVar (STVar&& other)
|
||||
{
|
||||
if (other.on_heap())
|
||||
{
|
||||
p_ = other.p_;
|
||||
other.p_ = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ = other.p_->move(
|
||||
sizeof(d_), &d_);
|
||||
}
|
||||
}
|
||||
|
||||
STVar&
|
||||
STVar::operator= (STVar const& rhs)
|
||||
{
|
||||
destroy();
|
||||
p_ = nullptr;
|
||||
if (rhs.p_)
|
||||
p_ = rhs.p_->copy(
|
||||
sizeof(d_), &d_);
|
||||
return *this;
|
||||
}
|
||||
|
||||
STVar&
|
||||
STVar::operator= (STVar&& rhs)
|
||||
{
|
||||
destroy();
|
||||
if (rhs.on_heap())
|
||||
{
|
||||
p_ = rhs.p_;
|
||||
rhs.p_ = nullptr;
|
||||
}
|
||||
else
|
||||
{
|
||||
p_ = nullptr;
|
||||
p_ = rhs.p_->move(
|
||||
sizeof(d_), &d_);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
STVar::STVar (defaultObject_t, SField::ref name)
|
||||
: STVar(name.fieldType, name)
|
||||
{
|
||||
}
|
||||
|
||||
STVar::STVar (nonPresentObject_t, SField::ref name)
|
||||
: STVar(STI_NOTPRESENT, name)
|
||||
{
|
||||
}
|
||||
|
||||
STVar::STVar (SerialIter& sit, SField::ref name)
|
||||
{
|
||||
switch (name.fieldType)
|
||||
{
|
||||
case STI_NOTPRESENT: construct<STBase>(name); return;
|
||||
case STI_UINT8: construct<STUInt8>(sit, name); return;
|
||||
case STI_UINT16: construct<STUInt16>(sit, name); return;
|
||||
case STI_UINT32: construct<STUInt32>(sit, name); return;
|
||||
case STI_UINT64: construct<STUInt64>(sit, name); return;
|
||||
case STI_AMOUNT: construct<STAmount>(sit, name); return;
|
||||
case STI_HASH128: construct<STHash128>(sit, name); return;
|
||||
case STI_HASH160: construct<STHash160>(sit, name); return;
|
||||
case STI_HASH256: construct<STHash256>(sit, name); return;
|
||||
case STI_VECTOR256: construct<STVector256>(sit, name); return;
|
||||
case STI_VL: construct<STBlob>(sit, name); return;
|
||||
case STI_ACCOUNT: construct<STAccount>(sit, name); return;
|
||||
case STI_PATHSET: construct<STPathSet>(sit, name); return;
|
||||
case STI_OBJECT: construct<STObject>(sit, name); return;
|
||||
case STI_ARRAY: construct<STArray>(sit, name); return;
|
||||
default:
|
||||
throw std::runtime_error ("Unknown object type");
|
||||
}
|
||||
}
|
||||
|
||||
STVar::STVar (SerializedTypeID id, SField::ref name)
|
||||
{
|
||||
assert ((id == STI_NOTPRESENT) || (id == name.fieldType));
|
||||
switch (id)
|
||||
{
|
||||
case STI_NOTPRESENT: construct<STBase>(name); return;
|
||||
case STI_UINT8: construct<STUInt8>(name); return;
|
||||
case STI_UINT16: construct<STUInt16>(name); return;
|
||||
case STI_UINT32: construct<STUInt32>(name); return;
|
||||
case STI_UINT64: construct<STUInt64>(name); return;
|
||||
case STI_AMOUNT: construct<STAmount>(name); return;
|
||||
case STI_HASH128: construct<STHash128>(name); return;
|
||||
case STI_HASH160: construct<STHash160>(name); return;
|
||||
case STI_HASH256: construct<STHash256>(name); return;
|
||||
case STI_VECTOR256: construct<STVector256>(name); return;
|
||||
case STI_VL: construct<STBlob>(name); return;
|
||||
case STI_ACCOUNT: construct<STAccount>(name); return;
|
||||
case STI_PATHSET: construct<STPathSet>(name); return;
|
||||
case STI_OBJECT: construct<STObject>(name); return;
|
||||
case STI_ARRAY: construct<STArray>(name); return;
|
||||
default:
|
||||
throw std::runtime_error ("Unknown object type");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
STVar::destroy()
|
||||
{
|
||||
if (on_heap())
|
||||
delete p_;
|
||||
else
|
||||
p_->~STBase();
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // ripple
|
||||
133
src/ripple/protocol/impl/STVar.h
Normal file
133
src/ripple/protocol/impl/STVar.h
Normal file
@@ -0,0 +1,133 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2012, 2013 Ripple Labs Inc.
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL , DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
//==============================================================================
|
||||
|
||||
#ifndef RIPPLE_PROTOCOL_STVAR_H_INCLUDED
|
||||
#define RIPPLE_PROTOCOL_STVAR_H_INCLUDED
|
||||
|
||||
#include <ripple/protocol/Serializer.h>
|
||||
#include <ripple/protocol/SField.h>
|
||||
#include <ripple/protocol/STBase.h>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <utility>
|
||||
#include <typeinfo>
|
||||
|
||||
#include <beast/streams/debug_ostream.h>
|
||||
#include <beast/utility/static_initializer.h>
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
|
||||
namespace ripple {
|
||||
namespace detail {
|
||||
|
||||
struct defaultObject_t { };
|
||||
struct nonPresentObject_t { };
|
||||
|
||||
extern defaultObject_t defaultObject;
|
||||
extern nonPresentObject_t nonPresentObject;
|
||||
|
||||
// "variant" that can hold any type of serialized object
|
||||
// and includes a small-object allocation optimization.
|
||||
class STVar
|
||||
{
|
||||
private:
|
||||
std::aligned_storage<72>::type d_;
|
||||
STBase* p_ = nullptr;
|
||||
|
||||
struct Log
|
||||
{
|
||||
std::mutex mutex_;
|
||||
std::unordered_map<
|
||||
std::size_t, std::size_t> map_;
|
||||
|
||||
~Log();
|
||||
void operator() (std::size_t n);
|
||||
};
|
||||
|
||||
public:
|
||||
~STVar();
|
||||
STVar (STVar const& other);
|
||||
STVar (STVar&& other);
|
||||
STVar& operator= (STVar const& rhs);
|
||||
STVar& operator= (STVar&& rhs);
|
||||
|
||||
STVar (STBase&& t)
|
||||
{
|
||||
p_ = t.move(sizeof(d_), &d_);
|
||||
}
|
||||
|
||||
STVar (STBase const& t)
|
||||
{
|
||||
p_ = t.copy(sizeof(d_), &d_);
|
||||
}
|
||||
|
||||
STVar (defaultObject_t, SField::ref name);
|
||||
STVar (nonPresentObject_t, SField::ref name);
|
||||
STVar (SerialIter& sit, SField::ref name);
|
||||
|
||||
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(); }
|
||||
|
||||
private:
|
||||
STVar (SerializedTypeID id, SField::ref name);
|
||||
|
||||
void destroy();
|
||||
|
||||
template <class T, class... Args>
|
||||
void
|
||||
construct(Args&&... args)
|
||||
{
|
||||
if(sizeof(T) > sizeof(d_))
|
||||
p_ = new T(
|
||||
std::forward<Args>(args)...);
|
||||
else
|
||||
p_ = new(&d_) T(
|
||||
std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
bool
|
||||
on_heap() const
|
||||
{
|
||||
return static_cast<void const*>(p_) !=
|
||||
static_cast<void const*>(&d_);
|
||||
}
|
||||
};
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
} // detail
|
||||
} // ripple
|
||||
|
||||
#endif
|
||||
@@ -25,31 +25,22 @@
|
||||
|
||||
namespace ripple {
|
||||
|
||||
std::unique_ptr<STBase>
|
||||
STVector256::deserialize (SerialIter& sit, SField::ref name)
|
||||
STVector256::STVector256(SerialIter& sit, SField::ref name)
|
||||
: STBase(name)
|
||||
{
|
||||
auto vec = std::make_unique<STVector256> (name);
|
||||
|
||||
Blob data = sit.getVL ();
|
||||
|
||||
auto const count = data.size () / (256 / 8);
|
||||
|
||||
vec->mValue.reserve (count);
|
||||
|
||||
mValue.reserve (count);
|
||||
Blob::iterator begin = data.begin ();
|
||||
unsigned int uStart = 0;
|
||||
|
||||
for (unsigned int i = 0; i != count; i++)
|
||||
{
|
||||
unsigned int uEnd = uStart + (256 / 8);
|
||||
|
||||
// This next line could be optimized to construct a default uint256
|
||||
// in the vector and then copy into it
|
||||
vec->mValue.push_back (uint256 (Blob (begin + uStart, begin + uEnd)));
|
||||
unsigned int uEnd = uStart + (256 / 8);
|
||||
// This next line could be optimized to construct a default
|
||||
// uint256 in the vector and then copy into it
|
||||
mValue.push_back (uint256 (Blob (begin + uStart, begin + uEnd)));
|
||||
uStart = uEnd;
|
||||
}
|
||||
|
||||
return std::move (vec);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
Reference in New Issue
Block a user