Merge branch 'develop' into ximinez/acquireAsyncDispatch

This commit is contained in:
Ed Hennis
2026-07-09 19:50:02 -04:00
committed by GitHub
1312 changed files with 60412 additions and 23462 deletions

View File

@@ -6,6 +6,7 @@
#include <cstdint>
#include <cstring>
#include <memory>
#include <utility>
namespace xrpl {

View File

@@ -5,6 +5,7 @@
#include <lz4.h>
#include <algorithm>
#include <cstddef>
#include <cstdint>
#include <stdexcept>
#include <vector>

View File

@@ -2,6 +2,7 @@
#include <chrono>
#include <cmath>
#include <cstddef>
namespace xrpl {
@@ -12,8 +13,8 @@ template <int Window, typename Clock>
class DecayingSample
{
public:
using value_type = typename Clock::duration::rep;
using time_point = typename Clock::time_point;
using value_type = Clock::duration::rep;
using time_point = Clock::time_point;
DecayingSample() = delete;
@@ -93,7 +94,7 @@ template <int HalfLife, class Clock>
class DecayWindow
{
public:
using time_point = typename Clock::time_point;
using time_point = Clock::time_point;
explicit DecayWindow(time_point now) : when_(now)
{

View File

@@ -1,248 +0,0 @@
#pragma once
#include <xrpl/basics/contract.h>
#include <boost/outcome.hpp>
#include <stdexcept>
namespace xrpl {
/** Expected is an approximation of std::expected (hoped for in C++23)
See: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
The implementation is entirely based on boost::outcome_v2::result.
*/
// Exception thrown by an invalid access to Expected.
struct BadExpectedAccess : public std::runtime_error
{
BadExpectedAccess() : runtime_error("bad expected access")
{
}
};
namespace detail {
// Custom policy for Expected. Always throw on an invalid access.
struct ThrowPolicy : public boost::outcome_v2::policy::base
{
template <class Impl>
static constexpr void
// NOLINTNEXTLINE(readability-identifier-naming)
wide_value_check(Impl&& self)
{
if (!base::_has_value(std::forward<Impl>(self)))
Throw<BadExpectedAccess>();
}
template <class Impl>
static constexpr void
// NOLINTNEXTLINE(readability-identifier-naming)
wide_error_check(Impl&& self)
{
if (!base::_has_error(std::forward<Impl>(self)))
Throw<BadExpectedAccess>();
}
template <class Impl>
static constexpr void
// NOLINTNEXTLINE(readability-identifier-naming)
wide_exception_check(Impl&& self)
{
if (!base::_has_exception(std::forward<Impl>(self)))
Throw<BadExpectedAccess>();
}
};
} // namespace detail
// Definition of Unexpected, which is used to construct the unexpected
// return type of an Expected.
template <class E>
class Unexpected
{
public:
static_assert(!std::is_same_v<E, void>, "E must not be void");
Unexpected() = delete;
constexpr explicit Unexpected(E const& e) : val_(e)
{
}
constexpr explicit Unexpected(E&& e) : val_(std::move(e))
{
}
[[nodiscard]] constexpr E const&
value() const&
{
return val_;
}
constexpr E&
value() &
{
return val_;
}
constexpr E&&
value() &&
{
return std::move(val_);
}
[[nodiscard]] constexpr E const&&
value() const&&
{
return std::move(val_);
}
private:
E val_;
};
// Unexpected deduction guide that converts array to const*.
template <typename E, std::size_t N>
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::ThrowPolicy>
{
using Base = boost::outcome_v2::result<T, E, detail::ThrowPolicy>;
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))
{
}
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()))
{
}
[[nodiscard]] constexpr bool
// NOLINTNEXTLINE(readability-identifier-naming)
has_value() const
{
return Base::has_value();
}
[[nodiscard]] constexpr T const&
value() const
{
return Base::value();
}
constexpr T&
value()
{
return Base::value();
}
[[nodiscard]] constexpr E const&
error() const&
{
return Base::error();
}
[[nodiscard]] constexpr E&
error() &
{
return Base::error();
}
[[nodiscard]] constexpr E&&
error() &&
{
return std::move(Base::error());
}
constexpr explicit
operator bool() const
{
return has_value();
}
// Add operator* and operator-> so the Expected API looks a bit more like
// what std::expected is likely to look like. See:
// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p0323r10.html
[[nodiscard]] constexpr T&
operator*()
{
return this->value();
}
[[nodiscard]] constexpr T const&
operator*() const
{
return this->value();
}
[[nodiscard]] constexpr T*
operator->()
{
return &this->value();
}
[[nodiscard]] constexpr T const*
operator->() const
{
return &this->value();
}
};
// 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::ThrowPolicy>
{
using Base = boost::outcome_v2::result<void, E, detail::ThrowPolicy>;
public:
// The default constructor makes a successful Expected<void, E>.
// This aligns with std::expected behavior proposed in P0323R10.
constexpr Expected() : Base(boost::outcome_v2::success())
{
}
template <typename U>
requires std::convertible_to<U, E> && (!std::is_reference_v<U>)
constexpr Expected(Unexpected<U> e) : Base(E(std::move(e.value())))
{
}
[[nodiscard]] constexpr E const&
error() const&
{
return Base::error();
}
[[nodiscard]] constexpr E&
error() &
{
return Base::error();
}
[[nodiscard]] constexpr E&&
error() &&
{
return std::move(Base::error());
}
constexpr explicit
operator bool() const
{
return Base::has_value();
}
};
} // namespace xrpl

View File

@@ -3,7 +3,9 @@
#include <boost/filesystem.hpp>
#include <boost/system/error_code.hpp>
#include <cstddef>
#include <optional>
#include <string>
namespace xrpl {

View File

@@ -1,6 +1,7 @@
#pragma once
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <type_traits>
#include <utility>

View File

@@ -641,6 +641,9 @@ template <class T>
T*
SharedWeakUnion<T>::unsafeGetRawPtr() const
{
// tp_ packs a raw pointer together with a strength bit; recovering the
// pointer inherently requires an integer-to-pointer cast.
// NOLINTNEXTLINE(performance-no-int-to-ptr)
return reinterpret_cast<T*>(tp_ & kPtrMask);
}

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <atomic>
#include <cstddef>
#include <cstdint>
namespace xrpl {

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/beast/utility/Journal.h>
#include <boost/beast/core/string.hpp>
@@ -11,7 +10,9 @@
#include <memory>
#include <mutex>
#include <optional>
#include <string>
#include <utility>
#include <vector>
namespace xrpl {
@@ -206,8 +207,7 @@ private:
#ifndef JLOG
#define JLOG(x) \
if (!(x)) \
{ \
} \
; \
else \
x
#endif

View File

@@ -2,12 +2,20 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <algorithm>
#include <array>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <limits>
#include <optional>
#include <ostream>
#include <set>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
namespace xrpl {
@@ -38,17 +46,58 @@ isPowerOfTen(T value)
return logTen(value).has_value();
}
namespace detail {
/** Builds a table of the powers of 10
*
* This function is marked consteval, so it can only be run in
* a constexpr context. This assures that it is and can only be run at
* compile time. Doing it at runtime would be pretty wasteful and
* inefficient.
*/
constexpr std::size_t kInt64Digits = 20;
consteval std::array<std::uint64_t, kInt64Digits>
buildPowersOfTen()
{
std::array<std::uint64_t, kInt64Digits> result{};
std::uint64_t power = 1;
std::size_t exponent = 0;
// end the loop early so it doesn't overflow;
for (; exponent < result.size() - 1; ++exponent, power *= 10)
{
result[exponent] = power;
if (power > std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is too big");
}
result[exponent] = power;
if (power < std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is not big enough for the uint64_t type");
return result;
}
} // namespace detail
constexpr std::array<std::uint64_t, detail::kInt64Digits> kPowerOfTen = detail::buildPowersOfTen();
static_assert(kPowerOfTen[0] == 1);
static_assert(kPowerOfTen[1] == 10);
static_assert(kPowerOfTen[10] == 10'000'000'000);
static_assert(
isPowerOfTen(kPowerOfTen.back()) && *logTen(kPowerOfTen.back()) == detail::kInt64Digits - 1);
/** 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.
* The MantissaScale enum indicates properties of the range: size, and some behavioral
* options. This intentionally restricts the number of unique MantissaRanges that can
* be instantiated: one for each scale.
*
* The "small" scale is based on the behavior of STAmount for IOUs. It has a min
* 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
* uses before Lending Protocol was implemented, mostly related to AMM.
*
@@ -59,46 +108,100 @@ isPowerOfTen(T value)
* STNumber field type, and for internal calculations. That necessitated the
* "large" scale.
*
* The "large" scale is intended to represent all values that can be represented
* The "Large" scales are 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.
* value of 10^19-1. "LargeLegacy" is like "Large", but preserves
* a rounding error when a computation results in a mantissa of
* Number::kMaxRep that needs to be rounded up, but rounds down
* instead. It will maintain consistent behavior until the fixCleanup3_2_0
* amendment is enabled.
*
* 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
* should be left in place, but the "Small" scale option should be removed. This
* will allow for future expansion beyond 64-bits if it is ever needed.
*/
struct MantissaRange
struct MantissaRange final
{
using rep = std::uint64_t;
enum class MantissaScale { Small, Large };
explicit constexpr MantissaRange(MantissaScale scale)
: min(getMin(scale)), log(logTen(min).value_or(-1)), scale(scale)
enum class MantissaScale {
Small,
// LargeLegacy can be removed when fixCleanup3_2_0 is retired
LargeLegacy,
Large,
};
// This entire enum can be removed when fixCleanup3_2_0 is retired
enum class CuspRoundingFix : bool {
Disabled = false,
Enabled = true,
};
explicit constexpr MantissaRange(MantissaScale sc) : scale(sc)
{
}
rep min;
rep max{(min * 10) - 1};
int log;
MantissaScale scale;
MantissaScale const scale;
int const log{getExponent(scale)};
rep const min{getMin(scale, log)};
rep const max{(min * 10) - 1};
CuspRoundingFix const cuspRoundingFixEnabled{isCuspFixEnabled(scale)};
static MantissaRange const&
getMantissaRange(MantissaScale scale);
static std::set<MantissaScale> const&
getAllScales();
private:
static constexpr rep
getMin(MantissaScale scale)
static constexpr int
getExponent(MantissaScale scale)
{
switch (scale)
{
case MantissaScale::Small:
return 1'000'000'000'000'000ULL;
return 15;
case MantissaScale::LargeLegacy:
case MantissaScale::Large:
return 1'000'000'000'000'000'000ULL;
return 18;
// LCOV_EXCL_START
default:
// Since this can never be called outside a non-constexpr
// context, this throw assures that the build fails if an
// If called in a constexpr context, this throw assures that the build fails if an
// invalid scale is used.
throw std::runtime_error("Unknown mantissa scale");
// LCOV_EXCL_STOP
}
}
// Keep this function for future use with different ways to compute
// the ranges.
static constexpr rep
getMin(MantissaScale scale, int exponent)
{
if (exponent < 0 || exponent >= kPowerOfTen.size())
throw std::runtime_error("Invalid exponent"); // LCOV_EXCL_LINE
return kPowerOfTen[exponent];
}
static constexpr CuspRoundingFix
isCuspFixEnabled(MantissaScale scale)
{
switch (scale)
{
case MantissaScale::Small:
case MantissaScale::LargeLegacy:
return CuspRoundingFix::Disabled;
case MantissaScale::Large:
return CuspRoundingFix::Enabled;
default:
// If called in a constexpr context, this throw assures that the build fails if an
// invalid scale is used.
throw std::runtime_error("Unknown mantissa scale"); // LCOV_EXCL_LINE
}
}
static std::unordered_map<MantissaScale, MantissaRange> const&
getRanges();
};
// Like std::integral, but only 64-bit integral types.
@@ -203,7 +306,7 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
* amendments are enabled to determine which result to expect.
*
*/
class Number
class Number final
{
using rep = std::int64_t;
using internalrep = MantissaRange::rep;
@@ -309,33 +412,40 @@ public:
}
friend constexpr bool
operator<(Number const& x, Number const& y) noexcept
operator<(Number const& l, Number const& r) noexcept
{
bool const lneg = l.negative_;
bool const rneg = r.negative_;
// 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_;
if (lneg != rneg)
return lneg;
// Both have same sign and the left is zero: the right must be
// greater than 0.
if (x.mantissa_ == 0)
return y.mantissa_ > 0;
// Both have same sign and the left is zero: both must be non-negative.
// If the right is greater than 0, then it is larger, so the comparison is true.
if (l.mantissa_ == 0)
return r.mantissa_ > 0;
// Both have same sign, the right is zero and the left is non-zero.
if (y.mantissa_ == 0)
// Both have same sign, the right is zero and the left is non-zero, so the left must be
// positive, and thus is larger, so the comparison is false.
if (r.mantissa_ == 0)
return false;
// Both have the same sign, compare by exponents:
if (x.exponent_ > y.exponent_)
if (l.exponent_ > r.exponent_)
return lneg;
if (x.exponent_ < y.exponent_)
if (l.exponent_ < r.exponent_)
return !lneg;
// If equal exponents, compare mantissas
return x.mantissa_ < y.mantissa_;
// If equal signs and exponents, compare mantissas.
if (lneg)
{
// If negative, the operator is reversed.
return l.mantissa_ > r.mantissa_;
}
return l.mantissa_ < r.mantissa_;
}
/** Return the sign of the amount */
@@ -424,49 +534,28 @@ public:
return kRange.get().log;
}
/// oneSmall is needed because the ranges are private
static constexpr Number
oneSmall();
/// oneLarge is needed because the ranges are private
static constexpr Number
oneLarge();
// And one is needed because it needs to choose between oneSmall and
// oneLarge based on the current range
static Number
one();
template <Integral64 T>
template <
auto MinMantissa,
auto MaxMantissa,
Integral64 T = std::decay_t<decltype(MinMantissa)>>
[[nodiscard]]
std::pair<T, int>
normalizeToRange(T minMantissa, T maxMantissa) const;
normalizeToRange() const;
private:
static thread_local RoundingMode mode;
// The available ranges for mantissa
static constexpr MantissaRange kSmallRange{MantissaRange::MantissaScale::Small};
static_assert(isPowerOfTen(kSmallRange.min));
static_assert(kSmallRange.min == 1'000'000'000'000'000LL);
static_assert(kSmallRange.max == 9'999'999'999'999'999LL);
static_assert(kSmallRange.log == 15);
static_assert(kSmallRange.min < kMaxRep);
static_assert(kSmallRange.max < kMaxRep);
static constexpr MantissaRange kLargeRange{MantissaRange::MantissaScale::Large};
static_assert(isPowerOfTen(kLargeRange.min));
static_assert(kLargeRange.min == 1'000'000'000'000'000'000ULL);
static_assert(kLargeRange.max == internalrep(9'999'999'999'999'999'999ULL));
static_assert(kLargeRange.log == 18);
static_assert(kLargeRange.min < kMaxRep);
static_assert(kLargeRange.max > kMaxRep);
// 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> kRange;
void
normalize();
normalize(MantissaRange const& range);
/** Normalize Number components to an arbitrary range.
*
@@ -481,7 +570,8 @@ private:
T& mantissa,
int& exponent,
internalrep const& minMantissa,
internalrep const& maxMantissa);
internalrep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled);
template <class T>
friend void
@@ -490,7 +580,9 @@ private:
T& mantissa,
int& exponent,
MantissaRange::rep const& minMantissa,
MantissaRange::rep const& maxMantissa);
MantissaRange::rep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled,
bool dropped);
[[nodiscard]] bool
isnormal() const noexcept;
@@ -526,7 +618,7 @@ static constexpr Number kNumZero{};
inline Number::Number(bool negative, internalrep mantissa, int exponent, Normalized)
: Number(negative, mantissa, exponent, Unchecked{})
{
normalize();
normalize(kRange);
}
inline Number::Number(internalrep mantissa, int exponent, Normalized)
@@ -696,10 +788,21 @@ Number::isnormal() const noexcept
kMinExponent <= exponent_ && exponent_ <= kMaxExponent);
}
template <Integral64 T>
template <auto MinMantissa, auto MaxMantissa, Integral64 T>
std::pair<T, int>
Number::normalizeToRange(T minMantissa, T maxMantissa) const
Number::normalizeToRange() const
{
static_assert(std::is_same_v<T, std::uint64_t> || std::is_same_v<T, std::int64_t>);
static_assert(std::is_same_v<T, std::decay_t<decltype(MinMantissa)>>);
static_assert(std::is_same_v<T, std::decay_t<decltype(MaxMantissa)>>);
auto constexpr kMIN = static_cast<T>(MinMantissa);
auto constexpr kMAX = static_cast<T>(MaxMantissa);
static_assert(kMIN > 0);
static_assert(kMIN % 10 == 0);
static_assert(isPowerOfTen(kMIN));
static_assert(kMAX % 10 == 9);
static_assert((kMAX + 1) / 10 == kMIN);
bool negative = negative_;
internalrep mantissa = mantissa_;
int exponent = exponent_;
@@ -711,7 +814,10 @@ Number::normalizeToRange(T minMantissa, T maxMantissa) const
"xrpl::Number::normalizeToRange",
"Number is non-negative for unsigned range.");
}
Number::normalize(negative, mantissa, exponent, minMantissa, maxMantissa);
// Don't need to worry about the cuspRounding fix because rounding up will never take the
// mantissa over maxMantissa with a ones digit value other than 0. 0 can safely be truncated.
Number::normalize(
negative, mantissa, exponent, kMIN, kMAX, MantissaRange::CuspRoundingFix::Disabled);
auto const sign = negative ? -1 : 1;
return std::make_pair(static_cast<T>(sign * mantissa), exponent);
@@ -763,6 +869,8 @@ to_string(MantissaRange::MantissaScale const& scale)
{
case MantissaRange::MantissaScale::Small:
return "small";
case MantissaRange::MantissaScale::LargeLegacy:
return "largeLegacy";
case MantissaRange::MantissaScale::Large:
return "large";
default:

View File

@@ -6,6 +6,7 @@
#include <boost/icl/closed_interval.hpp>
#include <boost/icl/interval_set.hpp>
#include <functional>
#include <optional>
#include <string>
#include <vector>

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/net/IPEndpoint.h>
#include <functional>
#include <string>
#include <vector>
namespace xrpl {

View File

@@ -5,6 +5,8 @@
#include <boost/asio/io_context.hpp>
#include <memory>
namespace xrpl {
class ResolverAsio : public Resolver

View File

@@ -3,7 +3,9 @@
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/partitioned_unordered_map.h>
#include <cstddef>
#include <ostream>
#include <string>
namespace xrpl {

View File

@@ -1,5 +1,7 @@
#pragma once
#include <concepts>
#include <cstddef>
#include <memory>
#include <variant>

View File

@@ -15,6 +15,7 @@
#include <cstdint>
#include <cstring>
#include <mutex>
#include <stdexcept>
#include <vector>
#if BOOST_OS_LINUX

View File

@@ -211,15 +211,17 @@ operator<<(Stream& s, Slice const& v)
}
template <class T, std::size_t N>
std::enable_if_t<std::is_same_v<T, char> || std::is_same_v<T, unsigned char>, Slice>
Slice
makeSlice(std::array<T, N> const& a)
requires(std::is_same_v<T, char> || std::is_same_v<T, unsigned char>)
{
return Slice(a.data(), a.size());
}
template <class T, class Alloc>
std::enable_if_t<std::is_same_v<T, char> || std::is_same_v<T, unsigned char>, Slice>
Slice
makeSlice(std::vector<T, Alloc> const& v)
requires(std::is_same_v<T, char> || std::is_same_v<T, unsigned char>)
{
return Slice(v.data(), v.size());
}

View File

@@ -1,17 +1,19 @@
#pragma once
#include <xrpl/basics/Blob.h>
#include <xrpl/basics/strHex.h>
#include <boost/format.hpp>
#include <boost/utility/string_view.hpp>
#include <array>
#include <concepts>
#include <cstddef>
#include <cstdint>
#include <optional>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
namespace xrpl {
@@ -95,13 +97,7 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end)
}
inline std::optional<Blob>
strUnHex(std::string const& strSrc)
{
return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend());
}
inline std::optional<Blob>
strViewUnHex(std::string_view strSrc)
strUnHex(std::string_view strSrc)
{
return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend());
}

View File

@@ -1,22 +1,46 @@
#pragma once
#include <xrpl/basics/IntrusivePointer.h>
#include <xrpl/basics/Log.h>
#include <xrpl/basics/SharedWeakCachePointer.ipp>
#include <xrpl/basics/SharedWeakCachePointer.h>
#include <xrpl/basics/SharedWeakCachePointer.ipp> // IWYU pragma: keep
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/hardened_hash.h>
#include <xrpl/beast/clock/abstract_clock.h>
#include <xrpl/beast/insight/Insight.h>
#include <xrpl/beast/insight/Collector.h>
#include <xrpl/beast/insight/Gauge.h>
#include <xrpl/beast/insight/Hook.h>
#include <xrpl/beast/insight/NullCollector.h>
#include <xrpl/beast/utility/Journal.h>
#include <atomic>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex>
#include <string>
#include <thread>
#include <type_traits>
#include <vector>
namespace xrpl {
namespace detail {
// Replace-policy tags selecting how TaggedCache::canonicalizeImpl resolves a
// collision when the key already exists (defined in TaggedCache.ipp):
// - ReplaceCached: always replace the cached value with `data`. `data` is
// never written back and may be const.
// - ReplaceClient: keep the cached value and write it back into `data` (the
// client's pointer), which must therefore be writable.
// - ReplaceDynamically: call the supplied callback to decide per call; `data`
// is written back when the cached value is kept, so it must be writable.
struct ReplaceCached;
struct ReplaceClient;
struct ReplaceDynamically;
} // namespace detail
/** Map/cache combination.
This class implements a cache and a map. The cache keeps objects alive
in the map. The map allows multiple code paths that reference objects
@@ -96,6 +120,32 @@ public:
bool
del(key_type const& key, bool valid);
private:
// Selects the `data` parameter type of canonicalizeImpl from the replace
// policy: const for detail::ReplaceCached (never written back), otherwise
// writable.
template <typename Policy>
using CanonicalizeClientPointerType = std::conditional_t<
std::is_same_v<detail::ReplaceCached, Policy>,
SharedPointerType const&,
SharedPointerType&>;
/** Shared implementation of the canonicalize family.
`policy` selects how a collision is resolved when `key` already exists:
detail::ReplaceCached, detail::ReplaceClient or
detail::ReplaceDynamically. For ReplaceDynamically `replaceCallback` is
invoked with the existing strong pointer and returns whether to replace
the cached value with `data`; for the tag policies it is unused.
*/
template <class Policy, class Callback = std::nullptr_t>
bool
canonicalizeImpl(
key_type const& key,
CanonicalizeClientPointerType<Policy> data,
Policy policy,
Callback&& replaceCallback = nullptr);
public:
/** Replace aliased objects with originals.
@@ -104,19 +154,52 @@ public:
This routine eliminates the duplicate and performs a replacement
on the callers shared pointer if needed.
`replaceCallback` is a callable taking the existing strong pointer and
returning whether to replace the cached value with `data` (true) or to
keep the cached value and write it back into `data` (false). Because the
write-back case mutates `data`, `data` must be writable.
@param key The key corresponding to the object
@param data A shared pointer to the data corresponding to the object.
@param replace Function that decides if cache should be replaced
@param replaceCallback A callable (existing strong pointer -> bool).
@return `true` If the key already existed.
*/
template <class R>
@return `true` if an existing live entry was found and used; `false` if a new entry was
inserted or an expired tracked entry was re-cached.
**/
template <class Callback>
bool
canonicalize(key_type const& key, SharedPointerType& data, R&& replaceCallback);
canonicalize(key_type const& key, SharedPointerType& data, Callback&& replaceCallback);
/** Insert/update the canonical entry for `key`, always replacing the
cached value with `data`.
If an entry already exists for `key`, the cached value is unconditionally
replaced with `data`; otherwise `data` is inserted. `data` is never
written back, so it may be const.
@param key The key corresponding to the object.
@param data A shared pointer to the data corresponding to the object.
@return `true` if an existing live entry was found and used; `false` if a new entry was
inserted or an expired tracked entry was re-cached.
**/
bool
canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data);
/** Insert the canonical entry for `key`, keeping any existing cached value.
If an entry already exists for `key`, the cached value is kept and
written back into `data` so the caller ends up with the canonical
object; otherwise `data` is inserted. Because `data` may be overwritten
it must be writable.
@param key The key corresponding to the object.
@param data A shared pointer to the data corresponding to the object;
updated to the canonical value when one already exists.
@return `true` if an existing live entry was found and used; `false` if a new entry was
inserted or an expired tracked entry was re-cached.
**/
bool
canonicalizeReplaceClient(key_type const& key, SharedPointerType& data);
@@ -129,11 +212,13 @@ 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) -> ReturnType
requires(!IsKeyCache);
template <class ReturnType = bool>
auto
insert(key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>;
insert(key_type const& key) -> ReturnType
requires IsKeyCache;
// VFALCO NOTE It looks like this returns a copy of the data in
// the output parameter 'data'. This could be expensive.
@@ -157,7 +242,7 @@ public:
/** Fetch an item from the cache.
If the digest was not found, Handler
will be called with this signature:
std::shared_ptr<SLE const>(void)
SLE::const_pointer(void)
*/
template <class Handler>
SharedPointerType
@@ -181,14 +266,14 @@ private:
beast::insight::Collector::ptr const& collector)
: hook(collector->makeHook(handler))
, size(collector->makeGauge(prefix, "size"))
, hit_rate(collector->makeGauge(prefix, "hit_rate"))
, hitRate(collector->makeGauge(prefix, "hit_rate"))
{
}
beast::insight::Hook hook;
beast::insight::Gauge size;
beast::insight::Gauge hit_rate;
beast::insight::Gauge hitRate;
std::size_t hits{0};
std::size_t misses{0};
@@ -197,16 +282,16 @@ private:
class KeyOnlyEntry
{
public:
clock_type::time_point last_access;
clock_type::time_point lastAccess;
explicit KeyOnlyEntry(clock_type::time_point const& lastAccess) : last_access(lastAccess)
explicit KeyOnlyEntry(clock_type::time_point const& lastAccess) : lastAccess(lastAccess)
{
}
void
touch(clock_type::time_point const& now)
{
last_access = now;
lastAccess = now;
}
};
@@ -214,10 +299,10 @@ private:
{
public:
shared_weak_combo_pointer_type ptr;
clock_type::time_point last_access;
clock_type::time_point lastAccess;
ValueEntry(clock_type::time_point const& lastAccess, shared_pointer_type const& ptr)
: ptr(ptr), last_access(lastAccess)
: ptr(ptr), lastAccess(lastAccess)
{
}
@@ -246,7 +331,7 @@ private:
void
touch(clock_type::time_point const& now)
{
last_access = now;
lastAccess = now;
}
};
@@ -262,7 +347,7 @@ private:
sweepHelper(
clock_type::time_point const& whenExpire,
[[maybe_unused]] clock_type::time_point const& now,
typename KeyValueCacheType::map_type& partition,
KeyValueCacheType::map_type& partition,
SweptPointersVector& stuffToSweep,
std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&);
@@ -271,7 +356,7 @@ private:
sweepHelper(
clock_type::time_point const& whenExpire,
clock_type::time_point const& now,
typename KeyOnlyCacheType::map_type& partition,
KeyOnlyCacheType::map_type& partition,
SweptPointersVector&,
std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&);
@@ -286,13 +371,13 @@ private:
std::string name_;
// Desired number of cache entries (0 = ignore)
int const target_size_;
int const targetSize_;
// Desired maximum cache age
clock_type::duration const target_age_;
clock_type::duration const targetAge_;
// Number of items cached
int cache_count_{0};
int cacheCount_{0};
cache_type cache_; // Hold strong reference to recent objects
std::uint64_t hits_{0};
std::uint64_t misses_{0};

View File

@@ -1,10 +1,35 @@
#pragma once
#include <xrpl/basics/IntrusivePointer.ipp>
#include <xrpl/basics/Log.h> // IWYU pragma: keep
#include <xrpl/basics/TaggedCache.h>
namespace xrpl {
namespace detail {
// Replace-policy tags selecting how TaggedCache::canonicalizeImpl resolves a
// collision when the key already exists:
// - ReplaceCached: always replace the cached value with `data`. `data` is
// never written back and may be const.
// - ReplaceClient: keep the cached value and write it back into `data` (the
// client's pointer), which must therefore be writable.
// - ReplaceDynamically: call the supplied callback to decide per call; `data`
// is written back when the cached value is kept, so it must be writable.
struct ReplaceCached
{
};
struct ReplaceClient
{
};
struct ReplaceDynamically
{
};
} // namespace detail
template <
class Key,
class T,
@@ -32,10 +57,13 @@ inline TaggedCache<
beast::insight::Collector::ptr const& collector)
: journal_(journal)
, clock_(clock)
, stats_(name, std::bind(&TaggedCache::collectMetrics, this), collector)
, stats_(
name,
[this] { collectMetrics(); },
collector)
, name_(name)
, target_size_(size)
, target_age_(expiration)
, targetSize_(size)
, targetAge_(expiration)
{
}
@@ -86,7 +114,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
getCacheSize() const
{
std::scoped_lock const lock(mutex_);
return cache_count_;
return cacheCount_;
}
template <
@@ -139,7 +167,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
{
std::scoped_lock const lock(mutex_);
cache_.clear();
cache_count_ = 0;
cacheCount_ = 0;
}
template <
@@ -157,7 +185,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
{
std::scoped_lock const lock(mutex_);
cache_.clear();
cache_count_ = 0;
cacheCount_ = 0;
hits_ = 0;
misses_ = 0;
}
@@ -213,21 +241,21 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
{
std::scoped_lock const lock(mutex_);
if (target_size_ == 0 || (static_cast<int>(cache_.size()) <= target_size_))
if (targetSize_ == 0 || (static_cast<int>(cache_.size()) <= targetSize_))
{
whenExpire = now - target_age_;
whenExpire = now - targetAge_;
}
else
{
whenExpire = now - (target_age_ * target_size_ / cache_.size());
whenExpire = now - (targetAge_ * targetSize_ / cache_.size());
clock_type::duration const minimumAge(std::chrono::seconds(1));
if (whenExpire > (now - minimumAge))
whenExpire = now - minimumAge;
JLOG(journal_.trace())
<< name_ << " is growing fast " << cache_.size() << " of " << target_size_
<< " aging at " << (now - whenExpire).count() << " of " << target_age_.count();
<< name_ << " is growing fast " << cache_.size() << " of " << targetSize_
<< " aging at " << (now - whenExpire).count() << " of " << targetAge_.count();
}
std::vector<std::thread> workers;
@@ -242,7 +270,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
for (std::thread& worker : workers)
worker.join();
cache_count_ -= allRemovals;
cacheCount_ -= allRemovals;
}
// At this point allStuffToSweep will go out of scope outside the lock
// and decrement the reference count on each strong pointer.
@@ -280,7 +308,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
if (entry.isCached())
{
--cache_count_;
--cacheCount_;
entry.ptr.convertToWeak();
ret = true;
}
@@ -300,13 +328,29 @@ template <
class Hash,
class KeyEqual,
class Mutex>
template <class R>
template <class Policy, class Callback>
inline bool
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
canonicalize(key_type const& key, SharedPointerType& data, R&& replaceCallback)
canonicalizeImpl(
key_type const& key,
CanonicalizeClientPointerType<Policy> data,
[[maybe_unused]] Policy policy,
[[maybe_unused]] Callback&& replaceCallback)
{
// Return canonical value, store if needed, refresh in cache
// Return values: true=we had the data already
// `Policy` is one of:
// - detail::ReplaceCached: always replace the cached value with `data`;
// `data` is never written back and may be const.
// - detail::ReplaceClient: keep the cached value and write it back into
// `data` (the client's pointer), which must therefore be writable.
// - detail::ReplaceDynamically: call `replaceCallback` to decide at run
// time; `data` must be writable.
// For the latter two the write-back below requires a mutable `data`, so
// passing a const argument is a compile error.
constexpr bool replaceCached = std::is_same_v<Policy, detail::ReplaceCached>;
std::scoped_lock const lock(mutex_);
auto cit = cache_.find(key);
@@ -317,20 +361,21 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
std::piecewise_construct,
std::forward_as_tuple(key),
std::forward_as_tuple(clock_.now(), data));
++cache_count_;
++cacheCount_;
return false;
}
Entry& entry = cit->second;
entry.touch(clock_.now());
auto shouldReplace = [&] {
if constexpr (std::is_invocable_r_v<bool, R>)
auto shouldReplaceCached = [&] {
if constexpr (replaceCached)
{
// The reason for this extra complexity is for intrusive
// strong/weak combo getting a strong is relatively expensive
// and not needed for many cases.
return replaceCallback();
return true;
}
else if constexpr (std::is_same_v<Policy, detail::ReplaceClient>)
{
return false;
}
else
{
@@ -340,11 +385,11 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
if (entry.isCached())
{
if (shouldReplace())
if (shouldReplaceCached())
{
entry.ptr = data;
}
else
else if constexpr (!replaceCached)
{
data = entry.ptr.getStrong();
}
@@ -356,26 +401,44 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
if (cachedData)
{
if (shouldReplace())
if (shouldReplaceCached())
{
entry.ptr = data;
}
else
else if constexpr (!replaceCached)
{
entry.ptr.convertToStrong();
data = cachedData;
}
++cache_count_;
++cacheCount_;
return true;
}
entry.ptr = data;
++cache_count_;
++cacheCount_;
return false;
}
template <
class Key,
class T,
bool IsKeyCache,
class SharedWeakUnionPointer,
class SharedPointerType,
class Hash,
class KeyEqual,
class Mutex>
template <class Callback>
inline bool
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
canonicalize(key_type const& key, SharedPointerType& data, Callback&& replaceCallback)
{
return canonicalizeImpl(
key, data, detail::ReplaceDynamically{}, std::forward<Callback>(replaceCallback));
}
template <
class Key,
class T,
@@ -389,7 +452,7 @@ inline bool
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data)
{
return canonicalize(key, const_cast<SharedPointerType&>(data), []() { return true; });
return canonicalizeImpl(key, data, detail::ReplaceCached{});
}
template <
@@ -405,7 +468,7 @@ inline bool
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
canonicalizeReplaceClient(key_type const& key, SharedPointerType& data)
{
return canonicalize(key, data, []() { return false; });
return canonicalizeImpl(key, data, detail::ReplaceClient{});
}
template <
@@ -440,7 +503,8 @@ template <
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>
insert(key_type const& key, T const& value) -> ReturnType
requires(!IsKeyCache)
{
static_assert(
std::is_same_v<std::shared_ptr<T>, SharedPointerType> ||
@@ -470,14 +534,15 @@ template <
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>
insert(key_type const& key) -> ReturnType
requires IsKeyCache
{
std::scoped_lock const lock(mutex_);
clock_type::time_point const now(clock_.now());
auto [it, inserted] = cache_.emplace(
std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(now));
if (!inserted)
it->second.last_access = now;
it->second.lastAccess = now;
return inserted;
}
@@ -626,7 +691,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
if (entry.isCached())
{
// independent of cache size, so not counted as a hit
++cache_count_;
++cacheCount_;
entry.touch(clock_.now());
return entry.ptr.getStrong();
}
@@ -658,7 +723,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
if (total != 0)
hitRate = (hits_ * 100) / total;
}
stats_.hit_rate.set(hitRate);
stats_.hitRate.set(hitRate);
}
}
@@ -676,7 +741,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
sweepHelper(
clock_type::time_point const& whenExpire,
[[maybe_unused]] clock_type::time_point const& now,
typename KeyValueCacheType::map_type& partition,
KeyValueCacheType::map_type& partition,
SweptPointersVector& stuffToSweep,
std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&)
@@ -706,7 +771,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
++cit;
}
}
else if (cit->second.last_access <= whenExpire)
else if (cit->second.lastAccess <= whenExpire)
{
// strong, expired
++cacheRemovals;
@@ -756,7 +821,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
sweepHelper(
clock_type::time_point const& whenExpire,
clock_type::time_point const& now,
typename KeyOnlyCacheType::map_type& partition,
KeyOnlyCacheType::map_type& partition,
SweptPointersVector&,
std::atomic<int>& allRemovals,
std::scoped_lock<std::recursive_mutex> const&)
@@ -773,12 +838,12 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
auto cit = partition.begin();
while (cit != partition.end())
{
if (cit->second.last_access > now)
if (cit->second.lastAccess > now)
{
cit->second.last_access = now;
cit->second.lastAccess = now;
++cit;
}
else if (cit->second.last_access <= whenExpire)
else if (cit->second.lastAccess <= whenExpire)
{
cit = partition.erase(cit);
}

View File

@@ -12,8 +12,9 @@ namespace xrpl {
*/
template <class T>
std::enable_if_t<std::is_arithmetic_v<T>, std::string>
std::string
to_string(T t) // NOLINT(readability-identifier-naming)
requires(std::is_arithmetic_v<T>)
{
return std::to_string(t);
}

View File

@@ -2,12 +2,14 @@
#include <xrpl/basics/hardened_hash.h>
#include <xrpl/basics/partitioned_unordered_map.h>
#include <xrpl/beast/hash/hash_append.h>
#include <xrpl/beast/hash/uhash.h>
#include <xrpl/beast/hash/xxhasher.h>
#include <functional>
#include <memory>
#include <unordered_map>
#include <unordered_set>
#include <utility>
/**
* Use hash_* containers for keys that do not need a cryptographically secure

View File

@@ -34,8 +34,10 @@
#pragma once
#include <cstddef>
#include <cstdint>
#include <string>
#include <string_view>
namespace xrpl {
@@ -43,7 +45,7 @@ std::string
base64Encode(std::uint8_t const* data, std::size_t len);
inline std::string
base64Encode(std::string const& s)
base64Encode(std::string_view s)
{
return base64Encode(reinterpret_cast<std::uint8_t const*>(s.data()), s.size());
}

View File

@@ -5,12 +5,12 @@
#pragma once
#include <xrpl/basics/Expected.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/basics/contract.h>
#include <xrpl/basics/hardened_hash.h>
#include <xrpl/basics/partitioned_unordered_map.h>
#include <xrpl/basics/strHex.h>
#include <xrpl/beast/hash/hash_append.h>
#include <xrpl/beast/utility/Zero.h>
#include <xrpl/beast/utility/instrumentation.h>
@@ -19,7 +19,17 @@
#include <algorithm>
#include <array>
#include <compare>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <expected>
#include <iterator>
#include <optional>
#include <ostream>
#include <stdexcept>
#include <string>
#include <string_view>
#include <type_traits>
namespace xrpl {
@@ -87,7 +97,7 @@ public:
//
static constexpr std::size_t kBytes = Bits / 8;
static_assert(sizeof(data_) == kBytes, "");
static_assert(sizeof(data_) == kBytes);
using size_type = std::size_t;
using difference_type = std::ptrdiff_t;
@@ -177,7 +187,7 @@ private:
BadChar,
};
constexpr Expected<decltype(data_), ParseResult>
constexpr std::expected<decltype(data_), ParseResult>
parseFromStringView(std::string_view sv) noexcept
{
// Local lambda that converts a single hex char to four bits and
@@ -216,7 +226,7 @@ private:
}
if (sv.size() != size() * 2)
return Unexpected(ParseResult::BadLength);
return std::unexpected(ParseResult::BadLength);
std::size_t i = 0u;
auto in = sv.begin();
@@ -227,7 +237,7 @@ private:
{
if (auto const result = hexCharToUInt(*in++, shift, accum);
result != ParseResult::Okay)
return Unexpected(result);
return std::unexpected(result);
}
ret[i++] = accum;
}
@@ -270,12 +280,11 @@ public:
{
}
template <
class Container,
class = std::enable_if_t<
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>>>
template <class Container>
explicit BaseUInt(Container const& c)
requires(
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>)
{
// Use AlwaysFalseT so the static_assert condition is dependent
// and only triggers when this constructor template is instantiated.
@@ -285,13 +294,12 @@ public:
"Use base_uint::fromRaw instead.");
}
template <
class Container,
class = std::enable_if_t<
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>>>
template <class Container>
static BaseUInt
fromRaw(Container const& c)
requires(
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>)
{
BaseUInt result;
XRPL_ASSERT(
@@ -302,11 +310,11 @@ public:
}
template <class Container>
std::enable_if_t<
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>,
BaseUInt&>
BaseUInt&
operator=(Container const& c)
requires(
detail::IsContiguousContainer<Container>::value &&
std::is_trivially_copyable_v<typename Container::value_type>)
{
XRPL_ASSERT(
c.size() * sizeof(typename Container::value_type) == size(),

View File

@@ -10,6 +10,7 @@
#include <cstdint>
#include <ratio>
#include <string>
#include <type_traits>
namespace xrpl {

View File

@@ -1,54 +0,0 @@
#pragma once
#include <functional>
namespace xrpl {
#ifdef _MSC_VER
/*
* MSVC 2019 version 16.9.0 added [[nodiscard]] to the std comparison
* operator() functions. boost::bimap checks that the comparator is a
* BinaryFunction, in part by calling the function and ignoring the value.
* These two things don't play well together. These wrapper classes simply
* strip [[nodiscard]] from operator() for use in boost::bimap.
*
* See also:
* https://www.boost.org/doc/libs/1_75_0/libs/bimap/doc/html/boost_bimap/the_tutorial/controlling_collection_types.html
*/
template <class T = void>
struct less
{
using result_type = bool;
constexpr bool
operator()(T const& left, T const& right) const
{
return std::less<T>()(left, right);
}
};
template <class T = void>
struct equal_to
{
using result_type = bool;
constexpr bool
operator()(T const& left, T const& right) const
{
return std::equal_to<T>()(left, right);
}
};
#else
template <class T = void>
using less = std::less<T>;
template <class T = void>
using equal_to = std::equal_to<T>;
#endif
} // namespace xrpl

View File

@@ -1,6 +1,5 @@
#pragma once
#include <xrpl/beast/hash/hash_append.h>
#include <xrpl/beast/hash/xxhasher.h>
#include <cstdint>
@@ -75,7 +74,7 @@ private:
detail::seed_pair seeds_{detail::makeSeedPair<>()};
public:
using result_type = typename HashAlgorithm::result_type;
using result_type = HashAlgorithm::result_type;
HardenedHash() = default;

View File

@@ -1,12 +1,15 @@
#pragma once
#include <cstddef>
#include <string>
#include <string_view>
#include <utility>
namespace xrpl {
template <class Stream, class Iter>
Stream&
join(Stream& s, Iter iter, Iter end, std::string const& delimiter)
join(Stream& s, Iter iter, Iter end, std::string_view delimiter)
{
if (iter == end)
return s;

View File

@@ -2,6 +2,7 @@
#include <boost/asio/ssl/context.hpp>
#include <memory>
#include <string>
namespace xrpl {

View File

@@ -3,7 +3,10 @@
#include <xrpl/beast/hash/uhash.h>
#include <xrpl/beast/utility/instrumentation.h>
#include <cstddef>
#include <functional>
#include <iterator>
#include <memory>
#include <optional>
#include <string>
#include <thread>
@@ -57,8 +60,8 @@ public:
{
using iterator_category = std::forward_iterator_tag;
partition_map_type* map{nullptr};
typename partition_map_type::iterator ait{};
typename map_type::iterator mit;
partition_map_type::iterator ait{};
map_type::iterator mit;
Iterator() = default;
@@ -126,8 +129,8 @@ public:
using iterator_category = std::forward_iterator_tag;
partition_map_type* map{nullptr};
typename partition_map_type::iterator ait{};
typename map_type::iterator mit;
partition_map_type::iterator ait{};
map_type::iterator mit;
ConstIterator() = default;
@@ -135,11 +138,8 @@ public:
{
}
ConstIterator(Iterator const& orig)
ConstIterator(Iterator const& orig) : map(orig.map), ait(orig.ait), mit(orig.mit)
{
map = orig.map;
ait = orig.ait;
mit = orig.mit;
}
const_reference
@@ -228,11 +228,11 @@ private:
public:
PartitionedUnorderedMap(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 != 0u) ? *partitions : std::thread::hardware_concurrency();
: partitions_(
partitions && (*partitions != 0u) ? *partitions : std::thread::hardware_concurrency())
{
map_.resize(partitions_);
XRPL_ASSERT(
partitions_,

View File

@@ -3,7 +3,6 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/beast/xor_shift_engine.h>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <mutex>
@@ -29,6 +28,7 @@ static_assert(
namespace detail {
// Determines if a type can be called like an Engine
// NOLINTNEXTLINE(readability-redundant-typename): typename required by MSVC
template <class Engine, class Result = typename Engine::result_type>
using is_engine = std::is_invocable_r<Result, Engine>;
} // namespace detail
@@ -91,8 +91,9 @@ defaultPrng()
*/
/** @{ */
template <class Engine, class Integral>
std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
Integral
randInt(Engine& engine, Integral min, Integral max)
requires(std::is_integral_v<Integral> && detail::is_engine<Engine>::value)
{
XRPL_ASSERT(max > min, "xrpl::randInt : max over min inputs");
@@ -103,36 +104,41 @@ randInt(Engine& engine, Integral min, Integral max)
}
template <class Integral>
std::enable_if_t<std::is_integral_v<Integral>, Integral>
Integral
randInt(Integral min, Integral max)
requires(std::is_integral_v<Integral>)
{
return randInt(defaultPrng(), min, max);
}
template <class Engine, class Integral>
std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
Integral
randInt(Engine& engine, Integral max)
requires(std::is_integral_v<Integral> && detail::is_engine<Engine>::value)
{
return randInt(engine, Integral(0), max);
}
template <class Integral>
std::enable_if_t<std::is_integral_v<Integral>, Integral>
Integral
randInt(Integral max)
requires(std::is_integral_v<Integral>)
{
return randInt(defaultPrng(), max);
}
template <class Integral, class Engine>
std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
Integral
randInt(Engine& engine)
requires(std::is_integral_v<Integral> && detail::is_engine<Engine>::value)
{
return randInt(engine, std::numeric_limits<Integral>::max());
}
template <class Integral = int>
std::enable_if_t<std::is_integral_v<Integral>, Integral>
Integral
randInt()
requires(std::is_integral_v<Integral>)
{
return randInt(defaultPrng(), std::numeric_limits<Integral>::max());
}
@@ -141,19 +147,20 @@ randInt()
/** Return a random byte */
/** @{ */
template <class Byte, class Engine>
std::enable_if_t<
(std::is_same_v<Byte, unsigned char> || std::is_same_v<Byte, std::uint8_t>) &&
detail::is_engine<Engine>::value,
Byte>
Byte
randByte(Engine& engine)
requires(
(std::is_same_v<Byte, unsigned char> || std::is_same_v<Byte, std::uint8_t>) &&
detail::is_engine<Engine>::value)
{
return static_cast<Byte>(randInt<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_v<Byte, unsigned char> || std::is_same_v<Byte, std::uint8_t>), Byte>
Byte
randByte()
requires(std::is_same_v<Byte, unsigned char> || std::is_same_v<Byte, std::uint8_t>)
{
return randByte<Byte>(defaultPrng());
}

View File

@@ -1,29 +0,0 @@
#pragma once
#if XRPL_ROCKSDB_AVAILABLE
// #include <rocksdb2/port/port_posix.h>
#include <rocksdb/cache.h>
#include <rocksdb/compaction_filter.h>
#include <rocksdb/comparator.h>
#include <rocksdb/convenience.h>
#include <rocksdb/db.h>
#include <rocksdb/env.h>
#include <rocksdb/filter_policy.h>
#include <rocksdb/flush_block_policy.h>
#include <rocksdb/iterator.h>
#include <rocksdb/memtablerep.h>
#include <rocksdb/merge_operator.h>
#include <rocksdb/options.h>
#include <rocksdb/perf_context.h>
#include <rocksdb/slice.h>
#include <rocksdb/slice_transform.h>
#include <rocksdb/statistics.h>
#include <rocksdb/status.h>
#include <rocksdb/table.h>
#include <rocksdb/table_properties.h>
#include <rocksdb/transaction_log.h>
#include <rocksdb/types.h>
#include <rocksdb/universal_compaction.h>
#include <rocksdb/write_batch.h>
#endif

View File

@@ -1,6 +1,6 @@
#pragma once
#include <xrpl/beast/utility/instrumentation.h>
#include <xrpl/beast/utility/instrumentation.h> // IWYU pragma: keep
#include <type_traits>
@@ -17,8 +17,9 @@ concept SafeToCast = (std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
: sizeof(Dest) >= sizeof(Src));
template <class Dest, class Src>
constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
constexpr Dest
safeCast(Src s) noexcept
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
{
static_assert(
std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned");
@@ -30,15 +31,17 @@ safeCast(Src s) noexcept
}
template <class Dest, class Src>
constexpr std::enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
constexpr Dest
safeCast(Src s) noexcept
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
{
return static_cast<Dest>(safeCast<std::underlying_type_t<Dest>>(s));
}
template <class Dest, class Src>
constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
constexpr Dest
safeCast(Src s) noexcept
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
{
return safeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
}
@@ -48,8 +51,9 @@ safeCast(Src s) noexcept
// underlying types become safe, it can be converted to a safe_cast.
template <class Dest, class Src>
constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
constexpr Dest
unsafeCast(Src s) noexcept
requires(std::is_integral_v<Dest> && std::is_integral_v<Src>)
{
static_assert(
!SafeToCast<Src, Dest>,
@@ -59,15 +63,17 @@ unsafeCast(Src s) noexcept
}
template <class Dest, class Src>
constexpr std::enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
constexpr Dest
unsafeCast(Src s) noexcept
requires(std::is_enum_v<Dest> && std::is_integral_v<Src>)
{
return static_cast<Dest>(unsafeCast<std::underlying_type_t<Dest>>(s));
}
template <class Dest, class Src>
constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_enum_v<Src>, Dest>
constexpr Dest
unsafeCast(Src s) noexcept
requires(std::is_integral_v<Dest> && std::is_enum_v<Src>)
{
return unsafeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
}

View File

@@ -4,7 +4,7 @@
/*
ASAN flags some false positives with sudden jumps in control flow, like
exceptions, or when encountering coroutine stack switches. This macro can be used to disable ASAN
intrumentation for specific functions.
instrumentation for specific functions.
*/
#if defined(__GNUC__) || defined(__clang__)
#define XRPL_NO_SANITIZE_ADDRESS __attribute__((no_sanitize("address", "hwaddress")))

View File

@@ -24,20 +24,20 @@ namespace xrpl {
template <class EF>
class ScopeExit
{
EF exit_function_;
bool execute_on_destruction_{true};
EF exitFunction_;
bool executeOnDestruction_{true};
public:
~ScopeExit()
{
if (execute_on_destruction_)
exit_function_();
if (executeOnDestruction_)
exitFunction_();
}
ScopeExit(ScopeExit&& 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_}
: exitFunction_{std::forward<EF>(rhs.exitFunction_)}
, executeOnDestruction_{rhs.executeOnDestruction_}
{
rhs.release();
}
@@ -46,12 +46,10 @@ public:
operator=(ScopeExit&&) = delete;
template <class EFP>
explicit ScopeExit(
EFP&& f,
std::enable_if_t<
!std::is_same_v<std::remove_cv_t<EFP>, ScopeExit> &&
std::is_constructible_v<EF, EFP>>* = 0) noexcept
: exit_function_{std::forward<EFP>(f)}
explicit ScopeExit(EFP&& f) noexcept
requires(
!std::is_same_v<std::remove_cv_t<EFP>, ScopeExit> && std::is_constructible_v<EF, EFP>)
: exitFunction_{std::forward<EFP>(f)}
{
static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
}
@@ -59,7 +57,7 @@ public:
void
release() noexcept
{
execute_on_destruction_ = false;
executeOnDestruction_ = false;
}
};
@@ -69,22 +67,22 @@ ScopeExit(EF) -> ScopeExit<EF>;
template <class EF>
class ScopeFail
{
EF exit_function_;
bool execute_on_destruction_{true};
int uncaught_on_creation_{std::uncaught_exceptions()};
EF exitFunction_;
bool executeOnDestruction_{true};
int uncaughtOnCreation_{std::uncaught_exceptions()};
public:
~ScopeFail()
{
if (execute_on_destruction_ && std::uncaught_exceptions() > uncaught_on_creation_)
exit_function_();
if (executeOnDestruction_ && std::uncaught_exceptions() > uncaughtOnCreation_)
exitFunction_();
}
ScopeFail(ScopeFail&& 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_}
, uncaught_on_creation_{rhs.uncaught_on_creation_}
: exitFunction_{std::forward<EF>(rhs.exitFunction_)}
, executeOnDestruction_{rhs.executeOnDestruction_}
, uncaughtOnCreation_{rhs.uncaughtOnCreation_}
{
rhs.release();
}
@@ -93,12 +91,10 @@ public:
operator=(ScopeFail&&) = delete;
template <class EFP>
explicit ScopeFail(
EFP&& f,
std::enable_if_t<
!std::is_same_v<std::remove_cv_t<EFP>, ScopeFail> &&
std::is_constructible_v<EF, EFP>>* = 0) noexcept
: exit_function_{std::forward<EFP>(f)}
explicit ScopeFail(EFP&& f) noexcept
requires(
!std::is_same_v<std::remove_cv_t<EFP>, ScopeFail> && std::is_constructible_v<EF, EFP>)
: exitFunction_{std::forward<EFP>(f)}
{
static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
}
@@ -106,7 +102,7 @@ public:
void
release() noexcept
{
execute_on_destruction_ = false;
executeOnDestruction_ = false;
}
};
@@ -116,22 +112,22 @@ ScopeFail(EF) -> ScopeFail<EF>;
template <class EF>
class ScopeSuccess
{
EF exit_function_;
bool execute_on_destruction_{true};
int uncaught_on_creation_{std::uncaught_exceptions()};
EF exitFunction_;
bool executeOnDestruction_{true};
int uncaughtOnCreation_{std::uncaught_exceptions()};
public:
~ScopeSuccess() noexcept(noexcept(exit_function_()))
~ScopeSuccess() noexcept(noexcept(exitFunction_()))
{
if (execute_on_destruction_ && std::uncaught_exceptions() <= uncaught_on_creation_)
exit_function_();
if (executeOnDestruction_ && std::uncaught_exceptions() <= uncaughtOnCreation_)
exitFunction_();
}
ScopeSuccess(ScopeSuccess&& 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_}
, uncaught_on_creation_{rhs.uncaught_on_creation_}
: exitFunction_{std::forward<EF>(rhs.exitFunction_)}
, executeOnDestruction_{rhs.executeOnDestruction_}
, uncaughtOnCreation_{rhs.uncaughtOnCreation_}
{
rhs.release();
}
@@ -140,20 +136,19 @@ public:
operator=(ScopeSuccess&&) = delete;
template <class EFP>
explicit ScopeSuccess(
EFP&& f,
std::enable_if_t<
explicit ScopeSuccess(EFP&& f) noexcept(
std::is_nothrow_constructible_v<EF, EFP> || std::is_nothrow_constructible_v<EF, EFP&>)
requires(
!std::is_same_v<std::remove_cv_t<EFP>, ScopeSuccess> &&
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)}
std::is_constructible_v<EF, EFP>)
: exitFunction_{std::forward<EFP>(f)}
{
}
void
release() noexcept
{
execute_on_destruction_ = false;
executeOnDestruction_ = false;
}
};

View File

@@ -3,6 +3,9 @@
#include <boost/algorithm/hex.hpp>
#include <boost/endian/conversion.hpp>
#include <iterator>
#include <string>
namespace xrpl {
template <class FwdIt>

View File

@@ -7,6 +7,7 @@
#include <boost/operators.hpp>
#include <iostream>
#include <string>
#include <type_traits>
namespace xrpl {
@@ -42,10 +43,10 @@ public:
TaggedInteger() = default;
template <
class OtherInt,
class = std::enable_if_t<std::is_integral_v<OtherInt> && sizeof(OtherInt) <= sizeof(Int)>>
explicit constexpr TaggedInteger(OtherInt value) noexcept : value_(value)
template <class OtherInt>
explicit constexpr TaggedInteger(OtherInt value) noexcept
requires(std::is_integral_v<OtherInt> && sizeof(OtherInt) <= sizeof(Int))
: value_(value)
{
static_assert(sizeof(TaggedInteger) == sizeof(Int), "tagged_integer is adding padding");
}

View File

@@ -8,6 +8,7 @@
#include <chrono>
#include <condition_variable>
#include <cstddef>
#include <mutex>
#include <stdexcept>
@@ -18,8 +19,8 @@ template <class Clock>
class IOLatencyProbe
{
private:
using duration = typename Clock::duration;
using time_point = typename Clock::time_point;
using duration = Clock::duration;
using time_point = Clock::time_point;
std::recursive_mutex mutex_;
std::condition_variable_any cond_;

View File

@@ -34,10 +34,10 @@ template <class Clock>
class AbstractClock
{
public:
using rep = typename Clock::rep;
using period = typename Clock::period;
using duration = typename Clock::duration;
using time_point = typename Clock::time_point;
using rep = Clock::rep;
using period = Clock::period;
using duration = Clock::duration;
using time_point = Clock::time_point;
using clock_type = Clock;
static bool const is_steady = Clock::is_steady; // NOLINT(readability-identifier-naming)

View File

@@ -20,10 +20,10 @@ public:
explicit BasicSecondsClock() = default;
using rep = typename Clock::rep;
using period = typename Clock::period;
using duration = typename Clock::duration;
using time_point = typename Clock::time_point;
using rep = Clock::rep;
using period = Clock::period;
using duration = Clock::duration;
using time_point = Clock::time_point;
static bool const is_steady = // NOLINT(readability-identifier-naming)
Clock::is_steady;

View File

@@ -3,14 +3,15 @@
#include <xrpl/beast/container/aged_container.h>
#include <chrono>
#include <type_traits>
#include <cstddef>
namespace beast {
/** Expire aged container items past the specified age. */
template <class AgedContainer, class Rep, class Period>
std::enable_if_t<IsAgedContainer<AgedContainer>::value, std::size_t>
std::size_t
expire(AgedContainer& c, std::chrono::duration<Rep, Period> const& age)
requires(IsAgedContainer<AgedContainer>::value)
{
std::size_t n(0);
auto const expired(c.clock().now() - age);

View File

@@ -5,6 +5,7 @@
#include <chrono>
#include <functional>
#include <memory>
#include <utility>
namespace beast {

View File

@@ -5,6 +5,7 @@
#include <chrono>
#include <functional>
#include <memory>
#include <utility>
namespace beast {

View File

@@ -5,6 +5,7 @@
#include <chrono>
#include <functional>
#include <memory>
#include <utility>
namespace beast {

View File

@@ -5,6 +5,7 @@
#include <chrono>
#include <functional>
#include <memory>
#include <utility>
namespace beast {

View File

@@ -16,34 +16,33 @@ template <bool IsConst, class Iterator>
class AgedContainerIterator
{
public:
using iterator_category = typename std::iterator_traits<Iterator>::iterator_category;
using iterator_category = std::iterator_traits<Iterator>::iterator_category;
using value_type = std::conditional_t<
IsConst,
typename Iterator::value_type::Stashed::value_type const,
typename Iterator::value_type::Stashed::value_type>;
using difference_type = typename std::iterator_traits<Iterator>::difference_type;
using difference_type = std::iterator_traits<Iterator>::difference_type;
using pointer = value_type*;
using reference = value_type&;
using time_point = typename Iterator::value_type::Stashed::time_point;
using time_point = Iterator::value_type::Stashed::time_point;
AgedContainerIterator() = default;
// Disable constructing a const_iterator from a non-const_iterator.
// Converting between reverse and non-reverse iterators should be explicit.
template <
bool OtherIsConst,
class OtherIterator,
class = std::enable_if_t<
(!OtherIsConst || IsConst) &&
!static_cast<bool>(std::is_same_v<Iterator, OtherIterator>)>>
template <bool OtherIsConst, class OtherIterator>
explicit AgedContainerIterator(AgedContainerIterator<OtherIsConst, OtherIterator> const& other)
requires(
(!OtherIsConst || IsConst) &&
!static_cast<bool>(std::is_same_v<Iterator, OtherIterator>))
: iter_(other.iter_)
{
}
// Disable constructing a const_iterator from a non-const_iterator.
template <bool OtherIsConst, class = std::enable_if_t<!OtherIsConst || IsConst>>
template <bool OtherIsConst>
AgedContainerIterator(AgedContainerIterator<OtherIsConst, Iterator> const& other)
requires(!OtherIsConst || IsConst)
: iter_(other.iter_)
{
}
@@ -52,7 +51,8 @@ public:
template <bool OtherIsConst, class OtherIterator>
auto
operator=(AgedContainerIterator<OtherIsConst, OtherIterator> const& other)
-> std::enable_if_t<!OtherIsConst || IsConst, AgedContainerIterator&>
-> AgedContainerIterator&
requires(!OtherIsConst || IsConst)
{
iter_ = other.iter_;
return *this;

View File

@@ -11,9 +11,14 @@
#include <boost/version.hpp>
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <memory>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
@@ -62,8 +67,8 @@ class AgedOrderedContainer
{
public:
using clock_type = AbstractClock<Clock>;
using time_point = typename clock_type::time_point;
using duration = typename clock_type::duration;
using time_point = clock_type::time_point;
using duration = clock_type::duration;
using key_type = Key;
using mapped_type = T;
using value_type = std::conditional_t<IsMap, std::pair<Key const, T>, Key>;
@@ -94,8 +99,8 @@ private:
{
explicit Stashed() = default;
using value_type = typename AgedOrderedContainer::value_type;
using time_point = typename AgedOrderedContainer::time_point;
using value_type = AgedOrderedContainer::value_type;
using time_point = AgedOrderedContainer::time_point;
};
Element(time_point const& when, value_type const& value) : value(value), when(when)
@@ -106,10 +111,9 @@ private:
{
}
template <
class... Args,
class = std::enable_if_t<std::is_constructible_v<value_type, Args...>>>
template <class... Args>
Element(time_point const& when, Args&&... args)
requires(std::is_constructible_v<value_type, Args...>)
: value(std::forward<Args>(args)...), when(when)
{
}
@@ -192,8 +196,8 @@ private:
}
};
using list_type = typename boost::intrusive::
make_list<Element, boost::intrusive::constant_time_size<false>>::type;
using list_type =
boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
using cont_type = std::conditional_t<
IsMulti,
@@ -206,8 +210,7 @@ private:
boost::intrusive::constant_time_size<true>,
boost::intrusive::compare<KeyValueCompare>>::type>;
using ElementAllocator =
typename std::allocator_traits<Allocator>::template rebind_alloc<Element>;
using ElementAllocator = std::allocator_traits<Allocator>::template rebind_alloc<Element>;
using ElementAllocatorTraits = std::allocator_traits<ElementAllocator>;
@@ -356,6 +359,7 @@ private:
deleteElement(Element const* p)
{
ElementAllocatorTraits::destroy(config_.alloc(), p);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
ElementAllocatorTraits::deallocate(config_.alloc(), const_cast<Element*>(p), 1);
}
@@ -373,8 +377,8 @@ public:
using allocator_type = Allocator;
using reference = value_type&;
using const_reference = value_type const&;
using pointer = typename std::allocator_traits<Allocator>::pointer;
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
using pointer = std::allocator_traits<Allocator>::pointer;
using const_pointer = std::allocator_traits<Allocator>::const_pointer;
// A set iterator (IsMap==false) is always const
// because the elements of a set are immutable.
@@ -604,35 +608,25 @@ public:
//
//--------------------------------------------------------------------------
template <
class K,
bool MaybeMulti = IsMulti,
bool MaybeMap = IsMap,
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
template <class K, bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
std::conditional_t<IsMap, T, void*>&
at(K const& k);
at(K const& k)
requires(MaybeMap && !MaybeMulti);
template <
class K,
bool MaybeMulti = IsMulti,
bool MaybeMap = IsMap,
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
typename std::conditional<IsMap, T, void*>::type const&
at(K const& k) const;
template <class K, bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
std::conditional<IsMap, T, void*>::type const&
at(K const& k) const
requires(MaybeMap && !MaybeMulti);
template <
bool MaybeMulti = IsMulti,
bool MaybeMap = IsMap,
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
std::conditional_t<IsMap, T, void*>&
operator[](Key const& key);
operator[](Key const& key)
requires(MaybeMap && !MaybeMulti);
template <
bool MaybeMulti = IsMulti,
bool MaybeMap = IsMap,
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
std::conditional_t<IsMap, T, void*>&
operator[](Key&& key);
operator[](Key&& key)
requires(MaybeMap && !MaybeMulti);
//--------------------------------------------------------------------------
//
@@ -766,35 +760,40 @@ public:
// map, set
template <bool MaybeMulti = IsMulti>
auto
insert(value_type const& value) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>;
insert(value_type const& value) -> std::pair<iterator, bool>
requires(!MaybeMulti);
// multimap, multiset
template <bool MaybeMulti = IsMulti>
auto
insert(value_type const& value) -> std::enable_if_t<MaybeMulti, iterator>;
insert(value_type const& value) -> iterator
requires MaybeMulti;
// set
template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
auto
insert(value_type&& value)
-> std::enable_if_t<!MaybeMulti && !MaybeMap, std::pair<iterator, bool>>;
insert(value_type&& value) -> std::pair<iterator, bool>
requires(!MaybeMulti && !MaybeMap);
// multiset
template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
auto
insert(value_type&& value) -> std::enable_if_t<MaybeMulti && !MaybeMap, iterator>;
insert(value_type&& value) -> iterator
requires(MaybeMulti && !MaybeMap);
//---
// map, set
template <bool MaybeMulti = IsMulti>
auto
insert(const_iterator hint, value_type const& value) -> std::enable_if_t<!MaybeMulti, iterator>;
insert(const_iterator hint, value_type const& value) -> iterator
requires(!MaybeMulti);
// multimap, multiset
template <bool MaybeMulti = IsMulti>
std::enable_if_t<MaybeMulti, iterator>
iterator
insert(const_iterator /*hint*/, value_type const& value)
requires MaybeMulti
{
// VFALCO TODO Figure out how to utilize 'hint'
return insert(value);
@@ -803,12 +802,14 @@ public:
// map, set
template <bool MaybeMulti = IsMulti>
auto
insert(const_iterator hint, value_type&& value) -> std::enable_if_t<!MaybeMulti, iterator>;
insert(const_iterator hint, value_type&& value) -> iterator
requires(!MaybeMulti);
// multimap, multiset
template <bool MaybeMulti = IsMulti>
std::enable_if_t<MaybeMulti, iterator>
iterator
insert(const_iterator /*hint*/, value_type&& value)
requires MaybeMulti
{
// VFALCO TODO Figure out how to utilize 'hint'
return insert(std::move(value));
@@ -816,20 +817,18 @@ public:
// map, multimap
template <class P, bool MaybeMap = IsMap>
std::enable_if_t<
MaybeMap && std::is_constructible_v<value_type, P&&>,
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>>
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>
insert(P&& value)
requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
{
return emplace(std::forward<P>(value));
}
// map, multimap
template <class P, bool MaybeMap = IsMap>
std::enable_if_t<
MaybeMap && std::is_constructible_v<value_type, P&&>,
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>>
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>
insert(const_iterator hint, P&& value)
requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
{
return emplaceHint(hint, std::forward<P>(value));
}
@@ -851,46 +850,45 @@ public:
// map, set
template <bool MaybeMulti = IsMulti, class... Args>
auto
emplace(Args&&... args) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>;
emplace(Args&&... args) -> std::pair<iterator, bool>
requires(!MaybeMulti);
// multiset, multimap
template <bool MaybeMulti = IsMulti, class... Args>
auto
emplace(Args&&... args) -> std::enable_if_t<MaybeMulti, iterator>;
emplace(Args&&... args) -> iterator
requires MaybeMulti;
// map, set
template <bool MaybeMulti = IsMulti, class... Args>
auto
emplaceHint(const_iterator hint, Args&&... args)
-> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>;
emplaceHint(const_iterator hint, Args&&... args) -> std::pair<iterator, bool>
requires(!MaybeMulti);
// multiset, multimap
template <bool MaybeMulti = IsMulti, class... Args>
std::enable_if_t<MaybeMulti, iterator>
iterator
emplaceHint(const_iterator /*hint*/, Args&&... args)
requires MaybeMulti
{
// VFALCO TODO Figure out how to utilize 'hint'
return emplace<MaybeMulti>(std::forward<Args>(args)...);
}
// enable_if prevents erase (reverse_iterator pos) from compiling
template <
bool IsConst,
class Iterator,
class = std::enable_if_t<!IsBoostReverseIterator<Iterator>::value>>
// The constraint prevents erase (reverse_iterator pos) from compiling
template <bool IsConst, class Iterator>
beast::detail::AgedContainerIterator<false, Iterator>
erase(beast::detail::AgedContainerIterator<IsConst, Iterator> pos);
erase(beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
requires(!IsBoostReverseIterator<Iterator>::value);
// enable_if prevents erase (reverse_iterator first, reverse_iterator last)
// The constraint prevents erase (reverse_iterator first, reverse_iterator last)
// from compiling
template <
bool IsConst,
class Iterator,
class = std::enable_if_t<!IsBoostReverseIterator<Iterator>::value>>
template <bool IsConst, class Iterator>
beast::detail::AgedContainerIterator<false, Iterator>
erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> first,
beast::detail::AgedContainerIterator<IsConst, Iterator> last);
beast::detail::AgedContainerIterator<IsConst, Iterator> last)
requires(!IsBoostReverseIterator<Iterator>::value);
template <class K>
auto
@@ -901,13 +899,11 @@ public:
//--------------------------------------------------------------------------
// enable_if prevents touch (reverse_iterator pos) from compiling
template <
bool IsConst,
class Iterator,
class = std::enable_if_t<!IsBoostReverseIterator<Iterator>::value>>
// The constraint prevents touch (reverse_iterator pos) from compiling
template <bool IsConst, class Iterator>
void
touch(beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
requires(!IsBoostReverseIterator<Iterator>::value)
{
touch(pos, clock().now());
}
@@ -1138,25 +1134,25 @@ public:
}
private:
// enable_if prevents erase (reverse_iterator pos, now) from compiling
template <
bool IsConst,
class Iterator,
class = std::enable_if_t<!IsBoostReverseIterator<Iterator>::value>>
// The constraint prevents erase (reverse_iterator pos, now) from compiling
template <bool IsConst, class Iterator>
void
touch(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
typename clock_type::time_point const& now);
clock_type::time_point const& now)
requires(!IsBoostReverseIterator<Iterator>::value);
template <
bool MaybePropagate = std::allocator_traits<Allocator>::propagate_on_container_swap::value>
std::enable_if_t<MaybePropagate>
swapData(AgedOrderedContainer& other) noexcept;
void
swapData(AgedOrderedContainer& other) noexcept
requires MaybePropagate;
template <
bool MaybePropagate = std::allocator_traits<Allocator>::propagate_on_container_swap::value>
std::enable_if_t<!MaybePropagate>
swapData(AgedOrderedContainer& other) noexcept;
void
swapData(AgedOrderedContainer& other) noexcept
requires(!MaybePropagate);
private:
ConfigT config_;
@@ -1248,12 +1244,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrd
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
AgedOrderedContainer const& other)
: config_(other.config_)
#if BOOST_VERSION >= 108000
, cont_(other.cont_.get_comp())
#else
, cont_(other.cont_.comp())
#endif
: config_(other.config_), cont_(other.cont_.get_comp())
{
insert(other.cbegin(), other.cend());
}
@@ -1262,12 +1253,7 @@ template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compa
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
AgedOrderedContainer const& other,
Allocator const& alloc)
: config_(other.config_, alloc)
#if BOOST_VERSION >= 108000
, cont_(other.cont_.get_comp())
#else
, cont_(other.cont_.comp())
#endif
: config_(other.config_, alloc), cont_(other.cont_.get_comp())
{
insert(other.cbegin(), other.cend());
}
@@ -1284,13 +1270,7 @@ template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compa
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::AgedOrderedContainer(
AgedOrderedContainer&& other, // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
Allocator const& alloc)
: config_(std::move(other.config_), alloc)
#if BOOST_VERSION >= 108000
, cont_(std::move(other.cont_.get_comp()))
#else
, cont_(std::move(other.cont_.comp()))
#endif
: config_(std::move(other.config_), alloc), cont_(std::move(other.cont_.get_comp()))
{
insert(other.cbegin(), other.cend());
other.clear();
@@ -1381,9 +1361,10 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operato
//------------------------------------------------------------------------------
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <class K, bool MaybeMulti, bool MaybeMap, class>
template <class K, bool MaybeMulti, bool MaybeMap>
std::conditional_t<IsMap, T, void*>&
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::at(K const& k)
requires(MaybeMap && !MaybeMulti)
{
auto const iter(cont_.find(k, std::cref(config_.keyCompare())));
if (iter == cont_.end())
@@ -1392,9 +1373,10 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::at(K co
}
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <class K, bool MaybeMulti, bool MaybeMap, class>
typename std::conditional<IsMap, T, void*>::type const&
template <class K, bool MaybeMulti, bool MaybeMap>
std::conditional<IsMap, T, void*>::type const&
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::at(K const& k) const
requires(MaybeMap && !MaybeMulti)
{
auto const iter(cont_.find(k, std::cref(config_.keyCompare())));
if (iter == cont_.end())
@@ -1403,9 +1385,10 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::at(K co
}
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <bool MaybeMulti, bool MaybeMap, class>
template <bool MaybeMulti, bool MaybeMap>
std::conditional_t<IsMap, T, void*>&
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operator[](Key const& key)
requires(MaybeMap && !MaybeMulti)
{
typename cont_type::insert_commit_data d;
auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d));
@@ -1421,9 +1404,10 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operato
}
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <bool MaybeMulti, bool MaybeMap, class>
template <bool MaybeMulti, bool MaybeMap>
std::conditional_t<IsMap, T, void*>&
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operator[](Key&& key)
requires(MaybeMap && !MaybeMulti)
{
typename cont_type::insert_commit_data d;
auto const result(cont_.insert_check(key, std::cref(config_.keyCompare()), d));
@@ -1457,7 +1441,8 @@ template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compa
template <bool MaybeMulti>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(
value_type const& value) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>
value_type const& value) -> std::pair<iterator, bool>
requires(!MaybeMulti)
{
typename cont_type::insert_commit_data d;
auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d));
@@ -1476,7 +1461,8 @@ template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compa
template <bool MaybeMulti>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(
value_type const& value) -> std::enable_if_t<MaybeMulti, iterator>
value_type const& value) -> iterator
requires MaybeMulti
{
auto const before(cont_.upper_bound(extract(value), std::cref(config_.keyCompare())));
Element* const p(newElement(value));
@@ -1490,7 +1476,8 @@ template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compa
template <bool MaybeMulti, bool MaybeMap>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(value_type&& value)
-> std::enable_if_t<!MaybeMulti && !MaybeMap, std::pair<iterator, bool>>
-> std::pair<iterator, bool>
requires(!MaybeMulti && !MaybeMap)
{
typename cont_type::insert_commit_data d;
auto const result(cont_.insert_check(extract(value), std::cref(config_.keyCompare()), d));
@@ -1509,7 +1496,8 @@ template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compa
template <bool MaybeMulti, bool MaybeMap>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(value_type&& value)
-> std::enable_if_t<MaybeMulti && !MaybeMap, iterator>
-> iterator
requires(MaybeMulti && !MaybeMap)
{
auto const before(cont_.upper_bound(extract(value), std::cref(config_.keyCompare())));
Element* const p(newElement(std::move(value)));
@@ -1526,7 +1514,8 @@ template <bool MaybeMulti>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(
const_iterator hint,
value_type const& value) -> std::enable_if_t<!MaybeMulti, iterator>
value_type const& value) -> iterator
requires(!MaybeMulti)
{
typename cont_type::insert_commit_data d;
auto const result(
@@ -1547,7 +1536,8 @@ template <bool MaybeMulti>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::insert(
const_iterator hint,
value_type&& value) -> std::enable_if_t<!MaybeMulti, iterator>
value_type&& value) -> iterator
requires(!MaybeMulti)
{
typename cont_type::insert_commit_data d;
auto const result(
@@ -1567,7 +1557,8 @@ template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compa
template <bool MaybeMulti, class... Args>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::emplace(Args&&... args)
-> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>
-> std::pair<iterator, bool>
requires(!MaybeMulti)
{
// VFALCO NOTE Its unfortunate that we need to
// construct element here
@@ -1589,7 +1580,8 @@ template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compa
template <bool MaybeMulti, class... Args>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::emplace(Args&&... args)
-> std::enable_if_t<MaybeMulti, iterator>
-> iterator
requires MaybeMulti
{
Element* const p(newElement(std::forward<Args>(args)...));
auto const before(cont_.upper_bound(extract(p->value), std::cref(config_.keyCompare())));
@@ -1604,7 +1596,8 @@ template <bool MaybeMulti, class... Args>
auto
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::emplaceHint(
const_iterator hint,
Args&&... args) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>
Args&&... args) -> std::pair<iterator, bool>
requires(!MaybeMulti)
{
// VFALCO NOTE Its unfortunate that we need to
// construct element here
@@ -1623,21 +1616,23 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::emplace
}
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <bool IsConst, class Iterator, class>
template <bool IsConst, class Iterator>
beast::detail::AgedContainerIterator<false, Iterator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos)
requires(!IsBoostReverseIterator<Iterator>::value)
{
unlinkAndDeleteElement(&*((pos++).iterator()));
return beast::detail::AgedContainerIterator<false, Iterator>(pos.iterator());
}
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <bool IsConst, class Iterator, class>
template <bool IsConst, class Iterator>
beast::detail::AgedContainerIterator<false, Iterator>
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::erase(
beast::detail::AgedContainerIterator<IsConst, Iterator> first,
beast::detail::AgedContainerIterator<IsConst, Iterator> last)
requires(!IsBoostReverseIterator<Iterator>::value)
{
for (; first != last;)
unlinkAndDeleteElement(&*((first++).iterator()));
@@ -1732,7 +1727,7 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operato
cend(),
other.cbegin(),
other.cend(),
[&eq, &other](value_type const& lhs, typename Other::value_type const& rhs) {
[&eq, &other](value_type const& lhs, Other::value_type const& rhs) {
return eq(extract(lhs), other.extract(rhs));
});
}
@@ -1740,11 +1735,12 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::operato
//------------------------------------------------------------------------------
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <bool IsConst, class Iterator, class>
template <bool IsConst, class Iterator>
void
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::touch(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
typename clock_type::time_point const& now)
clock_type::time_point const& now)
requires(!IsBoostReverseIterator<Iterator>::value)
{
auto& e(*pos.iterator());
e.when = now;
@@ -1754,9 +1750,10 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::touch(
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <bool MaybePropagate>
std::enable_if_t<MaybePropagate>
void
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::swapData(
AgedOrderedContainer& other) noexcept
requires MaybePropagate
{
std::swap(config_.keyCompare(), other.config_.keyCompare());
std::swap(config_.alloc(), other.config_.alloc());
@@ -1765,9 +1762,10 @@ AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::swapDat
template <bool IsMulti, bool IsMap, class Key, class T, class Clock, class Compare, class Allocator>
template <bool MaybePropagate>
std::enable_if_t<!MaybePropagate>
void
AgedOrderedContainer<IsMulti, IsMap, Key, T, Clock, Compare, Allocator>::swapData(
AgedOrderedContainer& other) noexcept
requires(!MaybePropagate)
{
std::swap(config_.keyCompare(), other.config_.keyCompare());
std::swap(config_.clock, other.config_.clock);

View File

@@ -10,13 +10,19 @@
#include <boost/intrusive/unordered_set.hpp>
#include <algorithm>
#include <chrono>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <initializer_list>
#include <iterator>
#include <memory>
#include <stdexcept>
#include <tuple>
#include <type_traits>
#include <utility>
#include <vector>
/*
@@ -67,8 +73,8 @@ class AgedUnorderedContainer
{
public:
using clock_type = AbstractClock<Clock>;
using time_point = typename clock_type::time_point;
using duration = typename clock_type::duration;
using time_point = clock_type::time_point;
using duration = clock_type::duration;
using key_type = Key;
using mapped_type = T;
using value_type = std::conditional_t<IsMap, std::pair<Key const, T>, Key>;
@@ -99,8 +105,8 @@ private:
{
explicit Stashed() = default;
using value_type = typename AgedUnorderedContainer::value_type;
using time_point = typename AgedUnorderedContainer::time_point;
using value_type = AgedUnorderedContainer::value_type;
using time_point = AgedUnorderedContainer::time_point;
};
Element(time_point const& when, value_type const& value) : value(value), when(when)
@@ -111,10 +117,9 @@ private:
{
}
template <
class... Args,
class = std::enable_if_t<std::is_constructible_v<value_type, Args...>>>
template <class... Args>
Element(time_point const& when, Args&&... args)
requires(std::is_constructible_v<value_type, Args...>)
: value(std::forward<Args>(args)...), when(when)
{
}
@@ -201,8 +206,8 @@ private:
}
};
using list_type = typename boost::intrusive::
make_list<Element, boost::intrusive::constant_time_size<false>>::type;
using list_type =
boost::intrusive::make_list<Element, boost::intrusive::constant_time_size<false>>::type;
using cont_type = std::conditional_t<
IsMulti,
@@ -219,16 +224,14 @@ private:
boost::intrusive::equal<KeyValueEqual>,
boost::intrusive::cache_begin<true>>::type>;
using bucket_type = typename cont_type::bucket_type;
using bucket_traits = typename cont_type::bucket_traits;
using bucket_type = cont_type::bucket_type;
using bucket_traits = cont_type::bucket_traits;
using ElementAllocator =
typename std::allocator_traits<Allocator>::template rebind_alloc<Element>;
using ElementAllocator = std::allocator_traits<Allocator>::template rebind_alloc<Element>;
using ElementAllocatorTraits = std::allocator_traits<ElementAllocator>;
using BucketAllocator =
typename std::allocator_traits<Allocator>::template rebind_alloc<Element>;
using BucketAllocator = std::allocator_traits<Allocator>::template rebind_alloc<Element>;
using BucketAllocatorTraits = std::allocator_traits<BucketAllocator>;
@@ -525,6 +528,7 @@ private:
deleteElement(Element const* p)
{
ElementAllocatorTraits::destroy(config_.alloc(), p);
// NOLINTNEXTLINE(cppcoreguidelines-pro-type-const-cast)
ElementAllocatorTraits::deallocate(config_.alloc(), const_cast<Element*>(p), 1);
}
@@ -542,8 +546,8 @@ public:
using allocator_type = Allocator;
using reference = value_type&;
using const_reference = value_type const&;
using pointer = typename std::allocator_traits<Allocator>::pointer;
using const_pointer = typename std::allocator_traits<Allocator>::const_pointer;
using pointer = std::allocator_traits<Allocator>::pointer;
using const_pointer = std::allocator_traits<Allocator>::const_pointer;
// A set iterator (IsMap==false) is always const
// because the elements of a set are immutable.
@@ -837,35 +841,25 @@ public:
//
//--------------------------------------------------------------------------
template <
class K,
bool MaybeMulti = IsMulti,
bool MaybeMap = IsMap,
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
template <class K, bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
std::conditional_t<IsMap, T, void*>&
at(K const& k);
at(K const& k)
requires(MaybeMap && !MaybeMulti);
template <
class K,
bool MaybeMulti = IsMulti,
bool MaybeMap = IsMap,
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
typename std::conditional<IsMap, T, void*>::type const&
at(K const& k) const;
template <class K, bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
std::conditional<IsMap, T, void*>::type const&
at(K const& k) const
requires(MaybeMap && !MaybeMulti);
template <
bool MaybeMulti = IsMulti,
bool MaybeMap = IsMap,
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
std::conditional_t<IsMap, T, void*>&
operator[](Key const& key);
operator[](Key const& key)
requires(MaybeMap && !MaybeMulti);
template <
bool MaybeMulti = IsMulti,
bool MaybeMap = IsMap,
class = std::enable_if_t<MaybeMap && !MaybeMulti>>
template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
std::conditional_t<IsMap, T, void*>&
operator[](Key&& key);
operator[](Key&& key)
requires(MaybeMap && !MaybeMulti);
//--------------------------------------------------------------------------
//
@@ -963,28 +957,32 @@ public:
// map, set
template <bool MaybeMulti = IsMulti>
auto
insert(value_type const& value) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>;
insert(value_type const& value) -> std::pair<iterator, bool>
requires(!MaybeMulti);
// multimap, multiset
template <bool MaybeMulti = IsMulti>
auto
insert(value_type const& value) -> std::enable_if_t<MaybeMulti, iterator>;
insert(value_type const& value) -> iterator
requires MaybeMulti;
// map, set
template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
auto
insert(value_type&& value)
-> std::enable_if_t<!MaybeMulti && !MaybeMap, std::pair<iterator, bool>>;
insert(value_type&& value) -> std::pair<iterator, bool>
requires(!MaybeMulti && !MaybeMap);
// multimap, multiset
template <bool MaybeMulti = IsMulti, bool MaybeMap = IsMap>
auto
insert(value_type&& value) -> std::enable_if_t<MaybeMulti && !MaybeMap, iterator>;
insert(value_type&& value) -> iterator
requires(MaybeMulti && !MaybeMap);
// map, set
template <bool MaybeMulti = IsMulti>
std::enable_if_t<!MaybeMulti, iterator>
iterator
insert(const_iterator /*hint*/, value_type const& value)
requires(!MaybeMulti)
{
// Hint is ignored but we provide the interface so
// callers may use ordered and unordered interchangeably.
@@ -993,8 +991,9 @@ public:
// multimap, multiset
template <bool MaybeMulti = IsMulti>
std::enable_if_t<MaybeMulti, iterator>
iterator
insert(const_iterator /*hint*/, value_type const& value)
requires MaybeMulti
{
// VFALCO TODO The hint could be used to let
// the client order equal ranges
@@ -1003,8 +1002,9 @@ public:
// map, set
template <bool MaybeMulti = IsMulti>
std::enable_if_t<!MaybeMulti, iterator>
iterator
insert(const_iterator /*hint*/, value_type&& value)
requires(!MaybeMulti)
{
// Hint is ignored but we provide the interface so
// callers may use ordered and unordered interchangeably.
@@ -1013,8 +1013,9 @@ public:
// multimap, multiset
template <bool MaybeMulti = IsMulti>
std::enable_if_t<MaybeMulti, iterator>
iterator
insert(const_iterator /*hint*/, value_type&& value)
requires MaybeMulti
{
// VFALCO TODO The hint could be used to let
// the client order equal ranges
@@ -1023,20 +1024,18 @@ public:
// map, multimap
template <class P, bool MaybeMap = IsMap>
std::enable_if_t<
MaybeMap && std::is_constructible_v<value_type, P&&>,
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>>
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>
insert(P&& value)
requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
{
return emplace(std::forward<P>(value));
}
// map, multimap
template <class P, bool MaybeMap = IsMap>
std::enable_if_t<
MaybeMap && std::is_constructible_v<value_type, P&&>,
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>>
std::conditional_t<IsMulti, iterator, std::pair<iterator, bool>>
insert(const_iterator hint, P&& value)
requires(MaybeMap && std::is_constructible_v<value_type, P &&>)
{
return emplaceHint(hint, std::forward<P>(value));
}
@@ -1057,23 +1056,26 @@ public:
// set, map
template <bool MaybeMulti = IsMulti, class... Args>
auto
emplace(Args&&... args) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>;
emplace(Args&&... args) -> std::pair<iterator, bool>
requires(!MaybeMulti);
// multiset, multimap
template <bool MaybeMulti = IsMulti, class... Args>
auto
emplace(Args&&... args) -> std::enable_if_t<MaybeMulti, iterator>;
emplace(Args&&... args) -> iterator
requires MaybeMulti;
// set, map
template <bool MaybeMulti = IsMulti, class... Args>
auto
emplaceHint(const_iterator /*hint*/, Args&&... args)
-> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>;
emplaceHint(const_iterator /*hint*/, Args&&... args) -> std::pair<iterator, bool>
requires(!MaybeMulti);
// multiset, multimap
template <bool MaybeMulti = IsMulti, class... Args>
std::enable_if_t<MaybeMulti, iterator>
iterator
emplaceHint(const_iterator /*hint*/, Args&&... args)
requires MaybeMulti
{
// VFALCO TODO The hint could be used for multi, to let
// the client order equal ranges
@@ -1304,7 +1306,7 @@ public:
class OtherHash,
class OtherAllocator,
bool MaybeMulti = IsMulti>
std::enable_if_t<!MaybeMulti, bool>
bool
operator==(AgedUnorderedContainer<
false,
OtherIsMap,
@@ -1313,7 +1315,8 @@ public:
OtherDuration,
OtherHash,
KeyEqual,
OtherAllocator> const& other) const;
OtherAllocator> const& other) const
requires(!MaybeMulti);
template <
bool OtherIsMap,
@@ -1323,7 +1326,7 @@ public:
class OtherHash,
class OtherAllocator,
bool MaybeMulti = IsMulti>
std::enable_if_t<MaybeMulti, bool>
bool
operator==(AgedUnorderedContainer<
true,
OtherIsMap,
@@ -1332,7 +1335,8 @@ public:
OtherDuration,
OtherHash,
KeyEqual,
OtherAllocator> const& other) const;
OtherAllocator> const& other) const
requires MaybeMulti;
template <
bool OtherIsMulti,
@@ -1377,13 +1381,14 @@ private:
// map, set
template <bool MaybeMulti = IsMulti>
auto
insertUnchecked(value_type const& value)
-> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>;
insertUnchecked(value_type const& value) -> std::pair<iterator, bool>
requires(!MaybeMulti);
// multimap, multiset
template <bool MaybeMulti = IsMulti>
auto
insertUnchecked(value_type const& value) -> std::enable_if_t<MaybeMulti, iterator>;
insertUnchecked(value_type const& value) -> iterator
requires MaybeMulti;
template <class InputIt>
void
@@ -1414,7 +1419,7 @@ private:
void
touch(
beast::detail::AgedContainerIterator<IsConst, Iterator> pos,
typename clock_type::time_point const& now)
clock_type::time_point const& now)
{
auto& e(*pos.iterator());
e.when = now;
@@ -1424,8 +1429,9 @@ private:
template <
bool MaybePropagate = std::allocator_traits<Allocator>::propagate_on_container_swap::value>
std::enable_if_t<MaybePropagate>
void
swapData(AgedUnorderedContainer& other) noexcept
requires MaybePropagate
{
std::swap(config_.hashFunction(), other.config_.hashFunction());
std::swap(config_.keyEq(), other.config_.keyEq());
@@ -1435,8 +1441,9 @@ private:
template <
bool MaybePropagate = std::allocator_traits<Allocator>::propagate_on_container_swap::value>
std::enable_if_t<!MaybePropagate>
void
swapData(AgedUnorderedContainer& other) noexcept
requires(!MaybePropagate)
{
std::swap(config_.hashFunction(), other.config_.hashFunction());
std::swap(config_.keyEq(), other.config_.keyEq());
@@ -2090,9 +2097,10 @@ template <
class Hash,
class KeyEqual,
class Allocator>
template <class K, bool MaybeMulti, bool MaybeMap, class>
template <class K, bool MaybeMulti, bool MaybeMap>
std::conditional_t<IsMap, T, void*>&
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::at(K const& k)
requires(MaybeMap && !MaybeMulti)
{
auto const iter(
cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
@@ -2110,10 +2118,11 @@ template <
class Hash,
class KeyEqual,
class Allocator>
template <class K, bool MaybeMulti, bool MaybeMap, class>
typename std::conditional<IsMap, T, void*>::type const&
template <class K, bool MaybeMulti, bool MaybeMap>
std::conditional<IsMap, T, void*>::type const&
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::at(
K const& k) const
requires(MaybeMap && !MaybeMulti)
{
auto const iter(
cont_.find(k, std::cref(config_.hashFunction()), std::cref(config_.keyValueEqual())));
@@ -2131,10 +2140,11 @@ template <
class Hash,
class KeyEqual,
class Allocator>
template <bool MaybeMulti, bool MaybeMap, class>
template <bool MaybeMulti, bool MaybeMap>
std::conditional_t<IsMap, T, void*>&
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::operator[](
Key const& key)
requires(MaybeMap && !MaybeMulti)
{
maybeRehash(1);
typename cont_type::insert_commit_data d;
@@ -2160,10 +2170,11 @@ template <
class Hash,
class KeyEqual,
class Allocator>
template <bool MaybeMulti, bool MaybeMap, class>
template <bool MaybeMulti, bool MaybeMap>
std::conditional_t<IsMap, T, void*>&
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::operator[](
Key&& key)
requires(MaybeMap && !MaybeMulti)
{
maybeRehash(1);
typename cont_type::insert_commit_data d;
@@ -2216,7 +2227,8 @@ template <
template <bool MaybeMulti>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::insert(
value_type const& value) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>
value_type const& value) -> std::pair<iterator, bool>
requires(!MaybeMulti)
{
maybeRehash(1);
typename cont_type::insert_commit_data d;
@@ -2245,7 +2257,8 @@ template <
template <bool MaybeMulti>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::insert(
value_type const& value) -> std::enable_if_t<MaybeMulti, iterator>
value_type const& value) -> iterator
requires MaybeMulti
{
maybeRehash(1);
Element* const p(newElement(value));
@@ -2267,7 +2280,8 @@ template <
template <bool MaybeMulti, bool MaybeMap>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::insert(
value_type&& value) -> std::enable_if_t<!MaybeMulti && !MaybeMap, std::pair<iterator, bool>>
value_type&& value) -> std::pair<iterator, bool>
requires(!MaybeMulti && !MaybeMap)
{
maybeRehash(1);
typename cont_type::insert_commit_data d;
@@ -2296,7 +2310,8 @@ template <
template <bool MaybeMulti, bool MaybeMap>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::insert(
value_type&& value) -> std::enable_if_t<MaybeMulti && !MaybeMap, iterator>
value_type&& value) -> iterator
requires(MaybeMulti && !MaybeMap)
{
maybeRehash(1);
Element* const p(newElement(std::move(value)));
@@ -2305,7 +2320,6 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
return iterator(iter);
}
#if 1 // Use insert() instead of insert_check() insert_commit()
// set, map
template <
bool IsMulti,
@@ -2319,7 +2333,8 @@ template <
template <bool MaybeMulti, class... Args>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::emplace(
Args&&... args) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>
Args&&... args) -> std::pair<iterator, bool>
requires(!MaybeMulti)
{
maybeRehash(1);
// VFALCO NOTE Its unfortunate that we need to
@@ -2334,42 +2349,6 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
deleteElement(p);
return std::make_pair(iterator(result.first), false);
}
#else // As original, use insert_check() / insert_commit () pair.
// set, map
template <
bool IsMulti,
bool IsMap,
class Key,
class T,
class Clock,
class Hash,
class KeyEqual,
class Allocator>
template <bool maybe_multi, class... Args>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::emplace(
Args&&... args) -> typename std::enable_if<!maybe_multi, std::pair<iterator, bool>>::type
{
maybe_rehash(1);
// VFALCO NOTE Its unfortunate that we need to
// construct element here
element* const p(new_element(std::forward<Args>(args)...));
typename cont_type::insert_commit_data d;
auto const result(m_cont.insert_check(
extract(p->value),
std::cref(m_config.hashFunction()),
std::cref(m_config.keyValueEqual()),
d));
if (result.second)
{
auto const iter(m_cont.insert_commit(*p, d));
chronological.list.push_back(*p);
return std::make_pair(iterator(iter), true);
}
delete_element(p);
return std::make_pair(iterator(result.first), false);
}
#endif // 0
// multiset, multimap
template <
@@ -2384,7 +2363,8 @@ template <
template <bool MaybeMulti, class... Args>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::emplace(
Args&&... args) -> std::enable_if_t<MaybeMulti, iterator>
Args&&... args) -> iterator
requires MaybeMulti
{
maybeRehash(1);
Element* const p(newElement(std::forward<Args>(args)...));
@@ -2407,7 +2387,8 @@ template <bool MaybeMulti, class... Args>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::emplaceHint(
const_iterator /*hint*/,
Args&&... args) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>
Args&&... args) -> std::pair<iterator, bool>
requires(!MaybeMulti)
{
maybeRehash(1);
// VFALCO NOTE Its unfortunate that we need to
@@ -2558,7 +2539,7 @@ template <
class OtherHash,
class OtherAllocator,
bool MaybeMulti>
std::enable_if_t<!MaybeMulti, bool>
bool
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::operator==(
AgedUnorderedContainer<
false,
@@ -2569,6 +2550,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
OtherHash,
KeyEqual,
OtherAllocator> const& other) const
requires(!MaybeMulti)
{
if (size() != other.size())
return false;
@@ -2598,7 +2580,7 @@ template <
class OtherHash,
class OtherAllocator,
bool MaybeMulti>
std::enable_if_t<MaybeMulti, bool>
bool
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::operator==(
AgedUnorderedContainer<
true,
@@ -2609,6 +2591,7 @@ AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>
OtherHash,
KeyEqual,
OtherAllocator> const& other) const
requires MaybeMulti
{
if (size() != other.size())
return false;
@@ -2645,7 +2628,8 @@ template <
template <bool MaybeMulti>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::insertUnchecked(
value_type const& value) -> std::enable_if_t<!MaybeMulti, std::pair<iterator, bool>>
value_type const& value) -> std::pair<iterator, bool>
requires(!MaybeMulti)
{
typename cont_type::insert_commit_data d;
auto const result(cont_.insert_check(
@@ -2673,7 +2657,8 @@ template <
template <bool MaybeMulti>
auto
AgedUnorderedContainer<IsMulti, IsMap, Key, T, Clock, Hash, KeyEqual, Allocator>::insertUnchecked(
value_type const& value) -> std::enable_if_t<MaybeMulti, iterator>
value_type const& value) -> iterator
requires MaybeMulti
{
Element* const p(newElement(value));
chronological.list_.push_back(*p);

View File

@@ -6,6 +6,7 @@
#include <boost/predef.h>
#include <cstddef>
#include <string>
#include <string_view>

View File

@@ -5,11 +5,12 @@
#include <boost/core/detail/string_view.hpp>
#include <algorithm>
#include <cerrno>
#include <cctype>
#include <charconv>
#include <cstdlib>
#include <iterator>
#include <string>
#include <string_view>
#include <system_error>
#include <type_traits>
#include <typeinfo>
@@ -28,16 +29,18 @@ struct LexicalCast<std::string, In>
explicit LexicalCast() = default;
template <class Arithmetic = In>
std::enable_if_t<std::is_arithmetic_v<Arithmetic>, bool>
bool
operator()(std::string& out, Arithmetic in)
requires(std::is_arithmetic_v<Arithmetic>)
{
out = std::to_string(in);
return true;
}
template <class Enumeration = In>
std::enable_if_t<std::is_enum_v<Enumeration>, bool>
bool
operator()(std::string& out, Enumeration in)
requires(std::is_enum_v<Enumeration>)
{
out = std::to_string(static_cast<std::underlying_type_t<Enumeration>>(in));
return true;
@@ -55,8 +58,9 @@ struct LexicalCast<Out, std::string_view>
"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>
bool
operator()(Integral& out, std::string_view in) const
requires(std::is_integral_v<Integral> && !std::is_same_v<Integral, bool>)
{
auto first = in.data();
auto last = in.data() + in.size();

View File

@@ -1,6 +1,8 @@
#pragma once
#include <cstddef>
#include <iterator>
#include <type_traits>
namespace beast {
@@ -24,7 +26,7 @@ struct CopyConst<T const, U>
{
explicit CopyConst() = default;
using type = typename std::remove_const<U>::type const;
using type = std::remove_const<U>::type const;
};
/** @} */
@@ -56,7 +58,7 @@ 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 = beast::detail::CopyConst<N, typename N::value_type>::type;
using difference_type = std::ptrdiff_t;
using pointer = value_type*;
using reference = value_type&;
@@ -259,7 +261,7 @@ template <typename T, typename Tag = void>
class List
{
public:
using Node = typename detail::ListNode<T, Tag>;
using Node = detail::ListNode<T, Tag>;
using value_type = T;
using pointer = value_type*;

View File

@@ -1,6 +1,7 @@
#pragma once
#include <atomic>
#include <cstddef>
#include <iterator>
#include <type_traits>
@@ -12,13 +13,13 @@ template <class Container, bool IsConst>
class LockFreeStackIterator
{
protected:
using Node = typename Container::Node;
using Node = Container::Node;
using NodePtr = std::conditional_t<IsConst, Node const*, Node*>;
public:
using iterator_category = std::forward_iterator_tag;
using value_type = typename Container::value_type;
using difference_type = typename Container::difference_type;
using value_type = Container::value_type;
using difference_type = Container::difference_type;
using pointer =
std::conditional_t<IsConst, typename Container::const_pointer, typename Container::pointer>;
using reference = std::
@@ -40,7 +41,7 @@ public:
operator=(NodePtr node)
{
node_ = node;
return static_cast<LockFreeStackIterator&>(*this);
return *this;
}
LockFreeStackIterator&
@@ -58,7 +59,7 @@ public:
return result;
}
NodePtr
[[nodiscard]] NodePtr
node() const
{
return node_;

View File

@@ -5,8 +5,8 @@
#include <array>
#include <chrono>
#include <cstddef>
#include <cstring>
#include <functional>
#include <memory>
#include <string>
#include <system_error>
@@ -26,7 +26,7 @@ template <class T>
inline void
reverseBytes(T& t)
{
unsigned char* bytes =
auto* 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]);
@@ -200,26 +200,29 @@ struct IsContiguouslyHashable<T[N], HashAlgorithm>
// scalars
template <class Hasher, class T>
inline std::enable_if_t<IsContiguouslyHashable<T, Hasher>::value>
inline void
hash_append(Hasher& h, T const& t) noexcept
requires(IsContiguouslyHashable<T, Hasher>::value)
{
// NOLINTNEXTLINE(bugprone-sizeof-expression)
h(static_cast<void const*>(std::addressof(t)), sizeof(t));
}
template <class Hasher, class T>
inline std::enable_if_t<
!IsContiguouslyHashable<T, Hasher>::value &&
(std::is_integral_v<T> || std::is_pointer_v<T> || std::is_enum_v<T>)>
inline void
hash_append(Hasher& h, T t) noexcept
requires(
!IsContiguouslyHashable<T, Hasher>::value &&
(std::is_integral_v<T> || std::is_pointer_v<T> || std::is_enum_v<T>))
{
detail::reverseBytes(t);
h(std::addressof(t), sizeof(t));
}
template <class Hasher, class T>
inline std::enable_if_t<std::is_floating_point_v<T>>
inline void
hash_append(Hasher& h, T t) noexcept
requires(std::is_floating_point_v<T>)
{
if (t == 0)
t = 0;
@@ -239,36 +242,44 @@ hash_append(Hasher& h, std::nullptr_t) noexcept
// Forward declarations for ADL purposes
template <class Hasher, class T, std::size_t N>
std::enable_if_t<!IsContiguouslyHashable<T, Hasher>::value>
hash_append(Hasher& h, T (&a)[N]) noexcept;
void
hash_append(Hasher& h, T (&a)[N]) noexcept
requires(!IsContiguouslyHashable<T, Hasher>::value);
template <class Hasher, class CharT, class Traits, class Alloc>
std::enable_if_t<!IsContiguouslyHashable<CharT, Hasher>::value>
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
void
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept
requires(!IsContiguouslyHashable<CharT, Hasher>::value);
template <class Hasher, class CharT, class Traits, class Alloc>
std::enable_if_t<IsContiguouslyHashable<CharT, Hasher>::value>
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept;
void
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept
requires(IsContiguouslyHashable<CharT, Hasher>::value);
template <class Hasher, class T, class U>
std::enable_if_t<!IsContiguouslyHashable<std::pair<T, U>, Hasher>::value>
hash_append(Hasher& h, std::pair<T, U> const& p) noexcept;
void
hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
requires(!IsContiguouslyHashable<std::pair<T, U>, Hasher>::value);
template <class Hasher, class T, class Alloc>
std::enable_if_t<!IsContiguouslyHashable<T, Hasher>::value>
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
void
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
requires(!IsContiguouslyHashable<T, Hasher>::value);
template <class Hasher, class T, class Alloc>
std::enable_if_t<IsContiguouslyHashable<T, Hasher>::value>
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept;
void
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
requires(IsContiguouslyHashable<T, Hasher>::value);
template <class Hasher, class T, std::size_t N>
std::enable_if_t<!IsContiguouslyHashable<std::array<T, N>, Hasher>::value>
hash_append(Hasher& h, std::array<T, N> const& a) noexcept;
void
hash_append(Hasher& h, std::array<T, N> const& a) noexcept
requires(!IsContiguouslyHashable<std::array<T, N>, Hasher>::value);
template <class Hasher, class... T>
std::enable_if_t<!IsContiguouslyHashable<std::tuple<T...>, Hasher>::value>
hash_append(Hasher& h, std::tuple<T...> const& t) noexcept;
void
hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
requires(!IsContiguouslyHashable<std::tuple<T...>, Hasher>::value);
template <class Hasher, class Key, class T, class Hash, class Pred, class Alloc>
void
@@ -279,11 +290,13 @@ void
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<!IsContiguouslyHashable<Key, Hasher>::value>
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
void
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
requires(!IsContiguouslyHashable<Key, Hasher>::value);
template <class Hasher, class Key, class Compare, class Alloc>
std::enable_if_t<IsContiguouslyHashable<Key, Hasher>::value>
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept;
void
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
requires(IsContiguouslyHashable<Key, Hasher>::value);
template <class Hasher, class T0, class T1, class... T>
void
hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
@@ -291,8 +304,9 @@ hash_append(Hasher& h, T0 const& t0, T1 const& t1, T const&... t) noexcept;
// c-array
template <class Hasher, class T, std::size_t N>
std::enable_if_t<!IsContiguouslyHashable<T, Hasher>::value>
void
hash_append(Hasher& h, T (&a)[N]) noexcept
requires(!IsContiguouslyHashable<T, Hasher>::value)
{
for (auto const& t : a)
hash_append(h, t);
@@ -301,8 +315,9 @@ hash_append(Hasher& h, T (&a)[N]) noexcept
// basic_string
template <class Hasher, class CharT, class Traits, class Alloc>
inline std::enable_if_t<!IsContiguouslyHashable<CharT, Hasher>::value>
inline void
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept
requires(!IsContiguouslyHashable<CharT, Hasher>::value)
{
for (auto c : s)
hash_append(h, c);
@@ -310,8 +325,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<IsContiguouslyHashable<CharT, Hasher>::value>
inline void
hash_append(Hasher& h, std::basic_string<CharT, Traits, Alloc> const& s) noexcept
requires(IsContiguouslyHashable<CharT, Hasher>::value)
{
h(s.data(), s.size() * sizeof(CharT));
hash_append(h, s.size());
@@ -320,8 +336,9 @@ 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<!IsContiguouslyHashable<std::pair<T, U>, Hasher>::value>
inline void
hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
requires(!IsContiguouslyHashable<std::pair<T, U>, Hasher>::value)
{
hash_append(h, p.first, p.second);
}
@@ -329,8 +346,9 @@ hash_append(Hasher& h, std::pair<T, U> const& p) noexcept
// vector
template <class Hasher, class T, class Alloc>
inline std::enable_if_t<!IsContiguouslyHashable<T, Hasher>::value>
inline void
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
requires(!IsContiguouslyHashable<T, Hasher>::value)
{
for (auto const& t : v)
hash_append(h, t);
@@ -338,8 +356,9 @@ hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
}
template <class Hasher, class T, class Alloc>
inline std::enable_if_t<IsContiguouslyHashable<T, Hasher>::value>
inline void
hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
requires(IsContiguouslyHashable<T, Hasher>::value)
{
h(v.data(), v.size() * sizeof(T));
hash_append(h, v.size());
@@ -348,57 +367,37 @@ hash_append(Hasher& h, std::vector<T, Alloc> const& v) noexcept
// array
template <class Hasher, class T, std::size_t N>
std::enable_if_t<!IsContiguouslyHashable<std::array<T, N>, Hasher>::value>
void
hash_append(Hasher& h, std::array<T, N> const& a) noexcept
requires(!IsContiguouslyHashable<std::array<T, N>, Hasher>::value)
{
for (auto const& t : a)
hash_append(h, t);
}
template <class Hasher, class Key, class Compare, class Alloc>
std::enable_if_t<!IsContiguouslyHashable<Key, Hasher>::value>
void
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
requires(!IsContiguouslyHashable<Key, Hasher>::value)
{
for (auto const& t : v)
hash_append(h, t);
}
template <class Hasher, class Key, class Compare, class Alloc>
std::enable_if_t<IsContiguouslyHashable<Key, Hasher>::value>
void
hash_append(Hasher& h, boost::container::flat_set<Key, Compare, Alloc> const& v) noexcept
requires(IsContiguouslyHashable<Key, Hasher>::value)
{
h(&(v.begin()), v.size() * sizeof(Key));
}
// tuple
namespace detail {
inline void
forEachItem(...) noexcept
{
}
template <class Hasher, class T>
inline int
hashOne(Hasher& h, T const& t) noexcept
{
hash_append(h, t);
return 0;
}
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
{
for_each_item(hash_one(h, std::get<I>(t))...);
}
} // namespace detail
template <class Hasher, class... T>
inline std::enable_if_t<!IsContiguouslyHashable<std::tuple<T...>, Hasher>::value>
inline void
hash_append(Hasher& h, std::tuple<T...> const& t) noexcept
requires(!IsContiguouslyHashable<std::tuple<T...>, Hasher>::value)
{
detail::tuple_hash(h, t, std::index_sequence_for<T...>{});
std::apply([&h](auto const&... item) { (hash_append(h, item), ...); }, t);
}
// shared_ptr

View File

@@ -11,7 +11,7 @@ struct Uhash
{
Uhash() = default;
using result_type = typename Hasher::result_type;
using result_type = Hasher::result_type;
template <class T>
result_type

View File

@@ -7,8 +7,11 @@
#include <array>
#include <cstddef>
#include <cstdint>
#include <cstring>
#include <new>
#include <optional>
#include <span>
#include <type_traits>
namespace beast {
@@ -121,14 +124,18 @@ public:
}
}
template <class Seed, std::enable_if_t<std::is_unsigned_v<Seed>>* = nullptr>
explicit Xxhasher(Seed seed) : seed_(seed)
template <class Seed>
explicit Xxhasher(Seed seed)
requires(std::is_unsigned_v<Seed>)
: seed_(seed)
{
resetBuffers();
}
template <class Seed, std::enable_if_t<std::is_unsigned_v<Seed>>* = nullptr>
Xxhasher(Seed seed, Seed) : seed_(seed)
template <class Seed>
Xxhasher(Seed seed, Seed)
requires(std::is_unsigned_v<Seed>)
: seed_(seed)
{
resetBuffers();
}

View File

@@ -4,8 +4,10 @@
#include <xrpl/beast/insight/Event.h>
#include <xrpl/beast/insight/Gauge.h>
#include <xrpl/beast/insight/Hook.h>
#include <xrpl/beast/insight/HookImpl.h>
#include <xrpl/beast/insight/Meter.h>
#include <memory>
#include <string>
namespace beast::insight {

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/insight/CounterImpl.h>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -29,7 +30,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Counter(std::shared_ptr<CounterImpl> const& impl) : impl_(impl)
explicit Counter(std::shared_ptr<CounterImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -4,6 +4,7 @@
#include <chrono>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -31,7 +32,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Event(std::shared_ptr<EventImpl> const& impl) : impl_(impl)
explicit Event(std::shared_ptr<EventImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/insight/GaugeImpl.h>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -31,7 +32,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Gauge(std::shared_ptr<GaugeImpl> const& impl) : impl_(impl)
explicit Gauge(std::shared_ptr<GaugeImpl> impl) : impl_(std::move(impl))
{
}
@@ -48,6 +49,11 @@ public:
impl_->set(value);
}
// This is a write-through handle: assignment sets the value of the
// referenced metric. It is const-qualified and returns Gauge const&
// (a non-const Gauge& would require a const_cast), so it does not follow
// the conventional assignment-operator signature.
// NOLINTNEXTLINE(misc-unconventional-assign-operator)
Gauge const&
operator=(value_type value) const
{

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/insight/HookImpl.h>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -20,7 +21,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Hook(std::shared_ptr<HookImpl> const& impl) : impl_(impl)
explicit Hook(std::shared_ptr<HookImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -1,15 +0,0 @@
#pragma once
#include <xrpl/beast/insight/Collector.h>
#include <xrpl/beast/insight/Counter.h>
#include <xrpl/beast/insight/CounterImpl.h>
#include <xrpl/beast/insight/Event.h>
#include <xrpl/beast/insight/EventImpl.h>
#include <xrpl/beast/insight/Gauge.h>
#include <xrpl/beast/insight/GaugeImpl.h>
#include <xrpl/beast/insight/Group.h>
#include <xrpl/beast/insight/Groups.h>
#include <xrpl/beast/insight/Hook.h>
#include <xrpl/beast/insight/HookImpl.h>
#include <xrpl/beast/insight/NullCollector.h>
#include <xrpl/beast/insight/StatsDCollector.h>

View File

@@ -3,6 +3,7 @@
#include <xrpl/beast/insight/MeterImpl.h>
#include <memory>
#include <utility>
namespace beast::insight {
@@ -28,7 +29,7 @@ public:
factory function in the Collector interface.
@see Collector.
*/
explicit Meter(std::shared_ptr<MeterImpl> const& impl) : impl_(impl)
explicit Meter(std::shared_ptr<MeterImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -2,6 +2,8 @@
#include <xrpl/beast/insight/Collector.h>
#include <memory>
namespace beast::insight {
/** A Collector which does not collect metrics. */

View File

@@ -4,6 +4,9 @@
#include <xrpl/beast/net/IPEndpoint.h>
#include <xrpl/beast/utility/Journal.h>
#include <memory>
#include <string>
namespace beast::insight {
/** A Collector that reports metrics to a StatsD server.

View File

@@ -9,6 +9,7 @@
#include <boost/asio/ip/address.hpp>
#include <boost/functional/hash.hpp>
#include <cstddef>
#include <string>
//------------------------------------------------------------------------------

View File

@@ -1,7 +1,5 @@
#pragma once
#include <xrpl/beast/hash/hash_append.h>
#include <boost/asio/ip/address_v4.hpp>
namespace beast::IP {

View File

@@ -1,7 +1,5 @@
#pragma once
#include <xrpl/beast/utility/instrumentation.h>
#include <boost/asio/ip/address_v6.hpp>
namespace beast::IP {

View File

@@ -3,8 +3,13 @@
#include <xrpl/beast/hash/hash_append.h>
#include <xrpl/beast/hash/uhash.h>
#include <xrpl/beast/net/IPAddress.h>
#include <xrpl/beast/net/IPAddressV4.h>
#include <xrpl/beast/net/IPAddressV6.h>
#include <cstddef>
#include <cstdint>
#include <functional>
#include <istream>
#include <optional>
#include <string>

View File

@@ -8,6 +8,7 @@
#include <algorithm>
#include <cctype>
#include <cstddef>
#include <iterator>
#include <string>
#include <vector>
@@ -102,7 +103,7 @@ Result
split(FwdIt first, FwdIt last, Char delim)
{
using namespace detail;
using string = typename Result::value_type;
using string = Result::value_type;
Result result;

View File

@@ -11,6 +11,8 @@
#include <boost/thread/csbl/memory/allocator_arg.hpp>
#include <condition_variable>
#include <cstddef>
#include <exception>
#include <mutex>
#include <thread>
#include <vector>

View File

@@ -23,6 +23,7 @@ typeName()
if (auto s = abi::__cxa_demangle(name.c_str(), nullptr, nullptr, nullptr))
{
name = s;
// NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
std::free(s);
}
#endif

View File

@@ -1,15 +1,6 @@
#pragma once
#include <xrpl/beast/unit_test/amount.h>
#include <xrpl/beast/unit_test/global_suites.h>
#include <xrpl/beast/unit_test/match.h>
#include <xrpl/beast/unit_test/recorder.h>
#include <xrpl/beast/unit_test/reporter.h>
#include <xrpl/beast/unit_test/results.h>
#include <xrpl/beast/unit_test/runner.h>
#include <xrpl/beast/unit_test/suite.h>
#include <xrpl/beast/unit_test/suite_info.h>
#include <xrpl/beast/unit_test/suite_list.h>
#ifndef BEAST_EXPECT
#define BEAST_EXPECT_S1(x) #x

View File

@@ -32,11 +32,11 @@ protected:
}
public:
using value_type = typename cont_type::value_type;
using size_type = typename cont_type::size_type;
using difference_type = typename cont_type::difference_type;
using iterator = typename cont_type::const_iterator;
using const_iterator = typename cont_type::const_iterator;
using value_type = cont_type::value_type;
using size_type = cont_type::size_type;
using difference_type = cont_type::difference_type;
using iterator = cont_type::const_iterator;
using const_iterator = cont_type::const_iterator;
/** Returns `true` if the container is empty. */
[[nodiscard]] bool

View File

@@ -7,6 +7,7 @@
#include <xrpl/beast/unit_test/suite_info.h>
#include <string>
#include <utility>
namespace beast::unit_test {
@@ -41,7 +42,7 @@ private:
public:
template <class = void>
explicit Selector(ModeT mode, std::string const& pattern = "");
explicit Selector(ModeT mode, std::string pattern = "");
template <class = void>
bool
@@ -51,9 +52,9 @@ public:
//------------------------------------------------------------------------------
template <class>
Selector::Selector(ModeT mode, std::string const& pattern) : mode_(mode), pat_(pattern)
Selector::Selector(ModeT mode, std::string pattern) : mode_(mode), pat_(std::move(pattern))
{
if (mode_ == ModeT::Automatch && pattern.empty())
if (mode_ == ModeT::Automatch && pat_.empty())
mode_ = ModeT::All;
}

View File

@@ -6,6 +6,10 @@
#include <xrpl/beast/unit_test/results.h>
#include <xrpl/beast/unit_test/runner.h>
#include <xrpl/beast/unit_test/suite_info.h>
#include <string>
#include <utility>
namespace beast::unit_test {

View File

@@ -5,18 +5,21 @@
#pragma once
#include <xrpl/beast/unit_test/amount.h>
#include <xrpl/beast/unit_test/recorder.h>
#include <xrpl/beast/unit_test/runner.h>
#include <xrpl/beast/unit_test/suite_info.h>
#include <boost/lexical_cast.hpp>
#include <boost/optional.hpp>
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <string>
#include <utility>
#include <vector>
namespace beast::unit_test {
@@ -48,7 +51,7 @@ private:
std::size_t cases = 0;
std::size_t total = 0;
std::size_t failed = 0;
typename clock_type::time_point start = clock_type::now();
clock_type::time_point start = clock_type::now();
explicit SuiteResults(std::string name = "") : name(std::move(name))
{
@@ -60,7 +63,7 @@ private:
struct Results
{
using run_time = std::pair<std::string, typename clock_type::duration>;
using run_time = std::pair<std::string, clock_type::duration>;
static constexpr auto kMaxTop = 10;
@@ -69,7 +72,7 @@ private:
std::size_t total = 0;
std::size_t failed = 0;
std::vector<run_time> top;
typename clock_type::time_point start = clock_type::now();
clock_type::time_point start = clock_type::now();
void
add(SuiteResults const& r);
@@ -77,8 +80,8 @@ private:
std::ostream& os_;
Results results_;
SuiteResults suite_results_;
CaseResults case_results_;
SuiteResults suiteResults_;
CaseResults caseResults_;
public:
Reporter(Reporter const&) = delete;
@@ -91,7 +94,7 @@ public:
private:
static std::string
fmtdur(typename clock_type::duration const& d);
fmtdur(clock_type::duration const& d);
void
onSuiteBegin(SuiteInfo const& info) override;
@@ -141,9 +144,7 @@ Reporter<Unused>::Results::add(SuiteResults const& r)
top.begin(),
top.end(),
elapsed,
[](run_time const& t1, typename clock_type::duration const& t2) {
return t1.second > t2;
});
[](run_time const& t1, clock_type::duration const& t2) { return t1.second > t2; });
if (iter != top.end())
{
if (top.size() == kMaxTop)
@@ -181,7 +182,7 @@ Reporter<Unused>::~Reporter()
template <class Unused>
std::string
Reporter<Unused>::fmtdur(typename clock_type::duration const& d)
Reporter<Unused>::fmtdur(clock_type::duration const& d)
{
using namespace std::chrono;
auto const ms = duration_cast<milliseconds>(d);
@@ -196,22 +197,22 @@ template <class Unused>
void
Reporter<Unused>::onSuiteBegin(SuiteInfo const& info)
{
suite_results_ = SuiteResults{info.fullName()};
suiteResults_ = SuiteResults{info.fullName()};
}
template <class Unused>
void
Reporter<Unused>::onSuiteEnd()
{
results_.add(suite_results_);
results_.add(suiteResults_);
}
template <class Unused>
void
Reporter<Unused>::onCaseBegin(std::string const& name)
{
case_results_ = CaseResults(name);
os_ << suite_results_.name << (case_results_.name.empty() ? "" : (" " + case_results_.name))
caseResults_ = CaseResults(name);
os_ << suiteResults_.name << (caseResults_.name.empty() ? "" : (" " + caseResults_.name))
<< std::endl;
}
@@ -219,23 +220,23 @@ template <class Unused>
void
Reporter<Unused>::onCaseEnd()
{
suite_results_.add(case_results_);
suiteResults_.add(caseResults_);
}
template <class Unused>
void
Reporter<Unused>::onPass()
{
++case_results_.total;
++caseResults_.total;
}
template <class Unused>
void
Reporter<Unused>::onFail(std::string const& reason)
{
++case_results_.failed;
++case_results_.total;
os_ << "#" << case_results_.total << " failed" << (reason.empty() ? "" : ": ") << reason
++caseResults_.failed;
++caseResults_.total;
os_ << "#" << caseResults_.total << " failed" << (reason.empty() ? "" : ": ") << reason
<< std::endl;
}

View File

@@ -6,6 +6,7 @@
#include <xrpl/beast/unit_test/detail/const_container.h>
#include <cstddef>
#include <string>
#include <utility>
#include <vector>

View File

@@ -10,6 +10,8 @@
#include <boost/lexical_cast.hpp>
#include <boost/throw_exception.hpp>
#include <exception>
#include <memory>
#include <ostream>
#include <sstream>
#include <string>
@@ -634,7 +636,7 @@ Suite::run(Runner& r)
#define BEAST_DEFINE_TESTSUITE_MANUAL_PRIO(Class, Module, Library, Priority)
#else
#include <xrpl/beast/unit_test/global_suites.h>
#include <xrpl/beast/unit_test/global_suites.h> // IWYU pragma: keep
#define BEAST_DEFINE_TESTSUITE(Class, Module, Library) \
BEAST_DEFINE_TESTSUITE_INSERT(Class, Module, Library, false, 0)
#define BEAST_DEFINE_TESTSUITE_MANUAL(Class, Module, Library) \

View File

@@ -4,9 +4,9 @@
#pragma once
#include <cstring>
#include <functional>
#include <string>
#include <tuple>
#include <utility>
namespace beast::unit_test {

View File

@@ -10,8 +10,9 @@
#include <boost/assert.hpp>
#include <set>
#include <typeindex>
#include <unordered_set>
#include <string> // IWYU pragma: keep
#include <typeindex> // IWYU pragma: keep
#include <unordered_set> // IWYU pragma: keep
namespace beast::unit_test {

View File

@@ -6,7 +6,9 @@
#include <xrpl/beast/unit_test/suite.h>
#include <exception>
#include <functional>
#include <string>
#include <thread>
#include <utility>
@@ -43,7 +45,10 @@ 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 = [f = std::forward<F>(f),
... args = std::forward<Args>(args)]() mutable {
std::invoke(f, args...);
};
t_ = std::thread(&Thread::run, this, std::move(b));
}

View File

@@ -3,7 +3,10 @@
#include <xrpl/beast/utility/instrumentation.h>
#include <cstdint>
#include <ostream>
#include <sstream>
#include <string>
#include <type_traits>
namespace beast {
@@ -105,12 +108,12 @@ public:
};
#ifndef __INTELLISENSE__
static_assert(!std::is_default_constructible_v<Sink>, "");
static_assert(!std::is_copy_constructible_v<Sink>, "");
static_assert(!std::is_move_constructible_v<Sink>, "");
static_assert(!std::is_copy_assignable_v<Sink>, "");
static_assert(!std::is_move_assignable_v<Sink>, "");
static_assert(std::is_nothrow_destructible_v<Sink>, "");
static_assert(!std::is_default_constructible_v<Sink>);
static_assert(!std::is_copy_constructible_v<Sink>);
static_assert(!std::is_move_constructible_v<Sink>);
static_assert(!std::is_copy_assignable_v<Sink>);
static_assert(!std::is_move_assignable_v<Sink>);
static_assert(std::is_nothrow_destructible_v<Sink>);
#endif
/** Returns a Sink which does nothing. */
@@ -161,12 +164,12 @@ public:
};
#ifndef __INTELLISENSE__
static_assert(!std::is_default_constructible_v<ScopedStream>, "");
static_assert(std::is_copy_constructible_v<ScopedStream>, "");
static_assert(std::is_move_constructible_v<ScopedStream>, "");
static_assert(!std::is_copy_assignable_v<ScopedStream>, "");
static_assert(!std::is_move_assignable_v<ScopedStream>, "");
static_assert(std::is_nothrow_destructible_v<ScopedStream>, "");
static_assert(!std::is_default_constructible_v<ScopedStream>);
static_assert(std::is_copy_constructible_v<ScopedStream>);
static_assert(std::is_move_constructible_v<ScopedStream>);
static_assert(!std::is_copy_assignable_v<ScopedStream>);
static_assert(!std::is_move_assignable_v<ScopedStream>);
static_assert(std::is_nothrow_destructible_v<ScopedStream>);
#endif
//--------------------------------------------------------------------------
@@ -243,12 +246,12 @@ public:
};
#ifndef __INTELLISENSE__
static_assert(std::is_default_constructible_v<Stream>, "");
static_assert(std::is_copy_constructible_v<Stream>, "");
static_assert(std::is_move_constructible_v<Stream>, "");
static_assert(!std::is_copy_assignable_v<Stream>, "");
static_assert(!std::is_move_assignable_v<Stream>, "");
static_assert(std::is_nothrow_destructible_v<Stream>, "");
static_assert(std::is_default_constructible_v<Stream>);
static_assert(std::is_copy_constructible_v<Stream>);
static_assert(std::is_move_constructible_v<Stream>);
static_assert(!std::is_copy_assignable_v<Stream>);
static_assert(!std::is_move_assignable_v<Stream>);
static_assert(std::is_nothrow_destructible_v<Stream>);
#endif
//--------------------------------------------------------------------------
@@ -326,12 +329,12 @@ public:
};
#ifndef __INTELLISENSE__
static_assert(!std::is_default_constructible_v<Journal>, "");
static_assert(std::is_copy_constructible_v<Journal>, "");
static_assert(std::is_move_constructible_v<Journal>, "");
static_assert(std::is_copy_assignable_v<Journal>, "");
static_assert(std::is_move_assignable_v<Journal>, "");
static_assert(std::is_nothrow_destructible_v<Journal>, "");
static_assert(!std::is_default_constructible_v<Journal>);
static_assert(std::is_copy_constructible_v<Journal>);
static_assert(std::is_move_constructible_v<Journal>);
static_assert(std::is_copy_assignable_v<Journal>);
static_assert(std::is_move_assignable_v<Journal>);
static_assert(std::is_nothrow_destructible_v<Journal>);
#endif
//------------------------------------------------------------------------------
@@ -411,9 +414,9 @@ class BasicLogstream : public std::basic_ostream<CharT, Traits>
{
using char_type = CharT;
using traits_type = Traits;
using int_type = typename traits_type::int_type;
using pos_type = typename traits_type::pos_type;
using off_type = typename traits_type::off_type;
using int_type = traits_type::int_type;
using pos_type = traits_type::pos_type;
using off_type = traits_type::off_type;
detail::LogStreamBuf<CharT, Traits> buf_;

View File

@@ -3,8 +3,10 @@
#include <xrpl/beast/core/List.h>
#include <mutex>
#include <ostream>
#include <sstream>
#include <string>
#include <utility>
namespace beast {

View File

@@ -2,6 +2,7 @@
#include <xrpl/beast/utility/Journal.h>
#include <string>
#include <utility>
namespace beast {

View File

@@ -26,9 +26,7 @@ struct Zero
explicit Zero() = default;
};
namespace {
constexpr Zero kZero{};
} // namespace
inline constexpr Zero kZero{};
/** Default implementation of signum calls the method on the class. */
template <typename T>

View File

@@ -11,6 +11,8 @@
// Macros below are copied from antithesis_sdk.h and slightly simplified
// The duplication is because Visual Studio 2019 cannot compile that header
// even with the option -Zc:__cplusplus added.
// NOTE: cond must not contain bare commas outside () or []. Commas inside {}
// are not protected by the preprocessor and would be parsed as extra arguments.
#define ALWAYS(cond, message, ...) assert((message) && (cond))
#define ALWAYS_OR_UNREACHABLE(cond, message) assert((message) && (cond))
#define SOMETIMES(cond, message, ...)
@@ -22,6 +24,8 @@
#define XRPL_ASSERT_PARTS(cond, function, description, ...) \
XRPL_ASSERT(cond, function " : " description)
#define XRPL_ASSERT_IF(guard, cond, message) XRPL_ASSERT(!(guard) || (cond), message)
// How to use the instrumentation macros:
//
// * XRPL_ASSERT if cond must be true but the line might not be reached during
@@ -29,6 +33,14 @@
// * XRPL_ASSERT_PARTS is for convenience, and works like XRPL_ASSERT, but
// splits the message param into "function" and "description", then joins
// them with " : " before passing to XRPL_ASSERT.
// * XRPL_ASSERT_IF(guard, cond, message) asserts the implication
// `guard => cond`: it can only fail when guard is true (e.g. an amendment
// is enabled) and cond is false. Unlike `if (guard) XRPL_ASSERT(...)`, the
// assertion site is always evaluated, so the fuzzer registers it
// unconditionally; cond itself is short-circuited and only evaluated when
// guard is true. NOTE: do not rely on side effects in guard — in release
// builds the assertion body is stripped, and the compiler may optimize away
// a side-effect-free guard entirely.
// * ALWAYS if cond must be true _and_ the line must be reached during fuzzing.
// Same like `assert` in normal use.
// * REACHABLE if the line must be reached during fuzzing

View File

@@ -15,6 +15,6 @@ struct MaybeConst
/** Alias for omitting `typename`. */
template <bool IsConst, class T>
using maybe_const_t = typename MaybeConst<IsConst, T>::type;
using maybe_const_t = MaybeConst<IsConst, T>::type;
} // namespace beast

View File

@@ -1,11 +1,8 @@
#pragma once
#include <xrpl/beast/utility/instrumentation.h>
#include <array>
#include <cstdint>
#include <cstring>
#include <type_traits>
namespace beast {
@@ -13,10 +10,10 @@ template <class Generator>
void
rngfill(void* const buffer, std::size_t const bytes, Generator& g)
{
using result_type = typename Generator::result_type;
using result_type = Generator::result_type;
constexpr std::size_t kResultSize = sizeof(result_type);
std::uint8_t* const bufferStart = static_cast<std::uint8_t*>(buffer);
auto* const bufferStart = static_cast<std::uint8_t*>(buffer);
std::size_t const completeIterations = bytes / kResultSize;
std::size_t const bytesRemaining = bytes % kResultSize;
@@ -35,16 +32,14 @@ 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>
void
rngfill(std::array<std::uint8_t, N>& a, Generator& g)
requires(N % sizeof(typename Generator::result_type) == 0)
{
using result_type = typename Generator::result_type;
using result_type = Generator::result_type;
auto i = N / sizeof(result_type);
result_type* p = reinterpret_cast<result_type*>(a.data());
auto* p = reinterpret_cast<result_type*>(a.data());
while (i--)
*p++ = g();
}

View File

@@ -4,8 +4,12 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/conditions/detail/utils.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <set>
#include <system_error>
#include <utility>
namespace xrpl::cryptoconditions {

View File

@@ -4,6 +4,11 @@
#include <xrpl/basics/Slice.h>
#include <xrpl/conditions/Condition.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <system_error>
namespace xrpl::cryptoconditions {
struct Fulfillment

View File

@@ -7,7 +7,11 @@
#include <xrpl/conditions/detail/error.h>
#include <xrpl/protocol/digest.h>
#include <cstddef>
#include <cstdint>
#include <memory>
#include <system_error>
#include <utility>
namespace xrpl::cryptoconditions {

View File

@@ -6,7 +6,10 @@
#include <boost/dynamic_bitset.hpp>
#include <cstddef>
#include <cstdint>
#include <limits>
#include <system_error>
// A collection of functions to decode binary blobs
// encoded with X.690 Distinguished Encoding Rules.

View File

@@ -6,9 +6,13 @@
#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <cstddef>
#include <optional>
#include <ostream>
#include <stdexcept>
#include <string>
#include <unordered_map>
#include <utility>
#include <vector>
namespace xrpl {
@@ -298,7 +302,8 @@ set(T& target, std::string const& name, Section const& section)
try
{
auto const val = section.get<T>(name);
if ((foundAndValid = val.has_value()))
foundAndValid = val.has_value();
if (foundAndValid)
target = *val;
}
catch (boost::bad_lexical_cast const&) // NOLINT(bugprone-empty-catch)

View File

@@ -0,0 +1,180 @@
#pragma once
namespace xrpl {
struct Sections
{
static constexpr auto kAmendments = "amendments";
static constexpr auto kAmendmentMajorityTime = "amendment_majority_time";
static constexpr auto kBetaRpcApi = "beta_rpc_api";
static constexpr auto kClusterNodes = "cluster_nodes";
static constexpr auto kCompression = "compression";
static constexpr auto kCrawl = "crawl";
static constexpr auto kDatabasePath = "database_path";
static constexpr auto kDebugLogfile = "debug_logfile";
static constexpr auto kElbSupport = "elb_support";
static constexpr auto kFeatures = "features";
static constexpr auto kFeeDefault = "fee_default";
static constexpr auto kFetchDepth = "fetch_depth";
static constexpr auto kHashrouter = "hashrouter";
static constexpr auto kImportNodeDatabase = "import_db";
static constexpr auto kInsight = "insight";
static constexpr auto kIoWorkers = "io_workers";
static constexpr auto kIps = "ips";
static constexpr auto kIpsFixed = "ips_fixed";
static constexpr auto kLedgerHistory = "ledger_history";
static constexpr auto kLedgerReplay = "ledger_replay";
static constexpr auto kLedgerTxTables = "ledger_tx_tables";
static constexpr auto kMaxTransactions = "max_transactions";
static constexpr auto kNetworkId = "network_id";
static constexpr auto kNetworkQuorum = "network_quorum";
static constexpr auto kNodeDatabase = "node_db";
static constexpr auto kNodeSeed = "node_seed";
static constexpr auto kNodeSize = "node_size";
static constexpr auto kOverlay = "overlay";
static constexpr auto kPathSearch = "path_search";
static constexpr auto kPathSearchFast = "path_search_fast";
static constexpr auto kPathSearchMax = "path_search_max";
static constexpr auto kPathSearchOld = "path_search_old";
static constexpr auto kPeerPrivate = "peer_private";
static constexpr auto kPeersInMax = "peers_in_max";
static constexpr auto kPeersMax = "peers_max";
static constexpr auto kPeersOutMax = "peers_out_max";
static constexpr auto kPerf = "perf";
static constexpr auto kPortGrpc = "port_grpc";
static constexpr auto kPortPeer = "port_peer";
static constexpr auto kPortRpc = "port_rpc";
static constexpr auto kPortWs = "port_ws";
static constexpr auto kPortWssAdmin = "port_wss_admin";
static constexpr auto kPrefetchWorkers = "prefetch_workers";
static constexpr auto kReduceRelay = "reduce_relay";
static constexpr auto kRelationalDb = "relational_db";
static constexpr auto kRelayProposals = "relay_proposals";
static constexpr auto kRelayValidations = "relay_validations";
static constexpr auto kRpcStartup = "rpc_startup";
static constexpr auto kServer = "server";
static constexpr auto kServerDomain = "server_domain";
static constexpr auto kSigningSupport = "signing_support";
static constexpr auto kSntp = "sntp_servers";
static constexpr auto kSqdb = "sqdb";
static constexpr auto kSqlite = "sqlite";
static constexpr auto kSslVerify = "ssl_verify";
static constexpr auto kSslVerifyDir = "ssl_verify_dir";
static constexpr auto kSslVerifyFile = "ssl_verify_file";
static constexpr auto kSweepInterval = "sweep_interval";
static constexpr auto kTransactionQueue = "transaction_queue";
static constexpr auto kValidationSeed = "validation_seed";
static constexpr auto kValidatorKeys = "validator_keys";
static constexpr auto kValidatorKeyRevocation = "validator_key_revocation";
static constexpr auto kValidatorListKeys = "validator_list_keys";
static constexpr auto kValidatorListSites = "validator_list_sites";
static constexpr auto kValidatorListThreshold = "validator_list_threshold";
static constexpr auto kValidatorToken = "validator_token";
static constexpr auto kValidators = "validators";
static constexpr auto kValidatorsFile = "validators_file";
static constexpr auto kVetoAmendments = "veto_amendments";
static constexpr auto kVl = "vl";
static constexpr auto kVoting = "voting";
static constexpr auto kWorkers = "workers";
};
struct Keys
{
static constexpr auto kAccountReserve = "account_reserve";
static constexpr auto kAddress = "address";
static constexpr auto kAdmin = "admin";
static constexpr auto kAdminPassword = "admin_password";
static constexpr auto kAdminUser = "admin_user";
static constexpr auto kAdvisoryDelete = "advisory_delete";
static constexpr auto kAgeThresholdSeconds = "age_threshold_seconds";
static constexpr auto kBackOff = "backOff";
static constexpr auto kBackOffMilliseconds = "back_off_milliseconds";
static constexpr auto kBackend = "backend";
static constexpr auto kBbtOptions = "bbt_options";
static constexpr auto kBgThreads = "bg_threads";
static constexpr auto kBlockSize = "block_size";
static constexpr auto kCacheAge = "cache_age";
static constexpr auto kCacheMb = "cache_mb";
static constexpr auto kCacheSize = "cache_size";
static constexpr auto kClientMaxWindowBits = "client_max_window_bits";
static constexpr auto kClientNoContextTakeover = "client_no_context_takeover";
static constexpr auto kCompressLevel = "compress_level";
static constexpr auto kCounts = "counts";
static constexpr auto kDeleteBatch = "delete_batch";
static constexpr auto kEarliestSeq = "earliest_seq";
static constexpr auto kFastLoad = "fast_load";
static constexpr auto kFileSizeMb = "file_size_mb";
static constexpr auto kFileSizeMult = "file_size_mult";
static constexpr auto kFilterBits = "filter_bits";
static constexpr auto kFilterFull = "filter_full";
static constexpr auto kHardSet = "hard_set";
static constexpr auto kHighThreads = "high_threads";
static constexpr auto kHoldTime = "hold_time";
static constexpr auto kIp = "ip";
static constexpr auto kJournalMode = "journal_mode";
static constexpr auto kJournalSizeLimit = "journal_size_limit";
static constexpr auto kLedgersInQueue = "ledgers_in_queue";
static constexpr auto kLimit = "limit";
static constexpr auto kLogInterval = "log_interval";
static constexpr auto kMaxDivergedTime = "max_diverged_time";
static constexpr auto kMaxLedgerCountsToStore = "max_ledger_counts_to_store";
static constexpr auto kMaxUnknownTime = "max_unknown_time";
static constexpr auto kMaximumTxnInLedger = "maximum_txn_in_ledger";
static constexpr auto kMaximumTxnPerAccount = "maximum_txn_per_account";
static constexpr auto kMemoryLevel = "memory_level";
static constexpr auto kMinLedgersToComputeSizeLimit = "min_ledgers_to_compute_size_limit";
static constexpr auto kMinimumEscalationMultiplier = "minimum_escalation_multiplier";
static constexpr auto kMinimumLastLedgerBuffer = "minimum_last_ledger_buffer";
static constexpr auto kMinimumQueueSize = "minimum_queue_size";
static constexpr auto kMinimumTxnInLedger = "minimum_txn_in_ledger";
static constexpr auto kMinimumTxnInLedgerStandalone = "minimum_txn_in_ledger_standalone";
static constexpr auto kNormalConsensusIncreasePercent = "normal_consensus_increase_percent";
static constexpr auto kNudbBlockSize = "nudb_block_size";
static constexpr auto kOnlineDelete = "online_delete";
static constexpr auto kOpenFiles = "open_files";
static constexpr auto kOptions = "options";
static constexpr auto kOverlay = "overlay";
static constexpr auto kOwnerReserve = "owner_reserve";
static constexpr auto kPageSize = "page_size";
static constexpr auto kPassword = "password";
static constexpr auto kPath = "path";
static constexpr auto kPermessageDeflate = "permessage_deflate";
static constexpr auto kPort = "port";
static constexpr auto kPrefix = "prefix";
static constexpr auto kProtocol = "protocol";
static constexpr auto kRecoveryWaitSeconds = "recovery_wait_seconds";
static constexpr auto kReferenceFee = "reference_fee";
static constexpr auto kRelayTime = "relay_time";
static constexpr auto kRetrySequencePercent = "retry_sequence_percent";
static constexpr auto kRqBundle = "rq_bundle";
static constexpr auto kSafetyLevel = "safety_level";
static constexpr auto kSecureGateway = "secure_gateway";
static constexpr auto kSendQueueLimit = "send_queue_limit";
static constexpr auto kServer = "server";
static constexpr auto kServerMaxWindowBits = "server_max_window_bits";
static constexpr auto kServerNoContextTakeover = "server_no_context_takeover";
static constexpr auto kSlowConsensusDecreasePercent = "slow_consensus_decrease_percent";
static constexpr auto kSslCert = "ssl_cert";
static constexpr auto kSslCertChain = "ssl_cert_chain";
static constexpr auto kSslChain = "ssl_chain";
static constexpr auto kSslCiphers = "ssl_ciphers";
static constexpr auto kSslClientCa = "ssl_client_ca";
static constexpr auto kSslKey = "ssl_key";
static constexpr auto kSynchronous = "synchronous";
static constexpr auto kTargetTxnInLedger = "target_txn_in_ledger";
static constexpr auto kTempStore = "temp_store";
static constexpr auto kTxEnable = "tx_enable";
static constexpr auto kTxMetrics = "tx_metrics";
static constexpr auto kTxMinPeers = "tx_min_peers";
static constexpr auto kTxRelayPercentage = "tx_relay_percentage";
static constexpr auto kType = "type";
static constexpr auto kUniversalCompaction = "universal_compaction";
static constexpr auto kUnl = "unl";
static constexpr auto kUseTxTables = "use_tx_tables";
static constexpr auto kUser = "user";
static constexpr auto kVpBaseSquelchEnable = "vp_base_squelch_enable";
static constexpr auto kVpBaseSquelchMaxSelectedPeers = "vp_base_squelch_max_selected_peers";
static constexpr auto kVpEnable = "vp_enable";
};
} // namespace xrpl

View File

@@ -1,11 +1,14 @@
#pragma once
#include <xrpl/basics/Log.h>
#include <xrpl/beast/utility/Journal.h>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <optional>
#include <type_traits>
namespace xrpl {

View File

@@ -47,7 +47,7 @@ inline bool
JobQueue::Coro::post()
{
{
std::scoped_lock const lk(mutex_run_);
std::scoped_lock const lk(mutexRun_);
running_ = true;
}
@@ -58,7 +58,7 @@ JobQueue::Coro::post()
}
// The coroutine will not run. Clean up running_.
std::scoped_lock const lk(mutex_run_);
std::scoped_lock const lk(mutexRun_);
running_ = false;
cv_.notify_all();
return false;
@@ -68,7 +68,7 @@ inline void
JobQueue::Coro::resume()
{
{
std::scoped_lock const lk(mutex_run_);
std::scoped_lock const lk(mutexRun_);
running_ = true;
}
{
@@ -92,7 +92,7 @@ JobQueue::Coro::resume()
}
detail::getLocalValues().release();
detail::getLocalValues().reset(saved);
std::scoped_lock const lk(mutex_run_);
std::scoped_lock const lk(mutexRun_);
running_ = false;
cv_.notify_all();
}
@@ -127,7 +127,7 @@ JobQueue::Coro::expectEarlyExit()
inline void
JobQueue::Coro::join()
{
std::unique_lock<std::mutex> lk(mutex_run_);
std::unique_lock<std::mutex> lk(mutexRun_);
cv_.wait(lk, [this]() { return !running_; });
}

View File

@@ -4,10 +4,16 @@
#include <xrpl/basics/UnorderedContainers.h>
#include <xrpl/basics/base_uint.h>
#include <xrpl/basics/chrono.h>
#include <xrpl/basics/hardened_hash.h>
#include <xrpl/beast/container/aged_unordered_map.h>
#include <chrono>
#include <cstdint>
#include <mutex>
#include <optional>
#include <set>
#include <type_traits>
#include <utility>
namespace xrpl {
@@ -19,12 +25,14 @@ enum class HashRouterFlags : std::uint16_t {
HELD = 0x08, // Held by LedgerMaster after potential processing failure
TRUSTED = 0x10, // Comes from a trusted source
// Private flags (used internally in apply.cpp)
// Do not attempt to read, set, or reuse.
// Private flags. Each group is owned by one file; do not read, set, or
// reuse a flag outside the file noted.
// Used in apply.cpp
PRIVATE1 = 0x0100,
PRIVATE2 = 0x0200,
PRIVATE3 = 0x0400,
PRIVATE4 = 0x0800,
// Used in EscrowFinish.cpp
PRIVATE5 = 0x1000,
PRIVATE6 = 0x2000
};
@@ -119,7 +127,7 @@ private:
}
[[nodiscard]] HashRouterFlags
getFlags(void) const
getFlags() const
{
return flags_;
}

View File

@@ -2,9 +2,14 @@
#include <xrpl/basics/CountedObject.h>
#include <xrpl/core/ClosureCounter.h>
#include <xrpl/core/LoadEvent.h>
#include <xrpl/core/LoadMonitor.h>
#include <chrono>
#include <cstdint>
#include <functional>
#include <memory>
#include <string>
namespace xrpl {
@@ -127,7 +132,7 @@ private:
std::function<void()> job_;
std::shared_ptr<LoadEvent> loadEvent_;
std::string name_;
clock_type::time_point queue_time_;
clock_type::time_point queueTime_;
};
using JobCounter = ClosureCounter<void>;

View File

@@ -3,7 +3,6 @@
#include <xrpl/basics/LocalValue.h>
#include <xrpl/core/ClosureCounter.h>
#include <xrpl/core/JobTypeData.h>
#include <xrpl/core/JobTypes.h>
#include <xrpl/core/detail/Workers.h>
#include <xrpl/json/json_value.h>
@@ -12,10 +11,27 @@
// `boost/context/pooled_fixedsize_stack.hpp`, whose `.malloc()` / `.free()`
// member calls on `boost::pool` collide with MSVC's `_CRTDBG_MAP_ALLOC` macros
// in Debug builds (see cmake/XrplCompiler.cmake).
#include <xrpl/beast/insight/Collector.h>
#include <xrpl/beast/insight/Gauge.h>
#include <xrpl/beast/insight/Hook.h>
#include <xrpl/beast/utility/Journal.h>
#include <xrpl/core/Job.h>
#include <xrpl/core/LoadEvent.h>
#include <boost/context/protected_fixedsize_stack.hpp>
#include <boost/coroutine2/coroutine.hpp>
#include <atomic>
#include <chrono>
#include <condition_variable>
#include <cstdint>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <set>
#include <string>
#include <type_traits>
namespace xrpl {
@@ -52,7 +68,7 @@ public:
std::string name_;
bool running_{false};
std::mutex mutex_;
std::mutex mutex_run_;
std::mutex mutexRun_;
std::condition_variable cv_;
boost::coroutines2::coroutine<void>::push_type* yield_{};
boost::coroutines2::coroutine<void>::pull_type coro_;
@@ -112,7 +128,7 @@ public:
resume();
/** Returns true if the Coro is still runnable (has not returned). */
bool
[[nodiscard]] bool
runnable() const;
/** Once called, the Coro allows early exit without an assert. */
@@ -138,16 +154,14 @@ public:
@param type The type of job.
@param name Name of the job.
@param jobHandler Lambda with signature void (Job&). Called when the
job is executed.
@param jobHandler Callable with signature void(). Called when the job is executed.
@return true if jobHandler added to queue.
*/
template <
typename JobHandler,
typename = std::enable_if_t<std::is_same_v<decltype(std::declval<JobHandler&&>()()), void>>>
template <typename JobHandler>
bool
addJob(JobType type, std::string const& name, JobHandler&& jobHandler)
requires(std::is_void_v<std::invoke_result_t<JobHandler>>)
{
if (auto optionalCountedJob = jobCounter_.wrap(std::forward<JobHandler>(jobHandler)))
{
@@ -246,7 +260,7 @@ private:
// Statistics tracking
perf::PerfLog& perfLog_;
beast::insight::Collector::ptr collector_;
beast::insight::Gauge job_count_;
beast::insight::Gauge jobCount_;
beast::insight::Hook hook_;
std::condition_variable cv_;
@@ -384,7 +398,7 @@ private:
} // namespace xrpl
#include <xrpl/core/Coro.ipp>
#include <xrpl/core/Coro.ipp> // IWYU pragma: keep
namespace xrpl {

View File

@@ -2,7 +2,10 @@
#include <xrpl/basics/Log.h>
#include <xrpl/beast/insight/Collector.h>
#include <xrpl/beast/insight/Event.h>
#include <xrpl/core/Job.h>
#include <xrpl/core/JobTypeInfo.h>
#include <xrpl/core/LoadMonitor.h>
#include <utility>

Some files were not shown because too many files have changed in this diff Show More