mirror of
https://github.com/Xahau/xahaud.git
synced 2026-09-26 23:29:04 +00:00
This commit makes several changes to the base_uint class, which was originally taken from Bitcoin and has already been heavily modified by Ripple engineers. It introduces conditional widening of the internal limb type, going from 32 to 64 bits if the requested number of bits is a multiple of 64. This change alone halves iteration counts for common operations and, combined with use of add-with-carry compiler intrinsics, helps leverage modern processor resources more effectively. Other changes include: - Extracting the arithmetic operations into free helper functions which operate on the limb array directly. - Replacing the SFINAE-based is_contiguous_container trait with a byte_copy_source concept. - Rewriting the hex parsing around a consteval lookup table and a simple left-to-right loop, replacing the old shift-based nibble accumulator. - Using memmove instead of memcpy when copying to avoid UB in the unlikely case where the source and destination buffers overlap. - Eliminating a workaround in operator<=> to handle MacOS quirks. - Removing redundant parseHex overloads and introducing from_hex as a factory function. - Introducing a tagless_compare() for cross-tag comparison. - Adding noexcept, [[nodiscard]], and constexpr throughout.
478 lines
9.9 KiB
C++
478 lines
9.9 KiB
C++
//------------------------------------------------------------------------------
|
|
/*
|
|
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_SERIALIZER_H_INCLUDED
|
|
#define RIPPLE_PROTOCOL_SERIALIZER_H_INCLUDED
|
|
|
|
#include <xrpl/basics/Blob.h>
|
|
#include <xrpl/basics/Buffer.h>
|
|
#include <xrpl/basics/Slice.h>
|
|
#include <xrpl/basics/base_uint.h>
|
|
#include <xrpl/basics/contract.h>
|
|
#include <xrpl/basics/safe_cast.h>
|
|
#include <xrpl/basics/strHex.h>
|
|
#include <xrpl/beast/utility/instrumentation.h>
|
|
#include <xrpl/protocol/HashPrefix.h>
|
|
#include <xrpl/protocol/SField.h>
|
|
#include <cstdint>
|
|
#include <cstring>
|
|
#include <iomanip>
|
|
#include <type_traits>
|
|
|
|
namespace ripple {
|
|
|
|
class Serializer
|
|
{
|
|
private:
|
|
// DEPRECATED
|
|
Blob mData;
|
|
|
|
public:
|
|
explicit Serializer(int n = 256)
|
|
{
|
|
mData.reserve(n);
|
|
}
|
|
|
|
Serializer(void const* data, std::size_t size)
|
|
{
|
|
mData.resize(size);
|
|
|
|
if (size)
|
|
{
|
|
XRPL_ASSERT(
|
|
data,
|
|
"ripple::Serializer::Serializer(void const*) : non-null input");
|
|
std::memcpy(mData.data(), data, size);
|
|
}
|
|
}
|
|
|
|
Slice
|
|
slice() const noexcept
|
|
{
|
|
return Slice(mData.data(), mData.size());
|
|
}
|
|
|
|
std::size_t
|
|
size() const noexcept
|
|
{
|
|
return mData.size();
|
|
}
|
|
|
|
void const*
|
|
data() const noexcept
|
|
{
|
|
return mData.data();
|
|
}
|
|
|
|
// assemble functions
|
|
int
|
|
add8(unsigned char i);
|
|
int
|
|
add16(std::uint16_t i);
|
|
|
|
template <typename T>
|
|
requires(std::is_same_v<
|
|
std::make_unsigned_t<std::remove_cv_t<T>>,
|
|
std::uint32_t>)
|
|
int
|
|
add32(T i)
|
|
{
|
|
int ret = mData.size();
|
|
mData.push_back(static_cast<unsigned char>((i >> 24) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>((i >> 16) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>((i >> 8) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>(i & 0xff));
|
|
return ret;
|
|
}
|
|
|
|
int
|
|
add32(HashPrefix p);
|
|
|
|
template <typename T>
|
|
requires(std::is_same_v<
|
|
std::make_unsigned_t<std::remove_cv_t<T>>,
|
|
std::uint64_t>)
|
|
int
|
|
add64(T i)
|
|
{
|
|
int ret = mData.size();
|
|
mData.push_back(static_cast<unsigned char>((i >> 56) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>((i >> 48) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>((i >> 40) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>((i >> 32) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>((i >> 24) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>((i >> 16) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>((i >> 8) & 0xff));
|
|
mData.push_back(static_cast<unsigned char>(i & 0xff));
|
|
return ret;
|
|
}
|
|
|
|
template <typename Integer>
|
|
int addInteger(Integer);
|
|
|
|
template <std::size_t Bits, class Tag>
|
|
int
|
|
addBitString(base_uint<Bits, Tag> const& v)
|
|
{
|
|
return addRaw(v.data(), v.size());
|
|
}
|
|
|
|
int
|
|
addRaw(Blob const& vector);
|
|
int
|
|
addRaw(Slice slice);
|
|
int
|
|
addRaw(const void* ptr, int len);
|
|
int
|
|
addRaw(const Serializer& s);
|
|
|
|
int
|
|
addVL(Blob const& vector);
|
|
int
|
|
addVL(Slice const& slice);
|
|
template <class Iter>
|
|
int
|
|
addVL(Iter begin, Iter end, int len);
|
|
int
|
|
addVL(const void* ptr, int len);
|
|
|
|
// disassemble functions
|
|
bool
|
|
get8(int&, int offset) const;
|
|
|
|
template <typename Integer>
|
|
bool
|
|
getInteger(Integer& number, int offset)
|
|
{
|
|
static const auto bytes = sizeof(Integer);
|
|
if ((offset + bytes) > mData.size())
|
|
return false;
|
|
number = 0;
|
|
|
|
auto ptr = &mData[offset];
|
|
for (auto i = 0; i < bytes; ++i)
|
|
{
|
|
if (i)
|
|
number <<= 8;
|
|
number |= *ptr++;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
template <std::size_t Bits, typename Tag = void>
|
|
bool
|
|
getBitString(base_uint<Bits, Tag>& data, int offset) const
|
|
{
|
|
auto success = (offset + (Bits / 8)) <= mData.size();
|
|
if (success)
|
|
memcpy(data.begin(), &(mData.front()) + offset, (Bits / 8));
|
|
return success;
|
|
}
|
|
|
|
int
|
|
addFieldID(int type, int name);
|
|
int
|
|
addFieldID(SerializedTypeID type, int name)
|
|
{
|
|
return addFieldID(safe_cast<int>(type), name);
|
|
}
|
|
|
|
// DEPRECATED
|
|
uint256
|
|
getSHA512Half() const;
|
|
|
|
// totality functions
|
|
Blob const&
|
|
peekData() const
|
|
{
|
|
return mData;
|
|
}
|
|
Blob
|
|
getData() const
|
|
{
|
|
return mData;
|
|
}
|
|
Blob&
|
|
modData()
|
|
{
|
|
return mData;
|
|
}
|
|
|
|
int
|
|
getDataLength() const
|
|
{
|
|
return mData.size();
|
|
}
|
|
const void*
|
|
getDataPtr() const
|
|
{
|
|
return mData.data();
|
|
}
|
|
void*
|
|
getDataPtr()
|
|
{
|
|
return mData.data();
|
|
}
|
|
int
|
|
getLength() const
|
|
{
|
|
return mData.size();
|
|
}
|
|
std::string
|
|
getString() const
|
|
{
|
|
return std::string(static_cast<const char*>(getDataPtr()), size());
|
|
}
|
|
void
|
|
erase()
|
|
{
|
|
mData.clear();
|
|
}
|
|
bool
|
|
chop(int num);
|
|
|
|
// vector-like functions
|
|
Blob ::iterator
|
|
begin()
|
|
{
|
|
return mData.begin();
|
|
}
|
|
Blob ::iterator
|
|
end()
|
|
{
|
|
return mData.end();
|
|
}
|
|
Blob ::const_iterator
|
|
begin() const
|
|
{
|
|
return mData.begin();
|
|
}
|
|
Blob ::const_iterator
|
|
end() const
|
|
{
|
|
return mData.end();
|
|
}
|
|
void
|
|
reserve(size_t n)
|
|
{
|
|
mData.reserve(n);
|
|
}
|
|
void
|
|
resize(size_t n)
|
|
{
|
|
mData.resize(n);
|
|
}
|
|
size_t
|
|
capacity() const
|
|
{
|
|
return mData.capacity();
|
|
}
|
|
|
|
bool
|
|
operator==(Blob const& v) const
|
|
{
|
|
return v == mData;
|
|
}
|
|
bool
|
|
operator!=(Blob const& v) const
|
|
{
|
|
return v != mData;
|
|
}
|
|
bool
|
|
operator==(const Serializer& v) const
|
|
{
|
|
return v.mData == mData;
|
|
}
|
|
bool
|
|
operator!=(const Serializer& v) const
|
|
{
|
|
return v.mData != mData;
|
|
}
|
|
|
|
static int
|
|
decodeLengthLength(int b1);
|
|
static int
|
|
decodeVLLength(int b1);
|
|
static int
|
|
decodeVLLength(int b1, int b2);
|
|
static int
|
|
decodeVLLength(int b1, int b2, int b3);
|
|
|
|
private:
|
|
static int
|
|
encodeLengthLength(int length); // length to encode length
|
|
int
|
|
addEncoded(int length);
|
|
};
|
|
|
|
template <class Iter>
|
|
int
|
|
Serializer::addVL(Iter begin, Iter end, int len)
|
|
{
|
|
int ret = addEncoded(len);
|
|
for (; begin != end; ++begin)
|
|
{
|
|
addRaw(begin->data(), begin->size());
|
|
#ifndef NDEBUG
|
|
len -= begin->size();
|
|
#endif
|
|
}
|
|
XRPL_ASSERT(
|
|
len == 0, "ripple::Serializer::addVL : length matches distance");
|
|
return ret;
|
|
}
|
|
|
|
//------------------------------------------------------------------------------
|
|
|
|
// DEPRECATED
|
|
// Transitional adapter to new serialization interfaces
|
|
class SerialIter
|
|
{
|
|
private:
|
|
std::uint8_t const* p_;
|
|
std::size_t remain_;
|
|
std::size_t used_ = 0;
|
|
|
|
public:
|
|
SerialIter(void const* data, std::size_t size) noexcept;
|
|
|
|
SerialIter(Slice const& slice) : SerialIter(slice.data(), slice.size())
|
|
{
|
|
}
|
|
|
|
// Infer the size of the data based on the size of the passed array.
|
|
template <int N>
|
|
explicit SerialIter(std::uint8_t const (&data)[N]) : SerialIter(&data[0], N)
|
|
{
|
|
static_assert(N > 0, "");
|
|
}
|
|
|
|
std::size_t
|
|
empty() const noexcept
|
|
{
|
|
return remain_ == 0;
|
|
}
|
|
|
|
void
|
|
reset() noexcept;
|
|
|
|
int
|
|
getBytesLeft() const noexcept
|
|
{
|
|
return static_cast<int>(remain_);
|
|
}
|
|
|
|
// get functions throw on error
|
|
unsigned char
|
|
get8();
|
|
|
|
std::uint16_t
|
|
get16();
|
|
|
|
std::uint32_t
|
|
get32();
|
|
std::int32_t
|
|
geti32();
|
|
|
|
std::uint64_t
|
|
get64();
|
|
std::int64_t
|
|
geti64();
|
|
|
|
template <std::size_t Bits, class Tag = void>
|
|
base_uint<Bits, Tag>
|
|
getBitString();
|
|
|
|
uint128
|
|
get128()
|
|
{
|
|
return getBitString<128>();
|
|
}
|
|
|
|
uint160
|
|
get160()
|
|
{
|
|
return getBitString<160>();
|
|
}
|
|
|
|
uint192
|
|
get192()
|
|
{
|
|
return getBitString<192>();
|
|
}
|
|
|
|
uint256
|
|
get256()
|
|
{
|
|
return getBitString<256>();
|
|
}
|
|
|
|
void
|
|
getFieldID(int& type, int& name);
|
|
|
|
// Returns the size of the VL if the
|
|
// next object is a VL. Advances the iterator
|
|
// to the beginning of the VL.
|
|
int
|
|
getVLDataLength();
|
|
|
|
Slice
|
|
getSlice(std::size_t bytes);
|
|
|
|
// VFALCO DEPRECATED Returns a copy
|
|
Blob
|
|
getRaw(int size);
|
|
|
|
// VFALCO DEPRECATED Returns a copy
|
|
Blob
|
|
getVL();
|
|
|
|
void
|
|
skip(int num);
|
|
|
|
Buffer
|
|
getVLBuffer();
|
|
|
|
template <class T>
|
|
T
|
|
getRawHelper(int size);
|
|
};
|
|
|
|
template <std::size_t Bits, class Tag>
|
|
base_uint<Bits, Tag>
|
|
SerialIter::getBitString()
|
|
{
|
|
auto constexpr N = base_uint<Bits, Tag>::bytes;
|
|
|
|
if (remain_ < N)
|
|
Throw<std::runtime_error>("invalid SerialIter getBitString");
|
|
|
|
auto const x = p_;
|
|
|
|
p_ += N;
|
|
used_ += N;
|
|
remain_ -= N;
|
|
|
|
return base_uint<Bits, Tag>(std::span<uint8_t const, N>{x, N});
|
|
}
|
|
|
|
} // namespace ripple
|
|
|
|
#endif
|