mirror of
https://github.com/XRPLF/rippled.git
synced 2026-06-05 09:46:53 +00:00
Compare commits
2 Commits
3.2.0-b7
...
vlntb/boun
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8a4162a9a9 | ||
|
|
0639b464e5 |
95
.clang-tidy
95
.clang-tidy
@@ -1,11 +1,13 @@
|
||||
---
|
||||
# This entire group of checks was applied to all cpp files but not all header files.
|
||||
# ---
|
||||
Checks: "-*,
|
||||
bugprone-argument-comment,
|
||||
bugprone-assert-side-effect,
|
||||
bugprone-bad-signal-to-kill-thread,
|
||||
bugprone-bool-pointer-implicit-conversion,
|
||||
bugprone-capturing-this-in-member-variable,
|
||||
bugprone-casting-through-void,
|
||||
bugprone-capturing-this-in-member-variable,
|
||||
bugprone-chained-comparison,
|
||||
bugprone-compare-pointer-to-member-virtual-function,
|
||||
bugprone-copy-constructor-init,
|
||||
@@ -24,10 +26,10 @@ Checks: "-*,
|
||||
bugprone-lambda-function-name,
|
||||
bugprone-macro-parentheses,
|
||||
bugprone-macro-repeated-side-effects,
|
||||
bugprone-misleading-setter-of-reference,
|
||||
bugprone-misplaced-operator-in-strlen-in-alloc,
|
||||
bugprone-misplaced-pointer-arithmetic-in-alloc,
|
||||
bugprone-misplaced-widening-cast,
|
||||
bugprone-misleading-setter-of-reference,
|
||||
bugprone-move-forwarding-reference,
|
||||
bugprone-multi-level-implicit-pointer-conversion,
|
||||
bugprone-multiple-new-in-one-expression,
|
||||
@@ -73,10 +75,10 @@ Checks: "-*,
|
||||
bugprone-unhandled-self-assignment,
|
||||
bugprone-unique-ptr-array-mismatch,
|
||||
bugprone-unsafe-functions,
|
||||
bugprone-unused-local-non-trivial-variable,
|
||||
bugprone-use-after-move,
|
||||
bugprone-unused-raii,
|
||||
bugprone-unused-return-value,
|
||||
bugprone-use-after-move,
|
||||
bugprone-unused-local-non-trivial-variable,
|
||||
bugprone-virtual-near-miss,
|
||||
cppcoreguidelines-init-variables,
|
||||
cppcoreguidelines-misleading-capture-default-by-value,
|
||||
@@ -88,7 +90,6 @@ Checks: "-*,
|
||||
cppcoreguidelines-use-enum-class,
|
||||
cppcoreguidelines-virtual-class-destructor,
|
||||
hicpp-ignored-remove-result,
|
||||
llvm-namespace-comment,
|
||||
misc-const-correctness,
|
||||
misc-definitions-in-headers,
|
||||
misc-header-include-cycle,
|
||||
@@ -100,7 +101,6 @@ Checks: "-*,
|
||||
misc-unused-alias-decls,
|
||||
misc-unused-using-decls,
|
||||
modernize-concat-nested-namespaces,
|
||||
modernize-deprecated-headers,
|
||||
modernize-make-shared,
|
||||
modernize-make-unique,
|
||||
modernize-pass-by-value,
|
||||
@@ -116,6 +116,8 @@ Checks: "-*,
|
||||
modernize-use-starts-ends-with,
|
||||
modernize-use-std-numbers,
|
||||
modernize-use-using,
|
||||
modernize-deprecated-headers,
|
||||
llvm-namespace-comment,
|
||||
performance-faster-string-find,
|
||||
performance-for-range-copy,
|
||||
performance-implicit-conversion-in-loop,
|
||||
@@ -135,7 +137,6 @@ Checks: "-*,
|
||||
readability-duplicate-include,
|
||||
readability-else-after-return,
|
||||
readability-enum-initial-value,
|
||||
readability-identifier-naming,
|
||||
readability-implicit-bool-conversion,
|
||||
readability-make-member-function-const,
|
||||
readability-math-missing-parentheses,
|
||||
@@ -153,52 +154,52 @@ Checks: "-*,
|
||||
readability-use-std-min-max
|
||||
"
|
||||
# ---
|
||||
# other checks that have issues that need to be resolved:
|
||||
#
|
||||
# readability-inconsistent-declaration-parameter-name, # in this codebase this check will break a lot of arg names
|
||||
# readability-static-accessed-through-instance, # this check is probably unnecessary. it makes the code less readable
|
||||
# readability-identifier-naming, # https://github.com/XRPLF/rippled/pull/6571
|
||||
# ---
|
||||
|
||||
#
|
||||
CheckOptions:
|
||||
readability-braces-around-statements.ShortStatementLines: 2
|
||||
# readability-identifier-naming.MacroDefinitionCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassCase: CamelCase
|
||||
# readability-identifier-naming.StructCase: CamelCase
|
||||
# readability-identifier-naming.UnionCase: CamelCase
|
||||
# readability-identifier-naming.EnumCase: CamelCase
|
||||
# readability-identifier-naming.EnumConstantCase: CamelCase
|
||||
# readability-identifier-naming.ScopedEnumConstantCase: CamelCase
|
||||
# readability-identifier-naming.GlobalConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.GlobalConstantPrefix: "k"
|
||||
# readability-identifier-naming.GlobalVariableCase: CamelCase
|
||||
# readability-identifier-naming.GlobalVariablePrefix: "g"
|
||||
# readability-identifier-naming.ConstexprFunctionCase: camelBack
|
||||
# readability-identifier-naming.ConstexprMethodCase: camelBack
|
||||
# readability-identifier-naming.ClassMethodCase: camelBack
|
||||
# readability-identifier-naming.ClassMemberCase: camelBack
|
||||
# readability-identifier-naming.ClassConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.ClassConstantPrefix: "k"
|
||||
# readability-identifier-naming.StaticConstantCase: UPPER_CASE
|
||||
# readability-identifier-naming.StaticConstantPrefix: "k"
|
||||
# readability-identifier-naming.StaticVariableCase: UPPER_CASE
|
||||
# readability-identifier-naming.StaticVariablePrefix: "k"
|
||||
# readability-identifier-naming.ConstexprVariableCase: UPPER_CASE
|
||||
# readability-identifier-naming.ConstexprVariablePrefix: "k"
|
||||
# readability-identifier-naming.LocalConstantCase: camelBack
|
||||
# readability-identifier-naming.LocalVariableCase: camelBack
|
||||
# readability-identifier-naming.TemplateParameterCase: CamelCase
|
||||
# readability-identifier-naming.ParameterCase: camelBack
|
||||
# readability-identifier-naming.FunctionCase: camelBack
|
||||
# readability-identifier-naming.MemberCase: camelBack
|
||||
# readability-identifier-naming.PrivateMemberSuffix: _
|
||||
# readability-identifier-naming.ProtectedMemberSuffix: _
|
||||
# readability-identifier-naming.PublicMemberSuffix: ""
|
||||
# readability-identifier-naming.FunctionIgnoredRegexp: ".*tag_invoke.*"
|
||||
bugprone-unsafe-functions.ReportMoreUnsafeFunctions: true
|
||||
bugprone-unused-return-value.CheckedReturnTypes: ::std::error_code;::std::error_condition;::std::errc
|
||||
|
||||
misc-include-cleaner.IgnoreHeaders: ".*/(detail|impl)/.*;.*fwd\\.h(pp)?;time.h;stdlib.h;sqlite3.h;netinet/in\\.h;sys/resource\\.h;sys/sysinfo\\.h;linux/sysinfo\\.h;__chrono/.*;bits/.*;_abort\\.h;boost/uuid/uuid_hash.hpp;boost/beast/core/flat_buffer\\.hpp;boost/beast/http/field\\.hpp;boost/beast/http/dynamic_body\\.hpp;boost/beast/http/message\\.hpp;boost/beast/http/read\\.hpp;boost/beast/http/write\\.hpp;openssl/obj_mac\\.h"
|
||||
|
||||
readability-braces-around-statements.ShortStatementLines: 2
|
||||
readability-identifier-naming.MacroDefinitionCase: UPPER_CASE
|
||||
readability-identifier-naming.ClassCase: CamelCase
|
||||
readability-identifier-naming.StructCase: CamelCase
|
||||
readability-identifier-naming.UnionCase: CamelCase
|
||||
readability-identifier-naming.EnumCase: CamelCase
|
||||
readability-identifier-naming.EnumConstantCase: CamelCase
|
||||
readability-identifier-naming.ScopedEnumConstantCase: CamelCase
|
||||
readability-identifier-naming.GlobalConstantCase: CamelCase
|
||||
readability-identifier-naming.GlobalConstantPrefix: "k"
|
||||
readability-identifier-naming.GlobalVariableCase: CamelCase
|
||||
readability-identifier-naming.GlobalVariablePrefix: "g"
|
||||
readability-identifier-naming.ConstexprFunctionCase: camelBack
|
||||
readability-identifier-naming.ConstexprMethodCase: camelBack
|
||||
readability-identifier-naming.ClassMethodCase: camelBack
|
||||
readability-identifier-naming.ClassMemberCase: camelBack
|
||||
readability-identifier-naming.ClassConstantCase: CamelCase
|
||||
readability-identifier-naming.ClassConstantPrefix: "k"
|
||||
readability-identifier-naming.StaticConstantCase: CamelCase
|
||||
readability-identifier-naming.StaticConstantPrefix: "k"
|
||||
readability-identifier-naming.StaticVariableCase: camelBack
|
||||
readability-identifier-naming.ConstexprVariableCase: camelBack
|
||||
readability-identifier-naming.LocalConstantCase: camelBack
|
||||
readability-identifier-naming.LocalVariableCase: camelBack
|
||||
readability-identifier-naming.TemplateParameterCase: CamelCase
|
||||
readability-identifier-naming.ParameterCase: camelBack
|
||||
readability-identifier-naming.FunctionCase: camelBack
|
||||
readability-identifier-naming.MemberCase: camelBack
|
||||
readability-identifier-naming.PrivateMemberCase: camelBack
|
||||
readability-identifier-naming.PrivateMemberSuffix: _
|
||||
readability-identifier-naming.ProtectedMemberCase: camelBack
|
||||
readability-identifier-naming.ProtectedMemberSuffix: _
|
||||
readability-identifier-naming.PublicMemberCase: camelBack
|
||||
readability-identifier-naming.PublicMemberSuffix: ""
|
||||
readability-identifier-naming.GlobalFunctionIgnoredRegexp: "^(to_string|hash_append|tuple_hash)$"
|
||||
|
||||
HeaderFilterRegex: '^.*/(test|xrpl|xrpld)/.*\.(h|hpp|ipp)$'
|
||||
#
|
||||
HeaderFilterRegex: '^.*/(test|xrpl|xrpld)/.*\.(h|hpp)$'
|
||||
ExcludeHeaderFilterRegex: '^.*/protocol_autogen/.*\.(h|hpp)$'
|
||||
WarningsAsErrors: "*"
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
# This file is sorted in reverse chronological order, with the most recent commits at the top.
|
||||
# The commits listed here are ignored by git blame, which is useful for formatting-only commits that would otherwise obscure the history of changes to a file.
|
||||
|
||||
# refactor: Enable clang-tidy `readability-identifier-naming` check (#6571)
|
||||
8995564ed6b9e453e144bb663303072a3c1ba305
|
||||
# refactor: Enable remaining clang-tidy `cppcoreguidelines` checks (#6538)
|
||||
72f4cb097f626b08b02fc3efcb4aa11cb2e7adb8
|
||||
# refactor: Rename system name from 'ripple' to 'xrpld' (#6347)
|
||||
|
||||
2
.github/scripts/rename/config.sh
vendored
2
.github/scripts/rename/config.sh
vendored
@@ -62,7 +62,7 @@ ${SED_COMMAND} -i 's@ripple/@xrpld/@g' src/test/core/Config_test.cpp
|
||||
${SED_COMMAND} -i 's/Rippled/File/g' src/test/core/Config_test.cpp
|
||||
|
||||
# Restore the old config file name in the code that maintains support for now.
|
||||
${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp
|
||||
${SED_COMMAND} -i 's/configLegacyName = "xrpld.cfg"/configLegacyName = "rippled.cfg"/g' src/xrpld/core/detail/Config.cpp
|
||||
|
||||
# Restore an URL.
|
||||
${SED_COMMAND} -i 's/connect-your-xrpld-to-the-xrp-test-net.html/connect-your-rippled-to-the-xrp-test-net.html/g' cfg/xrpld-example.cfg
|
||||
|
||||
2
.github/scripts/rename/docs.sh
vendored
2
.github/scripts/rename/docs.sh
vendored
@@ -90,7 +90,7 @@ ${SED_COMMAND} -i 's/www.ripple.com/www.xrpl.org/g' src/test/protocol/Seed_test.
|
||||
# Restore specific changes.
|
||||
${SED_COMMAND} -i 's@b5efcc/src/xrpld@b5efcc/src/ripple@' include/xrpl/protocol/README.md
|
||||
${SED_COMMAND} -i 's/dbPrefix_ = "xrpldb"/dbPrefix_ = "rippledb"/' src/xrpld/app/misc/SHAMapStoreImp.h # cspell: disable-line
|
||||
${SED_COMMAND} -i 's/kConfigLegacyName = "xrpld.cfg"/kConfigLegacyName = "rippled.cfg"/' src/xrpld/core/detail/Config.cpp
|
||||
${SED_COMMAND} -i 's/configLegacyName = "xrpld.cfg"/configLegacyName = "rippled.cfg"/' src/xrpld/core/detail/Config.cpp
|
||||
|
||||
popd
|
||||
echo "Renaming complete."
|
||||
|
||||
90
.github/scripts/strategy-matrix/generate.py
vendored
90
.github/scripts/strategy-matrix/generate.py
vendored
@@ -32,32 +32,7 @@ We will further set additional CMake arguments as follows:
|
||||
"""
|
||||
|
||||
|
||||
def build_config_name(os_entry: dict[str, str], platform: str, build_type: str) -> str:
|
||||
parts = [os_entry["distro_name"]]
|
||||
for key in ("distro_version", "compiler_name", "compiler_version"):
|
||||
if value := os_entry[key]:
|
||||
parts.append(value)
|
||||
parts.append("arm64" if "arm64" in platform else "amd64")
|
||||
parts.append(build_type.lower())
|
||||
return "-".join(parts)
|
||||
|
||||
|
||||
def generate_packaging_matrix(config: Config) -> list[dict]:
|
||||
"""Emit one entry per os entry with `package: true`. Architecture is
|
||||
hardcoded to linux/amd64 here (and the runner is hardcoded at the
|
||||
workflow level) until arm64 packaging is ready.
|
||||
"""
|
||||
return [
|
||||
{
|
||||
"artifact_name": f"xrpld-{build_config_name(os, 'linux/amd64', 'Release')}",
|
||||
"os": os,
|
||||
}
|
||||
for os in config.os
|
||||
if os.get("package", False)
|
||||
]
|
||||
|
||||
|
||||
def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
def generate_strategy_matrix(all: bool, config: Config) -> list:
|
||||
configurations = []
|
||||
for architecture, os, build_type, cmake_args in itertools.product(
|
||||
config.architecture, config.os, config.build_type, config.cmake_args
|
||||
@@ -97,7 +72,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
skip = False
|
||||
if (
|
||||
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
|
||||
and build_type == "Release"
|
||||
and build_type == "Debug"
|
||||
and architecture["platform"] == "linux/amd64"
|
||||
):
|
||||
skip = False
|
||||
@@ -115,9 +90,8 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
):
|
||||
cmake_args = f"-DUNIT_TEST_REFERENCE_FEE=1000 {cmake_args}"
|
||||
skip = False
|
||||
elif os["distro_version"] == "trixie":
|
||||
if (
|
||||
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-22"
|
||||
f"{os['compiler_name']}-{os['compiler_version']}" == "clang-20"
|
||||
and build_type == "Debug"
|
||||
and architecture["platform"] == "linux/amd64"
|
||||
):
|
||||
@@ -126,15 +100,14 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
continue
|
||||
|
||||
# RHEL:
|
||||
# - 9 using GCC 12: Debug and Release on linux/amd64
|
||||
# (Release is required for RPM packaging).
|
||||
# - 9 using GCC 12: Debug on linux/amd64.
|
||||
# - 10 using Clang: Release on linux/amd64.
|
||||
if os["distro_name"] == "rhel":
|
||||
skip = True
|
||||
if os["distro_version"] == "9":
|
||||
if (
|
||||
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
|
||||
and build_type in ["Debug", "Release"]
|
||||
and build_type == "Debug"
|
||||
and architecture["platform"] == "linux/amd64"
|
||||
):
|
||||
skip = False
|
||||
@@ -149,8 +122,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
continue
|
||||
|
||||
# Ubuntu:
|
||||
# - Jammy using GCC 12: Debug on linux/arm64, Release on
|
||||
# linux/amd64 (Release is required for DEB packaging).
|
||||
# - Jammy using GCC 12: Debug on linux/arm64.
|
||||
# - Noble using GCC 14: Release on linux/amd64.
|
||||
# - Noble using Clang 18: Debug on linux/amd64.
|
||||
# - Noble using Clang 19: Release on linux/arm64.
|
||||
@@ -163,12 +135,6 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
and architecture["platform"] == "linux/arm64"
|
||||
):
|
||||
skip = False
|
||||
if (
|
||||
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-12"
|
||||
and build_type == "Release"
|
||||
and architecture["platform"] == "linux/amd64"
|
||||
):
|
||||
skip = False
|
||||
elif os["distro_version"] == "noble":
|
||||
if (
|
||||
f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-14"
|
||||
@@ -222,9 +188,8 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
|
||||
# We skip all clang 20+ on arm64 due to Boost build error.
|
||||
if (
|
||||
os["compiler_name"] == "clang"
|
||||
and os["compiler_version"].isdigit()
|
||||
and int(os["compiler_version"]) >= 20
|
||||
f"{os['compiler_name']}-{os['compiler_version']}"
|
||||
in ["clang-20", "clang-21"]
|
||||
and architecture["platform"] == "linux/arm64"
|
||||
):
|
||||
continue
|
||||
@@ -251,7 +216,17 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
|
||||
# Generate a unique name for the configuration, e.g. macos-arm64-debug
|
||||
# or debian-bookworm-gcc-12-amd64-release.
|
||||
config_name = build_config_name(os, architecture["platform"], build_type)
|
||||
config_name = os["distro_name"]
|
||||
if (n := os["distro_version"]) != "":
|
||||
config_name += f"-{n}"
|
||||
if (n := os["compiler_name"]) != "":
|
||||
config_name += f"-{n}"
|
||||
if (n := os["compiler_version"]) != "":
|
||||
config_name += f"-{n}"
|
||||
config_name += (
|
||||
f"-{architecture['platform'][architecture['platform'].find('/')+1:]}"
|
||||
)
|
||||
config_name += f"-{build_type.lower()}"
|
||||
if "-Dcoverage=ON" in cmake_args:
|
||||
config_name += "-coverage"
|
||||
if "-Dunity=ON" in cmake_args:
|
||||
@@ -263,14 +238,13 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
# Add Address and UB sanitizers as separate configurations for specific
|
||||
# bookworm distros. Thread sanitizer is currently disabled (see below).
|
||||
# GCC-Asan xrpld-embedded tests are failing because of https://github.com/google/sanitizers/issues/856
|
||||
if (
|
||||
os["distro_version"] == "bookworm"
|
||||
and f"{os['compiler_name']}-{os['compiler_version']}" == "gcc-15"
|
||||
) or (
|
||||
os["distro_version"] == "trixie"
|
||||
and f"{os['compiler_name']}-{os['compiler_version']}" == "clang-22"
|
||||
):
|
||||
# Add ASAN and UBSAN configurations for both gcc-15 and clang-22
|
||||
if os[
|
||||
"distro_version"
|
||||
] == "bookworm" and f"{os['compiler_name']}-{os['compiler_version']}" in [
|
||||
"gcc-15",
|
||||
"clang-20",
|
||||
]:
|
||||
# Add ASAN configuration.
|
||||
configurations.append(
|
||||
{
|
||||
"config_name": config_name + "-asan",
|
||||
@@ -283,6 +257,7 @@ def generate_strategy_matrix(all: bool, config: Config) -> list[dict]:
|
||||
"sanitizers": "address",
|
||||
}
|
||||
)
|
||||
# Add UBSAN configuration.
|
||||
configurations.append(
|
||||
{
|
||||
"config_name": config_name + "-ubsan",
|
||||
@@ -355,19 +330,10 @@ if __name__ == "__main__":
|
||||
required=False,
|
||||
type=Path,
|
||||
)
|
||||
parser.add_argument(
|
||||
"-p",
|
||||
"--packaging",
|
||||
help="Emit the packaging matrix (derived from the 'package' field on os entries) instead of the build/test matrix.",
|
||||
action="store_true",
|
||||
)
|
||||
args = parser.parse_args()
|
||||
|
||||
matrix = []
|
||||
if args.packaging:
|
||||
config_path = args.config if args.config else THIS_DIR / "linux.json"
|
||||
matrix += generate_packaging_matrix(read_config(config_path))
|
||||
elif args.config is None or args.config == "":
|
||||
if args.config is None or args.config == "":
|
||||
matrix += generate_strategy_matrix(
|
||||
args.all, read_config(THIS_DIR / "linux.json")
|
||||
)
|
||||
|
||||
65
.github/scripts/strategy-matrix/linux.json
vendored
65
.github/scripts/strategy-matrix/linux.json
vendored
@@ -15,205 +15,196 @@
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "15",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "16",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "17",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "18",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "19",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "bookworm",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "20",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "15",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "20",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "21",
|
||||
"image_sha": "4c086b9"
|
||||
},
|
||||
{
|
||||
"distro_name": "debian",
|
||||
"distro_version": "trixie",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "22",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "8",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "8",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "4c086b9",
|
||||
"package": true
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "9",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "10",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "rhel",
|
||||
"distro_version": "10",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "any",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "jammy",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "12",
|
||||
"image_sha": "4c086b9",
|
||||
"package": true
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "13",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "gcc",
|
||||
"compiler_version": "14",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "16",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "17",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "18",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
},
|
||||
{
|
||||
"distro_name": "ubuntu",
|
||||
"distro_version": "noble",
|
||||
"compiler_name": "clang",
|
||||
"compiler_version": "19",
|
||||
"image_sha": "4c086b9"
|
||||
"image_sha": "ab4d1f0"
|
||||
}
|
||||
],
|
||||
"build_type": ["Debug", "Release"],
|
||||
|
||||
101
.github/workflows/build-nix-image.yml
vendored
101
.github/workflows/build-nix-image.yml
vendored
@@ -1,101 +0,0 @@
|
||||
name: Build Nix Docker image
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- develop
|
||||
paths:
|
||||
- ".github/workflows/build-nix-image.yml"
|
||||
- "docker/nix.Dockerfile"
|
||||
- "flake.nix"
|
||||
- "flake.lock"
|
||||
- "nix/**"
|
||||
pull_request:
|
||||
paths:
|
||||
- ".github/workflows/build-nix-image.yml"
|
||||
- "docker/nix.Dockerfile"
|
||||
- "flake.nix"
|
||||
- "flake.lock"
|
||||
- "nix/**"
|
||||
workflow_dispatch:
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
cancel-in-progress: true
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
UBUNTU_VERSION: "20.04"
|
||||
RHEL_VERSION: "9"
|
||||
DEBIAN_VERSION: "bookworm"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
name: Build and push Nix image (${{ matrix.distro }})
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
- distro: nixos
|
||||
- distro: ubuntu
|
||||
- distro: rhel
|
||||
- distro: debian
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Determine base image
|
||||
id: vars
|
||||
run: |
|
||||
case "${{ matrix.distro }}" in
|
||||
nixos)
|
||||
echo "base_image=nixos/nix:latest" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
ubuntu)
|
||||
echo "base_image=ubuntu:${UBUNTU_VERSION}" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
rhel)
|
||||
echo "base_image=registry.access.redhat.com/ubi${RHEL_VERSION}/ubi:latest" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
debian)
|
||||
echo "base_image=debian:${DEBIAN_VERSION}" >> $GITHUB_OUTPUT
|
||||
;;
|
||||
esac
|
||||
|
||||
- name: Set up Docker Buildx
|
||||
uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0
|
||||
|
||||
- name: Login to GitHub Container Registry
|
||||
if: github.event_name == 'push'
|
||||
uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0
|
||||
with:
|
||||
registry: ghcr.io
|
||||
username: ${{ github.repository_owner }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Docker metadata
|
||||
id: meta
|
||||
uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0
|
||||
with:
|
||||
images: ghcr.io/xrplf/ci/nix-${{ matrix.distro }}
|
||||
tags: |
|
||||
type=sha,prefix=sha-,format=short
|
||||
type=raw,value=latest
|
||||
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0
|
||||
with:
|
||||
context: .
|
||||
file: docker/nix.Dockerfile
|
||||
platforms: linux/amd64
|
||||
push: ${{ github.event_name == 'push' }}
|
||||
tags: ${{ steps.meta.outputs.tags }}
|
||||
labels: ${{ steps.meta.outputs.labels }}
|
||||
build-args: BASE_IMAGE=${{ steps.vars.outputs.base_image }}
|
||||
2
.github/workflows/check-pr-title.yml
vendored
2
.github/workflows/check-pr-title.yml
vendored
@@ -11,4 +11,4 @@ on:
|
||||
jobs:
|
||||
check_title:
|
||||
if: ${{ github.event.pull_request.draft != true }}
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@291206777251b4d493641b5afbdf7c23009d2988
|
||||
uses: XRPLF/actions/.github/workflows/check-pr-title.yml@a5d8dd35be543365e90a11358447130c8763871d
|
||||
|
||||
17
.github/workflows/on-pr.yml
vendored
17
.github/workflows/on-pr.yml
vendored
@@ -58,19 +58,20 @@ jobs:
|
||||
|
||||
# Keep the paths below in sync with those in `on-trigger.yml`.
|
||||
.github/actions/build-deps/**
|
||||
.github/actions/build-test/**
|
||||
.github/actions/generate-version/**
|
||||
.github/actions/setup-conan/**
|
||||
.github/scripts/strategy-matrix/**
|
||||
.github/workflows/reusable-build.yml
|
||||
.github/workflows/reusable-build-test-config.yml
|
||||
.github/workflows/reusable-build-test.yml
|
||||
.github/workflows/reusable-clang-tidy.yml
|
||||
.github/workflows/reusable-package.yml
|
||||
.github/workflows/reusable-clang-tidy-files.yml
|
||||
.github/workflows/reusable-strategy-matrix.yml
|
||||
.github/workflows/reusable-test.yml
|
||||
.github/workflows/reusable-upload-recipe.yml
|
||||
.clang-tidy
|
||||
.codecov.yml
|
||||
cfg/**
|
||||
cmake/**
|
||||
conan/**
|
||||
external/**
|
||||
@@ -80,10 +81,6 @@ jobs:
|
||||
CMakeLists.txt
|
||||
conanfile.py
|
||||
conan.lock
|
||||
LICENSE.md
|
||||
package/**
|
||||
README.md
|
||||
|
||||
- name: Check whether to run
|
||||
# This step determines whether the rest of the workflow should
|
||||
# run. The rest of the workflow will run if this job runs AND at
|
||||
@@ -140,11 +137,6 @@ jobs:
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
package:
|
||||
needs: [should-run, build-test]
|
||||
if: ${{ needs.should-run.outputs.go == 'true' }}
|
||||
uses: ./.github/workflows/reusable-package.yml
|
||||
|
||||
upload-recipe:
|
||||
needs:
|
||||
- should-run
|
||||
@@ -179,10 +171,9 @@ jobs:
|
||||
- check-rename
|
||||
- clang-tidy
|
||||
- build-test
|
||||
- package
|
||||
- upload-recipe
|
||||
- notify-clio
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Fail
|
||||
run: exit 1
|
||||
run: false
|
||||
|
||||
23
.github/workflows/on-tag.yml
vendored
23
.github/workflows/on-tag.yml
vendored
@@ -1,5 +1,5 @@
|
||||
# This workflow uploads the libxrpl recipe to the Conan remote and builds
|
||||
# release packages when a versioned tag is pushed.
|
||||
# This workflow uploads the libxrpl recipe to the Conan remote when a versioned
|
||||
# tag is pushed.
|
||||
name: Tag
|
||||
|
||||
on:
|
||||
@@ -22,22 +22,3 @@ jobs:
|
||||
secrets:
|
||||
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
|
||||
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
|
||||
|
||||
build-test:
|
||||
if: ${{ github.repository == 'XRPLF/rippled' }}
|
||||
uses: ./.github/workflows/reusable-build-test.yml
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
os: [linux]
|
||||
with:
|
||||
ccache_enabled: false
|
||||
os: ${{ matrix.os }}
|
||||
strategy_matrix: minimal
|
||||
secrets:
|
||||
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}
|
||||
|
||||
package:
|
||||
if: ${{ github.repository == 'XRPLF/rippled' }}
|
||||
needs: build-test
|
||||
uses: ./.github/workflows/reusable-package.yml
|
||||
|
||||
12
.github/workflows/on-trigger.yml
vendored
12
.github/workflows/on-trigger.yml
vendored
@@ -15,19 +15,20 @@ on:
|
||||
|
||||
# Keep the paths below in sync with those in `on-pr.yml`.
|
||||
- ".github/actions/build-deps/**"
|
||||
- ".github/actions/build-test/**"
|
||||
- ".github/actions/generate-version/**"
|
||||
- ".github/actions/setup-conan/**"
|
||||
- ".github/scripts/strategy-matrix/**"
|
||||
- ".github/workflows/reusable-build.yml"
|
||||
- ".github/workflows/reusable-build-test-config.yml"
|
||||
- ".github/workflows/reusable-build-test.yml"
|
||||
- ".github/workflows/reusable-clang-tidy.yml"
|
||||
- ".github/workflows/reusable-package.yml"
|
||||
- ".github/workflows/reusable-clang-tidy-files.yml"
|
||||
- ".github/workflows/reusable-strategy-matrix.yml"
|
||||
- ".github/workflows/reusable-test.yml"
|
||||
- ".github/workflows/reusable-upload-recipe.yml"
|
||||
- ".clang-tidy"
|
||||
- ".codecov.yml"
|
||||
- "cfg/**"
|
||||
- "cmake/**"
|
||||
- "conan/**"
|
||||
- "external/**"
|
||||
@@ -37,9 +38,6 @@ on:
|
||||
- "CMakeLists.txt"
|
||||
- "conanfile.py"
|
||||
- "conan.lock"
|
||||
- "LICENSE.md"
|
||||
- "package/**"
|
||||
- "README.md"
|
||||
|
||||
# Run at 06:32 UTC on every day of the week from Monday through Friday. This
|
||||
# will force all dependencies to be rebuilt, which is useful to verify that
|
||||
@@ -100,7 +98,3 @@ jobs:
|
||||
secrets:
|
||||
remote_username: ${{ secrets.CONAN_REMOTE_USERNAME }}
|
||||
remote_password: ${{ secrets.CONAN_REMOTE_PASSWORD }}
|
||||
|
||||
package:
|
||||
needs: build-test
|
||||
uses: ./.github/workflows/reusable-package.yml
|
||||
|
||||
13
.github/workflows/reusable-build-test-config.yml
vendored
13
.github/workflows/reusable-build-test-config.yml
vendored
@@ -116,7 +116,7 @@ jobs:
|
||||
run: echo "CCACHE_LOGFILE=${{ runner.temp }}/ccache.log" >> "${GITHUB_ENV}"
|
||||
|
||||
- name: Print build environment
|
||||
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
|
||||
uses: XRPLF/actions/print-env@8f811899319ef002e7a088c77c57d95aba602a97
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
@@ -143,6 +143,7 @@ jobs:
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
env:
|
||||
BUILD_TYPE: ${{ inputs.build_type }}
|
||||
SANITIZERS: ${{ inputs.sanitizers }}
|
||||
CMAKE_ARGS: ${{ inputs.cmake_args }}
|
||||
run: |
|
||||
cmake \
|
||||
@@ -283,16 +284,8 @@ jobs:
|
||||
|
||||
- name: Show test failure summary
|
||||
if: ${{ failure() && !inputs.build_only }}
|
||||
env:
|
||||
WORKING_DIR: ${{ runner.os == 'Windows' && format('{0}\{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
|
||||
working-directory: ${{ runner.os == 'Windows' && format('{0}/{1}', env.BUILD_DIR, inputs.build_type) || env.BUILD_DIR }}
|
||||
run: |
|
||||
if [ ! -d "${WORKING_DIR}" ]; then
|
||||
echo "Working directory '${WORKING_DIR}' does not exist."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
cd "${WORKING_DIR}"
|
||||
|
||||
if [ ! -f unittest.log ]; then
|
||||
echo "unittest.log not found; embedded tests may not have run."
|
||||
exit 0
|
||||
|
||||
175
.github/workflows/reusable-clang-tidy-files.yml
vendored
Normal file
175
.github/workflows/reusable-clang-tidy-files.yml
vendored
Normal file
@@ -0,0 +1,175 @@
|
||||
name: Run clang-tidy on files
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
files:
|
||||
description: "List of files to check (empty means check all files)"
|
||||
type: string
|
||||
default: ""
|
||||
create_issue_on_failure:
|
||||
description: "Whether to create an issue if the check failed"
|
||||
type: boolean
|
||||
default: false
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
# Conan installs the generators in the build/generators directory, see the
|
||||
# layout() method in conanfile.py. We then run CMake from the build directory.
|
||||
BUILD_DIR: build
|
||||
BUILD_TYPE: Release
|
||||
|
||||
jobs:
|
||||
run-clang-tidy:
|
||||
name: Run clang tidy
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: "ghcr.io/xrplf/ci/debian-trixie:clang-21-sha-53033a2"
|
||||
permissions:
|
||||
issues: write
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
|
||||
with:
|
||||
enable_ccache: false
|
||||
|
||||
- name: Print build environment
|
||||
uses: XRPLF/actions/print-env@8f811899319ef002e7a088c77c57d95aba602a97
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
id: nproc
|
||||
|
||||
- name: Setup Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
|
||||
- name: Build dependencies
|
||||
uses: ./.github/actions/build-deps
|
||||
with:
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ env.BUILD_TYPE }}
|
||||
log_verbosity: verbose
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
cmake \
|
||||
-G 'Ninja' \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
||||
-Dtests=ON \
|
||||
-Dwerr=ON \
|
||||
-Dxrpld=ON \
|
||||
..
|
||||
|
||||
# clang-tidy needs headers generated from proto files
|
||||
- name: Build libxrpl.libpb
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
ninja -j ${{ steps.nproc.outputs.nproc }} xrpl.libpb
|
||||
|
||||
- name: Run clang tidy
|
||||
id: run_clang_tidy
|
||||
continue-on-error: true
|
||||
env:
|
||||
TARGETS: ${{ inputs.files != '' && inputs.files || 'src tests' }}
|
||||
run: |
|
||||
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -fix -allow-no-checks ${TARGETS} 2>&1 | tee clang-tidy-output.txt
|
||||
|
||||
- name: Upload clang-tidy output
|
||||
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: clang-tidy-results
|
||||
path: clang-tidy-output.txt
|
||||
retention-days: 30
|
||||
|
||||
- name: Generate git diff
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
git diff | tee clang-tidy-git-diff.txt
|
||||
|
||||
- name: Upload clang-tidy diff output
|
||||
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: clang-tidy-git-diff
|
||||
path: clang-tidy-git-diff.txt
|
||||
retention-days: 30
|
||||
|
||||
- name: Create an issue
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }}
|
||||
id: create_issue
|
||||
shell: bash
|
||||
env:
|
||||
GH_TOKEN: ${{ github.token }}
|
||||
run: |
|
||||
# Prepare issue body with clang-tidy output
|
||||
cat > issue.md <<EOF
|
||||
## Clang-tidy Check Failed
|
||||
|
||||
**Workflow:** ${{ github.workflow }}
|
||||
**Run ID:** ${{ github.run_id }}
|
||||
**Commit:** ${{ github.sha }}
|
||||
**Branch/Ref:** ${{ github.ref }}
|
||||
**Triggered by:** ${{ github.actor }}
|
||||
|
||||
### Clang-tidy Output:
|
||||
\`\`\`
|
||||
EOF
|
||||
|
||||
# Append clang-tidy output (filter for errors and warnings)
|
||||
if [ -f clang-tidy-output.txt ]; then
|
||||
# Extract lines containing 'error:', 'warning:', or 'note:'
|
||||
grep -E '(error:|warning:|note:)' clang-tidy-output.txt > filtered-output.txt || true
|
||||
|
||||
# If filtered output is empty, use original (might be a different error format)
|
||||
if [ ! -s filtered-output.txt ]; then
|
||||
cp clang-tidy-output.txt filtered-output.txt
|
||||
fi
|
||||
|
||||
# Truncate if too large
|
||||
head -c 60000 filtered-output.txt >> issue.md
|
||||
if [ "$(wc -c < filtered-output.txt)" -gt 60000 ]; then
|
||||
echo "" >> issue.md
|
||||
echo "... (output truncated, see artifacts for full output)" >> issue.md
|
||||
fi
|
||||
|
||||
rm filtered-output.txt
|
||||
else
|
||||
echo "No output file found" >> issue.md
|
||||
fi
|
||||
|
||||
cat >> issue.md <<EOF
|
||||
\`\`\`
|
||||
|
||||
**Workflow run:** ${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}
|
||||
|
||||
---
|
||||
*This issue was automatically created by the clang-tidy workflow.*
|
||||
EOF
|
||||
|
||||
# Create the issue
|
||||
gh issue create \
|
||||
--label "Bug,Clang-tidy" \
|
||||
--title "Clang-tidy check failed" \
|
||||
--body-file ./issue.md \
|
||||
> create_issue.log
|
||||
|
||||
created_issue="$(sed 's|.*/||' create_issue.log)"
|
||||
echo "created_issue=$created_issue" >> $GITHUB_OUTPUT
|
||||
echo "Created issue #$created_issue"
|
||||
|
||||
rm -f create_issue.log issue.md clang-tidy-output.txt
|
||||
|
||||
- name: Fail the workflow if clang-tidy failed
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
echo "Clang-tidy check failed!"
|
||||
exit 1
|
||||
189
.github/workflows/reusable-clang-tidy.yml
vendored
189
.github/workflows/reusable-clang-tidy.yml
vendored
@@ -1,4 +1,4 @@
|
||||
name: Run clang-tidy on files
|
||||
name: Clang-tidy check
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
@@ -16,175 +16,40 @@ defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
BUILD_DIR: build
|
||||
BUILD_TYPE: Debug # Debug so that ASSERTS and such participate in clang-tidy check
|
||||
|
||||
OUTPUT_FILE: clang-tidy-output.txt
|
||||
DIFF_FILE: clang-tidy-git-diff.txt
|
||||
ISSUE_FILE: clang-tidy-issue.md
|
||||
|
||||
jobs:
|
||||
determine-files:
|
||||
name: Determine files to check
|
||||
if: ${{ inputs.check_only_changed }}
|
||||
permissions:
|
||||
contents: read
|
||||
uses: XRPLF/actions/.github/workflows/determine-tidy-files.yml@224f3c48d3014d082a1129237b8291ff0b0a331f
|
||||
|
||||
run-clang-tidy:
|
||||
name: Run clang tidy
|
||||
needs: [determine-files]
|
||||
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.cpp_changed_files != '' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: "ghcr.io/xrplf/ci/debian-trixie:clang-21-sha-53033a2"
|
||||
permissions:
|
||||
contents: read
|
||||
issues: write
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
clang_tidy_config_changed: ${{ steps.changed_clang_tidy.outputs.any_changed }}
|
||||
any_cpp_changed: ${{ steps.changed_files.outputs.any_changed }}
|
||||
all_changed_files: ${{ steps.changed_files.outputs.all_changed_files }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Prepare runner
|
||||
uses: XRPLF/actions/prepare-runner@90f11ee655d1687824fb8793db770477d52afbab
|
||||
- name: Get changed C++ files
|
||||
id: changed_files
|
||||
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
|
||||
with:
|
||||
enable_ccache: false
|
||||
files: |
|
||||
**/*.cpp
|
||||
**/*.h
|
||||
**/*.ipp
|
||||
separator: " "
|
||||
|
||||
- name: Print build environment
|
||||
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
id: nproc
|
||||
|
||||
- name: Setup Conan
|
||||
uses: ./.github/actions/setup-conan
|
||||
|
||||
- name: Build dependencies
|
||||
uses: ./.github/actions/build-deps
|
||||
- name: Get changed clang-tidy configuration
|
||||
id: changed_clang_tidy
|
||||
uses: tj-actions/changed-files@9426d40962ed5378910ee2e21d5f8c6fcbf2dd96 # v47.0.6
|
||||
with:
|
||||
build_nproc: ${{ steps.nproc.outputs.nproc }}
|
||||
build_type: ${{ env.BUILD_TYPE }}
|
||||
log_verbosity: verbose
|
||||
files: |
|
||||
.clang-tidy
|
||||
|
||||
- name: Configure CMake
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
cmake \
|
||||
-G 'Ninja' \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE="${BUILD_TYPE}" \
|
||||
-Dtests=ON \
|
||||
-Dwerr=ON \
|
||||
-Dxrpld=ON \
|
||||
..
|
||||
|
||||
# clang-tidy needs headers generated from proto files
|
||||
- name: Build libxrpl.libpb
|
||||
working-directory: ${{ env.BUILD_DIR }}
|
||||
run: |
|
||||
ninja -j ${{ steps.nproc.outputs.nproc }} xrpl.libpb
|
||||
|
||||
- name: Run clang tidy
|
||||
id: run_clang_tidy
|
||||
continue-on-error: true
|
||||
env:
|
||||
TARGETS: ${{ (needs.determine-files.outputs.clang_tidy_config_changed != 'true' && inputs.check_only_changed) && needs.determine-files.outputs.cpp_changed_files || 'src tests' }}
|
||||
run: |
|
||||
set -o pipefail
|
||||
run-clang-tidy -j ${{ steps.nproc.outputs.nproc }} -p "${BUILD_DIR}" -quiet -fix -allow-no-checks ${TARGETS} 2>&1 | tee "${OUTPUT_FILE}"
|
||||
|
||||
- name: Print errors
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
sed '/error\||/!d' "${OUTPUT_FILE}"
|
||||
|
||||
- name: Upload clang-tidy output
|
||||
if: ${{ github.event.repository.visibility == 'public' && steps.run_clang_tidy.outcome != 'success' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
path: ${{ env.OUTPUT_FILE }}
|
||||
archive: false
|
||||
retention-days: 30
|
||||
|
||||
- name: Check for changes
|
||||
id: files_changed
|
||||
continue-on-error: true
|
||||
run: |
|
||||
git diff --exit-code
|
||||
|
||||
- name: Fix style
|
||||
if: ${{ steps.files_changed.outcome != 'success' }}
|
||||
run: |
|
||||
pre-commit run --all-files || true
|
||||
|
||||
- name: Generate git diff
|
||||
if: ${{ steps.files_changed.outcome != 'success' }}
|
||||
run: |
|
||||
git diff | tee "${DIFF_FILE}"
|
||||
|
||||
- name: Upload clang-tidy diff output
|
||||
if: ${{ github.event.repository.visibility == 'public' && steps.files_changed.outcome != 'success' }}
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
path: ${{ env.DIFF_FILE }}
|
||||
archive: false
|
||||
retention-days: 30
|
||||
|
||||
- name: Write issue header
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
cat > "${ISSUE_FILE}" <<EOF
|
||||
## Clang-tidy Check Failed
|
||||
|
||||
### Clang-tidy Output:
|
||||
\`\`\`
|
||||
EOF
|
||||
|
||||
- name: Append clang-tidy output to issue body (filter for errors and warnings)
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
if [ -f "${OUTPUT_FILE}" ]; then
|
||||
# Extract lines containing 'error:', 'warning:', or 'note:'
|
||||
grep -E '(error:|warning:|note:)' "${OUTPUT_FILE}" > filtered-output.txt || true
|
||||
|
||||
# If filtered output is empty, use original (might be a different error format)
|
||||
if [ ! -s filtered-output.txt ]; then
|
||||
cp "${OUTPUT_FILE}" filtered-output.txt
|
||||
fi
|
||||
|
||||
# Truncate if too large
|
||||
head -c 60000 filtered-output.txt >> "${ISSUE_FILE}"
|
||||
if [ "$(wc -c < filtered-output.txt)" -gt 60000 ]; then
|
||||
echo "" >> "${ISSUE_FILE}"
|
||||
echo "... (output truncated, see artifacts for full output)" >> "${ISSUE_FILE}"
|
||||
fi
|
||||
|
||||
rm filtered-output.txt
|
||||
else
|
||||
echo "No output file found" >> "${ISSUE_FILE}"
|
||||
fi
|
||||
|
||||
- name: Append issue footer
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
cat >> "${ISSUE_FILE}" <<EOF
|
||||
\`\`\`
|
||||
|
||||
---
|
||||
*This issue was automatically created by the clang-tidy workflow.*
|
||||
EOF
|
||||
|
||||
- name: Create issue
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' && inputs.create_issue_on_failure }}
|
||||
uses: XRPLF/actions/create-issue@36d450d12d301e8410c1b7936e5de70c291cbe36
|
||||
with:
|
||||
title: "Clang-tidy check failed"
|
||||
body_file: ${{ env.ISSUE_FILE }}
|
||||
labels: "Bug,Clang-tidy"
|
||||
assignees: "godexsoft,mathbunnyru"
|
||||
|
||||
- name: Fail if clang-tidy found issues
|
||||
if: ${{ steps.run_clang_tidy.outcome != 'success' }}
|
||||
run: |
|
||||
echo "Clang-tidy check failed!"
|
||||
exit 1
|
||||
run-clang-tidy:
|
||||
needs: [determine-files]
|
||||
if: ${{ always() && !cancelled() && (!inputs.check_only_changed || needs.determine-files.outputs.any_cpp_changed == 'true' || needs.determine-files.outputs.clang_tidy_config_changed == 'true') }}
|
||||
uses: ./.github/workflows/reusable-clang-tidy-files.yml
|
||||
with:
|
||||
files: ${{ (needs.determine-files.outputs.clang_tidy_config_changed != 'true' && inputs.check_only_changed) && needs.determine-files.outputs.all_changed_files || '' }}
|
||||
create_issue_on_failure: ${{ inputs.create_issue_on_failure }}
|
||||
|
||||
99
.github/workflows/reusable-package.yml
vendored
99
.github/workflows/reusable-package.yml
vendored
@@ -1,99 +0,0 @@
|
||||
# Build Linux packages (DEB and RPM) from pre-built binary artifacts.
|
||||
# Discovers which configurations to package from linux.json (os entries
|
||||
# with "package": true) and fans out one job per entry. Today only
|
||||
# linux/amd64 is emitted; the architecture is hardcoded both here
|
||||
# (runner) and in generate.py.
|
||||
name: Package
|
||||
|
||||
on:
|
||||
workflow_call:
|
||||
inputs:
|
||||
pkg_release:
|
||||
description: "Package release number. Increment when repackaging the same executable."
|
||||
required: false
|
||||
type: string
|
||||
default: "1"
|
||||
|
||||
defaults:
|
||||
run:
|
||||
shell: bash
|
||||
|
||||
env:
|
||||
BUILD_DIR: build
|
||||
|
||||
jobs:
|
||||
generate-matrix:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
matrix: ${{ steps.generate.outputs.matrix }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@a309ff8b426b58ec0e2a45f0f869d46889d02405 # v6.2.0
|
||||
with:
|
||||
python-version: 3.13
|
||||
|
||||
- name: Generate packaging matrix
|
||||
id: generate
|
||||
working-directory: .github/scripts/strategy-matrix
|
||||
run: |
|
||||
./generate.py --packaging --config=linux.json >> "${GITHUB_OUTPUT}"
|
||||
|
||||
generate-version:
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
version: ${{ steps.version.outputs.version }}
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
sparse-checkout: |
|
||||
.github/actions/generate-version
|
||||
src/libxrpl/protocol/BuildInfo.cpp
|
||||
- name: Generate version
|
||||
id: version
|
||||
uses: ./.github/actions/generate-version
|
||||
|
||||
package:
|
||||
needs: [generate-matrix, generate-version]
|
||||
if: ${{ github.event.repository.visibility == 'public' }}
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix: ${{ fromJson(needs.generate-matrix.outputs.matrix) }}
|
||||
name: "${{ matrix.artifact_name }}"
|
||||
permissions:
|
||||
contents: read
|
||||
runs-on: ["self-hosted", "Linux", "X64", "heavy"]
|
||||
container: ${{ format('ghcr.io/xrplf/ci/{0}-{1}:{2}-{3}-sha-{4}', matrix.os.distro_name, matrix.os.distro_version, matrix.os.compiler_name, matrix.os.compiler_version, matrix.os.image_sha) }}
|
||||
timeout-minutes: 30
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
|
||||
- name: Download pre-built binary
|
||||
uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}
|
||||
path: ${{ env.BUILD_DIR }}
|
||||
|
||||
- name: Make binary executable
|
||||
run: chmod +x "${BUILD_DIR}/xrpld"
|
||||
|
||||
- name: Build package
|
||||
env:
|
||||
PKG_VERSION: ${{ needs.generate-version.outputs.version }}
|
||||
PKG_RELEASE: ${{ inputs.pkg_release }}
|
||||
run: ./package/build_pkg.sh
|
||||
|
||||
- name: Upload package artifact
|
||||
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
|
||||
with:
|
||||
name: ${{ matrix.artifact_name }}-pkg-${{ needs.generate-version.outputs.version }}
|
||||
path: |
|
||||
${{ env.BUILD_DIR }}/debbuild/*.deb
|
||||
${{ env.BUILD_DIR }}/debbuild/*.ddeb
|
||||
${{ env.BUILD_DIR }}/rpmbuild/RPMS/**/*.rpm
|
||||
if-no-files-found: error
|
||||
2
.github/workflows/upload-conan-deps.yml
vendored
2
.github/workflows/upload-conan-deps.yml
vendored
@@ -75,7 +75,7 @@ jobs:
|
||||
enable_ccache: false
|
||||
|
||||
- name: Print build environment
|
||||
uses: XRPLF/actions/print-build-env@59dec886e4afb05a1724443af08baccbc045b574
|
||||
uses: XRPLF/actions/print-env@8f811899319ef002e7a088c77c57d95aba602a97
|
||||
|
||||
- name: Get number of processors
|
||||
uses: XRPLF/actions/get-nproc@cf0433aa74563aead044a1e395610c96d65a37cf
|
||||
|
||||
@@ -70,11 +70,7 @@ repos:
|
||||
rev: a42085ade523f591dca134379a595e7859986445 # frozen: v9.7.0
|
||||
hooks:
|
||||
- id: cspell # Spell check changed files
|
||||
exclude: |
|
||||
(?x)^(
|
||||
.config/cspell.config.yaml|
|
||||
include/xrpl/protocol_autogen/(transactions|ledger_entries)/.*
|
||||
)$
|
||||
exclude: (.config/cspell.config.yaml|^include/xrpl/protocol_autogen/(transactions|ledger_entries)/)
|
||||
- id: cspell # Spell check the commit message
|
||||
name: check commit message spelling
|
||||
args:
|
||||
|
||||
17
BUILD.md
17
BUILD.md
@@ -141,7 +141,7 @@ Alternatively, you can pull our recipes from the repository and export them loca
|
||||
|
||||
```bash
|
||||
# Define which recipes to export.
|
||||
recipes=('abseil' 'ed25519' 'mpt-crypto' 'openssl' 'secp256k1' 'snappy' 'soci' 'wasm-xrplf' 'wasmi')
|
||||
recipes=('abseil' 'ed25519' 'grpc' 'm4' 'mpt-crypto' 'openssl' 'secp256k1' 'snappy' 'soci' 'wasm-xrplf' 'wasmi')
|
||||
|
||||
# Selectively check out the recipes from our CCI fork.
|
||||
cd external
|
||||
@@ -427,19 +427,16 @@ install ccache --version 4.11.3 --allow-downgrade`.
|
||||
Single-config generators:
|
||||
|
||||
```
|
||||
cmake --build . --parallel N
|
||||
cmake --build .
|
||||
```
|
||||
|
||||
Multi-config generators:
|
||||
|
||||
```
|
||||
cmake --build . --config Release --parallel N
|
||||
cmake --build . --config Debug --parallel N
|
||||
cmake --build . --config Release
|
||||
cmake --build . --config Debug
|
||||
```
|
||||
|
||||
Replace the `--parallel` parameter N with the desired number of parallel jobs. A common starting point is half of the number of available CPU
|
||||
cores.
|
||||
|
||||
5. Test xrpld.
|
||||
|
||||
Single-config generators:
|
||||
@@ -533,15 +530,15 @@ stored inside the build directory, as either of:
|
||||
## Sanitizers
|
||||
|
||||
To build dependencies and xrpld with sanitizer instrumentation, set the
|
||||
`SANITIZERS` environment variable when running `conan install` and use the `sanitizers` profile:
|
||||
`SANITIZERS` environment variable (only once before running conan and cmake) and use the `sanitizers` profile in conan:
|
||||
|
||||
```bash
|
||||
export SANITIZERS=address,undefinedbehavior
|
||||
|
||||
conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug
|
||||
```
|
||||
|
||||
You can then build and test as usual, with the generated `xrpld` binary containing the sanitizer instrumentation. When you run it, it will report any sanitizer errors it detects in the console output.
|
||||
cmake -DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake -DCMAKE_BUILD_TYPE=Debug -Dxrpld=ON -Dtests=ON ..
|
||||
```
|
||||
|
||||
See [Sanitizers docs](./docs/build/sanitizers.md) for more details.
|
||||
|
||||
|
||||
@@ -134,7 +134,6 @@ endif()
|
||||
include(XrplCore)
|
||||
include(XrplProtocolAutogen)
|
||||
include(XrplInstall)
|
||||
include(XrplPackaging)
|
||||
include(XrplValidatorKeys)
|
||||
|
||||
if(tests)
|
||||
|
||||
@@ -348,8 +348,8 @@ For this reason:
|
||||
- Contract description for `UNREACHABLE` should describe the _unexpected_
|
||||
situation which caused the line to have been reached.
|
||||
- Example good name for an
|
||||
`UNREACHABLE` macro `"json::operator==(Value, Value) : invalid type"`; example
|
||||
good name for an `XRPL_ASSERT` macro `"json::Value::asCString : valid type"`.
|
||||
`UNREACHABLE` macro `"Json::operator==(Value, Value) : invalid type"`; example
|
||||
good name for an `XRPL_ASSERT` macro `"Json::Value::asCString : valid type"`.
|
||||
- Example **bad** name
|
||||
`"RFC1751::insert(char* s, int x, int start, int length) : length is greater than or equal zero"`
|
||||
(missing namespace, unnecessary full function signature, description too verbose).
|
||||
|
||||
@@ -28,7 +28,7 @@
|
||||
# https://vl.ripple.com
|
||||
# https://unl.xrplf.org
|
||||
# http://127.0.0.1:8000
|
||||
# file:///etc/xrpld/vl.txt
|
||||
# file:///etc/opt/xrpld/vl.txt
|
||||
#
|
||||
# [validator_list_keys]
|
||||
#
|
||||
|
||||
@@ -527,17 +527,6 @@
|
||||
#
|
||||
# The current default (which is subject to change) is 300 seconds.
|
||||
#
|
||||
# verify_endpoints = <0 | 1>
|
||||
#
|
||||
# If set to 0, the server will skip validation of endpoint
|
||||
# addresses received in TMEndpoints peer protocol messages,
|
||||
# allowing addresses that are not publicly routable or have a
|
||||
# port of 0. The default is 1 (verification enabled).
|
||||
#
|
||||
# WARNING: Disabling this option is a security risk and should
|
||||
# only be used for local testing and debugging. Do not disable
|
||||
# on mainnet.
|
||||
#
|
||||
#
|
||||
# [transaction_queue] EXPERIMENTAL
|
||||
#
|
||||
@@ -1269,7 +1258,7 @@
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# account_reserve = 1000000 # 1 XRP
|
||||
# account_reserve = 10000000 # 10 XRP
|
||||
#
|
||||
# owner_reserve = <drops>
|
||||
#
|
||||
@@ -1281,7 +1270,7 @@
|
||||
# default. Don't change this without understanding the consequences.
|
||||
#
|
||||
# Example:
|
||||
# owner_reserve = 200000 # 0.2 XRP
|
||||
# owner_reserve = 2000000 # 2 XRP
|
||||
#
|
||||
#-------------------------------------------------------------------------------
|
||||
#
|
||||
@@ -1466,7 +1455,10 @@ admin = 127.0.0.1
|
||||
protocol = http
|
||||
|
||||
[port_peer]
|
||||
port = 2459
|
||||
# Many servers still use the legacy port of 51235, so for backward-compatibility
|
||||
# we maintain that port number here. However, for new servers we recommend
|
||||
# changing this to the default port of 2459.
|
||||
port = 51235
|
||||
ip = 0.0.0.0
|
||||
# alternatively, to accept connections on IPv4 + IPv6, use:
|
||||
#ip = ::
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
#[===================================================================[
|
||||
Linux packaging support: 'package' target.
|
||||
|
||||
The packaging script (package/build_pkg.sh) installs to FHS-standard
|
||||
paths (/usr/bin, /etc/xrpld, etc.) regardless of CMAKE_INSTALL_PREFIX,
|
||||
so no prefix guard is needed here.
|
||||
#]===================================================================]
|
||||
if(NOT is_linux)
|
||||
message(STATUS "Packaging not supported on non-Linux hosts")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT DEFINED pkg_release)
|
||||
set(pkg_release 1)
|
||||
endif()
|
||||
|
||||
find_program(RPMBUILD_EXECUTABLE rpmbuild)
|
||||
find_program(DPKG_BUILDPACKAGE_EXECUTABLE dpkg-buildpackage)
|
||||
|
||||
if(NOT (RPMBUILD_EXECUTABLE OR DPKG_BUILDPACKAGE_EXECUTABLE))
|
||||
message(
|
||||
STATUS
|
||||
"Neither rpmbuild nor dpkg-buildpackage found; 'package' target not available"
|
||||
)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(package_env
|
||||
SRC_DIR=${CMAKE_SOURCE_DIR}
|
||||
BUILD_DIR=${CMAKE_BINARY_DIR}
|
||||
PKG_VERSION=${xrpld_version}
|
||||
PKG_RELEASE=${pkg_release}
|
||||
)
|
||||
|
||||
add_custom_target(
|
||||
package
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E env ${package_env}
|
||||
${CMAKE_SOURCE_DIR}/package/build_pkg.sh
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
DEPENDS xrpld
|
||||
COMMENT "Building Linux package (deb/rpm inferred from host tooling)"
|
||||
VERBATIM
|
||||
)
|
||||
@@ -1,33 +1,138 @@
|
||||
#[===================================================================[
|
||||
Apply sanitizer flags built by the Conan profile.
|
||||
Configure sanitizers based on environment variables.
|
||||
|
||||
Parsing, validation, and flag construction are performed in conan/profiles/sanitizers.
|
||||
This module reads the following CMake variables injected by the Conan toolchain via extra_variables:
|
||||
This module reads the following environment variables:
|
||||
- SANITIZERS: The sanitizers to enable. Possible values:
|
||||
- "address"
|
||||
- "address,undefinedbehavior"
|
||||
- "thread"
|
||||
- "thread,undefinedbehavior"
|
||||
- "undefinedbehavior"
|
||||
|
||||
- SANITIZERS: The active sanitizers (e.g. "address,undefinedbehavior").
|
||||
- SANITIZERS_COMPILER_FLAGS: Space-separated compiler flags.
|
||||
- SANITIZERS_LINKER_FLAGS: Space-separated linker flags.
|
||||
The compiler type and platform are detected in CompilationEnv.cmake.
|
||||
The sanitizer compile options are applied to the 'common' interface library
|
||||
which is linked to all targets in the project.
|
||||
|
||||
The flags are applied to the 'common' interface library which is linked to all targets in the project.
|
||||
Internal flag variables set by this module:
|
||||
|
||||
- SANITIZER_TYPES: List of sanitizer types to enable (e.g., "address",
|
||||
"thread", "undefined"). And two more flags for undefined behavior sanitizer (e.g., "float-divide-by-zero", "unsigned-integer-overflow").
|
||||
This list is joined with commas and passed to -fsanitize=<list>.
|
||||
|
||||
- SANITIZERS_COMPILE_FLAGS: Compiler flags for sanitizer instrumentation.
|
||||
Includes:
|
||||
* -fno-omit-frame-pointer: Preserves frame pointers for stack traces
|
||||
* -O1: Minimum optimization for reasonable performance
|
||||
* -fsanitize=<types>: Enables sanitizer instrumentation
|
||||
* -fsanitize-ignorelist=<path>: (Clang only) Compile-time ignorelist
|
||||
* -mcmodel=large/medium: (GCC only) Code model for large binaries
|
||||
* -Wno-stringop-overflow: (GCC only) Suppresses false positive warnings
|
||||
* -Wno-tsan: (For GCC TSAN combination only) Suppresses atomic_thread_fence warnings
|
||||
|
||||
- SANITIZERS_LINK_FLAGS: Linker flags for sanitizer runtime libraries.
|
||||
Includes:
|
||||
* -fsanitize=<types>: Links sanitizer runtime libraries
|
||||
* -mcmodel=large/medium: (GCC only) Matches compile-time code model
|
||||
|
||||
- SANITIZERS_RELOCATION_FLAGS: (GCC only) Code model flags for linking.
|
||||
Used to handle large instrumented binaries on x86_64:
|
||||
* -mcmodel=large: For AddressSanitizer (prevents relocation errors)
|
||||
* -mcmodel=medium: For ThreadSanitizer (large model is incompatible)
|
||||
#]===================================================================]
|
||||
|
||||
include_guard(GLOBAL)
|
||||
include(CompilationEnv)
|
||||
|
||||
if(NOT DEFINED SANITIZERS)
|
||||
# Read environment variable
|
||||
set(SANITIZERS "")
|
||||
if(DEFINED ENV{SANITIZERS})
|
||||
set(SANITIZERS "$ENV{SANITIZERS}")
|
||||
endif()
|
||||
|
||||
# Set SANITIZERS_ENABLED flag for use in other modules
|
||||
if(SANITIZERS MATCHES "address|thread|undefinedbehavior")
|
||||
set(SANITIZERS_ENABLED TRUE)
|
||||
else()
|
||||
set(SANITIZERS_ENABLED FALSE)
|
||||
return()
|
||||
endif()
|
||||
set(SANITIZERS_ENABLED TRUE)
|
||||
|
||||
message(STATUS "=== Configuring Sanitizers ===")
|
||||
message(STATUS " SANITIZERS: ${SANITIZERS}")
|
||||
message(STATUS " Compile flags: ${SANITIZERS_COMPILER_FLAGS}")
|
||||
message(STATUS " Link flags: ${SANITIZERS_LINKER_FLAGS}")
|
||||
# Sanitizers are not supported on Windows/MSVC
|
||||
if(is_msvc)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Sanitizers are not supported on Windows/MSVC. "
|
||||
"Please unset the SANITIZERS environment variable."
|
||||
)
|
||||
endif()
|
||||
|
||||
# GCC with sanitizers is incompatible with mold, gold, and lld linkers.
|
||||
# Namely, the instrumented binary exceeds size limits imposed by these linkers.
|
||||
message(STATUS "Configuring sanitizers: ${SANITIZERS}")
|
||||
|
||||
# Parse SANITIZERS value to determine which sanitizers to enable
|
||||
set(enable_asan FALSE)
|
||||
set(enable_tsan FALSE)
|
||||
set(enable_ubsan FALSE)
|
||||
|
||||
# Normalize SANITIZERS into a list
|
||||
set(san_list "${SANITIZERS}")
|
||||
string(REPLACE "," ";" san_list "${san_list}")
|
||||
separate_arguments(san_list)
|
||||
|
||||
foreach(san IN LISTS san_list)
|
||||
if(san STREQUAL "address")
|
||||
set(enable_asan TRUE)
|
||||
elseif(san STREQUAL "thread")
|
||||
set(enable_tsan TRUE)
|
||||
elseif(san STREQUAL "undefinedbehavior")
|
||||
set(enable_ubsan TRUE)
|
||||
else()
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Unsupported sanitizer type: ${san}"
|
||||
"Supported: address, thread, undefinedbehavior and their combinations."
|
||||
)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# Validate sanitizer compatibility
|
||||
if(enable_asan AND enable_tsan)
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"AddressSanitizer and ThreadSanitizer are incompatible and cannot be enabled simultaneously. "
|
||||
"Use 'address' or 'thread', optionally with 'undefinedbehavior'."
|
||||
)
|
||||
endif()
|
||||
|
||||
# Frame pointer is required for meaningful stack traces. Sanitizers recommend minimum of -O1 for reasonable performance
|
||||
set(SANITIZERS_COMPILE_FLAGS "-fno-omit-frame-pointer" "-O1")
|
||||
|
||||
# Build the sanitizer flags list
|
||||
set(SANITIZER_TYPES)
|
||||
|
||||
if(enable_asan)
|
||||
list(APPEND SANITIZER_TYPES "address")
|
||||
elseif(enable_tsan)
|
||||
list(APPEND SANITIZER_TYPES "thread")
|
||||
endif()
|
||||
|
||||
if(enable_ubsan)
|
||||
# UB sanitizer flags
|
||||
list(APPEND SANITIZER_TYPES "undefined" "float-divide-by-zero")
|
||||
if(is_clang)
|
||||
# Clang supports additional UB checks. More info here
|
||||
# https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html
|
||||
list(APPEND SANITIZER_TYPES "unsigned-integer-overflow")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Configure code model for GCC on amd64 Use large code model for ASAN to avoid relocation errors Use medium code model
|
||||
# for TSAN (large is not compatible with TSAN)
|
||||
set(SANITIZERS_RELOCATION_FLAGS)
|
||||
|
||||
# Compiler-specific configuration
|
||||
if(is_gcc)
|
||||
# Disable mold, gold and lld linkers for GCC with sanitizers Use default linker (bfd/ld) which is more lenient with
|
||||
# mixed code models This is needed since the size of instrumented binary exceeds the limits set by mold, lld and
|
||||
# gold linkers
|
||||
set(use_mold OFF CACHE BOOL "Use mold linker" FORCE)
|
||||
set(use_gold OFF CACHE BOOL "Use gold linker" FORCE)
|
||||
set(use_lld OFF CACHE BOOL "Use lld linker" FORCE)
|
||||
@@ -35,62 +140,80 @@ if(is_gcc)
|
||||
STATUS
|
||||
" Disabled mold, gold, and lld linkers for GCC with sanitizers"
|
||||
)
|
||||
|
||||
# Suppress false positive warnings in GCC with stringop-overflow
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-Wno-stringop-overflow")
|
||||
|
||||
if(is_amd64 AND enable_asan)
|
||||
message(STATUS " Using large code model (-mcmodel=large)")
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-mcmodel=large")
|
||||
list(APPEND SANITIZERS_RELOCATION_FLAGS "-mcmodel=large")
|
||||
elseif(enable_tsan)
|
||||
# GCC doesn't support atomic_thread_fence with tsan. Suppress warnings.
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-Wno-tsan")
|
||||
message(STATUS " Using medium code model (-mcmodel=medium)")
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-mcmodel=medium")
|
||||
list(APPEND SANITIZERS_RELOCATION_FLAGS "-mcmodel=medium")
|
||||
endif()
|
||||
|
||||
# Join sanitizer flags with commas for -fsanitize option
|
||||
list(JOIN SANITIZER_TYPES "," SANITIZER_TYPES_STR)
|
||||
|
||||
# Add sanitizer to compile and link flags
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
|
||||
set(SANITIZERS_LINK_FLAGS
|
||||
"${SANITIZERS_RELOCATION_FLAGS}"
|
||||
"-fsanitize=${SANITIZER_TYPES_STR}"
|
||||
)
|
||||
elseif(is_clang)
|
||||
# Add ignorelist for Clang (GCC doesn't support this) Use CMAKE_SOURCE_DIR to get the path to the ignorelist
|
||||
set(IGNORELIST_PATH
|
||||
"${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt"
|
||||
)
|
||||
if(NOT EXISTS "${IGNORELIST_PATH}")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Sanitizer ignorelist not found: ${IGNORELIST_PATH}"
|
||||
)
|
||||
endif()
|
||||
|
||||
list(
|
||||
APPEND SANITIZERS_COMPILE_FLAGS
|
||||
"-fsanitize-ignorelist=${IGNORELIST_PATH}"
|
||||
)
|
||||
message(STATUS " Using sanitizer ignorelist: ${IGNORELIST_PATH}")
|
||||
|
||||
# Join sanitizer flags with commas for -fsanitize option
|
||||
list(JOIN SANITIZER_TYPES "," SANITIZER_TYPES_STR)
|
||||
|
||||
# Add sanitizer to compile and link flags
|
||||
list(APPEND SANITIZERS_COMPILE_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
|
||||
set(SANITIZERS_LINK_FLAGS "-fsanitize=${SANITIZER_TYPES_STR}")
|
||||
endif()
|
||||
|
||||
# Flags arrive as space-separated strings; split into CMake lists before use
|
||||
separate_arguments(
|
||||
sanitizers_compiler_flags
|
||||
UNIX_COMMAND
|
||||
"${SANITIZERS_COMPILER_FLAGS}"
|
||||
)
|
||||
separate_arguments(
|
||||
sanitizers_linker_flags
|
||||
UNIX_COMMAND
|
||||
"${SANITIZERS_LINKER_FLAGS}"
|
||||
)
|
||||
message(STATUS " Compile flags: ${SANITIZERS_COMPILE_FLAGS}")
|
||||
message(STATUS " Link flags: ${SANITIZERS_LINK_FLAGS}")
|
||||
|
||||
# Apply the sanitizer flags to the 'common' interface library This is the same library used by XrplCompiler.cmake
|
||||
target_compile_options(
|
||||
common
|
||||
INTERFACE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:${sanitizers_compiler_flags}>
|
||||
$<$<COMPILE_LANGUAGE:C>:${sanitizers_compiler_flags}>
|
||||
$<$<COMPILE_LANGUAGE:CXX>:${SANITIZERS_COMPILE_FLAGS}>
|
||||
$<$<COMPILE_LANGUAGE:C>:${SANITIZERS_COMPILE_FLAGS}>
|
||||
)
|
||||
target_link_options(common INTERFACE ${sanitizers_linker_flags})
|
||||
|
||||
# This module appends -fsanitize-ignorelist=<path> for Clang builds.
|
||||
# The ignorelist path contains CMAKE_SOURCE_DIR, so it must be set here, rather than in the Conan profile.
|
||||
# GCC does not support -fsanitize-ignorelist.
|
||||
if(is_clang)
|
||||
set(ignorelist_path
|
||||
"${CMAKE_SOURCE_DIR}/sanitizers/suppressions/sanitizer-ignorelist.txt"
|
||||
)
|
||||
if(NOT EXISTS "${ignorelist_path}")
|
||||
message(
|
||||
FATAL_ERROR
|
||||
"Sanitizer ignorelist not found: ${ignorelist_path}"
|
||||
)
|
||||
endif()
|
||||
target_compile_options(
|
||||
common
|
||||
INTERFACE
|
||||
$<$<COMPILE_LANGUAGE:CXX>:-fsanitize-ignorelist=${ignorelist_path}>
|
||||
$<$<COMPILE_LANGUAGE:C>:-fsanitize-ignorelist=${ignorelist_path}>
|
||||
)
|
||||
message(STATUS " Ignorelist: ${ignorelist_path}")
|
||||
endif()
|
||||
# Apply linker flags
|
||||
target_link_options(common INTERFACE ${SANITIZERS_LINK_FLAGS})
|
||||
|
||||
# Define SANITIZERS macro for BuildInfo.cpp
|
||||
set(sanitizers_list)
|
||||
if(SANITIZERS MATCHES "address")
|
||||
set(enable_asan ON)
|
||||
if(enable_asan)
|
||||
list(APPEND sanitizers_list "ASAN")
|
||||
endif()
|
||||
if(SANITIZERS MATCHES "thread")
|
||||
set(enable_tsan ON)
|
||||
if(enable_tsan)
|
||||
list(APPEND sanitizers_list "TSAN")
|
||||
endif()
|
||||
if(SANITIZERS MATCHES "undefinedbehavior")
|
||||
set(enable_ubsan ON)
|
||||
if(enable_ubsan)
|
||||
list(APPEND sanitizers_list "UBSAN")
|
||||
endif()
|
||||
|
||||
|
||||
@@ -152,10 +152,10 @@ def parse_sfields_macro(sfields_path):
|
||||
|
||||
def create_field_list_parser():
|
||||
"""Create a pyparsing parser for field lists like '({...})'."""
|
||||
# A field identifier (e.g., sfDestination, SoeRequired, SoeMptSupported)
|
||||
# A field identifier (e.g., sfDestination, soeREQUIRED, soeMPTSupported)
|
||||
field_identifier = pp.Word(pp.alphas + "_", pp.alphanums + "_")
|
||||
|
||||
# A single field definition: {sfName, SoeRequired, ...}
|
||||
# A single field definition: {sfName, soeREQUIRED, ...}
|
||||
# Allow optional trailing comma inside the braces
|
||||
field_def = (
|
||||
pp.Suppress("{")
|
||||
@@ -185,8 +185,8 @@ def parse_field_list(fields_str):
|
||||
|
||||
Args:
|
||||
fields_str: A string like '({
|
||||
{sfDestination, SoeRequired},
|
||||
{sfAmount, SoeRequired, SoeMptSupported}
|
||||
{sfDestination, soeREQUIRED},
|
||||
{sfAmount, soeREQUIRED, soeMPTSupported}
|
||||
})'
|
||||
|
||||
Returns:
|
||||
@@ -205,7 +205,7 @@ def parse_field_list(fields_str):
|
||||
field_name = field_parts[0]
|
||||
requirement = field_parts[1]
|
||||
flags = list(field_parts[2:]) if len(field_parts) > 2 else []
|
||||
supports_mpt = "SoeMptSupported" in flags
|
||||
supports_mpt = "soeMPTSupported" in flags
|
||||
|
||||
fields.append(
|
||||
{
|
||||
|
||||
@@ -10,4 +10,4 @@ pcpp>=1.30
|
||||
pyparsing>=3.0.0
|
||||
|
||||
# Template engine - used to generate C++ code from templates
|
||||
Mako>=1.2.2
|
||||
Mako>=1.2.0
|
||||
|
||||
@@ -52,13 +52,13 @@ public:
|
||||
% if field.get('mpt_support'):
|
||||
* MPT Support: ${field['mpt_support']}
|
||||
% endif
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'soeREQUIRED':
|
||||
* @return The field value.
|
||||
% else:
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
% endif
|
||||
*/
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'soeREQUIRED':
|
||||
[[nodiscard]]
|
||||
${field['typeData']['return_type']}
|
||||
get${field['name'][2:]}() const
|
||||
@@ -94,13 +94,13 @@ public:
|
||||
* MPT Support: ${field['mpt_support']}
|
||||
% endif
|
||||
* @note This is an untyped field (${field.get('cppType', 'unknown')}).
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'soeREQUIRED':
|
||||
* @return The field value.
|
||||
% else:
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
% endif
|
||||
*/
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'soeREQUIRED':
|
||||
[[nodiscard]]
|
||||
${field['typeData']['return_type']}
|
||||
get${field['name'][2:]}() const
|
||||
@@ -133,13 +133,13 @@ public:
|
||||
};
|
||||
|
||||
<%
|
||||
required_fields = [f for f in fields if f['requirement'] == 'SoeRequired']
|
||||
required_fields = [f for f in fields if f['requirement'] == 'soeREQUIRED']
|
||||
%>\
|
||||
/**
|
||||
* @brief Builder for ${name} ledger entries.
|
||||
*
|
||||
* Provides a fluent interface for constructing ledger entries with method chaining.
|
||||
* Uses STObject internally for flexible ledger entry construction.
|
||||
* Uses Json::Value internally for flexible ledger entry construction.
|
||||
* Inherits common field setters from LedgerEntryBuilderBase.
|
||||
*/
|
||||
class ${name}Builder : public LedgerEntryBuilderBase<${name}Builder>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Auto-generated unit tests for ledger entry ${name}
|
||||
<%
|
||||
required_fields = [f for f in fields if f["requirement"] == "SoeRequired"]
|
||||
optional_fields = [f for f in fields if f["requirement"] != "SoeRequired"]
|
||||
required_fields = [f for f in fields if f["requirement"] == "soeREQUIRED"]
|
||||
optional_fields = [f for f in fields if f["requirement"] != "soeREQUIRED"]
|
||||
|
||||
def canonical_expr(field):
|
||||
return f"canonical_{field['stiSuffix']}()"
|
||||
|
||||
@@ -54,13 +54,13 @@ public:
|
||||
% if field.get('supports_mpt'):
|
||||
* @note This field supports MPT (Multi-Purpose Token) amounts.
|
||||
% endif
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'soeREQUIRED':
|
||||
* @return The field value.
|
||||
% else:
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
% endif
|
||||
*/
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'soeREQUIRED':
|
||||
[[nodiscard]]
|
||||
${field['typeData']['return_type']}
|
||||
get${field['name'][2:]}() const
|
||||
@@ -97,13 +97,13 @@ public:
|
||||
* @note This field supports MPT (Multi-Purpose Token) amounts.
|
||||
% endif
|
||||
* @note This is an untyped field.
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'soeREQUIRED':
|
||||
* @return The field value.
|
||||
% else:
|
||||
* @return The field value, or std::nullopt if not present.
|
||||
% endif
|
||||
*/
|
||||
% if field['requirement'] == 'SoeRequired':
|
||||
% if field['requirement'] == 'soeREQUIRED':
|
||||
[[nodiscard]]
|
||||
${field['typeData']['return_type']}
|
||||
get${field['name'][2:]}() const
|
||||
@@ -136,13 +136,13 @@ public:
|
||||
};
|
||||
|
||||
<%
|
||||
required_fields = [f for f in fields if f['requirement'] == 'SoeRequired']
|
||||
required_fields = [f for f in fields if f['requirement'] == 'soeREQUIRED']
|
||||
%>\
|
||||
/**
|
||||
* @brief Builder for ${name} transactions.
|
||||
*
|
||||
* Provides a fluent interface for constructing transactions with method chaining.
|
||||
* Uses STObject internally for flexible transaction construction.
|
||||
* Uses Json::Value internally for flexible transaction construction.
|
||||
* Inherits common field setters from TransactionBuilderBase.
|
||||
*/
|
||||
class ${name}Builder : public TransactionBuilderBase<${name}Builder>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Auto-generated unit tests for transaction ${name}
|
||||
<%
|
||||
required_fields = [f for f in fields if f["requirement"] == "SoeRequired"]
|
||||
optional_fields = [f for f in fields if f["requirement"] != "SoeRequired"]
|
||||
required_fields = [f for f in fields if f["requirement"] == "soeREQUIRED"]
|
||||
optional_fields = [f for f in fields if f["requirement"] != "soeREQUIRED"]
|
||||
|
||||
def canonical_expr(field):
|
||||
return f"canonical_{field['stiSuffix']}()"
|
||||
@@ -33,7 +33,7 @@ TEST(Transactions${name}Tests, BuilderSettersRoundTrip)
|
||||
{
|
||||
// Generate a deterministic keypair for signing
|
||||
auto const [publicKey, secretKey] =
|
||||
generateKeyPair(KeyType::Secp256k1, generateSeed("test${name}"));
|
||||
generateKeyPair(KeyType::secp256k1, generateSeed("test${name}"));
|
||||
|
||||
// Common transaction fields
|
||||
auto const accountValue = calcAccountID(publicKey);
|
||||
@@ -101,7 +101,7 @@ TEST(Transactions${name}Tests, BuilderFromStTxRoundTrip)
|
||||
{
|
||||
// Generate a deterministic keypair for signing
|
||||
auto const [publicKey, secretKey] =
|
||||
generateKeyPair(KeyType::Secp256k1, generateSeed("test${name}FromTx"));
|
||||
generateKeyPair(KeyType::secp256k1, generateSeed("test${name}FromTx"));
|
||||
|
||||
// Common transaction fields
|
||||
auto const accountValue = calcAccountID(publicKey);
|
||||
@@ -168,7 +168,7 @@ TEST(Transactions${name}Tests, WrapperThrowsOnWrongTxType)
|
||||
{
|
||||
// Build a valid transaction of a different type
|
||||
auto const [pk, sk] =
|
||||
generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongType"));
|
||||
generateKeyPair(KeyType::secp256k1, generateSeed("testWrongType"));
|
||||
auto const account = calcAccountID(pk);
|
||||
|
||||
% if wrong_tx_include == "AccountSet":
|
||||
@@ -186,7 +186,7 @@ TEST(Transactions${name}Tests, BuilderThrowsOnWrongTxType)
|
||||
{
|
||||
// Build a valid transaction of a different type
|
||||
auto const [pk, sk] =
|
||||
generateKeyPair(KeyType::Secp256k1, generateSeed("testWrongTypeBuilder"));
|
||||
generateKeyPair(KeyType::secp256k1, generateSeed("testWrongTypeBuilder"));
|
||||
auto const account = calcAccountID(pk);
|
||||
|
||||
% if wrong_tx_include == "AccountSet":
|
||||
@@ -205,7 +205,7 @@ TEST(Transactions${name}Tests, OptionalFieldsReturnNullopt)
|
||||
{
|
||||
// Generate a deterministic keypair for signing
|
||||
auto const [publicKey, secretKey] =
|
||||
generateKeyPair(KeyType::Secp256k1, generateSeed("test${name}Nullopt"));
|
||||
generateKeyPair(KeyType::secp256k1, generateSeed("test${name}Nullopt"));
|
||||
|
||||
// Common transaction fields
|
||||
auto const accountValue = calcAccountID(publicKey);
|
||||
|
||||
24
conan.lock
24
conan.lock
@@ -1,38 +1,38 @@
|
||||
{
|
||||
"version": "0.5",
|
||||
"requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1777558780.503",
|
||||
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1774439233.809",
|
||||
"xxhash/0.8.3#681d36a0a6111fc56e5e45ea182c19cc%1765850149.987",
|
||||
"sqlite3/3.53.0#324ada52333108388a9a6108bfa96734%1776096494.149",
|
||||
"sqlite3/3.51.0#66aa11eabd0e34954c5c1c061ad44abe%1774467355.988",
|
||||
"soci/4.0.3#fe32b9ad5eb47e79ab9e45a68f363945%1774450067.231",
|
||||
"snappy/1.1.10#968fef506ff261592ec30c574d4a7809%1765850147.878",
|
||||
"secp256k1/0.7.1#481881709eb0bdd0185a12b912bbe8ad%1770910500.329",
|
||||
"rocksdb/10.5.1#4a197eca381a3e5ae8adf8cffa5aacd0%1765850186.86",
|
||||
"re2/20251105#8579cfd0bda4daf0683f9e3898f964b4%1774398111.888",
|
||||
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12",
|
||||
"openssl/3.6.2#4789bbf131b77d0515d15e094c8f697f%1778071755.506",
|
||||
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1775040983.408",
|
||||
"openssl/3.6.1#e6399de266349245a4542fc5f6c71552%1774458290.139",
|
||||
"nudb/2.0.9#11149c73f8f2baff9a0198fe25971fc7%1774883011.384",
|
||||
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504%1765850143.914",
|
||||
"libiconv/1.17#1e65319e945f2d31941a9d28cc13c058%1765842973.492",
|
||||
"libbacktrace/cci.20210118#a7691bfccd8caaf66309df196790a5a1%1765842973.03",
|
||||
"libarchive/3.8.7#c446109bd1f1d8ba7936c94189bc50e6%1776147552.838",
|
||||
"jemalloc/5.3.1#1fc58d55316041f10fbc1e8a2eae632a%1776700028.228",
|
||||
"libarchive/3.8.1#ffee18995c706e02bf96e7a2f7042e0d%1765850144.736",
|
||||
"jemalloc/5.3.0#e951da9cf599e956cebc117880d2d9f8%1729241615.244",
|
||||
"gtest/1.17.0#5224b3b3ff3b4ce1133cbdd27d53ee7d%1768312129.152",
|
||||
"grpc/1.78.1#b1a9e74b145cc471bed4dc64dc6eb2c1%1774467387.342",
|
||||
"ed25519/2015.03#ae761bdc52730a843f0809bdf6c1b1f6%1765850143.772",
|
||||
"date/3.0.4#862e11e80030356b53c2c38599ceb32b%1765850143.772",
|
||||
"c-ares/1.34.6#545240bb1c40e2cacd4362d6b8967650%1774439234.681",
|
||||
"bzip2/1.0.8#c470882369c2d95c5c77e970c0c7e321%1765850143.837",
|
||||
"boost/1.91.0#ea540ca2133d831b560036aa24dece3c%1778050991.9",
|
||||
"boost/1.90.0#d5e8defe7355494953be18524a7f135b%1769454080.269",
|
||||
"abseil/20250127.0#bb0baf1f362bc4a725a24eddd419b8f7%1774365460.196"
|
||||
],
|
||||
"build_requires": [
|
||||
"zlib/1.3.2#1cb806da49011867778ffb6ac7190fcb%1777558780.503",
|
||||
"zlib/1.3.1#cac0f6daea041b0ccf42934163defb20%1774439233.809",
|
||||
"strawberryperl/5.32.1.1#8d114504d172cfea8ea1662d09b6333e%1774447376.964",
|
||||
"protobuf/6.33.5#d96d52ba5baaaa532f47bda866ad87a5%1774467363.12",
|
||||
"nasm/2.16.01#31e26f2ee3c4346ecd347911bd126904%1765850144.707",
|
||||
"msys2/cci.latest#d22fe7b2808f5fd34d0a7923ace9c54f%1770657326.649",
|
||||
"m4/1.4.19#4523e4347b55cd26ae918bd5770cab9a%1778062762.471",
|
||||
"m4/1.4.19#5d7a4994e5875d76faf7acf3ed056036%1774365463.87",
|
||||
"cmake/4.3.0#b939a42e98f593fb34d3a8c5cc860359%1774439249.183",
|
||||
"b2/5.4.2#ffd6084a119587e70f11cd45d1a386e2%1774439233.447",
|
||||
"automake/1.16.5#b91b7c384c3deaa9d535be02da14d04f%1755524470.56",
|
||||
@@ -48,13 +48,13 @@
|
||||
"lz4/1.10.0"
|
||||
],
|
||||
"boost/[>=1.83.0 <1.91.0]": [
|
||||
"boost/1.91.0"
|
||||
"boost/1.90.0"
|
||||
],
|
||||
"sqlite3/[>=3.44 <4]": [
|
||||
"sqlite3/3.53.0"
|
||||
"sqlite3/3.51.0"
|
||||
],
|
||||
"boost/1.83.0": [
|
||||
"boost/1.91.0"
|
||||
"boost/1.90.0"
|
||||
],
|
||||
"lz4/[>=1.9.4 <2]": [
|
||||
"lz4/1.10.0#59fc63cac7f10fbe8e05c7e62c2f3504"
|
||||
|
||||
@@ -3,5 +3,3 @@
|
||||
core:non_interactive=True
|
||||
core.download:parallel={{ os.cpu_count() }}
|
||||
core.upload:parallel={{ os.cpu_count() }}
|
||||
tools.files.download:retry=5
|
||||
tools.files.download:retry_wait=10
|
||||
|
||||
@@ -1 +1 @@
|
||||
include(sanitizers)
|
||||
include(sanitizers)
|
||||
|
||||
@@ -1,122 +1,93 @@
|
||||
include(default)
|
||||
{% set compiler, version, compiler_exe = detect_api.detect_default_compiler() %}
|
||||
{% set arch = detect_api.detect_arch() %}
|
||||
{% set sanitizers = os.getenv("SANITIZERS") %}
|
||||
|
||||
{% if not sanitizers %}
|
||||
{# Sanitizers not configured; no additional settings needed #}
|
||||
{% else %}
|
||||
[conf]
|
||||
{% if sanitizers %}
|
||||
{% if compiler == "gcc" %}
|
||||
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
|
||||
{% set sanitizer_list = [] %}
|
||||
{% set defines = [] %}
|
||||
{% set model_code = "" %}
|
||||
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1", "-Wno-stringop-overflow"] %}
|
||||
|
||||
{% if compiler == "msvc" %}
|
||||
{{ "Sanitizers are not supported on Windows/MSVC. Please unset the SANITIZERS environment variable." }}
|
||||
{% endif %}
|
||||
{% if "address" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("address") %}
|
||||
{% set model_code = "-mcmodel=large" %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% elif "thread" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("thread") %}
|
||||
{% set model_code = "-mcmodel=medium" %}
|
||||
{% set _ = extra_cxxflags.append("-Wno-tsan") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% endif %}
|
||||
|
||||
{% set known_sanitizers = ["address", "thread", "undefinedbehavior"] %}
|
||||
{% set provided_sanitizers = [] %}
|
||||
{% for san in sanitizers.split(",") %}
|
||||
{% set san = san.strip() %}
|
||||
{% if san not in known_sanitizers %}
|
||||
{{ "Unknown sanitizer in SANITIZERS: " ~ san }}
|
||||
{% endif %}
|
||||
{% set _ = provided_sanitizers.append(san) %}
|
||||
{% endfor %}
|
||||
{% if "undefinedbehavior" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("undefined") %}
|
||||
{% set _ = sanitizer_list.append("float-divide-by-zero") %}
|
||||
{% endif %}
|
||||
|
||||
{% set enable_asan = "address" in provided_sanitizers %}
|
||||
{% set enable_tsan = "thread" in provided_sanitizers %}
|
||||
{% set enable_ubsan = "undefinedbehavior" in provided_sanitizers %}
|
||||
{% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) ~ " " ~ model_code %}
|
||||
|
||||
{% if enable_asan and enable_tsan %}
|
||||
{{ "AddressSanitizer and ThreadSanitizer are incompatible and cannot be enabled simultaneously." }}
|
||||
{% endif %}
|
||||
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:defines+={{defines}}
|
||||
{% endif %}
|
||||
{% elif compiler == "apple-clang" or compiler == "clang" %}
|
||||
{% if "address" in sanitizers or "thread" in sanitizers or "undefinedbehavior" in sanitizers %}
|
||||
{% set sanitizer_list = [] %}
|
||||
{% set defines = [] %}
|
||||
{% set extra_cxxflags = ["-fno-omit-frame-pointer", "-O1"] %}
|
||||
|
||||
{% set sanitizer_types = [] %}
|
||||
{% set defines = [] %}
|
||||
{% if "address" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("address") %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% elif "thread" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("thread") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN")%}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT")%}
|
||||
{% endif %}
|
||||
|
||||
{% if enable_asan %}
|
||||
{% set _ = sanitizer_types.append("address") %}
|
||||
{% set _ = defines.append("BOOST_USE_ASAN") %}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT") %}
|
||||
{% elif enable_tsan %}
|
||||
{% set _ = sanitizer_types.append("thread") %}
|
||||
{% set _ = defines.append("BOOST_USE_TSAN") %}
|
||||
{% set _ = defines.append("BOOST_USE_UCONTEXT") %}
|
||||
{% endif %}
|
||||
{% if "undefinedbehavior" in sanitizers %}
|
||||
{% set _ = sanitizer_list.append("undefined") %}
|
||||
{% set _ = sanitizer_list.append("float-divide-by-zero") %}
|
||||
{% set _ = sanitizer_list.append("unsigned-integer-overflow") %}
|
||||
{% endif %}
|
||||
|
||||
{% if enable_ubsan %}
|
||||
{% set _ = sanitizer_types.append("undefined") %}
|
||||
{% set _ = sanitizer_types.append("float-divide-by-zero") %}
|
||||
{# Clang supports additional UB checks beyond the GCC baseline #}
|
||||
{% if compiler == "clang" or compiler == "apple-clang" %}
|
||||
{% set _ = sanitizer_types.append("unsigned-integer-overflow") %}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% set sanitizer_flags = "-fsanitize=" ~ ",".join(sanitizer_list) %}
|
||||
|
||||
{# Frame pointer required for meaningful stack traces; -O1 for reasonable performance #}
|
||||
{% set compile_flags = ["-fno-omit-frame-pointer", "-O1"] %}
|
||||
|
||||
{% if compiler == "gcc" %}
|
||||
{# Suppress false positive warnings with GCC #}
|
||||
{% set _ = compile_flags.append("-Wno-stringop-overflow") %}
|
||||
|
||||
{% set relocation_flags = [] %}
|
||||
|
||||
{% if arch == "x86_64" and enable_asan %}
|
||||
{# Large code model prevents relocation errors in instrumented ASAN binaries #}
|
||||
{% set _ = compile_flags.append("-mcmodel=large") %}
|
||||
{% set _ = relocation_flags.append("-mcmodel=large") %}
|
||||
{% elif enable_tsan %}
|
||||
{# GCC doesn't support atomic_thread_fence with TSAN; suppress warnings #}
|
||||
{% set _ = compile_flags.append("-Wno-tsan") %}
|
||||
{% if arch == "x86_64" %}
|
||||
{# Medium code model for TSAN; large is incompatible #}
|
||||
{% set _ = compile_flags.append("-mcmodel=medium") %}
|
||||
{% set _ = relocation_flags.append("-mcmodel=medium") %}
|
||||
tools.build:cxxflags+=['{{sanitizer_flags}} {{" ".join(extra_cxxflags)}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_flags}}']
|
||||
tools.build:defines+={{defines}}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
{% set fsanitize = "-fsanitize=" ~ ",".join(sanitizer_types) %}
|
||||
{% set _ = compile_flags.append(fsanitize) %}
|
||||
{% set _ = relocation_flags.append(fsanitize) %}
|
||||
|
||||
{% set sanitizer_compiler_flags = " ".join(compile_flags) %}
|
||||
{% set sanitizer_linker_flags = " ".join(relocation_flags) %}
|
||||
{% elif compiler == "clang" or compiler == "apple-clang" %}
|
||||
{% set fsanitize = "-fsanitize=" ~ ",".join(sanitizer_types) %}
|
||||
{% set _ = compile_flags.append(fsanitize) %}
|
||||
|
||||
{% set sanitizer_compiler_flags = " ".join(compile_flags) %}
|
||||
{% set sanitizer_linker_flags = fsanitize %}
|
||||
{% endif %}
|
||||
|
||||
[conf]
|
||||
tools.build:defines+={{defines}}
|
||||
tools.build:cxxflags+=['{{sanitizer_compiler_flags}}']
|
||||
tools.build:sharedlinkflags+=['{{sanitizer_linker_flags}}']
|
||||
tools.build:exelinkflags+=['{{sanitizer_linker_flags}}']
|
||||
|
||||
tools.info.package_id:confs+=["tools.build:cxxflags", "tools.build:exelinkflags", "tools.build:sharedlinkflags", "tools.build:defines"]
|
||||
|
||||
# &: means "apply only to the consumer/root package"
|
||||
&:tools.cmake.cmaketoolchain:extra_variables={"SANITIZERS": "{{sanitizers}}", "SANITIZERS_COMPILER_FLAGS": "{{sanitizer_compiler_flags}}", "SANITIZERS_LINKER_FLAGS": "{{sanitizer_linker_flags}}"}
|
||||
|
||||
[options]
|
||||
{% if enable_asan %}
|
||||
# Build Boost.Context with ucontext backend (not fcontext) so that
|
||||
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
|
||||
# are compiled into the library. fcontext (assembly) has no ASAN support.
|
||||
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
|
||||
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
|
||||
boost/*:without_context=False
|
||||
# Boost stacktrace fails to build with some sanitizers
|
||||
boost/*:without_stacktrace=True
|
||||
{% elif enable_tsan %}
|
||||
# Build Boost.Context with ucontext backend for TSAN. fcontext (assembly)
|
||||
# has no TSAN annotations, so without this the BOOST_USE_TSAN/BOOST_USE_UCONTEXT
|
||||
# defines in [conf] would be ineffective.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext thread-sanitizer=on define=BOOST_USE_TSAN=1
|
||||
boost/*:without_context=False
|
||||
boost/*:without_stacktrace=True
|
||||
{% endif %}
|
||||
|
||||
{% if sanitizers %}
|
||||
{% if "address" in sanitizers %}
|
||||
# Build Boost.Context with ucontext backend (not fcontext) so that
|
||||
# ASAN fiber-switching annotations (__sanitizer_start/finish_switch_fiber)
|
||||
# are compiled into the library. fcontext (assembly) has no ASAN support.
|
||||
# define=BOOST_USE_ASAN=1 is critical: it must be defined when building
|
||||
# Boost.Context itself so the ucontext backend compiles in the ASAN annotations.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext address-sanitizer=on define=BOOST_USE_ASAN=1
|
||||
boost/*:without_context=False
|
||||
# Boost stacktrace fails to build with some sanitizers
|
||||
boost/*:without_stacktrace=True
|
||||
{% elif "thread" in sanitizers %}
|
||||
# Build Boost.Context with ucontext backend for TSAN. fcontext (assembly)
|
||||
# has no TSAN annotations, so without this the BOOST_USE_TSAN/BOOST_USE_UCONTEXT
|
||||
# defines in [conf] would be ineffective.
|
||||
boost/*:extra_b2_flags=context-impl=ucontext thread-sanitizer=on define=BOOST_USE_TSAN=1
|
||||
boost/*:without_context=False
|
||||
boost/*:without_stacktrace=True
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
14
conanfile.py
14
conanfile.py
@@ -1,3 +1,4 @@
|
||||
import os
|
||||
import re
|
||||
|
||||
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
|
||||
@@ -29,12 +30,12 @@ class Xrpl(ConanFile):
|
||||
requires = [
|
||||
"ed25519/2015.03",
|
||||
"grpc/1.78.1",
|
||||
"libarchive/3.8.7",
|
||||
"libarchive/3.8.1",
|
||||
"nudb/2.0.9",
|
||||
"openssl/3.6.2",
|
||||
"openssl/3.6.1",
|
||||
"secp256k1/0.7.1",
|
||||
"soci/4.0.3",
|
||||
"zlib/1.3.2",
|
||||
"zlib/1.3.1",
|
||||
]
|
||||
|
||||
test_requires = [
|
||||
@@ -56,7 +57,6 @@ class Xrpl(ConanFile):
|
||||
"tests": False,
|
||||
"unity": False,
|
||||
"xrpld": False,
|
||||
"boost/*:without_cobalt": True,
|
||||
"boost/*:without_context": False,
|
||||
"boost/*:without_coroutine": True,
|
||||
"boost/*:without_coroutine2": False,
|
||||
@@ -130,13 +130,13 @@ class Xrpl(ConanFile):
|
||||
self.options["boost"].without_cobalt = True
|
||||
|
||||
def requirements(self):
|
||||
self.requires("boost/1.91.0", force=True, transitive_headers=True)
|
||||
self.requires("boost/1.90.0", force=True, transitive_headers=True)
|
||||
self.requires("date/3.0.4", transitive_headers=True)
|
||||
self.requires("lz4/1.10.0", force=True)
|
||||
self.requires("protobuf/6.33.5", force=True)
|
||||
self.requires("sqlite3/3.53.0", force=True)
|
||||
self.requires("sqlite3/3.51.0", force=True)
|
||||
if self.options.jemalloc:
|
||||
self.requires("jemalloc/5.3.1")
|
||||
self.requires("jemalloc/5.3.0")
|
||||
if self.options.rocksdb:
|
||||
self.requires("rocksdb/10.5.1")
|
||||
self.requires("xxhash/0.8.3", transitive_headers=True)
|
||||
|
||||
@@ -63,7 +63,6 @@ words:
|
||||
- Bougalis
|
||||
- Britto
|
||||
- Btrfs
|
||||
- Buildx
|
||||
- canonicality
|
||||
- changespq
|
||||
- checkme
|
||||
@@ -72,7 +71,6 @@ words:
|
||||
- citardauq
|
||||
- clawback
|
||||
- clawbacks
|
||||
- cmaketoolchain
|
||||
- coeffs
|
||||
- coldwallet
|
||||
- compr
|
||||
@@ -99,15 +97,12 @@ words:
|
||||
- desync
|
||||
- desynced
|
||||
- determ
|
||||
- disablerepo
|
||||
- distro
|
||||
- doxyfile
|
||||
- dxrpl
|
||||
- enabled
|
||||
- enablerepo
|
||||
- endmacro
|
||||
- exceptioned
|
||||
- EXPECT_STREQ
|
||||
- Falco
|
||||
- fcontext
|
||||
- finalizers
|
||||
@@ -119,7 +114,6 @@ words:
|
||||
- gcovr
|
||||
- ghead
|
||||
- Gnutella
|
||||
- godexsoft
|
||||
- gpgcheck
|
||||
- gpgkey
|
||||
- hotwallet
|
||||
@@ -157,7 +151,6 @@ words:
|
||||
- lseq
|
||||
- lsmf
|
||||
- ltype
|
||||
- mathbunnyru
|
||||
- mcmodel
|
||||
- MEMORYSTATUSEX
|
||||
- MPTAMM
|
||||
@@ -165,7 +158,6 @@ words:
|
||||
- Merkle
|
||||
- Metafuncton
|
||||
- misprediction
|
||||
- missingok
|
||||
- mptbalance
|
||||
- MPTDEX
|
||||
- mptflags
|
||||
@@ -197,9 +189,7 @@ words:
|
||||
- NOLINT
|
||||
- NOLINTNEXTLINE
|
||||
- nonxrp
|
||||
- noreplace
|
||||
- noripple
|
||||
- notifempty
|
||||
- nudb
|
||||
- nullptr
|
||||
- nunl
|
||||
@@ -219,7 +209,6 @@ words:
|
||||
- preauthorize
|
||||
- preauthorizes
|
||||
- preclaim
|
||||
- preun
|
||||
- protobuf
|
||||
- protos
|
||||
- ptrs
|
||||
@@ -254,14 +243,12 @@ words:
|
||||
- sfields
|
||||
- shamap
|
||||
- shamapitem
|
||||
- shlibs
|
||||
- sidechain
|
||||
- SIGGOOD
|
||||
- sle
|
||||
- sles
|
||||
- soci
|
||||
- socidb
|
||||
- SRPMS
|
||||
- sslws
|
||||
- statsd
|
||||
- STATSDCOLLECTOR
|
||||
@@ -289,8 +276,8 @@ words:
|
||||
- txn
|
||||
- txns
|
||||
- txs
|
||||
- ubsan
|
||||
- UBSAN
|
||||
- ubsan
|
||||
- umant
|
||||
- unacquired
|
||||
- unambiguity
|
||||
@@ -327,6 +314,7 @@ words:
|
||||
- xbridge
|
||||
- xchain
|
||||
- ximinez
|
||||
- EXPECT_STREQ
|
||||
- XMACRO
|
||||
- xrpkuwait
|
||||
- xrpl
|
||||
@@ -334,4 +322,3 @@ words:
|
||||
- xrplf
|
||||
- xxhash
|
||||
- xxhasher
|
||||
- CGNAT
|
||||
|
||||
@@ -1,66 +0,0 @@
|
||||
ARG BASE_IMAGE=nixos/nix:latest
|
||||
|
||||
# Nix builder
|
||||
FROM nixos/nix:latest AS builder-source
|
||||
|
||||
RUN mkdir -p ~/.config/nix && \
|
||||
echo "experimental-features = nix-command flakes" >> ~/.config/nix/nix.conf
|
||||
|
||||
# Copy our source and setup our working dir.
|
||||
COPY nix/ci-env.nix /tmp/build/nix/ci-env.nix
|
||||
COPY nix/packages.nix /tmp/build/nix/packages.nix
|
||||
COPY nix/utils.nix /tmp/build/nix/utils.nix
|
||||
COPY flake.nix /tmp/build/
|
||||
COPY flake.lock /tmp/build/
|
||||
WORKDIR /tmp/build
|
||||
|
||||
FROM builder-source AS builder
|
||||
|
||||
# Build our Nix CI environment (all build tools in a single store path)
|
||||
RUN nix \
|
||||
--option filter-syscalls false \
|
||||
build
|
||||
|
||||
# Copy the Nix store closure into a directory. The Nix store closure is the
|
||||
# entire set of Nix store values that we need for our build.
|
||||
RUN mkdir /tmp/nix-store-closure && \
|
||||
cp -R $(nix-store -qR result/) /tmp/nix-store-closure
|
||||
|
||||
# Final image
|
||||
FROM ${BASE_IMAGE}
|
||||
|
||||
# bash is not located at /bin/bash in nixos/nix, so we need to create a symlink to it.
|
||||
RUN if [ -d /nix ]; then \
|
||||
ln -s /root/.nix-profile/bin/bash /bin/bash; \
|
||||
fi
|
||||
|
||||
# Use Bash as the default shell for RUN commands, using the options
|
||||
# `set -o errexit -o pipefail`, and as the entrypoint.
|
||||
SHELL ["/bin/bash", "-e", "-o", "pipefail", "-c"]
|
||||
ENTRYPOINT ["/bin/bash"]
|
||||
|
||||
# Copy /nix/store and the env symlink tree
|
||||
COPY --from=builder /tmp/nix-store-closure /nix/store
|
||||
COPY --from=builder /tmp/build/result /nix/ci-env
|
||||
|
||||
ENV PATH="/nix/ci-env/bin:$PATH"
|
||||
|
||||
RUN <<EOF
|
||||
ccache --version
|
||||
clang-format --version
|
||||
cmake --version
|
||||
conan --version
|
||||
g++ --version
|
||||
gcc --version
|
||||
gcovr --version
|
||||
git --version
|
||||
make --version
|
||||
mold --version
|
||||
ninja --version
|
||||
perl --version
|
||||
pkg-config --version
|
||||
pre-commit --version
|
||||
python3 --version
|
||||
run-clang-tidy --help
|
||||
vim --version
|
||||
EOF
|
||||
47
docs/build/sanitizers.md
vendored
47
docs/build/sanitizers.md
vendored
@@ -1,17 +1,15 @@
|
||||
# Sanitizer Configuration for Xrpld
|
||||
|
||||
This document explains how to properly configure and run sanitizers (`AddressSanitizer`, `UndefinedBehaviorSanitizer`, `ThreadSanitizer`) with the xrpld project.
|
||||
This document explains how to properly configure and run sanitizers (AddressSanitizer, undefinedbehaviorSanitizer, ThreadSanitizer) with the xrpld project.
|
||||
Corresponding suppression files are located in the `sanitizers/suppressions` directory.
|
||||
|
||||
> [!CAUTION]
|
||||
> Do not mix Address and Thread sanitizers - they are incompatible.
|
||||
> Also, we don't yet support MSVC sanitizers, so this is only for Clang/GCC builds.
|
||||
|
||||
- [Sanitizer Configuration for Xrpld](#sanitizer-configuration-for-xrpld)
|
||||
- [Building with Sanitizers](#building-with-sanitizers)
|
||||
- [Summary](#summary)
|
||||
- [Build steps:](#build-steps)
|
||||
- [Install dependencies](#install-dependencies)
|
||||
- [Call CMake](#call-cmake)
|
||||
- [Build](#build)
|
||||
- [Running Tests with Sanitizers](#running-tests-with-sanitizers)
|
||||
- [AddressSanitizer (ASAN)](#addresssanitizer-asan)
|
||||
- [ThreadSanitizer (TSan)](#threadsanitizer-tsan)
|
||||
@@ -35,13 +33,9 @@ Corresponding suppression files are located in the `sanitizers/suppressions` dir
|
||||
Follow the same instructions as mentioned in [BUILD.md](../../BUILD.md) but with the following changes:
|
||||
|
||||
1. Make sure you have a clean build directory.
|
||||
2. Set the `SANITIZERS` environment variable before calling `conan install`. Only set it once.
|
||||
2. Set the `SANITIZERS` environment variable before calling conan install and cmake. Only set it once. Make sure both conan and cmake read the same values.
|
||||
Example: `export SANITIZERS=address,undefinedbehavior`
|
||||
3. Use `--profile:all sanitizers` with Conan to build dependencies with sanitizer instrumentation.
|
||||
|
||||
> [!NOTE]
|
||||
> Building with sanitizer-instrumented dependencies is slower but produces fewer false positives.
|
||||
|
||||
3. Optionally use `--profile:all sanitizers` with Conan to build dependencies with sanitizer instrumentation. [!NOTE]Building with sanitizer-instrumented dependencies is slower but produces fewer false positives.
|
||||
4. Set `ASAN_OPTIONS`, `LSAN_OPTIONS`, `UBSAN_OPTIONS` and `TSAN_OPTIONS` environment variables to configure sanitizer behavior when running executables. [More details below](#running-tests-with-sanitizers).
|
||||
|
||||
---
|
||||
@@ -57,13 +51,36 @@ cd .build
|
||||
|
||||
#### Install dependencies
|
||||
|
||||
The `SANITIZERS` environment variable is used during `conan install` command.
|
||||
The `SANITIZERS` environment variable is used by both Conan and CMake.
|
||||
|
||||
```bash
|
||||
SANITIZERS=address,undefinedbehavior conan install .. --output-folder . --build missing --settings build_type=Debug --profile:all sanitizers
|
||||
export SANITIZERS=address,undefinedbehavior
|
||||
# Standard build (without instrumenting dependencies)
|
||||
conan install .. --output-folder . --build missing --settings build_type=Debug
|
||||
|
||||
# Or with sanitizer-instrumented dependencies (takes longer but fewer false positives)
|
||||
conan install .. --output-folder . --profile:all sanitizers --build missing --settings build_type=Debug
|
||||
```
|
||||
|
||||
Proceed with the rest of the build instructions as mentioned in [BUILD.md](../../BUILD.md).
|
||||
[!CAUTION]
|
||||
Do not mix Address and Thread sanitizers - they are incompatible.
|
||||
|
||||
Since you already set the `SANITIZERS` environment variable when running Conan, same values will be read for the next part.
|
||||
|
||||
#### Call CMake
|
||||
|
||||
```bash
|
||||
cmake .. -G Ninja \
|
||||
-DCMAKE_TOOLCHAIN_FILE:FILEPATH=build/generators/conan_toolchain.cmake \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-Dtests=ON -Dxrpld=ON
|
||||
```
|
||||
|
||||
#### Build
|
||||
|
||||
```bash
|
||||
cmake --build . --parallel 4
|
||||
```
|
||||
|
||||
## Running Tests with Sanitizers
|
||||
|
||||
@@ -81,7 +98,7 @@ export LSAN_OPTIONS="include=sanitizers/suppressions/runtime-lsan-options.txt:su
|
||||
|
||||
**Why `detect_container_overflow=0`?**
|
||||
|
||||
- Boost intrusive containers (used in `AgedUnorderedContainer`) trigger false positives
|
||||
- Boost intrusive containers (used in `aged_unordered_container`) trigger false positives
|
||||
- Boost context switching (used in `Workers.cpp`) confuses ASAN's stack tracking
|
||||
- Since we usually don't build Boost (because we don't want to instrument Boost and detect issues in Boost code) with ASAN but use Boost containers in ASAN instrumented xrpld code, it generates false positives.
|
||||
- Building dependencies with ASAN instrumentation reduces false positives. But we don't want to instrument dependencies like Boost with ASAN because it is slow (to compile as well as run tests) and not necessary.
|
||||
|
||||
@@ -477,7 +477,7 @@ struct Ledger
|
||||
// The parent ledger's close time
|
||||
NetClock::time_point parentCloseTime() const;
|
||||
|
||||
json::Value getJson() const;
|
||||
Json::Value getJson() const;
|
||||
|
||||
//... implementation specific
|
||||
};
|
||||
|
||||
26
flake.lock
generated
26
flake.lock
generated
@@ -2,11 +2,11 @@
|
||||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1777954456,
|
||||
"narHash": "sha256-hGdgeU2Nk87RAuZyYjyDjFL6LK7dAZN5RE9+hrDTkDU=",
|
||||
"lastModified": 1769461804,
|
||||
"narHash": "sha256-6h5sROT/3CTHvzPy9koKBmoCa2eJKh4fzQK8eYFEgl8=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "549bd84d6279f9852cae6225e372cc67fb91a4c1",
|
||||
"rev": "b579d443b37c9c5373044201ea77604e37e748c8",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
@@ -15,27 +15,9 @@
|
||||
"type": "indirect"
|
||||
}
|
||||
},
|
||||
"nixpkgs-glibc231": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1593520194,
|
||||
"narHash": "sha256-+TZW+2I7kLL9JglPNOagm1ywjf9ua0JYGoptq/dzVn0=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9cd98386a38891d1074fc18036b842dc4416f562",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "9cd98386a38891d1074fc18036b842dc4416f562",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"nixpkgs": "nixpkgs",
|
||||
"nixpkgs-glibc231": "nixpkgs-glibc231"
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
13
flake.nix
13
flake.nix
@@ -2,24 +2,15 @@
|
||||
description = "Nix related things for xrpld";
|
||||
inputs = {
|
||||
nixpkgs.url = "nixpkgs/nixos-unstable";
|
||||
# nixpkgs snapshot (2020-06-30) that shipped glibc 2.31 as the primary
|
||||
# version — matches the system libc on Ubuntu 20.04 LTS. Imported
|
||||
# manually (flake = false) because this revision predates nixpkgs'
|
||||
# own flake.nix.
|
||||
nixpkgs-glibc231 = {
|
||||
url = "github:NixOS/nixpkgs/9cd98386a38891d1074fc18036b842dc4416f562";
|
||||
flake = false;
|
||||
};
|
||||
};
|
||||
|
||||
outputs =
|
||||
{ nixpkgs, nixpkgs-glibc231, ... }:
|
||||
{ nixpkgs, ... }:
|
||||
let
|
||||
forEachSystem = import ./nix/utils.nix { inherit nixpkgs nixpkgs-glibc231; };
|
||||
forEachSystem = (import ./nix/utils.nix { inherit nixpkgs; }).forEachSystem;
|
||||
in
|
||||
{
|
||||
devShells = forEachSystem (import ./nix/devshell.nix);
|
||||
packages = forEachSystem (import ./nix/ci-env.nix);
|
||||
formatter = forEachSystem ({ pkgs, ... }: pkgs.nixfmt);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -27,7 +27,7 @@ private:
|
||||
std::unordered_map<std::string, std::string> lookup_;
|
||||
std::vector<std::string> lines_;
|
||||
std::vector<std::string> values_;
|
||||
bool hadTrailingComments_ = false;
|
||||
bool had_trailing_comments_ = false;
|
||||
|
||||
using const_iterator = decltype(lookup_)::const_iterator;
|
||||
|
||||
@@ -133,7 +133,7 @@ public:
|
||||
/// Returns a value if present, else another value.
|
||||
template <class T>
|
||||
[[nodiscard]] T
|
||||
valueOr(std::string const& name, T const& other) const
|
||||
value_or(std::string const& name, T const& other) const
|
||||
{
|
||||
auto const v = get<T>(name);
|
||||
return v.has_value() ? *v : other;
|
||||
@@ -142,9 +142,9 @@ public:
|
||||
// indicates if trailing comments were seen
|
||||
// during the appending of any lines/values
|
||||
[[nodiscard]] bool
|
||||
hadTrailingComments() const
|
||||
had_trailing_comments() const
|
||||
{
|
||||
return hadTrailingComments_;
|
||||
return had_trailing_comments_;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
@@ -273,9 +273,9 @@ public:
|
||||
// indicates if trailing comments were seen
|
||||
// in any loaded Sections
|
||||
[[nodiscard]] bool
|
||||
hadTrailingComments() const
|
||||
had_trailing_comments() const
|
||||
{
|
||||
return std::ranges::any_of(map_, [](auto s) { return s.second.hadTrailingComments(); });
|
||||
return std::ranges::any_of(map_, [](auto s) { return s.second.had_trailing_comments(); });
|
||||
}
|
||||
|
||||
protected:
|
||||
@@ -294,17 +294,17 @@ template <class T>
|
||||
bool
|
||||
set(T& target, std::string const& name, Section const& section)
|
||||
{
|
||||
bool foundAndValid = false;
|
||||
bool found_and_valid = false;
|
||||
try
|
||||
{
|
||||
auto const val = section.get<T>(name);
|
||||
if ((foundAndValid = val.has_value()))
|
||||
if ((found_and_valid = val.has_value()))
|
||||
target = *val;
|
||||
}
|
||||
catch (boost::bad_lexical_cast const&) // NOLINT(bugprone-empty-catch)
|
||||
{
|
||||
}
|
||||
return foundAndValid;
|
||||
return found_and_valid;
|
||||
}
|
||||
|
||||
/** Set a value from a configuration Section
|
||||
@@ -316,10 +316,10 @@ template <class T>
|
||||
bool
|
||||
set(T& target, T const& defaultValue, std::string const& name, Section const& section)
|
||||
{
|
||||
bool const foundAndValid = set<T>(target, name, section);
|
||||
if (!foundAndValid)
|
||||
bool const found_and_valid = set<T>(target, name, section);
|
||||
if (!found_and_valid)
|
||||
target = defaultValue;
|
||||
return foundAndValid;
|
||||
return found_and_valid;
|
||||
}
|
||||
|
||||
/** Retrieve a key/value pair from a section.
|
||||
@@ -333,7 +333,7 @@ get(Section const& section, std::string const& name, T const& defaultValue = T{}
|
||||
{
|
||||
try
|
||||
{
|
||||
return section.valueOr<T>(name, defaultValue);
|
||||
return section.value_or<T>(name, defaultValue);
|
||||
}
|
||||
catch (boost::bad_lexical_cast const&) // NOLINT(bugprone-empty-catch)
|
||||
{
|
||||
@@ -358,17 +358,17 @@ get(Section const& section, std::string const& name, char const* defaultValue)
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
getIfExists(Section const& section, std::string const& name, T& v)
|
||||
get_if_exists(Section const& section, std::string const& name, T& v)
|
||||
{
|
||||
return set<T>(v, name, section);
|
||||
}
|
||||
|
||||
template <>
|
||||
inline bool
|
||||
getIfExists<bool>(Section const& section, std::string const& name, bool& v)
|
||||
get_if_exists<bool>(Section const& section, std::string const& name, bool& v)
|
||||
{
|
||||
int intVal = 0;
|
||||
auto stat = getIfExists(section, name, intVal);
|
||||
auto stat = get_if_exists(section, name, intVal);
|
||||
if (stat)
|
||||
v = bool(intVal);
|
||||
return stat;
|
||||
|
||||
@@ -38,11 +38,11 @@ public:
|
||||
|
||||
do
|
||||
{
|
||||
head = instance.head_.load();
|
||||
head = instance.m_head.load();
|
||||
next_ = head;
|
||||
} while (instance.head_.exchange(this) != head);
|
||||
} while (instance.m_head.exchange(this) != head);
|
||||
|
||||
++instance.count_;
|
||||
++instance.m_count;
|
||||
}
|
||||
|
||||
~Counter() noexcept = default;
|
||||
@@ -88,8 +88,8 @@ private:
|
||||
~CountedObjects() noexcept = default;
|
||||
|
||||
private:
|
||||
std::atomic<int> count_;
|
||||
std::atomic<Counter*> head_;
|
||||
std::atomic<int> m_count;
|
||||
std::atomic<Counter*> m_head;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -108,8 +108,8 @@ private:
|
||||
static auto&
|
||||
getCounter() noexcept
|
||||
{
|
||||
static CountedObjects::Counter kC{beast::typeName<Object>()};
|
||||
return kC;
|
||||
static CountedObjects::Counter c{beast::type_name<Object>()};
|
||||
return c;
|
||||
}
|
||||
|
||||
CountedObject() noexcept
|
||||
|
||||
@@ -20,7 +20,7 @@ public:
|
||||
/**
|
||||
@param now Start time of DecayingSample.
|
||||
*/
|
||||
explicit DecayingSample(time_point now) : value_(value_type()), when_(now)
|
||||
explicit DecayingSample(time_point now) : m_value(value_type()), m_when(now)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -31,8 +31,8 @@ public:
|
||||
add(value_type value, time_point now)
|
||||
{
|
||||
decay(now);
|
||||
value_ += value;
|
||||
return value_ / Window;
|
||||
m_value += value;
|
||||
return m_value / Window;
|
||||
}
|
||||
|
||||
/** Retrieve the current value in normalized units.
|
||||
@@ -42,7 +42,7 @@ public:
|
||||
value(time_point now)
|
||||
{
|
||||
decay(now);
|
||||
return value_ / Window;
|
||||
return m_value / Window;
|
||||
}
|
||||
|
||||
private:
|
||||
@@ -50,38 +50,38 @@ private:
|
||||
void
|
||||
decay(time_point now)
|
||||
{
|
||||
if (now == when_)
|
||||
if (now == m_when)
|
||||
return;
|
||||
|
||||
if (value_ != value_type())
|
||||
if (m_value != value_type())
|
||||
{
|
||||
std::size_t elapsed =
|
||||
std::chrono::duration_cast<std::chrono::seconds>(now - when_).count();
|
||||
std::chrono::duration_cast<std::chrono::seconds>(now - m_when).count();
|
||||
|
||||
// A span larger than four times the window decays the
|
||||
// value to an insignificant amount so just reset it.
|
||||
//
|
||||
if (elapsed > 4 * Window)
|
||||
{
|
||||
value_ = value_type();
|
||||
m_value = value_type();
|
||||
}
|
||||
else
|
||||
{
|
||||
for (; elapsed > 0; --elapsed)
|
||||
{
|
||||
value_ -= (value_ + Window - 1) / Window;
|
||||
m_value -= (m_value + Window - 1) / Window;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
when_ = now;
|
||||
m_when = now;
|
||||
}
|
||||
|
||||
// Current value in exponential units
|
||||
value_type value_;
|
||||
value_type m_value;
|
||||
|
||||
// Last time the aging function was applied
|
||||
time_point when_;
|
||||
time_point m_when;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
@@ -16,9 +16,9 @@ namespace xrpl {
|
||||
*/
|
||||
|
||||
// Exception thrown by an invalid access to Expected.
|
||||
struct BadExpectedAccess : public std::runtime_error
|
||||
struct bad_expected_access : public std::runtime_error
|
||||
{
|
||||
BadExpectedAccess() : runtime_error("bad expected access")
|
||||
bad_expected_access() : runtime_error("bad expected access")
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -26,33 +26,30 @@ struct BadExpectedAccess : public std::runtime_error
|
||||
namespace detail {
|
||||
|
||||
// Custom policy for Expected. Always throw on an invalid access.
|
||||
struct ThrowPolicy : public boost::outcome_v2::policy::base
|
||||
struct throw_policy : 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>();
|
||||
Throw<bad_expected_access>();
|
||||
}
|
||||
|
||||
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>();
|
||||
Throw<bad_expected_access>();
|
||||
}
|
||||
|
||||
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>();
|
||||
Throw<bad_expected_access>();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -110,9 +107,9 @@ 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>
|
||||
class [[nodiscard]] Expected : private boost::outcome_v2::result<T, E, detail::throw_policy>
|
||||
{
|
||||
using Base = boost::outcome_v2::result<T, E, detail::ThrowPolicy>;
|
||||
using Base = boost::outcome_v2::result<T, E, detail::throw_policy>;
|
||||
|
||||
public:
|
||||
template <typename U>
|
||||
@@ -129,7 +126,6 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr bool
|
||||
// NOLINTNEXTLINE(readability-identifier-naming)
|
||||
has_value() const
|
||||
{
|
||||
return Base::has_value();
|
||||
@@ -148,23 +144,17 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr E const&
|
||||
error() const&
|
||||
error() const
|
||||
{
|
||||
return Base::error();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr E&
|
||||
error() &
|
||||
constexpr E&
|
||||
error()
|
||||
{
|
||||
return Base::error();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr E&&
|
||||
error() &&
|
||||
{
|
||||
return std::move(Base::error());
|
||||
}
|
||||
|
||||
constexpr explicit
|
||||
operator bool() const
|
||||
{
|
||||
@@ -203,9 +193,9 @@ public:
|
||||
// (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>
|
||||
Expected<void, E> : private boost::outcome_v2::result<void, E, detail::throw_policy>
|
||||
{
|
||||
using Base = boost::outcome_v2::result<void, E, detail::ThrowPolicy>;
|
||||
using Base = boost::outcome_v2::result<void, E, detail::throw_policy>;
|
||||
|
||||
public:
|
||||
// The default constructor makes a successful Expected<void, E>.
|
||||
@@ -221,23 +211,17 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr E const&
|
||||
error() const&
|
||||
error() const
|
||||
{
|
||||
return Base::error();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr E&
|
||||
error() &
|
||||
constexpr E&
|
||||
error()
|
||||
{
|
||||
return Base::error();
|
||||
}
|
||||
|
||||
[[nodiscard]] constexpr E&&
|
||||
error() &&
|
||||
{
|
||||
return std::move(Base::error());
|
||||
}
|
||||
|
||||
constexpr explicit
|
||||
operator bool() const
|
||||
{
|
||||
|
||||
@@ -164,11 +164,11 @@ public:
|
||||
|
||||
/** Return the strong count */
|
||||
[[nodiscard]] std::size_t
|
||||
useCount() const;
|
||||
use_count() const;
|
||||
|
||||
template <class TT, class... Args>
|
||||
friend SharedIntrusive<TT>
|
||||
makeSharedIntrusive(Args&&... args);
|
||||
make_SharedIntrusive(Args&&... args);
|
||||
|
||||
template <class TT>
|
||||
friend class SharedIntrusive;
|
||||
@@ -364,7 +364,7 @@ public:
|
||||
* return 0
|
||||
*/
|
||||
[[nodiscard]] std::size_t
|
||||
useCount() const;
|
||||
use_count() const;
|
||||
|
||||
/** Return true if there is a non-zero strong count. */
|
||||
[[nodiscard]] bool
|
||||
@@ -406,8 +406,8 @@ private:
|
||||
// pointer. The low bit must be masked to zero when converting back to a
|
||||
// pointer. If the low bit is '1', this is a weak pointer.
|
||||
std::uintptr_t tp_{0};
|
||||
static constexpr std::uintptr_t kTagMask = 1;
|
||||
static constexpr std::uintptr_t kPtrMask = ~kTagMask;
|
||||
static constexpr std::uintptr_t tagMask = 1;
|
||||
static constexpr std::uintptr_t ptrMask = ~tagMask;
|
||||
|
||||
private:
|
||||
/** Return the raw pointer held by this object.
|
||||
@@ -415,7 +415,7 @@ private:
|
||||
[[nodiscard]] T*
|
||||
unsafeGetRawPtr() const;
|
||||
|
||||
enum class RefStrength { Strong, Weak };
|
||||
enum class RefStrength { strong, weak };
|
||||
/** Set the raw pointer and tag bit directly.
|
||||
*/
|
||||
void
|
||||
@@ -442,7 +442,7 @@ private:
|
||||
*/
|
||||
template <class TT, class... Args>
|
||||
SharedIntrusive<TT>
|
||||
makeSharedIntrusive(Args&&... args)
|
||||
make_SharedIntrusive(Args&&... args)
|
||||
{
|
||||
auto p = new TT(std::forward<Args>(args)...);
|
||||
|
||||
@@ -469,21 +469,21 @@ using SharedWeakUnionPtr = SharedWeakUnion<T>;
|
||||
|
||||
template <class T, class... A>
|
||||
SharedPtr<T>
|
||||
makeShared(A&&... args)
|
||||
make_shared(A&&... args)
|
||||
{
|
||||
return makeSharedIntrusive<T>(std::forward<A>(args)...);
|
||||
return make_SharedIntrusive<T>(std::forward<A>(args)...);
|
||||
}
|
||||
|
||||
template <class T, class TT>
|
||||
SharedPtr<T>
|
||||
staticPointerCast(TT const& v)
|
||||
static_pointer_cast(TT const& v)
|
||||
{
|
||||
return SharedPtr<T>(StaticCastTagSharedIntrusive{}, v);
|
||||
}
|
||||
|
||||
template <class T, class TT>
|
||||
SharedPtr<T>
|
||||
dynamicPointerCast(TT const& v)
|
||||
dynamic_pointer_cast(TT const& v)
|
||||
{
|
||||
return SharedPtr<T>(DynamicCastTagSharedIntrusive{}, v);
|
||||
}
|
||||
|
||||
@@ -43,16 +43,14 @@ SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT> const& rhs)
|
||||
}
|
||||
|
||||
template <class T>
|
||||
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive&& rhs)
|
||||
: ptr_{std::move(rhs).unsafeExchange(nullptr)}
|
||||
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive&& rhs) : ptr_{rhs.unsafeExchange(nullptr)}
|
||||
{
|
||||
}
|
||||
|
||||
template <class T>
|
||||
template <class TT>
|
||||
requires std::convertible_to<TT*, T*>
|
||||
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT>&& rhs)
|
||||
: ptr_{std::move(rhs).unsafeExchange(nullptr)}
|
||||
SharedIntrusive<T>::SharedIntrusive(SharedIntrusive<TT>&& rhs) : ptr_{rhs.unsafeExchange(nullptr)}
|
||||
{
|
||||
}
|
||||
template <class T>
|
||||
@@ -95,7 +93,7 @@ SharedIntrusive<T>::operator=(SharedIntrusive&& rhs)
|
||||
if (this == &rhs)
|
||||
return *this;
|
||||
|
||||
unsafeReleaseAndStore(std::move(rhs).unsafeExchange(nullptr));
|
||||
unsafeReleaseAndStore(rhs.unsafeExchange(nullptr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -107,7 +105,7 @@ SharedIntrusive<T>::operator=(SharedIntrusive<TT>&& rhs)
|
||||
{
|
||||
static_assert(!std::is_same_v<T, TT>, "This overload should not be instantiated for T == TT");
|
||||
|
||||
unsafeReleaseAndStore(std::move(rhs).unsafeExchange(nullptr));
|
||||
unsafeReleaseAndStore(rhs.unsafeExchange(nullptr));
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -159,7 +157,7 @@ SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusiv
|
||||
template <class T>
|
||||
template <class TT>
|
||||
SharedIntrusive<T>::SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs)
|
||||
: ptr_{static_cast<T*>(std::move(rhs).unsafeExchange(nullptr))}
|
||||
: ptr_{static_cast<T*>(rhs.unsafeExchange(nullptr))}
|
||||
{
|
||||
}
|
||||
|
||||
@@ -186,10 +184,8 @@ SharedIntrusive<T>::SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusi
|
||||
{
|
||||
ptr_ = dynamic_cast<T*>(toSet);
|
||||
if (!ptr_)
|
||||
{
|
||||
// need to set the pointer back or will leak
|
||||
std::move(rhs).unsafeExchange(toSet);
|
||||
}
|
||||
rhs.unsafeExchange(toSet);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -230,10 +226,10 @@ SharedIntrusive<T>::get() const
|
||||
|
||||
template <class T>
|
||||
std::size_t
|
||||
SharedIntrusive<T>::useCount() const
|
||||
SharedIntrusive<T>::use_count() const
|
||||
{
|
||||
if (auto p = unsafeGetRawPtr())
|
||||
return p->useCount();
|
||||
return p->use_count();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -270,12 +266,12 @@ SharedIntrusive<T>::unsafeReleaseAndStore(T* next)
|
||||
auto action = prev->releaseStrongRef();
|
||||
switch (action)
|
||||
{
|
||||
case NoOp:
|
||||
case noop:
|
||||
break;
|
||||
case Destroy:
|
||||
case destroy:
|
||||
delete prev;
|
||||
break;
|
||||
case PartialDestroy:
|
||||
case partialDestroy:
|
||||
prev->partialDestructor();
|
||||
partialDestructorFinished(&prev);
|
||||
// prev is null and may no longer be used
|
||||
@@ -349,7 +345,7 @@ template <class T>
|
||||
bool
|
||||
WeakIntrusive<T>::expired() const
|
||||
{
|
||||
return ((ptr_ == nullptr) || ptr_->expired());
|
||||
return (!ptr_ || ptr_->expired());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -364,16 +360,16 @@ template <class T>
|
||||
void
|
||||
WeakIntrusive<T>::unsafeReleaseNoStore()
|
||||
{
|
||||
if (ptr_ == nullptr)
|
||||
if (!ptr_)
|
||||
return;
|
||||
|
||||
using enum ReleaseWeakRefAction;
|
||||
auto action = ptr_->releaseWeakRef();
|
||||
switch (action)
|
||||
{
|
||||
case NoOp:
|
||||
case noop:
|
||||
break;
|
||||
case Destroy:
|
||||
case destroy:
|
||||
delete ptr_;
|
||||
break;
|
||||
}
|
||||
@@ -389,13 +385,9 @@ SharedWeakUnion<T>::SharedWeakUnion(SharedWeakUnion const& rhs) : tp_{rhs.tp_}
|
||||
return;
|
||||
|
||||
if (rhs.isStrong())
|
||||
{
|
||||
p->addStrongRef();
|
||||
}
|
||||
else
|
||||
{
|
||||
p->addWeakRef();
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -406,7 +398,7 @@ SharedWeakUnion<T>::SharedWeakUnion(SharedIntrusive<TT> const& rhs)
|
||||
auto p = rhs.unsafeGetRawPtr();
|
||||
if (p)
|
||||
p->addStrongRef();
|
||||
unsafeSetRawPtr(p, RefStrength::Strong);
|
||||
unsafeSetRawPtr(p, RefStrength::strong);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -422,8 +414,8 @@ SharedWeakUnion<T>::SharedWeakUnion(SharedIntrusive<TT>&& rhs)
|
||||
{
|
||||
auto p = rhs.unsafeGetRawPtr();
|
||||
if (p)
|
||||
unsafeSetRawPtr(p, RefStrength::Strong);
|
||||
std::move(rhs).unsafeSetRawPtr(nullptr);
|
||||
unsafeSetRawPtr(p, RefStrength::strong);
|
||||
rhs.unsafeSetRawPtr(nullptr);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -439,12 +431,12 @@ SharedWeakUnion<T>::operator=(SharedWeakUnion const& rhs)
|
||||
if (rhs.isStrong())
|
||||
{
|
||||
p->addStrongRef();
|
||||
unsafeSetRawPtr(p, RefStrength::Strong);
|
||||
unsafeSetRawPtr(p, RefStrength::strong);
|
||||
}
|
||||
else
|
||||
{
|
||||
p->addWeakRef();
|
||||
unsafeSetRawPtr(p, RefStrength::Weak);
|
||||
unsafeSetRawPtr(p, RefStrength::weak);
|
||||
}
|
||||
}
|
||||
else
|
||||
@@ -464,7 +456,7 @@ SharedWeakUnion<T>::operator=(SharedIntrusive<TT> const& rhs)
|
||||
auto p = rhs.unsafeGetRawPtr();
|
||||
if (p)
|
||||
p->addStrongRef();
|
||||
unsafeSetRawPtr(p, RefStrength::Strong);
|
||||
unsafeSetRawPtr(p, RefStrength::strong);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -475,8 +467,8 @@ SharedWeakUnion<T>&
|
||||
SharedWeakUnion<T>::operator=(SharedIntrusive<TT>&& rhs)
|
||||
{
|
||||
unsafeReleaseNoStore();
|
||||
unsafeSetRawPtr(rhs.unsafeGetRawPtr(), RefStrength::Strong);
|
||||
std::move(rhs).unsafeSetRawPtr(nullptr);
|
||||
unsafeSetRawPtr(rhs.unsafeGetRawPtr(), RefStrength::strong);
|
||||
rhs.unsafeSetRawPtr(nullptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
@@ -525,10 +517,10 @@ SharedWeakUnion<T>::get() const
|
||||
|
||||
template <class T>
|
||||
std::size_t
|
||||
SharedWeakUnion<T>::useCount() const
|
||||
SharedWeakUnion<T>::use_count() const
|
||||
{
|
||||
if (auto p = get())
|
||||
return p->useCount();
|
||||
return p->use_count();
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -567,14 +559,14 @@ template <class T>
|
||||
bool
|
||||
SharedWeakUnion<T>::isStrong() const
|
||||
{
|
||||
return (tp_ & kTagMask) == 0u;
|
||||
return !(tp_ & tagMask);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
bool
|
||||
SharedWeakUnion<T>::isWeak() const
|
||||
{
|
||||
return (tp_ & kTagMask) != 0u;
|
||||
return tp_ & tagMask;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -589,10 +581,10 @@ SharedWeakUnion<T>::convertToStrong()
|
||||
{
|
||||
[[maybe_unused]] auto action = p->releaseWeakRef();
|
||||
XRPL_ASSERT(
|
||||
(action == ReleaseWeakRefAction::NoOp),
|
||||
(action == ReleaseWeakRefAction::noop),
|
||||
"xrpl::SharedWeakUnion::convertToStrong : "
|
||||
"action is noop");
|
||||
unsafeSetRawPtr(p, RefStrength::Strong);
|
||||
unsafeSetRawPtr(p, RefStrength::strong);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -613,9 +605,9 @@ SharedWeakUnion<T>::convertToWeak()
|
||||
auto action = p->addWeakReleaseStrongRef();
|
||||
switch (action)
|
||||
{
|
||||
case NoOp:
|
||||
case noop:
|
||||
break;
|
||||
case Destroy:
|
||||
case destroy:
|
||||
// We just added a weak ref. How could we destroy?
|
||||
// LCOV_EXCL_START
|
||||
UNREACHABLE(
|
||||
@@ -625,7 +617,7 @@ SharedWeakUnion<T>::convertToWeak()
|
||||
unsafeSetRawPtr(nullptr);
|
||||
return true; // Should never happen
|
||||
// LCOV_EXCL_STOP
|
||||
case PartialDestroy:
|
||||
case partialDestroy:
|
||||
// This is a weird case. We just converted the last strong
|
||||
// pointer to a weak pointer.
|
||||
p->partialDestructor();
|
||||
@@ -633,7 +625,7 @@ SharedWeakUnion<T>::convertToWeak()
|
||||
// p is null and may no longer be used
|
||||
break;
|
||||
}
|
||||
unsafeSetRawPtr(p, RefStrength::Weak);
|
||||
unsafeSetRawPtr(p, RefStrength::weak);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -641,7 +633,7 @@ template <class T>
|
||||
T*
|
||||
SharedWeakUnion<T>::unsafeGetRawPtr() const
|
||||
{
|
||||
return reinterpret_cast<T*>(tp_ & kPtrMask);
|
||||
return reinterpret_cast<T*>(tp_ & ptrMask);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -649,8 +641,8 @@ void
|
||||
SharedWeakUnion<T>::unsafeSetRawPtr(T* p, RefStrength rs)
|
||||
{
|
||||
tp_ = reinterpret_cast<std::uintptr_t>(p);
|
||||
if (tp_ && rs == RefStrength::Weak)
|
||||
tp_ |= kTagMask;
|
||||
if (tp_ && rs == RefStrength::weak)
|
||||
tp_ |= tagMask;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -674,12 +666,12 @@ SharedWeakUnion<T>::unsafeReleaseNoStore()
|
||||
auto strongAction = p->releaseStrongRef();
|
||||
switch (strongAction)
|
||||
{
|
||||
case NoOp:
|
||||
case noop:
|
||||
break;
|
||||
case Destroy:
|
||||
case destroy:
|
||||
delete p;
|
||||
break;
|
||||
case PartialDestroy:
|
||||
case partialDestroy:
|
||||
p->partialDestructor();
|
||||
partialDestructorFinished(&p);
|
||||
// p is null and may no longer be used
|
||||
@@ -692,9 +684,9 @@ SharedWeakUnion<T>::unsafeReleaseNoStore()
|
||||
auto weakAction = p->releaseWeakRef();
|
||||
switch (weakAction)
|
||||
{
|
||||
case NoOp:
|
||||
case noop:
|
||||
break;
|
||||
case Destroy:
|
||||
case destroy:
|
||||
delete p;
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -18,7 +18,7 @@ namespace xrpl {
|
||||
destroy: Run the destructor. This action will occur when either the strong
|
||||
count or weak count is decremented and the other count is also zero.
|
||||
*/
|
||||
enum class ReleaseStrongRefAction { NoOp, PartialDestroy, Destroy };
|
||||
enum class ReleaseStrongRefAction { noop, partialDestroy, destroy };
|
||||
|
||||
/** Action to perform when releasing a weak pointer.
|
||||
|
||||
@@ -28,7 +28,7 @@ enum class ReleaseStrongRefAction { NoOp, PartialDestroy, Destroy };
|
||||
destroy: Run the destructor. This action will occur when either the strong
|
||||
count or weak count is decremented and the other count is also zero.
|
||||
*/
|
||||
enum class ReleaseWeakRefAction { NoOp, Destroy };
|
||||
enum class ReleaseWeakRefAction { noop, destroy };
|
||||
|
||||
/** Implement the strong count, weak count, and bit flags for an intrusive
|
||||
pointer.
|
||||
@@ -71,7 +71,7 @@ struct IntrusiveRefCounts
|
||||
expired() const noexcept;
|
||||
|
||||
std::size_t
|
||||
useCount() const noexcept;
|
||||
use_count() const noexcept;
|
||||
|
||||
// This function MUST be called after a partial destructor finishes running.
|
||||
// Calling this function may cause other threads to delete the object
|
||||
@@ -98,11 +98,11 @@ private:
|
||||
// enough for strong pointers and 14 bit counts are enough for weak
|
||||
// pointers. Use type aliases to make it easy to switch types.
|
||||
using CountType = std::uint16_t;
|
||||
static constexpr size_t kStrongCountNumBits = sizeof(CountType) * 8;
|
||||
static constexpr size_t kWeakCountNumBits = kStrongCountNumBits - 2;
|
||||
static constexpr size_t StrongCountNumBits = sizeof(CountType) * 8;
|
||||
static constexpr size_t WeakCountNumBits = StrongCountNumBits - 2;
|
||||
using FieldType = std::uint32_t;
|
||||
static constexpr size_t kFieldTypeBits = sizeof(FieldType) * 8;
|
||||
static constexpr FieldType kOne = 1;
|
||||
static constexpr size_t FieldTypeBits = sizeof(FieldType) * 8;
|
||||
static constexpr FieldType one = 1;
|
||||
|
||||
/** `refCounts` consists of four fields that are treated atomically:
|
||||
|
||||
@@ -137,21 +137,21 @@ private:
|
||||
|
||||
*/
|
||||
|
||||
mutable std::atomic<FieldType> refCounts_{kStrongDelta};
|
||||
mutable std::atomic<FieldType> refCounts{strongDelta};
|
||||
|
||||
/** Amount to change the strong count when adding or releasing a reference
|
||||
|
||||
Note: The strong count is stored in the low `StrongCountNumBits` bits
|
||||
of refCounts
|
||||
*/
|
||||
static constexpr FieldType kStrongDelta = 1;
|
||||
static constexpr FieldType strongDelta = 1;
|
||||
|
||||
/** Amount to change the weak count when adding or releasing a reference
|
||||
|
||||
Note: The weak count is stored in the high `WeakCountNumBits` bits of
|
||||
refCounts
|
||||
*/
|
||||
static constexpr FieldType kWeakDelta = (kOne << kStrongCountNumBits);
|
||||
static constexpr FieldType weakDelta = (one << StrongCountNumBits);
|
||||
|
||||
/** Flag that is set when the partialDestroy function has started running
|
||||
(or is about to start running).
|
||||
@@ -159,33 +159,33 @@ private:
|
||||
See description of the `refCounts` field for a fuller description of
|
||||
this field.
|
||||
*/
|
||||
static constexpr FieldType kPartialDestroyStartedMask = (kOne << (kFieldTypeBits - 1));
|
||||
static constexpr FieldType partialDestroyStartedMask = (one << (FieldTypeBits - 1));
|
||||
|
||||
/** Flag that is set when the partialDestroy function has finished running
|
||||
|
||||
See description of the `refCounts` field for a fuller description of
|
||||
this field.
|
||||
*/
|
||||
static constexpr FieldType kPartialDestroyFinishedMask = (kOne << (kFieldTypeBits - 2));
|
||||
static constexpr FieldType partialDestroyFinishedMask = (one << (FieldTypeBits - 2));
|
||||
|
||||
/** Mask that will zero out all the `count` bits and leave the tag bits
|
||||
unchanged.
|
||||
*/
|
||||
static constexpr FieldType kTagMask = kPartialDestroyStartedMask | kPartialDestroyFinishedMask;
|
||||
static constexpr FieldType tagMask = partialDestroyStartedMask | partialDestroyFinishedMask;
|
||||
|
||||
/** Mask that will zero out the `tag` bits and leave the count bits
|
||||
unchanged.
|
||||
*/
|
||||
static constexpr FieldType kValueMask = ~kTagMask;
|
||||
static constexpr FieldType valueMask = ~tagMask;
|
||||
|
||||
/** Mask that will zero out everything except the strong count.
|
||||
*/
|
||||
static constexpr FieldType kStrongMask = ((kOne << kStrongCountNumBits) - 1) & kValueMask;
|
||||
static constexpr FieldType strongMask = ((one << StrongCountNumBits) - 1) & valueMask;
|
||||
|
||||
/** Mask that will zero out everything except the weak count.
|
||||
*/
|
||||
static constexpr FieldType kWeakMask =
|
||||
(((kOne << kWeakCountNumBits) - 1) << kStrongCountNumBits) & kValueMask;
|
||||
static constexpr FieldType weakMask =
|
||||
(((one << WeakCountNumBits) - 1) << StrongCountNumBits) & valueMask;
|
||||
|
||||
/** Unpack the count and tag fields from the packed atomic integer form. */
|
||||
struct RefCountPair
|
||||
@@ -210,29 +210,29 @@ private:
|
||||
[[nodiscard]] FieldType
|
||||
combinedValue() const noexcept;
|
||||
|
||||
static constexpr CountType kMaxStrongValue =
|
||||
static_cast<CountType>((kOne << kStrongCountNumBits) - 1);
|
||||
static constexpr CountType kMaxWeakValue =
|
||||
static_cast<CountType>((kOne << kWeakCountNumBits) - 1);
|
||||
static constexpr CountType maxStrongValue =
|
||||
static_cast<CountType>((one << StrongCountNumBits) - 1);
|
||||
static constexpr CountType maxWeakValue =
|
||||
static_cast<CountType>((one << WeakCountNumBits) - 1);
|
||||
/** Put an extra margin to detect when running up against limits.
|
||||
This is only used in debug code, and is useful if we reduce the
|
||||
number of bits in the strong and weak counts (to 16 and 14 bits).
|
||||
*/
|
||||
static constexpr CountType kCheckStrongMaxValue = kMaxStrongValue - 32;
|
||||
static constexpr CountType kCheckWeakMaxValue = kMaxWeakValue - 32;
|
||||
static constexpr CountType checkStrongMaxValue = maxStrongValue - 32;
|
||||
static constexpr CountType checkWeakMaxValue = maxWeakValue - 32;
|
||||
};
|
||||
};
|
||||
|
||||
inline void
|
||||
IntrusiveRefCounts::addStrongRef() const noexcept
|
||||
{
|
||||
refCounts_.fetch_add(kStrongDelta, std::memory_order_acq_rel);
|
||||
refCounts.fetch_add(strongDelta, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
inline void
|
||||
IntrusiveRefCounts::addWeakRef() const noexcept
|
||||
{
|
||||
refCounts_.fetch_add(kWeakDelta, std::memory_order_acq_rel);
|
||||
refCounts.fetch_add(weakDelta, std::memory_order_acq_rel);
|
||||
}
|
||||
|
||||
inline ReleaseStrongRefAction
|
||||
@@ -246,36 +246,36 @@ IntrusiveRefCounts::releaseStrongRef() const
|
||||
// conditional `fetch_or`. This loop will almost always run once.
|
||||
|
||||
using enum ReleaseStrongRefAction;
|
||||
auto prevIntVal = refCounts_.load(std::memory_order_acquire);
|
||||
auto prevIntVal = refCounts.load(std::memory_order_acquire);
|
||||
while (true)
|
||||
{
|
||||
RefCountPair const prevVal{prevIntVal};
|
||||
XRPL_ASSERT(
|
||||
(prevVal.strong >= kStrongDelta),
|
||||
(prevVal.strong >= strongDelta),
|
||||
"xrpl::IntrusiveRefCounts::releaseStrongRef : previous ref "
|
||||
"higher than new");
|
||||
auto nextIntVal = prevIntVal - kStrongDelta;
|
||||
ReleaseStrongRefAction action = NoOp;
|
||||
auto nextIntVal = prevIntVal - strongDelta;
|
||||
ReleaseStrongRefAction action = noop;
|
||||
if (prevVal.strong == 1)
|
||||
{
|
||||
if (prevVal.weak == 0)
|
||||
{
|
||||
action = Destroy;
|
||||
action = destroy;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextIntVal |= kPartialDestroyStartedMask;
|
||||
action = PartialDestroy;
|
||||
nextIntVal |= partialDestroyStartedMask;
|
||||
action = partialDestroy;
|
||||
}
|
||||
}
|
||||
|
||||
if (refCounts_.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||
if (refCounts.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||
{
|
||||
// Can't be in partial destroy because only decrementing the strong
|
||||
// count to zero can start a partial destroy, and that can't happen
|
||||
// twice.
|
||||
XRPL_ASSERT(
|
||||
(action == NoOp) || !(prevIntVal & kPartialDestroyStartedMask),
|
||||
(action == noop) || !(prevIntVal & partialDestroyStartedMask),
|
||||
"xrpl::IntrusiveRefCounts::releaseStrongRef : not in partial "
|
||||
"destroy");
|
||||
return action;
|
||||
@@ -288,9 +288,9 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
|
||||
{
|
||||
using enum ReleaseStrongRefAction;
|
||||
|
||||
static_assert(kWeakDelta > kStrongDelta);
|
||||
static constexpr auto kDelta = kWeakDelta - kStrongDelta;
|
||||
auto prevIntVal = refCounts_.load(std::memory_order_acquire);
|
||||
static_assert(weakDelta > strongDelta);
|
||||
auto constexpr delta = weakDelta - strongDelta;
|
||||
auto prevIntVal = refCounts.load(std::memory_order_acquire);
|
||||
// This loop will almost always run once. The loop is needed to atomically
|
||||
// change the counts and flags (the count could be atomically changed, but
|
||||
// the flags depend on the current value of the counts).
|
||||
@@ -311,24 +311,24 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
|
||||
"xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not in "
|
||||
"partial destroy");
|
||||
|
||||
auto nextIntVal = prevIntVal + kDelta;
|
||||
ReleaseStrongRefAction action = NoOp;
|
||||
auto nextIntVal = prevIntVal + delta;
|
||||
ReleaseStrongRefAction action = noop;
|
||||
if (prevVal.strong == 1)
|
||||
{
|
||||
if (prevVal.weak == 0)
|
||||
{
|
||||
action = NoOp;
|
||||
action = noop;
|
||||
}
|
||||
else
|
||||
{
|
||||
nextIntVal |= kPartialDestroyStartedMask;
|
||||
action = PartialDestroy;
|
||||
nextIntVal |= partialDestroyStartedMask;
|
||||
action = partialDestroy;
|
||||
}
|
||||
}
|
||||
if (refCounts_.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||
if (refCounts.compare_exchange_weak(prevIntVal, nextIntVal, std::memory_order_acq_rel))
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(!(prevIntVal & kPartialDestroyStartedMask)),
|
||||
(!(prevIntVal & partialDestroyStartedMask)),
|
||||
"xrpl::IntrusiveRefCounts::addWeakReleaseStrongRef : not "
|
||||
"started partial destroy");
|
||||
return action;
|
||||
@@ -339,7 +339,7 @@ IntrusiveRefCounts::addWeakReleaseStrongRef() const
|
||||
inline ReleaseWeakRefAction
|
||||
IntrusiveRefCounts::releaseWeakRef() const
|
||||
{
|
||||
auto prevIntVal = refCounts_.fetch_sub(kWeakDelta, std::memory_order_acq_rel);
|
||||
auto prevIntVal = refCounts.fetch_sub(weakDelta, std::memory_order_acq_rel);
|
||||
RefCountPair prev = prevIntVal;
|
||||
if (prev.weak == 1 && prev.strong == 0)
|
||||
{
|
||||
@@ -348,19 +348,19 @@ IntrusiveRefCounts::releaseWeakRef() const
|
||||
// This case should only be hit if the partialDestroyStartedBit is
|
||||
// set non-atomically (and even then very rarely). The code is kept
|
||||
// in case we need to set the flag non-atomically for perf reasons.
|
||||
refCounts_.wait(prevIntVal, std::memory_order_acquire);
|
||||
prevIntVal = refCounts_.load(std::memory_order_acquire);
|
||||
refCounts.wait(prevIntVal, std::memory_order_acquire);
|
||||
prevIntVal = refCounts.load(std::memory_order_acquire);
|
||||
prev = RefCountPair{prevIntVal};
|
||||
}
|
||||
if (prev.partialDestroyFinishedBit == 0u)
|
||||
{
|
||||
// partial destroy MUST finish before running a full destroy (when
|
||||
// using weak pointers)
|
||||
refCounts_.wait(prevIntVal - kWeakDelta, std::memory_order_acquire);
|
||||
refCounts.wait(prevIntVal - weakDelta, std::memory_order_acquire);
|
||||
}
|
||||
return ReleaseWeakRefAction::Destroy;
|
||||
return ReleaseWeakRefAction::destroy;
|
||||
}
|
||||
return ReleaseWeakRefAction::NoOp;
|
||||
return ReleaseWeakRefAction::noop;
|
||||
}
|
||||
|
||||
inline bool
|
||||
@@ -369,13 +369,13 @@ IntrusiveRefCounts::checkoutStrongRefFromWeak() const noexcept
|
||||
auto curValue = RefCountPair{1, 1}.combinedValue();
|
||||
auto desiredValue = RefCountPair{2, 1}.combinedValue();
|
||||
|
||||
while (!refCounts_.compare_exchange_weak(curValue, desiredValue, std::memory_order_acq_rel))
|
||||
while (!refCounts.compare_exchange_weak(curValue, desiredValue, std::memory_order_acq_rel))
|
||||
{
|
||||
RefCountPair const prev{curValue};
|
||||
if (prev.strong == 0u)
|
||||
return false;
|
||||
|
||||
desiredValue = curValue + kStrongDelta;
|
||||
desiredValue = curValue + strongDelta;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -383,38 +383,38 @@ IntrusiveRefCounts::checkoutStrongRefFromWeak() const noexcept
|
||||
inline bool
|
||||
IntrusiveRefCounts::expired() const noexcept
|
||||
{
|
||||
RefCountPair const val = refCounts_.load(std::memory_order_acquire);
|
||||
RefCountPair const val = refCounts.load(std::memory_order_acquire);
|
||||
return val.strong == 0;
|
||||
}
|
||||
|
||||
inline std::size_t
|
||||
IntrusiveRefCounts::useCount() const noexcept
|
||||
IntrusiveRefCounts::use_count() const noexcept
|
||||
{
|
||||
RefCountPair const val = refCounts_.load(std::memory_order_acquire);
|
||||
RefCountPair const val = refCounts.load(std::memory_order_acquire);
|
||||
return val.strong;
|
||||
}
|
||||
|
||||
inline IntrusiveRefCounts::~IntrusiveRefCounts() noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
auto v = refCounts_.load(std::memory_order_acquire);
|
||||
auto v = refCounts.load(std::memory_order_acquire);
|
||||
XRPL_ASSERT(
|
||||
(!(v & kValueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
|
||||
auto t = v & kTagMask;
|
||||
XRPL_ASSERT((!t || t == kTagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
|
||||
(!(v & valueMask)), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : count must be zero");
|
||||
auto t = v & tagMask;
|
||||
XRPL_ASSERT((!t || t == tagMask), "xrpl::IntrusiveRefCounts::~IntrusiveRefCounts : valid tag");
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
inline IntrusiveRefCounts::RefCountPair::RefCountPair(IntrusiveRefCounts::FieldType v) noexcept
|
||||
: strong{static_cast<CountType>(v & kStrongMask)}
|
||||
, weak{static_cast<CountType>((v & kWeakMask) >> kStrongCountNumBits)}
|
||||
, partialDestroyStartedBit{v & kPartialDestroyStartedMask}
|
||||
, partialDestroyFinishedBit{v & kPartialDestroyFinishedMask}
|
||||
: strong{static_cast<CountType>(v & strongMask)}
|
||||
, weak{static_cast<CountType>((v & weakMask) >> StrongCountNumBits)}
|
||||
, partialDestroyStartedBit{v & partialDestroyStartedMask}
|
||||
, partialDestroyFinishedBit{v & partialDestroyFinishedMask}
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
|
||||
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||
"xrpl::IntrusiveRefCounts::RefCountPair(FieldType) : inputs inside "
|
||||
"range");
|
||||
}
|
||||
@@ -425,7 +425,7 @@ inline IntrusiveRefCounts::RefCountPair::RefCountPair(
|
||||
: strong{s}, weak{w}
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
|
||||
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||
"xrpl::IntrusiveRefCounts::RefCountPair(CountType, CountType) : "
|
||||
"inputs inside range");
|
||||
}
|
||||
@@ -434,11 +434,11 @@ inline IntrusiveRefCounts::FieldType
|
||||
IntrusiveRefCounts::RefCountPair::combinedValue() const noexcept
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
(strong < kCheckStrongMaxValue && weak < kCheckWeakMaxValue),
|
||||
(strong < checkStrongMaxValue && weak < checkWeakMaxValue),
|
||||
"xrpl::IntrusiveRefCounts::RefCountPair::combinedValue : inputs "
|
||||
"inside range");
|
||||
return (static_cast<IntrusiveRefCounts::FieldType>(weak)
|
||||
<< IntrusiveRefCounts::kStrongCountNumBits) |
|
||||
<< IntrusiveRefCounts::StrongCountNumBits) |
|
||||
static_cast<IntrusiveRefCounts::FieldType>(strong) | partialDestroyStartedBit |
|
||||
partialDestroyFinishedBit;
|
||||
}
|
||||
@@ -449,7 +449,7 @@ partialDestructorFinished(T** o)
|
||||
{
|
||||
T& self = **o;
|
||||
IntrusiveRefCounts::RefCountPair const p =
|
||||
self.refCounts_.fetch_or(IntrusiveRefCounts::kPartialDestroyFinishedMask);
|
||||
self.refCounts.fetch_or(IntrusiveRefCounts::partialDestroyFinishedMask);
|
||||
XRPL_ASSERT(
|
||||
(!p.partialDestroyFinishedBit && p.partialDestroyStartedBit && !p.strong),
|
||||
"xrpl::partialDestructorFinished : not a weak ref");
|
||||
@@ -458,7 +458,7 @@ partialDestructorFinished(T** o)
|
||||
// There was a weak count before the partial destructor ran (or we would
|
||||
// have run the full destructor) and now there isn't a weak count. Some
|
||||
// thread is waiting to run the destructor.
|
||||
self.refCounts_.notify_one();
|
||||
self.refCounts.notify_one();
|
||||
}
|
||||
// Set the pointer to null to emphasize that the object shouldn't be used
|
||||
// after calling this function as it may be destroyed in another thread.
|
||||
|
||||
@@ -26,17 +26,17 @@ struct LocalValues
|
||||
template <class T>
|
||||
struct Value : BasicValue
|
||||
{
|
||||
T t;
|
||||
T t_;
|
||||
|
||||
Value() = default;
|
||||
explicit Value(T t) : t(std::move(t))
|
||||
explicit Value(T t) : t_(std::move(t))
|
||||
{
|
||||
}
|
||||
|
||||
void*
|
||||
get() override
|
||||
{
|
||||
return &t;
|
||||
return &t_;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -55,8 +55,8 @@ template <class = void>
|
||||
boost::thread_specific_ptr<detail::LocalValues>&
|
||||
getLocalValues()
|
||||
{
|
||||
static boost::thread_specific_ptr<detail::LocalValues> kTsp(&detail::LocalValues::cleanup);
|
||||
return kTsp;
|
||||
static boost::thread_specific_ptr<detail::LocalValues> tsp(&detail::LocalValues::cleanup);
|
||||
return tsp;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
@@ -10,11 +10,24 @@
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
// DEPRECATED use beast::severities::Severity instead
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
|
||||
enum LogSeverity {
|
||||
lsINVALID = -1, // used to indicate an invalid severity
|
||||
lsTRACE = 0, // Very low-level progress information, details inside
|
||||
// an operation
|
||||
lsDEBUG = 1, // Function-level progress information, operations
|
||||
lsINFO = 2, // Server-level progress information, major operations
|
||||
lsWARNING = 3, // Conditions that warrant human attention, may indicate
|
||||
// a problem
|
||||
lsERROR = 4, // A condition that indicates a problem
|
||||
lsFATAL = 5 // A severe condition that indicates a server problem
|
||||
};
|
||||
|
||||
/** Manages partitions for logging. */
|
||||
class Logs
|
||||
{
|
||||
@@ -26,17 +39,17 @@ private:
|
||||
std::string partition_;
|
||||
|
||||
public:
|
||||
Sink(std::string partition, beast::Severity thresh, Logs& logs);
|
||||
Sink(std::string partition, beast::severities::Severity thresh, Logs& logs);
|
||||
|
||||
Sink(Sink const&) = delete;
|
||||
Sink&
|
||||
operator=(Sink const&) = delete;
|
||||
|
||||
void
|
||||
write(beast::Severity level, std::string const& text) override;
|
||||
write(beast::severities::Severity level, std::string const& text) override;
|
||||
|
||||
void
|
||||
writeAlways(beast::Severity level, std::string const& text) override;
|
||||
writeAlways(beast::severities::Severity level, std::string const& text) override;
|
||||
};
|
||||
|
||||
/** Manages a system file containing logged output.
|
||||
@@ -117,18 +130,18 @@ private:
|
||||
/** @} */
|
||||
|
||||
private:
|
||||
std::unique_ptr<std::ofstream> stream_;
|
||||
boost::filesystem::path path_;
|
||||
std::unique_ptr<std::ofstream> m_stream;
|
||||
boost::filesystem::path m_path;
|
||||
};
|
||||
|
||||
std::mutex mutable mutex_;
|
||||
std::map<std::string, std::unique_ptr<beast::Journal::Sink>, boost::beast::iless> sinks_;
|
||||
beast::Severity thresh_;
|
||||
beast::severities::Severity thresh_;
|
||||
File file_;
|
||||
bool silent_ = false;
|
||||
|
||||
public:
|
||||
Logs(beast::Severity level);
|
||||
Logs(beast::severities::Severity level);
|
||||
|
||||
Logs(Logs const&) = delete;
|
||||
Logs&
|
||||
@@ -148,18 +161,18 @@ public:
|
||||
beast::Journal
|
||||
journal(std::string const& name);
|
||||
|
||||
beast::Severity
|
||||
beast::severities::Severity
|
||||
threshold() const;
|
||||
|
||||
void
|
||||
threshold(beast::Severity thresh);
|
||||
threshold(beast::severities::Severity thresh);
|
||||
|
||||
std::vector<std::pair<std::string, std::string>>
|
||||
partitionSeverities() const;
|
||||
partition_severities() const;
|
||||
|
||||
void
|
||||
write(
|
||||
beast::Severity level,
|
||||
beast::severities::Severity level,
|
||||
std::string const& partition,
|
||||
std::string const& text,
|
||||
bool console);
|
||||
@@ -179,25 +192,36 @@ public:
|
||||
}
|
||||
|
||||
virtual std::unique_ptr<beast::Journal::Sink>
|
||||
makeSink(std::string const& partition, beast::Severity startingLevel);
|
||||
makeSink(std::string const& partition, beast::severities::Severity startingLevel);
|
||||
|
||||
public:
|
||||
static std::string
|
||||
toString(beast::Severity s);
|
||||
static LogSeverity
|
||||
fromSeverity(beast::severities::Severity level);
|
||||
|
||||
static std::optional<beast::Severity>
|
||||
static beast::severities::Severity
|
||||
toSeverity(LogSeverity level);
|
||||
|
||||
static std::string
|
||||
toString(LogSeverity s);
|
||||
|
||||
static LogSeverity
|
||||
fromString(std::string const& s);
|
||||
|
||||
private:
|
||||
// Maximum line length for log messages.
|
||||
// If the message exceeds this length it will be truncated with ellipses.
|
||||
static constexpr auto kMaximumMessageCharacters = 12 * 1024;
|
||||
// Need to be named before converting
|
||||
// NOLINTNEXTLINE(cppcoreguidelines-use-enum-class)
|
||||
enum {
|
||||
// Maximum line length for log messages.
|
||||
// If the message exceeds this length it will be truncated with
|
||||
// ellipses.
|
||||
maximumMessageCharacters = 12 * 1024
|
||||
};
|
||||
|
||||
static void
|
||||
format(
|
||||
std::string& output,
|
||||
std::string const& message,
|
||||
beast::Severity severity,
|
||||
beast::severities::Severity severity,
|
||||
std::string const& partition);
|
||||
};
|
||||
|
||||
|
||||
@@ -70,27 +70,27 @@ isPowerOfTen(T value)
|
||||
struct MantissaRange
|
||||
{
|
||||
using rep = std::uint64_t;
|
||||
enum class MantissaScale { Small, Large };
|
||||
enum class mantissa_scale { small, large };
|
||||
|
||||
explicit constexpr MantissaRange(MantissaScale scale)
|
||||
: min(getMin(scale)), log(logTen(min).value_or(-1)), scale(scale)
|
||||
explicit constexpr MantissaRange(mantissa_scale scale_)
|
||||
: min(getMin(scale_)), log(logTen(min).value_or(-1)), scale(scale_)
|
||||
{
|
||||
}
|
||||
|
||||
rep min;
|
||||
rep max{(min * 10) - 1};
|
||||
int log;
|
||||
MantissaScale scale;
|
||||
mantissa_scale scale;
|
||||
|
||||
private:
|
||||
static constexpr rep
|
||||
getMin(MantissaScale scale)
|
||||
getMin(mantissa_scale scale_)
|
||||
{
|
||||
switch (scale)
|
||||
switch (scale_)
|
||||
{
|
||||
case MantissaScale::Small:
|
||||
case mantissa_scale::small:
|
||||
return 1'000'000'000'000'000ULL;
|
||||
case MantissaScale::Large:
|
||||
case mantissa_scale::large:
|
||||
return 1'000'000'000'000'000'000ULL;
|
||||
default:
|
||||
// Since this can never be called outside a non-constexpr
|
||||
@@ -214,26 +214,26 @@ class Number
|
||||
|
||||
public:
|
||||
// The range for the exponent when normalized
|
||||
static constexpr int kMinExponent = -32768;
|
||||
static constexpr int kMaxExponent = 32768;
|
||||
constexpr static int minExponent = -32768;
|
||||
constexpr static int maxExponent = 32768;
|
||||
|
||||
static constexpr internalrep kMaxRep = std::numeric_limits<rep>::max();
|
||||
static_assert(kMaxRep == 9'223'372'036'854'775'807);
|
||||
static_assert(-kMaxRep == std::numeric_limits<rep>::min() + 1);
|
||||
constexpr static internalrep maxRep = std::numeric_limits<rep>::max();
|
||||
static_assert(maxRep == 9'223'372'036'854'775'807);
|
||||
static_assert(-maxRep == std::numeric_limits<rep>::min() + 1);
|
||||
|
||||
// May need to make unchecked private
|
||||
struct Unchecked
|
||||
struct unchecked
|
||||
{
|
||||
explicit Unchecked() = default;
|
||||
explicit unchecked() = default;
|
||||
};
|
||||
|
||||
// Like unchecked, normalized is used with the ctors that take an
|
||||
// internalrep mantissa. Unlike unchecked, those ctors will normalize the
|
||||
// value.
|
||||
// Only unit tests are expected to use this class
|
||||
struct Normalized
|
||||
struct normalized
|
||||
{
|
||||
explicit Normalized() = default;
|
||||
explicit normalized() = default;
|
||||
};
|
||||
|
||||
explicit constexpr Number() = default;
|
||||
@@ -244,13 +244,13 @@ public:
|
||||
bool negative,
|
||||
internalrep mantissa,
|
||||
int exponent,
|
||||
Unchecked) noexcept;
|
||||
unchecked) noexcept;
|
||||
// Assume unsigned values are... unsigned. i.e. positive
|
||||
explicit constexpr Number(internalrep mantissa, int exponent, Unchecked) noexcept;
|
||||
explicit constexpr Number(internalrep mantissa, int exponent, unchecked) noexcept;
|
||||
// Only unit tests are expected to use this ctor
|
||||
explicit Number(bool negative, internalrep mantissa, int exponent, Normalized);
|
||||
explicit Number(bool negative, internalrep mantissa, int exponent, normalized);
|
||||
// Assume unsigned values are... unsigned. i.e. positive
|
||||
explicit Number(internalrep mantissa, int exponent, Normalized);
|
||||
explicit Number(internalrep mantissa, int exponent, normalized);
|
||||
|
||||
[[nodiscard]] constexpr rep
|
||||
mantissa() const noexcept;
|
||||
@@ -384,51 +384,49 @@ public:
|
||||
root2(Number f);
|
||||
|
||||
// Thread local rounding control. Default is to_nearest
|
||||
enum class RoundingMode { ToNearest, TowardsZero, Downward, Upward };
|
||||
|
||||
static RoundingMode
|
||||
enum class rounding_mode { to_nearest, towards_zero, downward, upward };
|
||||
static rounding_mode
|
||||
getround();
|
||||
|
||||
static RoundingMode
|
||||
setround(RoundingMode inMode);
|
||||
// Returns previously set mode
|
||||
static rounding_mode
|
||||
setround(rounding_mode mode);
|
||||
|
||||
/** Returns which mantissa scale is currently in use for normalization.
|
||||
*
|
||||
* If you think you need to call this outside of unit tests, no you don't.
|
||||
*/
|
||||
static MantissaRange::MantissaScale
|
||||
static MantissaRange::mantissa_scale
|
||||
getMantissaScale();
|
||||
|
||||
/** Changes which mantissa scale is used for normalization.
|
||||
*
|
||||
* If you think you need to call this outside of unit tests, no you don't.
|
||||
*/
|
||||
static void
|
||||
setMantissaScale(MantissaRange::MantissaScale scale);
|
||||
setMantissaScale(MantissaRange::mantissa_scale scale);
|
||||
|
||||
static internalrep
|
||||
minMantissa()
|
||||
{
|
||||
return kRange.get().min;
|
||||
return range_.get().min;
|
||||
}
|
||||
|
||||
static internalrep
|
||||
maxMantissa()
|
||||
{
|
||||
return kRange.get().max;
|
||||
return range_.get().max;
|
||||
}
|
||||
|
||||
static int
|
||||
mantissaLog()
|
||||
{
|
||||
return kRange.get().log;
|
||||
return range_.get().log;
|
||||
}
|
||||
|
||||
/// oneSmall is needed because the ranges are private
|
||||
static constexpr Number
|
||||
constexpr static Number
|
||||
oneSmall();
|
||||
/// oneLarge is needed because the ranges are private
|
||||
static constexpr Number
|
||||
constexpr static Number
|
||||
oneLarge();
|
||||
|
||||
// And one is needed because it needs to choose between oneSmall and
|
||||
@@ -442,28 +440,28 @@ public:
|
||||
normalizeToRange(T minMantissa, T maxMantissa) const;
|
||||
|
||||
private:
|
||||
static thread_local RoundingMode mode;
|
||||
static thread_local rounding_mode 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);
|
||||
constexpr static MantissaRange smallRange{MantissaRange::mantissa_scale::small};
|
||||
static_assert(isPowerOfTen(smallRange.min));
|
||||
static_assert(smallRange.min == 1'000'000'000'000'000LL);
|
||||
static_assert(smallRange.max == 9'999'999'999'999'999LL);
|
||||
static_assert(smallRange.log == 15);
|
||||
static_assert(smallRange.min < maxRep);
|
||||
static_assert(smallRange.max < maxRep);
|
||||
constexpr static MantissaRange largeRange{MantissaRange::mantissa_scale::large};
|
||||
static_assert(isPowerOfTen(largeRange.min));
|
||||
static_assert(largeRange.min == 1'000'000'000'000'000'000ULL);
|
||||
static_assert(largeRange.max == internalrep(9'999'999'999'999'999'999ULL));
|
||||
static_assert(largeRange.log == 18);
|
||||
static_assert(largeRange.min < maxRep);
|
||||
static_assert(largeRange.max > maxRep);
|
||||
|
||||
// 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;
|
||||
static thread_local std::reference_wrapper<MantissaRange const> range_;
|
||||
|
||||
void
|
||||
normalize();
|
||||
@@ -471,7 +469,7 @@ private:
|
||||
/** Normalize Number components to an arbitrary range.
|
||||
*
|
||||
* min/maxMantissa are parameters because this function is used by both
|
||||
* normalize(), which reads from kRange, and by normalizeToRange,
|
||||
* normalize(), which reads from range_, and by normalizeToRange,
|
||||
* which is public and can accept an arbitrary range from the caller.
|
||||
*/
|
||||
template <class T>
|
||||
@@ -487,8 +485,8 @@ private:
|
||||
friend void
|
||||
doNormalize(
|
||||
bool& negative,
|
||||
T& mantissa,
|
||||
int& exponent,
|
||||
T& mantissa_,
|
||||
int& exponent_,
|
||||
MantissaRange::rep const& minMantissa,
|
||||
MantissaRange::rep const& maxMantissa);
|
||||
|
||||
@@ -511,31 +509,31 @@ private:
|
||||
class Guard;
|
||||
};
|
||||
|
||||
constexpr Number::Number(bool negative, internalrep mantissa, int exponent, Unchecked) noexcept
|
||||
constexpr Number::Number(bool negative, internalrep mantissa, int exponent, unchecked) noexcept
|
||||
: negative_(negative), mantissa_{mantissa}, exponent_{exponent}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr Number::Number(internalrep mantissa, int exponent, Unchecked) noexcept
|
||||
: Number(false, mantissa, exponent, Unchecked{})
|
||||
constexpr Number::Number(internalrep mantissa, int exponent, unchecked) noexcept
|
||||
: Number(false, mantissa, exponent, unchecked{})
|
||||
{
|
||||
}
|
||||
|
||||
static constexpr Number kNumZero{};
|
||||
constexpr static Number numZero{};
|
||||
|
||||
inline Number::Number(bool negative, internalrep mantissa, int exponent, Normalized)
|
||||
: Number(negative, mantissa, exponent, Unchecked{})
|
||||
inline Number::Number(bool negative, internalrep mantissa, int exponent, normalized)
|
||||
: Number(negative, mantissa, exponent, unchecked{})
|
||||
{
|
||||
normalize();
|
||||
}
|
||||
|
||||
inline Number::Number(internalrep mantissa, int exponent, Normalized)
|
||||
: Number(false, mantissa, exponent, Normalized{})
|
||||
inline Number::Number(internalrep mantissa, int exponent, normalized)
|
||||
: Number(false, mantissa, exponent, normalized{})
|
||||
{
|
||||
}
|
||||
|
||||
inline Number::Number(rep mantissa, int exponent)
|
||||
: Number(mantissa < 0, externalToInternal(mantissa), exponent, Normalized{})
|
||||
: Number(mantissa < 0, externalToInternal(mantissa), exponent, normalized{})
|
||||
{
|
||||
}
|
||||
|
||||
@@ -552,10 +550,10 @@ constexpr Number::rep
|
||||
Number::mantissa() const noexcept
|
||||
{
|
||||
auto m = mantissa_;
|
||||
if (m > kMaxRep)
|
||||
if (m > maxRep)
|
||||
{
|
||||
XRPL_ASSERT_PARTS(
|
||||
!isnormal() || (m % 10 == 0 && m / 10 <= kMaxRep),
|
||||
!isnormal() || (m % 10 == 0 && m / 10 <= maxRep),
|
||||
"xrpl::Number::mantissa",
|
||||
"large normalized mantissa has no remainder");
|
||||
m /= 10;
|
||||
@@ -573,10 +571,10 @@ constexpr int
|
||||
Number::exponent() const noexcept
|
||||
{
|
||||
auto e = exponent_;
|
||||
if (mantissa_ > kMaxRep)
|
||||
if (mantissa_ > maxRep)
|
||||
{
|
||||
XRPL_ASSERT_PARTS(
|
||||
!isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= kMaxRep),
|
||||
!isnormal() || (mantissa_ % 10 == 0 && mantissa_ / 10 <= maxRep),
|
||||
"xrpl::Number::exponent",
|
||||
"large normalized mantissa has no remainder");
|
||||
++e;
|
||||
@@ -671,29 +669,29 @@ operator/(Number const& x, Number const& y)
|
||||
inline Number
|
||||
Number::min() noexcept
|
||||
{
|
||||
return Number{false, kRange.get().min, kMinExponent, Unchecked{}};
|
||||
return Number{false, range_.get().min, minExponent, unchecked{}};
|
||||
}
|
||||
|
||||
inline Number
|
||||
Number::max() noexcept
|
||||
{
|
||||
return Number{false, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
|
||||
return Number{false, std::min(range_.get().max, maxRep), maxExponent, unchecked{}};
|
||||
}
|
||||
|
||||
inline Number
|
||||
Number::lowest() noexcept
|
||||
{
|
||||
return Number{true, std::min(kRange.get().max, kMaxRep), kMaxExponent, Unchecked{}};
|
||||
return Number{true, std::min(range_.get().max, maxRep), maxExponent, unchecked{}};
|
||||
}
|
||||
|
||||
inline bool
|
||||
Number::isnormal() const noexcept
|
||||
{
|
||||
MantissaRange const& range = kRange;
|
||||
auto const absM = mantissa_;
|
||||
MantissaRange const& range = range_;
|
||||
auto const abs_m = mantissa_;
|
||||
return *this == Number{} ||
|
||||
(range.min <= absM && absM <= range.max && (absM <= kMaxRep || absM % 10 == 0) &&
|
||||
kMinExponent <= exponent_ && exponent_ <= kMaxExponent);
|
||||
(range.min <= abs_m && abs_m <= range.max && (abs_m <= maxRep || abs_m % 10 == 0) &&
|
||||
minExponent <= exponent_ && exponent_ <= maxExponent);
|
||||
}
|
||||
|
||||
template <Integral64 T>
|
||||
@@ -757,34 +755,34 @@ squelch(Number const& x, Number const& limit) noexcept
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(MantissaRange::MantissaScale const& scale)
|
||||
to_string(MantissaRange::mantissa_scale const& scale)
|
||||
{
|
||||
switch (scale)
|
||||
{
|
||||
case MantissaRange::MantissaScale::Small:
|
||||
case MantissaRange::mantissa_scale::small:
|
||||
return "small";
|
||||
case MantissaRange::MantissaScale::Large:
|
||||
case MantissaRange::mantissa_scale::large:
|
||||
return "large";
|
||||
default:
|
||||
throw std::runtime_error("Bad scale");
|
||||
}
|
||||
}
|
||||
|
||||
class SaveNumberRoundMode
|
||||
class saveNumberRoundMode
|
||||
{
|
||||
Number::RoundingMode mode_;
|
||||
Number::rounding_mode mode_;
|
||||
|
||||
public:
|
||||
~SaveNumberRoundMode()
|
||||
~saveNumberRoundMode()
|
||||
{
|
||||
Number::setround(mode_);
|
||||
}
|
||||
explicit SaveNumberRoundMode(Number::RoundingMode mode) noexcept : mode_{mode}
|
||||
explicit saveNumberRoundMode(Number::rounding_mode mode) noexcept : mode_{mode}
|
||||
{
|
||||
}
|
||||
SaveNumberRoundMode(SaveNumberRoundMode const&) = delete;
|
||||
SaveNumberRoundMode&
|
||||
operator=(SaveNumberRoundMode const&) = delete;
|
||||
saveNumberRoundMode(saveNumberRoundMode const&) = delete;
|
||||
saveNumberRoundMode&
|
||||
operator=(saveNumberRoundMode const&) = delete;
|
||||
};
|
||||
|
||||
// saveNumberRoundMode doesn't do quite enough for us. What we want is a
|
||||
@@ -793,10 +791,10 @@ public:
|
||||
// build it here.
|
||||
class NumberRoundModeGuard
|
||||
{
|
||||
SaveNumberRoundMode saved_;
|
||||
saveNumberRoundMode saved_;
|
||||
|
||||
public:
|
||||
explicit NumberRoundModeGuard(Number::RoundingMode mode) noexcept
|
||||
explicit NumberRoundModeGuard(Number::rounding_mode mode) noexcept
|
||||
: saved_{Number::setround(mode)}
|
||||
{
|
||||
}
|
||||
@@ -814,10 +812,10 @@ public:
|
||||
*/
|
||||
class NumberMantissaScaleGuard
|
||||
{
|
||||
MantissaRange::MantissaScale const saved_;
|
||||
MantissaRange::mantissa_scale const saved_;
|
||||
|
||||
public:
|
||||
explicit NumberMantissaScaleGuard(MantissaRange::MantissaScale scale) noexcept
|
||||
explicit NumberMantissaScaleGuard(MantissaRange::mantissa_scale scale) noexcept
|
||||
: saved_{Number::getMantissaScale()}
|
||||
{
|
||||
Number::setMantissaScale(scale);
|
||||
|
||||
@@ -101,7 +101,7 @@ to_string(RangeSet<T> const& rs)
|
||||
*/
|
||||
template <class T>
|
||||
[[nodiscard]] bool
|
||||
fromString(RangeSet<T>& rs, std::string const& s)
|
||||
from_string(RangeSet<T>& rs, std::string const& s)
|
||||
{
|
||||
std::vector<std::string> intervals;
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
@@ -16,7 +16,7 @@ public:
|
||||
|
||||
/** Issue an asynchronous stop request. */
|
||||
virtual void
|
||||
stopAsync() = 0;
|
||||
stop_async() = 0;
|
||||
|
||||
/** Issue a synchronous stop request. */
|
||||
virtual void
|
||||
|
||||
@@ -13,7 +13,7 @@ public:
|
||||
explicit ResolverAsio() = default;
|
||||
|
||||
static std::unique_ptr<ResolverAsio>
|
||||
make(boost::asio::io_context&, beast::Journal);
|
||||
New(boost::asio::io_context&, beast::Journal);
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -21,12 +21,12 @@ public:
|
||||
}
|
||||
|
||||
[[nodiscard]] uint256 const&
|
||||
asUInt256() const
|
||||
as_uint256() const
|
||||
{
|
||||
return hash_;
|
||||
}
|
||||
uint256&
|
||||
asUInt256()
|
||||
as_uint256()
|
||||
{
|
||||
return hash_;
|
||||
}
|
||||
@@ -93,7 +93,7 @@ template <>
|
||||
inline std::size_t
|
||||
extract(SHAMapHash const& key)
|
||||
{
|
||||
return *reinterpret_cast<std::size_t const*>(key.asUInt256().data());
|
||||
return *reinterpret_cast<std::size_t const*>(key.as_uint256().data());
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -73,7 +73,7 @@ public:
|
||||
/** If this is a strong pointer, return the strong count. Otherwise return 0
|
||||
*/
|
||||
[[nodiscard]] std::size_t
|
||||
useCount() const;
|
||||
use_count() const;
|
||||
|
||||
/** Return true if there is a non-zero strong count. */
|
||||
[[nodiscard]] bool
|
||||
|
||||
@@ -57,10 +57,10 @@ template <class T>
|
||||
std::shared_ptr<T> const&
|
||||
SharedWeakCachePointer<T>::getStrong() const
|
||||
{
|
||||
static std::shared_ptr<T> const kEmpty;
|
||||
static std::shared_ptr<T> const empty;
|
||||
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
|
||||
return *p;
|
||||
return kEmpty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
@@ -86,7 +86,7 @@ SharedWeakCachePointer<T>::get() const
|
||||
|
||||
template <class T>
|
||||
std::size_t
|
||||
SharedWeakCachePointer<T>::useCount() const
|
||||
SharedWeakCachePointer<T>::use_count() const
|
||||
{
|
||||
if (auto p = std::get_if<std::shared_ptr<T>>(&combo_))
|
||||
return p->use_count();
|
||||
|
||||
@@ -36,32 +36,32 @@ class SlabAllocator
|
||||
struct SlabBlock
|
||||
{
|
||||
// A mutex to protect the freelist for this block:
|
||||
std::mutex m;
|
||||
std::mutex m_;
|
||||
|
||||
// A linked list of appropriately sized free buffers:
|
||||
std::uint8_t* l = nullptr;
|
||||
std::uint8_t* l_ = nullptr;
|
||||
|
||||
// The next memory block
|
||||
SlabBlock* next;
|
||||
SlabBlock* next_;
|
||||
|
||||
// The underlying memory block:
|
||||
std::uint8_t const* const p = nullptr;
|
||||
std::uint8_t const* const p_ = nullptr;
|
||||
|
||||
// The extent of the underlying memory block:
|
||||
std::size_t const size;
|
||||
std::size_t const size_;
|
||||
|
||||
SlabBlock(SlabBlock* next, std::uint8_t* data, std::size_t size, std::size_t item)
|
||||
: next(next), p(data), size(size)
|
||||
: next_(next), p_(data), size_(size)
|
||||
{
|
||||
// We don't need to grab the mutex here, since we're the only
|
||||
// ones with access at this moment.
|
||||
|
||||
while (data + item <= p + size)
|
||||
while (data + item <= p_ + size_)
|
||||
{
|
||||
// Use memcpy to avoid unaligned UB
|
||||
// (will optimize to equivalent code)
|
||||
std::memcpy(data, static_cast<void const*>(&l), sizeof(std::uint8_t*));
|
||||
l = data;
|
||||
std::memcpy(data, static_cast<void const*>(&l_), sizeof(std::uint8_t*));
|
||||
l_ = data;
|
||||
data += item;
|
||||
}
|
||||
}
|
||||
@@ -81,9 +81,9 @@ class SlabAllocator
|
||||
|
||||
/** Determines whether the given pointer belongs to this allocator */
|
||||
bool
|
||||
own(std::uint8_t const* pIn) const noexcept
|
||||
own(std::uint8_t const* p) const noexcept
|
||||
{
|
||||
return (pIn >= p) && (pIn < p + size);
|
||||
return (p >= p_) && (p < p_ + size_);
|
||||
}
|
||||
|
||||
std::uint8_t*
|
||||
@@ -92,14 +92,15 @@ class SlabAllocator
|
||||
std::uint8_t* ret = nullptr; // NOLINT(misc-const-correctness)
|
||||
|
||||
{
|
||||
std::scoped_lock const lock(m);
|
||||
ret = l;
|
||||
std::scoped_lock const l(m_);
|
||||
|
||||
ret = l_;
|
||||
|
||||
if (ret != nullptr)
|
||||
{
|
||||
// Use memcpy to avoid unaligned UB
|
||||
// (will optimize to equivalent code)
|
||||
std::memcpy(static_cast<void*>(&l), ret, sizeof(std::uint8_t*));
|
||||
std::memcpy(static_cast<void*>(&l_), ret, sizeof(std::uint8_t*));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,12 +121,12 @@ class SlabAllocator
|
||||
{
|
||||
XRPL_ASSERT(own(ptr), "xrpl::SlabAllocator::SlabBlock::deallocate : own input");
|
||||
|
||||
std::scoped_lock const lock(m);
|
||||
std::scoped_lock const l(m_);
|
||||
|
||||
// Use memcpy to avoid unaligned UB
|
||||
// (will optimize to equivalent code)
|
||||
std::memcpy(ptr, static_cast<void const*>(&l), sizeof(std::uint8_t*));
|
||||
l = ptr;
|
||||
std::memcpy(ptr, static_cast<void const*>(&l_), sizeof(std::uint8_t*));
|
||||
l_ = ptr;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -200,7 +201,7 @@ public:
|
||||
if (auto ret = slab->allocate())
|
||||
return ret;
|
||||
|
||||
slab = slab->next;
|
||||
slab = slab->next_;
|
||||
}
|
||||
|
||||
// No slab can satisfy our request, so we attempt to allocate a new
|
||||
@@ -241,7 +242,7 @@ public:
|
||||
|
||||
// Link the new slab
|
||||
while (!slabs_.compare_exchange_weak(
|
||||
slab->next, slab, std::memory_order_release, std::memory_order_relaxed))
|
||||
slab->next_, slab, std::memory_order_release, std::memory_order_relaxed))
|
||||
{
|
||||
; // Nothing to do
|
||||
}
|
||||
@@ -264,7 +265,7 @@ public:
|
||||
"xrpl::SlabAllocator::SlabAllocator::deallocate : non-null "
|
||||
"input");
|
||||
|
||||
for (auto slab = slabs_.load(); slab != nullptr; slab = slab->next)
|
||||
for (auto slab = slabs_.load(); slab != nullptr; slab = slab->next_)
|
||||
{
|
||||
if (slab->own(ptr))
|
||||
{
|
||||
@@ -293,16 +294,16 @@ public:
|
||||
friend class SlabAllocatorSet;
|
||||
|
||||
private:
|
||||
std::size_t extra_;
|
||||
std::size_t alloc_;
|
||||
std::size_t align_;
|
||||
std::size_t extra;
|
||||
std::size_t alloc;
|
||||
std::size_t align;
|
||||
|
||||
public:
|
||||
constexpr SlabConfig(
|
||||
std::size_t extra,
|
||||
std::size_t alloc = 0,
|
||||
std::size_t align = alignof(Type))
|
||||
: extra_(extra), alloc_(alloc), align_(align)
|
||||
std::size_t extra_,
|
||||
std::size_t alloc_ = 0,
|
||||
std::size_t align_ = alignof(Type))
|
||||
: extra(extra_), alloc(alloc_), align(align_)
|
||||
{
|
||||
}
|
||||
};
|
||||
@@ -312,22 +313,22 @@ public:
|
||||
// Ensure that the specified allocators are sorted from smallest to
|
||||
// largest by size:
|
||||
std::sort(std::begin(cfg), std::end(cfg), [](SlabConfig const& a, SlabConfig const& b) {
|
||||
return a.extra_ < b.extra_;
|
||||
return a.extra < b.extra;
|
||||
});
|
||||
|
||||
// We should never have two slabs of the same size
|
||||
if (std::adjacent_find(
|
||||
std::begin(cfg), std::end(cfg), [](SlabConfig const& a, SlabConfig const& b) {
|
||||
return a.extra_ == b.extra_;
|
||||
return a.extra == b.extra;
|
||||
}) != cfg.end())
|
||||
{
|
||||
throw std::runtime_error(
|
||||
"SlabAllocatorSet<" + beast::typeName<Type>() + ">: duplicate slab size");
|
||||
"SlabAllocatorSet<" + beast::type_name<Type>() + ">: duplicate slab size");
|
||||
}
|
||||
|
||||
for (auto const& c : cfg)
|
||||
{
|
||||
auto& a = allocators_.emplace_back(c.extra_, c.alloc_, c.align_);
|
||||
auto& a = allocators_.emplace_back(c.extra, c.alloc, c.align);
|
||||
|
||||
if (a.size() > maxSize_)
|
||||
maxSize_ = a.size();
|
||||
|
||||
@@ -110,7 +110,7 @@ public:
|
||||
|
||||
/** Shrinks the slice by moving its start forward by n characters. */
|
||||
void
|
||||
removePrefix(std::size_t n)
|
||||
remove_prefix(std::size_t n)
|
||||
{
|
||||
data_ += n;
|
||||
size_ -= n;
|
||||
@@ -118,7 +118,7 @@ public:
|
||||
|
||||
/** Shrinks the slice by moving its end backward by n characters. */
|
||||
void
|
||||
removeSuffix(std::size_t n)
|
||||
remove_suffix(std::size_t n)
|
||||
{
|
||||
size_ -= n;
|
||||
}
|
||||
|
||||
@@ -7,11 +7,9 @@
|
||||
#include <boost/utility/string_view.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <concepts>
|
||||
#include <cstdint>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
|
||||
namespace xrpl {
|
||||
|
||||
@@ -28,39 +26,28 @@ namespace xrpl {
|
||||
std::string
|
||||
sqlBlobLiteral(Blob const& blob);
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
concept SomeChar = std::same_as<std::remove_cvref_t<T>, int8_t> ||
|
||||
std::same_as<std::remove_cvref_t<T>, char> || std::same_as<std::remove_cvref_t<T>, uint8_t>;
|
||||
|
||||
inline constexpr std::array<std::optional<int>, 256> const kDigitLookupTable = []() {
|
||||
std::array<std::optional<int>, 256> t{};
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
t['0' + i] = i;
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
t['A' + i] = 10 + i;
|
||||
t['a' + i] = 10 + i;
|
||||
}
|
||||
|
||||
return t;
|
||||
}();
|
||||
|
||||
inline std::optional<int>
|
||||
hexCharToInt(SomeChar auto hexChar)
|
||||
{
|
||||
return kDigitLookupTable[static_cast<uint8_t>(hexChar)];
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
template <class Iterator>
|
||||
std::optional<Blob>
|
||||
strUnHex(std::size_t strSize, Iterator begin, Iterator end)
|
||||
{
|
||||
static constexpr std::array<int, 256> const digitLookupTable = []() {
|
||||
std::array<int, 256> t{};
|
||||
|
||||
for (auto& x : t)
|
||||
x = -1;
|
||||
|
||||
for (int i = 0; i < 10; ++i)
|
||||
t['0' + i] = i;
|
||||
|
||||
for (int i = 0; i < 6; ++i)
|
||||
{
|
||||
t['A' + i] = 10 + i;
|
||||
t['a' + i] = 10 + i;
|
||||
}
|
||||
|
||||
return t;
|
||||
}();
|
||||
|
||||
Blob out;
|
||||
|
||||
out.reserve((strSize + 1) / 2);
|
||||
@@ -69,26 +56,27 @@ strUnHex(std::size_t strSize, Iterator begin, Iterator end)
|
||||
|
||||
if (strSize & 1)
|
||||
{
|
||||
auto const c = detail::hexCharToInt(*iter++);
|
||||
if (!c.has_value())
|
||||
int c = digitLookupTable[*iter++];
|
||||
|
||||
if (c < 0)
|
||||
return {};
|
||||
|
||||
out.push_back(static_cast<unsigned char>(*c));
|
||||
out.push_back(c);
|
||||
}
|
||||
|
||||
while (iter != end)
|
||||
{
|
||||
auto const cHigh = detail::hexCharToInt(*iter++);
|
||||
int const cHigh = digitLookupTable[*iter++];
|
||||
|
||||
if (!cHigh.has_value())
|
||||
if (cHigh < 0)
|
||||
return {};
|
||||
|
||||
auto const cLow = detail::hexCharToInt(*iter++);
|
||||
int const cLow = digitLookupTable[*iter++];
|
||||
|
||||
if (!cLow.has_value())
|
||||
if (cLow < 0)
|
||||
return {};
|
||||
|
||||
out.push_back(static_cast<unsigned char>((*cHigh << 4) | *cLow));
|
||||
out.push_back(static_cast<unsigned char>((cHigh << 4) | cLow));
|
||||
}
|
||||
|
||||
return {std::move(out)};
|
||||
@@ -106,9 +94,9 @@ strViewUnHex(std::string_view strSrc)
|
||||
return strUnHex(strSrc.size(), strSrc.cbegin(), strSrc.cend());
|
||||
}
|
||||
|
||||
struct ParsedUrl
|
||||
struct parsedURL
|
||||
{
|
||||
explicit ParsedUrl() = default;
|
||||
explicit parsedURL() = default;
|
||||
|
||||
std::string scheme;
|
||||
std::string username;
|
||||
@@ -118,7 +106,7 @@ struct ParsedUrl
|
||||
std::string path;
|
||||
|
||||
bool
|
||||
operator==(ParsedUrl const& other) const
|
||||
operator==(parsedURL const& other) const
|
||||
{
|
||||
return scheme == other.scheme && domain == other.domain && port == other.port &&
|
||||
path == other.path;
|
||||
@@ -126,13 +114,13 @@ struct ParsedUrl
|
||||
};
|
||||
|
||||
bool
|
||||
parseUrl(ParsedUrl& pUrl, std::string const& strUrl);
|
||||
parseUrl(parsedURL& pUrl, std::string const& strUrl);
|
||||
|
||||
std::string
|
||||
trimWhitespace(std::string str);
|
||||
trim_whitespace(std::string str);
|
||||
|
||||
std::optional<std::uint64_t>
|
||||
toUInt64(std::string const& s);
|
||||
to_uint64(std::string const& s);
|
||||
|
||||
/** Determines if the given string looks like a TOML-file hosting domain.
|
||||
|
||||
|
||||
@@ -35,7 +35,7 @@ template <
|
||||
bool IsKeyCache = false,
|
||||
class SharedWeakUnionPointerType = SharedWeakCachePointer<T>,
|
||||
class SharedPointerType = std::shared_ptr<T>,
|
||||
class Hash = HardenedHash<>,
|
||||
class Hash = hardened_hash<>,
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Mutex = std::recursive_mutex>
|
||||
class TaggedCache
|
||||
@@ -44,7 +44,7 @@ public:
|
||||
using mutex_type = Mutex;
|
||||
using key_type = Key;
|
||||
using mapped_type = T;
|
||||
using clock_type = beast::AbstractClock<std::chrono::steady_clock>;
|
||||
using clock_type = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
using shared_weak_combo_pointer_type = SharedWeakUnionPointerType;
|
||||
using shared_pointer_type = SharedPointerType;
|
||||
|
||||
@@ -55,7 +55,7 @@ public:
|
||||
clock_type::duration expiration,
|
||||
clock_type& clock,
|
||||
beast::Journal journal,
|
||||
beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::make());
|
||||
beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::New());
|
||||
|
||||
public:
|
||||
/** Return the clock associated with the cache. */
|
||||
@@ -86,7 +86,7 @@ public:
|
||||
*/
|
||||
template <class KeyComparable>
|
||||
bool
|
||||
touchIfExists(KeyComparable const& key);
|
||||
touch_if_exists(KeyComparable const& key);
|
||||
|
||||
using SweptPointersVector = std::vector<SharedWeakUnionPointerType>;
|
||||
|
||||
@@ -115,10 +115,10 @@ public:
|
||||
canonicalize(key_type const& key, SharedPointerType& data, R&& replaceCallback);
|
||||
|
||||
bool
|
||||
canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data);
|
||||
canonicalize_replace_cache(key_type const& key, SharedPointerType const& data);
|
||||
|
||||
bool
|
||||
canonicalizeReplaceClient(key_type const& key, SharedPointerType& data);
|
||||
canonicalize_replace_client(key_type const& key, SharedPointerType& data);
|
||||
|
||||
SharedPointerType
|
||||
fetch(key_type const& key);
|
||||
@@ -169,7 +169,7 @@ private:
|
||||
initialFetch(key_type const& key, std::scoped_lock<mutex_type> const& l);
|
||||
|
||||
void
|
||||
collectMetrics();
|
||||
collect_metrics();
|
||||
|
||||
private:
|
||||
struct Stats
|
||||
@@ -179,16 +179,16 @@ private:
|
||||
std::string const& prefix,
|
||||
Handler const& handler,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
: hook(collector->makeHook(handler))
|
||||
, size(collector->makeGauge(prefix, "size"))
|
||||
, hitRate(collector->makeGauge(prefix, "hit_rate"))
|
||||
: hook(collector->make_hook(handler))
|
||||
, size(collector->make_gauge(prefix, "size"))
|
||||
, hit_rate(collector->make_gauge(prefix, "hit_rate"))
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
beast::insight::Hook hook;
|
||||
beast::insight::Gauge size;
|
||||
beast::insight::Gauge hitRate;
|
||||
beast::insight::Gauge hit_rate;
|
||||
|
||||
std::size_t hits{0};
|
||||
std::size_t misses{0};
|
||||
@@ -197,16 +197,17 @@ private:
|
||||
class KeyOnlyEntry
|
||||
{
|
||||
public:
|
||||
clock_type::time_point lastAccess;
|
||||
clock_type::time_point last_access;
|
||||
|
||||
explicit KeyOnlyEntry(clock_type::time_point const& lastAccess) : lastAccess(lastAccess)
|
||||
explicit KeyOnlyEntry(clock_type::time_point const& last_access_)
|
||||
: last_access(last_access_)
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
touch(clock_type::time_point const& now)
|
||||
{
|
||||
lastAccess = now;
|
||||
last_access = now;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -214,10 +215,10 @@ private:
|
||||
{
|
||||
public:
|
||||
shared_weak_combo_pointer_type ptr;
|
||||
clock_type::time_point lastAccess;
|
||||
clock_type::time_point last_access;
|
||||
|
||||
ValueEntry(clock_type::time_point const& lastAccess, shared_pointer_type const& ptr)
|
||||
: ptr(ptr), lastAccess(lastAccess)
|
||||
ValueEntry(clock_type::time_point const& last_access_, shared_pointer_type const& ptr_)
|
||||
: ptr(ptr_), last_access(last_access_)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -246,7 +247,7 @@ private:
|
||||
void
|
||||
touch(clock_type::time_point const& now)
|
||||
{
|
||||
lastAccess = now;
|
||||
last_access = now;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -260,7 +261,7 @@ private:
|
||||
|
||||
[[nodiscard]] std::thread
|
||||
sweepHelper(
|
||||
clock_type::time_point const& whenExpire,
|
||||
clock_type::time_point const& when_expire,
|
||||
[[maybe_unused]] clock_type::time_point const& now,
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
@@ -269,33 +270,33 @@ private:
|
||||
|
||||
[[nodiscard]] std::thread
|
||||
sweepHelper(
|
||||
clock_type::time_point const& whenExpire,
|
||||
clock_type::time_point const& when_expire,
|
||||
clock_type::time_point const& now,
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
std::atomic<int>& allRemovals,
|
||||
std::scoped_lock<std::recursive_mutex> const&);
|
||||
|
||||
beast::Journal journal_;
|
||||
clock_type& clock_;
|
||||
Stats stats_;
|
||||
beast::Journal m_journal;
|
||||
clock_type& m_clock;
|
||||
Stats m_stats;
|
||||
|
||||
mutex_type mutable mutex_;
|
||||
mutex_type mutable m_mutex;
|
||||
|
||||
// Used for logging
|
||||
std::string name_;
|
||||
std::string m_name;
|
||||
|
||||
// Desired number of cache entries (0 = ignore)
|
||||
int const targetSize_;
|
||||
int const m_target_size;
|
||||
|
||||
// Desired maximum cache age
|
||||
clock_type::duration const targetAge_;
|
||||
clock_type::duration const m_target_age;
|
||||
|
||||
// Number of items cached
|
||||
int cacheCount_{0};
|
||||
cache_type cache_; // Hold strong reference to recent objects
|
||||
std::uint64_t hits_{0};
|
||||
std::uint64_t misses_{0};
|
||||
int m_cache_count{0};
|
||||
cache_type m_cache; // Hold strong reference to recent objects
|
||||
std::uint64_t m_hits{0};
|
||||
std::uint64_t m_misses{0};
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -30,12 +30,13 @@ inline TaggedCache<
|
||||
clock_type& clock,
|
||||
beast::Journal journal,
|
||||
beast::insight::Collector::ptr const& collector)
|
||||
: journal_(journal)
|
||||
, clock_(clock)
|
||||
, stats_(name, std::bind(&TaggedCache::collectMetrics, this), collector)
|
||||
, name_(name)
|
||||
, targetSize_(size)
|
||||
, targetAge_(expiration)
|
||||
: m_journal(journal)
|
||||
, m_clock(clock)
|
||||
, m_stats(name, std::bind(&TaggedCache::collect_metrics, this), collector)
|
||||
, m_name(name)
|
||||
, m_target_size(size)
|
||||
, m_target_age(expiration)
|
||||
|
||||
{
|
||||
}
|
||||
|
||||
@@ -52,7 +53,7 @@ inline auto
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
clock() -> clock_type&
|
||||
{
|
||||
return clock_;
|
||||
return m_clock;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -68,8 +69,8 @@ inline std::size_t
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
size() const
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return cache_.size();
|
||||
std::scoped_lock lock(m_mutex);
|
||||
return m_cache.size();
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -85,8 +86,8 @@ inline int
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
getCacheSize() const
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return cacheCount_;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
return m_cache_count;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -102,8 +103,8 @@ inline int
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
getTrackSize() const
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
return cache_.size();
|
||||
std::scoped_lock lock(m_mutex);
|
||||
return m_cache.size();
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -119,9 +120,9 @@ inline float
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
getHitRate()
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
auto const total = static_cast<float>(hits_ + misses_);
|
||||
return hits_ * (100.0f / std::max(1.0f, total));
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto const total = static_cast<float>(m_hits + m_misses);
|
||||
return m_hits * (100.0f / std::max(1.0f, total));
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -137,9 +138,9 @@ inline void
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
clear()
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
cache_.clear();
|
||||
cacheCount_ = 0;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_cache.clear();
|
||||
m_cache_count = 0;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -155,11 +156,11 @@ inline void
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
reset()
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
cache_.clear();
|
||||
cacheCount_ = 0;
|
||||
hits_ = 0;
|
||||
misses_ = 0;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
m_cache.clear();
|
||||
m_cache_count = 0;
|
||||
m_hits = 0;
|
||||
m_misses = 0;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -174,17 +175,17 @@ template <
|
||||
template <class KeyComparable>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
touchIfExists(KeyComparable const& key)
|
||||
touch_if_exists(KeyComparable const& key)
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
auto const iter(cache_.find(key));
|
||||
if (iter == cache_.end())
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto const iter(m_cache.find(key));
|
||||
if (iter == m_cache.end())
|
||||
{
|
||||
++stats_.misses;
|
||||
++m_stats.misses;
|
||||
return false;
|
||||
}
|
||||
iter->second.touch(clock_.now());
|
||||
++stats_.hits;
|
||||
iter->second.touch(m_clock.now());
|
||||
++m_stats.hits;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -204,53 +205,53 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
// Keep references to all the stuff we sweep
|
||||
// For performance, each worker thread should exit before the swept data
|
||||
// is destroyed but still within the main cache lock.
|
||||
std::vector<SweptPointersVector> allStuffToSweep(cache_.partitions());
|
||||
std::vector<SweptPointersVector> allStuffToSweep(m_cache.partitions());
|
||||
|
||||
clock_type::time_point const now(clock_.now());
|
||||
clock_type::time_point whenExpire;
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
clock_type::time_point when_expire;
|
||||
|
||||
auto const start = std::chrono::steady_clock::now();
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
if (targetSize_ == 0 || (static_cast<int>(cache_.size()) <= targetSize_))
|
||||
if (m_target_size == 0 || (static_cast<int>(m_cache.size()) <= m_target_size))
|
||||
{
|
||||
whenExpire = now - targetAge_;
|
||||
when_expire = now - m_target_age;
|
||||
}
|
||||
else
|
||||
{
|
||||
whenExpire = now - (targetAge_ * targetSize_ / cache_.size());
|
||||
when_expire = now - m_target_age * m_target_size / m_cache.size();
|
||||
|
||||
clock_type::duration const minimumAge(std::chrono::seconds(1));
|
||||
if (whenExpire > (now - minimumAge))
|
||||
whenExpire = now - minimumAge;
|
||||
if (when_expire > (now - minimumAge))
|
||||
when_expire = now - minimumAge;
|
||||
|
||||
JLOG(journal_.trace())
|
||||
<< name_ << " is growing fast " << cache_.size() << " of " << targetSize_
|
||||
<< " aging at " << (now - whenExpire).count() << " of " << targetAge_.count();
|
||||
JLOG(m_journal.trace())
|
||||
<< m_name << " is growing fast " << m_cache.size() << " of " << m_target_size
|
||||
<< " aging at " << (now - when_expire).count() << " of " << m_target_age.count();
|
||||
}
|
||||
|
||||
std::vector<std::thread> workers;
|
||||
workers.reserve(cache_.partitions());
|
||||
workers.reserve(m_cache.partitions());
|
||||
std::atomic<int> allRemovals = 0;
|
||||
|
||||
for (std::size_t p = 0; p < cache_.partitions(); ++p)
|
||||
for (std::size_t p = 0; p < m_cache.partitions(); ++p)
|
||||
{
|
||||
workers.push_back(sweepHelper(
|
||||
whenExpire, now, cache_.map()[p], allStuffToSweep[p], allRemovals, lock));
|
||||
when_expire, now, m_cache.map()[p], allStuffToSweep[p], allRemovals, lock));
|
||||
}
|
||||
for (std::thread& worker : workers)
|
||||
worker.join();
|
||||
|
||||
cacheCount_ -= allRemovals;
|
||||
m_cache_count -= allRemovals;
|
||||
}
|
||||
// At this point allStuffToSweep will go out of scope outside the lock
|
||||
// and decrement the reference count on each strong pointer.
|
||||
JLOG(journal_.debug()) << name_ << " TaggedCache sweep lock duration "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start)
|
||||
.count()
|
||||
<< "ms";
|
||||
JLOG(m_journal.debug()) << m_name << " TaggedCache sweep lock duration "
|
||||
<< std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
std::chrono::steady_clock::now() - start)
|
||||
.count()
|
||||
<< "ms";
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -266,12 +267,13 @@ inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
del(key_type const& key, bool valid)
|
||||
{
|
||||
// Remove from cache, if !valid, remove from map too. Returns true if removed from cache
|
||||
std::scoped_lock const lock(mutex_);
|
||||
// Remove from cache, if !valid, remove from map too. Returns true if
|
||||
// removed from cache
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
auto cit = cache_.find(key);
|
||||
auto cit = m_cache.find(key);
|
||||
|
||||
if (cit == cache_.end())
|
||||
if (cit == m_cache.end())
|
||||
return false;
|
||||
|
||||
Entry& entry = cit->second;
|
||||
@@ -280,13 +282,13 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
|
||||
if (entry.isCached())
|
||||
{
|
||||
--cacheCount_;
|
||||
--m_cache_count;
|
||||
entry.ptr.convertToWeak();
|
||||
ret = true;
|
||||
}
|
||||
|
||||
if (!valid || entry.isExpired())
|
||||
cache_.erase(cit);
|
||||
m_cache.erase(cit);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@@ -307,22 +309,22 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
{
|
||||
// Return canonical value, store if needed, refresh in cache
|
||||
// Return values: true=we had the data already
|
||||
std::scoped_lock const lock(mutex_);
|
||||
std::scoped_lock lock(m_mutex);
|
||||
|
||||
auto cit = cache_.find(key);
|
||||
auto cit = m_cache.find(key);
|
||||
|
||||
if (cit == cache_.end())
|
||||
if (cit == m_cache.end())
|
||||
{
|
||||
cache_.emplace(
|
||||
m_cache.emplace(
|
||||
std::piecewise_construct,
|
||||
std::forward_as_tuple(key),
|
||||
std::forward_as_tuple(clock_.now(), data));
|
||||
++cacheCount_;
|
||||
std::forward_as_tuple(m_clock.now(), data));
|
||||
++m_cache_count;
|
||||
return false;
|
||||
}
|
||||
|
||||
Entry& entry = cit->second;
|
||||
entry.touch(clock_.now());
|
||||
entry.touch(m_clock.now());
|
||||
|
||||
auto shouldReplace = [&] {
|
||||
if constexpr (std::is_invocable_r_v<bool, R>)
|
||||
@@ -366,12 +368,12 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
data = cachedData;
|
||||
}
|
||||
|
||||
++cacheCount_;
|
||||
++m_cache_count;
|
||||
return true;
|
||||
}
|
||||
|
||||
entry.ptr = data;
|
||||
++cacheCount_;
|
||||
++m_cache_count;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -387,7 +389,7 @@ template <
|
||||
class Mutex>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data)
|
||||
canonicalize_replace_cache(key_type const& key, SharedPointerType const& data)
|
||||
{
|
||||
return canonicalize(key, const_cast<SharedPointerType&>(data), []() { return true; });
|
||||
}
|
||||
@@ -403,7 +405,7 @@ template <
|
||||
class Mutex>
|
||||
inline bool
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
canonicalizeReplaceClient(key_type const& key, SharedPointerType& data)
|
||||
canonicalize_replace_client(key_type const& key, SharedPointerType& data)
|
||||
{
|
||||
return canonicalize(key, data, []() { return false; });
|
||||
}
|
||||
@@ -421,10 +423,10 @@ inline SharedPointerType
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
fetch(key_type const& key)
|
||||
{
|
||||
std::scoped_lock<mutex_type> const l(mutex_);
|
||||
std::scoped_lock<mutex_type> l(m_mutex);
|
||||
auto ret = initialFetch(key, l);
|
||||
if (!ret)
|
||||
++misses_;
|
||||
++m_misses;
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -449,12 +451,12 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
if constexpr (std::is_same_v<std::shared_ptr<T>, SharedPointerType>)
|
||||
{
|
||||
auto p = std::make_shared<T>(std::cref(value));
|
||||
return canonicalizeReplaceClient(key, p);
|
||||
return canonicalize_replace_client(key, p);
|
||||
}
|
||||
if constexpr (std::is_same_v<intr_ptr::SharedPtr<T>, SharedPointerType>)
|
||||
{
|
||||
auto p = intr_ptr::makeShared<T>(std::cref(value));
|
||||
return canonicalizeReplaceClient(key, p);
|
||||
auto p = intr_ptr::make_shared<T>(std::cref(value));
|
||||
return canonicalize_replace_client(key, p);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -472,12 +474,12 @@ inline auto
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
insert(key_type const& key) -> std::enable_if_t<IsKeyCache, ReturnType>
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
clock_type::time_point const now(clock_.now());
|
||||
auto [it, inserted] = cache_.emplace(
|
||||
std::scoped_lock lock(m_mutex);
|
||||
clock_type::time_point const now(m_clock.now());
|
||||
auto [it, inserted] = m_cache.emplace(
|
||||
std::piecewise_construct, std::forward_as_tuple(key), std::forward_as_tuple(now));
|
||||
if (!inserted)
|
||||
it->second.lastAccess = now;
|
||||
it->second.last_access = now;
|
||||
return inserted;
|
||||
}
|
||||
|
||||
@@ -517,7 +519,7 @@ inline auto
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
peekMutex() -> mutex_type&
|
||||
{
|
||||
return mutex_;
|
||||
return m_mutex;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -536,9 +538,9 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
std::vector<key_type> v;
|
||||
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
v.reserve(cache_.size());
|
||||
for (auto const& _ : cache_)
|
||||
std::scoped_lock lock(m_mutex);
|
||||
v.reserve(m_cache.size());
|
||||
for (auto const& _ : m_cache)
|
||||
v.push_back(_.first);
|
||||
}
|
||||
|
||||
@@ -558,11 +560,11 @@ inline double
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
rate() const
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
auto const tot = hits_ + misses_;
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto const tot = m_hits + m_misses;
|
||||
if (tot == 0)
|
||||
return 0;
|
||||
return double(hits_) / tot;
|
||||
return double(m_hits) / tot;
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -580,7 +582,7 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
fetch(key_type const& digest, Handler const& h)
|
||||
{
|
||||
{
|
||||
std::scoped_lock const l(mutex_);
|
||||
std::scoped_lock l(m_mutex);
|
||||
if (auto ret = initialFetch(digest, l))
|
||||
return ret;
|
||||
}
|
||||
@@ -589,11 +591,11 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
if (!sle)
|
||||
return {};
|
||||
|
||||
std::scoped_lock const l(mutex_);
|
||||
++misses_;
|
||||
auto const [it, inserted] = cache_.emplace(digest, Entry(clock_.now(), std::move(sle)));
|
||||
std::scoped_lock l(m_mutex);
|
||||
++m_misses;
|
||||
auto const [it, inserted] = m_cache.emplace(digest, Entry(m_clock.now(), std::move(sle)));
|
||||
if (!inserted)
|
||||
it->second.touch(clock_.now());
|
||||
it->second.touch(m_clock.now());
|
||||
return it->second.ptr.getStrong();
|
||||
}
|
||||
// End CachedSLEs functions.
|
||||
@@ -611,27 +613,27 @@ inline SharedPointerType
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
initialFetch(key_type const& key, std::scoped_lock<mutex_type> const& l)
|
||||
{
|
||||
auto cit = cache_.find(key);
|
||||
if (cit == cache_.end())
|
||||
auto cit = m_cache.find(key);
|
||||
if (cit == m_cache.end())
|
||||
return {};
|
||||
|
||||
Entry& entry = cit->second;
|
||||
if (entry.isCached())
|
||||
{
|
||||
++hits_;
|
||||
entry.touch(clock_.now());
|
||||
++m_hits;
|
||||
entry.touch(m_clock.now());
|
||||
return entry.ptr.getStrong();
|
||||
}
|
||||
entry.ptr = entry.lock();
|
||||
if (entry.isCached())
|
||||
{
|
||||
// independent of cache size, so not counted as a hit
|
||||
++cacheCount_;
|
||||
entry.touch(clock_.now());
|
||||
++m_cache_count;
|
||||
entry.touch(m_clock.now());
|
||||
return entry.ptr.getStrong();
|
||||
}
|
||||
|
||||
cache_.erase(cit);
|
||||
m_cache.erase(cit);
|
||||
return {};
|
||||
}
|
||||
|
||||
@@ -646,19 +648,19 @@ template <
|
||||
class Mutex>
|
||||
inline void
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
collectMetrics()
|
||||
collect_metrics()
|
||||
{
|
||||
stats_.size.set(getCacheSize());
|
||||
m_stats.size.set(getCacheSize());
|
||||
|
||||
{
|
||||
beast::insight::Gauge::value_type hitRate(0);
|
||||
beast::insight::Gauge::value_type hit_rate(0);
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
auto const total(hits_ + misses_);
|
||||
std::scoped_lock lock(m_mutex);
|
||||
auto const total(m_hits + m_misses);
|
||||
if (total != 0)
|
||||
hitRate = (hits_ * 100) / total;
|
||||
hit_rate = (m_hits * 100) / total;
|
||||
}
|
||||
stats_.hitRate.set(hitRate);
|
||||
m_stats.hit_rate.set(hit_rate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -674,7 +676,7 @@ template <
|
||||
inline std::thread
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
sweepHelper(
|
||||
clock_type::time_point const& whenExpire,
|
||||
clock_type::time_point const& when_expire,
|
||||
[[maybe_unused]] clock_type::time_point const& now,
|
||||
typename KeyValueCacheType::map_type& partition,
|
||||
SweptPointersVector& stuffToSweep,
|
||||
@@ -706,11 +708,11 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
++cit;
|
||||
}
|
||||
}
|
||||
else if (cit->second.lastAccess <= whenExpire)
|
||||
else if (cit->second.last_access <= when_expire)
|
||||
{
|
||||
// strong, expired
|
||||
++cacheRemovals;
|
||||
if (cit->second.ptr.useCount() == 1)
|
||||
if (cit->second.ptr.use_count() == 1)
|
||||
{
|
||||
stuffToSweep.emplace_back(std::move(cit->second.ptr));
|
||||
++mapRemovals;
|
||||
@@ -733,8 +735,8 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
|
||||
if (mapRemovals || cacheRemovals)
|
||||
{
|
||||
JLOG(journal_.debug())
|
||||
<< "TaggedCache partition sweep " << name_ << ": cache = " << partition.size()
|
||||
JLOG(m_journal.debug())
|
||||
<< "TaggedCache partition sweep " << m_name << ": cache = " << partition.size()
|
||||
<< "-" << cacheRemovals << ", map-=" << mapRemovals;
|
||||
}
|
||||
|
||||
@@ -754,7 +756,7 @@ template <
|
||||
inline std::thread
|
||||
TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash, KeyEqual, Mutex>::
|
||||
sweepHelper(
|
||||
clock_type::time_point const& whenExpire,
|
||||
clock_type::time_point const& when_expire,
|
||||
clock_type::time_point const& now,
|
||||
typename KeyOnlyCacheType::map_type& partition,
|
||||
SweptPointersVector&,
|
||||
@@ -762,10 +764,8 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
std::scoped_lock<std::recursive_mutex> const&)
|
||||
{
|
||||
return std::thread([&, this]() {
|
||||
// NOLINTBEGIN https://github.com/XRPLF/rippled/issues/7056
|
||||
int cacheRemovals = 0;
|
||||
int mapRemovals = 0;
|
||||
// NOLINTEND
|
||||
|
||||
// Keep references to all the stuff we sweep
|
||||
// so that we can destroy them outside the lock.
|
||||
@@ -773,12 +773,12 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
auto cit = partition.begin();
|
||||
while (cit != partition.end())
|
||||
{
|
||||
if (cit->second.lastAccess > now)
|
||||
if (cit->second.last_access > now)
|
||||
{
|
||||
cit->second.lastAccess = now;
|
||||
cit->second.last_access = now;
|
||||
++cit;
|
||||
}
|
||||
else if (cit->second.lastAccess <= whenExpire)
|
||||
else if (cit->second.last_access <= when_expire)
|
||||
{
|
||||
cit = partition.erase(cit);
|
||||
}
|
||||
@@ -789,10 +789,10 @@ TaggedCache<Key, T, IsKeyCache, SharedWeakUnionPointer, SharedPointerType, Hash,
|
||||
}
|
||||
}
|
||||
|
||||
if (mapRemovals > 0 || cacheRemovals > 0)
|
||||
if (mapRemovals || cacheRemovals)
|
||||
{
|
||||
JLOG(journal_.debug())
|
||||
<< "TaggedCache partition sweep " << name_ << ": cache = " << partition.size()
|
||||
JLOG(m_journal.debug())
|
||||
<< "TaggedCache partition sweep " << m_name << ": cache = " << partition.size()
|
||||
<< "-" << cacheRemovals << ", map-=" << mapRemovals;
|
||||
}
|
||||
|
||||
|
||||
@@ -13,31 +13,31 @@ namespace xrpl {
|
||||
|
||||
template <class T>
|
||||
std::enable_if_t<std::is_arithmetic_v<T>, std::string>
|
||||
to_string(T t) // NOLINT(readability-identifier-naming)
|
||||
to_string(T t)
|
||||
{
|
||||
return std::to_string(t);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(bool b) // NOLINT(readability-identifier-naming)
|
||||
to_string(bool b)
|
||||
{
|
||||
return b ? "true" : "false";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(char c) // NOLINT(readability-identifier-naming)
|
||||
to_string(char c)
|
||||
{
|
||||
return std::string(1, c);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(std::string s) // NOLINT(readability-identifier-naming)
|
||||
to_string(std::string s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
to_string(char const* s) // NOLINT(readability-identifier-naming)
|
||||
to_string(char const* s)
|
||||
{
|
||||
return s;
|
||||
}
|
||||
|
||||
@@ -28,7 +28,7 @@ namespace xrpl {
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = beast::Uhash<>,
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hash_map = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
@@ -36,33 +36,33 @@ using hash_map = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = beast::Uhash<>,
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hash_multimap = std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
class Hash = beast::Uhash<>,
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hash_set = std::unordered_set<Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
class Hash = beast::Uhash<>,
|
||||
class Hash = beast::uhash<>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hash_multiset = std::unordered_multiset<Value, Hash, Pred, Allocator>;
|
||||
|
||||
// hardened_hash containers
|
||||
|
||||
using strong_hash = beast::Xxhasher;
|
||||
using strong_hash = beast::xxhasher;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = HardenedHash<strong_hash>,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hardened_hash_map = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
@@ -70,29 +70,29 @@ using hardened_hash_map = std::unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = HardenedHash<strong_hash>,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hardened_partitioned_hash_map = PartitionedUnorderedMap<Key, Value, Hash, Pred, Allocator>;
|
||||
using hardened_partitioned_hash_map = partitioned_unordered_map<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Key,
|
||||
class Value,
|
||||
class Hash = HardenedHash<strong_hash>,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, Value>>>
|
||||
using hardened_hash_multimap = std::unordered_multimap<Key, Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
class Hash = HardenedHash<strong_hash>,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hardened_hash_set = std::unordered_set<Value, Hash, Pred, Allocator>;
|
||||
|
||||
template <
|
||||
class Value,
|
||||
class Hash = HardenedHash<strong_hash>,
|
||||
class Hash = hardened_hash<strong_hash>,
|
||||
class Pred = std::equal_to<Value>,
|
||||
class Allocator = std::allocator<Value>>
|
||||
using hardened_hash_multiset = std::unordered_multiset<Value, Hash, Pred, Allocator>;
|
||||
|
||||
@@ -21,8 +21,7 @@ public:
|
||||
using period = std::ratio<1>;
|
||||
using duration = std::chrono::duration<rep, period>;
|
||||
using time_point = std::chrono::time_point<UptimeClock>;
|
||||
static constexpr bool is_steady = // NOLINT(readability-identifier-naming)
|
||||
std::chrono::system_clock::is_steady;
|
||||
static constexpr bool is_steady = std::chrono::system_clock::is_steady;
|
||||
|
||||
explicit UptimeClock() = default;
|
||||
|
||||
@@ -30,19 +29,19 @@ public:
|
||||
now(); // seconds since xrpld program start
|
||||
|
||||
private:
|
||||
static std::atomic<rep> kNow;
|
||||
static std::atomic<bool> kStop;
|
||||
static std::atomic<rep> now_;
|
||||
static std::atomic<bool> stop_;
|
||||
|
||||
struct UpdateThread : private std::thread
|
||||
struct update_thread : private std::thread
|
||||
{
|
||||
~UpdateThread();
|
||||
UpdateThread(UpdateThread&&) = default;
|
||||
~update_thread();
|
||||
update_thread(update_thread&&) = default;
|
||||
|
||||
using std::thread::thread;
|
||||
};
|
||||
|
||||
static UpdateThread
|
||||
startClock();
|
||||
static update_thread
|
||||
start_clock();
|
||||
};
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -13,7 +13,7 @@ namespace xrpl {
|
||||
// Note: This algorithm is evolved from std::set_intersection.
|
||||
template <class InputIter1, class InputIter2, class Action, class Comp>
|
||||
void
|
||||
generalizedSetIntersection(
|
||||
generalized_set_intersection(
|
||||
InputIter1 first1,
|
||||
InputIter1 last1,
|
||||
InputIter2 first2,
|
||||
@@ -53,7 +53,7 @@ generalizedSetIntersection(
|
||||
// std::set_intersection.
|
||||
template <class FwdIter1, class InputIter2, class Pred, class Comp>
|
||||
FwdIter1
|
||||
removeIfIntersectOrMatch(
|
||||
remove_if_intersect_or_match(
|
||||
FwdIter1 first1,
|
||||
FwdIter1 last1,
|
||||
InputIter2 first2,
|
||||
|
||||
@@ -40,15 +40,15 @@
|
||||
namespace xrpl {
|
||||
|
||||
std::string
|
||||
base64Encode(std::uint8_t const* data, std::size_t len);
|
||||
base64_encode(std::uint8_t const* data, std::size_t len);
|
||||
|
||||
inline std::string
|
||||
base64Encode(std::string const& s)
|
||||
base64_encode(std::string const& s)
|
||||
{
|
||||
return base64Encode(reinterpret_cast<std::uint8_t const*>(s.data()), s.size());
|
||||
return base64_encode(reinterpret_cast<std::uint8_t const*>(s.data()), s.size());
|
||||
}
|
||||
|
||||
std::string
|
||||
base64Decode(std::string_view data);
|
||||
base64_decode(std::string_view data);
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -27,12 +27,12 @@ namespace xrpl {
|
||||
namespace detail {
|
||||
|
||||
template <class Container, class = std::void_t<>>
|
||||
struct IsContiguousContainer : std::false_type
|
||||
struct is_contiguous_container : std::false_type
|
||||
{
|
||||
};
|
||||
|
||||
template <class Container>
|
||||
struct IsContiguousContainer<
|
||||
struct is_contiguous_container<
|
||||
Container,
|
||||
std::void_t<
|
||||
decltype(std::declval<Container const>().size()),
|
||||
@@ -42,12 +42,7 @@ struct IsContiguousContainer<
|
||||
};
|
||||
|
||||
template <>
|
||||
struct IsContiguousContainer<Slice> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
template <typename...>
|
||||
struct AlwaysFalseT : std::bool_constant<false>
|
||||
struct is_contiguous_container<Slice> : std::true_type
|
||||
{
|
||||
};
|
||||
|
||||
@@ -67,18 +62,18 @@ struct AlwaysFalseT : std::bool_constant<false>
|
||||
number of bits.
|
||||
*/
|
||||
template <std::size_t Bits, class Tag = void>
|
||||
class BaseUInt
|
||||
class base_uint
|
||||
{
|
||||
static_assert((Bits % 32) == 0, "The length of a base_uint in bits must be a multiple of 32.");
|
||||
|
||||
static_assert(Bits >= 64, "The length of a base_uint in bits must be at least 64.");
|
||||
|
||||
static constexpr std::size_t kWidth = Bits / 32;
|
||||
static constexpr std::size_t WIDTH = Bits / 32;
|
||||
|
||||
// This is really big-endian in byte order.
|
||||
// We sometimes use std::uint32_t for speed.
|
||||
|
||||
std::array<std::uint32_t, kWidth> data_;
|
||||
std::array<std::uint32_t, WIDTH> data_;
|
||||
|
||||
public:
|
||||
//--------------------------------------------------------------------------
|
||||
@@ -86,8 +81,8 @@ public:
|
||||
// STL Container Interface
|
||||
//
|
||||
|
||||
static constexpr std::size_t kBytes = Bits / 8;
|
||||
static_assert(sizeof(data_) == kBytes, "");
|
||||
static std::size_t constexpr bytes = Bits / 8;
|
||||
static_assert(sizeof(data_) == bytes, "");
|
||||
|
||||
using size_type = std::size_t;
|
||||
using difference_type = std::ptrdiff_t;
|
||||
@@ -121,7 +116,7 @@ public:
|
||||
iterator
|
||||
end()
|
||||
{
|
||||
return data() + kBytes;
|
||||
return data() + bytes;
|
||||
}
|
||||
[[nodiscard]] const_iterator
|
||||
begin() const
|
||||
@@ -131,7 +126,7 @@ public:
|
||||
[[nodiscard]] const_iterator
|
||||
end() const
|
||||
{
|
||||
return data() + kBytes;
|
||||
return data() + bytes;
|
||||
}
|
||||
[[nodiscard]] const_iterator
|
||||
cbegin() const
|
||||
@@ -141,14 +136,14 @@ public:
|
||||
[[nodiscard]] const_iterator
|
||||
cend() const
|
||||
{
|
||||
return data() + kBytes;
|
||||
return data() + bytes;
|
||||
}
|
||||
|
||||
/** Value hashing function.
|
||||
The seed prevents crafted inputs from causing degenerate parent
|
||||
containers.
|
||||
*/
|
||||
using hasher = HardenedHash<>;
|
||||
using hasher = hardened_hash<>;
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
|
||||
@@ -165,16 +160,16 @@ private:
|
||||
explicit VoidHelper() = default;
|
||||
};
|
||||
|
||||
explicit BaseUInt(void const* data, VoidHelper)
|
||||
explicit base_uint(void const* data, VoidHelper)
|
||||
{
|
||||
memcpy(data_.data(), data, kBytes);
|
||||
memcpy(data_.data(), data, bytes);
|
||||
}
|
||||
|
||||
// Helper function to initialize a base_uint from a std::string_view.
|
||||
enum class ParseResult {
|
||||
Okay,
|
||||
BadLength,
|
||||
BadChar,
|
||||
okay,
|
||||
badLength,
|
||||
badChar,
|
||||
};
|
||||
|
||||
constexpr Expected<decltype(data_), ParseResult>
|
||||
@@ -185,7 +180,7 @@ private:
|
||||
auto hexCharToUInt = [](char c, std::uint32_t shift, std::uint32_t& accum) -> ParseResult {
|
||||
std::uint32_t nibble = 0xFFu;
|
||||
if (c < '0' || c > 'f')
|
||||
return ParseResult::BadChar;
|
||||
return ParseResult::badChar;
|
||||
|
||||
if (c >= 'a')
|
||||
{
|
||||
@@ -201,11 +196,11 @@ private:
|
||||
}
|
||||
|
||||
if (nibble > 0xFu)
|
||||
return ParseResult::BadChar;
|
||||
return ParseResult::badChar;
|
||||
|
||||
accum |= (nibble << shift);
|
||||
|
||||
return ParseResult::Okay;
|
||||
return ParseResult::okay;
|
||||
};
|
||||
|
||||
decltype(data_) ret{};
|
||||
@@ -216,7 +211,7 @@ private:
|
||||
}
|
||||
|
||||
if (sv.size() != size() * 2)
|
||||
return Unexpected(ParseResult::BadLength);
|
||||
return Unexpected(ParseResult::badLength);
|
||||
|
||||
std::size_t i = 0u;
|
||||
auto in = sv.begin();
|
||||
@@ -226,7 +221,7 @@ private:
|
||||
for (std::uint32_t const shift : {4u, 0u, 12u, 8u, 20u, 16u, 28u, 24u})
|
||||
{
|
||||
if (auto const result = hexCharToUInt(*in++, shift, accum);
|
||||
result != ParseResult::Okay)
|
||||
result != ParseResult::okay)
|
||||
return Unexpected(result);
|
||||
}
|
||||
ret[i++] = accum;
|
||||
@@ -240,7 +235,7 @@ private:
|
||||
auto const result = parseFromStringView(sv);
|
||||
if (!result)
|
||||
{
|
||||
if (result.error() == ParseResult::BadLength)
|
||||
if (result.error() == ParseResult::badLength)
|
||||
Throw<std::invalid_argument>("invalid length for hex string");
|
||||
|
||||
Throw<std::range_error>("invalid hex character");
|
||||
@@ -249,15 +244,15 @@ private:
|
||||
}
|
||||
|
||||
public:
|
||||
constexpr BaseUInt() : data_{}
|
||||
constexpr base_uint() : data_{}
|
||||
{
|
||||
}
|
||||
|
||||
constexpr BaseUInt(beast::Zero) : data_{}
|
||||
constexpr base_uint(beast::Zero) : data_{}
|
||||
{
|
||||
}
|
||||
|
||||
explicit BaseUInt(std::uint64_t b)
|
||||
explicit base_uint(std::uint64_t b)
|
||||
{
|
||||
*this = b;
|
||||
}
|
||||
@@ -265,7 +260,7 @@ public:
|
||||
// This constructor is intended to be used at compile time since it might
|
||||
// throw at runtime. Consider declaring this constructor consteval once
|
||||
// we get to C++23.
|
||||
explicit constexpr BaseUInt(std::string_view sv) noexcept(false)
|
||||
explicit constexpr base_uint(std::string_view sv) noexcept(false)
|
||||
: data_(parseFromStringViewThrows(sv))
|
||||
{
|
||||
}
|
||||
@@ -273,44 +268,26 @@ public:
|
||||
template <
|
||||
class Container,
|
||||
class = std::enable_if_t<
|
||||
detail::IsContiguousContainer<Container>::value &&
|
||||
detail::is_contiguous_container<Container>::value &&
|
||||
std::is_trivially_copyable_v<typename Container::value_type>>>
|
||||
explicit BaseUInt(Container const& c)
|
||||
explicit base_uint(Container const& c)
|
||||
{
|
||||
// Use AlwaysFalseT so the static_assert condition is dependent
|
||||
// and only triggers when this constructor template is instantiated.
|
||||
static_assert(
|
||||
detail::AlwaysFalseT<Container>::value,
|
||||
"This constructor is not intended to be used and will be soon removed. "
|
||||
"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>>>
|
||||
static BaseUInt
|
||||
fromRaw(Container const& c)
|
||||
{
|
||||
BaseUInt result;
|
||||
XRPL_ASSERT(
|
||||
c.size() * sizeof(typename Container::value_type) == size(),
|
||||
"xrpl::BaseUInt::fromRaw(Container auto) : input size match");
|
||||
std::memcpy(result.data_.data(), c.data(), size());
|
||||
return result;
|
||||
"xrpl::base_uint::base_uint(Container auto) : input size match");
|
||||
std::memcpy(data_.data(), c.data(), size());
|
||||
}
|
||||
|
||||
template <class Container>
|
||||
std::enable_if_t<
|
||||
detail::IsContiguousContainer<Container>::value &&
|
||||
detail::is_contiguous_container<Container>::value &&
|
||||
std::is_trivially_copyable_v<typename Container::value_type>,
|
||||
BaseUInt&>
|
||||
base_uint&>
|
||||
operator=(Container const& c)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
c.size() * sizeof(typename Container::value_type) == size(),
|
||||
"xrpl::BaseUInt::operator=(Container auto) : input size match");
|
||||
"xrpl::base_uint::operator=(Container auto) : input size match");
|
||||
std::memcpy(data_.data(), c.data(), size());
|
||||
return *this;
|
||||
}
|
||||
@@ -318,14 +295,14 @@ public:
|
||||
/* Construct from a raw pointer.
|
||||
The buffer pointed to by `data` must be at least Bits/8 bytes.
|
||||
*/
|
||||
static BaseUInt
|
||||
static base_uint
|
||||
fromVoid(void const* data)
|
||||
{
|
||||
return BaseUInt(data, VoidHelper());
|
||||
return base_uint(data, VoidHelper());
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::optional<BaseUInt>
|
||||
static std::optional<base_uint>
|
||||
fromVoidChecked(T const& from)
|
||||
{
|
||||
if (from.size() != size())
|
||||
@@ -336,7 +313,7 @@ public:
|
||||
[[nodiscard]] constexpr int
|
||||
signum() const
|
||||
{
|
||||
for (int i = 0; i < kWidth; i++)
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
{
|
||||
if (data_[i] != 0)
|
||||
return 1;
|
||||
@@ -348,24 +325,24 @@ public:
|
||||
bool
|
||||
operator!() const
|
||||
{
|
||||
return *this == beast::kZero;
|
||||
return *this == beast::zero;
|
||||
}
|
||||
|
||||
constexpr BaseUInt
|
||||
constexpr base_uint
|
||||
operator~() const
|
||||
{
|
||||
BaseUInt ret;
|
||||
base_uint ret;
|
||||
|
||||
for (int i = 0; i < kWidth; i++)
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
ret.data_[i] = ~data_[i];
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BaseUInt&
|
||||
base_uint&
|
||||
operator=(std::uint64_t uHost)
|
||||
{
|
||||
*this = beast::kZero;
|
||||
*this = beast::zero;
|
||||
// NOLINTBEGIN(cppcoreguidelines-pro-type-member-init)
|
||||
union
|
||||
{
|
||||
@@ -375,43 +352,43 @@ public:
|
||||
// NOLINTEND(cppcoreguidelines-pro-type-member-init)
|
||||
// Put in least significant bits.
|
||||
ul = boost::endian::native_to_big(uHost);
|
||||
data_[kWidth - 2] = u[0];
|
||||
data_[kWidth - 1] = u[1];
|
||||
data_[WIDTH - 2] = u[0];
|
||||
data_[WIDTH - 1] = u[1];
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseUInt&
|
||||
operator^=(BaseUInt const& b)
|
||||
base_uint&
|
||||
operator^=(base_uint const& b)
|
||||
{
|
||||
for (int i = 0; i < kWidth; i++)
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] ^= b.data_[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseUInt&
|
||||
operator&=(BaseUInt const& b)
|
||||
base_uint&
|
||||
operator&=(base_uint const& b)
|
||||
{
|
||||
for (int i = 0; i < kWidth; i++)
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] &= b.data_[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseUInt&
|
||||
operator|=(BaseUInt const& b)
|
||||
base_uint&
|
||||
operator|=(base_uint const& b)
|
||||
{
|
||||
for (int i = 0; i < kWidth; i++)
|
||||
for (int i = 0; i < WIDTH; i++)
|
||||
data_[i] |= b.data_[i];
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseUInt&
|
||||
base_uint&
|
||||
operator++()
|
||||
{
|
||||
// prefix operator
|
||||
for (int i = kWidth - 1; i >= 0; --i)
|
||||
for (int i = WIDTH - 1; i >= 0; --i)
|
||||
{
|
||||
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) + 1);
|
||||
if (data_[i] != 0)
|
||||
@@ -421,20 +398,20 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseUInt
|
||||
base_uint
|
||||
operator++(int)
|
||||
{
|
||||
// postfix operator
|
||||
BaseUInt const ret = *this;
|
||||
base_uint const ret = *this;
|
||||
++(*this);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
BaseUInt&
|
||||
base_uint&
|
||||
operator--()
|
||||
{
|
||||
for (int i = kWidth - 1; i >= 0; --i)
|
||||
for (int i = WIDTH - 1; i >= 0; --i)
|
||||
{
|
||||
auto prev = data_[i];
|
||||
data_[i] = boost::endian::native_to_big(boost::endian::big_to_native(data_[i]) - 1);
|
||||
@@ -446,36 +423,36 @@ public:
|
||||
return *this;
|
||||
}
|
||||
|
||||
BaseUInt
|
||||
base_uint
|
||||
operator--(int)
|
||||
{
|
||||
// postfix operator
|
||||
BaseUInt const ret = *this;
|
||||
base_uint const ret = *this;
|
||||
--(*this);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
[[nodiscard]] BaseUInt
|
||||
[[nodiscard]] base_uint
|
||||
next() const
|
||||
{
|
||||
auto ret = *this;
|
||||
return ++ret;
|
||||
}
|
||||
|
||||
[[nodiscard]] BaseUInt
|
||||
[[nodiscard]] base_uint
|
||||
prev() const
|
||||
{
|
||||
auto ret = *this;
|
||||
return --ret;
|
||||
}
|
||||
|
||||
BaseUInt&
|
||||
operator+=(BaseUInt const& b)
|
||||
base_uint&
|
||||
operator+=(base_uint const& b)
|
||||
{
|
||||
std::uint64_t carry = 0;
|
||||
|
||||
for (int i = kWidth - 1; i >= 0; i--)
|
||||
for (int i = WIDTH - 1; i >= 0; i--)
|
||||
{
|
||||
std::uint64_t const n = carry + boost::endian::big_to_native(data_[i]) +
|
||||
boost::endian::big_to_native(b.data_[i]);
|
||||
@@ -489,7 +466,7 @@ public:
|
||||
|
||||
template <class Hasher>
|
||||
friend void
|
||||
hash_append(Hasher& h, BaseUInt const& a) noexcept
|
||||
hash_append(Hasher& h, base_uint const& a) noexcept
|
||||
{
|
||||
// Do not allow any endian transformations on this memory
|
||||
h(a.data_.data(), sizeof(a.data_));
|
||||
@@ -526,13 +503,13 @@ public:
|
||||
return parseHex(std::string_view{str});
|
||||
}
|
||||
|
||||
static constexpr std::size_t
|
||||
constexpr static std::size_t
|
||||
size()
|
||||
{
|
||||
return kBytes;
|
||||
return bytes;
|
||||
}
|
||||
|
||||
BaseUInt<Bits, Tag>&
|
||||
base_uint<Bits, Tag>&
|
||||
operator=(beast::Zero)
|
||||
{
|
||||
data_.fill(0);
|
||||
@@ -543,28 +520,28 @@ public:
|
||||
[[nodiscard]] bool
|
||||
isZero() const
|
||||
{
|
||||
return *this == beast::kZero;
|
||||
return *this == beast::zero;
|
||||
}
|
||||
[[nodiscard]] bool
|
||||
isNonZero() const
|
||||
{
|
||||
return *this != beast::kZero;
|
||||
return *this != beast::zero;
|
||||
}
|
||||
void
|
||||
zero()
|
||||
{
|
||||
*this = beast::kZero;
|
||||
*this = beast::zero;
|
||||
}
|
||||
};
|
||||
|
||||
using uint128 = BaseUInt<128>;
|
||||
using uint160 = BaseUInt<160>;
|
||||
using uint256 = BaseUInt<256>;
|
||||
using uint192 = BaseUInt<192>;
|
||||
using uint128 = base_uint<128>;
|
||||
using uint160 = base_uint<160>;
|
||||
using uint256 = base_uint<256>;
|
||||
using uint192 = base_uint<192>;
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
[[nodiscard]] constexpr std::strong_ordering
|
||||
operator<=>(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
|
||||
operator<=>(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
|
||||
{
|
||||
// This comparison might seem wrong on a casual inspection because it
|
||||
// compares data internally stored as std::uint32_t byte-by-byte. But
|
||||
@@ -585,7 +562,7 @@ operator<=>(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
|
||||
|
||||
template <std::size_t Bits, typename Tag>
|
||||
[[nodiscard]] constexpr bool
|
||||
operator==(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
|
||||
operator==(base_uint<Bits, Tag> const& lhs, base_uint<Bits, Tag> const& rhs)
|
||||
{
|
||||
return (lhs <=> rhs) == 0;
|
||||
}
|
||||
@@ -593,59 +570,59 @@ operator==(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
|
||||
//------------------------------------------------------------------------------
|
||||
template <std::size_t Bits, class Tag>
|
||||
constexpr bool
|
||||
operator==(BaseUInt<Bits, Tag> const& a, std::uint64_t b)
|
||||
operator==(base_uint<Bits, Tag> const& a, std::uint64_t b)
|
||||
{
|
||||
return a == BaseUInt<Bits, Tag>(b);
|
||||
return a == base_uint<Bits, Tag>(b);
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <std::size_t Bits, class Tag>
|
||||
constexpr BaseUInt<Bits, Tag>
|
||||
operator^(BaseUInt<Bits, Tag> const& a, BaseUInt<Bits, Tag> const& b)
|
||||
constexpr base_uint<Bits, Tag>
|
||||
operator^(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
|
||||
{
|
||||
return BaseUInt<Bits, Tag>(a) ^= b;
|
||||
return base_uint<Bits, Tag>(a) ^= b;
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
constexpr BaseUInt<Bits, Tag>
|
||||
operator&(BaseUInt<Bits, Tag> const& a, BaseUInt<Bits, Tag> const& b)
|
||||
constexpr base_uint<Bits, Tag>
|
||||
operator&(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
|
||||
{
|
||||
return BaseUInt<Bits, Tag>(a) &= b;
|
||||
return base_uint<Bits, Tag>(a) &= b;
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
constexpr BaseUInt<Bits, Tag>
|
||||
operator|(BaseUInt<Bits, Tag> const& a, BaseUInt<Bits, Tag> const& b)
|
||||
constexpr base_uint<Bits, Tag>
|
||||
operator|(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
|
||||
{
|
||||
return BaseUInt<Bits, Tag>(a) |= b;
|
||||
return base_uint<Bits, Tag>(a) |= b;
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
constexpr BaseUInt<Bits, Tag>
|
||||
operator+(BaseUInt<Bits, Tag> const& a, BaseUInt<Bits, Tag> const& b)
|
||||
constexpr base_uint<Bits, Tag>
|
||||
operator+(base_uint<Bits, Tag> const& a, base_uint<Bits, Tag> const& b)
|
||||
{
|
||||
return BaseUInt<Bits, Tag>(a) += b;
|
||||
return base_uint<Bits, Tag>(a) += b;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline std::string
|
||||
to_string(BaseUInt<Bits, Tag> const& a)
|
||||
to_string(base_uint<Bits, Tag> const& a)
|
||||
{
|
||||
return strHex(a.cbegin(), a.cend());
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline std::string
|
||||
toShortString(BaseUInt<Bits, Tag> const& a)
|
||||
to_short_string(base_uint<Bits, Tag> const& a)
|
||||
{
|
||||
static_assert(BaseUInt<Bits, Tag>::kBytes > 4, "For 4 bytes or less, use a native type");
|
||||
static_assert(base_uint<Bits, Tag>::bytes > 4, "For 4 bytes or less, use a native type");
|
||||
return strHex(a.cbegin(), a.cbegin() + 4) + "...";
|
||||
}
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
inline std::ostream&
|
||||
operator<<(std::ostream& out, BaseUInt<Bits, Tag> const& u)
|
||||
operator<<(std::ostream& out, base_uint<Bits, Tag> const& u)
|
||||
{
|
||||
return out << to_string(u);
|
||||
}
|
||||
@@ -673,9 +650,9 @@ static_assert(sizeof(uint256) == 256 / 8, "There should be no padding bytes");
|
||||
namespace beast {
|
||||
|
||||
template <std::size_t Bits, class Tag>
|
||||
struct IsUniquelyRepresented<xrpl::BaseUInt<Bits, Tag>> : public std::true_type
|
||||
struct is_uniquely_represented<xrpl::base_uint<Bits, Tag>> : public std::true_type
|
||||
{
|
||||
explicit IsUniquelyRepresented() = default;
|
||||
explicit is_uniquely_represented() = default;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -30,10 +30,10 @@ using weeks = std::chrono::duration<int, std::ratio_multiply<days::period, std::
|
||||
= seconds(946684800)
|
||||
*/
|
||||
|
||||
static constexpr std::chrono::seconds kEpochOffset =
|
||||
constexpr static std::chrono::seconds epoch_offset =
|
||||
date::sys_days{date::year{2000} / 1 / 1} - date::sys_days{date::year{1970} / 1 / 1};
|
||||
|
||||
static_assert(kEpochOffset.count() == 946684800);
|
||||
static_assert(epoch_offset.count() == 946684800);
|
||||
|
||||
class NetClock
|
||||
{
|
||||
@@ -45,7 +45,7 @@ public:
|
||||
using duration = std::chrono::duration<rep, period>;
|
||||
using time_point = std::chrono::time_point<NetClock>;
|
||||
|
||||
static bool const is_steady = false; // NOLINT(readability-identifier-naming)
|
||||
static bool const is_steady = false;
|
||||
};
|
||||
|
||||
template <class Duration>
|
||||
@@ -60,42 +60,42 @@ to_string(NetClock::time_point tp)
|
||||
{
|
||||
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
|
||||
using namespace std::chrono;
|
||||
return to_string(system_clock::time_point{tp.time_since_epoch() + kEpochOffset});
|
||||
return to_string(system_clock::time_point{tp.time_since_epoch() + epoch_offset});
|
||||
}
|
||||
|
||||
template <class Duration>
|
||||
std::string
|
||||
toStringIso(date::sys_time<Duration> tp)
|
||||
to_string_iso(date::sys_time<Duration> tp)
|
||||
{
|
||||
using namespace std::chrono;
|
||||
return date::format("%FT%TZ", tp);
|
||||
}
|
||||
|
||||
inline std::string
|
||||
toStringIso(NetClock::time_point tp)
|
||||
to_string_iso(NetClock::time_point tp)
|
||||
{
|
||||
// 2000-01-01 00:00:00 UTC is 946684800s from 1970-01-01 00:00:00 UTC
|
||||
// Note, NetClock::duration is seconds, as checked by static_assert
|
||||
static_assert(std::is_same_v<NetClock::duration::period, std::ratio<1>>);
|
||||
return toStringIso(date::sys_time<NetClock::duration>{tp.time_since_epoch() + kEpochOffset});
|
||||
return to_string_iso(date::sys_time<NetClock::duration>{tp.time_since_epoch() + epoch_offset});
|
||||
}
|
||||
|
||||
/** A clock for measuring elapsed time.
|
||||
|
||||
The epoch is unspecified.
|
||||
*/
|
||||
using Stopwatch = beast::AbstractClock<std::chrono::steady_clock>;
|
||||
using Stopwatch = beast::abstract_clock<std::chrono::steady_clock>;
|
||||
|
||||
/** A manual Stopwatch for unit tests. */
|
||||
using TestStopwatch = beast::ManualClock<std::chrono::steady_clock>;
|
||||
using TestStopwatch = beast::manual_clock<std::chrono::steady_clock>;
|
||||
|
||||
/** Returns an instance of a wall clock. */
|
||||
inline Stopwatch&
|
||||
stopwatch()
|
||||
{
|
||||
using Clock = beast::BasicSecondsClock;
|
||||
using Clock = beast::basic_seconds_clock;
|
||||
using Facade = Clock::Clock;
|
||||
return beast::getAbstractClock<Facade, Clock>();
|
||||
return beast::get_abstract_clock<Facade, Clock>();
|
||||
}
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace xrpl {
|
||||
|
||||
/** Generates and logs a call stack */
|
||||
void
|
||||
logThrow(std::string const& title);
|
||||
LogThrow(std::string const& title);
|
||||
|
||||
/** Rethrow the exception currently being handled.
|
||||
|
||||
@@ -30,9 +30,9 @@ logThrow(std::string const& title);
|
||||
triggering false positives, since it throws.
|
||||
*/
|
||||
[[noreturn]] XRPL_NO_SANITIZE_ADDRESS inline void
|
||||
rethrow()
|
||||
Rethrow()
|
||||
{
|
||||
logThrow("Re-throwing exception");
|
||||
LogThrow("Re-throwing exception");
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -52,12 +52,12 @@ Throw(Args&&... args)
|
||||
std::is_convertible_v<E*, std::exception*>, "Exception must derive from std::exception.");
|
||||
|
||||
E e(std::forward<Args>(args)...);
|
||||
logThrow(std::string("Throwing exception of type " + beast::typeName<E>() + ": ") + e.what());
|
||||
LogThrow(std::string("Throwing exception of type " + beast::type_name<E>() + ": ") + e.what());
|
||||
throw std::move(e);
|
||||
}
|
||||
|
||||
/** Called when faulty logic causes a broken invariant. */
|
||||
[[noreturn]] void
|
||||
logicError(std::string const& how) noexcept;
|
||||
LogicError(std::string const& how) noexcept;
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -16,24 +16,24 @@ using seed_pair = std::pair<std::uint64_t, std::uint64_t>;
|
||||
|
||||
template <bool = true>
|
||||
seed_pair
|
||||
makeSeedPair() noexcept
|
||||
make_seed_pair() noexcept
|
||||
{
|
||||
struct StateT
|
||||
struct state_t
|
||||
{
|
||||
std::mutex mutex;
|
||||
std::random_device rng;
|
||||
std::mt19937_64 gen;
|
||||
std::uniform_int_distribution<std::uint64_t> dist;
|
||||
|
||||
StateT() : gen(rng())
|
||||
state_t() : gen(rng())
|
||||
{
|
||||
}
|
||||
// state_t(state_t const&) = delete;
|
||||
// state_t& operator=(state_t const&) = delete;
|
||||
};
|
||||
static StateT kState;
|
||||
std::scoped_lock const lock(kState.mutex);
|
||||
return {kState.dist(kState.gen), kState.dist(kState.gen)};
|
||||
static state_t state;
|
||||
std::scoped_lock const lock(state.mutex);
|
||||
return {state.dist(state.gen), state.dist(state.gen)};
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
@@ -68,22 +68,22 @@ makeSeedPair() noexcept
|
||||
see https://131002.net/siphash/#at
|
||||
*/
|
||||
|
||||
template <class HashAlgorithm = beast::Xxhasher>
|
||||
class HardenedHash
|
||||
template <class HashAlgorithm = beast::xxhasher>
|
||||
class hardened_hash
|
||||
{
|
||||
private:
|
||||
detail::seed_pair seeds_{detail::makeSeedPair<>()};
|
||||
detail::seed_pair m_seeds{detail::make_seed_pair<>()};
|
||||
|
||||
public:
|
||||
using result_type = typename HashAlgorithm::result_type;
|
||||
|
||||
HardenedHash() = default;
|
||||
hardened_hash() = default;
|
||||
|
||||
template <class T>
|
||||
result_type
|
||||
operator()(T const& t) const noexcept
|
||||
{
|
||||
HashAlgorithm h(seeds_.first, seeds_.second);
|
||||
HashAlgorithm h(m_seeds.first, m_seeds.second);
|
||||
hash_append(h, t);
|
||||
return static_cast<result_type>(h);
|
||||
}
|
||||
|
||||
@@ -8,11 +8,11 @@ namespace xrpl {
|
||||
|
||||
/** Create a self-signed SSL context that allows anonymous Diffie Hellman. */
|
||||
std::shared_ptr<boost::asio::ssl::context>
|
||||
makeSslContext(std::string const& cipherList);
|
||||
make_SSLContext(std::string const& cipherList);
|
||||
|
||||
/** Create an authenticated SSL context using the specified files. */
|
||||
std::shared_ptr<boost::asio::ssl::context>
|
||||
makeSslContextAuthed(
|
||||
make_SSLContextAuthed(
|
||||
std::string const& keyFile,
|
||||
std::string const& certFile,
|
||||
std::string const& chainFile,
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
#include <optional>
|
||||
|
||||
namespace xrpl {
|
||||
constexpr auto kMuldivMax = std::numeric_limits<std::uint64_t>::max();
|
||||
auto constexpr muldiv_max = std::numeric_limits<std::uint64_t>::max();
|
||||
|
||||
/** Return value*mul/div accurately.
|
||||
Computes the result of the multiplication and division in
|
||||
|
||||
@@ -24,7 +24,7 @@ template <>
|
||||
inline std::size_t
|
||||
extract(std::string const& key)
|
||||
{
|
||||
return ::beast::Uhash<>{}(key);
|
||||
return ::beast::uhash<>{}(key);
|
||||
}
|
||||
|
||||
template <
|
||||
@@ -33,7 +33,7 @@ template <
|
||||
typename Hash,
|
||||
typename Pred = std::equal_to<Key>,
|
||||
typename Alloc = std::allocator<std::pair<Key const, Value>>>
|
||||
class PartitionedUnorderedMap
|
||||
class partitioned_unordered_map
|
||||
{
|
||||
std::size_t partitions_;
|
||||
|
||||
@@ -53,46 +53,46 @@ public:
|
||||
using map_type = std::unordered_map<key_type, mapped_type, hasher, key_equal, allocator_type>;
|
||||
using partition_map_type = std::vector<map_type>;
|
||||
|
||||
struct Iterator
|
||||
struct iterator
|
||||
{
|
||||
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* map_{nullptr};
|
||||
typename partition_map_type::iterator ait_{};
|
||||
typename map_type::iterator mit_;
|
||||
|
||||
Iterator() = default;
|
||||
iterator() = default;
|
||||
|
||||
Iterator(partition_map_type* m) : map(m)
|
||||
iterator(partition_map_type* map) : map_(map)
|
||||
{
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return *mit;
|
||||
return *mit_;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &(*mit);
|
||||
return &(*mit_);
|
||||
}
|
||||
|
||||
void
|
||||
inc()
|
||||
{
|
||||
++mit;
|
||||
while (mit == ait->end())
|
||||
++mit_;
|
||||
while (mit_ == ait_->end())
|
||||
{
|
||||
++ait;
|
||||
if (ait == map->end())
|
||||
++ait_;
|
||||
if (ait_ == map_->end())
|
||||
return;
|
||||
mit = ait->begin();
|
||||
mit_ = ait_->begin();
|
||||
}
|
||||
}
|
||||
|
||||
// ++it
|
||||
Iterator&
|
||||
iterator&
|
||||
operator++()
|
||||
{
|
||||
inc();
|
||||
@@ -100,75 +100,75 @@ public:
|
||||
}
|
||||
|
||||
// it++
|
||||
Iterator
|
||||
iterator
|
||||
operator++(int)
|
||||
{
|
||||
Iterator tmp(*this);
|
||||
iterator tmp(*this);
|
||||
inc();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(Iterator const& lhs, Iterator const& rhs)
|
||||
operator==(iterator const& lhs, iterator const& rhs)
|
||||
{
|
||||
return lhs.map == rhs.map && lhs.ait == rhs.ait && lhs.mit == rhs.mit;
|
||||
return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && lhs.mit_ == rhs.mit_;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(Iterator const& lhs, Iterator const& rhs)
|
||||
operator!=(iterator const& lhs, iterator const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
};
|
||||
|
||||
struct ConstIterator
|
||||
struct const_iterator
|
||||
{
|
||||
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* map_{nullptr};
|
||||
typename partition_map_type::iterator ait_{};
|
||||
typename map_type::iterator mit_;
|
||||
|
||||
ConstIterator() = default;
|
||||
const_iterator() = default;
|
||||
|
||||
ConstIterator(partition_map_type* m) : map(m)
|
||||
const_iterator(partition_map_type* map) : map_(map)
|
||||
{
|
||||
}
|
||||
|
||||
ConstIterator(Iterator const& orig)
|
||||
const_iterator(iterator const& orig)
|
||||
{
|
||||
map = orig.map;
|
||||
ait = orig.ait;
|
||||
mit = orig.mit;
|
||||
map_ = orig.map_;
|
||||
ait_ = orig.ait_;
|
||||
mit_ = orig.mit_;
|
||||
}
|
||||
|
||||
const_reference
|
||||
operator*() const
|
||||
{
|
||||
return *mit;
|
||||
return *mit_;
|
||||
}
|
||||
|
||||
const_pointer
|
||||
operator->() const
|
||||
{
|
||||
return &(*mit);
|
||||
return &(*mit_);
|
||||
}
|
||||
|
||||
void
|
||||
inc()
|
||||
{
|
||||
++mit;
|
||||
while (mit == ait->end())
|
||||
++mit_;
|
||||
while (mit_ == ait_->end())
|
||||
{
|
||||
++ait;
|
||||
if (ait == map->end())
|
||||
++ait_;
|
||||
if (ait_ == map_->end())
|
||||
return;
|
||||
mit = ait->begin();
|
||||
mit_ = ait_->begin();
|
||||
}
|
||||
}
|
||||
|
||||
// ++it
|
||||
ConstIterator&
|
||||
const_iterator&
|
||||
operator++()
|
||||
{
|
||||
inc();
|
||||
@@ -176,22 +176,22 @@ public:
|
||||
}
|
||||
|
||||
// it++
|
||||
ConstIterator
|
||||
const_iterator
|
||||
operator++(int)
|
||||
{
|
||||
ConstIterator tmp(*this);
|
||||
const_iterator tmp(*this);
|
||||
inc();
|
||||
return tmp;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator==(ConstIterator const& lhs, ConstIterator const& rhs)
|
||||
operator==(const_iterator const& lhs, const_iterator const& rhs)
|
||||
{
|
||||
return lhs.map == rhs.map && lhs.ait == rhs.ait && lhs.mit == rhs.mit;
|
||||
return lhs.map_ == rhs.map_ && lhs.ait_ == rhs.ait_ && lhs.mit_ == rhs.mit_;
|
||||
}
|
||||
|
||||
friend bool
|
||||
operator!=(ConstIterator const& lhs, ConstIterator const& rhs)
|
||||
operator!=(const_iterator const& lhs, const_iterator const& rhs)
|
||||
{
|
||||
return !(lhs == rhs);
|
||||
}
|
||||
@@ -208,26 +208,26 @@ private:
|
||||
static void
|
||||
end(T& it)
|
||||
{
|
||||
it.ait = it.map->end();
|
||||
it.mit = it.map->back().end();
|
||||
it.ait_ = it.map_->end();
|
||||
it.mit_ = it.map_->back().end();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static void
|
||||
begin(T& it)
|
||||
{
|
||||
for (it.ait = it.map->begin(); it.ait != it.map->end(); ++it.ait)
|
||||
for (it.ait_ = it.map_->begin(); it.ait_ != it.map_->end(); ++it.ait_)
|
||||
{
|
||||
if (it.ait->begin() == it.ait->end())
|
||||
if (it.ait_->begin() == it.ait_->end())
|
||||
continue;
|
||||
it.mit = it.ait->begin();
|
||||
it.mit_ = it.ait_->begin();
|
||||
return;
|
||||
}
|
||||
end(it);
|
||||
}
|
||||
|
||||
public:
|
||||
PartitionedUnorderedMap(std::optional<std::size_t> partitions = std::nullopt)
|
||||
partitioned_unordered_map(std::optional<std::size_t> partitions = std::nullopt)
|
||||
{
|
||||
// Set partitions to the number of hardware threads if the parameter
|
||||
// is either empty or set to 0.
|
||||
@@ -236,7 +236,7 @@ public:
|
||||
map_.resize(partitions_);
|
||||
XRPL_ASSERT(
|
||||
partitions_,
|
||||
"xrpl::PartitionedUnorderedMap::PartitionedUnorderedMap : "
|
||||
"xrpl::partitioned_unordered_map::partitioned_unordered_map : "
|
||||
"nonzero partitions");
|
||||
}
|
||||
|
||||
@@ -252,45 +252,45 @@ public:
|
||||
return map_;
|
||||
}
|
||||
|
||||
Iterator
|
||||
iterator
|
||||
begin()
|
||||
{
|
||||
Iterator it(&map_);
|
||||
iterator it(&map_);
|
||||
begin(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
ConstIterator
|
||||
const_iterator
|
||||
cbegin() const
|
||||
{
|
||||
ConstIterator it(&map_);
|
||||
const_iterator it(&map_);
|
||||
begin(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
ConstIterator
|
||||
const_iterator
|
||||
begin() const
|
||||
{
|
||||
return cbegin();
|
||||
}
|
||||
|
||||
Iterator
|
||||
iterator
|
||||
end()
|
||||
{
|
||||
Iterator it(&map_);
|
||||
iterator it(&map_);
|
||||
end(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
ConstIterator
|
||||
const_iterator
|
||||
cend() const
|
||||
{
|
||||
ConstIterator it(&map_);
|
||||
const_iterator it(&map_);
|
||||
end(it);
|
||||
return it;
|
||||
}
|
||||
|
||||
ConstIterator
|
||||
const_iterator
|
||||
end() const
|
||||
{
|
||||
return cend();
|
||||
@@ -301,50 +301,50 @@ private:
|
||||
void
|
||||
find(key_type const& key, T& it) const
|
||||
{
|
||||
it.ait = it.map->begin() + partitioner(key);
|
||||
it.mit = it.ait->find(key);
|
||||
if (it.mit == it.ait->end())
|
||||
it.ait_ = it.map_->begin() + partitioner(key);
|
||||
it.mit_ = it.ait_->find(key);
|
||||
if (it.mit_ == it.ait_->end())
|
||||
end(it);
|
||||
}
|
||||
|
||||
public:
|
||||
Iterator
|
||||
iterator
|
||||
find(key_type const& key)
|
||||
{
|
||||
Iterator it(&map_);
|
||||
iterator it(&map_);
|
||||
find(key, it);
|
||||
return it;
|
||||
}
|
||||
|
||||
ConstIterator
|
||||
const_iterator
|
||||
find(key_type const& key) const
|
||||
{
|
||||
ConstIterator it(&map_);
|
||||
const_iterator it(&map_);
|
||||
find(key, it);
|
||||
return it;
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
std::pair<Iterator, bool>
|
||||
std::pair<iterator, bool>
|
||||
emplace(std::piecewise_construct_t const&, T&& keyTuple, U&& valueTuple)
|
||||
{
|
||||
auto const& key = std::get<0>(keyTuple);
|
||||
Iterator it(&map_);
|
||||
it.ait = it.map->begin() + partitioner(key);
|
||||
auto [eit, inserted] = it.ait->emplace(
|
||||
iterator it(&map_);
|
||||
it.ait_ = it.map_->begin() + partitioner(key);
|
||||
auto [eit, inserted] = it.ait_->emplace(
|
||||
std::piecewise_construct, std::forward<T>(keyTuple), std::forward<U>(valueTuple));
|
||||
it.mit = eit;
|
||||
it.mit_ = eit;
|
||||
return {it, inserted};
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
std::pair<Iterator, bool>
|
||||
std::pair<iterator, bool>
|
||||
emplace(T&& key, U&& val)
|
||||
{
|
||||
Iterator it(&map_);
|
||||
it.ait = it.map->begin() + partitioner(key);
|
||||
auto [eit, inserted] = it.ait->emplace(std::forward<T>(key), std::forward<U>(val));
|
||||
it.mit = eit;
|
||||
iterator it(&map_);
|
||||
it.ait_ = it.map_->begin() + partitioner(key);
|
||||
auto [eit, inserted] = it.ait_->emplace(std::forward<T>(key), std::forward<U>(val));
|
||||
it.mit_ = eit;
|
||||
return {it, inserted};
|
||||
}
|
||||
|
||||
@@ -355,19 +355,19 @@ public:
|
||||
p.clear();
|
||||
}
|
||||
|
||||
Iterator
|
||||
erase(ConstIterator position)
|
||||
iterator
|
||||
erase(const_iterator position)
|
||||
{
|
||||
Iterator it(&map_);
|
||||
it.ait = position.ait;
|
||||
it.mit = position.ait->erase(position.mit);
|
||||
iterator it(&map_);
|
||||
it.ait_ = position.ait_;
|
||||
it.mit_ = position.ait_->erase(position.mit_);
|
||||
|
||||
while (it.mit == it.ait->end())
|
||||
while (it.mit_ == it.ait_->end())
|
||||
{
|
||||
++it.ait;
|
||||
if (it.ait == it.map->end())
|
||||
++it.ait_;
|
||||
if (it.ait_ == it.map_->end())
|
||||
break;
|
||||
it.mit = it.ait->begin();
|
||||
it.mit_ = it.ait_->begin();
|
||||
}
|
||||
|
||||
return it;
|
||||
|
||||
@@ -44,30 +44,30 @@ using is_engine = std::is_invocable_r<Result, Engine>;
|
||||
will be randomly seeded.
|
||||
*/
|
||||
inline beast::xor_shift_engine&
|
||||
defaultPrng()
|
||||
default_prng()
|
||||
{
|
||||
// This is used to seed the thread-specific PRNGs on demand
|
||||
static beast::xor_shift_engine kSeeder = [] {
|
||||
static beast::xor_shift_engine seeder = [] {
|
||||
std::random_device rng;
|
||||
std::uniform_int_distribution<std::uint64_t> distribution{1};
|
||||
return beast::xor_shift_engine(distribution(rng));
|
||||
}();
|
||||
|
||||
// This protects the seeder
|
||||
static std::mutex kM;
|
||||
static std::mutex m;
|
||||
|
||||
// The thread-specific PRNGs:
|
||||
thread_local beast::xor_shift_engine kEngine = [] {
|
||||
thread_local beast::xor_shift_engine engine = [] {
|
||||
std::uint64_t seed = 0;
|
||||
{
|
||||
std::scoped_lock const lk(kM);
|
||||
std::scoped_lock const lk(m);
|
||||
std::uniform_int_distribution<std::uint64_t> distribution{1};
|
||||
seed = distribution(kSeeder);
|
||||
seed = distribution(seeder);
|
||||
}
|
||||
return beast::xor_shift_engine{seed};
|
||||
}();
|
||||
|
||||
return kEngine;
|
||||
return engine;
|
||||
}
|
||||
|
||||
/** Return a uniformly distributed random integer.
|
||||
@@ -92,9 +92,9 @@ defaultPrng()
|
||||
/** @{ */
|
||||
template <class Engine, class Integral>
|
||||
std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
|
||||
randInt(Engine& engine, Integral min, Integral max)
|
||||
rand_int(Engine& engine, Integral min, Integral max)
|
||||
{
|
||||
XRPL_ASSERT(max > min, "xrpl::randInt : max over min inputs");
|
||||
XRPL_ASSERT(max > min, "xrpl::rand_int : max over min inputs");
|
||||
|
||||
// This should have no state and constructing it should
|
||||
// be very cheap. If that turns out not to be the case
|
||||
@@ -104,37 +104,37 @@ randInt(Engine& engine, Integral min, Integral max)
|
||||
|
||||
template <class Integral>
|
||||
std::enable_if_t<std::is_integral_v<Integral>, Integral>
|
||||
randInt(Integral min, Integral max)
|
||||
rand_int(Integral min, Integral max)
|
||||
{
|
||||
return randInt(defaultPrng(), min, max);
|
||||
return rand_int(default_prng(), min, max);
|
||||
}
|
||||
|
||||
template <class Engine, class Integral>
|
||||
std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
|
||||
randInt(Engine& engine, Integral max)
|
||||
rand_int(Engine& engine, Integral max)
|
||||
{
|
||||
return randInt(engine, Integral(0), max);
|
||||
return rand_int(engine, Integral(0), max);
|
||||
}
|
||||
|
||||
template <class Integral>
|
||||
std::enable_if_t<std::is_integral_v<Integral>, Integral>
|
||||
randInt(Integral max)
|
||||
rand_int(Integral max)
|
||||
{
|
||||
return randInt(defaultPrng(), max);
|
||||
return rand_int(default_prng(), max);
|
||||
}
|
||||
|
||||
template <class Integral, class Engine>
|
||||
std::enable_if_t<std::is_integral_v<Integral> && detail::is_engine<Engine>::value, Integral>
|
||||
randInt(Engine& engine)
|
||||
rand_int(Engine& engine)
|
||||
{
|
||||
return randInt(engine, std::numeric_limits<Integral>::max());
|
||||
return rand_int(engine, std::numeric_limits<Integral>::max());
|
||||
}
|
||||
|
||||
template <class Integral = int>
|
||||
std::enable_if_t<std::is_integral_v<Integral>, Integral>
|
||||
randInt()
|
||||
rand_int()
|
||||
{
|
||||
return randInt(defaultPrng(), std::numeric_limits<Integral>::max());
|
||||
return rand_int(default_prng(), std::numeric_limits<Integral>::max());
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@@ -145,17 +145,17 @@ 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>
|
||||
randByte(Engine& engine)
|
||||
rand_byte(Engine& engine)
|
||||
{
|
||||
return static_cast<Byte>(randInt<Engine, std::uint32_t>(
|
||||
return static_cast<Byte>(rand_int<Engine, std::uint32_t>(
|
||||
engine, std::numeric_limits<Byte>::min(), std::numeric_limits<Byte>::max()));
|
||||
}
|
||||
|
||||
template <class Byte = std::uint8_t>
|
||||
std::enable_if_t<(std::is_same_v<Byte, unsigned char> || std::is_same_v<Byte, std::uint8_t>), Byte>
|
||||
randByte()
|
||||
rand_byte()
|
||||
{
|
||||
return randByte<Byte>(defaultPrng());
|
||||
return rand_byte<Byte>(default_prng());
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@@ -163,15 +163,15 @@ randByte()
|
||||
/** @{ */
|
||||
template <class Engine>
|
||||
inline bool
|
||||
randBool(Engine& engine)
|
||||
rand_bool(Engine& engine)
|
||||
{
|
||||
return randInt(engine, 1) == 1;
|
||||
return rand_int(engine, 1) == 1;
|
||||
}
|
||||
|
||||
inline bool
|
||||
randBool()
|
||||
rand_bool()
|
||||
{
|
||||
return randBool(defaultPrng());
|
||||
return rand_bool(default_prng());
|
||||
}
|
||||
/** @} */
|
||||
|
||||
|
||||
@@ -18,29 +18,29 @@ concept SafeToCast = (std::is_integral_v<Src> && std::is_integral_v<Dest>) &&
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
safeCast(Src s) noexcept
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
static_assert(
|
||||
std::is_signed_v<Dest> || std::is_unsigned_v<Src>, "Cannot cast signed to unsigned");
|
||||
constexpr unsigned kNotSame = std::is_signed_v<Dest> != std::is_signed_v<Src>;
|
||||
constexpr unsigned not_same = std::is_signed_v<Dest> != std::is_signed_v<Src>;
|
||||
static_assert(
|
||||
sizeof(Dest) >= sizeof(Src) + kNotSame,
|
||||
sizeof(Dest) >= sizeof(Src) + not_same,
|
||||
"Destination is too small to hold all values of source");
|
||||
return static_cast<Dest>(s);
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<std::is_enum_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
safeCast(Src s) noexcept
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
return static_cast<Dest>(safeCast<std::underlying_type_t<Dest>>(s));
|
||||
return static_cast<Dest>(safe_cast<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>
|
||||
safeCast(Src s) noexcept
|
||||
safe_cast(Src s) noexcept
|
||||
{
|
||||
return safeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
return safe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
}
|
||||
|
||||
// unsafe_cast explicitly flags a static_cast as not necessarily able to hold
|
||||
@@ -49,7 +49,7 @@ safeCast(Src s) noexcept
|
||||
|
||||
template <class Dest, class Src>
|
||||
constexpr std::enable_if_t<std::is_integral_v<Dest> && std::is_integral_v<Src>, Dest>
|
||||
unsafeCast(Src s) noexcept
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
static_assert(
|
||||
!SafeToCast<Src, Dest>,
|
||||
@@ -60,28 +60,28 @@ 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>
|
||||
unsafeCast(Src s) noexcept
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
return static_cast<Dest>(unsafeCast<std::underlying_type_t<Dest>>(s));
|
||||
return static_cast<Dest>(unsafe_cast<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>
|
||||
unsafeCast(Src s) noexcept
|
||||
unsafe_cast(Src s) noexcept
|
||||
{
|
||||
return unsafeCast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
return unsafe_cast<Dest>(static_cast<std::underlying_type_t<Src>>(s));
|
||||
}
|
||||
|
||||
template <class Dest, class Src>
|
||||
requires std::is_pointer_v<Dest>
|
||||
inline Dest
|
||||
safeDowncast(Src* s) noexcept
|
||||
safe_downcast(Src* s) noexcept
|
||||
{
|
||||
#ifdef NDEBUG
|
||||
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
#else
|
||||
auto* result = dynamic_cast<Dest>(s);
|
||||
XRPL_ASSERT(result != nullptr, "xrpl::safeDowncast : pointer downcast is valid");
|
||||
XRPL_ASSERT(result != nullptr, "xrpl::safe_downcast : pointer downcast is valid");
|
||||
return result;
|
||||
#endif
|
||||
}
|
||||
@@ -89,12 +89,12 @@ safeDowncast(Src* s) noexcept
|
||||
template <class Dest, class Src>
|
||||
requires std::is_lvalue_reference_v<Dest>
|
||||
inline Dest
|
||||
safeDowncast(Src& s) noexcept
|
||||
safe_downcast(Src& s) noexcept
|
||||
{
|
||||
#ifndef NDEBUG
|
||||
XRPL_ASSERT(
|
||||
dynamic_cast<std::add_pointer_t<std::remove_reference_t<Dest>>>(&s) != nullptr,
|
||||
"xrpl::safeDowncast : reference downcast is valid");
|
||||
"xrpl::safe_downcast : reference downcast is valid");
|
||||
#endif
|
||||
return static_cast<Dest>(s); // NOLINT(cppcoreguidelines-pro-type-static-cast-downcast)
|
||||
}
|
||||
|
||||
@@ -22,36 +22,36 @@ namespace xrpl {
|
||||
// to enforce this restriction.
|
||||
|
||||
template <class EF>
|
||||
class ScopeExit
|
||||
class scope_exit
|
||||
{
|
||||
EF exitFunction_;
|
||||
bool executeOnDestruction_{true};
|
||||
EF exit_function_;
|
||||
bool execute_on_destruction_{true};
|
||||
|
||||
public:
|
||||
~ScopeExit()
|
||||
~scope_exit()
|
||||
{
|
||||
if (executeOnDestruction_)
|
||||
exitFunction_();
|
||||
if (execute_on_destruction_)
|
||||
exit_function_();
|
||||
}
|
||||
|
||||
ScopeExit(ScopeExit&& rhs) noexcept(
|
||||
scope_exit(scope_exit&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exitFunction_{std::forward<EF>(rhs.exitFunction_)}
|
||||
, executeOnDestruction_{rhs.executeOnDestruction_}
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
{
|
||||
rhs.release();
|
||||
}
|
||||
|
||||
ScopeExit&
|
||||
operator=(ScopeExit&&) = delete;
|
||||
scope_exit&
|
||||
operator=(scope_exit&&) = delete;
|
||||
|
||||
template <class EFP>
|
||||
explicit ScopeExit(
|
||||
explicit scope_exit(
|
||||
EFP&& f,
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, ScopeExit> &&
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_exit> &&
|
||||
std::is_constructible_v<EF, EFP>>* = 0) noexcept
|
||||
: exitFunction_{std::forward<EFP>(f)}
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
|
||||
}
|
||||
@@ -59,46 +59,46 @@ public:
|
||||
void
|
||||
release() noexcept
|
||||
{
|
||||
executeOnDestruction_ = false;
|
||||
execute_on_destruction_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class EF>
|
||||
ScopeExit(EF) -> ScopeExit<EF>;
|
||||
scope_exit(EF) -> scope_exit<EF>;
|
||||
|
||||
template <class EF>
|
||||
class ScopeFail
|
||||
class scope_fail
|
||||
{
|
||||
EF exitFunction_;
|
||||
bool executeOnDestruction_{true};
|
||||
int uncaughtOnCreation_{std::uncaught_exceptions()};
|
||||
EF exit_function_;
|
||||
bool execute_on_destruction_{true};
|
||||
int uncaught_on_creation_{std::uncaught_exceptions()};
|
||||
|
||||
public:
|
||||
~ScopeFail()
|
||||
~scope_fail()
|
||||
{
|
||||
if (executeOnDestruction_ && std::uncaught_exceptions() > uncaughtOnCreation_)
|
||||
exitFunction_();
|
||||
if (execute_on_destruction_ && std::uncaught_exceptions() > uncaught_on_creation_)
|
||||
exit_function_();
|
||||
}
|
||||
|
||||
ScopeFail(ScopeFail&& rhs) noexcept(
|
||||
scope_fail(scope_fail&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exitFunction_{std::forward<EF>(rhs.exitFunction_)}
|
||||
, executeOnDestruction_{rhs.executeOnDestruction_}
|
||||
, uncaughtOnCreation_{rhs.uncaughtOnCreation_}
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
, uncaught_on_creation_{rhs.uncaught_on_creation_}
|
||||
{
|
||||
rhs.release();
|
||||
}
|
||||
|
||||
ScopeFail&
|
||||
operator=(ScopeFail&&) = delete;
|
||||
scope_fail&
|
||||
operator=(scope_fail&&) = delete;
|
||||
|
||||
template <class EFP>
|
||||
explicit ScopeFail(
|
||||
explicit scope_fail(
|
||||
EFP&& f,
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, ScopeFail> &&
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_fail> &&
|
||||
std::is_constructible_v<EF, EFP>>* = 0) noexcept
|
||||
: exitFunction_{std::forward<EFP>(f)}
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
static_assert(std::is_nothrow_constructible_v<EF, decltype(std::forward<EFP>(f))>);
|
||||
}
|
||||
@@ -106,59 +106,59 @@ public:
|
||||
void
|
||||
release() noexcept
|
||||
{
|
||||
executeOnDestruction_ = false;
|
||||
execute_on_destruction_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class EF>
|
||||
ScopeFail(EF) -> ScopeFail<EF>;
|
||||
scope_fail(EF) -> scope_fail<EF>;
|
||||
|
||||
template <class EF>
|
||||
class ScopeSuccess
|
||||
class scope_success
|
||||
{
|
||||
EF exitFunction_;
|
||||
bool executeOnDestruction_{true};
|
||||
int uncaughtOnCreation_{std::uncaught_exceptions()};
|
||||
EF exit_function_;
|
||||
bool execute_on_destruction_{true};
|
||||
int uncaught_on_creation_{std::uncaught_exceptions()};
|
||||
|
||||
public:
|
||||
~ScopeSuccess() noexcept(noexcept(exitFunction_()))
|
||||
~scope_success() noexcept(noexcept(exit_function_()))
|
||||
{
|
||||
if (executeOnDestruction_ && std::uncaught_exceptions() <= uncaughtOnCreation_)
|
||||
exitFunction_();
|
||||
if (execute_on_destruction_ && std::uncaught_exceptions() <= uncaught_on_creation_)
|
||||
exit_function_();
|
||||
}
|
||||
|
||||
ScopeSuccess(ScopeSuccess&& rhs) noexcept(
|
||||
scope_success(scope_success&& rhs) noexcept(
|
||||
std::is_nothrow_move_constructible_v<EF> || std::is_nothrow_copy_constructible_v<EF>)
|
||||
: exitFunction_{std::forward<EF>(rhs.exitFunction_)}
|
||||
, executeOnDestruction_{rhs.executeOnDestruction_}
|
||||
, uncaughtOnCreation_{rhs.uncaughtOnCreation_}
|
||||
: exit_function_{std::forward<EF>(rhs.exit_function_)}
|
||||
, execute_on_destruction_{rhs.execute_on_destruction_}
|
||||
, uncaught_on_creation_{rhs.uncaught_on_creation_}
|
||||
{
|
||||
rhs.release();
|
||||
}
|
||||
|
||||
ScopeSuccess&
|
||||
operator=(ScopeSuccess&&) = delete;
|
||||
scope_success&
|
||||
operator=(scope_success&&) = delete;
|
||||
|
||||
template <class EFP>
|
||||
explicit ScopeSuccess(
|
||||
explicit scope_success(
|
||||
EFP&& f,
|
||||
std::enable_if_t<
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, ScopeSuccess> &&
|
||||
!std::is_same_v<std::remove_cv_t<EFP>, scope_success> &&
|
||||
std::is_constructible_v<EF, EFP>>* =
|
||||
0) noexcept(std::is_nothrow_constructible_v<EF, EFP> || std::is_nothrow_constructible_v<EF, EFP&>)
|
||||
: exitFunction_{std::forward<EFP>(f)}
|
||||
: exit_function_{std::forward<EFP>(f)}
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
release() noexcept
|
||||
{
|
||||
executeOnDestruction_ = false;
|
||||
execute_on_destruction_ = false;
|
||||
}
|
||||
};
|
||||
|
||||
template <class EF>
|
||||
ScopeSuccess(EF) -> ScopeSuccess<EF>;
|
||||
scope_success(EF) -> scope_success<EF>;
|
||||
|
||||
/**
|
||||
Automatically unlocks and re-locks a unique_lock object.
|
||||
@@ -198,29 +198,29 @@ ScopeSuccess(EF) -> ScopeSuccess<EF>;
|
||||
*/
|
||||
|
||||
template <class Mutex>
|
||||
class ScopeUnlock
|
||||
class scope_unlock
|
||||
{
|
||||
std::unique_lock<Mutex>* plock_;
|
||||
std::unique_lock<Mutex>* plock;
|
||||
|
||||
public:
|
||||
explicit ScopeUnlock(std::unique_lock<Mutex>& lock) noexcept(true) : plock_(&lock)
|
||||
explicit scope_unlock(std::unique_lock<Mutex>& lock) noexcept(true) : plock(&lock)
|
||||
{
|
||||
XRPL_ASSERT(plock_->owns_lock(), "xrpl::ScopeUnlock::ScopeUnlock : mutex must be locked");
|
||||
plock_->unlock();
|
||||
XRPL_ASSERT(plock->owns_lock(), "xrpl::scope_unlock::scope_unlock : mutex must be locked");
|
||||
plock->unlock();
|
||||
}
|
||||
|
||||
// Immovable type
|
||||
ScopeUnlock(ScopeUnlock const&) = delete;
|
||||
ScopeUnlock&
|
||||
operator=(ScopeUnlock const&) = delete;
|
||||
scope_unlock(scope_unlock const&) = delete;
|
||||
scope_unlock&
|
||||
operator=(scope_unlock const&) = delete;
|
||||
|
||||
~ScopeUnlock() noexcept(true)
|
||||
~scope_unlock() noexcept(true)
|
||||
{
|
||||
plock_->lock();
|
||||
plock->lock();
|
||||
}
|
||||
};
|
||||
|
||||
template <class Mutex>
|
||||
ScopeUnlock(std::unique_lock<Mutex>&) -> ScopeUnlock<Mutex>;
|
||||
scope_unlock(std::unique_lock<Mutex>&) -> scope_unlock<Mutex>;
|
||||
|
||||
} // namespace xrpl
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace detail {
|
||||
specific amount of time, to prevent this.
|
||||
*/
|
||||
inline void
|
||||
spinPause() noexcept
|
||||
spin_pause() noexcept
|
||||
{
|
||||
#ifdef __aarch64__
|
||||
asm volatile("yield");
|
||||
@@ -71,7 +71,7 @@ spinPause() noexcept
|
||||
https://en.cppreference.com/w/cpp/named_req/Lockable
|
||||
*/
|
||||
template <class T>
|
||||
class PackedSpinlock
|
||||
class packed_spinlock
|
||||
{
|
||||
// clang-format off
|
||||
static_assert(std::is_unsigned_v<T>);
|
||||
@@ -87,9 +87,9 @@ private:
|
||||
T const mask_;
|
||||
|
||||
public:
|
||||
PackedSpinlock(PackedSpinlock const&) = delete;
|
||||
PackedSpinlock&
|
||||
operator=(PackedSpinlock const&) = delete;
|
||||
packed_spinlock(packed_spinlock const&) = delete;
|
||||
packed_spinlock&
|
||||
operator=(packed_spinlock const&) = delete;
|
||||
|
||||
/** A single spinlock packed inside the specified atomic
|
||||
|
||||
@@ -99,15 +99,16 @@ public:
|
||||
@note For performance reasons, you should strive to have `lock` be
|
||||
on a cacheline by itself.
|
||||
*/
|
||||
PackedSpinlock(std::atomic<T>& lock, int index) : bits_(lock), mask_(static_cast<T>(1) << index)
|
||||
packed_spinlock(std::atomic<T>& lock, int index)
|
||||
: bits_(lock), mask_(static_cast<T>(1) << index)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
index >= 0 && (mask_ != 0),
|
||||
"xrpl::PackedSpinlock::PackedSpinlock : valid index and mask");
|
||||
"xrpl::packed_spinlock::packed_spinlock : valid index and mask");
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
try_lock() // NOLINT(readability-identifier-naming)
|
||||
try_lock()
|
||||
{
|
||||
return (bits_.fetch_or(mask_, std::memory_order_acquire) & mask_) == 0;
|
||||
}
|
||||
@@ -122,7 +123,7 @@ public:
|
||||
// of contention by avoiding writes that would definitely not
|
||||
// result in the lock being acquired.
|
||||
while ((bits_.load(std::memory_order_relaxed) & mask_) != 0)
|
||||
detail::spinPause();
|
||||
detail::spin_pause();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,7 +147,7 @@ public:
|
||||
https://en.cppreference.com/w/cpp/named_req/Lockable
|
||||
*/
|
||||
template <class T>
|
||||
class Spinlock
|
||||
class spinlock
|
||||
{
|
||||
static_assert(std::is_unsigned_v<T>);
|
||||
static_assert(std::atomic<T>::is_always_lock_free);
|
||||
@@ -155,9 +156,9 @@ private:
|
||||
std::atomic<T>& lock_;
|
||||
|
||||
public:
|
||||
Spinlock(Spinlock const&) = delete;
|
||||
Spinlock&
|
||||
operator=(Spinlock const&) = delete;
|
||||
spinlock(spinlock const&) = delete;
|
||||
spinlock&
|
||||
operator=(spinlock const&) = delete;
|
||||
|
||||
/** Grabs the
|
||||
|
||||
@@ -166,12 +167,12 @@ public:
|
||||
@note For performance reasons, you should strive to have `lock` be
|
||||
on a cacheline by itself.
|
||||
*/
|
||||
Spinlock(std::atomic<T>& lock) : lock_(lock)
|
||||
spinlock(std::atomic<T>& lock) : lock_(lock)
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] bool
|
||||
try_lock() // NOLINT(readability-identifier-naming)
|
||||
try_lock()
|
||||
{
|
||||
T expected = 0;
|
||||
|
||||
@@ -192,7 +193,7 @@ public:
|
||||
// of contention by avoiding writes that would definitely not
|
||||
// result in the lock being acquired.
|
||||
while (lock_.load(std::memory_order_relaxed) != 0)
|
||||
detail::spinPause();
|
||||
detail::spin_pause();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,171 +23,171 @@ namespace xrpl {
|
||||
allowed arithmetic operations.
|
||||
*/
|
||||
template <class Int, class Tag>
|
||||
class TaggedInteger : boost::totally_ordered<
|
||||
TaggedInteger<Int, Tag>,
|
||||
boost::integer_arithmetic<
|
||||
TaggedInteger<Int, Tag>,
|
||||
boost::bitwise<
|
||||
TaggedInteger<Int, Tag>,
|
||||
boost::unit_steppable<
|
||||
TaggedInteger<Int, Tag>,
|
||||
boost::shiftable<TaggedInteger<Int, Tag>>>>>>
|
||||
class tagged_integer : boost::totally_ordered<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::integer_arithmetic<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::bitwise<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::unit_steppable<
|
||||
tagged_integer<Int, Tag>,
|
||||
boost::shiftable<tagged_integer<Int, Tag>>>>>>
|
||||
{
|
||||
private:
|
||||
Int value_;
|
||||
Int m_value;
|
||||
|
||||
public:
|
||||
using value_type = Int;
|
||||
using tag_type = Tag;
|
||||
|
||||
TaggedInteger() = default;
|
||||
tagged_integer() = 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)
|
||||
explicit constexpr tagged_integer(OtherInt value) noexcept : m_value(value)
|
||||
{
|
||||
static_assert(sizeof(TaggedInteger) == sizeof(Int), "tagged_integer is adding padding");
|
||||
static_assert(sizeof(tagged_integer) == sizeof(Int), "tagged_integer is adding padding");
|
||||
}
|
||||
|
||||
bool
|
||||
operator<(TaggedInteger const& rhs) const noexcept
|
||||
operator<(tagged_integer const& rhs) const noexcept
|
||||
{
|
||||
return value_ < rhs.value_;
|
||||
return m_value < rhs.m_value;
|
||||
}
|
||||
|
||||
bool
|
||||
operator==(TaggedInteger const& rhs) const noexcept
|
||||
operator==(tagged_integer const& rhs) const noexcept
|
||||
{
|
||||
return value_ == rhs.value_;
|
||||
return m_value == rhs.m_value;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator+=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator+=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ += rhs.value_;
|
||||
m_value += rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator-=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator-=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ -= rhs.value_;
|
||||
m_value -= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator*=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator*=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ *= rhs.value_;
|
||||
m_value *= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator/=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator/=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ /= rhs.value_;
|
||||
m_value /= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator%=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator%=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ %= rhs.value_;
|
||||
m_value %= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator|=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator|=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ |= rhs.value_;
|
||||
m_value |= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator&=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator&=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ &= rhs.value_;
|
||||
m_value &= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator^=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator^=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ ^= rhs.value_;
|
||||
m_value ^= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator<<=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator<<=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ <<= rhs.value_;
|
||||
m_value <<= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
operator>>=(TaggedInteger const& rhs) noexcept
|
||||
tagged_integer&
|
||||
operator>>=(tagged_integer const& rhs) noexcept
|
||||
{
|
||||
value_ >>= rhs.value_;
|
||||
m_value >>= rhs.m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger
|
||||
tagged_integer
|
||||
operator~() const noexcept
|
||||
{
|
||||
return TaggedInteger{~value_};
|
||||
return tagged_integer{~m_value};
|
||||
}
|
||||
|
||||
TaggedInteger
|
||||
tagged_integer
|
||||
operator+() const noexcept
|
||||
{
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger
|
||||
tagged_integer
|
||||
operator-() const noexcept
|
||||
{
|
||||
return TaggedInteger{-value_};
|
||||
return tagged_integer{-m_value};
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
tagged_integer&
|
||||
operator++() noexcept
|
||||
{
|
||||
++value_;
|
||||
++m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
TaggedInteger&
|
||||
tagged_integer&
|
||||
operator--() noexcept
|
||||
{
|
||||
--value_;
|
||||
--m_value;
|
||||
return *this;
|
||||
}
|
||||
|
||||
explicit
|
||||
operator Int() const noexcept
|
||||
{
|
||||
return value_;
|
||||
return m_value;
|
||||
}
|
||||
|
||||
friend std::ostream&
|
||||
operator<<(std::ostream& s, TaggedInteger const& t)
|
||||
operator<<(std::ostream& s, tagged_integer const& t)
|
||||
{
|
||||
s << t.value_;
|
||||
s << t.m_value;
|
||||
return s;
|
||||
}
|
||||
|
||||
friend std::istream&
|
||||
operator>>(std::istream& s, TaggedInteger& t)
|
||||
operator>>(std::istream& s, tagged_integer& t)
|
||||
{
|
||||
s >> t.value_;
|
||||
s >> t.m_value;
|
||||
return s;
|
||||
}
|
||||
|
||||
friend std::string
|
||||
to_string(TaggedInteger const& t)
|
||||
to_string(tagged_integer const& t)
|
||||
{
|
||||
return std::to_string(t.value_);
|
||||
return std::to_string(t.m_value);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -195,10 +195,10 @@ public:
|
||||
|
||||
namespace beast {
|
||||
template <class Int, class Tag, class HashAlgorithm>
|
||||
struct IsContiguouslyHashable<xrpl::TaggedInteger<Int, Tag>, HashAlgorithm>
|
||||
: public IsContiguouslyHashable<Int, HashAlgorithm>
|
||||
struct is_contiguously_hashable<xrpl::tagged_integer<Int, Tag>, HashAlgorithm>
|
||||
: public is_contiguously_hashable<Int, HashAlgorithm>
|
||||
{
|
||||
explicit IsContiguouslyHashable() = default;
|
||||
explicit is_contiguously_hashable() = default;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -15,44 +15,44 @@ namespace beast {
|
||||
|
||||
/** Measures handler latency on an io_context queue. */
|
||||
template <class Clock>
|
||||
class IOLatencyProbe
|
||||
class io_latency_probe
|
||||
{
|
||||
private:
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
std::recursive_mutex mutex_;
|
||||
std::condition_variable_any cond_;
|
||||
std::size_t count_{1};
|
||||
duration const period_;
|
||||
boost::asio::io_context& ios_;
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> timer_;
|
||||
bool cancel_{false};
|
||||
std::recursive_mutex m_mutex;
|
||||
std::condition_variable_any m_cond;
|
||||
std::size_t m_count{1};
|
||||
duration const m_period;
|
||||
boost::asio::io_context& m_ios;
|
||||
boost::asio::basic_waitable_timer<std::chrono::steady_clock> m_timer;
|
||||
bool m_cancel{false};
|
||||
|
||||
public:
|
||||
IOLatencyProbe(duration const& period, boost::asio::io_context& ios)
|
||||
: period_(period), ios_(ios), timer_(ios_)
|
||||
io_latency_probe(duration const& period, boost::asio::io_context& ios)
|
||||
: m_period(period), m_ios(ios), m_timer(m_ios)
|
||||
{
|
||||
}
|
||||
|
||||
~IOLatencyProbe()
|
||||
~io_latency_probe()
|
||||
{
|
||||
std::unique_lock<decltype(mutex_)> lock(mutex_);
|
||||
std::unique_lock<decltype(m_mutex)> lock(m_mutex);
|
||||
cancel(lock, true);
|
||||
}
|
||||
|
||||
/** Return the io_context associated with the latency probe. */
|
||||
/** @{ */
|
||||
boost::asio::io_context&
|
||||
getIoContext()
|
||||
get_io_context()
|
||||
{
|
||||
return ios_;
|
||||
return m_ios;
|
||||
}
|
||||
|
||||
[[nodiscard]] boost::asio::io_context const&
|
||||
getIoContext() const
|
||||
get_io_context() const
|
||||
{
|
||||
return ios_;
|
||||
return m_ios;
|
||||
}
|
||||
/** @} */
|
||||
|
||||
@@ -63,14 +63,14 @@ public:
|
||||
void
|
||||
cancel()
|
||||
{
|
||||
std::unique_lock<decltype(mutex_)> lock(mutex_);
|
||||
std::unique_lock<decltype(m_mutex)> lock(m_mutex);
|
||||
cancel(lock, true);
|
||||
}
|
||||
|
||||
void
|
||||
cancelAsync()
|
||||
cancel_async()
|
||||
{
|
||||
std::unique_lock<decltype(mutex_)> lock(mutex_);
|
||||
std::unique_lock<decltype(m_mutex)> lock(m_mutex);
|
||||
cancel(lock, false);
|
||||
}
|
||||
/** @} */
|
||||
@@ -81,13 +81,13 @@ public:
|
||||
*/
|
||||
template <class Handler>
|
||||
void
|
||||
sampleOne(Handler&& handler)
|
||||
sample_one(Handler&& handler)
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
if (cancel_)
|
||||
throw std::logic_error("IOLatencyProbe is canceled");
|
||||
std::scoped_lock const lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
boost::asio::post(
|
||||
ios_, SampleOp<Handler>(std::forward<Handler>(handler), Clock::now(), false, this));
|
||||
m_ios, sample_op<Handler>(std::forward<Handler>(handler), Clock::now(), false, this));
|
||||
}
|
||||
|
||||
/** Initiate continuous i/o latency sampling.
|
||||
@@ -98,123 +98,125 @@ public:
|
||||
void
|
||||
sample(Handler&& handler)
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
if (cancel_)
|
||||
throw std::logic_error("IOLatencyProbe is canceled");
|
||||
std::scoped_lock const lock(m_mutex);
|
||||
if (m_cancel)
|
||||
throw std::logic_error("io_latency_probe is canceled");
|
||||
boost::asio::post(
|
||||
ios_, SampleOp<Handler>(std::forward<Handler>(handler), Clock::now(), true, this));
|
||||
m_ios, sample_op<Handler>(std::forward<Handler>(handler), Clock::now(), true, this));
|
||||
}
|
||||
|
||||
private:
|
||||
void
|
||||
cancel(std::unique_lock<decltype(mutex_)>& lock, bool wait)
|
||||
cancel(std::unique_lock<decltype(m_mutex)>& lock, bool wait)
|
||||
{
|
||||
if (!cancel_)
|
||||
if (!m_cancel)
|
||||
{
|
||||
--count_;
|
||||
cancel_ = true;
|
||||
--m_count;
|
||||
m_cancel = true;
|
||||
}
|
||||
|
||||
if (wait)
|
||||
cond_.wait(lock, [this] { return this->count_ == 0; });
|
||||
m_cond.wait(lock, [this] { return this->m_count == 0; });
|
||||
}
|
||||
|
||||
void
|
||||
addref()
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
++count_;
|
||||
std::scoped_lock const lock(m_mutex);
|
||||
++m_count;
|
||||
}
|
||||
|
||||
void
|
||||
release()
|
||||
{
|
||||
std::scoped_lock const lock(mutex_);
|
||||
if (--count_ == 0)
|
||||
cond_.notify_all();
|
||||
std::scoped_lock const lock(m_mutex);
|
||||
if (--m_count == 0)
|
||||
m_cond.notify_all();
|
||||
}
|
||||
|
||||
template <class Handler>
|
||||
struct SampleOp
|
||||
struct sample_op
|
||||
{
|
||||
Handler handler;
|
||||
time_point start;
|
||||
bool repeat;
|
||||
IOLatencyProbe* probe;
|
||||
Handler m_handler;
|
||||
time_point m_start;
|
||||
bool m_repeat;
|
||||
io_latency_probe* m_probe;
|
||||
|
||||
SampleOp(
|
||||
sample_op(
|
||||
Handler const& handler,
|
||||
time_point const& start,
|
||||
bool repeat,
|
||||
IOLatencyProbe* probe)
|
||||
: handler(handler), start(start), repeat(repeat), probe(probe)
|
||||
io_latency_probe* probe)
|
||||
: m_handler(handler), m_start(start), m_repeat(repeat), m_probe(probe)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
probe,
|
||||
"beast::IOLatencyProbe::SampleOp::SampleOp : non-null "
|
||||
m_probe,
|
||||
"beast::io_latency_probe::sample_op::sample_op : non-null "
|
||||
"probe input");
|
||||
probe->addref();
|
||||
m_probe->addref();
|
||||
}
|
||||
|
||||
SampleOp(SampleOp&& from) noexcept
|
||||
: handler(std::move(from.handler))
|
||||
, start(from.start)
|
||||
, repeat(from.repeat)
|
||||
, probe(from.probe)
|
||||
sample_op(sample_op&& from) noexcept
|
||||
: m_handler(std::move(from.m_handler))
|
||||
, m_start(from.m_start)
|
||||
, m_repeat(from.m_repeat)
|
||||
, m_probe(from.m_probe)
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
probe,
|
||||
"beast::IOLatencyProbe::SampleOp::SampleOp(SampleOp&&) : "
|
||||
m_probe,
|
||||
"beast::io_latency_probe::sample_op::sample_op(sample_op&&) : "
|
||||
"non-null probe input");
|
||||
from.probe = nullptr;
|
||||
from.m_probe = nullptr;
|
||||
}
|
||||
|
||||
SampleOp(SampleOp const&) = delete;
|
||||
SampleOp
|
||||
operator=(SampleOp const&) = delete;
|
||||
SampleOp&
|
||||
operator=(SampleOp&&) = delete;
|
||||
sample_op(sample_op const&) = delete;
|
||||
sample_op
|
||||
operator=(sample_op const&) = delete;
|
||||
sample_op&
|
||||
operator=(sample_op&&) = delete;
|
||||
|
||||
~SampleOp()
|
||||
~sample_op()
|
||||
{
|
||||
if (probe)
|
||||
probe->release();
|
||||
if (m_probe)
|
||||
m_probe->release();
|
||||
}
|
||||
|
||||
void
|
||||
operator()() const
|
||||
{
|
||||
if (probe == nullptr)
|
||||
if (m_probe == nullptr)
|
||||
return;
|
||||
typename Clock::time_point const now(Clock::now());
|
||||
typename Clock::duration const elapsed(now - start);
|
||||
typename Clock::duration const elapsed(now - m_start);
|
||||
|
||||
handler(elapsed);
|
||||
m_handler(elapsed);
|
||||
|
||||
{
|
||||
std::scoped_lock const lock(probe->mutex_);
|
||||
if (probe->cancel_)
|
||||
std::scoped_lock const lock(m_probe->m_mutex);
|
||||
if (m_probe->m_cancel)
|
||||
return;
|
||||
}
|
||||
|
||||
if (repeat)
|
||||
if (m_repeat)
|
||||
{
|
||||
// Calculate when we want to sample again, and
|
||||
// adjust for the expected latency.
|
||||
//
|
||||
typename Clock::time_point const when(now + probe->period_ - (2 * elapsed));
|
||||
typename Clock::time_point const when(now + m_probe->m_period - (2 * elapsed));
|
||||
|
||||
if (when <= now)
|
||||
{
|
||||
// The latency is too high to maintain the desired
|
||||
// period so don't bother with a timer.
|
||||
//
|
||||
boost::asio::post(probe->ios_, SampleOp<Handler>(handler, now, repeat, probe));
|
||||
boost::asio::post(
|
||||
m_probe->m_ios, sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
else
|
||||
{
|
||||
probe->timer_.expires_after(when - now);
|
||||
probe->timer_.async_wait(SampleOp<Handler>(handler, now, repeat, probe));
|
||||
m_probe->m_timer.expires_after(when - now);
|
||||
m_probe->m_timer.async_wait(
|
||||
sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -222,10 +224,11 @@ private:
|
||||
void
|
||||
operator()(boost::system::error_code const& ec)
|
||||
{
|
||||
if (probe == nullptr)
|
||||
if (m_probe == nullptr)
|
||||
return;
|
||||
typename Clock::time_point const now(Clock::now());
|
||||
boost::asio::post(probe->ios_, SampleOp<Handler>(handler, now, repeat, probe));
|
||||
boost::asio::post(
|
||||
m_probe->m_ios, sample_op<Handler>(m_handler, now, m_repeat, m_probe));
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
@@ -31,7 +31,7 @@ namespace beast {
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
template <class Clock>
|
||||
class AbstractClock
|
||||
class abstract_clock
|
||||
{
|
||||
public:
|
||||
using rep = typename Clock::rep;
|
||||
@@ -40,11 +40,11 @@ public:
|
||||
using time_point = typename Clock::time_point;
|
||||
using clock_type = Clock;
|
||||
|
||||
static bool const is_steady = Clock::is_steady; // NOLINT(readability-identifier-naming)
|
||||
static bool const is_steady = Clock::is_steady;
|
||||
|
||||
virtual ~AbstractClock() = default;
|
||||
AbstractClock() = default;
|
||||
AbstractClock(AbstractClock const&) = default;
|
||||
virtual ~abstract_clock() = default;
|
||||
abstract_clock() = default;
|
||||
abstract_clock(abstract_clock const&) = default;
|
||||
|
||||
/** Returns the current time. */
|
||||
[[nodiscard]] virtual time_point
|
||||
@@ -56,12 +56,12 @@ public:
|
||||
namespace detail {
|
||||
|
||||
template <class Facade, class Clock>
|
||||
struct AbstractClockWrapper : public AbstractClock<Facade>
|
||||
struct abstract_clock_wrapper : public abstract_clock<Facade>
|
||||
{
|
||||
explicit AbstractClockWrapper() = default;
|
||||
explicit abstract_clock_wrapper() = default;
|
||||
|
||||
using typename AbstractClock<Facade>::duration;
|
||||
using typename AbstractClock<Facade>::time_point;
|
||||
using typename abstract_clock<Facade>::duration;
|
||||
using typename abstract_clock<Facade>::time_point;
|
||||
|
||||
[[nodiscard]] time_point
|
||||
now() const override
|
||||
@@ -80,11 +80,11 @@ struct AbstractClockWrapper : public AbstractClock<Facade>
|
||||
@tparam Clock The actual concrete clock to use.
|
||||
*/
|
||||
template <class Facade, class Clock = Facade>
|
||||
AbstractClock<Facade>&
|
||||
getAbstractClock()
|
||||
abstract_clock<Facade>&
|
||||
get_abstract_clock()
|
||||
{
|
||||
static detail::AbstractClockWrapper<Facade, Clock> kClock;
|
||||
return kClock;
|
||||
static detail::abstract_clock_wrapper<Facade, Clock> clock;
|
||||
return clock;
|
||||
}
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -13,20 +13,19 @@ namespace beast {
|
||||
@tparam Clock A type meeting these requirements:
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
class BasicSecondsClock
|
||||
class basic_seconds_clock
|
||||
{
|
||||
public:
|
||||
using Clock = std::chrono::steady_clock;
|
||||
|
||||
explicit BasicSecondsClock() = default;
|
||||
explicit basic_seconds_clock() = default;
|
||||
|
||||
using rep = typename Clock::rep;
|
||||
using period = typename Clock::period;
|
||||
using duration = typename Clock::duration;
|
||||
using time_point = typename Clock::time_point;
|
||||
|
||||
static bool const is_steady = // NOLINT(readability-identifier-naming)
|
||||
Clock::is_steady;
|
||||
static bool const is_steady = Clock::is_steady;
|
||||
|
||||
static time_point
|
||||
now();
|
||||
|
||||
@@ -17,18 +17,18 @@ namespace beast {
|
||||
http://en.cppreference.com/w/cpp/concept/Clock
|
||||
*/
|
||||
template <class Clock>
|
||||
class ManualClock : public AbstractClock<Clock>
|
||||
class manual_clock : public abstract_clock<Clock>
|
||||
{
|
||||
public:
|
||||
using typename AbstractClock<Clock>::rep;
|
||||
using typename AbstractClock<Clock>::duration;
|
||||
using typename AbstractClock<Clock>::time_point;
|
||||
using typename abstract_clock<Clock>::rep;
|
||||
using typename abstract_clock<Clock>::duration;
|
||||
using typename abstract_clock<Clock>::time_point;
|
||||
|
||||
private:
|
||||
time_point now_;
|
||||
|
||||
public:
|
||||
explicit ManualClock(time_point const& now = time_point(duration(0))) : now_(now)
|
||||
explicit manual_clock(time_point const& now = time_point(duration(0))) : now_(now)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -44,16 +44,16 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
!Clock::is_steady || when >= now_,
|
||||
"beast::ManualClock::set(time_point) : forward input");
|
||||
"beast::manual_clock::set(time_point) : forward input");
|
||||
now_ = when;
|
||||
}
|
||||
|
||||
/** Convenience for setting the time in seconds from epoch. */
|
||||
template <class Integer>
|
||||
void
|
||||
set(Integer secondsFromEpoch)
|
||||
set(Integer seconds_from_epoch)
|
||||
{
|
||||
set(time_point(duration(std::chrono::seconds(secondsFromEpoch))));
|
||||
set(time_point(duration(std::chrono::seconds(seconds_from_epoch))));
|
||||
}
|
||||
|
||||
/** Advance the clock by a duration. */
|
||||
@@ -63,12 +63,12 @@ public:
|
||||
{
|
||||
XRPL_ASSERT(
|
||||
!Clock::is_steady || (now_ + elapsed) >= now_,
|
||||
"beast::ManualClock::advance(duration) : forward input");
|
||||
"beast::manual_clock::advance(duration) : forward input");
|
||||
now_ += elapsed;
|
||||
}
|
||||
|
||||
/** Convenience for advancing the clock by one second. */
|
||||
ManualClock&
|
||||
manual_clock&
|
||||
operator++()
|
||||
{
|
||||
advance(std::chrono::seconds(1));
|
||||
|
||||
@@ -5,9 +5,9 @@
|
||||
namespace beast {
|
||||
|
||||
template <class T>
|
||||
struct IsAgedContainer : std::false_type
|
||||
struct is_aged_container : std::false_type
|
||||
{
|
||||
explicit IsAgedContainer() = default;
|
||||
explicit is_aged_container() = default;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -9,7 +9,7 @@ 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::enable_if_t<is_aged_container<AgedContainer>::value, std::size_t>
|
||||
expire(AgedContainer& c, std::chrono::duration<Rep, Period> const& age)
|
||||
{
|
||||
std::size_t n(0);
|
||||
|
||||
@@ -14,6 +14,6 @@ template <
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_map = detail::AgedOrderedContainer<false, true, Key, T, Clock, Compare, Allocator>;
|
||||
using aged_map = detail::aged_ordered_container<false, true, Key, T, Clock, Compare, Allocator>;
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -14,6 +14,6 @@ template <
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_multimap = detail::AgedOrderedContainer<true, true, Key, T, Clock, Compare, Allocator>;
|
||||
using aged_multimap = detail::aged_ordered_container<true, true, Key, T, Clock, Compare, Allocator>;
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -14,6 +14,5 @@ template <
|
||||
class Compare = std::less<Key>,
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_multiset =
|
||||
detail::AgedOrderedContainer<true, false, Key, void, Clock, Compare, Allocator>;
|
||||
|
||||
detail::aged_ordered_container<true, false, Key, void, Clock, Compare, Allocator>;
|
||||
} // namespace beast
|
||||
|
||||
@@ -13,6 +13,6 @@ template <
|
||||
class Clock = std::chrono::steady_clock,
|
||||
class Compare = std::less<Key>,
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_set = detail::AgedOrderedContainer<false, false, Key, void, Clock, Compare, Allocator>;
|
||||
using aged_set = detail::aged_ordered_container<false, false, Key, void, Clock, Compare, Allocator>;
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -16,6 +16,5 @@ template <
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_unordered_map =
|
||||
detail::AgedUnorderedContainer<false, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
detail::aged_unordered_container<false, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
} // namespace beast
|
||||
|
||||
@@ -16,6 +16,5 @@ template <
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<std::pair<Key const, T>>>
|
||||
using aged_unordered_multimap =
|
||||
detail::AgedUnorderedContainer<true, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
detail::aged_unordered_container<true, true, Key, T, Clock, Hash, KeyEqual, Allocator>;
|
||||
} // namespace beast
|
||||
|
||||
@@ -15,6 +15,6 @@ template <
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_unordered_multiset =
|
||||
detail::AgedUnorderedContainer<true, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
detail::aged_unordered_container<true, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
} // namespace beast
|
||||
|
||||
@@ -15,6 +15,5 @@ template <
|
||||
class KeyEqual = std::equal_to<Key>,
|
||||
class Allocator = std::allocator<Key>>
|
||||
using aged_unordered_set =
|
||||
detail::AgedUnorderedContainer<false, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
|
||||
detail::aged_unordered_container<false, false, Key, void, Clock, Hash, KeyEqual, Allocator>;
|
||||
} // namespace beast
|
||||
|
||||
@@ -3,10 +3,10 @@
|
||||
namespace beast::detail {
|
||||
|
||||
// Extracts the key portion of value
|
||||
template <bool MaybeMap>
|
||||
struct AgedAssociativeContainerExtractT
|
||||
template <bool maybe_map>
|
||||
struct aged_associative_container_extract_t
|
||||
{
|
||||
explicit AgedAssociativeContainerExtractT() = default;
|
||||
explicit aged_associative_container_extract_t() = default;
|
||||
|
||||
template <class Value>
|
||||
decltype(Value::first) const&
|
||||
@@ -17,9 +17,9 @@ struct AgedAssociativeContainerExtractT
|
||||
};
|
||||
|
||||
template <>
|
||||
struct AgedAssociativeContainerExtractT<false>
|
||||
struct aged_associative_container_extract_t<false>
|
||||
{
|
||||
explicit AgedAssociativeContainerExtractT() = default;
|
||||
explicit aged_associative_container_extract_t() = default;
|
||||
|
||||
template <class Value>
|
||||
Value const&
|
||||
|
||||
@@ -12,136 +12,137 @@ class aged_ordered_container;
|
||||
namespace detail {
|
||||
|
||||
// If Iterator is SCARY then this iterator will be as well.
|
||||
template <bool IsConst, class Iterator>
|
||||
class AgedContainerIterator
|
||||
template <bool is_const, class Iterator>
|
||||
class aged_container_iterator
|
||||
{
|
||||
public:
|
||||
using iterator_category = typename 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>;
|
||||
is_const,
|
||||
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 pointer = value_type*;
|
||||
using reference = value_type&;
|
||||
using time_point = typename Iterator::value_type::Stashed::time_point;
|
||||
using time_point = typename Iterator::value_type::stashed::time_point;
|
||||
|
||||
AgedContainerIterator() = default;
|
||||
aged_container_iterator() = default;
|
||||
|
||||
// Disable constructing a const_iterator from a non-const_iterator.
|
||||
// Converting between reverse and non-reverse iterators should be explicit.
|
||||
template <
|
||||
bool OtherIsConst,
|
||||
bool other_is_const,
|
||||
class OtherIterator,
|
||||
class = std::enable_if_t<
|
||||
(!OtherIsConst || IsConst) &&
|
||||
(!other_is_const || is_const) &&
|
||||
!static_cast<bool>(std::is_same_v<Iterator, OtherIterator>)>>
|
||||
explicit AgedContainerIterator(AgedContainerIterator<OtherIsConst, OtherIterator> const& other)
|
||||
: iter_(other.iter_)
|
||||
explicit aged_container_iterator(
|
||||
aged_container_iterator<other_is_const, OtherIterator> const& other)
|
||||
: m_iter(other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
// Disable constructing a const_iterator from a non-const_iterator.
|
||||
template <bool OtherIsConst, class = std::enable_if_t<!OtherIsConst || IsConst>>
|
||||
AgedContainerIterator(AgedContainerIterator<OtherIsConst, Iterator> const& other)
|
||||
: iter_(other.iter_)
|
||||
template <bool other_is_const, class = std::enable_if_t<!other_is_const || is_const>>
|
||||
aged_container_iterator(aged_container_iterator<other_is_const, Iterator> const& other)
|
||||
: m_iter(other.m_iter)
|
||||
{
|
||||
}
|
||||
|
||||
// Disable assigning a const_iterator to a non-const iterator
|
||||
template <bool OtherIsConst, class OtherIterator>
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
auto
|
||||
operator=(AgedContainerIterator<OtherIsConst, OtherIterator> const& other)
|
||||
-> std::enable_if_t<!OtherIsConst || IsConst, AgedContainerIterator&>
|
||||
operator=(aged_container_iterator<other_is_const, OtherIterator> const& other)
|
||||
-> std::enable_if_t<!other_is_const || is_const, aged_container_iterator&>
|
||||
{
|
||||
iter_ = other.iter_;
|
||||
m_iter = other.m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <bool OtherIsConst, class OtherIterator>
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
bool
|
||||
operator==(AgedContainerIterator<OtherIsConst, OtherIterator> const& other) const
|
||||
operator==(aged_container_iterator<other_is_const, OtherIterator> const& other) const
|
||||
{
|
||||
return iter_ == other.iter_;
|
||||
return m_iter == other.m_iter;
|
||||
}
|
||||
|
||||
template <bool OtherIsConst, class OtherIterator>
|
||||
template <bool other_is_const, class OtherIterator>
|
||||
bool
|
||||
operator!=(AgedContainerIterator<OtherIsConst, OtherIterator> const& other) const
|
||||
operator!=(aged_container_iterator<other_is_const, OtherIterator> const& other) const
|
||||
{
|
||||
return iter_ != other.iter_;
|
||||
return m_iter != other.m_iter;
|
||||
}
|
||||
|
||||
AgedContainerIterator&
|
||||
aged_container_iterator&
|
||||
operator++()
|
||||
{
|
||||
++iter_;
|
||||
++m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AgedContainerIterator
|
||||
aged_container_iterator
|
||||
operator++(int)
|
||||
{
|
||||
AgedContainerIterator const prev(*this);
|
||||
++iter_;
|
||||
aged_container_iterator const prev(*this);
|
||||
++m_iter;
|
||||
return prev;
|
||||
}
|
||||
|
||||
AgedContainerIterator&
|
||||
aged_container_iterator&
|
||||
operator--()
|
||||
{
|
||||
--iter_;
|
||||
--m_iter;
|
||||
return *this;
|
||||
}
|
||||
|
||||
AgedContainerIterator
|
||||
aged_container_iterator
|
||||
operator--(int)
|
||||
{
|
||||
AgedContainerIterator const prev(*this);
|
||||
--iter_;
|
||||
aged_container_iterator const prev(*this);
|
||||
--m_iter;
|
||||
return prev;
|
||||
}
|
||||
|
||||
reference
|
||||
operator*() const
|
||||
{
|
||||
return iter_->value;
|
||||
return m_iter->value;
|
||||
}
|
||||
|
||||
pointer
|
||||
operator->() const
|
||||
{
|
||||
return &iter_->value;
|
||||
return &m_iter->value;
|
||||
}
|
||||
|
||||
[[nodiscard]] time_point const&
|
||||
when() const
|
||||
{
|
||||
return iter_->when;
|
||||
return m_iter->when;
|
||||
}
|
||||
|
||||
private:
|
||||
template <bool, bool, class, class, class, class, class>
|
||||
friend class AgedOrderedContainer;
|
||||
friend class aged_ordered_container;
|
||||
|
||||
template <bool, bool, class, class, class, class, class, class>
|
||||
friend class AgedUnorderedContainer;
|
||||
friend class aged_unordered_container;
|
||||
|
||||
template <bool, class>
|
||||
friend class AgedContainerIterator;
|
||||
friend class aged_container_iterator;
|
||||
|
||||
template <class OtherIterator>
|
||||
AgedContainerIterator(OtherIterator iter) : iter_(std::move(iter))
|
||||
aged_container_iterator(OtherIterator iter) : m_iter(std::move(iter))
|
||||
{
|
||||
}
|
||||
|
||||
[[nodiscard]] Iterator const&
|
||||
iterator() const
|
||||
{
|
||||
return iter_;
|
||||
return m_iter;
|
||||
}
|
||||
|
||||
Iterator iter_;
|
||||
Iterator m_iter;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -14,25 +14,25 @@
|
||||
namespace beast::detail {
|
||||
|
||||
template <class T>
|
||||
struct IsEmptyBaseOptimizationDerived
|
||||
struct is_empty_base_optimization_derived
|
||||
: std::integral_constant<bool, std::is_empty_v<T> && !boost::is_final<T>::value>
|
||||
{
|
||||
};
|
||||
|
||||
template <class T, int UniqueID = 0, bool IsDerived = IsEmptyBaseOptimizationDerived<T>::value>
|
||||
class EmptyBaseOptimization : private T
|
||||
template <class T, int UniqueID = 0, bool isDerived = is_empty_base_optimization_derived<T>::value>
|
||||
class empty_base_optimization : private T
|
||||
{
|
||||
public:
|
||||
EmptyBaseOptimization() = default;
|
||||
EmptyBaseOptimization(EmptyBaseOptimization&&) = default;
|
||||
EmptyBaseOptimization(EmptyBaseOptimization const&) = default;
|
||||
EmptyBaseOptimization&
|
||||
operator=(EmptyBaseOptimization&&) = default;
|
||||
EmptyBaseOptimization&
|
||||
operator=(EmptyBaseOptimization const&) = default;
|
||||
empty_base_optimization() = default;
|
||||
empty_base_optimization(empty_base_optimization&&) = default;
|
||||
empty_base_optimization(empty_base_optimization const&) = default;
|
||||
empty_base_optimization&
|
||||
operator=(empty_base_optimization&&) = default;
|
||||
empty_base_optimization&
|
||||
operator=(empty_base_optimization const&) = default;
|
||||
|
||||
template <class Arg1, class... ArgN>
|
||||
explicit EmptyBaseOptimization(Arg1&& arg1, ArgN&&... argn)
|
||||
explicit empty_base_optimization(Arg1&& arg1, ArgN&&... argn)
|
||||
: T(std::forward<Arg1>(arg1), std::forward<ArgN>(argn)...)
|
||||
{
|
||||
}
|
||||
@@ -53,21 +53,21 @@ public:
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
template <class T, int UniqueID>
|
||||
class EmptyBaseOptimization<T, UniqueID, false>
|
||||
class empty_base_optimization<T, UniqueID, false>
|
||||
{
|
||||
T t_;
|
||||
|
||||
public:
|
||||
EmptyBaseOptimization() = default;
|
||||
EmptyBaseOptimization(EmptyBaseOptimization&&) = default;
|
||||
EmptyBaseOptimization(EmptyBaseOptimization const&) = default;
|
||||
EmptyBaseOptimization&
|
||||
operator=(EmptyBaseOptimization&&) = default;
|
||||
EmptyBaseOptimization&
|
||||
operator=(EmptyBaseOptimization const&) = default;
|
||||
empty_base_optimization() = default;
|
||||
empty_base_optimization(empty_base_optimization&&) = default;
|
||||
empty_base_optimization(empty_base_optimization const&) = default;
|
||||
empty_base_optimization&
|
||||
operator=(empty_base_optimization&&) = default;
|
||||
empty_base_optimization&
|
||||
operator=(empty_base_optimization const&) = default;
|
||||
|
||||
template <class Arg1, class... ArgN>
|
||||
explicit EmptyBaseOptimization(Arg1&& arg1, ArgN&&... argn)
|
||||
explicit empty_base_optimization(Arg1&& arg1, ArgN&&... argn)
|
||||
: t_(std::forward<Arg1>(arg1), std::forward<ArgN>(argn)...)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ setCurrentThreadName(std::string_view newThreadName);
|
||||
|
||||
// On Linux, thread names are limited to 16 bytes including the null terminator.
|
||||
// Maximum number of characters is therefore 15.
|
||||
constexpr std::size_t kMaxThreadNameLength = 15;
|
||||
constexpr std::size_t maxThreadNameLength = 15;
|
||||
|
||||
/** Sets the name of the caller thread with compile-time size checking.
|
||||
@tparam N The size of the string literal including null terminator
|
||||
@@ -34,7 +34,7 @@ template <std::size_t N>
|
||||
void
|
||||
setCurrentThreadName(char const (&newThreadName)[N])
|
||||
{
|
||||
static_assert(N <= kMaxThreadNameLength + 1, "Thread name cannot exceed 15 characters");
|
||||
static_assert(N <= maxThreadNameLength + 1, "Thread name cannot exceed 15 characters");
|
||||
|
||||
setCurrentThreadName(std::string_view(newThreadName, N - 1));
|
||||
}
|
||||
|
||||
@@ -45,8 +45,8 @@ class ListNode
|
||||
template <typename>
|
||||
friend class ListIterator;
|
||||
|
||||
ListNode* next_ = nullptr;
|
||||
ListNode* prev_ = nullptr;
|
||||
ListNode* m_next = nullptr;
|
||||
ListNode* m_prev = nullptr;
|
||||
};
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
@@ -62,12 +62,12 @@ public:
|
||||
using reference = value_type&;
|
||||
using size_type = std::size_t;
|
||||
|
||||
ListIterator(N* node = nullptr) noexcept : node_(node)
|
||||
ListIterator(N* node = nullptr) noexcept : m_node(node)
|
||||
{
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
ListIterator(ListIterator<M> const& other) noexcept : node_(other.node_)
|
||||
ListIterator(ListIterator<M> const& other) noexcept : m_node(other.m_node)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -75,7 +75,7 @@ public:
|
||||
bool
|
||||
operator==(ListIterator<M> const& other) const noexcept
|
||||
{
|
||||
return node_ == other.node_;
|
||||
return m_node == other.m_node;
|
||||
}
|
||||
|
||||
template <typename M>
|
||||
@@ -131,22 +131,22 @@ private:
|
||||
[[nodiscard]] reference
|
||||
dereference() const noexcept
|
||||
{
|
||||
return static_cast<reference>(*node_);
|
||||
return static_cast<reference>(*m_node);
|
||||
}
|
||||
|
||||
void
|
||||
increment() noexcept
|
||||
{
|
||||
node_ = node_->next_;
|
||||
m_node = m_node->m_next;
|
||||
}
|
||||
|
||||
void
|
||||
decrement() noexcept
|
||||
{
|
||||
node_ = node_->prev_;
|
||||
m_node = m_node->m_prev;
|
||||
}
|
||||
|
||||
N* node_;
|
||||
N* m_node;
|
||||
};
|
||||
|
||||
} // namespace detail
|
||||
@@ -161,11 +161,11 @@ private:
|
||||
|
||||
struct Object : List <Object>::Node
|
||||
{
|
||||
explicit Object (int value) : value_ (value)
|
||||
explicit Object (int value) : m_value (value)
|
||||
{
|
||||
}
|
||||
|
||||
int value_;
|
||||
int m_value;
|
||||
};
|
||||
|
||||
@endcode
|
||||
@@ -190,7 +190,7 @@ private:
|
||||
@code
|
||||
|
||||
for (List <Object>::iterator iter = list.begin(); iter != list.end; ++iter)
|
||||
std::cout << iter->value_;
|
||||
std::cout << iter->m_value;
|
||||
|
||||
@endcode
|
||||
|
||||
@@ -199,10 +199,10 @@ private:
|
||||
@code
|
||||
|
||||
BOOST_FOREACH (Object& object, list) // boost only
|
||||
std::cout << object.value_;
|
||||
std::cout << object.m_value;
|
||||
|
||||
for (Object& object : list) // C++11 only
|
||||
std::cout << object.value_;
|
||||
std::cout << object.m_value;
|
||||
|
||||
@endcode
|
||||
|
||||
@@ -275,8 +275,8 @@ public:
|
||||
/** Create an empty list. */
|
||||
List()
|
||||
{
|
||||
head_.prev_ = nullptr; // identifies the head
|
||||
tail_.next_ = nullptr; // identifies the tail
|
||||
m_head.m_prev = nullptr; // identifies the head
|
||||
m_tail.m_next = nullptr; // identifies the tail
|
||||
clear();
|
||||
}
|
||||
|
||||
@@ -297,7 +297,7 @@ public:
|
||||
[[nodiscard]] size_type
|
||||
size() const noexcept
|
||||
{
|
||||
return size_;
|
||||
return m_size;
|
||||
}
|
||||
|
||||
/** Obtain a reference to the first element.
|
||||
@@ -307,7 +307,7 @@ public:
|
||||
reference
|
||||
front() noexcept
|
||||
{
|
||||
return element_from(head_.next_);
|
||||
return element_from(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const reference to the first element.
|
||||
@@ -317,7 +317,7 @@ public:
|
||||
[[nodiscard]] const_reference
|
||||
front() const noexcept
|
||||
{
|
||||
return element_from(head_.next_);
|
||||
return element_from(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a reference to the last element.
|
||||
@@ -327,7 +327,7 @@ public:
|
||||
reference
|
||||
back() noexcept
|
||||
{
|
||||
return element_from(tail_.prev_);
|
||||
return element_from(m_tail.m_prev);
|
||||
}
|
||||
|
||||
/** Obtain a const reference to the last element.
|
||||
@@ -337,7 +337,7 @@ public:
|
||||
[[nodiscard]] const_reference
|
||||
back() const noexcept
|
||||
{
|
||||
return element_from(tail_.prev_);
|
||||
return element_from(m_tail.m_prev);
|
||||
}
|
||||
|
||||
/** Obtain an iterator to the beginning of the list.
|
||||
@@ -346,7 +346,7 @@ public:
|
||||
iterator
|
||||
begin() noexcept
|
||||
{
|
||||
return iterator(head_.next_);
|
||||
return iterator(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the beginning of the list.
|
||||
@@ -355,7 +355,7 @@ public:
|
||||
[[nodiscard]] const_iterator
|
||||
begin() const noexcept
|
||||
{
|
||||
return const_iterator(head_.next_);
|
||||
return const_iterator(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the beginning of the list.
|
||||
@@ -364,7 +364,7 @@ public:
|
||||
[[nodiscard]] const_iterator
|
||||
cbegin() const noexcept
|
||||
{
|
||||
return const_iterator(head_.next_);
|
||||
return const_iterator(m_head.m_next);
|
||||
}
|
||||
|
||||
/** Obtain a iterator to the end of the list.
|
||||
@@ -373,7 +373,7 @@ public:
|
||||
iterator
|
||||
end() noexcept
|
||||
{
|
||||
return iterator(&tail_);
|
||||
return iterator(&m_tail);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the end of the list.
|
||||
@@ -382,7 +382,7 @@ public:
|
||||
[[nodiscard]] const_iterator
|
||||
end() const noexcept
|
||||
{
|
||||
return const_iterator(&tail_);
|
||||
return const_iterator(&m_tail);
|
||||
}
|
||||
|
||||
/** Obtain a const iterator to the end of the list
|
||||
@@ -391,7 +391,7 @@ public:
|
||||
[[nodiscard]] const_iterator
|
||||
cend() const noexcept
|
||||
{
|
||||
return const_iterator(&tail_);
|
||||
return const_iterator(&m_tail);
|
||||
}
|
||||
|
||||
/** Clear the list.
|
||||
@@ -400,9 +400,9 @@ public:
|
||||
void
|
||||
clear() noexcept
|
||||
{
|
||||
head_.next_ = &tail_;
|
||||
tail_.prev_ = &head_;
|
||||
size_ = 0;
|
||||
m_head.m_next = &m_tail;
|
||||
m_tail.m_prev = &m_head;
|
||||
m_size = 0;
|
||||
}
|
||||
|
||||
/** Insert an element.
|
||||
@@ -415,11 +415,11 @@ public:
|
||||
insert(iterator pos, T& element) noexcept
|
||||
{
|
||||
Node* node = static_cast<Node*>(&element);
|
||||
node->next_ = &*pos;
|
||||
node->prev_ = node->next_->prev_;
|
||||
node->next_->prev_ = node;
|
||||
node->prev_->next_ = node;
|
||||
++size_;
|
||||
node->m_next = &*pos;
|
||||
node->m_prev = node->m_next->m_prev;
|
||||
node->m_next->m_prev = node;
|
||||
node->m_prev->m_next = node;
|
||||
++m_size;
|
||||
return iterator(node);
|
||||
}
|
||||
|
||||
@@ -434,11 +434,11 @@ public:
|
||||
if (!other.empty())
|
||||
{
|
||||
Node* before = &*pos;
|
||||
other.head_.next_->prev_ = before->prev_;
|
||||
before->prev_->next_ = other.head_.next_;
|
||||
other.tail_.prev_->next_ = before;
|
||||
before->prev_ = other.tail_.prev_;
|
||||
size_ += other.size_;
|
||||
other.m_head.m_next->m_prev = before->m_prev;
|
||||
before->m_prev->m_next = other.m_head.m_next;
|
||||
other.m_tail.m_prev->m_next = before;
|
||||
before->m_prev = other.m_tail.m_prev;
|
||||
m_size += other.m_size;
|
||||
other.clear();
|
||||
}
|
||||
}
|
||||
@@ -453,9 +453,9 @@ public:
|
||||
{
|
||||
Node const* node = &*pos;
|
||||
++pos;
|
||||
node->next_->prev_ = node->prev_;
|
||||
node->prev_->next_ = node->next_;
|
||||
--size_;
|
||||
node->m_next->m_prev = node->m_prev;
|
||||
node->m_prev->m_next = node->m_next;
|
||||
--m_size;
|
||||
return pos;
|
||||
}
|
||||
|
||||
@@ -464,7 +464,7 @@ public:
|
||||
@param element The element to insert.
|
||||
*/
|
||||
iterator
|
||||
pushFront(T& element) noexcept
|
||||
push_front(T& element) noexcept
|
||||
{
|
||||
return insert(begin(), element);
|
||||
}
|
||||
@@ -474,7 +474,7 @@ public:
|
||||
@return A reference to the popped element.
|
||||
*/
|
||||
T&
|
||||
popFront() noexcept
|
||||
pop_front() noexcept
|
||||
{
|
||||
T& element(front());
|
||||
erase(begin());
|
||||
@@ -486,7 +486,7 @@ public:
|
||||
@param element The element to append.
|
||||
*/
|
||||
iterator
|
||||
pushBack(T& element) noexcept
|
||||
push_back(T& element) noexcept
|
||||
{
|
||||
return insert(end(), element);
|
||||
}
|
||||
@@ -496,7 +496,7 @@ public:
|
||||
@return A reference to the popped element.
|
||||
*/
|
||||
T&
|
||||
popBack() noexcept
|
||||
pop_back() noexcept
|
||||
{
|
||||
T& element(back());
|
||||
erase(--end());
|
||||
@@ -539,7 +539,7 @@ public:
|
||||
@return An iterator to the element.
|
||||
*/
|
||||
iterator
|
||||
iteratorTo(T& element) const noexcept
|
||||
iterator_to(T& element) const noexcept
|
||||
{
|
||||
return iterator(static_cast<Node*>(&element));
|
||||
}
|
||||
@@ -550,28 +550,28 @@ public:
|
||||
@return A const iterator to the element.
|
||||
*/
|
||||
[[nodiscard]] const_iterator
|
||||
constIteratorTo(T const& element) const noexcept
|
||||
const_iterator_to(T const& element) const noexcept
|
||||
{
|
||||
return const_iterator(static_cast<Node const*>(&element));
|
||||
}
|
||||
|
||||
private:
|
||||
reference
|
||||
elementFrom(Node* node) noexcept
|
||||
element_from(Node* node) noexcept
|
||||
{
|
||||
return *(static_cast<pointer>(node));
|
||||
}
|
||||
|
||||
const_reference
|
||||
elementFrom(Node const* node) const noexcept
|
||||
element_from(Node const* node) const noexcept
|
||||
{
|
||||
return *(static_cast<const_pointer>(node));
|
||||
}
|
||||
|
||||
private:
|
||||
size_type size_ = 0u;
|
||||
Node head_;
|
||||
Node tail_;
|
||||
size_type m_size = 0u;
|
||||
Node m_head;
|
||||
Node m_tail;
|
||||
};
|
||||
|
||||
} // namespace beast
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user