mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-03 16:56:48 +00:00
Signed-off-by: Pratik Mankawde <3397372+pratikmankawde@users.noreply.github.com> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
123 lines
2.5 KiB
C++
123 lines
2.5 KiB
C++
#pragma once
|
|
|
|
#include <nudb/detail/stream.hpp>
|
|
|
|
#include <cstdint>
|
|
#include <type_traits>
|
|
|
|
namespace xrpl::NodeStore {
|
|
|
|
// This is a variant of the base128 varint format from
|
|
// google protocol buffers:
|
|
// https://developers.google.com/protocol-buffers/docs/encoding#varints
|
|
|
|
// field tag
|
|
struct varint;
|
|
|
|
// Metafuncton to return largest
|
|
// possible size of T represented as varint.
|
|
// T must be unsigned
|
|
template <class T, bool = std::is_unsigned_v<T>>
|
|
struct varint_traits;
|
|
|
|
template <class T>
|
|
struct varint_traits<T, true>
|
|
{
|
|
explicit varint_traits() = default;
|
|
|
|
static std::size_t constexpr max = (8 * sizeof(T) + 6) / 7;
|
|
};
|
|
|
|
// Returns: Number of bytes consumed or 0 on error,
|
|
// if the buffer was too small or t overflowed.
|
|
//
|
|
template <class = void>
|
|
std::size_t
|
|
read_varint(void const* buf, std::size_t buflen, std::size_t& t)
|
|
{
|
|
if (buflen == 0)
|
|
return 0;
|
|
t = 0;
|
|
std::uint8_t const* p = reinterpret_cast<std::uint8_t const*>(buf);
|
|
std::size_t n = 0;
|
|
while (p[n] & 0x80)
|
|
{
|
|
if (++n >= buflen)
|
|
return 0;
|
|
}
|
|
if (++n > buflen)
|
|
return 0;
|
|
// Special case for 0
|
|
if (n == 1 && *p == 0)
|
|
{
|
|
t = 0;
|
|
return 1;
|
|
}
|
|
auto const used = n;
|
|
while (n > 0)
|
|
{
|
|
--n;
|
|
auto const d = p[n];
|
|
auto const t0 = t;
|
|
t *= 127;
|
|
t += d & 0x7f;
|
|
if (t <= t0)
|
|
return 0; // overflow
|
|
}
|
|
return used;
|
|
}
|
|
|
|
template <class T, std::enable_if_t<std::is_unsigned_v<T>>* = nullptr>
|
|
std::size_t
|
|
size_varint(T v)
|
|
{
|
|
std::size_t n = 0;
|
|
do
|
|
{
|
|
v /= 127;
|
|
++n;
|
|
} while (v != 0);
|
|
return n;
|
|
}
|
|
|
|
template <class = void>
|
|
std::size_t
|
|
write_varint(void* p0, std::size_t v)
|
|
{
|
|
// NOLINTNEXTLINE(misc-const-correctness)
|
|
std::uint8_t* p = reinterpret_cast<std::uint8_t*>(p0);
|
|
do
|
|
{
|
|
std::uint8_t d = v % 127;
|
|
v /= 127;
|
|
if (v != 0)
|
|
d |= 0x80;
|
|
*p++ = d;
|
|
} while (v != 0);
|
|
return p - reinterpret_cast<std::uint8_t*>(p0);
|
|
}
|
|
|
|
// input stream
|
|
|
|
template <class T, std::enable_if_t<std::is_same_v<T, varint>>* = nullptr>
|
|
void
|
|
read(nudb::detail::istream& is, std::size_t& u)
|
|
{
|
|
auto p0 = is(1);
|
|
auto p1 = p0;
|
|
while (*p1++ & 0x80)
|
|
is(1);
|
|
read_varint(p0, p1 - p0, u);
|
|
}
|
|
|
|
// output stream
|
|
|
|
template <class T, std::enable_if_t<std::is_same_v<T, varint>>* = nullptr>
|
|
void
|
|
write(nudb::detail::ostream& os, std::size_t t)
|
|
{
|
|
write_varint(os.data(size_varint(t)), t);
|
|
}
|
|
|
|
} // namespace xrpl::NodeStore
|