Files
rippled/include/xrpl/nodestore/detail/varint.h
Pratik Mankawde 3547112540 fix: Fix ubsan flagged issues (#6151)
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>
2026-04-27 20:34:16 +00:00

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