mirror of
https://github.com/XRPLF/rippled.git
synced 2026-01-29 02:55:31 +00:00
Compare commits
27 Commits
ximinez/fi
...
ximinez/nu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c499aacab | ||
|
|
0364d61b42 | ||
|
|
f0eef6ec63 | ||
|
|
7e2c2573d2 | ||
|
|
a48182c65d | ||
|
|
e7f81c2646 | ||
|
|
5f8acbc001 | ||
|
|
47bfd15004 | ||
|
|
accbe7343d | ||
|
|
cd4f915e40 | ||
|
|
f8d441bb6b | ||
|
|
2f0690f3c5 | ||
|
|
040bf34257 | ||
|
|
5c87c4ffb0 | ||
|
|
0a9436def4 | ||
|
|
e5646e4ebe | ||
|
|
f76bf5340c | ||
|
|
1af0f4bd43 | ||
|
|
c6821ab842 | ||
|
|
7ab9709373 | ||
|
|
aa12210fcd | ||
|
|
9235ec483a | ||
|
|
ffe0a3cc61 | ||
|
|
add9071b20 | ||
|
|
465e7b6d91 | ||
|
|
6223ebe05e | ||
|
|
4fe50c2d31 |
@@ -37,7 +37,7 @@ BinPackParameters: false
|
||||
BreakBeforeBinaryOperators: false
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializersBeforeComma: true
|
||||
ColumnLimit: 120
|
||||
ColumnLimit: 80
|
||||
CommentPragmas: "^ IWYU pragma:"
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 4
|
||||
|
||||
2
.github/actions/setup-conan/action.yml
vendored
2
.github/actions/setup-conan/action.yml
vendored
@@ -31,7 +31,7 @@ runs:
|
||||
conan config install conan/profiles/ -tf $(conan config home)/profiles/
|
||||
|
||||
echo 'Conan profile:'
|
||||
conan profile show --profile ci
|
||||
conan profile show
|
||||
|
||||
- name: Set up Conan remote
|
||||
shell: bash
|
||||
|
||||
@@ -125,8 +125,6 @@ jobs:
|
||||
subtract: ${{ inputs.nproc_subtract }}
|
||||
|
||||
- name: Setup Conan
|
||||
env:
|
||||
SANITIZERS: ${{ inputs.sanitizers }}
|
||||
uses: ./.github/actions/setup-conan
|
||||
|
||||
- name: Build dependencies
|
||||
|
||||
26
.github/workflows/reusable-upload-recipe.yml
vendored
26
.github/workflows/reusable-upload-recipe.yml
vendored
@@ -62,36 +62,12 @@ jobs:
|
||||
REMOTE_PASSWORD: ${{ secrets.remote_password }}
|
||||
run: conan remote login "${REMOTE_NAME}" "${REMOTE_USERNAME}" --password "${REMOTE_PASSWORD}"
|
||||
|
||||
- name: Upload Conan recipe (version)
|
||||
- name: Upload Conan recipe
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
run: |
|
||||
conan export . --version=${{ steps.version.outputs.version }}
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/${{ steps.version.outputs.version }}
|
||||
|
||||
- name: Upload Conan recipe (develop)
|
||||
if: ${{ github.ref == 'refs/heads/develop' }}
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
run: |
|
||||
conan export . --version=develop
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/develop
|
||||
|
||||
- name: Upload Conan recipe (rc)
|
||||
if: ${{ startsWith(github.ref, 'refs/heads/release') }}
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
run: |
|
||||
conan export . --version=rc
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/rc
|
||||
|
||||
- name: Upload Conan recipe (release)
|
||||
if: ${{ github.event_name == 'tag' }}
|
||||
env:
|
||||
REMOTE_NAME: ${{ inputs.remote_name }}
|
||||
run: |
|
||||
conan export . --version=release
|
||||
conan upload --confirm --check --remote="${REMOTE_NAME}" xrpl/release
|
||||
|
||||
outputs:
|
||||
ref: xrpl/${{ steps.version.outputs.version }}
|
||||
|
||||
3
.github/workflows/upload-conan-deps.yml
vendored
3
.github/workflows/upload-conan-deps.yml
vendored
@@ -84,8 +84,6 @@ jobs:
|
||||
subtract: ${{ env.NPROC_SUBTRACT }}
|
||||
|
||||
- name: Setup Conan
|
||||
env:
|
||||
SANITIZERS: ${{ matrix.sanitizers }}
|
||||
uses: ./.github/actions/setup-conan
|
||||
with:
|
||||
remote_name: ${{ env.CONAN_REMOTE_NAME }}
|
||||
@@ -100,7 +98,6 @@ jobs:
|
||||
# Set the verbosity to "quiet" for Windows to avoid an excessive
|
||||
# amount of logs. For other OSes, the "verbose" logs are more useful.
|
||||
log_verbosity: ${{ runner.os == 'Windows' && 'quiet' || 'verbose' }}
|
||||
sanitizers: ${{ matrix.sanitizers }}
|
||||
|
||||
- name: Log into Conan remote
|
||||
if: ${{ github.repository_owner == 'XRPLF' && (github.event_name == 'push' || github.event_name == 'workflow_dispatch') }}
|
||||
|
||||
4
BUILD.md
4
BUILD.md
@@ -148,8 +148,8 @@ function extract_version {
|
||||
}
|
||||
|
||||
# Define which recipes to export.
|
||||
recipes=('ed25519' 'grpc' 'nudb' 'openssl' 'secp256k1' 'snappy' 'soci')
|
||||
folders=('all' 'all' 'all' '3.x.x' 'all' 'all' 'all')
|
||||
recipes=('ed25519' 'grpc' 'openssl' 'secp256k1' 'snappy' 'soci')
|
||||
folders=('all' 'all' '3.x.x' 'all' 'all' 'all')
|
||||
|
||||
# Selectively check out the recipes from our CCI fork.
|
||||
cd external
|
||||
|
||||
@@ -30,6 +30,7 @@ target_link_libraries(xrpl_boost
|
||||
Boost::process
|
||||
Boost::program_options
|
||||
Boost::regex
|
||||
Boost::system
|
||||
Boost::thread)
|
||||
if(Boost_COMPILER)
|
||||
target_link_libraries(xrpl_boost INTERFACE Boost::disable_autolinking)
|
||||
|
||||
14
conan.lock
14
conan.lock
@@ -11,7 +11,7 @@
|
||||
"re2/20230301#ca3b241baec15bd31ea9187150e0b333%1765850148.103",
|
||||
"protobuf/6.32.1#f481fd276fc23a33b85a3ed1e898b693%1765850161.038",
|
||||
"openssl/3.5.4#1b986e61b38fdfda3b40bebc1b234393%1768312656.257",
|
||||
"nudb/2.0.9#0432758a24204da08fee953ec9ea03cb%1769436073.32",
|
||||
"nudb/2.0.9#fb8dfd1a5557f5e0528114c2da17721e%1765850143.957",
|
||||
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914",
|
||||
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492",
|
||||
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1765842973.03",
|
||||
@@ -23,7 +23,7 @@
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1765850143.772",
|
||||
"c-ares/1.34.5#5581c2b62a608b40bb85d965ab3ec7c8%1765850144.336",
|
||||
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1765850143.837",
|
||||
"boost/1.90.0#d5e8defe7355494953be18524a7f135b%1765955095.179",
|
||||
"boost/1.88.0#8852c0b72ce8271fb8ff7c53456d4983%1765850172.862",
|
||||
"abseil/20250127.0#99262a368bd01c0ccca8790dfced9719%1766517936.993"
|
||||
],
|
||||
"build_requires": [
|
||||
@@ -42,22 +42,18 @@
|
||||
],
|
||||
"python_requires": [],
|
||||
"overrides": {
|
||||
"boost/1.90.0#d5e8defe7355494953be18524a7f135b": [
|
||||
null,
|
||||
"boost/1.90.0"
|
||||
],
|
||||
"protobuf/5.27.0": [
|
||||
"protobuf/6.32.1"
|
||||
],
|
||||
"lz4/1.9.4": [
|
||||
"lz4/1.10.0"
|
||||
],
|
||||
"boost/1.83.0": [
|
||||
"boost/1.88.0"
|
||||
],
|
||||
"sqlite3/3.44.2": [
|
||||
"sqlite3/3.49.1"
|
||||
],
|
||||
"boost/1.83.0": [
|
||||
"boost/1.90.0"
|
||||
],
|
||||
"lz4/[>=1.9.4 <2]": [
|
||||
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504"
|
||||
]
|
||||
|
||||
@@ -131,7 +131,7 @@ class Xrpl(ConanFile):
|
||||
transitive_headers_opt = (
|
||||
{"transitive_headers": True} if conan_version.split(".")[0] == "2" else {}
|
||||
)
|
||||
self.requires("boost/1.90.0", force=True, **transitive_headers_opt)
|
||||
self.requires("boost/1.88.0", force=True, **transitive_headers_opt)
|
||||
self.requires("date/3.0.4", **transitive_headers_opt)
|
||||
self.requires("lz4/1.10.0", force=True)
|
||||
self.requires("protobuf/6.32.1", force=True)
|
||||
@@ -203,6 +203,7 @@ class Xrpl(ConanFile):
|
||||
"boost::program_options",
|
||||
"boost::process",
|
||||
"boost::regex",
|
||||
"boost::system",
|
||||
"boost::thread",
|
||||
"date::date",
|
||||
"ed25519::ed25519",
|
||||
|
||||
@@ -13,7 +13,9 @@ namespace xrpl {
|
||||
@throws runtime_error
|
||||
*/
|
||||
void
|
||||
extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const& dst);
|
||||
extractTarLz4(
|
||||
boost::filesystem::path const& src,
|
||||
boost::filesystem::path const& dst);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
using IniFileSections = std::unordered_map<std::string, std::vector<std::string>>;
|
||||
using IniFileSections =
|
||||
std::unordered_map<std::string, std::vector<std::string>>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -85,7 +86,8 @@ public:
|
||||
if (lines_.empty())
|
||||
return "";
|
||||
if (lines_.size() > 1)
|
||||
Throw<std::runtime_error>("A legacy value must have exactly one line. Section: " + name_);
|
||||
Throw<std::runtime_error>(
|
||||
"A legacy value must have exactly one line. Section: " + name_);
|
||||
return lines_[0];
|
||||
}
|
||||
|
||||
@@ -231,7 +233,10 @@ public:
|
||||
The previous value, if any, is overwritten.
|
||||
*/
|
||||
void
|
||||
overwrite(std::string const& section, std::string const& key, std::string const& value);
|
||||
overwrite(
|
||||
std::string const& section,
|
||||
std::string const& key,
|
||||
std::string const& value);
|
||||
|
||||
/** Remove all the key/value pairs from the section.
|
||||
*/
|
||||
@@ -269,7 +274,9 @@ public:
|
||||
bool
|
||||
had_trailing_comments() const
|
||||
{
|
||||
return std::any_of(map_.cbegin(), map_.cend(), [](auto s) { return s.second.had_trailing_comments(); });
|
||||
return std::any_of(map_.cbegin(), map_.cend(), [](auto s) {
|
||||
return s.second.had_trailing_comments();
|
||||
});
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -308,7 +315,10 @@ set(T& target, std::string const& name, Section const& section)
|
||||
*/
|
||||
template <class T>
|
||||
bool
|
||||
set(T& target, T const& defaultValue, std::string const& name, Section const& section)
|
||||
set(T& target,
|
||||
T const& defaultValue,
|
||||
std::string const& name,
|
||||
Section const& section)
|
||||
{
|
||||
bool found_and_valid = set<T>(target, name, section);
|
||||
if (!found_and_valid)
|
||||
@@ -323,7 +333,9 @@ set(T& target, T const& defaultValue, std::string const& name, Section const& se
|
||||
// NOTE This routine might be more clumsy than the previous two
|
||||
template <class T = std::string>
|
||||
T
|
||||
get(Section const& section, std::string const& name, T const& defaultValue = T{})
|
||||
get(Section const& section,
|
||||
std::string const& name,
|
||||
T const& defaultValue = T{})
|
||||
{
|
||||
try
|
||||
{
|
||||
|
||||
@@ -25,7 +25,8 @@ public:
|
||||
Buffer() = default;
|
||||
|
||||
/** Create an uninitialized buffer with the given size. */
|
||||
explicit Buffer(std::size_t size) : p_(size ? new std::uint8_t[size] : nullptr), size_(size)
|
||||
explicit Buffer(std::size_t size)
|
||||
: p_(size ? new std::uint8_t[size] : nullptr), size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -61,7 +62,8 @@ public:
|
||||
/** Move-construct.
|
||||
The other buffer is reset.
|
||||
*/
|
||||
Buffer(Buffer&& other) noexcept : p_(std::move(other.p_)), size_(other.size_)
|
||||
Buffer(Buffer&& other) noexcept
|
||||
: p_(std::move(other.p_)), size_(other.size_)
|
||||
{
|
||||
other.size_ = 0;
|
||||
}
|
||||
@@ -92,7 +94,8 @@ public:
|
||||
{
|
||||
// Ensure the slice isn't a subset of the buffer.
|
||||
XRPL_ASSERT(
|
||||
s.size() == 0 || size_ == 0 || s.data() < p_.get() || s.data() >= p_.get() + size_,
|
||||
s.size() == 0 || size_ == 0 || s.data() < p_.get() ||
|
||||
s.data() >= p_.get() + size_,
|
||||
"xrpl::Buffer::operator=(Slice) : input not a subset");
|
||||
|
||||
if (auto p = alloc(s.size()))
|
||||
|
||||
@@ -1,133 +0,0 @@
|
||||
//------------------------------------------------------------------------------
|
||||
/*
|
||||
This file is part of rippled: https://github.com/ripple/rippled
|
||||
Copyright (c) 2024 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_BASICS_CANPROCESS_H_INCLUDED
|
||||
#define RIPPLE_BASICS_CANPROCESS_H_INCLUDED
|
||||
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <set>
|
||||
|
||||
/** RAII class to check if an Item is already being processed on another thread,
|
||||
* as indicated by it's presence in a Collection.
|
||||
*
|
||||
* If the Item is not in the Collection, it will be added under lock in the
|
||||
* ctor, and removed under lock in the dtor. The object will be considered
|
||||
* "usable" and evaluate to `true`.
|
||||
*
|
||||
* If the Item is in the Collection, no changes will be made to the collection,
|
||||
* and the CanProcess object will be considered "unusable".
|
||||
*
|
||||
* It's up to the caller to decide what "usable" and "unusable" mean. (e.g.
|
||||
* Process or skip a block of code, or set a flag.)
|
||||
*
|
||||
* The current use is to avoid lock contention that would be involved in
|
||||
* processing something associated with the Item.
|
||||
*
|
||||
* Examples:
|
||||
*
|
||||
* void IncomingLedgers::acquireAsync(LedgerHash const& hash, ...)
|
||||
* {
|
||||
* if (CanProcess check{acquiresMutex_, pendingAcquires_, hash})
|
||||
* {
|
||||
* acquire(hash, ...);
|
||||
* }
|
||||
* }
|
||||
*
|
||||
* bool
|
||||
* NetworkOPsImp::recvValidation(
|
||||
* std::shared_ptr<STValidation> const& val,
|
||||
* std::string const& source)
|
||||
* {
|
||||
* CanProcess check(
|
||||
* validationsMutex_, pendingValidations_, val->getLedgerHash());
|
||||
* BypassAccept bypassAccept =
|
||||
* check ? BypassAccept::no : BypassAccept::yes;
|
||||
* handleNewValidation(app_, val, source, bypassAccept, m_journal);
|
||||
* }
|
||||
*
|
||||
*/
|
||||
class CanProcess
|
||||
{
|
||||
public:
|
||||
template <class Mutex, class Collection, class Item>
|
||||
CanProcess(Mutex& mtx, Collection& collection, Item const& item) : cleanup_(insert(mtx, collection, item))
|
||||
{
|
||||
}
|
||||
|
||||
~CanProcess()
|
||||
{
|
||||
if (cleanup_)
|
||||
cleanup_();
|
||||
}
|
||||
|
||||
explicit
|
||||
operator bool() const
|
||||
{
|
||||
return static_cast<bool>(cleanup_);
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool useIterator, class Mutex, class Collection, class Item>
|
||||
std::function<void()>
|
||||
doInsert(Mutex& mtx, Collection& collection, Item const& item)
|
||||
{
|
||||
std::unique_lock<Mutex> lock(mtx);
|
||||
// TODO: Use structured binding once LLVM 16 is the minimum supported
|
||||
// version. See also: https://github.com/llvm/llvm-project/issues/48582
|
||||
// https://github.com/llvm/llvm-project/commit/127bf44385424891eb04cff8e52d3f157fc2cb7c
|
||||
auto const insertResult = collection.insert(item);
|
||||
auto const it = insertResult.first;
|
||||
if (!insertResult.second)
|
||||
return {};
|
||||
if constexpr (useIterator)
|
||||
return [&, it]() {
|
||||
std::unique_lock<Mutex> lock(mtx);
|
||||
collection.erase(it);
|
||||
};
|
||||
else
|
||||
return [&]() {
|
||||
std::unique_lock<Mutex> lock(mtx);
|
||||
collection.erase(item);
|
||||
};
|
||||
}
|
||||
|
||||
// Generic insert() function doesn't use iterators because they may get
|
||||
// invalidated
|
||||
template <class Mutex, class Collection, class Item>
|
||||
std::function<void()>
|
||||
insert(Mutex& mtx, Collection& collection, Item const& item)
|
||||
{
|
||||
return doInsert<false>(mtx, collection, item);
|
||||
}
|
||||
|
||||
// Specialize insert() for std::set, which does not invalidate iterators for
|
||||
// insert and erase
|
||||
template <class Mutex, class Item>
|
||||
std::function<void()>
|
||||
insert(Mutex& mtx, std::set<Item>& collection, Item const& item)
|
||||
{
|
||||
return doInsert<true>(mtx, collection, item);
|
||||
}
|
||||
|
||||
// If set, then the item is "usable"
|
||||
std::function<void()> cleanup_;
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -36,7 +36,10 @@ lz4Compress(void const* in, std::size_t inSize, BufferFactory&& bf)
|
||||
auto compressed = bf(outCapacity);
|
||||
|
||||
auto compressedSize = LZ4_compress_default(
|
||||
reinterpret_cast<char const*>(in), reinterpret_cast<char*>(compressed), inSize, outCapacity);
|
||||
reinterpret_cast<char const*>(in),
|
||||
reinterpret_cast<char*>(compressed),
|
||||
inSize,
|
||||
outCapacity);
|
||||
if (compressedSize == 0)
|
||||
Throw<std::runtime_error>("lz4 compress: failed");
|
||||
|
||||
@@ -67,8 +70,10 @@ lz4Decompress(
|
||||
Throw<std::runtime_error>("lz4Decompress: integer overflow (output)");
|
||||
|
||||
if (LZ4_decompress_safe(
|
||||
reinterpret_cast<char const*>(in), reinterpret_cast<char*>(decompressed), inSize, decompressedSize) !=
|
||||
decompressedSize)
|
||||
reinterpret_cast<char const*>(in),
|
||||
reinterpret_cast<char*>(decompressed),
|
||||
inSize,
|
||||
decompressedSize) != decompressedSize)
|
||||
Throw<std::runtime_error>("lz4Decompress: failed");
|
||||
|
||||
return decompressedSize;
|
||||
@@ -84,7 +89,11 @@ lz4Decompress(
|
||||
*/
|
||||
template <typename InputStream>
|
||||
std::size_t
|
||||
lz4Decompress(InputStream& in, std::size_t inSize, std::uint8_t* decompressed, std::size_t decompressedSize)
|
||||
lz4Decompress(
|
||||
InputStream& in,
|
||||
std::size_t inSize,
|
||||
std::uint8_t* decompressed,
|
||||
std::size_t decompressedSize)
|
||||
{
|
||||
std::vector<std::uint8_t> compressed;
|
||||
std::uint8_t const* chunk = nullptr;
|
||||
@@ -107,7 +116,9 @@ lz4Decompress(InputStream& in, std::size_t inSize, std::uint8_t* decompressed, s
|
||||
compressed.resize(inSize);
|
||||
}
|
||||
|
||||
chunkSize = chunkSize < (inSize - copiedInSize) ? chunkSize : (inSize - copiedInSize);
|
||||
chunkSize = chunkSize < (inSize - copiedInSize)
|
||||
? chunkSize
|
||||
: (inSize - copiedInSize);
|
||||
|
||||
std::copy(chunk, chunk + chunkSize, compressed.data() + copiedInSize);
|
||||
|
||||
@@ -124,7 +135,8 @@ lz4Decompress(InputStream& in, std::size_t inSize, std::uint8_t* decompressed, s
|
||||
if (in.ByteCount() > (currentBytes + copiedInSize))
|
||||
in.BackUp(in.ByteCount() - currentBytes - copiedInSize);
|
||||
|
||||
if ((copiedInSize == 0 && chunkSize < inSize) || (copiedInSize > 0 && copiedInSize != inSize))
|
||||
if ((copiedInSize == 0 && chunkSize < inSize) ||
|
||||
(copiedInSize > 0 && copiedInSize != inSize))
|
||||
Throw<std::runtime_error>("lz4 decompress: insufficient input size");
|
||||
|
||||
return lz4Decompress(chunk, inSize, decompressed, decompressedSize);
|
||||
|
||||
@@ -56,7 +56,9 @@ private:
|
||||
|
||||
if (m_value != value_type())
|
||||
{
|
||||
std::size_t elapsed = std::chrono::duration_cast<std::chrono::seconds>(now - m_when).count();
|
||||
std::size_t elapsed =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(now - m_when)
|
||||
.count();
|
||||
|
||||
// A span larger than four times the window decays the
|
||||
// value to an insignificant amount so just reset it.
|
||||
|
||||
@@ -108,20 +108,23 @@ Unexpected(E (&)[N]) -> Unexpected<E const*>;
|
||||
|
||||
// Definition of Expected. All of the machinery comes from boost::result.
|
||||
template <class T, class E>
|
||||
class [[nodiscard]] Expected : private boost::outcome_v2::result<T, E, detail::throw_policy>
|
||||
class [[nodiscard]] Expected
|
||||
: private boost::outcome_v2::result<T, E, detail::throw_policy>
|
||||
{
|
||||
using Base = boost::outcome_v2::result<T, E, detail::throw_policy>;
|
||||
|
||||
public:
|
||||
template <typename U>
|
||||
requires std::convertible_to<U, T>
|
||||
constexpr Expected(U&& r) : Base(boost::outcome_v2::in_place_type_t<T>{}, std::forward<U>(r))
|
||||
constexpr Expected(U&& r)
|
||||
: Base(boost::outcome_v2::in_place_type_t<T>{}, std::forward<U>(r))
|
||||
{
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
requires std::convertible_to<U, E> && (!std::is_reference_v<U>)
|
||||
constexpr Expected(Unexpected<U> e) : Base(boost::outcome_v2::in_place_type_t<E>{}, std::move(e.value()))
|
||||
constexpr Expected(Unexpected<U> e)
|
||||
: Base(boost::outcome_v2::in_place_type_t<E>{}, std::move(e.value()))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -192,7 +195,8 @@ public:
|
||||
// Specialization of Expected<void, E>. Allows returning either success
|
||||
// (without a value) or the reason for the failure.
|
||||
template <class E>
|
||||
class [[nodiscard]] Expected<void, E> : private boost::outcome_v2::result<void, E, detail::throw_policy>
|
||||
class [[nodiscard]] Expected<void, E>
|
||||
: private boost::outcome_v2::result<void, E, detail::throw_policy>
|
||||
{
|
||||
using Base = boost::outcome_v2::result<void, E, detail::throw_policy>;
|
||||
|
||||
|
||||
@@ -15,7 +15,10 @@ getFileContents(
|
||||
std::optional<std::size_t> maxSize = std::nullopt);
|
||||
|
||||
void
|
||||
writeFileContents(boost::system::error_code& ec, boost::filesystem::path const& destPath, std::string const& contents);
|
||||
writeFileContents(
|
||||
boost::system::error_code& ec,
|
||||
boost::filesystem::path const& destPath,
|
||||
std::string const& contents);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
|
||||
@@ -45,8 +45,8 @@ struct SharedIntrusiveAdoptNoIncrementTag
|
||||
//
|
||||
|
||||
template <class T>
|
||||
concept CAdoptTag =
|
||||
std::is_same_v<T, SharedIntrusiveAdoptIncrementStrongTag> || std::is_same_v<T, SharedIntrusiveAdoptNoIncrementTag>;
|
||||
concept CAdoptTag = std::is_same_v<T, SharedIntrusiveAdoptIncrementStrongTag> ||
|
||||
std::is_same_v<T, SharedIntrusiveAdoptNoIncrementTag>;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -122,7 +122,9 @@ public:
|
||||
controlled by the rhs param.
|
||||
*/
|
||||
template <class TT>
|
||||
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs);
|
||||
SharedIntrusive(
|
||||
StaticCastTagSharedIntrusive,
|
||||
SharedIntrusive<TT> const& rhs);
|
||||
|
||||
/** Create a new SharedIntrusive by statically casting the pointer
|
||||
controlled by the rhs param.
|
||||
@@ -134,7 +136,9 @@ public:
|
||||
controlled by the rhs param.
|
||||
*/
|
||||
template <class TT>
|
||||
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs);
|
||||
SharedIntrusive(
|
||||
DynamicCastTagSharedIntrusive,
|
||||
SharedIntrusive<TT> const& rhs);
|
||||
|
||||
/** Create a new SharedIntrusive by dynamically casting the pointer
|
||||
controlled by the rhs param.
|
||||
@@ -300,7 +304,9 @@ class SharedWeakUnion
|
||||
// Tagged pointer. Low bit determines if this is a strong or a weak
|
||||
// pointer. The low bit must be masked to zero when converting back to a
|
||||
// pointer. If the low bit is '1', this is a weak pointer.
|
||||
static_assert(alignof(T) >= 2, "Bad alignment: Combo pointer requires low bit to be zero");
|
||||
static_assert(
|
||||
alignof(T) >= 2,
|
||||
"Bad alignment: Combo pointer requires low bit to be zero");
|
||||
|
||||
public:
|
||||
SharedWeakUnion() = default;
|
||||
@@ -444,7 +450,9 @@ make_SharedIntrusive(Args&&... args)
|
||||
auto p = new TT(std::forward<Args>(args)...);
|
||||
|
||||
static_assert(
|
||||
noexcept(SharedIntrusive<TT>(std::declval<TT*>(), std::declval<SharedIntrusiveAdoptNoIncrementTag>())),
|
||||
noexcept(SharedIntrusive<TT>(
|
||||
std::declval<TT*>(),
|
||||
std::declval<SharedIntrusiveAdoptNoIncrementTag>())),
|
||||
"SharedIntrusive constructor should not throw or this can leak "
|
||||
"memory");
|
||||
|
||||
|
||||
@@ -12,7 +12,9 @@ template <class T>
|
||||
template <CAdoptTag TAdoptTag>
|
||||
SharedIntrusive<T>::SharedIntrusive(T* p, TAdoptTag) noexcept : ptr_{p}
|
||||
{
|
||||
if constexpr (std::is_same_v<TAdoptTag, SharedIntrusiveAdoptIncrementStrongTag>)
|
||||
if constexpr (std::is_same_v<
|
||||
TAdoptTag,
|
||||
SharedIntrusiveAdoptIncrementStrongTag>)
|
||||
{
|
||||
if (p)
|
||||
p->addStrongRef();
|
||||
@@ -44,14 +46,16 @@ SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT> const& rhs)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive&& rhs) : ptr_{rhs.unsafeExchange(nullptr)}
|
||||
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive&& rhs)
|
||||
: ptr_{rhs.unsafeExchange(nullptr)}
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT>&& rhs) : ptr_{rhs.unsafeExchange(nullptr)}
|
||||
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT>&& rhs)
|
||||
: ptr_{rhs.unsafeExchange(nullptr)}
|
||||
{
|
||||
}
|
||||
template <class T>
|
||||
@@ -108,7 +112,9 @@ requires std::convertible_to<TT*, T*>
|
||||
SharedIntrusive<T>&
|
||||
SharedIntrusive<T>::operator=(SharedIntrusive<TT>&& rhs)
|
||||
{
|
||||
static_assert(!std::is_same_v<T, TT>, "This overload should not be instantiated for T == TT");
|
||||
static_assert(
|
||||
!std::is_same_v<T, TT>,
|
||||
"This overload should not be instantiated for T == TT");
|
||||
|
||||
unsafeReleaseAndStore(rhs.unsafeExchange(nullptr));
|
||||
return *this;
|
||||
@@ -133,7 +139,9 @@ template <CAdoptTag TAdoptTag>
|
||||
void
|
||||
SharedIntrusive<T>::adopt(T* p)
|
||||
{
|
||||
if constexpr (std::is_same_v<TAdoptTag, SharedIntrusiveAdoptIncrementStrongTag>)
|
||||
if constexpr (std::is_same_v<
|
||||
TAdoptTag,
|
||||
SharedIntrusiveAdoptIncrementStrongTag>)
|
||||
{
|
||||
if (p)
|
||||
p->addStrongRef();
|
||||
@@ -149,7 +157,9 @@ SharedIntrusive<T>::~SharedIntrusive()
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs)
|
||||
SharedIntrusive<T>::SharedIntrusive(
|
||||
StaticCastTagSharedIntrusive,
|
||||
SharedIntrusive<TT> const& rhs)
|
||||
: ptr_{[&] {
|
||||
auto p = static_cast<T*>(rhs.unsafeGetRawPtr());
|
||||
if (p)
|
||||
@@ -161,14 +171,18 @@ SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusiv
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs)
|
||||
SharedIntrusive<T>::SharedIntrusive(
|
||||
StaticCastTagSharedIntrusive,
|
||||
SharedIntrusive<TT>&& rhs)
|
||||
: ptr_{static_cast<T*>(rhs.unsafeExchange(nullptr))}
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
SharedIntrusive<T>::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs)
|
||||
SharedIntrusive<T>::SharedIntrusive(
|
||||
DynamicCastTagSharedIntrusive,
|
||||
SharedIntrusive<TT> const& rhs)
|
||||
: ptr_{[&] {
|
||||
auto p = dynamic_cast<T*>(rhs.unsafeGetRawPtr());
|
||||
if (p)
|
||||
@@ -180,7 +194,9 @@ SharedIntrusive<T>::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusi
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
SharedIntrusive<T>::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs)
|
||||
SharedIntrusive<T>::SharedIntrusive(
|
||||
DynamicCastTagSharedIntrusive,
|
||||
SharedIntrusive<TT>&& rhs)
|
||||
{
|
||||
// This can be simplified without the `exchange`, but the `exchange` is kept
|
||||
// in anticipation of supporting atomic operations.
|
||||
@@ -299,7 +315,8 @@ WeakIntrusive<T>::WeakIntrusive(WeakIntrusive&& rhs) : ptr_{rhs.ptr_}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
WeakIntrusive<T>::WeakIntrusive(SharedIntrusive<T> const& rhs) : ptr_{rhs.unsafeGetRawPtr()}
|
||||
WeakIntrusive<T>::WeakIntrusive(SharedIntrusive<T> const& rhs)
|
||||
: ptr_{rhs.unsafeGetRawPtr()}
|
||||
{
|
||||
if (ptr_)
|
||||
ptr_->addWeakRef();
|
||||
|
||||
@@ -160,19 +160,22 @@ private:
|
||||
See description of the `refCounts` field for a fuller description of
|
||||
this field.
|
||||
*/
|
||||
static constexpr FieldType partialDestroyStartedMask = (one << (FieldTypeBits - 1));
|
||||
static constexpr FieldType partialDestroyStartedMask =
|
||||
(one << (FieldTypeBits - 1));
|
||||
|
||||
/** Flag that is set when the partialDestroy function has finished running
|
||||
|
||||
See description of the `refCounts` field for a fuller description of
|
||||
this field.
|
||||
*/
|
||||
static constexpr FieldType partialDestroyFinishedMask = (one << (FieldTypeBits - 2));
|
||||
static constexpr FieldType partialDestroyFinishedMask =
|
||||
(one << (FieldTypeBits - 2));
|
||||
|
||||
/** Mask that will zero out all the `count` bits and leave the tag bits
|
||||
unchanged.
|
||||
*/
|
||||
static constexpr FieldType tagMask = partialDestroyStartedMask | partialDestroyFinishedMask;
|
||||
static constexpr FieldType tagMask =
|
||||
partialDestroyStartedMask | partialDestroyFinishedMask;
|
||||
|
||||
/** Mask that will zero out the `tag` bits and leave the count bits
|
||||
unchanged.
|
||||
@@ -181,11 +184,13 @@ private:
|
||||
|
||||
/** Mask that will zero out everything except the strong count.
|
||||
*/
|
||||
static constexpr FieldType strongMask = ((one << StrongCountNumBits) - 1) & valueMask;
|
||||
static constexpr FieldType strongMask =
|
||||
((one << StrongCountNumBits) - 1) & valueMask;
|
||||
|
||||
/** Mask that will zero out everything except the weak count.
|
||||
*/
|
||||
static constexpr FieldType weakMask = (((one << WeakCountNumBits) - 1) << StrongCountNumBits) & valueMask;
|
||||
static constexpr FieldType weakMask =
|
||||
(((one << WeakCountNumBits) - 1) << StrongCountNumBits) & valueMask;
|
||||
|
||||
/** Unpack the count and tag fields from the packed atomic integer form. */
|
||||
struct RefCountPair
|
||||
@@ -210,8 +215,10 @@ private:
|
||||
FieldType
|
||||
combinedValue() const noexcept;
|
||||
|
||||
static constexpr CountType maxStrongValue = static_cast<CountType>((one << StrongCountNumBits) - 1);
|
||||
static constexpr CountType maxWeakValue = static_cast<CountType>((one << WeakCountNumBits) - 1);
|
||||
static constexpr CountType maxStrongValue =
|
||||
static_cast<CountType>((one << StrongCountNumBits) - 1);
|
||||
static constexpr CountType maxWeakValue =
|
||||
static_cast<CountType>((one << WeakCountNumBits) - 1);
|
||||
/** Put an extra margin to detect when running up against limits.
|
||||
This is only used in debug code, and is useful if we reduce the
|
||||
number of bits in the strong and weak counts (to 16 and 14 bits).
|
||||
@@ -267,7 +274,8 @@ IntrusiveRefCounts::releaseStrongRef() const
|
||||
}
|
||||
}
|
||||
|
||||
if (refCounts.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||
if (refCounts.compare_exchange_weak(
|
||||
prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||
{
|
||||
// Can't be in partial destroy because only decrementing the strong
|
||||
// count to zero can start a partial destroy, and that can't happen
|
||||
@@ -323,7 +331,8 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
|
||||
action = partialDestroy;
|
||||
}
|
||||
}
|
||||
if (refCounts.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||
if (refCounts.compare_exchange_weak(
|
||||
prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(!(prevIntVal & partialDestroyStartedMask)),
|
||||
@@ -367,7 +376,8 @@ IntrusiveRefCounts::checkoutStrongRefFromWeak() const noexcept
|
||||
auto curValue = RefCountPair{1, 1}.combinedValue();
|
||||
auto desiredValue = RefCountPair{2, 1}.combinedValue();
|
||||
|
||||
while (!refCounts.compare_exchange_weak(curValue, desiredValue, std::memory_order_acq_rel))
|
||||
while (!refCounts.compare_exchange_weak(
|
||||
curValue, desiredValue, std::memory_order_acq_rel))
|
||||
{
|
||||
RefCountPair const prev{curValue};
|
||||
if (!prev.strong)
|
||||
@@ -396,15 +406,20 @@ inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
auto v = refCounts.load(std::memory_order_acquire);
|
||||
XRPL_ASSERT((!(v & valueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
|
||||
XRPL_ASSERT(
|
||||
(!(v & valueMask)),
|
||||
"xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
|
||||
auto t = v & tagMask;
|
||||
XRPL_ASSERT((!t || t == tagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
|
||||
XRPL_ASSERT(
|
||||
(!t || t == tagMask),
|
||||
"xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline IntrusiveRefCounts::RefCountPair::RefCountPair(IntrusiveRefCounts::FieldType v) noexcept
|
||||
inline IntrusiveRefCounts::RefCountPair::RefCountPair(
|
||||
IntrusiveRefCounts::FieldType v) noexcept
|
||||
: strong{static_cast<CountType>(v & strongMask)}
|
||||
, weak{static_cast<CountType>((v & weakMask) >> StrongCountNumBits)}
|
||||
, partialDestroyStartedBit{v & partialDestroyStartedMask}
|
||||
@@ -434,8 +449,10 @@ IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept
|
||||
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||
"xrpl::IntrusiveRefCounts::RefCountPair::combinedValue : inputs "
|
||||
"inside range");
|
||||
return (static_cast<IntrusiveRefCounts::FieldType>(weak) << IntrusiveRefCounts::StrongCountNumBits) |
|
||||
static_cast<IntrusiveRefCounts::FieldType>(strong) | partialDestroyStartedBit | partialDestroyFinishedBit;
|
||||
return (static_cast<IntrusiveRefCounts::FieldType>(weak)
|
||||
<< IntrusiveRefCounts::StrongCountNumBits) |
|
||||
static_cast<IntrusiveRefCounts::FieldType>(strong) |
|
||||
partialDestroyStartedBit | partialDestroyFinishedBit;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -443,9 +460,11 @@ inline void
|
||||
partialDestructorFinished(T** o)
|
||||
{
|
||||
T& self = **o;
|
||||
IntrusiveRefCounts::RefCountPair p = self.refCounts.fetch_or(IntrusiveRefCounts::partialDestroyFinishedMask);
|
||||
IntrusiveRefCounts::RefCountPair p =
|
||||
self.refCounts.fetch_or(IntrusiveRefCounts::partialDestroyFinishedMask);
|
||||
XRPL_ASSERT(
|
||||
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit && !p.strong),
|
||||
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit &&
|
||||
!p.strong),
|
||||
"xrpl::partialDestructorFinished : not a weak ref");
|
||||
if (!p.weak)
|
||||
{
|
||||
|
||||
@@ -55,7 +55,8 @@ template <class = void>
|
||||
boost::thread_specific_ptr<detail::LocalValues>&
|
||||
getLocalValues()
|
||||
{
|
||||
static boost::thread_specific_ptr<detail::LocalValues> tsp(&detail::LocalValues::cleanup);
|
||||
static boost::thread_specific_ptr<detail::LocalValues> tsp(
|
||||
&detail::LocalValues::cleanup);
|
||||
return tsp;
|
||||
}
|
||||
|
||||
@@ -104,7 +105,9 @@ LocalValue<T>::operator*()
|
||||
}
|
||||
|
||||
return *reinterpret_cast<T*>(
|
||||
lvs->values.emplace(this, std::make_unique<detail::LocalValues::Value<T>>(t_)).first->second->get());
|
||||
lvs->values
|
||||
.emplace(this, std::make_unique<detail::LocalValues::Value<T>>(t_))
|
||||
.first->second->get());
|
||||
}
|
||||
} // namespace xrpl
|
||||
|
||||
|
||||
@@ -39,17 +39,22 @@ private:
|
||||
std::string partition_;
|
||||
|
||||
public:
|
||||
Sink(std::string const& partition, beast::severities::Severity thresh, Logs& logs);
|
||||
Sink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity thresh,
|
||||
Logs& logs);
|
||||
|
||||
Sink(Sink const&) = delete;
|
||||
Sink&
|
||||
operator=(Sink const&) = delete;
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& text) override;
|
||||
write(beast::severities::Severity level, std::string const& text)
|
||||
override;
|
||||
|
||||
void
|
||||
writeAlways(beast::severities::Severity level, std::string const& text) override;
|
||||
writeAlways(beast::severities::Severity level, std::string const& text)
|
||||
override;
|
||||
};
|
||||
|
||||
/** Manages a system file containing logged output.
|
||||
@@ -135,7 +140,11 @@ private:
|
||||
};
|
||||
|
||||
std::mutex mutable mutex_;
|
||||
std::map<std::string, std::unique_ptr<beast::Journal::Sink>, boost::beast::iless> sinks_;
|
||||
std::map<
|
||||
std::string,
|
||||
std::unique_ptr<beast::Journal::Sink>,
|
||||
boost::beast::iless>
|
||||
sinks_;
|
||||
beast::severities::Severity thresh_;
|
||||
File file_;
|
||||
bool silent_ = false;
|
||||
@@ -171,7 +180,11 @@ public:
|
||||
partition_severities() const;
|
||||
|
||||
void
|
||||
write(beast::severities::Severity level, std::string const& partition, std::string const& text, bool console);
|
||||
write(
|
||||
beast::severities::Severity level,
|
||||
std::string const& partition,
|
||||
std::string const& text,
|
||||
bool console);
|
||||
|
||||
std::string
|
||||
rotate();
|
||||
@@ -188,7 +201,9 @@ public:
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<beast::Journal::Sink>
|
||||
makeSink(std::string const& partition, beast::severities::Severity startingLevel);
|
||||
makeSink(
|
||||
std::string const& partition,
|
||||
beast::severities::Severity startingLevel);
|
||||
|
||||
public:
|
||||
static LogSeverity
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <boost/multiprecision/cpp_int.hpp>
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
class Number;
|
||||
@@ -17,18 +21,37 @@ class Number;
|
||||
std::string
|
||||
to_string(Number const& amount);
|
||||
|
||||
/** Returns a rough estimate of log10(value).
|
||||
*
|
||||
* The return value is a pair (log, rem), where log is the estimated log10,
|
||||
* and rem is value divided by 10^log. If rem is 1, then value is an exact
|
||||
* power of ten, and log is the exact log10(value).
|
||||
*
|
||||
* This function only works for positive values.
|
||||
*/
|
||||
template <typename T>
|
||||
constexpr std::pair<int, T>
|
||||
logTenEstimate(T value)
|
||||
{
|
||||
int log = 0;
|
||||
T remainder = value;
|
||||
while (value >= 10)
|
||||
{
|
||||
if (value % 10 == 0)
|
||||
remainder = remainder / 10;
|
||||
value /= 10;
|
||||
++log;
|
||||
}
|
||||
return {log, remainder};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr std::optional<int>
|
||||
logTen(T value)
|
||||
{
|
||||
int log = 0;
|
||||
while (value >= 10 && value % 10 == 0)
|
||||
{
|
||||
value /= 10;
|
||||
++log;
|
||||
}
|
||||
if (value == 1)
|
||||
return log;
|
||||
auto const est = logTenEstimate(value);
|
||||
if (est.second == 1)
|
||||
return est.first;
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
@@ -42,12 +65,10 @@ isPowerOfTen(T value)
|
||||
/** MantissaRange defines a range for the mantissa of a normalized Number.
|
||||
*
|
||||
* The mantissa is in the range [min, max], where
|
||||
* * min is a power of 10, and
|
||||
* * max = min * 10 - 1.
|
||||
*
|
||||
* The mantissa_scale enum indicates whether the range is "small" or "large".
|
||||
* This intentionally restricts the number of MantissaRanges that can be
|
||||
* instantiated to two: one for each scale.
|
||||
* used to two: one for each scale.
|
||||
*
|
||||
* The "small" scale is based on the behavior of STAmount for IOUs. It has a min
|
||||
* value of 10^15, and a max value of 10^16-1. This was sufficient for
|
||||
@@ -61,8 +82,8 @@ isPowerOfTen(T value)
|
||||
* "large" scale.
|
||||
*
|
||||
* The "large" scale is intended to represent all values that can be represented
|
||||
* by an STAmount - IOUs, XRP, and MPTs. It has a min value of 10^18, and a max
|
||||
* value of 10^19-1.
|
||||
* by an STAmount - IOUs, XRP, and MPTs. It has a min value of 2^63/10+1
|
||||
* (truncated), and a max value of 2^63-1.
|
||||
*
|
||||
* Note that if the mentioned amendments are eventually retired, this class
|
||||
* should be left in place, but the "small" scale option should be removed. This
|
||||
@@ -74,25 +95,50 @@ struct MantissaRange
|
||||
enum mantissa_scale { small, large };
|
||||
|
||||
explicit constexpr MantissaRange(mantissa_scale scale_)
|
||||
: min(getMin(scale_)), max(min * 10 - 1), log(logTen(min).value_or(-1)), scale(scale_)
|
||||
: max(getMax(scale_))
|
||||
, min(computeMin(max))
|
||||
, referenceMin(getReferenceMin(scale_, min))
|
||||
, log(computeLog(min))
|
||||
, scale(scale_)
|
||||
{
|
||||
// Since this is constexpr, if any of these throw, it won't compile
|
||||
if (min * 10 <= max)
|
||||
throw std::out_of_range("min * 10 <= max");
|
||||
if (max / 10 >= min)
|
||||
throw std::out_of_range("max / 10 >= min");
|
||||
if ((min - 1) * 10 > max)
|
||||
throw std::out_of_range("(min - 1) * 10 > max");
|
||||
// This is a little hacky
|
||||
if ((max + 10) / 10 < min)
|
||||
throw std::out_of_range("(max + 10) / 10 < min");
|
||||
}
|
||||
|
||||
rep min;
|
||||
// Explicitly delete copy and move operations
|
||||
MantissaRange(MantissaRange const&) = delete;
|
||||
MantissaRange(MantissaRange&&) = delete;
|
||||
MantissaRange&
|
||||
operator=(MantissaRange const&) = delete;
|
||||
MantissaRange&
|
||||
operator=(MantissaRange&&) = delete;
|
||||
|
||||
rep max;
|
||||
rep min;
|
||||
// This is not a great name. Used to determine if mantissas are in range,
|
||||
// but have fewer digits than max
|
||||
rep referenceMin;
|
||||
int log;
|
||||
mantissa_scale scale;
|
||||
|
||||
private:
|
||||
static constexpr rep
|
||||
getMin(mantissa_scale scale_)
|
||||
getMax(mantissa_scale scale)
|
||||
{
|
||||
switch (scale_)
|
||||
switch (scale)
|
||||
{
|
||||
case small:
|
||||
return 1'000'000'000'000'000ULL;
|
||||
return 9'999'999'999'999'999ULL;
|
||||
case large:
|
||||
return 1'000'000'000'000'000'000ULL;
|
||||
return std::numeric_limits<std::int64_t>::max();
|
||||
default:
|
||||
// Since this can never be called outside a non-constexpr
|
||||
// context, this throw assures that the build fails if an
|
||||
@@ -100,11 +146,57 @@ private:
|
||||
throw std::runtime_error("Unknown mantissa scale");
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr rep
|
||||
computeMin(rep max)
|
||||
{
|
||||
return max / 10 + 1;
|
||||
}
|
||||
|
||||
static constexpr rep
|
||||
getReferenceMin(mantissa_scale scale, rep min)
|
||||
{
|
||||
switch (scale)
|
||||
{
|
||||
case large:
|
||||
return 1'000'000'000'000'000'000ULL;
|
||||
default:
|
||||
if (isPowerOfTen(min))
|
||||
return min;
|
||||
throw std::runtime_error("Unknown/bad mantissa scale");
|
||||
}
|
||||
}
|
||||
|
||||
static constexpr rep
|
||||
computeLog(rep min)
|
||||
{
|
||||
auto const estimate = logTenEstimate(min);
|
||||
return estimate.first + (estimate.second == 1 ? 0 : 1);
|
||||
}
|
||||
};
|
||||
|
||||
// Like std::integral, but only 64-bit integral types.
|
||||
template <class T>
|
||||
concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::uint64_t>;
|
||||
concept Integral64 =
|
||||
std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::uint64_t>;
|
||||
|
||||
template <class STAmount, class Asset>
|
||||
concept CanUseAsScale = requires(Asset a, Number n) { STAmount(a, n); } &&
|
||||
requires(STAmount s) { s.exponent(); };
|
||||
|
||||
namespace detail {
|
||||
#ifdef _MSC_VER
|
||||
using uint128_t = boost::multiprecision::uint128_t;
|
||||
using int128_t = boost::multiprecision::int128_t;
|
||||
#else // !defined(_MSC_VER)
|
||||
using uint128_t = __uint128_t;
|
||||
using int128_t = __int128_t;
|
||||
#endif // !defined(_MSC_VER)
|
||||
|
||||
template <class T>
|
||||
concept UnsignedMantissa =
|
||||
std::is_unsigned_v<T> || std::is_same_v<T, uint128_t>;
|
||||
} // namespace detail
|
||||
|
||||
/** Number is a floating point type that can represent a wide range of values.
|
||||
*
|
||||
@@ -133,9 +225,7 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
|
||||
* 1. Normalization can be disabled by using the "unchecked" ctor tag. This
|
||||
* should only be used at specific conversion points, some constexpr
|
||||
* values, and in unit tests.
|
||||
* 2. The max of the "large" range, 10^19-1, is the largest 10^X-1 value that
|
||||
* fits in an unsigned 64-bit number. (10^19-1 < 2^64-1 and
|
||||
* 10^20-1 > 2^64-1). This avoids under- and overflows.
|
||||
* 2. The max of the "large" range, 2^63-1, TODO: explain the large range.
|
||||
*
|
||||
* ---- External Interface ----
|
||||
*
|
||||
@@ -149,7 +239,7 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
|
||||
*
|
||||
* Note:
|
||||
* 1. 2^63-1 is between 10^18 and 10^19-1, which are the limits of the "large"
|
||||
* mantissa range.
|
||||
* mantissa range. TODO: update this explanation.
|
||||
* 2. The functions mantissa() and exponent() return the external view of the
|
||||
* Number value, specifically using a signed 63-bit mantissa. This may
|
||||
* require altering the internal representation to fit into that range
|
||||
@@ -209,8 +299,7 @@ class Number
|
||||
using rep = std::int64_t;
|
||||
using internalrep = MantissaRange::rep;
|
||||
|
||||
bool negative_{false};
|
||||
internalrep mantissa_{0};
|
||||
rep mantissa_{0};
|
||||
int exponent_{std::numeric_limits<int>::lowest()};
|
||||
|
||||
public:
|
||||
@@ -218,9 +307,11 @@ public:
|
||||
constexpr static int minExponent = -32768;
|
||||
constexpr static int maxExponent = 32768;
|
||||
|
||||
#if MAXREP
|
||||
constexpr static internalrep maxRep = std::numeric_limits<rep>::max();
|
||||
static_assert(maxRep == 9'223'372'036'854'775'807);
|
||||
static_assert(-maxRep == std::numeric_limits<rep>::min() + 1);
|
||||
#endif
|
||||
|
||||
// May need to make unchecked private
|
||||
struct unchecked
|
||||
@@ -241,11 +332,22 @@ public:
|
||||
|
||||
Number(rep mantissa);
|
||||
explicit Number(rep mantissa, int exponent);
|
||||
explicit constexpr Number(bool negative, internalrep mantissa, int exponent, unchecked) noexcept;
|
||||
explicit constexpr Number(
|
||||
bool negative,
|
||||
internalrep mantissa,
|
||||
int exponent,
|
||||
unchecked) noexcept;
|
||||
// Assume unsigned values are... unsigned. i.e. positive
|
||||
explicit constexpr Number(internalrep mantissa, int exponent, unchecked) noexcept;
|
||||
explicit constexpr Number(
|
||||
internalrep mantissa,
|
||||
int exponent,
|
||||
unchecked) noexcept;
|
||||
// Only unit tests are expected to use this ctor
|
||||
explicit Number(bool negative, internalrep mantissa, int exponent, normalized);
|
||||
explicit Number(
|
||||
bool negative,
|
||||
internalrep mantissa,
|
||||
int exponent,
|
||||
normalized);
|
||||
// Assume unsigned values are... unsigned. i.e. positive
|
||||
explicit Number(internalrep mantissa, int exponent, normalized);
|
||||
|
||||
@@ -254,6 +356,26 @@ public:
|
||||
constexpr int
|
||||
exponent() const noexcept;
|
||||
|
||||
/** Get the scale of this Number for the given asset.
|
||||
*
|
||||
* "scale" is similar to "exponent", but from the perspective of STAmount,
|
||||
* which has different rules for determining the exponent than Number.
|
||||
*
|
||||
* Because Number does not have access to STAmount or Asset, this function
|
||||
* is implemented as a template, with the expectation that it will only be
|
||||
* used by those types. Any types that fit the requirements will work,
|
||||
* though, if there's a need.
|
||||
*
|
||||
* @tparam STAmount The STAmount type.
|
||||
* @tparam Asset The Asset type.
|
||||
* @param asset The asset to use for determining the scale.
|
||||
* @return The scale of this Number for the given asset.
|
||||
*/
|
||||
template <class STAmount, class Asset>
|
||||
int
|
||||
scale(Asset const& asset) const
|
||||
requires CanUseAsScale<STAmount, Asset>;
|
||||
|
||||
constexpr Number
|
||||
operator+() const noexcept;
|
||||
constexpr Number
|
||||
@@ -295,7 +417,7 @@ public:
|
||||
friend constexpr bool
|
||||
operator==(Number const& x, Number const& y) noexcept
|
||||
{
|
||||
return x.negative_ == y.negative_ && x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_;
|
||||
return x.mantissa_ == y.mantissa_ && x.exponent_ == y.exponent_;
|
||||
}
|
||||
|
||||
friend constexpr bool
|
||||
@@ -309,8 +431,8 @@ public:
|
||||
{
|
||||
// If the two amounts have different signs (zero is treated as positive)
|
||||
// then the comparison is true iff the left is negative.
|
||||
bool const lneg = x.negative_;
|
||||
bool const rneg = y.negative_;
|
||||
bool const lneg = x.mantissa_ < 0;
|
||||
bool const rneg = y.mantissa_ < 0;
|
||||
|
||||
if (lneg != rneg)
|
||||
return lneg;
|
||||
@@ -338,7 +460,7 @@ public:
|
||||
constexpr int
|
||||
signum() const noexcept
|
||||
{
|
||||
return negative_ ? -1 : (mantissa_ ? 1 : 0);
|
||||
return mantissa_ < 0 ? -1 : (mantissa_ ? 1 : 0);
|
||||
}
|
||||
|
||||
Number
|
||||
@@ -377,6 +499,9 @@ public:
|
||||
friend Number
|
||||
root2(Number f);
|
||||
|
||||
friend Number
|
||||
power(Number const& f, unsigned n, unsigned d);
|
||||
|
||||
// Thread local rounding control. Default is to_nearest
|
||||
enum rounding_mode { to_nearest, towards_zero, downward, upward };
|
||||
static rounding_mode
|
||||
@@ -441,22 +566,48 @@ private:
|
||||
static_assert(isPowerOfTen(smallRange.min));
|
||||
static_assert(smallRange.min == 1'000'000'000'000'000LL);
|
||||
static_assert(smallRange.max == 9'999'999'999'999'999LL);
|
||||
static_assert(smallRange.referenceMin == smallRange.min);
|
||||
static_assert(smallRange.log == 15);
|
||||
#if MAXREP
|
||||
static_assert(smallRange.min < maxRep);
|
||||
static_assert(smallRange.max < maxRep);
|
||||
#endif
|
||||
constexpr static MantissaRange largeRange{MantissaRange::large};
|
||||
static_assert(isPowerOfTen(largeRange.min));
|
||||
static_assert(largeRange.min == 1'000'000'000'000'000'000ULL);
|
||||
static_assert(largeRange.max == internalrep(9'999'999'999'999'999'999ULL));
|
||||
static_assert(!isPowerOfTen(largeRange.min));
|
||||
static_assert(largeRange.min == 922'337'203'685'477'581ULL);
|
||||
static_assert(largeRange.max == internalrep(9'223'372'036'854'775'807ULL));
|
||||
static_assert(largeRange.max == std::numeric_limits<rep>::max());
|
||||
static_assert(largeRange.referenceMin == 1'000'000'000'000'000'000ULL);
|
||||
static_assert(largeRange.log == 18);
|
||||
// There are 2 values that will not fit in largeRange without some extra
|
||||
// work
|
||||
// * 9223372036854775808
|
||||
// * 9223372036854775809
|
||||
// They both end up < min, but with a leftover. If they round up, everything
|
||||
// will be fine. If they don't, well need to bring them up into range.
|
||||
// Guard::bringIntoRange handles this situation.
|
||||
|
||||
#if MAXREP
|
||||
static_assert(largeRange.min < maxRep);
|
||||
static_assert(largeRange.max > maxRep);
|
||||
#endif
|
||||
|
||||
// The range for the mantissa when normalized.
|
||||
// Use reference_wrapper to avoid making copies, and prevent accidentally
|
||||
// changing the values inside the range.
|
||||
static thread_local std::reference_wrapper<MantissaRange const> range_;
|
||||
|
||||
// And one is needed because it needs to choose between oneSmall and
|
||||
// oneLarge based on the current range
|
||||
static Number
|
||||
one(MantissaRange const& range);
|
||||
|
||||
static Number
|
||||
root(MantissaRange const& range, Number f, unsigned d);
|
||||
|
||||
void
|
||||
normalize(MantissaRange const& range);
|
||||
|
||||
void
|
||||
normalize();
|
||||
|
||||
@@ -479,11 +630,14 @@ private:
|
||||
friend void
|
||||
doNormalize(
|
||||
bool& negative,
|
||||
T& mantissa_,
|
||||
int& exponent_,
|
||||
T& mantissa,
|
||||
int& exponent,
|
||||
MantissaRange::rep const& minMantissa,
|
||||
MantissaRange::rep const& maxMantissa);
|
||||
|
||||
bool
|
||||
isnormal(MantissaRange const& range) const noexcept;
|
||||
|
||||
bool
|
||||
isnormal() const noexcept;
|
||||
|
||||
@@ -500,28 +654,88 @@ private:
|
||||
static internalrep
|
||||
externalToInternal(rep mantissa);
|
||||
|
||||
/** Breaks down the number into components, potentially de-normalizing it.
|
||||
*
|
||||
* Ensures that the mantissa always has range_.log + 1 digits.
|
||||
*
|
||||
*/
|
||||
template <detail::UnsignedMantissa Rep = internalrep>
|
||||
std::tuple<bool, Rep, int>
|
||||
toInternal(MantissaRange const& range) const;
|
||||
|
||||
/** Breaks down the number into components, potentially de-normalizing it.
|
||||
*
|
||||
* Ensures that the mantissa always has range_.log + 1 digits.
|
||||
*
|
||||
*/
|
||||
template <detail::UnsignedMantissa Rep = internalrep>
|
||||
std::tuple<bool, Rep, int>
|
||||
toInternal() const;
|
||||
|
||||
/** Rebuilds the number from components.
|
||||
*
|
||||
* If "normalized" is true, the values are expected to be normalized - all
|
||||
* in their valid ranges.
|
||||
*
|
||||
* If "normalized" is false, the values are expected to be "near
|
||||
* normalized", meaning that the mantissa has to be modified at most once to
|
||||
* bring it back into range.
|
||||
*
|
||||
*/
|
||||
template <
|
||||
bool expectNormal = true,
|
||||
detail::UnsignedMantissa Rep = internalrep>
|
||||
void
|
||||
fromInternal(
|
||||
bool negative,
|
||||
Rep mantissa,
|
||||
int exponent,
|
||||
MantissaRange const* pRange);
|
||||
|
||||
/** Rebuilds the number from components.
|
||||
*
|
||||
* If "normalized" is true, the values are expected to be normalized - all
|
||||
* in their valid ranges.
|
||||
*
|
||||
* If "normalized" is false, the values are expected to be "near
|
||||
* normalized", meaning that the mantissa has to be modified at most once to
|
||||
* bring it back into range.
|
||||
*
|
||||
*/
|
||||
template <
|
||||
bool expectNormal = true,
|
||||
detail::UnsignedMantissa Rep = internalrep>
|
||||
void
|
||||
fromInternal(bool negative, Rep mantissa, int exponent);
|
||||
|
||||
class Guard;
|
||||
|
||||
public:
|
||||
constexpr static internalrep largestMantissa = largeRange.max;
|
||||
};
|
||||
|
||||
inline constexpr Number::Number(bool negative, internalrep mantissa, int exponent, unchecked) noexcept
|
||||
: negative_(negative), mantissa_{mantissa}, exponent_{exponent}
|
||||
inline constexpr Number::Number(
|
||||
bool negative,
|
||||
internalrep mantissa,
|
||||
int exponent,
|
||||
unchecked) noexcept
|
||||
: mantissa_{(negative ? -1 : 1) * static_cast<rep>(mantissa)}
|
||||
, exponent_{exponent}
|
||||
{
|
||||
}
|
||||
|
||||
inline constexpr Number::Number(internalrep mantissa, int exponent, unchecked) noexcept
|
||||
inline constexpr Number::Number(
|
||||
internalrep mantissa,
|
||||
int exponent,
|
||||
unchecked) noexcept
|
||||
: Number(false, mantissa, exponent, unchecked{})
|
||||
{
|
||||
}
|
||||
|
||||
constexpr static Number numZero{};
|
||||
|
||||
inline Number::Number(bool negative, internalrep mantissa, int exponent, normalized)
|
||||
: Number(negative, mantissa, exponent, unchecked{})
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
inline Number::Number(internalrep mantissa, int exponent, normalized) : Number(false, mantissa, exponent, normalized{})
|
||||
inline Number::Number(internalrep mantissa, int exponent, normalized)
|
||||
: Number(false, mantissa, exponent, normalized{})
|
||||
{
|
||||
}
|
||||
|
||||
@@ -542,17 +756,7 @@ inline Number::Number(rep mantissa) : Number{mantissa, 0}
|
||||
inline constexpr Number::rep
|
||||
Number::mantissa() const noexcept
|
||||
{
|
||||
auto m = mantissa_;
|
||||
if (m > maxRep)
|
||||
{
|
||||
XRPL_ASSERT_PARTS(
|
||||
!isnormal() || (m % 10 == 0 && m / 10 <= maxRep),
|
||||
"xrpl::Number::mantissa",
|
||||
"large normalized mantissa has no remainder");
|
||||
m /= 10;
|
||||
}
|
||||
auto const sign = negative_ ? -1 : 1;
|
||||
return sign * static_cast<Number::rep>(m);
|
||||
return mantissa_;
|
||||
}
|
||||
|
||||
/** Returns the exponent of the external view of the Number.
|
||||
@@ -563,16 +767,15 @@ Number::mantissa() const noexcept
|
||||
inline constexpr int
|
||||
Number::exponent() const noexcept
|
||||
{
|
||||
auto e = exponent_;
|
||||
if (mantissa_ > maxRep)
|
||||
{
|
||||
XRPL_ASSERT_PARTS(
|
||||
!isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= maxRep),
|
||||
"xrpl::Number::exponent",
|
||||
"large normalized mantissa has no remainder");
|
||||
++e;
|
||||
}
|
||||
return e;
|
||||
return exponent_;
|
||||
}
|
||||
|
||||
template <class STAmount, class Asset>
|
||||
int
|
||||
Number::scale(Asset const& asset) const
|
||||
requires CanUseAsScale<STAmount, Asset>
|
||||
{
|
||||
return STAmount{asset, *this}.exponent();
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
@@ -587,7 +790,7 @@ Number::operator-() const noexcept
|
||||
if (mantissa_ == 0)
|
||||
return Number{};
|
||||
auto x = *this;
|
||||
x.negative_ = !x.negative_;
|
||||
x.mantissa_ = -1 * x.mantissa_;
|
||||
return x;
|
||||
}
|
||||
|
||||
@@ -668,39 +871,62 @@ Number::min() noexcept
|
||||
inline Number
|
||||
Number::max() noexcept
|
||||
{
|
||||
return Number{false, std::min(range_.get().max, maxRep), maxExponent, unchecked{}};
|
||||
return Number{false, range_.get().max, maxExponent, unchecked{}};
|
||||
}
|
||||
|
||||
inline Number
|
||||
Number::lowest() noexcept
|
||||
{
|
||||
return Number{true, std::min(range_.get().max, maxRep), maxExponent, unchecked{}};
|
||||
return Number{true, range_.get().max, maxExponent, unchecked{}};
|
||||
}
|
||||
|
||||
inline bool
|
||||
Number::isnormal(MantissaRange const& range) const noexcept
|
||||
{
|
||||
auto const abs_m = mantissa_ < 0 ? -mantissa_ : mantissa_;
|
||||
|
||||
return *this == Number{} ||
|
||||
(range.min <= abs_m && abs_m <= range.max && //
|
||||
minExponent <= exponent_ && exponent_ <= maxExponent);
|
||||
}
|
||||
|
||||
inline bool
|
||||
Number::isnormal() const noexcept
|
||||
{
|
||||
MantissaRange const& range = range_;
|
||||
auto const abs_m = mantissa_;
|
||||
return *this == Number{} ||
|
||||
(range.min <= abs_m && abs_m <= range.max && (abs_m <= maxRep || abs_m % 10 == 0) && minExponent <= exponent_ &&
|
||||
exponent_ <= maxExponent);
|
||||
return isnormal(range_);
|
||||
}
|
||||
|
||||
template <Integral64 T>
|
||||
std::pair<T, int>
|
||||
Number::normalizeToRange(T minMantissa, T maxMantissa) const
|
||||
{
|
||||
bool negative = negative_;
|
||||
internalrep mantissa = mantissa_;
|
||||
bool negative = mantissa_ < 0;
|
||||
auto const sign = negative ? -1 : 1;
|
||||
internalrep mantissa = sign * mantissa_;
|
||||
int exponent = exponent_;
|
||||
|
||||
if constexpr (std::is_unsigned_v<T>)
|
||||
XRPL_ASSERT_PARTS(!negative, "xrpl::Number::normalizeToRange", "Number is non-negative for unsigned range.");
|
||||
{
|
||||
XRPL_ASSERT_PARTS(
|
||||
!negative,
|
||||
"xrpl::Number::normalizeToRange",
|
||||
"Number is non-negative for unsigned range.");
|
||||
// To avoid logical errors in release builds, throw if the Number is
|
||||
// negative for an unsigned range.
|
||||
if (negative)
|
||||
throw std::runtime_error(
|
||||
"Number::normalizeToRange: Number is negative for "
|
||||
"unsigned range.");
|
||||
}
|
||||
Number::normalize(negative, mantissa, exponent, minMantissa, maxMantissa);
|
||||
|
||||
auto const sign = negative ? -1 : 1;
|
||||
return std::make_pair(static_cast<T>(sign * mantissa), exponent);
|
||||
// Cast mantissa to signed type first (if T is a signed type) to avoid
|
||||
// unsigned integer overflow when multiplying by negative sign
|
||||
T signedMantissa = static_cast<T>(mantissa);
|
||||
if (negative)
|
||||
signedMantissa = -signedMantissa;
|
||||
return std::make_pair(signedMantissa, exponent);
|
||||
return std::make_pair(sign * static_cast<T>(mantissa), exponent);
|
||||
}
|
||||
|
||||
inline constexpr Number
|
||||
@@ -765,7 +991,8 @@ public:
|
||||
{
|
||||
Number::setround(mode_);
|
||||
}
|
||||
explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept : mode_{mode}
|
||||
explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept
|
||||
: mode_{mode}
|
||||
{
|
||||
}
|
||||
saveNumberRoundMode(saveNumberRoundMode const&) = delete;
|
||||
@@ -782,7 +1009,8 @@ class NumberRoundModeGuard
|
||||
saveNumberRoundMode saved_;
|
||||
|
||||
public:
|
||||
explicit NumberRoundModeGuard(Number::rounding_mode mode) noexcept : saved_{Number::setround(mode)}
|
||||
explicit NumberRoundModeGuard(Number::rounding_mode mode) noexcept
|
||||
: saved_{Number::setround(mode)}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -802,7 +1030,9 @@ class NumberMantissaScaleGuard
|
||||
MantissaRange::mantissa_scale const saved_;
|
||||
|
||||
public:
|
||||
explicit NumberMantissaScaleGuard(MantissaRange::mantissa_scale scale) noexcept : saved_{Number::getMantissaScale()}
|
||||
explicit NumberMantissaScaleGuard(
|
||||
MantissaRange::mantissa_scale scale) noexcept
|
||||
: saved_{Number::getMantissaScale()}
|
||||
{
|
||||
Number::setMantissaScale(scale);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,8 @@ namespace xrpl {
|
||||
class Resolver
|
||||
{
|
||||
public:
|
||||
using HandlerType = std::function<void(std::string, std::vector<beast::IP::Endpoint>)>;
|
||||
using HandlerType =
|
||||
std::function<void(std::string, std::vector<beast::IP::Endpoint>)>;
|
||||
|
||||
virtual ~Resolver() = 0;
|
||||
|
||||
@@ -40,7 +41,9 @@ public:
|
||||
}
|
||||
|
||||
virtual void
|
||||
resolve(std::vector<std::string> const& names, HandlerType const& handler) = 0;
|
||||
resolve(
|
||||
std::vector<std::string> const& names,
|
||||
HandlerType const& handler) = 0;
|
||||
/** @} */
|
||||
};
|
||||
|
||||
|
||||
@@ -5,28 +5,34 @@
|
||||
|
||||
namespace xrpl {
|
||||
template <class T>
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(SharedWeakCachePointer const& rhs) = default;
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(
|
||||
SharedWeakCachePointer const& rhs) = default;
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(std::shared_ptr<TT> const& rhs) : combo_{rhs}
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(
|
||||
std::shared_ptr<TT> const& rhs)
|
||||
: combo_{rhs}
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(SharedWeakCachePointer&& rhs) = default;
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(
|
||||
SharedWeakCachePointer&& rhs) = default;
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(std::shared_ptr<TT>&& rhs) : combo_{std::move(rhs)}
|
||||
SharedWeakCachePointer<T>::SharedWeakCachePointer(std::shared_ptr<TT>&& rhs)
|
||||
: combo_{std::move(rhs)}
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SharedWeakCachePointer<T>&
|
||||
SharedWeakCachePointer<T>::operator=(SharedWeakCachePointer const& rhs) = default;
|
||||
SharedWeakCachePointer<T>::operator=(SharedWeakCachePointer const& rhs) =
|
||||
default;
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
|
||||
@@ -51,7 +51,11 @@ class SlabAllocator
|
||||
// The extent of the underlying memory block:
|
||||
std::size_t const size_;
|
||||
|
||||
SlabBlock(SlabBlock* next, std::uint8_t* data, std::size_t size, std::size_t item)
|
||||
SlabBlock(
|
||||
SlabBlock* next,
|
||||
std::uint8_t* data,
|
||||
std::size_t size,
|
||||
std::size_t item)
|
||||
: next_(next), p_(data), size_(size)
|
||||
{
|
||||
// We don't need to grab the mutex here, since we're the only
|
||||
@@ -122,7 +126,9 @@ class SlabAllocator
|
||||
void
|
||||
deallocate(std::uint8_t* ptr) noexcept
|
||||
{
|
||||
XRPL_ASSERT(own(ptr), "xrpl::SlabAllocator::SlabBlock::deallocate : own input");
|
||||
XRPL_ASSERT(
|
||||
own(ptr),
|
||||
"xrpl::SlabAllocator::SlabBlock::deallocate : own input");
|
||||
|
||||
std::lock_guard l(m_);
|
||||
|
||||
@@ -156,13 +162,18 @@ public:
|
||||
contexts (e.g. when minimal memory usage is needed) and
|
||||
allows for graceful failure.
|
||||
*/
|
||||
constexpr explicit SlabAllocator(std::size_t extra, std::size_t alloc = 0, std::size_t align = 0)
|
||||
constexpr explicit SlabAllocator(
|
||||
std::size_t extra,
|
||||
std::size_t alloc = 0,
|
||||
std::size_t align = 0)
|
||||
: itemAlignment_(align ? align : alignof(Type))
|
||||
, itemSize_(boost::alignment::align_up(sizeof(Type) + extra, itemAlignment_))
|
||||
, itemSize_(
|
||||
boost::alignment::align_up(sizeof(Type) + extra, itemAlignment_))
|
||||
, slabSize_(alloc)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(itemAlignment_ & (itemAlignment_ - 1)) == 0, "xrpl::SlabAllocator::SlabAllocator : valid alignment");
|
||||
(itemAlignment_ & (itemAlignment_ - 1)) == 0,
|
||||
"xrpl::SlabAllocator::SlabAllocator : valid alignment");
|
||||
}
|
||||
|
||||
SlabAllocator(SlabAllocator const& other) = delete;
|
||||
@@ -211,7 +222,8 @@ public:
|
||||
|
||||
// We want to allocate the memory at a 2 MiB boundary, to make it
|
||||
// possible to use hugepage mappings on Linux:
|
||||
auto buf = boost::alignment::aligned_alloc(megabytes(std::size_t(2)), size);
|
||||
auto buf =
|
||||
boost::alignment::aligned_alloc(megabytes(std::size_t(2)), size);
|
||||
|
||||
// clang-format off
|
||||
if (!buf) [[unlikely]]
|
||||
@@ -229,21 +241,31 @@ public:
|
||||
|
||||
// We need to carve out a bit of memory for the slab header
|
||||
// and then align the rest appropriately:
|
||||
auto slabData = reinterpret_cast<void*>(reinterpret_cast<std::uint8_t*>(buf) + sizeof(SlabBlock));
|
||||
auto slabData = reinterpret_cast<void*>(
|
||||
reinterpret_cast<std::uint8_t*>(buf) + sizeof(SlabBlock));
|
||||
auto slabSize = size - sizeof(SlabBlock);
|
||||
|
||||
// This operation is essentially guaranteed not to fail but
|
||||
// let's be careful anyways.
|
||||
if (!boost::alignment::align(itemAlignment_, itemSize_, slabData, slabSize))
|
||||
if (!boost::alignment::align(
|
||||
itemAlignment_, itemSize_, slabData, slabSize))
|
||||
{
|
||||
boost::alignment::aligned_free(buf);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
slab = new (buf) SlabBlock(slabs_.load(), reinterpret_cast<std::uint8_t*>(slabData), slabSize, itemSize_);
|
||||
slab = new (buf) SlabBlock(
|
||||
slabs_.load(),
|
||||
reinterpret_cast<std::uint8_t*>(slabData),
|
||||
slabSize,
|
||||
itemSize_);
|
||||
|
||||
// Link the new slab
|
||||
while (!slabs_.compare_exchange_weak(slab->next_, slab, std::memory_order_release, std::memory_order_relaxed))
|
||||
while (!slabs_.compare_exchange_weak(
|
||||
slab->next_,
|
||||
slab,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed))
|
||||
{
|
||||
; // Nothing to do
|
||||
}
|
||||
@@ -300,7 +322,10 @@ public:
|
||||
std::size_t align;
|
||||
|
||||
public:
|
||||
constexpr SlabConfig(std::size_t extra_, std::size_t alloc_ = 0, std::size_t align_ = alignof(Type))
|
||||
constexpr SlabConfig(
|
||||
std::size_t extra_,
|
||||
std::size_t alloc_ = 0,
|
||||
std::size_t align_ = alignof(Type))
|
||||
: extra(extra_), alloc(alloc_), align(align_)
|
||||
{
|
||||
}
|
||||
@@ -311,14 +336,23 @@ public:
|
||||
// Ensure that the specified allocators are sorted from smallest to
|
||||
// largest by size:
|
||||
std::sort(
|
||||
std::begin(cfg), std::end(cfg), [](SlabConfig const& a, SlabConfig const& b) { return a.extra < b.extra; });
|
||||
std::begin(cfg),
|
||||
std::end(cfg),
|
||||
[](SlabConfig const& a, SlabConfig const& b) {
|
||||
return a.extra < b.extra;
|
||||
});
|
||||
|
||||
// We should never have two slabs of the same size
|
||||
if (std::adjacent_find(std::begin(cfg), std::end(cfg), [](SlabConfig const& a, SlabConfig const& b) {
|
||||
return a.extra == b.extra;
|
||||
}) != cfg.end())
|
||||
if (std::adjacent_find(
|
||||
std::begin(cfg),
|
||||
std::end(cfg),
|
||||
[](SlabConfig const& a, SlabConfig const& b) {
|
||||
return a.extra == b.extra;
|
||||
}) != cfg.end())
|
||||
{
|
||||
throw std::runtime_error("SlabAllocatorSet<" + beast::type_name<Type>() + ">: duplicate slab size");
|
||||
throw std::runtime_error(
|
||||
"SlabAllocatorSet<" + beast::type_name<Type>() +
|
||||
">: duplicate slab size");
|
||||
}
|
||||
|
||||
for (auto const& c : cfg)
|
||||
|
||||
@@ -41,7 +41,8 @@ public:
|
||||
operator=(Slice const&) noexcept = default;
|
||||
|
||||
/** Create a slice pointing to existing memory. */
|
||||
Slice(void const* data, std::size_t size) noexcept : data_(reinterpret_cast<std::uint8_t const*>(data)), size_(size)
|
||||
Slice(void const* data, std::size_t size) noexcept
|
||||
: data_(reinterpret_cast<std::uint8_t const*>(data)), size_(size)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -84,7 +85,9 @@ public:
|
||||
std::uint8_t
|
||||
operator[](std::size_t i) const noexcept
|
||||
{
|
||||
XRPL_ASSERT(i < size_, "xrpl::Slice::operator[](std::size_t) const : valid input");
|
||||
XRPL_ASSERT(
|
||||
i < size_,
|
||||
"xrpl::Slice::operator[](std::size_t) const : valid input");
|
||||
return data_[i];
|
||||
}
|
||||
|
||||
@@ -159,7 +162,9 @@ public:
|
||||
@throws std::out_of_range if pos > size()
|
||||
*/
|
||||
Slice
|
||||
substr(std::size_t pos, std::size_t count = std::numeric_limits<std::size_t>::max()) const
|
||||
substr(
|
||||
std::size_t pos,
|
||||
std::size_t count = std::numeric_limits<std::size_t>::max()) const
|
||||
{
|
||||
if (pos > size())
|
||||
throw std::out_of_range("Requested sub-slice is out of bounds");
|
||||
@@ -198,7 +203,11 @@ operator!=(Slice const& lhs, Slice const& rhs) noexcept
|
||||
inline bool
|
||||
operator<(Slice const& lhs, Slice const& rhs) noexcept
|
||||
{
|
||||
return std::lexicographical_compare(lhs.data(), lhs.data() + lhs.size(), rhs.data(), rhs.data() + rhs.size());
|
||||
return std::lexicographical_compare(
|
||||
lhs.data(),
|
||||
lhs.data() + lhs.size(),
|
||||
rhs.data(),
|
||||
rhs.data() + rhs.size());
|
||||
}
|
||||
|
||||
template <class Stream>
|
||||
@@ -210,14 +219,18 @@ operator<<(Stream& s, Slice const& v)
|
||||
}
|
||||
|
||||
template <class T, std::size_t N>
|
||||
std::enable_if_t<std::is_same<T, char>::value || std::is_same<T, unsigned char>::value, Slice>
|
||||
std::enable_if_t<
|
||||
std::is_same<T, char>::value || std::is_same<T, unsigned char>::value,
|
||||
Slice>
|
||||
makeSlice(std::array<T, N> const& a)
|
||||
{
|
||||
return Slice(a.data(), a.size());
|
||||
}
|
||||
|
||||
template <class T, class Alloc>
|
||||
std::enable_if_t<std::is_same<T, char>::value || std::is_same<T, unsigned char>::value, Slice>
|
||||
std::enable_if_t<
|
||||
std::is_same<T, char>::value || std::is_same<T, unsigned char>::value,
|
||||
Slice>
|
||||
makeSlice(std::vector<T, Alloc> const& v)
|
||||
{
|
||||
return Slice(v.data(), v.size());
|
||||
|
||||
@@ -109,7 +109,8 @@ struct parsedURL
|
||||
bool
|
||||
operator==(parsedURL const& other) const
|
||||
{
|
||||
return scheme == other.scheme && domain == other.domain && port == other.port && path == other.path;
|
||||
return scheme == other.scheme && domain == other.domain &&
|
||||
port == other.port && path == other.path;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -56,7 +56,8 @@ public:
|
||||
clock_type::duration expiration,
|
||||
clock_type& clock,
|
||||
beast::Journal journal,
|
||||
beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::New());
|
||||
beast::insight::Collector::ptr const& collector =
|
||||
beast::insight::NullCollector::New());
|
||||
|
||||
public:
|
||||
/** Return the clock associated with the cache. */
|
||||
@@ -113,10 +114,15 @@ public:
|
||||
*/
|
||||
template <class R>
|
||||
bool
|
||||
canonicalize(key_type const& key, SharedPointerType& data, R&& replaceCallback);
|
||||
canonicalize(
|
||||
key_type const& key,
|
||||
SharedPointerType& data,
|
||||
R&& replaceCallback);
|
||||
|
||||
bool
|
||||
canonicalize_replace_cache(key_type const& key, SharedPointerType const& data);
|
||||
canonicalize_replace_cache(
|
||||
key_type const& key,
|
||||
SharedPointerType const& data);
|
||||
|
||||
bool
|
||||
canonicalize_replace_client(key_type const& key, SharedPointerType& data);
|
||||
@@ -130,7 +136,8 @@ public:
|
||||
*/
|
||||
template <class ReturnType = bool>
|
||||
auto
|
||||
insert(key_type const& key, T const& value) -> std::enable_if_t<!IsKeyCache, ReturnType>;
|
||||
insert(key_type const& key, T const& value)
|
||||
-> std::enable_if_t<!IsKeyCache, ReturnType>;
|
||||
|
||||
template <class ReturnType = bool>
|
||||
auto
|
||||
@@ -176,7 +183,10 @@ private:
|
||||
struct Stats
|
||||
{
|
||||
template <class Handler>
|
||||
Stats(std::string const& prefix, Handler const& handler, beast::insight::Collector::ptr const& collector)
|
||||
Stats(
|
||||
std::string const& prefix,
|
||||
Handler const& handler,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
: hook(collector->make_hook(handler))
|
||||
, size(collector->make_gauge(prefix, "size"))
|
||||
, hit_rate(collector->make_gauge(prefix, "hit_rate"))
|
||||
@@ -198,7 +208,8 @@ private:
|
||||
public:
|
||||
clock_type::time_point last_access;
|
||||
|
||||
explicit KeyOnlyEntry(clock_type::time_point const& last_access_) : last_access(last_access_)
|
||||
explicit KeyOnlyEntry(clock_type::time_point const& last_access_)
|
||||
: last_access(last_access_)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -215,7 +226,9 @@ private:
|
||||
shared_weak_combo_pointer_type ptr;
|
||||
clock_type::time_point last_access;
|
||||
|
||||
ValueEntry(clock_type::time_point const& last_access_, shared_pointer_type const& ptr_)
|
||||
ValueEntry(
|
||||
clock_type::time_point const& last_access_,
|
||||
shared_pointer_type const& ptr_)
|
||||
: ptr(ptr_), last_access(last_access_)
|
||||
{
|
||||
}
|
||||
@@ -249,13 +262,18 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
typedef typename std::conditional<IsKeyCache, KeyOnlyEntry, ValueEntry>::type Entry;
|
||||
typedef
|
||||
typename std::conditional<IsKeyCache, KeyOnlyEntry, ValueEntry>::type
|
||||
Entry;
|
||||
|
||||
using KeyOnlyCacheType = hardened_partitioned_hash_map<key_type, KeyOnlyEntry, Hash, KeyEqual>;
|
||||
using KeyOnlyCacheType =
|
||||
hardened_partitioned_hash_map<key_type, KeyOnlyEntry, Hash, KeyEqual>;
|
||||
|
||||
using KeyValueCacheType = hardened_partitioned_hash_map<key_type, ValueEntry, Hash, KeyEqual>;
|
||||
using KeyValueCacheType =
|
||||
hardened_partitioned_hash_map<key_type, ValueEntry, Hash, KeyEqual>;
|
||||
|
||||
using cache_type = hardened_partitioned_hash_map<key_type, Entry, Hash, KeyEqual>;
|
||||
using cache_type =
|
||||
hardened_partitioned_hash_map<key_type, Entry, Hash, KeyEqual>;
|
||||
|
||||
[[nodiscard]] std::thread
|
||||
sweepHelper(
|
||||
|
||||
@@ -15,13 +15,22 @@ template <
|
||||
class Hash,
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::TaggedCache(
|
||||
std::string const& name,
|
||||
int size,
|
||||
clock_type::duration expiration,
|
||||
clock_type& clock,
|
||||
beast::Journal journal,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
inline TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::
|
||||
TaggedCache(
|
||||
std::string const& name,
|
||||
int size,
|
||||
clock_type::duration expiration,
|
||||
clock_type& clock,
|
||||
beast::Journal journal,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
: m_journal(journal)
|
||||
, m_clock(clock)
|
||||
, m_stats(name, std::bind(&TaggedCache::collect_metrics, this), collector)
|
||||
@@ -44,8 +53,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline auto
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::clock()
|
||||
-> clock_type&
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::clock() -> clock_type&
|
||||
{
|
||||
return m_clock;
|
||||
}
|
||||
@@ -60,7 +76,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline std::size_t
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::size() const
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::size() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache.size();
|
||||
@@ -76,7 +100,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline int
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::getCacheSize() const
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::getCacheSize() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache_count;
|
||||
@@ -92,7 +124,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline int
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::getTrackSize() const
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::getTrackSize() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
return m_cache.size();
|
||||
@@ -108,7 +148,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline float
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::getHitRate()
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::getHitRate()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const total = static_cast<float>(m_hits + m_misses);
|
||||
@@ -125,7 +173,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline void
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::clear()
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::clear()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.clear();
|
||||
@@ -142,7 +198,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline void
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::reset()
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::reset()
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
m_cache.clear();
|
||||
@@ -162,8 +226,15 @@ template <
|
||||
class Mutex>
|
||||
template <class KeyComparable>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::touch_if_exists(
|
||||
KeyComparable const& key)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::touch_if_exists(KeyComparable const& key)
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const iter(m_cache.find(key));
|
||||
@@ -187,7 +258,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline void
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::sweep()
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::sweep()
|
||||
{
|
||||
// Keep references to all the stuff we sweep
|
||||
// For performance, each worker thread should exit before the swept data
|
||||
@@ -201,7 +280,8 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
|
||||
if (m_target_size == 0 || (static_cast<int>(m_cache.size()) <= m_target_size))
|
||||
if (m_target_size == 0 ||
|
||||
(static_cast<int>(m_cache.size()) <= m_target_size))
|
||||
{
|
||||
when_expire = now - m_target_age;
|
||||
}
|
||||
@@ -213,8 +293,10 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
if (when_expire > (now - minimumAge))
|
||||
when_expire = now - minimumAge;
|
||||
|
||||
JLOG(m_journal.trace()) << m_name << " is growing fast " << m_cache.size() << " of " << m_target_size
|
||||
<< " aging at " << (now - when_expire).count() << " of " << m_target_age.count();
|
||||
JLOG(m_journal.trace())
|
||||
<< m_name << " is growing fast " << m_cache.size() << " of "
|
||||
<< m_target_size << " aging at " << (now - when_expire).count()
|
||||
<< " of " << m_target_age.count();
|
||||
}
|
||||
|
||||
std::vector<std::thread> workers;
|
||||
@@ -223,7 +305,13 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
|
||||
for (std::size_t p = 0; p < m_cache.partitions(); ++p)
|
||||
{
|
||||
workers.push_back(sweepHelper(when_expire, now, m_cache.map()[p], allStuffToSweep[p], allRemovals, lock));
|
||||
workers.push_back(sweepHelper(
|
||||
when_expire,
|
||||
now,
|
||||
m_cache.map()[p],
|
||||
allStuffToSweep[p],
|
||||
allRemovals,
|
||||
lock));
|
||||
}
|
||||
for (std::thread& worker : workers)
|
||||
worker.join();
|
||||
@@ -234,7 +322,9 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
// and decrement the reference count on each strong pointer.
|
||||
JLOG(m_journal.debug())
|
||||
<< m_name << " TaggedCache sweep lock duration "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - start).count()
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start)
|
||||
.count()
|
||||
<< "ms";
|
||||
}
|
||||
|
||||
@@ -248,9 +338,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::del(
|
||||
key_type const& key,
|
||||
bool valid)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::del(key_type const& key, bool valid)
|
||||
{
|
||||
// Remove from cache, if !valid, remove from map too. Returns true if
|
||||
// removed from cache
|
||||
@@ -289,10 +385,19 @@ template <
|
||||
class Mutex>
|
||||
template <class R>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::canonicalize(
|
||||
key_type const& key,
|
||||
SharedPointerType& data,
|
||||
R&& replaceCallback)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::
|
||||
canonicalize(
|
||||
key_type const& key,
|
||||
SharedPointerType& data,
|
||||
R&& replaceCallback)
|
||||
{
|
||||
// Return canonical value, store if needed, refresh in cache
|
||||
// Return values: true=we had the data already
|
||||
@@ -303,7 +408,9 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
if (cit == m_cache.end())
|
||||
{
|
||||
m_cache.emplace(
|
||||
std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(m_clock.now(), data));
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(key),
|
||||
std::forward_as_tuple(m_clock.now(), data));
|
||||
++m_cache_count;
|
||||
return false;
|
||||
}
|
||||
@@ -373,10 +480,21 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
canonicalize_replace_cache(key_type const& key, SharedPointerType const& data)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::
|
||||
canonicalize_replace_cache(
|
||||
key_type const& key,
|
||||
SharedPointerType const& data)
|
||||
{
|
||||
return canonicalize(key, const_cast<SharedPointerType&>(data), []() { return true; });
|
||||
return canonicalize(
|
||||
key, const_cast<SharedPointerType&>(data), []() { return true; });
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -389,7 +507,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::
|
||||
canonicalize_replace_client(key_type const& key, SharedPointerType& data)
|
||||
{
|
||||
return canonicalize(key, data, []() { return false; });
|
||||
@@ -405,8 +531,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline SharedPointerType
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::fetch(
|
||||
key_type const& key)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::fetch(key_type const& key)
|
||||
{
|
||||
std::lock_guard<mutex_type> l(m_mutex);
|
||||
auto ret = initialFetch(key, l);
|
||||
@@ -426,9 +559,16 @@ template <
|
||||
class Mutex>
|
||||
template <class ReturnType>
|
||||
inline auto
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::insert(
|
||||
key_type const& key,
|
||||
T const& value) -> std::enable_if_t<!IsKeyCache, ReturnType>
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::insert(key_type const& key, T const& value)
|
||||
-> std::enable_if_t<!IsKeyCache, ReturnType>
|
||||
{
|
||||
static_assert(
|
||||
std::is_same_v<std::shared_ptr<T>, SharedPointerType> ||
|
||||
@@ -457,13 +597,23 @@ template <
|
||||
class Mutex>
|
||||
template <class ReturnType>
|
||||
inline auto
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::insert(
|
||||
key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::insert(key_type const& key)
|
||||
-> std::enable_if_t<IsKeyCache, ReturnType>
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
auto [it, inserted] =
|
||||
m_cache.emplace(std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(now));
|
||||
auto [it, inserted] = m_cache.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(key),
|
||||
std::forward_as_tuple(now));
|
||||
if (!inserted)
|
||||
it->second.last_access = now;
|
||||
return inserted;
|
||||
@@ -479,9 +629,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::retrieve(
|
||||
key_type const& key,
|
||||
T& data)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::retrieve(key_type const& key, T& data)
|
||||
{
|
||||
// retrieve the value of the stored data
|
||||
auto entry = fetch(key);
|
||||
@@ -503,8 +659,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline auto
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::peekMutex()
|
||||
-> mutex_type&
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::peekMutex() -> mutex_type&
|
||||
{
|
||||
return m_mutex;
|
||||
}
|
||||
@@ -519,8 +682,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline auto
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::getKeys() const
|
||||
-> std::vector<key_type>
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::getKeys() const -> std::vector<key_type>
|
||||
{
|
||||
std::vector<key_type> v;
|
||||
|
||||
@@ -544,7 +714,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline double
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::rate() const
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::rate() const
|
||||
{
|
||||
std::lock_guard lock(m_mutex);
|
||||
auto const tot = m_hits + m_misses;
|
||||
@@ -564,9 +742,15 @@ template <
|
||||
class Mutex>
|
||||
template <class Handler>
|
||||
inline SharedPointerType
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::fetch(
|
||||
key_type const& digest,
|
||||
Handler const& h)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::fetch(key_type const& digest, Handler const& h)
|
||||
{
|
||||
{
|
||||
std::lock_guard l(m_mutex);
|
||||
@@ -580,7 +764,8 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
|
||||
std::lock_guard l(m_mutex);
|
||||
++m_misses;
|
||||
auto const [it, inserted] = m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle)));
|
||||
auto const [it, inserted] =
|
||||
m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle)));
|
||||
if (!inserted)
|
||||
it->second.touch(m_clock.now());
|
||||
return it->second.ptr.getStrong();
|
||||
@@ -597,9 +782,16 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline SharedPointerType
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::initialFetch(
|
||||
key_type const& key,
|
||||
std::lock_guard<mutex_type> const& l)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::
|
||||
initialFetch(key_type const& key, std::lock_guard<mutex_type> const& l)
|
||||
{
|
||||
auto cit = m_cache.find(key);
|
||||
if (cit == m_cache.end())
|
||||
@@ -635,7 +827,15 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline void
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::collect_metrics()
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::collect_metrics()
|
||||
{
|
||||
m_stats.size.set(getCacheSize());
|
||||
|
||||
@@ -661,13 +861,22 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline std::thread
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::sweepHelper(
|
||||
clock_type::time_point const& when_expire,
|
||||
[[maybe_unused]] clock_type::time_point const& now,
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::lock_guard<std::recursive_mutex> const&)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::
|
||||
sweepHelper(
|
||||
clock_type::time_point const& when_expire,
|
||||
[[maybe_unused]] clock_type::time_point const& now,
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::lock_guard<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
int cacheRemovals = 0;
|
||||
@@ -721,8 +930,10 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
|
||||
if (mapRemovals || cacheRemovals)
|
||||
{
|
||||
JLOG(m_journal.debug()) << "TaggedCache partition sweep " << m_name << ": cache = " << partition.size()
|
||||
<< "-" << cacheRemovals << ", map-=" << mapRemovals;
|
||||
JLOG(m_journal.debug())
|
||||
<< "TaggedCache partition sweep " << m_name
|
||||
<< ": cache = " << partition.size() << "-" << cacheRemovals
|
||||
<< ", map-=" << mapRemovals;
|
||||
}
|
||||
|
||||
allRemovals += cacheRemovals;
|
||||
@@ -739,13 +950,22 @@ template <
|
||||
class KeyEqual,
|
||||
class Mutex>
|
||||
inline std::thread
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::sweepHelper(
|
||||
clock_type::time_point const& when_expire,
|
||||
clock_type::time_point const& now,
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::lock_guard<std::recursive_mutex> const&)
|
||||
TaggedCache<
|
||||
Key,
|
||||
T,
|
||||
IsKeyCache,
|
||||
SharedWeakUnionPointer,
|
||||
SharedPointerType,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Mutex>::
|
||||
sweepHelper(
|
||||
clock_type::time_point const& when_expire,
|
||||
clock_type::time_point const& now,
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::lock_guard<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
int cacheRemovals = 0;
|
||||
@@ -775,8 +995,10 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
|
||||
if (mapRemovals || cacheRemovals)
|
||||
{
|
||||
JLOG(m_journal.debug()) << "TaggedCache partition sweep " << m_name << ": cache = " << partition.size()
|
||||
<< "-" << cacheRemovals << ", map-=" << mapRemovals;
|
||||
JLOG(m_journal.debug())
|
||||
<< "TaggedCache partition sweep " << m_name
|
||||
<< ": cache = " << partition.size() << "-" << cacheRemovals
|
||||
<< ", map-=" << mapRemovals;
|
||||
}
|
||||
|
||||
allRemovals += cacheRemovals;
|
||||
|
||||
@@ -40,7 +40,8 @@ template <
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hash_multimap = std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
|
||||
using hash_multimap =
|
||||
std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
@@ -74,7 +75,8 @@ template <
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hardened_partitioned_hash_map = partitioned_unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
using hardened_partitioned_hash_map =
|
||||
partitioned_unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
@@ -82,7 +84,8 @@ template <
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hardened_hash_multimap = std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
|
||||
using hardened_hash_multimap =
|
||||
std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
@@ -96,7 +99,8 @@ template <
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hardened_hash_multiset = std::unordered_multiset<Value, Hash, Pred, Allocator>;
|
||||
using hardened_hash_multiset =
|
||||
std::unordered_multiset<Value, Hash, Pred, Allocator>;
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
|
||||
@@ -52,7 +52,13 @@ generalized_set_intersection(
|
||||
// std::set_intersection.
|
||||
template <class FwdIter1, class InputIter2, class Pred, class Comp>
|
||||
FwdIter1
|
||||
remove_if_intersect_or_match(FwdIter1 first1, FwdIter1 last1, InputIter2 first2, InputIter2 last2, Pred pred, Comp comp)
|
||||
remove_if_intersect_or_match(
|
||||
FwdIter1 first1,
|
||||
FwdIter1 last1,
|
||||
InputIter2 first2,
|
||||
InputIter2 last2,
|
||||
Pred pred,
|
||||
Comp comp)
|
||||
{
|
||||
// [original-first1, current-first1) is the set of elements to be preserved.
|
||||
// [current-first1, i) is the set of elements that have been removed.
|
||||
|
||||
@@ -46,7 +46,8 @@ base64_encode(std::uint8_t const* data, std::size_t len);
|
||||
inline std::string
|
||||
base64_encode(std::string const& s)
|
||||
{
|
||||
return base64_encode(reinterpret_cast<std::uint8_t const*>(s.data()), s.size());
|
||||
return base64_encode(
|
||||
reinterpret_cast<std::uint8_t const*>(s.data()), s.size());
|
||||
}
|
||||
|
||||
std::string
|
||||
|
||||
@@ -65,9 +65,13 @@ struct is_contiguous_container<Slice> : std::true_type
|
||||
template <std::size_t Bits, class Tag = void>
|
||||
class base_uint
|
||||
{
|
||||
static_assert((Bits % 32) == 0, "The length of a base_uint in bits must be a multiple of 32.");
|
||||
static_assert(
|
||||
(Bits % 32) == 0,
|
||||
"The length of a base_uint in bits must be a multiple of 32.");
|
||||
|
||||
static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64.");
|
||||
static_assert(
|
||||
Bits >= 64,
|
||||
"The length of a base_uint in bits must be at least 64.");
|
||||
|
||||
static constexpr std::size_t WIDTH = Bits / 32;
|
||||
|
||||
@@ -178,7 +182,9 @@ private:
|
||||
{
|
||||
// Local lambda that converts a single hex char to four bits and
|
||||
// ORs those bits into a uint32_t.
|
||||
auto hexCharToUInt = [](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult {
|
||||
auto hexCharToUInt = [](char c,
|
||||
std::uint32_t shift,
|
||||
std::uint32_t& accum) -> ParseResult {
|
||||
std::uint32_t nibble = 0xFFu;
|
||||
if (c < '0' || c > 'f')
|
||||
return ParseResult::badChar;
|
||||
@@ -215,7 +221,8 @@ private:
|
||||
std::uint32_t accum = {};
|
||||
for (std::uint32_t shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
|
||||
{
|
||||
if (auto const result = hexCharToUInt(*in++, shift, accum); result != ParseResult::okay)
|
||||
if (auto const result = hexCharToUInt(*in++, shift, accum);
|
||||
result != ParseResult::okay)
|
||||
return Unexpected(result);
|
||||
}
|
||||
ret[i++] = accum;
|
||||
@@ -254,7 +261,8 @@ public:
|
||||
// This constructor is intended to be used at compile time since it might
|
||||
// throw at runtime. Consider declaring this constructor consteval once
|
||||
// we get to C++23.
|
||||
explicit constexpr base_uint(std::string_view sv) noexcept(false) : data_(parseFromStringViewThrows(sv))
|
||||
explicit constexpr base_uint(std::string_view sv) noexcept(false)
|
||||
: data_(parseFromStringViewThrows(sv))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -379,7 +387,8 @@ public:
|
||||
// prefix operator
|
||||
for (int i = WIDTH - 1; i >= 0; --i)
|
||||
{
|
||||
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1);
|
||||
data_[i] = boost::endian::native_to_big(
|
||||
boost::endian::big_to_native(data_[i]) + 1);
|
||||
if (data_[i] != 0)
|
||||
break;
|
||||
}
|
||||
@@ -403,7 +412,8 @@ public:
|
||||
for (int i = WIDTH - 1; i >= 0; --i)
|
||||
{
|
||||
auto prev = data_[i];
|
||||
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
|
||||
data_[i] = boost::endian::native_to_big(
|
||||
boost::endian::big_to_native(data_[i]) - 1);
|
||||
|
||||
if (prev != 0)
|
||||
break;
|
||||
@@ -443,9 +453,11 @@ public:
|
||||
|
||||
for (int i = WIDTH; i--;)
|
||||
{
|
||||
std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) + boost::endian::big_to_native(b.data_[i]);
|
||||
std::uint64_t n = carry + boost::endian::big_to_native(data_[i]) +
|
||||
boost::endian::big_to_native(b.data_[i]);
|
||||
|
||||
data_[i] = boost::endian::native_to_big(static_cast<std::uint32_t>(n));
|
||||
data_[i] =
|
||||
boost::endian::native_to_big(static_cast<std::uint32_t>(n));
|
||||
carry = n >> 32;
|
||||
}
|
||||
|
||||
@@ -545,7 +557,8 @@ operator<=>(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
|
||||
if (ret.first == lhs.cend())
|
||||
return std::strong_ordering::equivalent;
|
||||
|
||||
return (*ret.first > *ret.second) ? std::strong_ordering::greater : std::strong_ordering::less;
|
||||
return (*ret.first > *ret.second) ? std::strong_ordering::greater
|
||||
: std::strong_ordering::less;
|
||||
}
|
||||
|
||||
template <std::size_t Bits, typename Tag>
|
||||
@@ -604,7 +617,9 @@ template <std::size_t Bits, class Tag>
|
||||
inline std::string
|
||||
to_short_string(base_uint<Bits, Tag> const& a)
|
||||
{
|
||||
static_assert(base_uint<Bits, Tag>::bytes > 4, "For 4 bytes or less, use a native type");
|
||||
static_assert(
|
||||
base_uint<Bits, Tag>::bytes > 4,
|
||||
"For 4 bytes or less, use a native type");
|
||||
return strHex(a.cbegin(), a.cbegin() + 4) + "...";
|
||||
}
|
||||
|
||||
@@ -638,7 +653,8 @@ static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
|
||||
namespace beast {
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
struct is_uniquely_represented<xrpl::base_uint<Bits, Tag>> : public std::true_type
|
||||
struct is_uniquely_represented<xrpl::base_uint<Bits, Tag>>
|
||||
: public std::true_type
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
@@ -16,9 +16,12 @@ namespace xrpl {
|
||||
|
||||
// A few handy aliases
|
||||
|
||||
using days = std::chrono::duration<int, std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>>;
|
||||
using days = std::chrono::duration<
|
||||
int,
|
||||
std::ratio_multiply<std::chrono::hours::period, std::ratio<24>>>;
|
||||
|
||||
using weeks = std::chrono::duration<int, std::ratio_multiply<days::period, std::ratio<7>>>;
|
||||
using weeks = std::chrono::
|
||||
duration<int, std::ratio_multiply<days::period, std::ratio<7>>>;
|
||||
|
||||
/** Clock for measuring the network time.
|
||||
|
||||
@@ -31,7 +34,8 @@ using weeks = std::chrono::duration<int, std::ratio_multiply<days::period, std::
|
||||
*/
|
||||
|
||||
constexpr static std::chrono::seconds epoch_offset =
|
||||
date::sys_days{date::year{2000} / 1 / 1} - date::sys_days{date::year{1970} / 1 / 1};
|
||||
date::sys_days{date::year{2000} / 1 / 1} -
|
||||
date::sys_days{date::year{1970} / 1 / 1};
|
||||
|
||||
static_assert(epoch_offset.count() == 946684800);
|
||||
|
||||
@@ -60,7 +64,8 @@ to_string(NetClock::time_point tp)
|
||||
{
|
||||
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
|
||||
using namespace std::chrono;
|
||||
return to_string(system_clock::time_point{tp.time_since_epoch() + epoch_offset});
|
||||
return to_string(
|
||||
system_clock::time_point{tp.time_since_epoch() + epoch_offset});
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
@@ -77,7 +82,8 @@ to_string_iso(NetClock::time_point tp)
|
||||
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
|
||||
// Note, NetClock::duration is seconds, as checked by static_assert
|
||||
static_assert(std::is_same_v<NetClock::duration::period, std::ratio<1>>);
|
||||
return to_string_iso(date::sys_time<NetClock::duration>{tp.time_since_epoch() + epoch_offset});
|
||||
return to_string_iso(date::sys_time<NetClock::duration>{
|
||||
tp.time_since_epoch() + epoch_offset});
|
||||
}
|
||||
|
||||
/** A clock for measuring elapsed time.
|
||||
|
||||
@@ -36,10 +36,15 @@ template <class E, class... Args>
|
||||
[[noreturn]] inline void
|
||||
Throw(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_convertible<E*, std::exception*>::value, "Exception must derive from std::exception.");
|
||||
static_assert(
|
||||
std::is_convertible<E*, std::exception*>::value,
|
||||
"Exception must derive from std::exception.");
|
||||
|
||||
E e(std::forward<Args>(args)...);
|
||||
LogThrow(std::string("Throwing exception of type " + beast::type_name<E>() + ": ") + e.what());
|
||||
LogThrow(
|
||||
std::string(
|
||||
"Throwing exception of type " + beast::type_name<E>() + ": ") +
|
||||
e.what());
|
||||
throw e;
|
||||
}
|
||||
|
||||
|
||||
@@ -24,7 +24,8 @@ public:
|
||||
Collection const& collection;
|
||||
std::string const delimiter;
|
||||
|
||||
explicit CollectionAndDelimiter(Collection const& c, std::string delim) : collection(c), delimiter(std::move(delim))
|
||||
explicit CollectionAndDelimiter(Collection const& c, std::string delim)
|
||||
: collection(c), delimiter(std::move(delim))
|
||||
{
|
||||
}
|
||||
|
||||
@@ -32,7 +33,11 @@ public:
|
||||
friend Stream&
|
||||
operator<<(Stream& s, CollectionAndDelimiter const& cd)
|
||||
{
|
||||
return join(s, std::begin(cd.collection), std::end(cd.collection), cd.delimiter);
|
||||
return join(
|
||||
s,
|
||||
std::begin(cd.collection),
|
||||
std::end(cd.collection),
|
||||
cd.delimiter);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -64,7 +69,8 @@ public:
|
||||
char const* collection;
|
||||
std::string const delimiter;
|
||||
|
||||
explicit CollectionAndDelimiter(char const c[N], std::string delim) : collection(c), delimiter(std::move(delim))
|
||||
explicit CollectionAndDelimiter(char const c[N], std::string delim)
|
||||
: collection(c), delimiter(std::move(delim))
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,8 @@ public:
|
||||
using const_reference = value_type const&;
|
||||
using pointer = value_type*;
|
||||
using const_pointer = value_type const*;
|
||||
using map_type = std::unordered_map<key_type, mapped_type, hasher, key_equal, allocator_type>;
|
||||
using map_type = std::
|
||||
unordered_map<key_type, mapped_type, hasher, key_equal, allocator_type>;
|
||||
using partition_map_type = std::vector<map_type>;
|
||||
|
||||
struct iterator
|
||||
@@ -112,7 +113,8 @@ public:
|
||||
friend bool
|
||||
operator==(iterator const& lhs, iterator const& rhs)
|
||||
{
|
||||
return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && lhs.mit_ == rhs.mit_;
|
||||
return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
|
||||
lhs.mit_ == rhs.mit_;
|
||||
}
|
||||
|
||||
friend bool
|
||||
@@ -188,7 +190,8 @@ public:
|
||||
friend bool
|
||||
operator==(const_iterator const& lhs, const_iterator const& rhs)
|
||||
{
|
||||
return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && lhs.mit_ == rhs.mit_;
|
||||
return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ &&
|
||||
lhs.mit_ == rhs.mit_;
|
||||
}
|
||||
|
||||
friend bool
|
||||
@@ -228,11 +231,14 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
partitioned_unordered_map(std::optional<std::size_t> partitions = std::nullopt)
|
||||
partitioned_unordered_map(
|
||||
std::optional<std::size_t> partitions = std::nullopt)
|
||||
{
|
||||
// Set partitions to the number of hardware threads if the parameter
|
||||
// is either empty or set to 0.
|
||||
partitions_ = partitions && *partitions ? *partitions : std::thread::hardware_concurrency();
|
||||
partitions_ = partitions && *partitions
|
||||
? *partitions
|
||||
: std::thread::hardware_concurrency();
|
||||
map_.resize(partitions_);
|
||||
XRPL_ASSERT(
|
||||
partitions_,
|
||||
@@ -331,8 +337,10 @@ public:
|
||||
auto const& key = std::get<0>(keyTuple);
|
||||
iterator it(&map_);
|
||||
it.ait_ = it.map_->begin() + partitioner(key);
|
||||
auto [eit, inserted] =
|
||||
it.ait_->emplace(std::piecewise_construct, std::forward<T>(keyTuple), std::forward<U>(valueTuple));
|
||||
auto [eit, inserted] = it.ait_->emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward<T>(keyTuple),
|
||||
std::forward<U>(valueTuple));
|
||||
it.mit_ = eit;
|
||||
return {it, inserted};
|
||||
}
|
||||
@@ -343,7 +351,8 @@ public:
|
||||
{
|
||||
iterator it(&map_);
|
||||
it.ait_ = it.map_->begin() + partitioner(key);
|
||||
auto [eit, inserted] = it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
|
||||
auto [eit, inserted] =
|
||||
it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
|
||||
it.mit_ = eit;
|
||||
return {it, inserted};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@ static_assert(
|
||||
"The Ripple default PRNG engine must return an unsigned integral type.");
|
||||
|
||||
static_assert(
|
||||
std::numeric_limits<beast::xor_shift_engine::result_type>::max() >= std::numeric_limits<std::uint64_t>::max(),
|
||||
std::numeric_limits<beast::xor_shift_engine::result_type>::max() >=
|
||||
std::numeric_limits<std::uint64_t>::max(),
|
||||
"The Ripple default PRNG engine return must be at least 64 bits wide.");
|
||||
#endif
|
||||
|
||||
@@ -89,7 +90,9 @@ default_prng()
|
||||
*/
|
||||
/** @{ */
|
||||
template <class Engine, class Integral>
|
||||
std::enable_if_t<std::is_integral<Integral>::value && detail::is_engine<Engine>::value, Integral>
|
||||
std::enable_if_t<
|
||||
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
||||
Integral>
|
||||
rand_int(Engine& engine, Integral min, Integral max)
|
||||
{
|
||||
XRPL_ASSERT(max > min, "xrpl::rand_int : max over min inputs");
|
||||
@@ -108,7 +111,9 @@ rand_int(Integral min, Integral max)
|
||||
}
|
||||
|
||||
template <class Engine, class Integral>
|
||||
std::enable_if_t<std::is_integral<Integral>::value && detail::is_engine<Engine>::value, Integral>
|
||||
std::enable_if_t<
|
||||
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
||||
Integral>
|
||||
rand_int(Engine& engine, Integral max)
|
||||
{
|
||||
return rand_int(engine, Integral(0), max);
|
||||
@@ -122,7 +127,9 @@ rand_int(Integral max)
|
||||
}
|
||||
|
||||
template <class Integral, class Engine>
|
||||
std::enable_if_t<std::is_integral<Integral>::value && detail::is_engine<Engine>::value, Integral>
|
||||
std::enable_if_t<
|
||||
std::is_integral<Integral>::value && detail::is_engine<Engine>::value,
|
||||
Integral>
|
||||
rand_int(Engine& engine)
|
||||
{
|
||||
return rand_int(engine, std::numeric_limits<Integral>::max());
|
||||
@@ -140,17 +147,23 @@ rand_int()
|
||||
/** @{ */
|
||||
template <class Byte, class Engine>
|
||||
std::enable_if_t<
|
||||
(std::is_same<Byte, unsigned char>::value || std::is_same<Byte, std::uint8_t>::value) &&
|
||||
(std::is_same<Byte, unsigned char>::value ||
|
||||
std::is_same<Byte, std::uint8_t>::value) &&
|
||||
detail::is_engine<Engine>::value,
|
||||
Byte>
|
||||
rand_byte(Engine& engine)
|
||||
{
|
||||
return static_cast<Byte>(
|
||||
rand_int<Engine, std::uint32_t>(engine, std::numeric_limits<Byte>::min(), std::numeric_limits<Byte>::max()));
|
||||
return static_cast<Byte>(rand_int<Engine, std::uint32_t>(
|
||||
engine,
|
||||
std::numeric_limits<Byte>::min(),
|
||||
std::numeric_limits<Byte>::max()));
|
||||
}
|
||||
|
||||
template <class Byte = std::uint8_t>
|
||||
std::enable_if_t<(std::is_same<Byte, unsigned char>::value || std::is_same<Byte, std::uint8_t>::value), Byte>
|
||||
std::enable_if_t<
|
||||
(std::is_same<Byte, unsigned char>::value ||
|
||||
std::is_same<Byte, std::uint8_t>::value),
|
||||
Byte>
|
||||
rand_byte()
|
||||
{
|
||||
return rand_byte<Byte>(default_prng());
|
||||
|
||||
@@ -12,29 +12,38 @@ namespace xrpl {
|
||||
template <class Src, class Dest>
|
||||
concept SafeToCast = (std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
|
||||
(std::is_signed<Src>::value || std::is_unsigned<Dest>::value) &&
|
||||
(std::is_signed<Src>::value != std::is_signed<Dest>::value ? sizeof(Dest) > sizeof(Src)
|
||||
: sizeof(Dest) >= sizeof(Src));
|
||||
(std::is_signed<Src>::value != std::is_signed<Dest>::value
|
||||
? sizeof(Dest) > sizeof(Src)
|
||||
: sizeof(Dest) >= sizeof(Src));
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
static_assert(std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned");
|
||||
constexpr unsigned not_same = std::is_signed_v<Dest> != std::is_signed_v<Src>;
|
||||
static_assert(sizeof(Dest) >= sizeof(Src) + not_same, "Destination is too small to hold all values of source");
|
||||
static_assert(
|
||||
std::is_signed_v<Dest> || std::is_unsigned_v<Src>,
|
||||
"Cannot cast signed to unsigned");
|
||||
constexpr unsigned not_same =
|
||||
std::is_signed_v<Dest> != std::is_signed_v<Src>;
|
||||
static_assert(
|
||||
sizeof(Dest) >= sizeof(Src) + not_same,
|
||||
"Destination is too small to hold all values of source");
|
||||
return static_cast<Dest>(s);
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
return static_cast<Dest>(safe_cast<std::underlying_type_t<Dest>>(s));
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
return safe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
}
|
||||
@@ -44,8 +53,9 @@ safe_cast(Src s) noexcept
|
||||
// underlying types become safe, it can be converted to a safe_cast.
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
static_assert(
|
||||
!SafeToCast<Src, Dest>,
|
||||
@@ -55,15 +65,17 @@ unsafe_cast(Src s) noexcept
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
return static_cast<Dest>(unsafe_cast<std::underlying_type_t<Dest>>(s));
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
inline constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
inline constexpr std::
|
||||
enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
return unsafe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
}
|
||||
|
||||
@@ -36,8 +36,10 @@ public:
|
||||
}
|
||||
|
||||
scope_exit(scope_exit&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
std::is_nothrow_move_constructible_v<EF> ||
|
||||
std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
{
|
||||
rhs.release();
|
||||
}
|
||||
@@ -48,11 +50,14 @@ public:
|
||||
template <class EFP>
|
||||
explicit scope_exit(
|
||||
EFP&& f,
|
||||
std::enable_if_t<!std::is_same_v<std::remove_cv_t<EFP>, scope_exit> && std::is_constructible_v<EF, EFP>>* =
|
||||
0) noexcept
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_exit> &&
|
||||
std::is_constructible_v<EF, EFP>>* = 0) noexcept
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
|
||||
static_assert(
|
||||
std::
|
||||
is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -75,12 +80,14 @@ class scope_fail
|
||||
public:
|
||||
~scope_fail()
|
||||
{
|
||||
if (execute_on_destruction_ && std::uncaught_exceptions() > uncaught_on_creation_)
|
||||
if (execute_on_destruction_ &&
|
||||
std::uncaught_exceptions() > uncaught_on_creation_)
|
||||
exit_function_();
|
||||
}
|
||||
|
||||
scope_fail(scope_fail&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
|
||||
std::is_nothrow_move_constructible_v<EF> ||
|
||||
std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
, uncaught_on_creation_{rhs.uncaught_on_creation_}
|
||||
@@ -94,11 +101,14 @@ public:
|
||||
template <class EFP>
|
||||
explicit scope_fail(
|
||||
EFP&& f,
|
||||
std::enable_if_t<!std::is_same_v<std::remove_cv_t<EFP>, scope_fail> && std::is_constructible_v<EF, EFP>>* =
|
||||
0) noexcept
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_fail> &&
|
||||
std::is_constructible_v<EF, EFP>>* = 0) noexcept
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
|
||||
static_assert(
|
||||
std::
|
||||
is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -121,12 +131,14 @@ class scope_success
|
||||
public:
|
||||
~scope_success() noexcept(noexcept(exit_function_()))
|
||||
{
|
||||
if (execute_on_destruction_ && std::uncaught_exceptions() <= uncaught_on_creation_)
|
||||
if (execute_on_destruction_ &&
|
||||
std::uncaught_exceptions() <= uncaught_on_creation_)
|
||||
exit_function_();
|
||||
}
|
||||
|
||||
scope_success(scope_success&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
|
||||
std::is_nothrow_move_constructible_v<EF> ||
|
||||
std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
, uncaught_on_creation_{rhs.uncaught_on_creation_}
|
||||
@@ -140,7 +152,9 @@ public:
|
||||
template <class EFP>
|
||||
explicit scope_success(
|
||||
EFP&& f,
|
||||
std::enable_if_t<!std::is_same_v<std::remove_cv_t<EFP>, scope_success> && std::is_constructible_v<EF, EFP>>* =
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_success> &&
|
||||
std::is_constructible_v<EF, EFP>>* =
|
||||
0) noexcept(std::is_nothrow_constructible_v<EF, EFP> || std::is_nothrow_constructible_v<EF, EFP&>)
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
@@ -199,9 +213,12 @@ class scope_unlock
|
||||
std::unique_lock<Mutex>* plock;
|
||||
|
||||
public:
|
||||
explicit scope_unlock(std::unique_lock<Mutex>& lock) noexcept(true) : plock(&lock)
|
||||
explicit scope_unlock(std::unique_lock<Mutex>& lock) noexcept(true)
|
||||
: plock(&lock)
|
||||
{
|
||||
XRPL_ASSERT(plock->owns_lock(), "xrpl::scope_unlock::scope_unlock : mutex must be locked");
|
||||
XRPL_ASSERT(
|
||||
plock->owns_lock(),
|
||||
"xrpl::scope_unlock::scope_unlock : mutex must be locked");
|
||||
plock->unlock();
|
||||
}
|
||||
|
||||
|
||||
@@ -100,9 +100,12 @@ public:
|
||||
@note For performance reasons, you should strive to have `lock` be
|
||||
on a cacheline by itself.
|
||||
*/
|
||||
packed_spinlock(std::atomic<T>& lock, int index) : bits_(lock), mask_(static_cast<T>(1) << index)
|
||||
packed_spinlock(std::atomic<T>& lock, int index)
|
||||
: bits_(lock), mask_(static_cast<T>(1) << index)
|
||||
{
|
||||
XRPL_ASSERT(index >= 0 && (mask_ != 0), "xrpl::packed_spinlock::packed_spinlock : valid index and mask");
|
||||
XRPL_ASSERT(
|
||||
index >= 0 && (mask_ != 0),
|
||||
"xrpl::packed_spinlock::packed_spinlock : valid index and mask");
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
@@ -175,7 +178,10 @@ public:
|
||||
T expected = 0;
|
||||
|
||||
return lock_.compare_exchange_weak(
|
||||
expected, std::numeric_limits<T>::max(), std::memory_order_acquire, std::memory_order_relaxed);
|
||||
expected,
|
||||
std::numeric_limits<T>::max(),
|
||||
std::memory_order_acquire,
|
||||
std::memory_order_relaxed);
|
||||
}
|
||||
|
||||
void
|
||||
|
||||
@@ -11,7 +11,9 @@ std::string
|
||||
strHex(FwdIt begin, FwdIt end)
|
||||
{
|
||||
static_assert(
|
||||
std::is_convertible<typename std::iterator_traits<FwdIt>::iterator_category, std::forward_iterator_tag>::value,
|
||||
std::is_convertible<
|
||||
typename std::iterator_traits<FwdIt>::iterator_category,
|
||||
std::forward_iterator_tag>::value,
|
||||
"FwdIt must be a forward iterator");
|
||||
std::string result;
|
||||
result.reserve(2 * std::distance(begin, end));
|
||||
|
||||
@@ -31,7 +31,9 @@ class tagged_integer
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::bitwise<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::unit_steppable<tagged_integer<Int, Tag>, boost::shiftable<tagged_integer<Int, Tag>>>>>>
|
||||
boost::unit_steppable<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::shiftable<tagged_integer<Int, Tag>>>>>>
|
||||
{
|
||||
private:
|
||||
Int m_value;
|
||||
@@ -44,10 +46,14 @@ public:
|
||||
|
||||
template <
|
||||
class OtherInt,
|
||||
class = typename std::enable_if<std::is_integral<OtherInt>::value && sizeof(OtherInt) <= sizeof(Int)>::type>
|
||||
class = typename std::enable_if<
|
||||
std::is_integral<OtherInt>::value &&
|
||||
sizeof(OtherInt) <= sizeof(Int)>::type>
|
||||
explicit constexpr tagged_integer(OtherInt value) noexcept : m_value(value)
|
||||
{
|
||||
static_assert(sizeof(tagged_integer) == sizeof(Int), "tagged_integer is adding padding");
|
||||
static_assert(
|
||||
sizeof(tagged_integer) == sizeof(Int),
|
||||
"tagged_integer is adding padding");
|
||||
}
|
||||
|
||||
bool
|
||||
|
||||
@@ -32,7 +32,11 @@ private:
|
||||
|
||||
public:
|
||||
io_latency_probe(duration const& period, boost::asio::io_context& ios)
|
||||
: m_count(1), m_period(period), m_ios(ios), m_timer(m_ios), m_cancel(false)
|
||||
: m_count(1)
|
||||
, m_period(period)
|
||||
, m_ios(ios)
|
||||
, m_timer(m_ios)
|
||||
, m_cancel(false)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -87,7 +91,10 @@ public:
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
boost::asio::post(m_ios, sample_op<Handler>(std::forward<Handler>(handler), Clock::now(), false, this));
|
||||
boost::asio::post(
|
||||
m_ios,
|
||||
sample_op<Handler>(
|
||||
std::forward<Handler>(handler), Clock::now(), false, this));
|
||||
}
|
||||
|
||||
/** Initiate continuous i/o latency sampling.
|
||||
@@ -101,7 +108,10 @@ public:
|
||||
std::lock_guard lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
boost::asio::post(m_ios, sample_op<Handler>(std::forward<Handler>(handler), Clock::now(), true, this));
|
||||
boost::asio::post(
|
||||
m_ios,
|
||||
sample_op<Handler>(
|
||||
std::forward<Handler>(handler), Clock::now(), true, this));
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -141,8 +151,15 @@ private:
|
||||
bool m_repeat;
|
||||
io_latency_probe* m_probe;
|
||||
|
||||
sample_op(Handler const& handler, time_point const& start, bool repeat, io_latency_probe* probe)
|
||||
: m_handler(handler), m_start(start), m_repeat(repeat), m_probe(probe)
|
||||
sample_op(
|
||||
Handler const& handler,
|
||||
time_point const& start,
|
||||
bool repeat,
|
||||
io_latency_probe* probe)
|
||||
: m_handler(handler)
|
||||
, m_start(start)
|
||||
, m_repeat(repeat)
|
||||
, m_probe(probe)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
m_probe,
|
||||
@@ -197,19 +214,23 @@ private:
|
||||
// Calculate when we want to sample again, and
|
||||
// adjust for the expected latency.
|
||||
//
|
||||
typename Clock::time_point const when(now + m_probe->m_period - 2 * elapsed);
|
||||
typename Clock::time_point const when(
|
||||
now + m_probe->m_period - 2 * elapsed);
|
||||
|
||||
if (when <= now)
|
||||
{
|
||||
// The latency is too high to maintain the desired
|
||||
// period so don't bother with a timer.
|
||||
//
|
||||
boost::asio::post(m_probe->m_ios, sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
boost::asio::post(
|
||||
m_probe->m_ios,
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_probe->m_timer.expires_after(when - now);
|
||||
m_probe->m_timer.async_wait(sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
m_probe->m_timer.async_wait(
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -220,7 +241,9 @@ private:
|
||||
if (!m_probe)
|
||||
return;
|
||||
typename Clock::time_point const now(Clock::now());
|
||||
boost::asio::post(m_probe->m_ios, sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
boost::asio::post(
|
||||
m_probe->m_ios,
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -29,7 +29,8 @@ private:
|
||||
time_point now_;
|
||||
|
||||
public:
|
||||
explicit manual_clock(time_point const& now = time_point(duration(0))) : now_(now)
|
||||
explicit manual_clock(time_point const& now = time_point(duration(0)))
|
||||
: now_(now)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -43,7 +44,9 @@ public:
|
||||
void
|
||||
set(time_point const& when)
|
||||
{
|
||||
XRPL_ASSERT(!Clock::is_steady || when >= now_, "beast::manual_clock::set(time_point) : forward input");
|
||||
XRPL_ASSERT(
|
||||
!Clock::is_steady || when >= now_,
|
||||
"beast::manual_clock::set(time_point) : forward input");
|
||||
now_ = when;
|
||||
}
|
||||
|
||||
@@ -61,7 +64,8 @@ public:
|
||||
advance(std::chrono::duration<Rep, Period> const& elapsed)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
!Clock::is_steady || (now_ + elapsed) >= now_, "beast::manual_clock::advance(duration) : forward input");
|
||||
!Clock::is_steady || (now_ + elapsed) >= now_,
|
||||
"beast::manual_clock::advance(duration) : forward input");
|
||||
now_ += elapsed;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,12 +10,14 @@ namespace beast {
|
||||
|
||||
/** Expire aged container items past the specified age. */
|
||||
template <class AgedContainer, class Rep, class Period>
|
||||
typename std::enable_if<is_aged_container<AgedContainer>::value, std::size_t>::type
|
||||
expire(AgedContainer& c, std::chrono::duration<Rep, Period> const& age)
|
||||
typename std::enable_if<is_aged_container<AgedContainer>::value, std::size_t>::
|
||||
type
|
||||
expire(AgedContainer& c, std::chrono::duration<Rep, Period> const& age)
|
||||
{
|
||||
std::size_t n(0);
|
||||
auto const expired(c.clock().now() - age);
|
||||
for (auto iter(c.chronological.cbegin()); iter != c.chronological.cend() && iter.when() <= expired;)
|
||||
for (auto iter(c.chronological.cbegin());
|
||||
iter != c.chronological.cend() && iter.when() <= expired;)
|
||||
{
|
||||
iter = c.erase(iter);
|
||||
++n;
|
||||
|
||||
@@ -15,7 +15,8 @@ template <
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_map = detail::aged_ordered_container<false, true, Key, T, Clock, Compare, Allocator>;
|
||||
using aged_map = detail::
|
||||
aged_ordered_container<false, true, Key, T, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ template <
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_multimap = detail::aged_ordered_container<true, true, Key, T, Clock, Compare, Allocator>;
|
||||
using aged_multimap = detail::
|
||||
aged_ordered_container<true, true, Key, T, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ template <
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less<Key>,
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_multiset = detail::aged_ordered_container<true, false, Key, void, Clock, Compare, Allocator>;
|
||||
using aged_multiset = detail::
|
||||
aged_ordered_container<true, false, Key, void, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,8 @@ template <
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less<Key>,
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_set = detail::aged_ordered_container<false, false, Key, void, Clock, Compare, Allocator>;
|
||||
using aged_set = detail::
|
||||
aged_ordered_container<false, false, Key, void, Clock, Compare, Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,15 @@ template <
|
||||
class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_unordered_map = detail::aged_unordered_container<false, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
using aged_unordered_map = detail::aged_unordered_container<
|
||||
false,
|
||||
true,
|
||||
Key,
|
||||
T,
|
||||
Clock,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,15 @@ template <
|
||||
class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_unordered_multimap = detail::aged_unordered_container<true, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
using aged_unordered_multimap = detail::aged_unordered_container<
|
||||
true,
|
||||
true,
|
||||
Key,
|
||||
T,
|
||||
Clock,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -15,8 +15,15 @@ template <
|
||||
class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_unordered_multiset =
|
||||
detail::aged_unordered_container<true, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
using aged_unordered_multiset = detail::aged_unordered_container<
|
||||
true,
|
||||
false,
|
||||
Key,
|
||||
void,
|
||||
Clock,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,15 @@ template <
|
||||
class Hash = std::hash<Key>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_unordered_set = detail::aged_unordered_container<false, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
using aged_unordered_set = detail::aged_unordered_container<
|
||||
false,
|
||||
false,
|
||||
Key,
|
||||
void,
|
||||
Clock,
|
||||
Hash,
|
||||
KeyEqual,
|
||||
Allocator>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -16,12 +16,14 @@ template <bool is_const, class Iterator>
|
||||
class aged_container_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
|
||||
using iterator_category =
|
||||
typename std::iterator_traits<Iterator>::iterator_category;
|
||||
using value_type = typename std::conditional<
|
||||
is_const,
|
||||
typename Iterator::value_type::stashed::value_type const,
|
||||
typename Iterator::value_type::stashed::value_type>::type;
|
||||
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
|
||||
using difference_type =
|
||||
typename std::iterator_traits<Iterator>::difference_type;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using time_point = typename Iterator::value_type::stashed::time_point;
|
||||
@@ -36,22 +38,31 @@ public:
|
||||
class = typename std::enable_if<
|
||||
(other_is_const == false || is_const == true) &&
|
||||
std::is_same<Iterator, OtherIterator>::value == false>::type>
|
||||
explicit aged_container_iterator(aged_container_iterator<other_is_const, OtherIterator> const& other)
|
||||
explicit aged_container_iterator(
|
||||
aged_container_iterator<other_is_const, OtherIterator> const& other)
|
||||
: m_iter(other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
// Disable constructing a const_iterator from a non-const_iterator.
|
||||
template <bool other_is_const, class = typename std::enable_if<other_is_const == false || is_const == true>::type>
|
||||
aged_container_iterator(aged_container_iterator<other_is_const, Iterator> const& other) : m_iter(other.m_iter)
|
||||
template <
|
||||
bool other_is_const,
|
||||
class = typename std::enable_if<
|
||||
other_is_const == false || is_const == true>::type>
|
||||
aged_container_iterator(
|
||||
aged_container_iterator<other_is_const, Iterator> const& other)
|
||||
: m_iter(other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
// Disable assigning a const_iterator to a non-const iterator
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
auto
|
||||
operator=(aged_container_iterator<other_is_const, OtherIterator> const& other) ->
|
||||
typename std::enable_if<other_is_const == false || is_const == true, aged_container_iterator&>::type
|
||||
operator=(
|
||||
aged_container_iterator<other_is_const, OtherIterator> const& other) ->
|
||||
typename std::enable_if<
|
||||
other_is_const == false || is_const == true,
|
||||
aged_container_iterator&>::type
|
||||
{
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
@@ -59,14 +70,16 @@ public:
|
||||
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
bool
|
||||
operator==(aged_container_iterator<other_is_const, OtherIterator> const& other) const
|
||||
operator==(aged_container_iterator<other_is_const, OtherIterator> const&
|
||||
other) const
|
||||
{
|
||||
return m_iter == other.m_iter;
|
||||
}
|
||||
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
bool
|
||||
operator!=(aged_container_iterator<other_is_const, OtherIterator> const& other) const
|
||||
operator!=(aged_container_iterator<other_is_const, OtherIterator> const&
|
||||
other) const
|
||||
{
|
||||
return m_iter != other.m_iter;
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -17,11 +17,16 @@ namespace detail {
|
||||
|
||||
template <class T>
|
||||
struct is_empty_base_optimization_derived
|
||||
: std::integral_constant<bool, std::is_empty<T>::value && !boost::is_final<T>::value>
|
||||
: std::integral_constant<
|
||||
bool,
|
||||
std::is_empty<T>::value && !boost::is_final<T>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <class T, int UniqueID = 0, bool isDerived = is_empty_base_optimization_derived<T>::value>
|
||||
template <
|
||||
class T,
|
||||
int UniqueID = 0,
|
||||
bool isDerived = is_empty_base_optimization_derived<T>::value>
|
||||
class empty_base_optimization : private T
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -35,7 +35,9 @@ template <std::size_t N>
|
||||
void
|
||||
setCurrentThreadName(char const (&newThreadName)[N])
|
||||
{
|
||||
static_assert(N <= maxThreadNameLength + 1, "Thread name cannot exceed 15 characters");
|
||||
static_assert(
|
||||
N <= maxThreadNameLength + 1,
|
||||
"Thread name cannot exceed 15 characters");
|
||||
|
||||
setCurrentThreadName(std::string_view(newThreadName, N - 1));
|
||||
}
|
||||
|
||||
@@ -40,7 +40,8 @@ struct LexicalCast<std::string, In>
|
||||
std::enable_if_t<std::is_enum_v<Enumeration>, bool>
|
||||
operator()(std::string& out, Enumeration in)
|
||||
{
|
||||
out = std::to_string(static_cast<std::underlying_type_t<Enumeration>>(in));
|
||||
out = std::to_string(
|
||||
static_cast<std::underlying_type_t<Enumeration>>(in));
|
||||
return true;
|
||||
}
|
||||
};
|
||||
@@ -51,10 +52,14 @@ struct LexicalCast<Out, std::string_view>
|
||||
{
|
||||
explicit LexicalCast() = default;
|
||||
|
||||
static_assert(std::is_integral_v<Out>, "beast::LexicalCast can only be used with integral types");
|
||||
static_assert(
|
||||
std::is_integral_v<Out>,
|
||||
"beast::LexicalCast can only be used with integral types");
|
||||
|
||||
template <class Integral = Out>
|
||||
std::enable_if_t<std::is_integral_v<Integral> && !std::is_same_v<Integral, bool>, bool>
|
||||
std::enable_if_t<
|
||||
std::is_integral_v<Integral> && !std::is_same_v<Integral, bool>,
|
||||
bool>
|
||||
operator()(Integral& out, std::string_view in) const
|
||||
{
|
||||
auto first = in.data();
|
||||
@@ -74,9 +79,10 @@ struct LexicalCast<Out, std::string_view>
|
||||
std::string result;
|
||||
|
||||
// Convert the input to lowercase
|
||||
std::transform(in.begin(), in.end(), std::back_inserter(result), [](auto c) {
|
||||
return std::tolower(static_cast<unsigned char>(c));
|
||||
});
|
||||
std::transform(
|
||||
in.begin(), in.end(), std::back_inserter(result), [](auto c) {
|
||||
return std::tolower(static_cast<unsigned char>(c));
|
||||
});
|
||||
|
||||
if (result == "1" || result == "true")
|
||||
{
|
||||
@@ -134,7 +140,8 @@ struct LexicalCast<Out, char const*>
|
||||
bool
|
||||
operator()(Out& out, char const* in) const
|
||||
{
|
||||
XRPL_ASSERT(in, "beast::detail::LexicalCast(char const*) : non-null input");
|
||||
XRPL_ASSERT(
|
||||
in, "beast::detail::LexicalCast(char const*) : non-null input");
|
||||
return LexicalCast<Out, std::string_view>()(out, in);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,7 +55,8 @@ class ListIterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = std::bidirectional_iterator_tag;
|
||||
using value_type = typename beast::detail::CopyConst<N, typename N::value_type>::type;
|
||||
using value_type =
|
||||
typename beast::detail::CopyConst<N, typename N::value_type>::type;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
|
||||
@@ -14,16 +14,21 @@ class LockFreeStackIterator
|
||||
{
|
||||
protected:
|
||||
using Node = typename Container::Node;
|
||||
using NodePtr = typename std::conditional<IsConst, Node const*, Node*>::type;
|
||||
using NodePtr =
|
||||
typename std::conditional<IsConst, Node const*, Node*>::type;
|
||||
|
||||
public:
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using value_type = typename Container::value_type;
|
||||
using difference_type = typename Container::difference_type;
|
||||
using pointer =
|
||||
typename std::conditional<IsConst, typename Container::const_pointer, typename Container::pointer>::type;
|
||||
using reference =
|
||||
typename std::conditional<IsConst, typename Container::const_reference, typename Container::reference>::type;
|
||||
using pointer = typename std::conditional<
|
||||
IsConst,
|
||||
typename Container::const_pointer,
|
||||
typename Container::pointer>::type;
|
||||
using reference = typename std::conditional<
|
||||
IsConst,
|
||||
typename Container::const_reference,
|
||||
typename Container::reference>::type;
|
||||
|
||||
LockFreeStackIterator() : m_node()
|
||||
{
|
||||
@@ -34,7 +39,9 @@ public:
|
||||
}
|
||||
|
||||
template <bool OtherIsConst>
|
||||
explicit LockFreeStackIterator(LockFreeStackIterator<Container, OtherIsConst> const& other) : m_node(other.m_node)
|
||||
explicit LockFreeStackIterator(
|
||||
LockFreeStackIterator<Container, OtherIsConst> const& other)
|
||||
: m_node(other.m_node)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -153,7 +160,8 @@ public:
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator = LockFreeStackIterator<LockFreeStack<Element, Tag>, false>;
|
||||
using const_iterator = LockFreeStackIterator<LockFreeStack<Element, Tag>, true>;
|
||||
using const_iterator =
|
||||
LockFreeStackIterator<LockFreeStack<Element, Tag>, true>;
|
||||
|
||||
LockFreeStack() : m_end(nullptr), m_head(&m_end)
|
||||
{
|
||||
@@ -191,7 +199,11 @@ public:
|
||||
{
|
||||
first = (old_head == &m_end);
|
||||
node->m_next = old_head;
|
||||
} while (!m_head.compare_exchange_strong(old_head, node, std::memory_order_release, std::memory_order_relaxed));
|
||||
} while (!m_head.compare_exchange_strong(
|
||||
old_head,
|
||||
node,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed));
|
||||
return first;
|
||||
}
|
||||
|
||||
@@ -214,7 +226,11 @@ public:
|
||||
if (node == &m_end)
|
||||
return nullptr;
|
||||
new_head = node->m_next.load();
|
||||
} while (!m_head.compare_exchange_strong(node, new_head, std::memory_order_release, std::memory_order_relaxed));
|
||||
} while (!m_head.compare_exchange_strong(
|
||||
node,
|
||||
new_head,
|
||||
std::memory_order_release,
|
||||
std::memory_order_relaxed));
|
||||
return static_cast<Element*>(node);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,7 +27,8 @@ template <class T>
|
||||
inline void
|
||||
reverse_bytes(T& t)
|
||||
{
|
||||
unsigned char* bytes = static_cast<unsigned char*>(std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
|
||||
unsigned char* bytes = static_cast<unsigned char*>(
|
||||
std::memmove(std::addressof(t), std::addressof(t), sizeof(T)));
|
||||
for (unsigned i = 0; i < sizeof(T) / 2; ++i)
|
||||
std::swap(bytes[i], bytes[sizeof(T) - 1 - i]);
|
||||
}
|
||||
@@ -52,7 +53,11 @@ template <class T, class Hasher>
|
||||
inline void
|
||||
maybe_reverse_bytes(T& t, Hasher&)
|
||||
{
|
||||
maybe_reverse_bytes(t, std::integral_constant<bool, Hasher::endian != boost::endian::order::native>{});
|
||||
maybe_reverse_bytes(
|
||||
t,
|
||||
std::integral_constant<
|
||||
bool,
|
||||
Hasher::endian != boost::endian::order::native>{});
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@@ -66,8 +71,10 @@ maybe_reverse_bytes(T& t, Hasher&)
|
||||
|
||||
template <class T>
|
||||
struct is_uniquely_represented
|
||||
: public std::
|
||||
integral_constant<bool, std::is_integral<T>::value || std::is_enum<T>::value || std::is_pointer<T>::value>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
std::is_integral<T>::value || std::is_enum<T>::value ||
|
||||
std::is_pointer<T>::value>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
@@ -85,7 +92,8 @@ struct is_uniquely_represented<T volatile> : public is_uniquely_represented<T>
|
||||
};
|
||||
|
||||
template <class T>
|
||||
struct is_uniquely_represented<T const volatile> : public is_uniquely_represented<T>
|
||||
struct is_uniquely_represented<T const volatile>
|
||||
: public is_uniquely_represented<T>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
@@ -96,7 +104,8 @@ template <class T, class U>
|
||||
struct is_uniquely_represented<std::pair<T, U>>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T>::value && is_uniquely_represented<U>::value &&
|
||||
is_uniquely_represented<T>::value &&
|
||||
is_uniquely_represented<U>::value &&
|
||||
sizeof(T) + sizeof(U) == sizeof(std::pair<T, U>)>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
@@ -108,7 +117,8 @@ template <class... T>
|
||||
struct is_uniquely_represented<std::tuple<T...>>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
std::conjunction_v<is_uniquely_represented<T>...> && sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
|
||||
std::conjunction_v<is_uniquely_represented<T>...> &&
|
||||
sizeof(std::tuple<T...>) == (sizeof(T) + ...)>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
@@ -125,8 +135,10 @@ struct is_uniquely_represented<T[N]> : public is_uniquely_represented<T>
|
||||
|
||||
template <class T, std::size_t N>
|
||||
struct is_uniquely_represented<std::array<T, N>>
|
||||
: public std::
|
||||
integral_constant<bool, is_uniquely_represented<T>::value && sizeof(T) * N == sizeof(std::array<T, N>)>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T>::value &&
|
||||
sizeof(T) * N == sizeof(std::array<T, N>)>
|
||||
{
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
@@ -146,10 +158,12 @@ struct is_uniquely_represented<std::array<T, N>>
|
||||
*/
|
||||
/** @{ */
|
||||
template <class T, class HashAlgorithm>
|
||||
struct is_contiguously_hashable : public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T>::value &&
|
||||
(sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)>
|
||||
struct is_contiguously_hashable
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T>::value &&
|
||||
(sizeof(T) == 1 ||
|
||||
HashAlgorithm::endian == boost::endian::order::native)>
|
||||
{
|
||||
explicit is_contiguously_hashable() = default;
|
||||
};
|
||||
@@ -159,7 +173,8 @@ struct is_contiguously_hashable<T[N], HashAlgorithm>
|
||||
: public std::integral_constant<
|
||||
bool,
|
||||
is_uniquely_represented<T[N]>::value &&
|
||||
(sizeof(T) == 1 || HashAlgorithm::endian == boost::endian::order::native)>
|
||||
(sizeof(T) == 1 ||
|
||||
HashAlgorithm::endian == boost::endian::order::native)>
|
||||
{
|
||||
explicit is_contiguously_hashable() = default;
|
||||
};
|
||||
@@ -204,7 +219,8 @@ hash_append(Hasher& h, T const& t) noexcept
|
||||
template <class Hasher, class T>
|
||||
inline std::enable_if_t<
|
||||
!is_contiguously_hashable<T, Hasher>::value &&
|
||||
(std::is_integral<T>::value || std::is_pointer<T>::value || std::is_enum<T>::value)>
|
||||
(std::is_integral<T>::value || std::is_pointer<T>::value ||
|
||||
std::is_enum<T>::value)>
|
||||
hash_append(Hasher& h, T t) noexcept
|
||||
{
|
||||
detail::reverse_bytes(t);
|
||||
@@ -238,11 +254,15 @@ hash_append(Hasher& h, T (&a)[N]) noexcept;
|
||||
|
||||
template <class Hasher, class CharT, class Traits, class Alloc>
|
||||
std::enable_if_t<!is_contiguously_hashable<CharT, Hasher>::value>
|
||||
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
|
||||
|
||||
template <class Hasher, class CharT, class Traits, class Alloc>
|
||||
std::enable_if_t<is_contiguously_hashable<CharT, Hasher>::value>
|
||||
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
|
||||
|
||||
template <class Hasher, class T, class U>
|
||||
std::enable_if_t<!is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
|
||||
@@ -274,10 +294,14 @@ hash_append(Hasher& h, std::unordered_set<Key, Hash, Pred, Alloc> const& s);
|
||||
|
||||
template <class Hasher, class Key, class Compare, class Alloc>
|
||||
std::enable_if_t<!is_contiguously_hashable<Key, Hasher>::value>
|
||||
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
||||
template <class Hasher, class Key, class Compare, class Alloc>
|
||||
std::enable_if_t<is_contiguously_hashable<Key, Hasher>::value>
|
||||
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
|
||||
template <class Hasher, class T0, class T1, class... T>
|
||||
void
|
||||
hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
|
||||
@@ -296,7 +320,9 @@ hash_append(Hasher& h, T (&a)[N]) noexcept
|
||||
|
||||
template <class Hasher, class CharT, class Traits, class Alloc>
|
||||
inline std::enable_if_t<!is_contiguously_hashable<CharT, Hasher>::value>
|
||||
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::basic_string<CharT, Traits, Alloc> const& s) noexcept
|
||||
{
|
||||
for (auto c : s)
|
||||
hash_append(h, c);
|
||||
@@ -305,7 +331,9 @@ hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcep
|
||||
|
||||
template <class Hasher, class CharT, class Traits, class Alloc>
|
||||
inline std::enable_if_t<is_contiguously_hashable<CharT, Hasher>::value>
|
||||
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::basic_string<CharT, Traits, Alloc> const& s) noexcept
|
||||
{
|
||||
h(s.data(), s.size() * sizeof(CharT));
|
||||
hash_append(h, s.size());
|
||||
@@ -314,7 +342,8 @@ hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcep
|
||||
// pair
|
||||
|
||||
template <class Hasher, class T, class U>
|
||||
inline std::enable_if_t<!is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
|
||||
inline std::enable_if_t<
|
||||
!is_contiguously_hashable<std::pair<T, U>, Hasher>::value>
|
||||
hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
|
||||
{
|
||||
hash_append(h, p.first, p.second);
|
||||
@@ -351,14 +380,18 @@ hash_append(Hasher& h, std::array<T, N> const& a) noexcept
|
||||
|
||||
template <class Hasher, class Key, class Compare, class Alloc>
|
||||
std::enable_if_t<!is_contiguously_hashable<Key, Hasher>::value>
|
||||
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||
{
|
||||
for (auto const& t : v)
|
||||
hash_append(h, t);
|
||||
}
|
||||
template <class Hasher, class Key, class Compare, class Alloc>
|
||||
std::enable_if_t<is_contiguously_hashable<Key, Hasher>::value>
|
||||
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
|
||||
{
|
||||
h(&(v.begin()), v.size() * sizeof(Key));
|
||||
}
|
||||
@@ -381,7 +414,10 @@ hash_one(Hasher& h, T const& t) noexcept
|
||||
|
||||
template <class Hasher, class... T, std::size_t... I>
|
||||
inline void
|
||||
tuple_hash(Hasher& h, std::tuple<T...> const& t, std::index_sequence<I...>) noexcept
|
||||
tuple_hash(
|
||||
Hasher& h,
|
||||
std::tuple<T...> const& t,
|
||||
std::index_sequence<I...>) noexcept
|
||||
{
|
||||
for_each_item(hash_one(h, std::get<I>(t))...);
|
||||
}
|
||||
@@ -389,7 +425,8 @@ tuple_hash(Hasher& h, std::tuple<T...> const& t, std::index_sequence<I...>) noex
|
||||
} // namespace detail
|
||||
|
||||
template <class Hasher, class... T>
|
||||
inline std::enable_if_t<!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
|
||||
inline std::enable_if_t<
|
||||
!is_contiguously_hashable<std::tuple<T...>, Hasher>::value>
|
||||
hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
|
||||
{
|
||||
detail::tuple_hash(h, t, std::index_sequence_for<T...>{});
|
||||
@@ -415,7 +452,9 @@ hash_append(Hasher& h, std::chrono::duration<Rep, Period> const& d) noexcept
|
||||
|
||||
template <class Hasher, class Clock, class Duration>
|
||||
inline void
|
||||
hash_append(Hasher& h, std::chrono::time_point<Clock, Duration> const& tp) noexcept
|
||||
hash_append(
|
||||
Hasher& h,
|
||||
std::chrono::time_point<Clock, Duration> const& tp) noexcept
|
||||
{
|
||||
hash_append(h, tp.time_since_epoch());
|
||||
}
|
||||
|
||||
@@ -49,7 +49,8 @@ private:
|
||||
{
|
||||
std::memcpy(writeBuffer_.data(), data, len);
|
||||
writeBuffer_ = writeBuffer_.subspan(len);
|
||||
readBuffer_ = std::span{std::begin(buffer_), buffer_.size() - writeBuffer_.size()};
|
||||
readBuffer_ = std::span{
|
||||
std::begin(buffer_), buffer_.size() - writeBuffer_.size()};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -97,7 +98,8 @@ private:
|
||||
{
|
||||
if (seed_.has_value())
|
||||
{
|
||||
return XXH3_64bits_withSeed(readBuffer_.data(), readBuffer_.size(), *seed_);
|
||||
return XXH3_64bits_withSeed(
|
||||
readBuffer_.data(), readBuffer_.size(), *seed_);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -126,13 +128,17 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
template <class Seed, std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
||||
template <
|
||||
class Seed,
|
||||
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
||||
explicit xxhasher(Seed seed) : seed_(seed)
|
||||
{
|
||||
resetBuffers();
|
||||
}
|
||||
|
||||
template <class Seed, std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
||||
template <
|
||||
class Seed,
|
||||
std::enable_if_t<std::is_unsigned<Seed>::value>* = nullptr>
|
||||
xxhasher(Seed seed, Seed) : seed_(seed)
|
||||
{
|
||||
resetBuffers();
|
||||
|
||||
@@ -23,7 +23,9 @@ public:
|
||||
@param journal Destination for logging output.
|
||||
*/
|
||||
static std::shared_ptr<StatsDCollector>
|
||||
New(IP::Endpoint const& address, std::string const& prefix, Journal journal);
|
||||
New(IP::Endpoint const& address,
|
||||
std::string const& prefix,
|
||||
Journal journal);
|
||||
};
|
||||
|
||||
} // namespace insight
|
||||
|
||||
@@ -26,7 +26,8 @@ struct ci_equal_pred
|
||||
operator()(char c1, char c2)
|
||||
{
|
||||
// VFALCO TODO Use a table lookup here
|
||||
return std::tolower(static_cast<unsigned char>(c1)) == std::tolower(static_cast<unsigned char>(c2));
|
||||
return std::tolower(static_cast<unsigned char>(c1)) ==
|
||||
std::tolower(static_cast<unsigned char>(c2));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -96,7 +97,8 @@ trim_right(String const& s)
|
||||
*/
|
||||
template <
|
||||
class FwdIt,
|
||||
class Result = std::vector<std::basic_string<typename std::iterator_traits<FwdIt>::value_type>>,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename std::iterator_traits<FwdIt>::value_type>>,
|
||||
class Char>
|
||||
Result
|
||||
split(FwdIt first, FwdIt last, Char delim)
|
||||
@@ -170,7 +172,10 @@ split(FwdIt first, FwdIt last, Char delim)
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class FwdIt, class Result = std::vector<std::basic_string<typename std::iterator_traits<FwdIt>::value_type>>>
|
||||
template <
|
||||
class FwdIt,
|
||||
class Result = std::vector<
|
||||
std::basic_string<typename std::iterator_traits<FwdIt>::value_type>>>
|
||||
Result
|
||||
split_commas(FwdIt first, FwdIt last)
|
||||
{
|
||||
@@ -218,7 +223,8 @@ public:
|
||||
bool
|
||||
operator==(list_iterator const& other) const
|
||||
{
|
||||
return other.it_ == it_ && other.end_ == end_ && other.value_.size() == value_.size();
|
||||
return other.it_ == it_ && other.end_ == end_ &&
|
||||
other.value_.size() == value_.size();
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -282,12 +288,14 @@ list_iterator::increment()
|
||||
++it_;
|
||||
if (it_ == end_)
|
||||
{
|
||||
value_ = boost::string_ref(&*start, std::distance(start, it_));
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
return;
|
||||
}
|
||||
if (*it_ == '"')
|
||||
{
|
||||
value_ = boost::string_ref(&*start, std::distance(start, it_));
|
||||
value_ = boost::string_ref(
|
||||
&*start, std::distance(start, it_));
|
||||
++it_;
|
||||
return;
|
||||
}
|
||||
@@ -313,7 +321,8 @@ list_iterator::increment()
|
||||
++it_;
|
||||
if (it_ == end_ || *it_ == ',' || is_lws(*it_))
|
||||
{
|
||||
value_ = boost::string_ref(&*start, std::distance(start, it_));
|
||||
value_ =
|
||||
boost::string_ref(&*start, std::distance(start, it_));
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -335,7 +344,8 @@ inline boost::iterator_range<list_iterator>
|
||||
make_list(boost::string_ref const& field)
|
||||
{
|
||||
return boost::iterator_range<list_iterator>{
|
||||
list_iterator{field.begin(), field.end()}, list_iterator{field.end(), field.end()}};
|
||||
list_iterator{field.begin(), field.end()},
|
||||
list_iterator{field.end(), field.end()}};
|
||||
}
|
||||
|
||||
/** Returns true if the specified token exists in the list.
|
||||
@@ -357,8 +367,12 @@ bool
|
||||
is_keep_alive(boost::beast::http::message<isRequest, Body, Fields> const& m)
|
||||
{
|
||||
if (m.version() <= 10)
|
||||
return boost::beast::http::token_list{m[boost::beast::http::field::connection]}.exists("keep-alive");
|
||||
return !boost::beast::http::token_list{m[boost::beast::http::field::connection]}.exists("close");
|
||||
return boost::beast::http::token_list{
|
||||
m[boost::beast::http::field::connection]}
|
||||
.exists("keep-alive");
|
||||
return !boost::beast::http::token_list{
|
||||
m[boost::beast::http::field::connection]}
|
||||
.exists("close");
|
||||
}
|
||||
|
||||
} // namespace rfc2616
|
||||
|
||||
@@ -31,7 +31,9 @@ protected:
|
||||
boost::asio::io_context ios_;
|
||||
|
||||
private:
|
||||
boost::optional<boost::asio::executor_work_guard<boost::asio::io_context::executor_type>> work_;
|
||||
boost::optional<boost::asio::executor_work_guard<
|
||||
boost::asio::io_context::executor_type>>
|
||||
work_;
|
||||
std::vector<std::thread> threads_;
|
||||
std::mutex m_;
|
||||
std::condition_variable cv_;
|
||||
@@ -41,7 +43,8 @@ public:
|
||||
/// The type of yield context passed to functions.
|
||||
using yield_context = boost::asio::yield_context;
|
||||
|
||||
explicit enable_yield_to(std::size_t concurrency = 1) : work_(boost::asio::make_work_guard(ios_))
|
||||
explicit enable_yield_to(std::size_t concurrency = 1)
|
||||
: work_(boost::asio::make_work_guard(ios_))
|
||||
{
|
||||
threads_.reserve(concurrency);
|
||||
while (concurrency--)
|
||||
|
||||
@@ -23,7 +23,12 @@ global_suites()
|
||||
template <class Suite>
|
||||
struct insert_suite
|
||||
{
|
||||
insert_suite(char const* name, char const* module, char const* library, bool manual, int priority)
|
||||
insert_suite(
|
||||
char const* name,
|
||||
char const* module,
|
||||
char const* library,
|
||||
bool manual,
|
||||
int priority)
|
||||
{
|
||||
global_suites().insert<Suite>(name, module, library, manual, priority);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,8 @@ public:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class>
|
||||
selector::selector(mode_t mode, std::string const& pattern) : mode_(mode), pat_(pattern)
|
||||
selector::selector(mode_t mode, std::string const& pattern)
|
||||
: mode_(mode), pat_(pattern)
|
||||
{
|
||||
if (mode_ == automatch && pattern.empty())
|
||||
mode_ = all;
|
||||
|
||||
@@ -140,7 +140,10 @@ reporter<_>::results::add(suite_results const& r)
|
||||
if (elapsed >= std::chrono::seconds{1})
|
||||
{
|
||||
auto const iter = std::lower_bound(
|
||||
top.begin(), top.end(), elapsed, [](run_time const& t1, typename clock_type::duration const& t2) {
|
||||
top.begin(),
|
||||
top.end(),
|
||||
elapsed,
|
||||
[](run_time const& t1, typename clock_type::duration const& t2) {
|
||||
return t1.second > t2;
|
||||
});
|
||||
if (iter != top.end())
|
||||
@@ -173,8 +176,10 @@ reporter<_>::~reporter()
|
||||
os_ << std::setw(8) << fmtdur(i.second) << " " << i.first << '\n';
|
||||
}
|
||||
auto const elapsed = clock_type::now() - results_.start;
|
||||
os_ << fmtdur(elapsed) << ", " << amount{results_.suites, "suite"} << ", " << amount{results_.cases, "case"} << ", "
|
||||
<< amount{results_.total, "test"} << " total, " << amount{results_.failed, "failure"} << std::endl;
|
||||
os_ << fmtdur(elapsed) << ", " << amount{results_.suites, "suite"} << ", "
|
||||
<< amount{results_.cases, "case"} << ", "
|
||||
<< amount{results_.total, "test"} << " total, "
|
||||
<< amount{results_.failed, "failure"} << std::endl;
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -209,7 +214,9 @@ void
|
||||
reporter<_>::on_case_begin(std::string const& name)
|
||||
{
|
||||
case_results_ = case_results(name);
|
||||
os_ << suite_results_.name << (case_results_.name.empty() ? "" : (" " + case_results_.name)) << std::endl;
|
||||
os_ << suite_results_.name
|
||||
<< (case_results_.name.empty() ? "" : (" " + case_results_.name))
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
template <class _>
|
||||
@@ -232,7 +239,8 @@ reporter<_>::on_fail(std::string const& reason)
|
||||
{
|
||||
++case_results_.failed;
|
||||
++case_results_.total;
|
||||
os_ << "#" << case_results_.total << " failed" << (reason.empty() ? "" : ": ") << reason << std::endl;
|
||||
os_ << "#" << case_results_.total << " failed"
|
||||
<< (reason.empty() ? "" : ": ") << reason << std::endl;
|
||||
}
|
||||
|
||||
template <class _>
|
||||
|
||||
@@ -24,7 +24,8 @@ public:
|
||||
{
|
||||
}
|
||||
|
||||
test(bool pass_, std::string const& reason_) : pass(pass_), reason(reason_)
|
||||
test(bool pass_, std::string const& reason_)
|
||||
: pass(pass_), reason(reason_)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -92,13 +92,17 @@ private:
|
||||
}
|
||||
};
|
||||
|
||||
template <class CharT, class Traits = std::char_traits<CharT>, class Allocator = std::allocator<CharT>>
|
||||
template <
|
||||
class CharT,
|
||||
class Traits = std::char_traits<CharT>,
|
||||
class Allocator = std::allocator<CharT>>
|
||||
class log_os : public std::basic_ostream<CharT, Traits>
|
||||
{
|
||||
log_buf<CharT, Traits, Allocator> buf_;
|
||||
|
||||
public:
|
||||
explicit log_os(suite& self) : std::basic_ostream<CharT, Traits>(&buf_), buf_(self)
|
||||
explicit log_os(suite& self)
|
||||
: std::basic_ostream<CharT, Traits>(&buf_), buf_(self)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -237,7 +241,11 @@ public:
|
||||
|
||||
template <class Condition, class String>
|
||||
bool
|
||||
expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line);
|
||||
expect(
|
||||
Condition const& shouldBeTrue,
|
||||
String const& reason,
|
||||
char const* file,
|
||||
int line);
|
||||
/** @} */
|
||||
|
||||
//
|
||||
@@ -341,7 +349,8 @@ public:
|
||||
}
|
||||
|
||||
template <class T>
|
||||
scoped_testcase(suite& self, std::stringstream& ss, T const& t) : suite_(self), ss_(ss)
|
||||
scoped_testcase(suite& self, std::stringstream& ss, T const& t)
|
||||
: suite_(self), ss_(ss)
|
||||
{
|
||||
ss_.clear();
|
||||
ss_.str({});
|
||||
@@ -414,7 +423,11 @@ suite::expect(Condition const& shouldBeTrue, String const& reason)
|
||||
|
||||
template <class Condition, class String>
|
||||
bool
|
||||
suite::expect(Condition const& shouldBeTrue, String const& reason, char const* file, int line)
|
||||
suite::expect(
|
||||
Condition const& shouldBeTrue,
|
||||
String const& reason,
|
||||
char const* file,
|
||||
int line)
|
||||
{
|
||||
if (shouldBeTrue)
|
||||
{
|
||||
@@ -563,7 +576,8 @@ suite::run(runner& r)
|
||||
|
||||
If the condition is false, the file and line number are reported.
|
||||
*/
|
||||
#define BEAST_EXPECTS(cond, reason) ((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false))
|
||||
#define BEAST_EXPECTS(cond, reason) \
|
||||
((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false))
|
||||
#endif
|
||||
|
||||
} // namespace unit_test
|
||||
@@ -573,9 +587,11 @@ suite::run(runner& r)
|
||||
|
||||
// detail:
|
||||
// This inserts the suite with the given manual flag
|
||||
#define BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, manual, priority) \
|
||||
static beast::unit_test::detail::insert_suite<Class##_test> Library##Module##Class##_test_instance( \
|
||||
#Class, #Module, #Library, manual, priority)
|
||||
#define BEAST_DEFINE_TESTSUITE_INSERT( \
|
||||
Class, Module, Library, manual, priority) \
|
||||
static beast::unit_test::detail::insert_suite<Class##_test> \
|
||||
Library##Module##Class##_test_instance( \
|
||||
#Class, #Module, #Library, manual, priority)
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -630,7 +646,8 @@ suite::run(runner& r)
|
||||
|
||||
#else
|
||||
#include <xrpl/beast/unit_test/global_suites.h>
|
||||
#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0)
|
||||
#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \
|
||||
BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0)
|
||||
#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \
|
||||
BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, true, 0)
|
||||
#define BEAST_DEFINE_TESTSUITE_PRIO(Class, Module, Library, Priority) \
|
||||
|
||||
@@ -28,7 +28,13 @@ class suite_info
|
||||
run_type run_;
|
||||
|
||||
public:
|
||||
suite_info(std::string name, std::string module, std::string library, bool manual, int priority, run_type run)
|
||||
suite_info(
|
||||
std::string name,
|
||||
std::string module,
|
||||
std::string library,
|
||||
bool manual,
|
||||
int priority,
|
||||
run_type run)
|
||||
: name_(std::move(name))
|
||||
, module_(std::move(module))
|
||||
, library_(std::move(library))
|
||||
@@ -82,8 +88,10 @@ public:
|
||||
{
|
||||
// we want higher priority suites sorted first, thus the negation
|
||||
// of priority value here
|
||||
return std::forward_as_tuple(-lhs.priority_, lhs.library_, lhs.module_, lhs.name_) <
|
||||
std::forward_as_tuple(-rhs.priority_, rhs.library_, rhs.module_, rhs.name_);
|
||||
return std::forward_as_tuple(
|
||||
-lhs.priority_, lhs.library_, lhs.module_, lhs.name_) <
|
||||
std::forward_as_tuple(
|
||||
-rhs.priority_, rhs.library_, rhs.module_, rhs.name_);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -92,10 +100,20 @@ public:
|
||||
/// Convenience for producing suite_info for a given test type.
|
||||
template <class Suite>
|
||||
suite_info
|
||||
make_suite_info(std::string name, std::string module, std::string library, bool manual, int priority)
|
||||
make_suite_info(
|
||||
std::string name,
|
||||
std::string module,
|
||||
std::string library,
|
||||
bool manual,
|
||||
int priority)
|
||||
{
|
||||
return suite_info(
|
||||
std::move(name), std::move(module), std::move(library), manual, priority, [](runner& r) { Suite{}(r); });
|
||||
std::move(name),
|
||||
std::move(module),
|
||||
std::move(library),
|
||||
manual,
|
||||
priority,
|
||||
[](runner& r) { Suite{}(r); });
|
||||
}
|
||||
|
||||
} // namespace unit_test
|
||||
|
||||
@@ -33,14 +33,24 @@ public:
|
||||
*/
|
||||
template <class Suite>
|
||||
void
|
||||
insert(char const* name, char const* module, char const* library, bool manual, int priority);
|
||||
insert(
|
||||
char const* name,
|
||||
char const* module,
|
||||
char const* library,
|
||||
bool manual,
|
||||
int priority);
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class Suite>
|
||||
void
|
||||
suite_list::insert(char const* name, char const* module, char const* library, bool manual, int priority)
|
||||
suite_list::insert(
|
||||
char const* name,
|
||||
char const* module,
|
||||
char const* library,
|
||||
bool manual,
|
||||
int priority)
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
{
|
||||
@@ -55,7 +65,8 @@ suite_list::insert(char const* name, char const* module, char const* library, bo
|
||||
BOOST_ASSERT(result.second); // Duplicate type
|
||||
}
|
||||
#endif
|
||||
cont().emplace(make_suite_info<Suite>(name, module, library, manual, priority));
|
||||
cont().emplace(
|
||||
make_suite_info<Suite>(name, module, library, manual, priority));
|
||||
}
|
||||
|
||||
} // namespace unit_test
|
||||
|
||||
@@ -45,7 +45,8 @@ public:
|
||||
template <class F, class... Args>
|
||||
explicit thread(suite& s, F&& f, Args&&... args) : s_(&s)
|
||||
{
|
||||
std::function<void(void)> b = std::bind(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
std::function<void(void)> b =
|
||||
std::bind(std::forward<F>(f), std::forward<Args>(args)...);
|
||||
t_ = std::thread(&thread::run, this, std::move(b));
|
||||
}
|
||||
|
||||
|
||||
@@ -130,7 +130,8 @@ public:
|
||||
class ScopedStream
|
||||
{
|
||||
public:
|
||||
ScopedStream(ScopedStream const& other) : ScopedStream(other.m_sink, other.m_level)
|
||||
ScopedStream(ScopedStream const& other)
|
||||
: ScopedStream(other.m_sink, other.m_level)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -166,12 +167,16 @@ public:
|
||||
};
|
||||
|
||||
#ifndef __INTELLISENSE__
|
||||
static_assert(std::is_default_constructible<ScopedStream>::value == false, "");
|
||||
static_assert(
|
||||
std::is_default_constructible<ScopedStream>::value == false,
|
||||
"");
|
||||
static_assert(std::is_copy_constructible<ScopedStream>::value == true, "");
|
||||
static_assert(std::is_move_constructible<ScopedStream>::value == true, "");
|
||||
static_assert(std::is_copy_assignable<ScopedStream>::value == false, "");
|
||||
static_assert(std::is_move_assignable<ScopedStream>::value == false, "");
|
||||
static_assert(std::is_nothrow_destructible<ScopedStream>::value == true, "");
|
||||
static_assert(
|
||||
std::is_nothrow_destructible<ScopedStream>::value == true,
|
||||
"");
|
||||
#endif
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -181,7 +186,8 @@ public:
|
||||
{
|
||||
public:
|
||||
/** Create a stream which produces no output. */
|
||||
explicit Stream() : m_sink(getNullSink()), m_level(severities::kDisabled)
|
||||
explicit Stream()
|
||||
: m_sink(getNullSink()), m_level(severities::kDisabled)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -191,7 +197,9 @@ public:
|
||||
*/
|
||||
Stream(Sink& sink, Severity level) : m_sink(sink), m_level(level)
|
||||
{
|
||||
XRPL_ASSERT(m_level < severities::kDisabled, "beast::Journal::Stream::Stream : maximum level");
|
||||
XRPL_ASSERT(
|
||||
m_level < severities::kDisabled,
|
||||
"beast::Journal::Stream::Stream : maximum level");
|
||||
}
|
||||
|
||||
/** Construct or copy another Stream. */
|
||||
@@ -422,7 +430,8 @@ class basic_logstream : public std::basic_ostream<CharT, Traits>
|
||||
detail::logstream_buf<CharT, Traits> buf_;
|
||||
|
||||
public:
|
||||
explicit basic_logstream(beast::Journal::Stream const& strm) : std::basic_ostream<CharT, Traits>(&buf_), buf_(strm)
|
||||
explicit basic_logstream(beast::Journal::Stream const& strm)
|
||||
: std::basic_ostream<CharT, Traits>(&buf_), buf_(strm)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
@@ -18,12 +18,16 @@ private:
|
||||
std::string prefix_;
|
||||
|
||||
public:
|
||||
explicit WrappedSink(beast::Journal::Sink& sink, std::string const& prefix = "")
|
||||
explicit WrappedSink(
|
||||
beast::Journal::Sink& sink,
|
||||
std::string const& prefix = "")
|
||||
: Sink(sink), sink_(sink), prefix_(prefix)
|
||||
{
|
||||
}
|
||||
|
||||
explicit WrappedSink(beast::Journal const& journal, std::string const& prefix = "")
|
||||
explicit WrappedSink(
|
||||
beast::Journal const& journal,
|
||||
std::string const& prefix = "")
|
||||
: WrappedSink(journal.sink(), prefix)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -20,7 +20,8 @@
|
||||
#endif
|
||||
|
||||
#define XRPL_ASSERT ALWAYS_OR_UNREACHABLE
|
||||
#define XRPL_ASSERT_PARTS(cond, function, description, ...) XRPL_ASSERT(cond, function " : " description)
|
||||
#define XRPL_ASSERT_PARTS(cond, function, description, ...) \
|
||||
XRPL_ASSERT(cond, function " : " description)
|
||||
|
||||
// How to use the instrumentation macros:
|
||||
//
|
||||
|
||||
@@ -10,8 +10,10 @@ template <bool IsConst, class T>
|
||||
struct maybe_const
|
||||
{
|
||||
explicit maybe_const() = default;
|
||||
using type = typename std::
|
||||
conditional<IsConst, typename std::remove_const<T>::type const, typename std::remove_const<T>::type>::type;
|
||||
using type = typename std::conditional<
|
||||
IsConst,
|
||||
typename std::remove_const<T>::type const,
|
||||
typename std::remove_const<T>::type>::type;
|
||||
};
|
||||
|
||||
/** Alias for omitting `typename`. */
|
||||
|
||||
@@ -36,7 +36,10 @@ rngfill(void* const buffer, std::size_t const bytes, Generator& g)
|
||||
}
|
||||
}
|
||||
|
||||
template <class Generator, std::size_t N, class = std::enable_if_t<N % sizeof(typename Generator::result_type) == 0>>
|
||||
template <
|
||||
class Generator,
|
||||
std::size_t N,
|
||||
class = std::enable_if_t<N % sizeof(typename Generator::result_type) == 0>>
|
||||
void
|
||||
rngfill(std::array<std::uint8_t, N>& a, Generator& g)
|
||||
{
|
||||
|
||||
@@ -76,18 +76,21 @@ private:
|
||||
std::remove_reference_t<Closure> closure_;
|
||||
|
||||
static_assert(
|
||||
std::is_same<decltype(closure_(std::declval<Args_t>()...)), Ret_t>::value,
|
||||
std::is_same<decltype(closure_(std::declval<Args_t>()...)), Ret_t>::
|
||||
value,
|
||||
"Closure arguments don't match ClosureCounter Ret_t or Args_t");
|
||||
|
||||
public:
|
||||
Substitute() = delete;
|
||||
|
||||
Substitute(Substitute const& rhs) : counter_(rhs.counter_), closure_(rhs.closure_)
|
||||
Substitute(Substitute const& rhs)
|
||||
: counter_(rhs.counter_), closure_(rhs.closure_)
|
||||
{
|
||||
++counter_;
|
||||
}
|
||||
|
||||
Substitute(Substitute&& rhs) noexcept(std::is_nothrow_move_constructible<Closure>::value)
|
||||
Substitute(Substitute&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible<Closure>::value)
|
||||
: counter_(rhs.counter_), closure_(std::move(rhs.closure_))
|
||||
{
|
||||
++counter_;
|
||||
@@ -147,11 +150,13 @@ public:
|
||||
waitForClosures_ = true;
|
||||
if (closureCount_ > 0)
|
||||
{
|
||||
if (!allClosuresDoneCond_.wait_for(lock, wait, [this] { return closureCount_ == 0; }))
|
||||
if (!allClosuresDoneCond_.wait_for(
|
||||
lock, wait, [this] { return closureCount_ == 0; }))
|
||||
{
|
||||
if (auto stream = j.error())
|
||||
stream << name << " waiting for ClosureCounter::join().";
|
||||
allClosuresDoneCond_.wait(lock, [this] { return closureCount_ == 0; });
|
||||
allClosuresDoneCond_.wait(
|
||||
lock, [this] { return closureCount_ == 0; });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,13 +6,20 @@
|
||||
namespace xrpl {
|
||||
|
||||
template <class F>
|
||||
JobQueue::Coro::Coro(Coro_create_t, JobQueue& jq, JobType type, std::string const& name, F&& f)
|
||||
JobQueue::Coro::Coro(
|
||||
Coro_create_t,
|
||||
JobQueue& jq,
|
||||
JobType type,
|
||||
std::string const& name,
|
||||
F&& f)
|
||||
: jq_(jq)
|
||||
, type_(type)
|
||||
, name_(name)
|
||||
, running_(false)
|
||||
, coro_(
|
||||
[this, fn = std::forward<F>(f)](boost::coroutines::asymmetric_coroutine<void>::push_type& do_yield) {
|
||||
[this, fn = std::forward<F>(f)](
|
||||
boost::coroutines::asymmetric_coroutine<void>::push_type&
|
||||
do_yield) {
|
||||
yield_ = &do_yield;
|
||||
yield();
|
||||
fn(shared_from_this());
|
||||
@@ -50,7 +57,8 @@ JobQueue::Coro::post()
|
||||
}
|
||||
|
||||
// sp keeps 'this' alive
|
||||
if (jq_.addJob(type_, name_, [this, sp = shared_from_this()]() { resume(); }))
|
||||
if (jq_.addJob(
|
||||
type_, name_, [this, sp = shared_from_this()]() { resume(); }))
|
||||
{
|
||||
return true;
|
||||
}
|
||||
@@ -76,7 +84,8 @@ JobQueue::Coro::resume()
|
||||
auto saved = detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(&lvs_);
|
||||
std::lock_guard lock(mutex_);
|
||||
XRPL_ASSERT(static_cast<bool>(coro_), "xrpl::JobQueue::Coro::resume : is runnable");
|
||||
XRPL_ASSERT(
|
||||
static_cast<bool>(coro_), "xrpl::JobQueue::Coro::resume : is runnable");
|
||||
coro_();
|
||||
detail::getLocalValues().release();
|
||||
detail::getLocalValues().reset(saved);
|
||||
|
||||
@@ -93,7 +93,11 @@ public:
|
||||
Job(JobType type, std::uint64_t index);
|
||||
|
||||
// VFALCO TODO try to remove the dependency on LoadMonitor.
|
||||
Job(JobType type, std::string const& name, std::uint64_t index, LoadMonitor& lm, std::function<void()> const& job);
|
||||
Job(JobType type,
|
||||
std::string const& name,
|
||||
std::uint64_t index,
|
||||
LoadMonitor& lm,
|
||||
std::function<void()> const& job);
|
||||
|
||||
JobType
|
||||
getType() const;
|
||||
|
||||
@@ -141,11 +141,14 @@ public:
|
||||
*/
|
||||
template <
|
||||
typename JobHandler,
|
||||
typename = std::enable_if_t<std::is_same<decltype(std::declval<JobHandler&&>()()), void>::value>>
|
||||
typename = std::enable_if_t<std::is_same<
|
||||
decltype(std::declval<JobHandler&&>()()),
|
||||
void>::value>>
|
||||
bool
|
||||
addJob(JobType type, std::string const& name, JobHandler&& jobHandler)
|
||||
{
|
||||
if (auto optionalCountedJob = jobCounter_.wrap(std::forward<JobHandler>(jobHandler)))
|
||||
if (auto optionalCountedJob =
|
||||
jobCounter_.wrap(std::forward<JobHandler>(jobHandler)))
|
||||
{
|
||||
return addRefCountedJob(type, name, std::move(*optionalCountedJob));
|
||||
}
|
||||
@@ -261,7 +264,10 @@ private:
|
||||
//
|
||||
// return true if func added to queue.
|
||||
bool
|
||||
addRefCountedJob(JobType type, std::string const& name, JobFunction const& func);
|
||||
addRefCountedJob(
|
||||
JobType type,
|
||||
std::string const& name,
|
||||
JobFunction const& func);
|
||||
|
||||
// Returns the next Job we should run now.
|
||||
//
|
||||
@@ -390,7 +396,8 @@ JobQueue::postCoro(JobType t, std::string const& name, F&& f)
|
||||
Last param is the function the coroutine runs. Signature of
|
||||
void(std::shared_ptr<Coro>).
|
||||
*/
|
||||
auto coro = std::make_shared<Coro>(Coro_create_t{}, *this, t, name, std::forward<F>(f));
|
||||
auto coro = std::make_shared<Coro>(
|
||||
Coro_create_t{}, *this, t, name, std::forward<F>(f));
|
||||
if (!coro->post())
|
||||
{
|
||||
// The Coro was not successfully posted. Disable it so it's destructor
|
||||
|
||||
@@ -32,10 +32,19 @@ public:
|
||||
beast::insight::Event dequeue;
|
||||
beast::insight::Event execute;
|
||||
|
||||
JobTypeData(JobTypeInfo const& info_, beast::insight::Collector::ptr const& collector, Logs& logs) noexcept
|
||||
: m_load(logs.journal("LoadMonitor")), m_collector(collector), info(info_), waiting(0), running(0), deferred(0)
|
||||
JobTypeData(
|
||||
JobTypeInfo const& info_,
|
||||
beast::insight::Collector::ptr const& collector,
|
||||
Logs& logs) noexcept
|
||||
: m_load(logs.journal("LoadMonitor"))
|
||||
, m_collector(collector)
|
||||
, info(info_)
|
||||
, waiting(0)
|
||||
, running(0)
|
||||
, deferred(0)
|
||||
{
|
||||
m_load.setTargetLatency(info.getAverageLatency(), info.getPeakLatency());
|
||||
m_load.setTargetLatency(
|
||||
info.getAverageLatency(), info.getPeakLatency());
|
||||
|
||||
if (!info.special())
|
||||
{
|
||||
|
||||
@@ -33,7 +33,11 @@ public:
|
||||
int limit,
|
||||
std::chrono::milliseconds avgLatency,
|
||||
std::chrono::milliseconds peakLatency)
|
||||
: m_type(type), m_name(std::move(name)), m_limit(limit), m_avgLatency(avgLatency), m_peakLatency(peakLatency)
|
||||
: m_type(type)
|
||||
, m_name(std::move(name))
|
||||
, m_limit(limit)
|
||||
, m_avgLatency(avgLatency)
|
||||
, m_peakLatency(peakLatency)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -16,7 +16,13 @@ public:
|
||||
using const_iterator = Map::const_iterator;
|
||||
|
||||
private:
|
||||
JobTypes() : m_unknown(jtINVALID, "invalid", 0, std::chrono::milliseconds{0}, std::chrono::milliseconds{0})
|
||||
JobTypes()
|
||||
: m_unknown(
|
||||
jtINVALID,
|
||||
"invalid",
|
||||
0,
|
||||
std::chrono::milliseconds{0},
|
||||
std::chrono::milliseconds{0})
|
||||
{
|
||||
using namespace std::chrono_literals;
|
||||
int maxLimit = std::numeric_limits<int>::max();
|
||||
@@ -27,17 +33,22 @@ private:
|
||||
int limit,
|
||||
std::chrono::milliseconds avgLatency,
|
||||
std::chrono::milliseconds peakLatency) {
|
||||
XRPL_ASSERT(m_map.find(jt) == m_map.end(), "xrpl::JobTypes::JobTypes::add : unique job type input");
|
||||
XRPL_ASSERT(
|
||||
m_map.find(jt) == m_map.end(),
|
||||
"xrpl::JobTypes::JobTypes::add : unique job type input");
|
||||
|
||||
[[maybe_unused]] auto const inserted =
|
||||
m_map
|
||||
.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(jt),
|
||||
std::forward_as_tuple(jt, name, limit, avgLatency, peakLatency))
|
||||
std::forward_as_tuple(
|
||||
jt, name, limit, avgLatency, peakLatency))
|
||||
.second;
|
||||
|
||||
XRPL_ASSERT(inserted == true, "xrpl::JobTypes::JobTypes::add : input is inserted");
|
||||
XRPL_ASSERT(
|
||||
inserted == true,
|
||||
"xrpl::JobTypes::JobTypes::add : input is inserted");
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
|
||||
@@ -27,7 +27,9 @@ public:
|
||||
addSamples(int count, std::chrono::milliseconds latency);
|
||||
|
||||
void
|
||||
setTargetLatency(std::chrono::milliseconds avg, std::chrono::milliseconds pk);
|
||||
setTargetLatency(
|
||||
std::chrono::milliseconds avg,
|
||||
std::chrono::milliseconds pk);
|
||||
|
||||
bool
|
||||
isOverTarget(std::chrono::milliseconds avg, std::chrono::milliseconds peak);
|
||||
|
||||
@@ -105,7 +105,11 @@ public:
|
||||
* @param instance JobQueue worker thread instance
|
||||
*/
|
||||
virtual void
|
||||
jobStart(JobType const type, microseconds dur, steady_time_point startTime, int instance) = 0;
|
||||
jobStart(
|
||||
JobType const type,
|
||||
microseconds dur,
|
||||
steady_time_point startTime,
|
||||
int instance) = 0;
|
||||
|
||||
/**
|
||||
* Log job finishing
|
||||
@@ -152,7 +156,11 @@ PerfLog::Setup
|
||||
setup_PerfLog(Section const& section, boost::filesystem::path const& configDir);
|
||||
|
||||
std::unique_ptr<PerfLog>
|
||||
make_PerfLog(PerfLog::Setup const& setup, Application& app, beast::Journal journal, std::function<void()>&& signalStop);
|
||||
make_PerfLog(
|
||||
PerfLog::Setup const& setup,
|
||||
Application& app,
|
||||
beast::Journal journal,
|
||||
std::function<void()>&& signalStop);
|
||||
|
||||
template <typename Func, class Rep, class Period>
|
||||
auto
|
||||
@@ -167,10 +175,12 @@ measureDurationAndLog(
|
||||
auto result = func();
|
||||
|
||||
auto end_time = std::chrono::high_resolution_clock::now();
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(end_time - start_time);
|
||||
auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
end_time - start_time);
|
||||
if (duration > maxDelay)
|
||||
{
|
||||
JLOG(journal.warn()) << actionDescription << " took " << duration.count() << " ms";
|
||||
JLOG(journal.warn())
|
||||
<< actionDescription << " took " << duration.count() << " ms";
|
||||
}
|
||||
|
||||
return result;
|
||||
|
||||
@@ -95,7 +95,8 @@ public:
|
||||
Callback& callback,
|
||||
perf::PerfLog* perfLog,
|
||||
std::string const& threadNames = "Worker",
|
||||
int numberOfThreads = static_cast<int>(std::thread::hardware_concurrency()));
|
||||
int numberOfThreads =
|
||||
static_cast<int>(std::thread::hardware_concurrency()));
|
||||
|
||||
~Workers();
|
||||
|
||||
@@ -161,10 +162,14 @@ private:
|
||||
Idle: Active, but blocked on waiting for a task.
|
||||
Paused: Blocked waiting to exit or become active.
|
||||
*/
|
||||
class Worker : public beast::LockFreeStack<Worker>::Node, public beast::LockFreeStack<Worker, PausedTag>::Node
|
||||
class Worker : public beast::LockFreeStack<Worker>::Node,
|
||||
public beast::LockFreeStack<Worker, PausedTag>::Node
|
||||
{
|
||||
public:
|
||||
Worker(Workers& workers, std::string const& threadName, int const instance);
|
||||
Worker(
|
||||
Workers& workers,
|
||||
std::string const& threadName,
|
||||
int const instance);
|
||||
|
||||
~Worker();
|
||||
|
||||
@@ -198,13 +203,15 @@ private:
|
||||
std::condition_variable m_cv; // signaled when all threads paused
|
||||
std::mutex m_mut;
|
||||
bool m_allPaused;
|
||||
semaphore m_semaphore; // each pending task is 1 resource
|
||||
int m_numberOfThreads; // how many we want active now
|
||||
std::atomic<int> m_activeCount; // to know when all are paused
|
||||
std::atomic<int> m_pauseCount; // how many threads need to pause now
|
||||
std::atomic<int> m_runningTaskCount; // how many calls to processTask() active
|
||||
beast::LockFreeStack<Worker> m_everyone; // holds all created workers
|
||||
beast::LockFreeStack<Worker, PausedTag> m_paused; // holds just paused workers
|
||||
semaphore m_semaphore; // each pending task is 1 resource
|
||||
int m_numberOfThreads; // how many we want active now
|
||||
std::atomic<int> m_activeCount; // to know when all are paused
|
||||
std::atomic<int> m_pauseCount; // how many threads need to pause now
|
||||
std::atomic<int>
|
||||
m_runningTaskCount; // how many calls to processTask() active
|
||||
beast::LockFreeStack<Worker> m_everyone; // holds all created workers
|
||||
beast::LockFreeStack<Worker, PausedTag>
|
||||
m_paused; // holds just paused workers
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -15,7 +15,9 @@ using Output = std::function<void(boost::beast::string_view const&)>;
|
||||
inline Output
|
||||
stringOutput(std::string& s)
|
||||
{
|
||||
return [&](boost::beast::string_view const& b) { s.append(b.data(), b.size()); };
|
||||
return [&](boost::beast::string_view const& b) {
|
||||
s.append(b.data(), b.size());
|
||||
};
|
||||
}
|
||||
|
||||
/** Writes a minimal representation of a Json value to an Output in O(n) time.
|
||||
|
||||
@@ -144,15 +144,26 @@ private:
|
||||
bool
|
||||
decodeDouble(Token& token);
|
||||
bool
|
||||
decodeUnicodeCodePoint(Token& token, Location& current, Location end, unsigned int& unicode);
|
||||
decodeUnicodeCodePoint(
|
||||
Token& token,
|
||||
Location& current,
|
||||
Location end,
|
||||
unsigned int& unicode);
|
||||
bool
|
||||
decodeUnicodeEscapeSequence(Token& token, Location& current, Location end, unsigned int& unicode);
|
||||
decodeUnicodeEscapeSequence(
|
||||
Token& token,
|
||||
Location& current,
|
||||
Location end,
|
||||
unsigned int& unicode);
|
||||
bool
|
||||
addError(std::string const& message, Token& token, Location extra = 0);
|
||||
bool
|
||||
recoverFromError(TokenType skipUntilToken);
|
||||
bool
|
||||
addErrorAndRecover(std::string const& message, Token& token, TokenType skipUntilToken);
|
||||
addErrorAndRecover(
|
||||
std::string const& message,
|
||||
Token& token,
|
||||
TokenType skipUntilToken);
|
||||
void
|
||||
skipUntilSpace();
|
||||
Value&
|
||||
|
||||
@@ -148,7 +148,11 @@ private:
|
||||
class CZString
|
||||
{
|
||||
public:
|
||||
enum DuplicationPolicy { noDuplication = 0, duplicate, duplicateOnCopy };
|
||||
enum DuplicationPolicy {
|
||||
noDuplication = 0,
|
||||
duplicate,
|
||||
duplicateOnCopy
|
||||
};
|
||||
CZString(int index);
|
||||
CZString(char const* cstr, DuplicationPolicy allocate);
|
||||
CZString(CZString const& other);
|
||||
|
||||
@@ -316,7 +316,10 @@ public:
|
||||
operator<<(std::ostream& o, Compact const& cJv)
|
||||
{
|
||||
detail::write_value(
|
||||
[&o](void const* data, std::size_t n) { o.write(static_cast<char const*>(data), n); }, cJv.jv_);
|
||||
[&o](void const* data, std::size_t n) {
|
||||
o.write(static_cast<char const*>(data), n);
|
||||
},
|
||||
cJv.jv_);
|
||||
return o;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -34,17 +34,23 @@ constexpr ApplyFlags
|
||||
operator|(ApplyFlags const& lhs, ApplyFlags const& rhs)
|
||||
{
|
||||
return safe_cast<ApplyFlags>(
|
||||
safe_cast<std::underlying_type_t<ApplyFlags>>(lhs) | safe_cast<std::underlying_type_t<ApplyFlags>>(rhs));
|
||||
safe_cast<std::underlying_type_t<ApplyFlags>>(lhs) |
|
||||
safe_cast<std::underlying_type_t<ApplyFlags>>(rhs));
|
||||
}
|
||||
|
||||
static_assert((tapFAIL_HARD | tapRETRY) == safe_cast<ApplyFlags>(0x30u), "ApplyFlags operator |");
|
||||
static_assert((tapRETRY | tapFAIL_HARD) == safe_cast<ApplyFlags>(0x30u), "ApplyFlags operator |");
|
||||
static_assert(
|
||||
(tapFAIL_HARD | tapRETRY) == safe_cast<ApplyFlags>(0x30u),
|
||||
"ApplyFlags operator |");
|
||||
static_assert(
|
||||
(tapRETRY | tapFAIL_HARD) == safe_cast<ApplyFlags>(0x30u),
|
||||
"ApplyFlags operator |");
|
||||
|
||||
constexpr ApplyFlags
|
||||
operator&(ApplyFlags const& lhs, ApplyFlags const& rhs)
|
||||
{
|
||||
return safe_cast<ApplyFlags>(
|
||||
safe_cast<std::underlying_type_t<ApplyFlags>>(lhs) & safe_cast<std::underlying_type_t<ApplyFlags>>(rhs));
|
||||
safe_cast<std::underlying_type_t<ApplyFlags>>(lhs) &
|
||||
safe_cast<std::underlying_type_t<ApplyFlags>>(rhs));
|
||||
}
|
||||
|
||||
static_assert((tapFAIL_HARD & tapRETRY) == tapNONE, "ApplyFlags operator &");
|
||||
@@ -53,10 +59,13 @@ static_assert((tapRETRY & tapFAIL_HARD) == tapNONE, "ApplyFlags operator &");
|
||||
constexpr ApplyFlags
|
||||
operator~(ApplyFlags const& flags)
|
||||
{
|
||||
return safe_cast<ApplyFlags>(~safe_cast<std::underlying_type_t<ApplyFlags>>(flags));
|
||||
return safe_cast<ApplyFlags>(
|
||||
~safe_cast<std::underlying_type_t<ApplyFlags>>(flags));
|
||||
}
|
||||
|
||||
static_assert(~tapRETRY == safe_cast<ApplyFlags>(0xFFFFFFDFu), "ApplyFlags operator ~");
|
||||
static_assert(
|
||||
~tapRETRY == safe_cast<ApplyFlags>(0xFFFFFFDFu),
|
||||
"ApplyFlags operator ~");
|
||||
|
||||
inline ApplyFlags
|
||||
operator|=(ApplyFlags& lhs, ApplyFlags const& rhs)
|
||||
@@ -212,14 +221,21 @@ public:
|
||||
// Called when a credit is made to an account
|
||||
// This is required to support PaymentSandbox
|
||||
virtual void
|
||||
creditHook(AccountID const& from, AccountID const& to, STAmount const& amount, STAmount const& preCreditBalance)
|
||||
creditHook(
|
||||
AccountID const& from,
|
||||
AccountID const& to,
|
||||
STAmount const& amount,
|
||||
STAmount const& preCreditBalance)
|
||||
{
|
||||
}
|
||||
|
||||
// Called when the owner count changes
|
||||
// This is required to support PaymentSandbox
|
||||
virtual void
|
||||
adjustOwnerCountHook(AccountID const& account, std::uint32_t cur, std::uint32_t next)
|
||||
adjustOwnerCountHook(
|
||||
AccountID const& account,
|
||||
std::uint32_t cur,
|
||||
std::uint32_t next)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -316,10 +332,18 @@ public:
|
||||
*/
|
||||
/** @{ */
|
||||
bool
|
||||
dirRemove(Keylet const& directory, std::uint64_t page, uint256 const& key, bool keepRoot);
|
||||
dirRemove(
|
||||
Keylet const& directory,
|
||||
std::uint64_t page,
|
||||
uint256 const& key,
|
||||
bool keepRoot);
|
||||
|
||||
bool
|
||||
dirRemove(Keylet const& directory, std::uint64_t page, Keylet const& key, bool keepRoot)
|
||||
dirRemove(
|
||||
Keylet const& directory,
|
||||
std::uint64_t page,
|
||||
Keylet const& key,
|
||||
bool keepRoot)
|
||||
{
|
||||
return dirRemove(directory, page, key.key, keepRoot);
|
||||
}
|
||||
@@ -327,7 +351,9 @@ public:
|
||||
|
||||
/** Remove the specified directory, invoking the callback for every node. */
|
||||
bool
|
||||
dirDelete(Keylet const& directory, std::function<void(uint256 const&)> const&);
|
||||
dirDelete(
|
||||
Keylet const& directory,
|
||||
std::function<void(uint256 const&)> const&);
|
||||
|
||||
/** Remove the specified directory, if it is empty.
|
||||
|
||||
|
||||
@@ -34,7 +34,13 @@ public:
|
||||
destructor.
|
||||
*/
|
||||
std::optional<TxMeta>
|
||||
apply(OpenView& to, STTx const& tx, TER ter, std::optional<uint256> parentBatchId, bool isDryRun, beast::Journal j);
|
||||
apply(
|
||||
OpenView& to,
|
||||
STTx const& tx,
|
||||
TER ter,
|
||||
std::optional<uint256> parentBatchId,
|
||||
bool isDryRun,
|
||||
beast::Journal j);
|
||||
|
||||
/** Set the amount of currency delivered.
|
||||
|
||||
|
||||
@@ -68,7 +68,10 @@ public:
|
||||
private:
|
||||
friend class BookDirs;
|
||||
|
||||
const_iterator(ReadView const& view, uint256 const& root, uint256 const& dir_key)
|
||||
const_iterator(
|
||||
ReadView const& view,
|
||||
uint256 const& root,
|
||||
uint256 const& dir_key)
|
||||
: view_(&view), root_(root), key_(dir_key), cur_key_(dir_key)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -26,7 +26,8 @@ public:
|
||||
CachedViewImpl&
|
||||
operator=(CachedViewImpl const&) = delete;
|
||||
|
||||
CachedViewImpl(DigestAwareReadView const* base, CachedSLEs& cache) : base_(*base), cache_(cache)
|
||||
CachedViewImpl(DigestAwareReadView const* base, CachedSLEs& cache)
|
||||
: base_(*base), cache_(cache)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -65,7 +66,9 @@ public:
|
||||
}
|
||||
|
||||
std::optional<key_type>
|
||||
succ(key_type const& key, std::optional<key_type> const& last = std::nullopt) const override
|
||||
succ(
|
||||
key_type const& key,
|
||||
std::optional<key_type> const& last = std::nullopt) const override
|
||||
{
|
||||
return base_.succ(key, last);
|
||||
}
|
||||
|
||||
@@ -20,7 +20,9 @@ namespace credentials {
|
||||
|
||||
// Check if credential sfExpiration field has passed ledger's parentCloseTime
|
||||
bool
|
||||
checkExpired(std::shared_ptr<SLE const> const& sleCredential, NetClock::time_point const& closed);
|
||||
checkExpired(
|
||||
std::shared_ptr<SLE const> const& sleCredential,
|
||||
NetClock::time_point const& closed);
|
||||
|
||||
// Return true if any expired credential was found in arr (and deleted)
|
||||
bool
|
||||
@@ -28,7 +30,10 @@ removeExpired(ApplyView& view, STVector256 const& arr, beast::Journal const j);
|
||||
|
||||
// Actually remove a credentials object from the ledger
|
||||
TER
|
||||
deleteSLE(ApplyView& view, std::shared_ptr<SLE> const& sleCredential, beast::Journal j);
|
||||
deleteSLE(
|
||||
ApplyView& view,
|
||||
std::shared_ptr<SLE> const& sleCredential,
|
||||
beast::Journal j);
|
||||
|
||||
// Amendment and parameters checks for sfCredentialIDs field
|
||||
NotTEC
|
||||
@@ -39,7 +44,11 @@ checkFields(STTx const& tx, beast::Journal j);
|
||||
// If you call it in preclaim, you also must call verifyDepositPreauth in
|
||||
// doApply
|
||||
TER
|
||||
valid(STTx const& tx, ReadView const& view, AccountID const& src, beast::Journal j);
|
||||
valid(
|
||||
STTx const& tx,
|
||||
ReadView const& view,
|
||||
AccountID const& src,
|
||||
beast::Journal j);
|
||||
|
||||
// Check if subject has any credential maching the given domain. If you call it
|
||||
// in preclaim and it returns tecEXPIRED, you should call verifyValidDomain in
|
||||
@@ -50,7 +59,10 @@ validDomain(ReadView const& view, uint256 domainID, AccountID const& subject);
|
||||
// This function is only called when we about to return tecNO_PERMISSION
|
||||
// because all the checks for the DepositPreauth authorization failed.
|
||||
TER
|
||||
authorizedDepositPreauth(ApplyView const& view, STVector256 const& ctx, AccountID const& dst);
|
||||
authorizedDepositPreauth(
|
||||
ApplyView const& view,
|
||||
STVector256 const& ctx,
|
||||
AccountID const& dst);
|
||||
|
||||
// Sort credentials array, return empty set if there are duplicates
|
||||
std::set<std::pair<AccountID, Slice>>
|
||||
@@ -66,7 +78,11 @@ checkArray(STArray const& credentials, unsigned maxSize, beast::Journal j);
|
||||
// Check expired credentials and for credentials maching DomainID of the ledger
|
||||
// object
|
||||
TER
|
||||
verifyValidDomain(ApplyView& view, AccountID const& account, uint256 domainID, beast::Journal j);
|
||||
verifyValidDomain(
|
||||
ApplyView& view,
|
||||
AccountID const& account,
|
||||
uint256 domainID,
|
||||
beast::Journal j);
|
||||
|
||||
// Check expired credentials and for existing DepositPreauth ledger object
|
||||
TER
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user