xrpld
Loading...
Searching...
No Matches
base_uint.h
1// Copyright (c) 2009-2010 Satoshi Nakamoto
2// Copyright (c) 2011 The Bitcoin developers
3// Distributed under the MIT/X11 software license, see the accompanying
4// file license.txt or http://www.opensource.org/licenses/mit-license.php.
5
6#pragma once
7
8#include <xrpl/basics/Slice.h>
9#include <xrpl/basics/contract.h>
10#include <xrpl/basics/hardened_hash.h>
11#include <xrpl/basics/partitioned_unordered_map.h>
12#include <xrpl/basics/strHex.h>
13#include <xrpl/beast/hash/hash_append.h>
14#include <xrpl/beast/utility/Zero.h>
15#include <xrpl/beast/utility/instrumentation.h>
16
17#include <boost/endian/conversion.hpp>
18#include <boost/functional/hash.hpp>
19
20#include <algorithm>
21#include <array>
22#include <compare>
23#include <cstddef>
24#include <cstdint>
25#include <cstring>
26#include <expected>
27#include <iterator>
28#include <optional>
29#include <ostream>
30#include <stdexcept>
31#include <string>
32#include <string_view>
33#include <type_traits>
34
35namespace xrpl {
36
37namespace detail {
38
39template <class Container, class = std::void_t<>>
43
44template <class Container>
46 Container,
47 std::void_t<
48 decltype(std::declval<Container const>().size()),
49 decltype(std::declval<Container const>().data()),
50 typename Container::value_type>> : std::true_type
51{
52};
53
54template <>
58
59template <typename...>
63
64} // namespace detail
65
80template <std::size_t Bits, class Tag = void>
82{
83 static_assert((Bits % 32) == 0, "The length of a base_uint in bits must be a multiple of 32.");
84
85 static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64.");
86
87 static constexpr std::size_t kWidth = Bits / 32;
88
89 // This is really big-endian in byte order.
90 // We sometimes use std::uint32_t for speed.
91
93
94public:
95 //--------------------------------------------------------------------------
96 //
97 // STL Container Interface
98 //
99
100 static constexpr std::size_t kBytes = Bits / 8;
101 static_assert(sizeof(data_) == kBytes);
102
105 using value_type = unsigned char;
108 using const_pointer = value_type const*;
114 using tag_type = Tag;
115
116 pointer
118 {
119 return reinterpret_cast<pointer>(data_.data());
120 }
121 [[nodiscard]] const_pointer
122 data() const
123 {
124 return reinterpret_cast<const_pointer>(data_.data());
125 }
126
127 iterator
129 {
130 return data();
131 }
132 iterator
134 {
135 return data() + kBytes;
136 }
137 [[nodiscard]] const_iterator
138 begin() const
139 {
140 return data();
141 }
142 [[nodiscard]] const_iterator
143 end() const
144 {
145 return data() + kBytes;
146 }
147 [[nodiscard]] const_iterator
148 cbegin() const
149 {
150 return data();
151 }
152 [[nodiscard]] const_iterator
153 cend() const
154 {
155 return data() + kBytes;
156 }
157
164
165 //--------------------------------------------------------------------------
166
167private:
175 // NIKB TODO Remove the need for this constructor.
177 {
178 explicit VoidHelper() = default;
179 };
180
181 explicit BaseUInt(void const* data, VoidHelper)
182 {
183 memcpy(data_.data(), data, kBytes);
184 }
185
186 // Helper function to initialize a base_uint from a std::string_view.
187 enum class ParseResult {
188 Okay,
189 BadLength,
190 BadChar,
191 };
192
193 constexpr std::expected<decltype(data_), ParseResult>
195 {
196 // Local lambda that converts a single hex char to four bits and
197 // ORs those bits into a uint32_t.
198 auto hexCharToUInt = [](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult {
199 std::uint32_t nibble = 0xFFu;
200 if (c < '0' || c > 'f')
201 return ParseResult::BadChar;
202
203 if (c >= 'a')
204 {
205 nibble = static_cast<std::uint32_t>(c - 'a' + 0xA);
206 }
207 else if (c >= 'A')
208 {
209 nibble = static_cast<std::uint32_t>(c - 'A' + 0xA);
210 }
211 else if (c <= '9')
212 {
213 nibble = static_cast<std::uint32_t>(c - '0');
214 }
215
216 if (nibble > 0xFu)
217 return ParseResult::BadChar;
218
219 accum |= (nibble << shift);
220
221 return ParseResult::Okay;
222 };
223
224 decltype(data_) ret{};
225
226 if (sv == "0")
227 {
228 return ret;
229 }
230
231 if (sv.size() != size() * 2)
232 return std::unexpected(ParseResult::BadLength);
233
234 std::size_t i = 0u;
235 auto in = sv.begin();
236 while (in != sv.end())
237 {
238 std::uint32_t accum = {};
239 for (std::uint32_t const shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
240 {
241 if (auto const result = hexCharToUInt(*in++, shift, accum);
242 result != ParseResult::Okay)
243 return std::unexpected(result);
244 }
245 ret[i++] = accum;
246 }
247 return ret;
248 }
249
250 constexpr decltype(data_)
252 {
253 auto const result = parseFromStringView(sv);
254 if (!result)
255 {
256 if (result.error() == ParseResult::BadLength)
257 Throw<std::invalid_argument>("invalid length for hex string");
258
259 Throw<std::range_error>("invalid hex character");
260 }
261 return *result;
262 }
263
264public:
265 constexpr BaseUInt() : data_{}
266 {
267 }
268
270 {
271 }
272
274 {
275 *this = b;
276 }
277
278 // This constructor is intended to be used at compile time since it might
279 // throw at runtime. Consider declaring this constructor consteval once
280 // we get to C++23.
281 explicit constexpr BaseUInt(std::string_view sv) noexcept(false)
283 {
284 }
285
286 template <class Container>
287 explicit BaseUInt(Container const& c)
288 requires(
291 {
292 // Use AlwaysFalseT so the static_assert condition is dependent
293 // and only triggers when this constructor template is instantiated.
294 static_assert(
296 "This constructor is not intended to be used and will be soon removed. "
297 "Use base_uint::fromRaw instead.");
298 }
299
300 template <class Container>
301 static BaseUInt
302 fromRaw(Container const& c)
303 requires(
306 {
307 BaseUInt result;
308 XRPL_ASSERT(
309 c.size() * sizeof(typename Container::value_type) == size(),
310 "xrpl::BaseUInt::fromRaw(Container auto) : input size match");
311 std::size_t const canCopy =
312 std::min(size(), c.size() * sizeof(typename Container::value_type));
313 std::memcpy(result.data_.data(), c.data(), canCopy);
314 return result;
315 }
316
317 template <class Container>
318 BaseUInt&
319 operator=(Container const& c)
320 requires(
323 {
324 XRPL_ASSERT(
325 c.size() * sizeof(typename Container::value_type) == size(),
326 "xrpl::BaseUInt::operator=(Container auto) : input size match");
327 std::size_t const canCopy =
328 std::min(size(), c.size() * sizeof(typename Container::value_type));
329 if (canCopy < size())
330 *this = beast::kZero;
331 std::memcpy(data_.data(), c.data(), canCopy);
332 return *this;
333 }
334
335 /* Construct from a raw pointer.
336 The buffer pointed to by `data` must be at least Bits/8 bytes.
337 */
338 static BaseUInt
339 fromVoid(void const* data)
340 {
341 return BaseUInt(data, VoidHelper());
342 }
343
344 template <class T>
346 fromVoidChecked(T const& from)
347 {
348 if (from.size() != size())
349 return {};
350 return fromVoid(from.data());
351 }
352
353 [[nodiscard]] constexpr int
354 signum() const
355 {
356 for (int i = 0; i < kWidth; i++)
357 {
358 if (data_[i] != 0)
359 return 1;
360 }
361
362 return 0;
363 }
364
365 bool
366 operator!() const
367 {
368 return *this == beast::kZero;
369 }
370
371 constexpr BaseUInt
372 operator~() const
373 {
374 BaseUInt ret;
375
376 for (int i = 0; i < kWidth; i++)
377 ret.data_[i] = ~data_[i];
378
379 return ret;
380 }
381
382 BaseUInt&
384 {
385 *this = beast::kZero;
386 // NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
387 union
388 {
389 unsigned u[2];
390 std::uint64_t ul;
391 };
392 // NOLINTEND(cppcoreguidelines-pro-type-member-init)
393 // Put in least significant bits.
394 ul = boost::endian::native_to_big(uHost);
395 data_[kWidth - 2] = u[0];
396 data_[kWidth - 1] = u[1];
397 return *this;
398 }
399
400 BaseUInt&
402 {
403 for (int i = 0; i < kWidth; i++)
404 data_[i] ^= b.data_[i];
405
406 return *this;
407 }
408
409 BaseUInt&
411 {
412 for (int i = 0; i < kWidth; i++)
413 data_[i] &= b.data_[i];
414
415 return *this;
416 }
417
418 BaseUInt&
420 {
421 for (int i = 0; i < kWidth; i++)
422 data_[i] |= b.data_[i];
423
424 return *this;
425 }
426
427 BaseUInt&
429 {
430 // prefix operator
431 for (int i = kWidth - 1; i >= 0; --i)
432 {
433 data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1);
434 if (data_[i] != 0)
435 break;
436 }
437
438 return *this;
439 }
440
443 {
444 // postfix operator
445 BaseUInt const ret = *this;
446 ++(*this);
447
448 return ret;
449 }
450
451 BaseUInt&
453 {
454 for (int i = kWidth - 1; i >= 0; --i)
455 {
456 auto prev = data_[i];
457 data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
458
459 if (prev != 0)
460 break;
461 }
462
463 return *this;
464 }
465
468 {
469 // postfix operator
470 BaseUInt const ret = *this;
471 --(*this);
472
473 return ret;
474 }
475
476 [[nodiscard]] BaseUInt
477 next() const
478 {
479 auto ret = *this;
480 return ++ret;
481 }
482
483 [[nodiscard]] BaseUInt
484 prev() const
485 {
486 auto ret = *this;
487 return --ret;
488 }
489
490 BaseUInt&
492 {
493 std::uint64_t carry = 0;
494
495 for (int i = kWidth - 1; i >= 0; i--)
496 {
497 std::uint64_t const n = carry + boost::endian::big_to_native(data_[i]) +
498 boost::endian::big_to_native(b.data_[i]);
499
500 data_[i] = boost::endian::native_to_big(static_cast<std::uint32_t>(n));
501 carry = n >> 32;
502 }
503
504 return *this;
505 }
506
507 template <class Hasher>
508 friend void
509 hash_append(Hasher& h, BaseUInt const& a) noexcept
510 {
511 // Do not allow any endian transformations on this memory
512 h(a.data_.data(), sizeof(a.data_));
513 }
514
524 [[nodiscard]] constexpr bool
526 {
527 auto const result = parseFromStringView(sv);
528 if (!result)
529 return false;
530
531 data_ = *result;
532 return true;
533 }
534
535 [[nodiscard]] constexpr bool
536 parseHex(char const* str)
537 {
538 return parseHex(std::string_view{str});
539 }
540
541 [[nodiscard]] bool
543 {
544 return parseHex(std::string_view{str});
545 }
546
547 static constexpr std::size_t
549 {
550 return kBytes;
551 }
552
555 {
556 data_.fill(0);
557 return *this;
558 }
559
560 // Deprecated.
561 [[nodiscard]] bool
562 isZero() const
563 {
564 return *this == beast::kZero;
565 }
566 [[nodiscard]] bool
567 isNonZero() const
568 {
569 return *this != beast::kZero;
570 }
571 void
573 {
574 *this = beast::kZero;
575 }
576};
577
582
583template <std::size_t Bits, class Tag>
584[[nodiscard]] constexpr std::strong_ordering
586{
587 // This comparison might seem wrong on a casual inspection because it
588 // compares data internally stored as std::uint32_t byte-by-byte. But
589 // note that the underlying data is stored in big endian, even if the
590 // platform is little endian. This makes the comparison correct.
591 //
592 // FIXME: use std::lexicographical_compare_three_way once support is
593 // added to MacOS.
594
595 auto const ret = std::mismatch(lhs.cbegin(), lhs.cend(), rhs.cbegin());
596
597 // a == b
598 if (ret.first == lhs.cend())
599 return std::strong_ordering::equivalent;
600
601 return (*ret.first > *ret.second) ? std::strong_ordering::greater : std::strong_ordering::less;
602}
603
604template <std::size_t Bits, typename Tag>
605[[nodiscard]] constexpr bool
607{
608 return (lhs <=> rhs) == 0; // NOLINT(modernize-use-nullptr)
609}
610
611//------------------------------------------------------------------------------
612template <std::size_t Bits, class Tag>
613constexpr bool
615{
616 return a == BaseUInt<Bits, Tag>(b);
617}
618
619//------------------------------------------------------------------------------
620template <std::size_t Bits, class Tag>
621constexpr BaseUInt<Bits, Tag>
623{
624 return BaseUInt<Bits, Tag>(a) ^= b;
625}
626
627template <std::size_t Bits, class Tag>
628constexpr BaseUInt<Bits, Tag>
630{
631 return BaseUInt<Bits, Tag>(a) &= b;
632}
633
634template <std::size_t Bits, class Tag>
635constexpr BaseUInt<Bits, Tag>
637{
638 return BaseUInt<Bits, Tag>(a) |= b;
639}
640
641template <std::size_t Bits, class Tag>
642constexpr BaseUInt<Bits, Tag>
644{
645 return BaseUInt<Bits, Tag>(a) += b;
646}
647
648//------------------------------------------------------------------------------
649template <std::size_t Bits, class Tag>
650inline std::string
652{
653 return strHex(a.cbegin(), a.cend());
654}
655
656template <std::size_t Bits, class Tag>
657inline std::string
659{
660 static_assert(BaseUInt<Bits, Tag>::kBytes > 4, "For 4 bytes or less, use a native type");
661 return strHex(a.cbegin(), a.cbegin() + 4) + "...";
662}
663
664template <std::size_t Bits, class Tag>
667{
668 return out << to_string(u);
669}
670
671template <>
672inline std::size_t
673extract(uint256 const& key)
674{
675 std::size_t result = 0;
676 // Use memcpy to avoid unaligned UB
677 // (will optimize to equivalent code)
678 std::memcpy(&result, key.data(), sizeof(std::size_t));
679 return result;
680}
681
682#ifndef __INTELLISENSE__
683static_assert(sizeof(uint128) == 128 / 8, "There should be no padding bytes");
684static_assert(sizeof(uint160) == 160 / 8, "There should be no padding bytes");
685static_assert(sizeof(uint192) == 192 / 8, "There should be no padding bytes");
686static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
687#endif
688
689} // namespace xrpl
690
691namespace beast {
692
693template <std::size_t Bits, class Tag>
694struct IsUniquelyRepresented<xrpl::BaseUInt<Bits, Tag>> : public std::true_type
695{
696 explicit IsUniquelyRepresented() = default;
697};
698
699} // namespace beast
T begin(T... args)
Integers of any length that is a multiple of 32-bits.
Definition base_uint.h:82
std::size_t size_type
Definition base_uint.h:103
bool operator!() const
Definition base_uint.h:366
value_type * pointer
Definition base_uint.h:106
unsigned char value_type
Definition base_uint.h:105
std::reverse_iterator< iterator > reverse_iterator
Definition base_uint.h:112
BaseUInt operator++(int)
Definition base_uint.h:442
BaseUInt(std::uint64_t b)
Definition base_uint.h:273
static BaseUInt fromRaw(Container const &c)
Definition base_uint.h:302
std::ptrdiff_t difference_type
Definition base_uint.h:104
static BaseUInt fromVoid(void const *data)
Definition base_uint.h:339
const_iterator cend() const
Definition base_uint.h:153
BaseUInt & operator++()
Definition base_uint.h:428
constexpr BaseUInt(std::string_view sv) noexcept(false)
Definition base_uint.h:281
BaseUInt & operator&=(BaseUInt const &b)
Definition base_uint.h:410
bool parseHex(std::string const &str)
Definition base_uint.h:542
constexpr int signum() const
Definition base_uint.h:354
BaseUInt & operator+=(BaseUInt const &b)
Definition base_uint.h:491
constexpr bool parseHex(char const *str)
Definition base_uint.h:536
value_type const * const_pointer
Definition base_uint.h:108
const_iterator begin() const
Definition base_uint.h:138
bool isZero() const
Definition base_uint.h:562
constexpr decltype(data_) parseFromStringViewThrows(std::string_view sv) noexcept(false)
Definition base_uint.h:251
std::reverse_iterator< const_iterator > const_reverse_iterator
Definition base_uint.h:113
BaseUInt & operator--()
Definition base_uint.h:452
constexpr std::expected< decltype(data_), ParseResult > parseFromStringView(std::string_view sv) noexcept
Definition base_uint.h:194
bool isNonZero() const
Definition base_uint.h:567
BaseUInt & operator|=(BaseUInt const &b)
Definition base_uint.h:419
BaseUInt(Container const &c)
Definition base_uint.h:287
const_pointer data() const
Definition base_uint.h:122
iterator end()
Definition base_uint.h:133
static constexpr std::size_t kWidth
Definition base_uint.h:87
value_type & reference
Definition base_uint.h:107
BaseUInt< Bits, Tag > & operator=(beast::Zero)
Definition base_uint.h:554
std::array< std::uint32_t, kWidth > data_
Definition base_uint.h:92
pointer data()
Definition base_uint.h:117
BaseUInt & operator=(Container const &c)
Definition base_uint.h:319
constexpr BaseUInt(beast::Zero)
Definition base_uint.h:269
HardenedHash<> hasher
Value hashing function.
Definition base_uint.h:163
BaseUInt(void const *data, VoidHelper)
Definition base_uint.h:181
friend void hash_append(Hasher &h, BaseUInt const &a) noexcept
Definition base_uint.h:509
const_pointer const_iterator
Definition base_uint.h:111
BaseUInt next() const
Definition base_uint.h:477
BaseUInt & operator^=(BaseUInt const &b)
Definition base_uint.h:401
constexpr BaseUInt()
Definition base_uint.h:265
constexpr BaseUInt operator~() const
Definition base_uint.h:372
static constexpr std::size_t kBytes
Definition base_uint.h:100
static std::optional< BaseUInt > fromVoidChecked(T const &from)
Definition base_uint.h:346
const_iterator end() const
Definition base_uint.h:143
BaseUInt & operator=(std::uint64_t uHost)
Definition base_uint.h:383
iterator begin()
Definition base_uint.h:128
static constexpr std::size_t size()
Definition base_uint.h:548
BaseUInt operator--(int)
Definition base_uint.h:467
value_type const & const_reference
Definition base_uint.h:109
BaseUInt prev() const
Definition base_uint.h:484
constexpr bool parseHex(std::string_view sv)
Parse a hex string into a base_uint.
Definition base_uint.h:525
const_iterator cbegin() const
Definition base_uint.h:148
pointer iterator
Definition base_uint.h:110
Seed functor once per construction.
An immutable linear range of bytes.
Definition Slice.h:28
T data(T... args)
T end(T... args)
T is_trivially_copyable_v
T memcpy(T... args)
T min(T... args)
T mismatch(T... args)
constexpr Zero kZero
Definition Zero.h:30
STL namespace.
Use hash_* containers for keys that do not need a cryptographically secure hashing algorithm.
Definition algorithm.h:5
constexpr BaseUInt< Bits, Tag > operator+(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:643
constexpr BaseUInt< Bits, Tag > operator^(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:622
std::size_t extract(uint256 const &key)
Definition base_uint.h:673
BaseUInt< 192 > uint192
Definition base_uint.h:581
constexpr BaseUInt< Bits, Tag > operator&(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:629
constexpr bool operator==(BaseUInt< Bits, Tag > const &lhs, BaseUInt< Bits, Tag > const &rhs)
Definition base_uint.h:606
std::string strHex(FwdIt begin, FwdIt end)
Definition strHex.h:13
constexpr BaseUInt< Bits, Tag > operator|(BaseUInt< Bits, Tag > const &a, BaseUInt< Bits, Tag > const &b)
Definition base_uint.h:636
BaseUInt< 128 > uint128
Definition base_uint.h:578
std::ostream & operator<<(std::ostream &out, BaseUInt< Bits, Tag > const &u)
Definition base_uint.h:666
std::string to_string(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:651
Dir::ConstIterator const_iterator
Definition Dir.cpp:16
std::string toShortString(BaseUInt< Bits, Tag > const &a)
Definition base_uint.h:658
constexpr std::strong_ordering operator<=>(BaseUInt< Bits, Tag > const &lhs, BaseUInt< Bits, Tag > const &rhs)
Definition base_uint.h:585
BaseUInt< 160 > uint160
Definition base_uint.h:579
BaseUInt< 256 > uint256
Definition base_uint.h:580
XRPL_NO_SANITIZE_ADDRESS void Throw(Args &&... args)
Definition contract.h:52
T size(T... args)
Zero allows classes to offer efficient comparisons to zero.
Definition Zero.h:26
T unexpected(T... args)