diff --git a/INSTALL.md b/INSTALL.md index c01a2d1263..7a5ded2f7f 100644 --- a/INSTALL.md +++ b/INSTALL.md @@ -57,7 +57,7 @@ To install Postgresql, follow instructions from the [Postgresql download page](h ## Build Dependencies -- c++ toolchain and headers that supports c++17 +- c++ toolchain and headers that supports c++20 - `clang` >= 20.0 - `g++` >= 14.0 - `pkg-config` diff --git a/README.md b/README.md index f60d885bb0..8ab58013e6 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ Stellar-core is a replicated state machine that maintains a local copy of a cryptographic ledger and processes transactions against it, in consensus with a set of peers. It implements the [Stellar Consensus Protocol](https://github.com/stellar/stellar-core/blob/master/src/scp/readme.md), a _federated_ consensus protocol. -It is written in C++17 and runs on Linux, OSX and Windows. +It is written in C++20 and runs on Linux, OSX and Windows. Learn more by reading the [overview document](https://github.com/stellar/stellar-core/blob/master/docs/readme.md). # Documentation diff --git a/configure.ac b/configure.ac index ff5b27751a..98a74ec27b 100644 --- a/configure.ac +++ b/configure.ac @@ -49,7 +49,7 @@ AC_SUBST(LIBTOOL_DEPS) AC_LANG(C++) # if modifying the following macro for a future C++ version, please update CXX # for enable-afl in the fuzzer configuration block below -AX_CXX_COMPILE_STDCXX(17, noext,mandatory) +AX_CXX_COMPILE_STDCXX(20, noext,mandatory) AX_FRESH_COMPILER # -pthread seems to be required by -std=c++14 on some hosts AX_APPEND_COMPILE_FLAGS([-pthread]) @@ -249,17 +249,17 @@ AS_IF([test "x$enable_afl" = "xyes"], [ [clang*], [AC_CHECK_PROGS([AFL_CLANG], [afl-clang-fast]) AC_CHECK_PROGS([AFL_CLANGPP], [afl-clang-fast++]) CC="afl-clang-fast" - # below we hard code -std=c++17 since updates to AX_CXX_COMPILE_STDCXX append it to + # below we hard code -std=c++20 since updates to AX_CXX_COMPILE_STDCXX append it to # CXX, not to CXXFLAGS and thus when setting CXX we override this. For a more detailed explanation # see: https://github.com/stellar/docker-stellar-core/pull/66#issuecomment-521886881 - CXX="afl-clang-fast++ -std=c++17 -DAFL_LLVM_MODE=1"], + CXX="afl-clang-fast++ -std=c++20 -DAFL_LLVM_MODE=1"], [gcc*], [AC_CHECK_PROGS([AFL_GCC], [afl-gcc]) AC_CHECK_PROGS([AFL_GPP], [afl-g++]) CC="afl-gcc" - # below we hard code -std=c++17 since updates to AX_CXX_COMPILE_STDCXX append it to + # below we hard code -std=c++20 since updates to AX_CXX_COMPILE_STDCXX append it to # CXX, not to CXXFLAGS and thus when setting CXX we override this. For a more detailed explanation # see: https://github.com/stellar/docker-stellar-core/pull/66#issuecomment-521886881 - CXX="afl-g++ -std=c++17"], + CXX="afl-g++ -std=c++20"], [AC_MSG_ERROR([Don't know how to instrument CC=$CC with AFL])]) ]) AM_CONDITIONAL([USE_AFL_FUZZ], [test "x$enable_afl" == "xyes"]) diff --git a/lib/autocheck/include/autocheck/classifier.hpp b/lib/autocheck/include/autocheck/classifier.hpp index 76fc9dedc7..7308886724 100644 --- a/lib/autocheck/include/autocheck/classifier.hpp +++ b/lib/autocheck/include/autocheck/classifier.hpp @@ -38,7 +38,7 @@ namespace autocheck { typename Func, typename Enable = typename std::enable_if< !std::is_convertible< - typename std::result_of::type, + std::invoke_result_t, std::string >::value >::type diff --git a/lib/fmt b/lib/fmt index e69e5f977d..407c905e45 160000 --- a/lib/fmt +++ b/lib/fmt @@ -1 +1 @@ -Subproject commit e69e5f977d458f2650bb346dadf2ad30c5320281 +Subproject commit 407c905e45ad75fc29bf0f9bb7c5c2fd3475976f diff --git a/lib/spdlog b/lib/spdlog index 7e635fca68..79524ddd08 160000 --- a/lib/spdlog +++ b/lib/spdlog @@ -1 +1 @@ -Subproject commit 7e635fca68d014934b4af8a1cf874f63989352b7 +Subproject commit 79524ddd08a4ec981b7fea76afd08ee05f83755d diff --git a/lib/xdrpp b/lib/xdrpp index 8e1fe06581..5d8b27c98c 160000 --- a/lib/xdrpp +++ b/lib/xdrpp @@ -1 +1 @@ -Subproject commit 8e1fe06581060a970afcb934de4b4645b0d5d350 +Subproject commit 5d8b27c98c9a340758516196e401438ad401c4b4 diff --git a/m4/ax_cxx_compile_stdcxx.m4 b/m4/ax_cxx_compile_stdcxx.m4 index 0b6cb3a7d7..d805957056 100644 --- a/m4/ax_cxx_compile_stdcxx.m4 +++ b/m4/ax_cxx_compile_stdcxx.m4 @@ -10,13 +10,13 @@ # # Check for baseline language coverage in the compiler for the specified # version of the C++ standard. If necessary, add switches to CXX and -# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard) -# or '14' (for the C++14 standard). +# CXXCPP to enable support. VERSION may be '11', '14', '17', '20', or +# '23' for the respective C++ standard version. # # The second argument, if specified, indicates whether you insist on an # extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g. # -std=c++11). If neither is specified, you get whatever works, with -# preference for an extended mode. +# preference for no added switch, and then for an extended mode. # # The third argument, if specified 'mandatory' or if left unspecified, # indicates that baseline support for the specified C++ standard is @@ -34,13 +34,17 @@ # Copyright (c) 2015 Paul Norman # Copyright (c) 2015 Moritz Klammler # Copyright (c) 2016, 2018 Krzesimir Nowak +# Copyright (c) 2019 Enji Cooper +# Copyright (c) 2020 Jason Merrill +# Copyright (c) 2021, 2024 Jörn Heusipp +# Copyright (c) 2015, 2022, 2023, 2024 Olly Betts # # Copying and distribution of this file, with or without modification, are # permitted in any medium without royalty provided the copyright notice # and this notice are preserved. This file is offered as-is, without any # warranty. -#serial 9 +#serial 25 dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro dnl (serial version number 13). @@ -49,6 +53,8 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"], [$1], [14], [ax_cxx_compile_alternatives="14 1y"], [$1], [17], [ax_cxx_compile_alternatives="17 1z"], + [$1], [20], [ax_cxx_compile_alternatives="20"], + [$1], [23], [ax_cxx_compile_alternatives="23"], [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl m4_if([$2], [], [], [$2], [ext], [], @@ -61,6 +67,16 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl AC_LANG_PUSH([C++])dnl ac_success=no + m4_if([$2], [], [dnl + AC_CACHE_CHECK(whether $CXX supports C++$1 features by default, + ax_cv_cxx_compile_cxx$1, + [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])], + [ax_cv_cxx_compile_cxx$1=yes], + [ax_cv_cxx_compile_cxx$1=no])]) + if test x$ax_cv_cxx_compile_cxx$1 = xyes; then + ac_success=yes + fi]) + m4_if([$2], [noext], [], [dnl if test x$ac_success = xno; then for alternative in ${ax_cxx_compile_alternatives}; do @@ -90,9 +106,18 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl dnl HP's aCC needs +std=c++11 according to: dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf dnl Cray's crayCC needs "-h std=c++11" + dnl MSVC needs -std:c++NN for C++17 and later (default is C++14) for alternative in ${ax_cxx_compile_alternatives}; do - for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do - cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}" MSVC; do + if test x"$switch" = xMSVC; then + dnl AS_TR_SH maps both `:` and `=` to `_` so -std:c++17 would collide + dnl with -std=c++17. We suffix the cache variable name with _MSVC to + dnl avoid this. + switch=-std:c++${alternative} + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_${switch}_MSVC]) + else + cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch]) + fi AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch, $cachevar, [ac_save_CXX="$CXX" @@ -136,23 +161,44 @@ AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl dnl Test body for checking C++11 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11] ) - dnl Test body for checking C++14 support m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14] ) +dnl Test body for checking C++17 support + m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17], - _AX_CXX_COMPILE_STDCXX_testbody_new_in_11 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 - _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17] +) + +dnl Test body for checking C++20 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_20], + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_20] ) +dnl Test body for checking C++23 support + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_23], + [_AX_CXX_COMPILE_STDCXX_testbody_new_in_11 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_14 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_17 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_20 + _AX_CXX_COMPILE_STDCXX_testbody_new_in_23] +) + + dnl Tests for new features in C++11 m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ @@ -164,7 +210,21 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[ #error "This is not a C++ compiler" -#elif __cplusplus < 201103L +// MSVC always sets __cplusplus to 199711L in older versions; newer versions +// only set it correctly if /Zc:__cplusplus is specified as well as a +// /std:c++NN switch: +// +// https://devblogs.microsoft.com/cppblog/msvc-now-correctly-reports-__cplusplus/ +// +// The value __cplusplus ought to have is available in _MSVC_LANG since +// Visual Studio 2015 Update 3: +// +// https://learn.microsoft.com/en-us/cpp/preprocessor/predefined-macros +// +// This was also the first MSVC version to support C++14 so we can't use the +// value of either __cplusplus or _MSVC_LANG to quickly rule out MSVC having +// C++11 or C++14 support, but we can check _MSVC_LANG for C++17 and later. +#elif __cplusplus < 201103L && !defined _MSC_VER #error "This is not a C++11 compiler" @@ -189,11 +249,13 @@ namespace cxx11 struct Base { + virtual ~Base() {} virtual void f() {} }; struct Derived : public Base { + virtual ~Derived() override {} virtual void f() override {} }; @@ -453,7 +515,7 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[ #error "This is not a C++ compiler" -#elif __cplusplus < 201402L +#elif __cplusplus < 201402L && !defined _MSC_VER #error "This is not a C++14 compiler" @@ -577,20 +639,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ #error "This is not a C++ compiler" -#elif __cplusplus <= 201402L +#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L #error "This is not a C++17 compiler" #else -#if defined(__clang__) - #define REALLY_CLANG -#else - #if defined(__GNUC__) - #define REALLY_GCC - #endif -#endif - #include #include #include @@ -598,16 +652,12 @@ m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[ namespace cxx17 { -#if !defined(REALLY_CLANG) namespace test_constexpr_lambdas { - // TODO: test it with clang++ from git - constexpr int foo = [](){return 42;}(); } -#endif // !defined(REALLY_CLANG) namespace test::nested_namespace::definitions { @@ -842,12 +892,9 @@ namespace cxx17 } -#if !defined(REALLY_CLANG) namespace test_template_argument_deduction_for_class_templates { - // TODO: test it with clang++ from git - template struct pair { @@ -866,7 +913,6 @@ namespace cxx17 } } -#endif // !defined(REALLY_CLANG) namespace test_non_type_auto_template_parameters { @@ -880,12 +926,9 @@ namespace cxx17 } -#if !defined(REALLY_CLANG) namespace test_structured_bindings { - // TODO: test it with clang++ from git - int arr[2] = { 1, 2 }; std::pair pr = { 1, 2 }; @@ -917,14 +960,10 @@ namespace cxx17 const auto [ x3, y3 ] = f3(); } -#endif // !defined(REALLY_CLANG) -#if !defined(REALLY_CLANG) namespace test_exception_spec_type_system { - // TODO: test it with clang++ from git - struct Good {}; struct Bad {}; @@ -942,7 +981,6 @@ namespace cxx17 static_assert (std::is_same_v); } -#endif // !defined(REALLY_CLANG) namespace test_inline_variables { @@ -967,6 +1005,66 @@ namespace cxx17 } // namespace cxx17 -#endif // __cplusplus <= 201402L +#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 201703L + +]]) + + +dnl Tests for new features in C++20 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_20], [[ + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L + +#error "This is not a C++20 compiler" + +#else + +#include + +namespace cxx20 +{ + +// As C++20 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx20 + +#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202002L + +]]) + + +dnl Tests for new features in C++23 + +m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_23], [[ + +#ifndef __cplusplus + +#error "This is not a C++ compiler" + +#elif (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L + +#error "This is not a C++23 compiler" + +#else + +#include + +namespace cxx23 +{ + +// As C++23 supports feature test macros in the standard, there is no +// immediate need to actually test for feature availability on the +// Autoconf side. + +} // namespace cxx23 + +#endif // (defined _MSVC_LANG ? _MSVC_LANG : __cplusplus) < 202302L ]]) diff --git a/m4/ax_cxx_compile_stdcxx_14.m4 b/m4/ax_cxx_compile_stdcxx_14.m4 deleted file mode 100644 index 094db0d025..0000000000 --- a/m4/ax_cxx_compile_stdcxx_14.m4 +++ /dev/null @@ -1,34 +0,0 @@ -# ============================================================================= -# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_14.html -# ============================================================================= -# -# SYNOPSIS -# -# AX_CXX_COMPILE_STDCXX_14([ext|noext], [mandatory|optional]) -# -# DESCRIPTION -# -# Check for baseline language coverage in the compiler for the C++14 -# standard; if necessary, add switches to CXX and CXXCPP to enable -# support. -# -# This macro is a convenience alias for calling the AX_CXX_COMPILE_STDCXX -# macro with the version set to C++14. The two optional arguments are -# forwarded literally as the second and third argument respectively. -# Please see the documentation for the AX_CXX_COMPILE_STDCXX macro for -# more information. If you want to use this macro, you also need to -# download the ax_cxx_compile_stdcxx.m4 file. -# -# LICENSE -# -# Copyright (c) 2015 Moritz Klammler -# -# Copying and distribution of this file, with or without modification, are -# permitted in any medium without royalty provided the copyright notice -# and this notice are preserved. This file is offered as-is, without any -# warranty. - -#serial 5 - -AX_REQUIRE_DEFINED([AX_CXX_COMPILE_STDCXX]) -AC_DEFUN([AX_CXX_COMPILE_STDCXX_14], [AX_CXX_COMPILE_STDCXX([14], [$1], [$2])]) diff --git a/src/bucket/BucketBase.cpp b/src/bucket/BucketBase.cpp index 57e164778d..575738dc4e 100644 --- a/src/bucket/BucketBase.cpp +++ b/src/bucket/BucketBase.cpp @@ -31,9 +31,9 @@ namespace stellar { -template -IndexT const& -BucketBase::getIndex() const +template +BucketBase::IndexT const& +BucketBase::getIndex() const { ZoneScoped; releaseAssertOrThrow(!mFilename.empty()); @@ -41,25 +41,24 @@ BucketBase::getIndex() const return *mIndex; } -template +template bool -BucketBase::isIndexed() const +BucketBase::isIndexed() const { return static_cast(mIndex); } -template +template void -BucketBase::setIndex(std::shared_ptr index) +BucketBase::setIndex(std::shared_ptr index) { releaseAssertOrThrow(!mIndex); mIndex = std::move(index); } -template -BucketBase::BucketBase(std::string const& filename, - Hash const& hash, - std::shared_ptr&& index) +template +BucketBase::BucketBase(std::string const& filename, Hash const& hash, + std::shared_ptr&& index) : mFilename(filename), mHash(hash), mIndex(std::move(index)) { releaseAssert(filename.empty() || fs::exists(filename)); @@ -71,34 +70,34 @@ BucketBase::BucketBase(std::string const& filename, } } -template BucketBase::BucketBase() +template BucketBase::BucketBase() { } -template +template Hash const& -BucketBase::getHash() const +BucketBase::getHash() const { return mHash; } -template +template std::filesystem::path const& -BucketBase::getFilename() const +BucketBase::getFilename() const { return mFilename; } -template +template size_t -BucketBase::getSize() const +BucketBase::getSize() const { return mSize; } -template +template bool -BucketBase::isEmpty() const +BucketBase::isEmpty() const { if (mFilename.empty() || isZero(mHash)) { @@ -109,17 +108,16 @@ BucketBase::isEmpty() const return false; } -template +template void -BucketBase::freeIndex() +BucketBase::freeIndex() { mIndex.reset(); } -template +template std::string -BucketBase::randomFileName(std::string const& tmpDir, - std::string ext) +BucketBase::randomFileName(std::string const& tmpDir, std::string ext) { ZoneScoped; for (;;) @@ -134,16 +132,16 @@ BucketBase::randomFileName(std::string const& tmpDir, } } -template +template std::string -BucketBase::randomBucketName(std::string const& tmpDir) +BucketBase::randomBucketName(std::string const& tmpDir) { return randomFileName(tmpDir, ".xdr"); } -template +template std::string -BucketBase::randomBucketIndexName(std::string const& tmpDir) +BucketBase::randomBucketIndexName(std::string const& tmpDir) { return randomFileName(tmpDir, ".index"); } @@ -181,7 +179,7 @@ BucketBase::randomBucketIndexName(std::string const& tmpDir) // and shadowing protocol simultaneously, the moment the first new-protocol // bucket enters the youngest level. At least one new bucket is in every merge's // shadows from then on in, so they all upgrade (and preserve lifecycle events). -template +template static void calculateMergeProtocolVersion( MergeCounters& mc, uint32_t maxProtocolVersion, @@ -236,8 +234,7 @@ calculateMergeProtocolVersion( // side, or entries that compare non-equal. In all these cases we just // take the lesser (or existing) entry and advance only one iterator, // not scrutinizing the entry type further. -template +template static bool mergeCasesWithDefaultAcceptance( BucketEntryIdCmp const& cmp, MergeCounters& mc, @@ -245,8 +242,6 @@ mergeCasesWithDefaultAcceptance( std::function putFunc, uint32_t protocolVersion, ShadowParams&&... shadowParams) { - BUCKET_TYPE_ASSERT(BucketT); - // Either of: // // - Out of new entries. @@ -283,12 +278,13 @@ mergeCasesWithDefaultAcceptance( return false; } -template +template template void -BucketBase::mergeInternal( - BucketManager& bucketManager, InputSource& inputSource, PutFuncT putFunc, - uint32_t protocolVersion, MergeCounters& mc, ShadowParams&&... shadowParams) +BucketBase::mergeInternal(BucketManager& bucketManager, + InputSource& inputSource, PutFuncT putFunc, + uint32_t protocolVersion, MergeCounters& mc, + ShadowParams&&... shadowParams) { BucketEntryIdCmp cmp; size_t iter = 0; @@ -326,7 +322,7 @@ BucketBase::mergeInternal( #endif } - if (!mergeCasesWithDefaultAcceptance( + if (!mergeCasesWithDefaultAcceptance( cmp, mc, inputSource, putFunc, protocolVersion, shadowParams...)) { @@ -336,18 +332,16 @@ BucketBase::mergeInternal( } } -template +template std::shared_ptr -BucketBase::merge( - BucketManager& bucketManager, uint32_t maxProtocolVersion, - std::shared_ptr const& oldBucket, - std::shared_ptr const& newBucket, - std::vector> const& shadows, - bool keepTombstoneEntries, bool countMergeEvents, asio::io_context& ctx, - bool doFsync) +BucketBase::merge(BucketManager& bucketManager, + uint32_t maxProtocolVersion, + std::shared_ptr const& oldBucket, + std::shared_ptr const& newBucket, + std::vector> const& shadows, + bool keepTombstoneEntries, bool countMergeEvents, + asio::io_context& ctx, bool doFsync) { - BUCKET_TYPE_ASSERT(BucketT); - ZoneScoped; // This is the key operation in the scheme: merging two (read-only) // buckets together into a new 3rd bucket, while calculating its hash, @@ -364,9 +358,9 @@ BucketBase::merge( uint32_t protocolVersion; bool keepShadowedLifecycleEntries = true; - calculateMergeProtocolVersion( - mc, maxProtocolVersion, oi, ni, shadowIterators, protocolVersion, - keepShadowedLifecycleEntries); + calculateMergeProtocolVersion(mc, maxProtocolVersion, oi, ni, + shadowIterators, protocolVersion, + keepShadowedLifecycleEntries); auto timer = bucketManager.getMergeTimer().TimeScope(); BucketMetadata meta; @@ -426,21 +420,23 @@ BucketBase::merge( return out.getBucket(bucketManager, &mk); } -template void BucketBase::mergeInternal< +template void BucketBase::mergeInternal< MemoryMergeInput, std::function, std::vector>&, bool&>( BucketManager&, MemoryMergeInput&, std::function, uint32_t, MergeCounters&, std::vector>&, bool&); -template void -BucketBase::mergeInternal< +template void BucketBase::mergeInternal< MemoryMergeInput, std::function>( BucketManager&, MemoryMergeInput&, std::function, uint32_t, MergeCounters&); -template class BucketBase; -template class BucketBase; +template class BucketBase; +static_assert(std::same_as::IndexT, LiveBucket::IndexT>); +template class BucketBase; +static_assert(std::same_as::IndexT, + HotArchiveBucket::IndexT>); } diff --git a/src/bucket/BucketBase.h b/src/bucket/BucketBase.h index c42285aec1..8509abe820 100644 --- a/src/bucket/BucketBase.h +++ b/src/bucket/BucketBase.h @@ -20,7 +20,7 @@ class io_context; namespace stellar { -template class SearchableBucketListSnapshot; +template class SearchableBucketListSnapshot; /** * Bucket is an immutable container for a sorted set of "Entries" (object ID, @@ -54,22 +54,14 @@ class LiveBucket; class LiveBucketIndex; class HotArchiveBucketIndex; -template -class BucketBase : public NonMovableOrCopyable +template class BucketBase : public NonMovableOrCopyable { - BUCKET_TYPE_ASSERT(BucketT); - + public: // Because of the CRTP design with derived Bucket classes, this base class - // does not have direct access to BucketT::IndexT, so we take two templates - // and make this assert. - static_assert( - std::is_same_v< - IndexT, - std::conditional_t< - std::is_same_v, LiveBucketIndex, - std::conditional_t, - HotArchiveBucketIndex, void>>>, - "IndexT must match BucketT::IndexT"); + // does not have direct access to BucketT::IndexT, so we hardcode the + // index types + using IndexT = std::conditional_t, + LiveBucketIndex, HotArchiveBucketIndex>; protected: std::filesystem::path const mFilename; @@ -169,6 +161,6 @@ class BucketBase : public NonMovableOrCopyable #endif // BUILD_TESTS - template friend class SearchableBucketListSnapshot; + template friend class SearchableBucketListSnapshot; }; } diff --git a/src/bucket/BucketIndexUtils.cpp b/src/bucket/BucketIndexUtils.cpp index 0999c1cfcc..8a72a2fcf2 100644 --- a/src/bucket/BucketIndexUtils.cpp +++ b/src/bucket/BucketIndexUtils.cpp @@ -27,13 +27,11 @@ getPageSizeFromConfig(Config const& cfg) return 1UL << cfg.BUCKETLIST_DB_INDEX_PAGE_SIZE_EXPONENT; } -template +template std::shared_ptr createIndex(BucketManager& bm, std::filesystem::path const& filename, Hash const& hash, asio::io_context& ctx, SHA256* hasher) { - BUCKET_TYPE_ASSERT(BucketT); - ZoneScoped; releaseAssertOrThrow(!filename.empty()); @@ -50,7 +48,7 @@ createIndex(BucketManager& bm, std::filesystem::path const& filename, } } -template +template std::shared_ptr loadIndex(BucketManager const& bm, std::filesystem::path const& filename, std::size_t fileSize) diff --git a/src/bucket/BucketIndexUtils.h b/src/bucket/BucketIndexUtils.h index f18ad45e92..20bc3c1bcc 100644 --- a/src/bucket/BucketIndexUtils.h +++ b/src/bucket/BucketIndexUtils.h @@ -100,7 +100,7 @@ std::streamoff getPageSizeFromConfig(Config const& cfg); // DiskIndex or InMemoryIndex depending on config and Bucket size. // Note: Constructor does not initialize the cache for live bucket indexes, // as this must be done when the Bucket is being added to the BucketList -template +template std::shared_ptr createIndex(BucketManager& bm, std::filesystem::path const& filename, Hash const& hash, asio::io_context& ctx, SHA256* hasher); @@ -109,7 +109,7 @@ createIndex(BucketManager& bm, std::filesystem::path const& filename, // index does not have expected version or pageSize, return null // Note: Constructor does not initialize the cache for live bucket indexes, // as this must be done when the Bucket is being added to the BucketList -template +template std::shared_ptr loadIndex(BucketManager const& bm, std::filesystem::path const& filename, std::size_t fileSize); diff --git a/src/bucket/BucketInputIterator.cpp b/src/bucket/BucketInputIterator.cpp index 7b4eed796a..04d2a345e9 100644 --- a/src/bucket/BucketInputIterator.cpp +++ b/src/bucket/BucketInputIterator.cpp @@ -15,7 +15,7 @@ namespace stellar * Helper class that reads from the file underlying a bucket, keeping the bucket * alive for the duration of its existence. */ -template +template void BucketInputIterator::loadEntry() { @@ -84,47 +84,48 @@ BucketInputIterator::loadEntry() } } -template +template std::streamoff BucketInputIterator::pos() { return mIn.pos(); } -template +template size_t BucketInputIterator::size() const { return mIn.size(); } -template BucketInputIterator::operator bool() const +template +BucketInputIterator::operator bool() const { return mEntryPtr != nullptr; } -template +template typename BucketT::EntryT const& BucketInputIterator::operator*() { return *mEntryPtr; } -template +template bool BucketInputIterator::seenMetadata() const { return mSeenMetadata; } -template +template BucketMetadata const& BucketInputIterator::getMetadata() const { return mMetadata; } -template +template BucketInputIterator::BucketInputIterator( std::shared_ptr bucket) : mBucket(bucket), mEntryPtr(nullptr), mSeenMetadata(false) @@ -145,12 +146,13 @@ BucketInputIterator::BucketInputIterator( } } -template BucketInputIterator::~BucketInputIterator() +template +BucketInputIterator::~BucketInputIterator() { mIn.close(); } -template +template BucketInputIterator& BucketInputIterator::operator++() { @@ -165,7 +167,7 @@ BucketInputIterator::operator++() return *this; } -template +template void BucketInputIterator::seek(std::streamoff offset) { diff --git a/src/bucket/BucketInputIterator.h b/src/bucket/BucketInputIterator.h index 3f5c969375..e357de5c36 100644 --- a/src/bucket/BucketInputIterator.h +++ b/src/bucket/BucketInputIterator.h @@ -17,9 +17,8 @@ class LiveBucket; class HotArchiveBucket; // Helper class that reads through the entries in a bucket. -template class BucketInputIterator +template class BucketInputIterator { - BUCKET_TYPE_ASSERT(BucketT); std::shared_ptr mBucket; diff --git a/src/bucket/BucketListBase.cpp b/src/bucket/BucketListBase.cpp index 55dad3fe7f..e749540158 100644 --- a/src/bucket/BucketListBase.cpp +++ b/src/bucket/BucketListBase.cpp @@ -22,7 +22,7 @@ namespace stellar { -template +template BucketLevel::BucketLevel(uint32_t i) : mLevel(i) , mNextCurr(FutureBucket()) @@ -31,7 +31,7 @@ BucketLevel::BucketLevel(uint32_t i) { } -template +template uint256 BucketLevel::getHash() const { @@ -41,7 +41,7 @@ BucketLevel::getHash() const return hsh.finish(); } -template +template FutureBucket const& BucketLevel::getNext() const { @@ -49,7 +49,7 @@ BucketLevel::getNext() const return std::get>(mNextCurr); } -template +template FutureBucket& BucketLevel::getNext() { @@ -57,7 +57,7 @@ BucketLevel::getNext() return std::get>(mNextCurr); } -template +template void BucketLevel::setNext(FutureBucket const& fb) { @@ -65,7 +65,7 @@ BucketLevel::setNext(FutureBucket const& fb) mNextCurr = fb; } -template +template void BucketLevel::setNextInMemory(std::shared_ptr&& bucket) { @@ -73,28 +73,28 @@ BucketLevel::setNextInMemory(std::shared_ptr&& bucket) mNextCurr = std::move(bucket); } -template +template void BucketLevel::clearNext() { mNextCurr = FutureBucket(); } -template +template std::shared_ptr BucketLevel::getCurr() const { return mCurr; } -template +template std::shared_ptr BucketLevel::getSnap() const { return mSnap; } -template +template void BucketLevel::setCurr(std::shared_ptr b) { @@ -102,11 +102,11 @@ BucketLevel::setCurr(std::shared_ptr b) mCurr = b; } -template BucketListBase::~BucketListBase() +template BucketListBase::~BucketListBase() { } -template +template bool BucketListBase::shouldMergeWithEmptyCurr(uint32_t ledger, uint32_t level) @@ -135,7 +135,7 @@ BucketListBase::shouldMergeWithEmptyCurr(uint32_t ledger, return false; } -template +template void BucketLevel::setSnap(std::shared_ptr b) { @@ -143,28 +143,28 @@ BucketLevel::setSnap(std::shared_ptr b) mSnap = b; } -template +template bool BucketLevel::hasInMemoryMerge() const { return std::holds_alternative>(mNextCurr); } -template +template bool BucketLevel::hasFutureBucketMerge() const { return std::holds_alternative>(mNextCurr); } -template +template bool BucketLevel::hasInProgressMerge() const { return hasInMemoryMerge() || getNext().isMerging(); } -template +template void BucketLevel::commit() { @@ -287,7 +287,7 @@ BucketLevel::prepareFirstLevel( // ---------------------------------------------------------------------------------------- // ... // clang-format on -template +template void BucketLevel::prepare( Application& app, uint32_t currLedger, uint32_t currLedgerProtocol, @@ -315,7 +315,7 @@ BucketLevel::prepare( releaseAssert(getNext().isMerging()); } -template +template std::shared_ptr BucketLevel::snap() { @@ -356,7 +356,7 @@ operator uint32_t() const // levelSize(8) = 262144=0x040000 // levelSize(9) = 1048576=0x100000 // levelSize(10) = 4194304=0x400000 -template +template uint32_t BucketListBase::levelSize(uint32_t level) { @@ -379,14 +379,14 @@ BucketListBase::levelSize(uint32_t level) // levelHalf(8) = 131072=0x020000 // levelHalf(9) = 524288=0x080000 // levelHalf(10) = 2097152=0x200000 -template +template uint32_t BucketListBase::levelHalf(uint32_t level) { return levelSize(level) >> 1; } -template +template uint32_t BucketListBase::sizeOfCurr(uint32_t ledger, uint32_t level) { @@ -436,7 +436,7 @@ BucketListBase::sizeOfCurr(uint32_t ledger, uint32_t level) } } -template +template uint32_t BucketListBase::sizeOfSnap(uint32_t ledger, uint32_t level) { @@ -463,7 +463,7 @@ BucketListBase::sizeOfSnap(uint32_t ledger, uint32_t level) } } -template +template uint32_t BucketListBase::oldestLedgerInCurr(uint32_t ledger, uint32_t level) { @@ -484,7 +484,7 @@ BucketListBase::oldestLedgerInCurr(uint32_t ledger, uint32_t level) return count + 1; } -template +template uint32_t BucketListBase::oldestLedgerInSnap(uint32_t ledger, uint32_t level) { @@ -504,7 +504,7 @@ BucketListBase::oldestLedgerInSnap(uint32_t ledger, uint32_t level) return count + 1; } -template +template uint256 BucketListBase::getHash() const { @@ -536,7 +536,7 @@ BucketListBase::getHash() const // // clang-format on -template +template bool BucketListBase::levelShouldSpill(uint32_t ledger, uint32_t level) { @@ -555,7 +555,7 @@ BucketListBase::levelShouldSpill(uint32_t ledger, uint32_t level) // spill frequency of the level below. // incoming_spill_frequency(i) = 2^(2i - 1) for i > 0 // incoming_spill_frequency(0) = 1 -template +template uint32_t BucketListBase::bucketUpdatePeriod(uint32_t level, bool isCurr) { @@ -574,21 +574,21 @@ BucketListBase::bucketUpdatePeriod(uint32_t level, bool isCurr) return 1u << (2 * level - 1); } -template +template bool BucketListBase::keepTombstoneEntries(uint32_t level) { return level < BucketListBase::kNumLevels - 1; } -template +template BucketLevel const& BucketListBase::getLevel(uint32_t i) const { return mLevels.at(i); } -template +template BucketLevel& BucketListBase::getLevel(uint32_t i) { @@ -596,7 +596,7 @@ BucketListBase::getLevel(uint32_t i) } #ifdef BUILD_TESTS -template +template void BucketListBase::resolveAllFutures() { @@ -611,7 +611,7 @@ BucketListBase::resolveAllFutures() } #endif -template +template void BucketListBase::resolveAnyReadyFutures() { @@ -625,7 +625,7 @@ BucketListBase::resolveAnyReadyFutures() } } -template +template bool BucketListBase::futuresAllResolved(uint32_t maxLevel) const { @@ -642,7 +642,7 @@ BucketListBase::futuresAllResolved(uint32_t maxLevel) const return true; } -template +template uint32_t BucketListBase::getMaxMergeLevel(uint32_t currLedger) const { @@ -657,7 +657,7 @@ BucketListBase::getMaxMergeLevel(uint32_t currLedger) const return i; } -template +template uint64_t BucketListBase::getSize() const { @@ -678,7 +678,7 @@ BucketListBase::getSize() const return sum; } -template +template template void BucketListBase::addBatchInternal(Application& app, uint32_t currLedger, @@ -796,7 +796,7 @@ BucketListBase::addBatchInternal(Application& app, uint32_t currLedger, } } -template +template void BucketListBase::restartMerges(Application& app, uint32_t maxProtocolVersion, @@ -870,7 +870,7 @@ BucketListBase::restartMerges(Application& app, } } -template BucketListBase::BucketListBase() +template BucketListBase::BucketListBase() { for (uint32_t i = 0; i < kNumLevels; ++i) { diff --git a/src/bucket/BucketListBase.h b/src/bucket/BucketListBase.h index 4f57dcc111..e8088d4719 100644 --- a/src/bucket/BucketListBase.h +++ b/src/bucket/BucketListBase.h @@ -353,13 +353,11 @@ struct InflationWinner; namespace testutil { -template class BucketListDepthModifier; +template class BucketListDepthModifier; } -template class BucketLevel +template class BucketLevel { - BUCKET_TYPE_ASSERT(BucketT); - uint32_t mLevel; // Variant to hold either a FutureBucket (for async merges) or a // shared_ptr (for in-memory merges) @@ -417,7 +415,8 @@ class BucketListDepth operator uint32_t() const; - template friend class testutil::BucketListDepthModifier; + template + friend class testutil::BucketListDepthModifier; }; // While every BucketList shares the same high level structure wrt to spill @@ -426,10 +425,8 @@ class BucketListDepth // entry level. This abstract base class defines the shared structure of all // BucketLists. It must be extended for each specific BucketList type, where the // template parameter BucketT refers to the underlying Bucket type. -template class BucketListBase +template class BucketListBase { - BUCKET_TYPE_ASSERT(BucketT); - protected: std::vector> mLevels; diff --git a/src/bucket/BucketListSnapshot.cpp b/src/bucket/BucketListSnapshot.cpp index eae919bc06..fb721e193d 100644 --- a/src/bucket/BucketListSnapshot.cpp +++ b/src/bucket/BucketListSnapshot.cpp @@ -24,13 +24,13 @@ namespace stellar // BucketListSnapshotData // -template +template BucketListSnapshotData::Level::Level(BucketLevel const& level) : curr(level.getCurr()), snap(level.getSnap()) { } -template +template BucketListSnapshotData::Level::Level( std::shared_ptr currBucket, std::shared_ptr snapBucket) @@ -38,7 +38,7 @@ BucketListSnapshotData::Level::Level( { } -template +template BucketListSnapshotData::BucketListSnapshotData( BucketListBase const& bl, LedgerHeader const& header) : levels([&bl]() { @@ -54,7 +54,7 @@ BucketListSnapshotData::BucketListSnapshotData( { } -template +template uint32_t BucketListSnapshotData::getLedgerSeq() const { @@ -65,7 +65,7 @@ BucketListSnapshotData::getLedgerSeq() const // SearchableBucketListSnapshot // -template +template SearchableBucketListSnapshot::SearchableBucketListSnapshot( MetricsRegistry& metrics, std::shared_ptr const> data, @@ -89,7 +89,7 @@ SearchableBucketListSnapshot::SearchableBucketListSnapshot( // File streams are fairly expensive to create, so they are lazily created and // stored in mStreams. -template +template XDRInputFileStream& SearchableBucketListSnapshot::getStream( std::shared_ptr const& bucket) const @@ -108,7 +108,7 @@ SearchableBucketListSnapshot::getStream( // Loads an entry from the bucket file at the given offset. Returns a pair of // (entry, bloomMiss) where bloomMiss is true if the bloom filter indicated the // key might exist but it wasn't actually found (a false positive). -template +template std::pair, bool> SearchableBucketListSnapshot::getEntryAtOffset( std::shared_ptr const& bucket, LedgerKey const& k, @@ -139,7 +139,7 @@ SearchableBucketListSnapshot::getEntryAtOffset( // Looks up a single key in a bucket using its index. Returns (entry, bloomMiss) // where entry is nullptr if not found, and bloomMiss indicates a bloom filter // false positive (key appeared to exist but wasn't actually in the bucket). -template +template std::pair, bool> SearchableBucketListSnapshot::getBucketEntry( std::shared_ptr const& bucket, LedgerKey const& k) const @@ -178,7 +178,7 @@ SearchableBucketListSnapshot::getBucketEntry( // remove it from keys so that later buckets do not load shadowed entries. If we // don't find the entry, we keep it in keys so it will be searched for in lower // levels. -template +template void SearchableBucketListSnapshot::loadKeysFromBucket( std::shared_ptr const& bucket, @@ -249,7 +249,7 @@ SearchableBucketListSnapshot::loadKeysFromBucket( } } -template +template template void SearchableBucketListSnapshot::loopAllBuckets( @@ -274,7 +274,7 @@ SearchableBucketListSnapshot::loopAllBuckets( } } -template +template template void SearchableBucketListSnapshot::loopAllBuckets(Func&& f) const @@ -283,7 +283,7 @@ SearchableBucketListSnapshot::loopAllBuckets(Func&& f) const loopAllBuckets(std::forward(f), *mData); } -template +template std::shared_ptr SearchableBucketListSnapshot::load(LedgerKey const& k) const { @@ -318,7 +318,7 @@ SearchableBucketListSnapshot::load(LedgerKey const& k) const return result; } -template +template std::optional> SearchableBucketListSnapshot::loadKeysInternal( std::set const& inKeys, @@ -354,7 +354,7 @@ SearchableBucketListSnapshot::loadKeysInternal( return entries; } -template +template std::optional> SearchableBucketListSnapshot::loadKeysFromLedger( std::set const& inKeys, @@ -363,7 +363,7 @@ SearchableBucketListSnapshot::loadKeysFromLedger( return loadKeysInternal(inKeys, ledgerSeq); } -template +template medida::Timer& SearchableBucketListSnapshot::getBulkLoadTimer( std::string const& label, size_t numEntries) const @@ -384,7 +384,7 @@ SearchableBucketListSnapshot::getBulkLoadTimer( return iter->second; } -template +template uint32_t SearchableBucketListSnapshot::getLedgerSeq() const { @@ -392,7 +392,7 @@ SearchableBucketListSnapshot::getLedgerSeq() const return mData->getLedgerSeq(); } -template +template LedgerHeader const& SearchableBucketListSnapshot::getLedgerHeader() const { @@ -400,14 +400,14 @@ SearchableBucketListSnapshot::getLedgerHeader() const return mData->header; } -template +template std::shared_ptr const> const& SearchableBucketListSnapshot::getSnapshotData() const { return mData; } -template +template std::map const>> const& SearchableBucketListSnapshot::getHistoricalSnapshots() const diff --git a/src/bucket/BucketListSnapshot.h b/src/bucket/BucketListSnapshot.h index 0412a5f966..bf62473a59 100644 --- a/src/bucket/BucketListSnapshot.h +++ b/src/bucket/BucketListSnapshot.h @@ -41,16 +41,14 @@ struct EvictionResultEntry; struct InflationWinner; struct StateArchivalSettings; class EvictionStatistics; -template class BucketListBase; -template class BucketLevel; +template class BucketListBase; +template class BucketLevel; // BucketListSnapshotData holds the immutable snapshot data that can be safely // shared across threads. It contains bucket references and the ledger header, // but no mutable state like file streams. -template struct BucketListSnapshotData +template struct BucketListSnapshotData { - BUCKET_TYPE_ASSERT(BucketT); - struct Level { std::shared_ptr const curr; @@ -78,10 +76,8 @@ template struct BucketListSnapshotData // - A single snapshot instance must only be used by one thread at a time. // - The underlying snapshot data (shared via shared_ptr) is immutable and // can be safely shared. -template class SearchableBucketListSnapshot +template class SearchableBucketListSnapshot { - BUCKET_TYPE_ASSERT(BucketT); - protected: // Shared immutable snapshot data std::shared_ptr const> mData; diff --git a/src/bucket/BucketManager.cpp b/src/bucket/BucketManager.cpp index c25e93ab3e..5cf955e1ea 100644 --- a/src/bucket/BucketManager.cpp +++ b/src/bucket/BucketManager.cpp @@ -331,20 +331,18 @@ BucketManager::getMergeTimer() return mBucketSnapMerge; } -template +template medida::Meter& BucketManager::getBloomMissMeter() const { - BUCKET_TYPE_ASSERT(BucketT); return mAppConnector.getMetrics().NewMeter( {BucketT::METRIC_STRING, "bloom", "misses"}, "bloom"); } -template +template medida::Meter& BucketManager::getBloomLookupMeter() const { - BUCKET_TYPE_ASSERT(BucketT); return mAppConnector.getMetrics().NewMeter( {BucketT::METRIC_STRING, "bloom", "lookups"}, "bloom"); } @@ -484,7 +482,7 @@ BucketManager::adoptFileAsBucket( mHotArchiveBucketFutures, std::move(inMemoryState)); } -template +template std::shared_ptr BucketManager::adoptFileAsBucketInternal( std::string const& filename, uint256 const& hash, MergeKey* mergeKey, @@ -492,7 +490,6 @@ BucketManager::adoptFileAsBucketInternal( BucketMapT& bucketMap, FutureMapT& futureMap, std::unique_ptr> inMemoryState) { - BUCKET_TYPE_ASSERT(BucketT); ZoneScoped; if (mergeKey) @@ -588,13 +585,11 @@ BucketManager::noteEmptyMergeOutput(MergeKey const& mergeKey) noteEmptyMergeOutputInternal(mergeKey, mHotArchiveBucketFutures); } -template +template void BucketManager::noteEmptyMergeOutputInternal(MergeKey const& mergeKey, FutureMapT& futureMap) { - BUCKET_TYPE_ASSERT(BucketT); - // We _do_ want to remove the mergeKey from mLiveFutures, both so that that // map does not grow without bound and more importantly so that we drop the // refcount on the input buckets so they get GC'ed from the bucket dir. @@ -624,12 +619,11 @@ BucketManager::getBucketIfExists(uint256 const& hash) return getBucketIfExistsInternal(hash, mSharedHotArchiveBuckets); } -template +template std::shared_ptr BucketManager::getBucketIfExistsInternal( uint256 const& hash, BucketMapT const& bucketMap) const { - BUCKET_TYPE_ASSERT(BucketT); ZoneScoped; auto i = bucketMap.find(hash); if (i != bucketMap.end()) @@ -659,12 +653,11 @@ BucketManager::getBucketByHash(uint256 const& hash) return getBucketByHashInternal(hash, mSharedHotArchiveBuckets); } -template +template std::shared_ptr BucketManager::getBucketByHashInternal(uint256 const& hash, BucketMapT& bucketMap) { - BUCKET_TYPE_ASSERT(BucketT); ZoneScoped; if (isZero(hash)) { @@ -710,12 +703,11 @@ BucketManager::getMergeFuture(MergeKey const& key) return getMergeFutureInternal(key, mHotArchiveBucketFutures); } -template +template std::shared_future> BucketManager::getMergeFutureInternal(MergeKey const& key, FutureMapT& futureMap) { - BUCKET_TYPE_ASSERT(BucketT); ZoneScoped; MergeCounters mc; auto i = futureMap.find(key); @@ -775,13 +767,12 @@ BucketManager::putMergeFuture( putMergeFutureInternal(key, future, mHotArchiveBucketFutures); } -template +template void BucketManager::putMergeFutureInternal( MergeKey const& key, std::shared_future> future, FutureMapT& futureMap) { - BUCKET_TYPE_ASSERT(BucketT); ZoneScoped; CLOG_TRACE( Bucket, @@ -1144,7 +1135,7 @@ BucketManager::snapshotLedger(LedgerHeader& currentHeader) calculateSkipValues(currentHeader); } -template +template void BucketManager::maybeSetIndex( std::shared_ptr b, @@ -1523,7 +1514,7 @@ loadEntriesFromHotArchiveBucket(std::shared_ptr b, b->getSize(), name, ms, formatSize(bytesPerSec)); } -template +template std::map BucketManager::loadCompleteBucketListStateHelper( std::vector> const& buckets, @@ -1601,7 +1592,7 @@ BucketManager::mergeBuckets(asio::io_context& ctx, return out.getBucket(*this); } -template +template static bool visitBucketEntries(bool visitShadowedEntries, std::shared_ptr b, std::string const& name, std::optional minLedger, diff --git a/src/bucket/BucketManager.h b/src/bucket/BucketManager.h index 24da0e171c..62d4e64f27 100644 --- a/src/bucket/BucketManager.h +++ b/src/bucket/BucketManager.h @@ -68,10 +68,10 @@ struct HistoryArchiveState; */ class BucketManager : NonMovableOrCopyable { - template + template using BucketMapT = std::map>; - template + template using FutureMapT = UnorderedMap>>; @@ -158,7 +158,7 @@ class BucketManager : NonMovableOrCopyable void updateSharedBucketSize(); - template + template std::shared_ptr adoptFileAsBucketInternal( std::string const& filename, uint256 const& hash, MergeKey* mergeKey, std::shared_ptr index, @@ -166,36 +166,36 @@ class BucketManager : NonMovableOrCopyable std::unique_ptr> inMemoryState) REQUIRES(mBucketMutex); - template + template std::shared_ptr getBucketByHashInternal(uint256 const& hash, BucketMapT& bucketMap) REQUIRES(mBucketMutex); - template + template std::shared_ptr getBucketIfExistsInternal(uint256 const& hash, BucketMapT const& bucketMap) const REQUIRES(mBucketMutex); - template + template std::shared_future> getMergeFutureInternal(MergeKey const& key, FutureMapT& futureMap) REQUIRES(mBucketMutex); - template + template void putMergeFutureInternal(MergeKey const& key, std::shared_future> future, FutureMapT& futureMap) REQUIRES(mBucketMutex); - template + template void noteEmptyMergeOutputInternal(MergeKey const& mergeKey, FutureMapT& futureMap) REQUIRES(mBucketMutex); void reportLiveBucketIndexCacheMetrics(); - template + template std::map loadCompleteBucketListStateHelper( std::vector> const& buckets, std::function, std::string const&, @@ -239,15 +239,16 @@ class BucketManager : NonMovableOrCopyable medida::Timer& getMergeTimer(); - template medida::Meter& getBloomMissMeter() const; - template medida::Meter& getBloomLookupMeter() const; + template medida::Meter& getBloomMissMeter() const; + template medida::Meter& getBloomLookupMeter() const; medida::Meter& getCacheHitMeter() const; medida::Meter& getCacheMissMeter() const; // Reading and writing the merge counters is done in bulk, and takes a lock // briefly; this can be done from any thread. - template MergeCounters readMergeCounters(); - template void incrMergeCounters(MergeCounters const& delta); + template MergeCounters readMergeCounters(); + template + void incrMergeCounters(MergeCounters const& delta); // Get a reference to a persistent bucket (in the BucketManager's bucket // directory), from the BucketManager's shared bucket-set. @@ -260,7 +261,7 @@ class BucketManager : NonMovableOrCopyable // This method is mostly-threadsafe -- assuming you don't destruct the // BucketManager mid-call -- and is intended to be called from both main and // worker threads. Very carefully. - template + template std::shared_ptr adoptFileAsBucket( std::string const& filename, uint256 const& hash, MergeKey* mergeKey, std::shared_ptr index, @@ -272,16 +273,16 @@ class BucketManager : NonMovableOrCopyable // doesn't correspond to a file on disk; the method forgets about the // `FutureBucket` associated with the in-progress merge, allowing the merge // inputs to be GC'ed. - template + template void noteEmptyMergeOutput(MergeKey const& mergeKey); // Returns a bucket by hash if it exists and is currently managed by the // bucket list. - template + template std::shared_ptr getBucketIfExists(uint256 const& hash); // Return a bucket by hash if we have it, else return nullptr. - template + template std::shared_ptr getBucketByHash(uint256 const& hash); // Get a reference to a merge-future that's either running (or finished @@ -289,7 +290,7 @@ class BucketManager : NonMovableOrCopyable // merges and/or a set of records mapping merge inputs to outputs and the // set of outputs held in the BucketManager. Returns an invalid future if no // such future can be found or synthesized. - template + template std::shared_future> getMergeFuture(MergeKey const& key); @@ -298,7 +299,7 @@ class BucketManager : NonMovableOrCopyable // There is no corresponding entry-removal API: the std::shared_future will // be removed from the map when the merge completes and the output file is // adopted. - template + template void putMergeFuture(MergeKey const& key, std::shared_future> future); @@ -334,7 +335,7 @@ class BucketManager : NonMovableOrCopyable // for each bucket. However, during startup there are race conditions where // a bucket may be indexed twice. If there is an index race, set index with // this function, otherwise use BucketBase::setIndex(). - template + template void maybeSetIndex(std::shared_ptr b, std::shared_ptr index); diff --git a/src/bucket/BucketMergeAdapter.h b/src/bucket/BucketMergeAdapter.h index 5dc9760132..5ab34963c2 100644 --- a/src/bucket/BucketMergeAdapter.h +++ b/src/bucket/BucketMergeAdapter.h @@ -14,7 +14,7 @@ namespace stellar // These classes provide wrappers around the inputs to a BucketMerge, namely // either BucketInputIterators for file based merges, or a vector of bucket // entries for in-memory merges. -template class MergeInput +template class MergeInput { public: // Check if we're done - both iterators are exhausted @@ -39,7 +39,8 @@ template class MergeInput virtual ~MergeInput() = default; }; -template class FileMergeInput : public MergeInput +template +class FileMergeInput : public MergeInput { private: BucketInputIterator& mOldIter; @@ -103,7 +104,8 @@ template class FileMergeInput : public MergeInput } }; -template class MemoryMergeInput : public MergeInput +template +class MemoryMergeInput : public MergeInput { private: std::vector const& mOldEntries; diff --git a/src/bucket/BucketOutputIterator.cpp b/src/bucket/BucketOutputIterator.cpp index 6645f51143..176e015269 100644 --- a/src/bucket/BucketOutputIterator.cpp +++ b/src/bucket/BucketOutputIterator.cpp @@ -21,7 +21,7 @@ namespace stellar * Helper class that points to an output tempfile. Absorbs BucketEntries and * hashes them while writing to either destination. Produces a Bucket when done. */ -template +template BucketOutputIterator::BucketOutputIterator(std::string const& tmpDir, bool keepTombstoneEntries, BucketMetadata const& meta, @@ -73,7 +73,7 @@ BucketOutputIterator::BucketOutputIterator(std::string const& tmpDir, } } -template +template void BucketOutputIterator::put(typename BucketT::EntryT const& e) { @@ -164,7 +164,7 @@ BucketOutputIterator::put(typename BucketT::EntryT const& e) *mBuf = e; } -template +template std::shared_ptr BucketOutputIterator::getBucket( BucketManager& bucketManager, MergeKey* mergeKey, diff --git a/src/bucket/BucketOutputIterator.h b/src/bucket/BucketOutputIterator.h index a76e1c6bb7..768337537c 100644 --- a/src/bucket/BucketOutputIterator.h +++ b/src/bucket/BucketOutputIterator.h @@ -20,10 +20,8 @@ class BucketManager; // Helper class that writes new elements to a file and returns a bucket // when finished. -template class BucketOutputIterator +template class BucketOutputIterator { - BUCKET_TYPE_ASSERT(BucketT); - protected: std::filesystem::path mFilename; XDROutputFileStream mOut; diff --git a/src/bucket/BucketUtils.cpp b/src/bucket/BucketUtils.cpp index bc0358e683..e438b90b36 100644 --- a/src/bucket/BucketUtils.cpp +++ b/src/bucket/BucketUtils.cpp @@ -322,7 +322,7 @@ isBucketMetaEntry(LiveBucket::EntryT const& be) return be.type() == METAENTRY; } -template +template void BucketEntryCounters::count(typename BucketT::EntryT const& be) { diff --git a/src/bucket/BucketUtils.h b/src/bucket/BucketUtils.h index 16c404838d..20239389fd 100644 --- a/src/bucket/BucketUtils.h +++ b/src/bucket/BucketUtils.h @@ -30,10 +30,9 @@ class HotArchiveBucket; class SearchableLiveBucketListSnapshot; class SearchableHotArchiveBucketListSnapshot; -#define BUCKET_TYPE_ASSERT(BucketT) \ - static_assert(std::is_same_v || \ - std::is_same_v, \ - "BucketT must be a Bucket type") +template +concept IsBucketType = + std::same_as || std::same_as; using SearchableSnapshotConstPtr = std::shared_ptr; @@ -204,7 +203,8 @@ struct BucketEntryCounters std::map entryTypeCounts; std::map entryTypeSizes; - template void count(typename BucketT::EntryT const& be); + template + void count(typename BucketT::EntryT const& be); BucketEntryCounters& operator+=(BucketEntryCounters const& other); bool operator==(BucketEntryCounters const& other) const; bool operator!=(BucketEntryCounters const& other) const; diff --git a/src/bucket/DiskIndex.cpp b/src/bucket/DiskIndex.cpp index 158bc1a663..7d7dca5fe4 100644 --- a/src/bucket/DiskIndex.cpp +++ b/src/bucket/DiskIndex.cpp @@ -56,7 +56,7 @@ upper_bound_pred(LedgerKey const& key, RangeIndex::value_type const& indexEntry) } } -template +template std::pair::IterT> DiskIndex::scan(IterT start, LedgerKey const& k) const { @@ -85,7 +85,7 @@ DiskIndex::scan(IterT start, LedgerKey const& k) const } } -template +template std::optional> DiskIndex::getOffsetBounds(LedgerKey const& lowerBound, LedgerKey const& upperBound) const @@ -116,7 +116,7 @@ DiskIndex::getOffsetBounds(LedgerKey const& lowerBound, return std::make_pair(startOff, endOff); } -template +template std::optional> DiskIndex::getRangeForType(LedgerEntryType type) const { @@ -129,7 +129,7 @@ DiskIndex::getRangeForType(LedgerEntryType type) const return std::nullopt; } -template +template DiskIndex::DiskIndex(BucketManager& bm, std::filesystem::path const& filename, std::streamoff pageSize, Hash const& hash, @@ -299,7 +299,7 @@ DiskIndex::DiskIndex(BucketManager& bm, } } -template +template template DiskIndex::DiskIndex(Archive& ar, BucketManager const& bm, std::streamoff pageSize) @@ -320,7 +320,7 @@ DiskIndex::DiskIndex(Archive& ar, BucketManager const& bm, } } -template +template void DiskIndex::saveToDisk(BucketManager& bm, Hash const& hash, asio::io_context& ctx) const @@ -371,7 +371,7 @@ DiskIndex::saveToDisk(BucketManager& bm, Hash const& hash, } } -template +template void DiskIndex::markBloomMiss() const { @@ -379,7 +379,7 @@ DiskIndex::markBloomMiss() const } #ifdef BUILD_TESTS -template +template bool DiskIndex::operator==(DiskIndex const& in) const { diff --git a/src/bucket/DiskIndex.h b/src/bucket/DiskIndex.h index 591456b113..0a6c7c2a61 100644 --- a/src/bucket/DiskIndex.h +++ b/src/bucket/DiskIndex.h @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -67,9 +68,8 @@ using RangeIndex = std::vector>; // random eviction cache for partial caching, and a range based index + binary // fuse filter for disk lookups. Creating this index is expensive, so we persist // it to disk. We do not persist the random eviction cache. -template class DiskIndex : public NonMovableOrCopyable +template class DiskIndex : public NonMovableOrCopyable { - BUCKET_TYPE_ASSERT(BucketT); // Fields from here are persisted on disk. Cereal doesn't like templates so // we define an inner struct to hold all serializable fields. @@ -180,14 +180,13 @@ template class DiskIndex : public NonMovableOrCopyable ar(version, pageSize); } - // This messy template makes is such that this function is only defined + // This concept template makes is such that this function is only defined // when BucketT == LiveBucket - template , bool> = true> + template + requires std::same_as && std::same_as AssetPoolIDMap const& getAssetPoolIDMap() const { - static_assert(std::is_same_v); releaseAssert(mData.assetToPoolID); return *mData.assetToPoolID; } diff --git a/src/bucket/FutureBucket.cpp b/src/bucket/FutureBucket.cpp index 68f00c72c5..12eb8a277a 100644 --- a/src/bucket/FutureBucket.cpp +++ b/src/bucket/FutureBucket.cpp @@ -32,7 +32,7 @@ namespace stellar { -template +template FutureBucket::FutureBucket( Application& app, std::shared_ptr const& curr, std::shared_ptr const& snap, @@ -82,7 +82,7 @@ FutureBucket::FutureBucket( startMerge(app, maxProtocolVersion, countMergeEvents, level); } -template +template void FutureBucket::setLiveOutput(std::shared_ptr output) { @@ -93,14 +93,14 @@ FutureBucket::setLiveOutput(std::shared_ptr output) checkState(); } -template +template static void checkHashEq(std::shared_ptr const& b, std::string const& h) { releaseAssert(b->getHash() == hexToBin256(h)); } -template +template void FutureBucket::checkHashesMatch() const { @@ -135,7 +135,7 @@ FutureBucket::checkHashesMatch() const * the different hash-only states are mutually exclusive with each other and * with live values. */ -template +template void FutureBucket::checkState() const { @@ -196,7 +196,7 @@ FutureBucket::checkState() const } } -template +template void FutureBucket::clearInputs() { @@ -209,7 +209,7 @@ FutureBucket::clearInputs() mInputCurrBucketHash.clear(); } -template +template void FutureBucket::clearOutput() { @@ -220,7 +220,7 @@ FutureBucket::clearOutput() mOutputBucket.reset(); } -template +template void FutureBucket::clear() { @@ -229,35 +229,35 @@ FutureBucket::clear() clearOutput(); } -template +template bool FutureBucket::isLive() const { return (mState == FB_LIVE_INPUTS || mState == FB_LIVE_OUTPUT); } -template +template bool FutureBucket::isMerging() const { return mState == FB_LIVE_INPUTS; } -template +template bool FutureBucket::hasHashes() const { return (mState == FB_HASH_INPUTS || mState == FB_HASH_OUTPUT); } -template +template bool FutureBucket::isClear() const { return mState == FB_CLEAR; } -template +template bool FutureBucket::mergeComplete() const { @@ -271,7 +271,7 @@ FutureBucket::mergeComplete() const return futureIsReady(mOutputBucketFuture); } -template +template std::shared_ptr FutureBucket::resolve() { @@ -303,7 +303,7 @@ FutureBucket::resolve() return mOutputBucket; } -template +template bool FutureBucket::hasOutputHash() const { @@ -315,7 +315,7 @@ FutureBucket::hasOutputHash() const return false; } -template +template std::string const& FutureBucket::getOutputHash() const { @@ -324,7 +324,7 @@ FutureBucket::getOutputHash() const return mOutputBucketHash; } -template +template static std::chrono::seconds getAvailableTimeForMerge(Application& app, uint32_t level) { @@ -342,7 +342,7 @@ getAvailableTimeForMerge(Application& app, uint32_t level) return closeTime; } -template +template void FutureBucket::startMerge(Application& app, uint32_t maxProtocolVersion, bool countMergeEvents, uint32_t level) @@ -460,7 +460,7 @@ FutureBucket::startMerge(Application& app, uint32_t maxProtocolVersion, checkState(); } -template +template void FutureBucket::makeLive(Application& app, uint32_t maxProtocolVersion, uint32_t level) @@ -499,7 +499,7 @@ FutureBucket::makeLive(Application& app, uint32_t maxProtocolVersion, } } -template +template std::vector FutureBucket::getHashes() const { diff --git a/src/bucket/FutureBucket.h b/src/bucket/FutureBucket.h index e052fabc46..1cca781b2e 100644 --- a/src/bucket/FutureBucket.h +++ b/src/bucket/FutureBucket.h @@ -34,9 +34,8 @@ class HotArchiveBucket; * the bottom of closeLedger; and the HistoryManager, when storing and * retrieving HistoryArchiveStates. */ -template class FutureBucket +template class FutureBucket { - BUCKET_TYPE_ASSERT(BucketT); // There are two lifecycles of a FutureBucket: // diff --git a/src/bucket/HotArchiveBucket.h b/src/bucket/HotArchiveBucket.h index 72ac936b0d..6e2394744c 100644 --- a/src/bucket/HotArchiveBucket.h +++ b/src/bucket/HotArchiveBucket.h @@ -13,8 +13,8 @@ namespace stellar { class HotArchiveBucket; -template class BucketOutputIterator; -template class BucketInputIterator; +template class BucketOutputIterator; +template class BucketInputIterator; typedef BucketInputIterator HotArchiveBucketInputIterator; typedef BucketOutputIterator HotArchiveBucketOutputIterator; @@ -23,9 +23,8 @@ typedef BucketOutputIterator HotArchiveBucketOutputIterator; * Hot Archive Buckets are used by the HotBucketList to store recently evicted * entries. They contain entries of type HotArchiveBucketEntry. */ -class HotArchiveBucket - : public BucketBase, - public std::enable_shared_from_this +class HotArchiveBucket : public BucketBase, + public std::enable_shared_from_this { public: // Entry type that this bucket stores diff --git a/src/bucket/LedgerCmp.h b/src/bucket/LedgerCmp.h index 1cab91a98c..e74bdd3aff 100644 --- a/src/bucket/LedgerCmp.h +++ b/src/bucket/LedgerCmp.h @@ -128,10 +128,8 @@ struct LedgerEntryIdCmp * LedgerEntries (ignoring their hashes, as the LedgerEntryIdCmp ignores their * bodies). */ -template struct BucketEntryIdCmp +template struct BucketEntryIdCmp { - BUCKET_TYPE_ASSERT(BucketT); - bool compareHotArchive(HotArchiveBucketEntry const& a, HotArchiveBucketEntry const& b) const diff --git a/src/bucket/LiveBucket.h b/src/bucket/LiveBucket.h index fc68867b21..7f71a419d8 100644 --- a/src/bucket/LiveBucket.h +++ b/src/bucket/LiveBucket.h @@ -19,8 +19,8 @@ class AbstractLedgerTxn; class Application; class EvictionStatistics; class LiveBucket; -template class BucketOutputIterator; -template class BucketInputIterator; +template class BucketOutputIterator; +template class BucketInputIterator; typedef BucketOutputIterator LiveBucketOutputIterator; typedef BucketInputIterator LiveBucketInputIterator; @@ -29,7 +29,7 @@ typedef BucketInputIterator LiveBucketInputIterator; * Live Buckets are used by the LiveBucketList to store the current canonical * state of the ledger. They contain entries of type BucketEntry. */ -class LiveBucket : public BucketBase, +class LiveBucket : public BucketBase, public std::enable_shared_from_this { // Stores all BucketEntries (except METAENTRY) in the same order that they diff --git a/src/bucket/test/BucketTestUtils.cpp b/src/bucket/test/BucketTestUtils.cpp index ae0d0f8e26..08a6812941 100644 --- a/src/bucket/test/BucketTestUtils.cpp +++ b/src/bucket/test/BucketTestUtils.cpp @@ -162,7 +162,7 @@ EntryCounts::EntryCounts( } } -template +template size_t countEntries(std::shared_ptr bucket) { diff --git a/src/bucket/test/BucketTestUtils.h b/src/bucket/test/BucketTestUtils.h index 96b57f41f2..f7913c79f6 100644 --- a/src/bucket/test/BucketTestUtils.h +++ b/src/bucket/test/BucketTestUtils.h @@ -29,10 +29,8 @@ uint32_t getAppLedgerVersion(std::shared_ptr app); void for_versions_with_differing_bucket_logic( Config const& cfg, std::function const& f); -template struct EntryCounts +template struct EntryCounts { - BUCKET_TYPE_ASSERT(BucketT); - size_t nMeta{0}; size_t nInitOrArchived{0}; size_t nLive{0}; @@ -51,7 +49,8 @@ template struct EntryCounts EntryCounts(std::shared_ptr bucket); }; -template size_t countEntries(std::shared_ptr bucket); +template +size_t countEntries(std::shared_ptr bucket); Hash closeLedger(Application& app, std::optional skToSignValue, xdr::xvector upgrades = emptyUpgradeSteps); diff --git a/src/catchup/ApplyBucketsWork.h b/src/catchup/ApplyBucketsWork.h index a5d210157c..d456f286e0 100644 --- a/src/catchup/ApplyBucketsWork.h +++ b/src/catchup/ApplyBucketsWork.h @@ -14,7 +14,7 @@ namespace stellar class AssumeStateWork; class LiveBucketList; class Bucket; -template class IndexBucketsWork; +template class IndexBucketsWork; class LiveBucket; struct HistoryArchiveState; struct LedgerHeaderHistoryEntry; diff --git a/src/catchup/IndexBucketsWork.cpp b/src/catchup/IndexBucketsWork.cpp index 2eccfcdc5c..4a2cfb6d81 100644 --- a/src/catchup/IndexBucketsWork.cpp +++ b/src/catchup/IndexBucketsWork.cpp @@ -13,14 +13,14 @@ namespace stellar { -template +template IndexBucketsWork::IndexWork::IndexWork(Application& app, std::shared_ptr b) : BasicWork(app, "index-work", BasicWork::RETRY_NEVER), mBucket(b) { } -template +template BasicWork::State IndexBucketsWork::IndexWork::onRun() { @@ -32,21 +32,21 @@ IndexBucketsWork::IndexWork::onRun() return mState; } -template +template bool IndexBucketsWork::IndexWork::onAbort() { return true; }; -template +template void IndexBucketsWork::IndexWork::onReset() { mState = BasicWork::State::WORK_WAITING; } -template +template void IndexBucketsWork::IndexWork::postWork() { @@ -131,14 +131,14 @@ IndexBucketsWork::IndexWork::postWork() "IndexWork: starting in background"); } -template +template IndexBucketsWork::IndexBucketsWork( Application& app, std::vector> const& buckets) : Work(app, "index-bucketList", BasicWork::RETRY_NEVER), mBuckets(buckets) { } -template +template BasicWork::State IndexBucketsWork::doWork() { @@ -150,14 +150,14 @@ IndexBucketsWork::doWork() return checkChildrenStatus(); } -template +template void IndexBucketsWork::doReset() { mWorkSpawned = false; } -template +template void IndexBucketsWork::spawnWork() { diff --git a/src/catchup/IndexBucketsWork.h b/src/catchup/IndexBucketsWork.h index 99ef5b53ce..1db3010e22 100644 --- a/src/catchup/IndexBucketsWork.h +++ b/src/catchup/IndexBucketsWork.h @@ -4,6 +4,7 @@ #pragma once +#include "bucket/BucketUtils.h" #include "work/BasicWork.h" #include "work/Work.h" #include @@ -15,7 +16,7 @@ class Bucket; class LiveBucketIndex; class BucketManager; -template class IndexBucketsWork : public Work +template class IndexBucketsWork : public Work { class IndexWork : public BasicWork { diff --git a/src/crypto/KeyUtils.h b/src/crypto/KeyUtils.h index dfee295be1..1aa33dc2a3 100644 --- a/src/crypto/KeyUtils.h +++ b/src/crypto/KeyUtils.h @@ -10,6 +10,7 @@ #include +#include #include namespace stellar @@ -43,7 +44,11 @@ namespace KeyUtils { template -typename std::enable_if::value, std::string>::type +concept IsKeyType = std::same_as || std::same_as || + std::same_as; + +template +std::string toStrKey(T const& key) { return strKey::toStrKey(KeyFunctions::toKeyVersion(key.type()), @@ -51,23 +56,28 @@ toStrKey(T const& key) .value; } -template -typename std::enable_if::value, SecretValue>::type +// We use a template on this to avoid needing SecretKey's declaration to be +// visible in this file +template + requires std::same_as +SecretValue toStrKey(T const& key) { return strKey::toStrKey(KeyFunctions::toKeyVersion(key.type()), KeyFunctions::getKeyValue(key)); } -template -typename std::enable_if::value, std::string>::type +template +std::string toShortString(T const& key) { return toStrKey(key).substr(0, 5); } -template -typename std::enable_if::value, SecretValue>::type +// We require a template here for the same reason as in toStrKey (above) +template + requires std::same_as +SecretValue toShortString(T const& key) { return SecretValue{toStrKey(key).value.substr(0, 5)}; @@ -81,7 +91,7 @@ struct InvalidStrKey : public std::invalid_argument using std::invalid_argument::invalid_argument; }; -template +template T fromStrKey(std::string const& s) { diff --git a/src/crypto/XDRHasher.h b/src/crypto/XDRHasher.h index 6f9c4fec1a..597ef3125d 100644 --- a/src/crypto/XDRHasher.h +++ b/src/crypto/XDRHasher.h @@ -4,6 +4,7 @@ #pragma once +#include #include #include @@ -57,8 +58,9 @@ template struct XDRHasher } } template - typename std::enable_if::uint_type>::value>::type + requires std::same_as::uint_type> + void operator()(T t) { auto u = xdr::swap32le(xdr::xdr_traits::to_uint(t)); @@ -66,8 +68,9 @@ template struct XDRHasher } template - typename std::enable_if::uint_type>::value>::type + requires std::same_as::uint_type> + void operator()(T t) { auto u = xdr::swap64le(xdr::xdr_traits::to_uint(t)); @@ -75,7 +78,8 @@ template struct XDRHasher } template - typename std::enable_if::is_bytes>::type + requires xdr::xdr_traits::is_bytes + void operator()(T const& t) { size_t len = t.size(); @@ -95,8 +99,9 @@ template struct XDRHasher } template - typename std::enable_if::is_class || - xdr::xdr_traits::is_container>::type + requires xdr::xdr_traits::is_class || + xdr::xdr_traits::is_container + void operator()(T const& t) { xdr::xdr_traits::save(*this, t); diff --git a/src/history/FileTransferInfo.h b/src/history/FileTransferInfo.h index 60cd9c2d00..ee11a68068 100644 --- a/src/history/FileTransferInfo.h +++ b/src/history/FileTransferInfo.h @@ -37,13 +37,12 @@ class FileTransferInfo std::string getLocalDir(TmpDir const& localRoot) const; public: - template + template FileTransferInfo(BucketT const& bucket) : mType(FileType::HISTORY_FILE_TYPE_BUCKET) , mHexDigits(binToHex(bucket.getHash())) , mLocalPath(bucket.getFilename().string()) { - BUCKET_TYPE_ASSERT(BucketT); } FileTransferInfo(TmpDir const& snapDir, FileType const& snapType, diff --git a/src/history/HistoryArchive.cpp b/src/history/HistoryArchive.cpp index c71b99ae15..8fe966d390 100644 --- a/src/history/HistoryArchive.cpp +++ b/src/history/HistoryArchive.cpp @@ -41,7 +41,7 @@ formatString(std::string const& templateString, Tokens const&... tokens) { try { - return fmt::format(templateString, tokens...); + return fmt::format(fmt::runtime(templateString), tokens...); } catch (fmt::format_error const& ex) { diff --git a/src/history/HistoryArchive.h b/src/history/HistoryArchive.h index a7b89ba442..d03be0428f 100644 --- a/src/history/HistoryArchive.h +++ b/src/history/HistoryArchive.h @@ -34,9 +34,8 @@ namespace stellar class Application; -template struct HistoryStateBucket +template struct HistoryStateBucket { - BUCKET_TYPE_ASSERT(BucketT); using bucket_type = BucketT; std::string curr; diff --git a/src/history/test/HistoryTestsUtils.cpp b/src/history/test/HistoryTestsUtils.cpp index 219c3fbebc..89e4f52727 100644 --- a/src/history/test/HistoryTestsUtils.cpp +++ b/src/history/test/HistoryTestsUtils.cpp @@ -144,7 +144,7 @@ RealGenesisTmpDirHistoryConfigurator::configure(Config& mCfg, return mCfg; } -template +template BucketOutputIteratorForTesting::BucketOutputIteratorForTesting( std::string const& tmpDir, uint32_t protocolVersion, MergeCounters& mc, asio::io_context& ctx) @@ -154,7 +154,7 @@ BucketOutputIteratorForTesting::BucketOutputIteratorForTesting( { } -template +template std::pair BucketOutputIteratorForTesting::writeTmpTestBucket() { @@ -202,11 +202,10 @@ TestBucketGenerator::TestBucketGenerator( mApp.getTmpDirManager().tmpDir("tmp-bucket-generator")); } -template +template std::string TestBucketGenerator::generateBucket(TestBucketState state) { - BUCKET_TYPE_ASSERT(BucketT); uint256 hash = HashUtils::pseudoRandomForTesting(); if (state == TestBucketState::FILE_NOT_UPLOADED) diff --git a/src/history/test/HistoryTestsUtils.h b/src/history/test/HistoryTestsUtils.h index eaef09cd0b..a87ade1617 100644 --- a/src/history/test/HistoryTestsUtils.h +++ b/src/history/test/HistoryTestsUtils.h @@ -48,7 +48,7 @@ enum class TestBucketState class HistoryConfigurator; class TestBucketGenerator; -template class BucketOutputIteratorForTesting; +template class BucketOutputIteratorForTesting; struct CatchupPerformedWork; class HistoryConfigurator : NonCopyable @@ -100,11 +100,9 @@ class RealGenesisTmpDirHistoryConfigurator : public TmpDirHistoryConfigurator Config& configure(Config& cfg, bool writable) const override; }; -template +template class BucketOutputIteratorForTesting : public BucketOutputIterator { - BUCKET_TYPE_ASSERT(BucketT); - size_t const NUM_ITEMS_PER_BUCKET = 5; public: @@ -125,7 +123,7 @@ class TestBucketGenerator TestBucketGenerator(Application& app, std::shared_ptr archive); - template + template std::string generateBucket( TestBucketState desiredState = TestBucketState::CONTENTS_AND_HASH_OK); }; diff --git a/src/historywork/DownloadBucketsWork.cpp b/src/historywork/DownloadBucketsWork.cpp index a689a043e2..c2cfab89d6 100644 --- a/src/historywork/DownloadBucketsWork.cpp +++ b/src/historywork/DownloadBucketsWork.cpp @@ -71,7 +71,7 @@ DownloadBucketsWork::resetIter() mHotBucketsState.nextIter = mHotBucketsState.hashes.begin(); } -template +template void DownloadBucketsWork::onSuccessCb(Application& app, FileTransferInfo const& ft, std::string const& hash, int currId, @@ -103,7 +103,7 @@ DownloadBucketsWork::onSuccessCb(Application& app, FileTransferInfo const& ft, state.buckets[hash] = b; } -template +template std::pair, std::function> DownloadBucketsWork::prepareWorkForBucketType( std::string const& hash, FileTransferInfo const& ft, diff --git a/src/historywork/DownloadBucketsWork.h b/src/historywork/DownloadBucketsWork.h index eda4a70d1a..f657fda420 100644 --- a/src/historywork/DownloadBucketsWork.h +++ b/src/historywork/DownloadBucketsWork.h @@ -19,7 +19,7 @@ class FileTransferInfo; class DownloadBucketsWork : public BatchWork { // Wrapper around state associated with each BucketList - template struct BucketState + template struct BucketState { // Must hold mutex when accessing buckets std::map>& buckets; @@ -51,14 +51,14 @@ class DownloadBucketsWork : public BatchWork TmpDir const& mDownloadDir; std::shared_ptr mArchive; - template + template static void onSuccessCb(Application& app, FileTransferInfo const& ft, std::string const& hash, int currId, BucketState& state); // Helper function returns pair of verifyBucketWork and a callback to adopt // the verified BucketList. - template + template std::pair, std::function> prepareWorkForBucketType(std::string const& hash, FileTransferInfo const& ft, diff --git a/src/historywork/VerifyBucketWork.cpp b/src/historywork/VerifyBucketWork.cpp index 8a8e62038f..7990a1a177 100644 --- a/src/historywork/VerifyBucketWork.cpp +++ b/src/historywork/VerifyBucketWork.cpp @@ -21,7 +21,7 @@ namespace stellar { -template +template VerifyBucketWork::VerifyBucketWork( Application& app, std::string const& bucketFile, uint256 const& hash, std::shared_ptr& index, @@ -34,7 +34,7 @@ VerifyBucketWork::VerifyBucketWork( { } -template +template BasicWork::State VerifyBucketWork::onRun() { @@ -52,7 +52,7 @@ VerifyBucketWork::onRun() return State::WORK_WAITING; } -template +template void VerifyBucketWork::spawnVerifier() { @@ -151,7 +151,7 @@ VerifyBucketWork::spawnVerifier() "VerifyBucket: start in background"); } -template +template void VerifyBucketWork::onFailureRaise() { diff --git a/src/historywork/VerifyBucketWork.h b/src/historywork/VerifyBucketWork.h index 5372921e66..dec0886d8b 100644 --- a/src/historywork/VerifyBucketWork.h +++ b/src/historywork/VerifyBucketWork.h @@ -20,10 +20,8 @@ class LiveBucketIndex; class Bucket; -template class VerifyBucketWork : public BasicWork +template class VerifyBucketWork : public BasicWork { - BUCKET_TYPE_ASSERT(BucketT); - std::string mBucketFile; uint256 mHash; bool mDone{false}; diff --git a/src/invariant/test/InvariantTests.cpp b/src/invariant/test/InvariantTests.cpp index ff68e4366f..badb031ac1 100644 --- a/src/invariant/test/InvariantTests.cpp +++ b/src/invariant/test/InvariantTests.cpp @@ -691,13 +691,13 @@ TEST_CASE("BucketList state consistency invariant", "[invariant]") else { auto it = modifiedState.mContractDataEntries.begin(); - auto const& entryData = it->get(); + auto const& entryData = *it; LedgerEntry modifiedEntry = *entryData.ledgerEntry; modifiedEntry.lastModifiedLedgerSeq += 100; auto ttlData = entryData.ttlData; modifiedState.mContractDataEntries.erase(it); modifiedState.mContractDataEntries.emplace( - InternalContractDataMapEntry(modifiedEntry, ttlData)); + std::make_shared(modifiedEntry), ttlData); } auto result = @@ -739,7 +739,7 @@ TEST_CASE("BucketList state consistency invariant", "[invariant]") createContractDataWithTTL(PERSISTENT, 1000); TTLData ttlData(extraTTL.data.ttl().liveUntilLedgerSeq, 1); modifiedState.mContractDataEntries.emplace( - InternalContractDataMapEntry(extraEntry, ttlData)); + std::make_shared(extraEntry), ttlData); } auto result = @@ -765,13 +765,13 @@ TEST_CASE("BucketList state consistency invariant", "[invariant]") // Corrupt TTL of an entry in the cache auto it = modifiedState.mContractDataEntries.begin(); - auto const& entryData = it->get(); + auto const& entryData = *it; LedgerEntry entryCopy = *entryData.ledgerEntry; TTLData wrongTTL(42, 1); modifiedState.mContractDataEntries.erase(it); modifiedState.mContractDataEntries.emplace( - InternalContractDataMapEntry(entryCopy, wrongTTL)); + std::make_shared(entryCopy), wrongTTL); auto result = invariant.checkSnapshot(getLiveSnapshot(), getHotArchiveSnapshot(), diff --git a/src/ledger/InMemorySorobanState.cpp b/src/ledger/InMemorySorobanState.cpp index c7d1b40565..3795fdf859 100644 --- a/src/ledger/InMemorySorobanState.cpp +++ b/src/ledger/InMemorySorobanState.cpp @@ -50,15 +50,12 @@ TTLData::isDefault() const void InMemorySorobanState::updateContractDataTTL( - std::unordered_set::iterator dataIt, - TTLData newTtlData) + InternalContractDataMap::iterator dataIt, TTLData newTtlData) { // Since entries are immutable, we must erase and re-insert - auto ledgerEntryPtr = dataIt->get().ledgerEntry; + auto ledgerEntryPtr = dataIt->ledgerEntry; mContractDataEntries.erase(dataIt); - mContractDataEntries.emplace( - InternalContractDataMapEntry(std::move(ledgerEntryPtr), newTtlData)); + mContractDataEntries.emplace(std::move(ledgerEntryPtr), newTtlData); } void @@ -72,7 +69,7 @@ InMemorySorobanState::updateTTL(LedgerEntry const& ttlEntry) // TTL updates can apply to either ContractData or ContractCode entries. // First check if this TTL belongs to a stored ContractData entry. - auto dataIt = mContractDataEntries.find(InternalContractDataMapEntry(lk)); + auto dataIt = mContractDataEntries.find(lk); if (dataIt != mContractDataEntries.end()) { updateContractDataTTL(dataIt, newTtlData); @@ -94,19 +91,19 @@ InMemorySorobanState::updateContractData(LedgerEntry const& ledgerEntry) // Entry must already exist since this is an update auto lk = LedgerEntryKey(ledgerEntry); - auto dataIt = mContractDataEntries.find(InternalContractDataMapEntry(lk)); + auto dataIt = mContractDataEntries.find(lk); releaseAssertOrThrow(dataIt != mContractDataEntries.end()); - releaseAssertOrThrow(dataIt->get().ledgerEntry != nullptr); + releaseAssertOrThrow(dataIt->ledgerEntry != nullptr); - uint32_t oldSize = xdr::xdr_size(*dataIt->get().ledgerEntry); + uint32_t oldSize = xdr::xdr_size(*dataIt->ledgerEntry); uint32_t newSize = xdr::xdr_size(ledgerEntry); updateStateSizeOnEntryUpdate(oldSize, newSize, /*isContractCode=*/false); // Preserve the existing TTL while updating the data - auto preservedTTL = dataIt->get().ttlData; + auto preservedTTL = dataIt->ttlData; mContractDataEntries.erase(dataIt); mContractDataEntries.emplace( - InternalContractDataMapEntry(ledgerEntry, preservedTTL)); + std::make_shared(ledgerEntry), preservedTTL); } void @@ -115,8 +112,7 @@ InMemorySorobanState::createContractDataEntry(LedgerEntry const& ledgerEntry) releaseAssertOrThrow(ledgerEntry.data.type() == CONTRACT_DATA); // Verify entry doesn't already exist - auto dataIt = mContractDataEntries.find( - InternalContractDataMapEntry(LedgerEntryKey(ledgerEntry))); + auto dataIt = mContractDataEntries.find(ledgerEntry); releaseAssertOrThrow(dataIt == mContractDataEntries.end()); // Check if we've already seen this entry's TTL (can happen during @@ -137,7 +133,7 @@ InMemorySorobanState::createContractDataEntry(LedgerEntry const& ledgerEntry) updateStateSizeOnEntryUpdate(0, xdr::xdr_size(ledgerEntry), /*isContractCode=*/false); mContractDataEntries.emplace( - InternalContractDataMapEntry(ledgerEntry, ttlData)); + std::make_shared(ledgerEntry), ttlData); } bool @@ -158,12 +154,12 @@ InMemorySorobanState::createTTL(LedgerEntry const& ttlEntry) // Check if the corresponding ContractData entry already exists // (can happen during initialization when entries arrive out of order) - auto dataIt = mContractDataEntries.find(InternalContractDataMapEntry(lk)); + auto dataIt = mContractDataEntries.find(lk); if (dataIt != mContractDataEntries.end()) { // ContractData exists but has no TTL yet - update it // Verify TTL hasn't been set yet (should be default initialized) - releaseAssertOrThrow(dataIt->get().ttlData.isDefault()); + releaseAssertOrThrow(dataIt->ttlData.isDefault()); updateContractDataTTL(dataIt, newTtlData); } else @@ -191,11 +187,10 @@ void InMemorySorobanState::deleteContractData(LedgerKey const& ledgerKey) { releaseAssertOrThrow(ledgerKey.type() == CONTRACT_DATA); - auto it = - mContractDataEntries.find(InternalContractDataMapEntry(ledgerKey)); + auto it = mContractDataEntries.find(ledgerKey); releaseAssertOrThrow(it != mContractDataEntries.end()); - releaseAssertOrThrow(it->get().ledgerEntry != nullptr); - updateStateSizeOnEntryUpdate(xdr::xdr_size(*it->get().ledgerEntry), 0, + releaseAssertOrThrow(it->ledgerEntry != nullptr); + updateStateSizeOnEntryUpdate(xdr::xdr_size(*it->ledgerEntry), 0, /*isContractCode=*/false); mContractDataEntries.erase(it); } @@ -207,13 +202,12 @@ InMemorySorobanState::get(LedgerKey const& ledgerKey) const { case CONTRACT_DATA: { - auto it = - mContractDataEntries.find(InternalContractDataMapEntry(ledgerKey)); + auto it = mContractDataEntries.find(ledgerKey); if (it == mContractDataEntries.end()) { return nullptr; } - return it->get().ledgerEntry; + return it->ledgerEntry; } case CONTRACT_CODE: { @@ -326,14 +320,13 @@ InMemorySorobanState::hasTTL(LedgerKey const& ledgerKey) const } // Check if this is a ContractData TTL (stored with the data) - auto dataIt = - mContractDataEntries.find(InternalContractDataMapEntry(ledgerKey)); + auto dataIt = mContractDataEntries.find(ledgerKey); if (dataIt != mContractDataEntries.end()) { // Only return true if TTL has been set (non-zero) // During initialization, entries may exist with default constructed // TTLs - return !dataIt->get().ttlData.isDefault(); + return !dataIt->ttlData.isDefault(); } // Check if this is a ContractCode TTL (stored with the code) @@ -426,11 +419,10 @@ InMemorySorobanState::getTTL(LedgerKey const& ledgerKey) const // Since the TTL key is the hash of the associated LedgerKey, we don't know // which map it could belong in, so check both. - auto dataIt = - mContractDataEntries.find(InternalContractDataMapEntry(ledgerKey)); + auto dataIt = mContractDataEntries.find(ledgerKey); if (dataIt != mContractDataEntries.end()) { - return constructTTLEntry(dataIt->get().ttlData); + return constructTTLEntry(dataIt->ttlData); } auto codeIt = mContractCodeEntries.find(ledgerKey.ttl().keyHash); diff --git a/src/ledger/InMemorySorobanState.h b/src/ledger/InMemorySorobanState.h index 385e494841..7b07f5df3f 100644 --- a/src/ledger/InMemorySorobanState.h +++ b/src/ledger/InMemorySorobanState.h @@ -80,209 +80,80 @@ struct ContractCodeMapEntryT } }; -// InternalContractDataMapEntry provides a memory-efficient map -// implementation. +// InternalContractDataMap provides a memory-efficient map implementation. // // Soroban keys can be quite large (often dominating LedgerEntry size), so // storing them twice in a traditional key-value map would be wasteful. Instead, // we use std::unordered_set since LedgerEntry contains both key and value data. // -// Since C++17's unordered_set doesn't support heterogeneous lookup (searching -// with a different type than stored), we use polymorphism to enable key-only -// lookups without constructing full entries. This will be simplified when we -// upgrade to C++20. -// // We index entries by their TTL key (SHA256 hash of the ContractData key) // rather than the full ContractData key. This lets us look up both ContractData // entries and their TTLs with one index. // // Logical map structure: // TTLKey -> , liveUntilLedgerSeq> -// -class InternalContractDataMapEntry +using InternalContractDataMap = + std::unordered_set; + +inline Hash +getInternalContractDataMapHash(ContractDataMapEntryT const& entry) { - private: - // Abstract base class for polymorphic entry handling. - // This allows QueryKey and ValueEntry to be used interchangeably in the - // set. - struct AbstractEntry - { - virtual ~AbstractEntry() = default; - - // Returns the TTL key (SHA256 hash) that indexes this entry. - // For ContractData entries, this is getTTLKey(ledgerKey).ttl().keyHash - // For TTL queries, this is directly the keyHash from the TTL key - virtual uint256 copyKey() const = 0; - - // Computes hash for unordered_set storage. - // Note: This returns size_t for STL compatibility, not the uint256 key - virtual size_t hash() const = 0; - - // Returns the stored data. Only valid for ValueEntry instances. - virtual ContractDataMapEntryT const& get() const = 0; - - // Creates a deep copy of this entry. Required for copy constructor. - virtual std::unique_ptr clone() const = 0; - - // Equality comparison based on TTL keys - virtual bool - operator==(AbstractEntry const& other) const - { - return copyKey() == other.copyKey(); - } - }; - - // ValueEntry stores actual ContractData entries in the map. - // Contains both the LedgerEntry and its TTL information. - struct ValueEntry : public AbstractEntry - { - private: - ContractDataMapEntryT entry; - - public: - ValueEntry(std::shared_ptr&& ledgerEntry, - TTLData ttlData) - : entry(std::move(ledgerEntry), ttlData) - { - } - - uint256 - copyKey() const override - { - auto ttlKey = getTTLKey(LedgerEntryKey(*entry.ledgerEntry)); - return ttlKey.ttl().keyHash; - } - - size_t - hash() const override - { - return std::hash{}(copyKey()); - } - - ContractDataMapEntryT const& - get() const override - { - return entry; - } - - std::unique_ptr - clone() const override - { - return std::make_unique( - std::make_shared(*entry.ledgerEntry), - entry.ttlData); - } - }; - - // QueryKey is a lightweight key-only entry used for map lookups. - struct QueryKey : public AbstractEntry - { - private: - uint256 const ledgerKeyHash; - - public: - explicit QueryKey(uint256 const& ledgerKeyHash) - : ledgerKeyHash(ledgerKeyHash) - { - } - - uint256 - copyKey() const override - { - return ledgerKeyHash; - } - - size_t - hash() const override - { - return std::hash{}(ledgerKeyHash); - } - - // Should never be called - QueryKey is only for lookups - ContractDataMapEntryT const& - get() const override - { - throw std::runtime_error( - "QueryKey::get() called - this is a logic error"); - } - - std::unique_ptr - clone() const override - { - return std::make_unique(ledgerKeyHash); - } - }; - - std::unique_ptr impl; + return getTTLKey(LedgerEntryKey(*entry.ledgerEntry)).ttl().keyHash; +} - public: - // Copy constructor - required for InMemorySorobanState copy constructor. - InternalContractDataMapEntry(InternalContractDataMapEntry const& other) - : impl(other.impl->clone()) - { - } +inline Hash +getInternalContractDataMapHash(LedgerEntry const& entry) +{ + return getTTLKey(LedgerEntryKey(entry)).ttl().keyHash; +} - // Creates a ValueEntry from a LedgerEntry (copies the entry) - InternalContractDataMapEntry(LedgerEntry const& ledgerEntry, - TTLData ttlData) - : impl(std::make_unique( - std::make_shared(ledgerEntry), ttlData)) +inline Hash +getInternalContractDataMapHash(LedgerKey const& key) +{ + if (key.type() == CONTRACT_DATA) { + auto ttlKey = getTTLKey(key); + return ttlKey.ttl().keyHash; } - - // Creates a ValueEntry from a shared_ptr (avoids copying) - InternalContractDataMapEntry( - std::shared_ptr&& ledgerEntry, TTLData ttlData) - : impl(std::make_unique(std::move(ledgerEntry), ttlData)) + else if (key.type() == TTL) { + return key.ttl().keyHash; } - - // Creates a QueryKey for lookups. Accepts both CONTRACT_DATA and TTL keys. - // For CONTRACT_DATA keys, converts to TTL key hash. - // For TTL keys, uses the hash directly. - explicit InternalContractDataMapEntry(LedgerKey const& ledgerKey) + else { - if (ledgerKey.type() == CONTRACT_DATA) - { - auto ttlKey = getTTLKey(ledgerKey); - impl = std::make_unique(ttlKey.ttl().keyHash); - } - else if (ledgerKey.type() == TTL) - { - impl = std::make_unique(ledgerKey.ttl().keyHash); - } - else - { - throw std::runtime_error( - "Invalid ledger key type for contract data map entry"); - } + throw std::runtime_error( + "Invalid ledger key type for contract data map entry hash"); } +} - size_t - hash() const - { - return impl->hash(); - } +template +concept IsInternalContractDataMapType = + std::same_as || std::same_as || + std::same_as; - bool - operator==(InternalContractDataMapEntry const& other) const - { - return impl->operator==(*other.impl); - } +struct InternalContractDataEntryHash +{ + using is_transparent = void; - ContractDataMapEntryT const& - get() const + size_t + operator()(IsInternalContractDataMapType auto const& entry) const { - return impl->get(); + return std::hash()(getInternalContractDataMapHash(entry)); } }; -struct InternalContractDataEntryHash +struct InternalContractDataEntryEqual { - size_t - operator()(InternalContractDataMapEntry const& entry) const + using is_transparent = void; + + bool + operator()(IsInternalContractDataMapType auto const& lhs, + IsInternalContractDataMapType auto const& rhs) const { - return entry.hash(); + return getInternalContractDataMapHash(lhs) == + getInternalContractDataMapHash(rhs); } }; @@ -313,9 +184,7 @@ class InMemorySorobanState // Primary storage for ContractData entries with embedded TTL information. // Uses unordered_set with custom entries to save memory vs traditional map. - std::unordered_set - mContractDataEntries; + InternalContractDataMap mContractDataEntries; // Storage for ContractCode entries. Maps from TTL key hash to entry, ttl // struct. Unlike ContractData, we use a map here because the key size is @@ -341,10 +210,8 @@ class InMemorySorobanState // Helper to update an existing ContractData entry's TTL without changing // data - void updateContractDataTTL( - std::unordered_set::iterator dataIt, - TTLData newTtlData); + void updateContractDataTTL(InternalContractDataMap::iterator dataIt, + TTLData newTtlData); // Should be called after initialization/updates finish to check consistency // invariants. diff --git a/src/ledger/LedgerEntryScope.h b/src/ledger/LedgerEntryScope.h index 801216d79b..bb95d39df8 100644 --- a/src/ledger/LedgerEntryScope.h +++ b/src/ledger/LedgerEntryScope.h @@ -260,7 +260,7 @@ template class ScopedLedgerEntry LedgerEntryScopeID const mScopeID; // Must construct with a scope. - ScopedLedgerEntry() = delete; + ScopedLedgerEntry() = delete; ScopedLedgerEntry(ScopedLedgerEntry const& other); ScopedLedgerEntry(ScopedLedgerEntry&& other); diff --git a/src/main/Config.cpp b/src/main/Config.cpp index 2c7a44d2a2..9123d43323 100644 --- a/src/main/Config.cpp +++ b/src/main/Config.cpp @@ -21,6 +21,7 @@ #include "simulation/ApplyLoad.h" #endif +#include #include #include #include @@ -433,8 +434,8 @@ readArray(ConfigItem const& item) return result; } -template -std::enable_if_t, T> +template +T castInt(int64_t v, std::string const& name, T min, T max) { if (v < min || v > max) @@ -444,8 +445,8 @@ castInt(int64_t v, std::string const& name, T min, T max) return static_cast(v); } -template -std::enable_if_t, T> +template +T castInt(int64_t v, std::string const& name, T min, T max) { if (v < 0) diff --git a/src/main/test/ConfigTests.cpp b/src/main/test/ConfigTests.cpp index f62003f7ab..5a1362ad61 100644 --- a/src/main/test/ConfigTests.cpp +++ b/src/main/test/ConfigTests.cpp @@ -283,7 +283,7 @@ TEST_CASE("load validators config", "[config]") TEST_CASE("bad validators configs", "[config]") { // basic config has 4 top level as to meet safety requirement - std::string const configPattern = R"( + static char constexpr configPattern[] = R"( NODE_SEED="SA7FGJMMUIHNE3ZPI2UO5I632A7O5FBAZTXFAIEVFA4DSSGLHXACLAIT a3" {NODE_HOME_DOMAIN} NODE_IS_VALIDATOR=true @@ -429,7 +429,8 @@ PUBLIC_KEY="GCWD2OTEJXLIDSOFSTWDPM5IDY27ZGEXIUIBGGA45Q2VXGQ2QAEBG7ZS" ++i; DYNAMIC_SECTION(t[0] << " " << i) { - auto other2 = fmt::format(t[5], fmt::arg("QUALITY_G", t[6])); + auto other2 = + fmt::format(fmt::runtime(t[5]), fmt::arg("QUALITY_G", t[6])); auto newConfig = fmt::format( configPattern, fmt::arg("NODE_HOME_DOMAIN", t[1]), fmt::arg("A1_HOME_DOMAIN", t[2]), fmt::arg("A1_HISTORY", t[3]), @@ -475,7 +476,7 @@ TEST_CASE("nesting level", "[config]") }; std::string configNesting = "UNSAFE_QUORUM=true"; std::string quorumSetNumber = ""; - std::string quorumSetTemplate = R"( + static char constexpr quorumSetTemplate[] = R"( [QUORUM_SET{}] THRESHOLD_PERCENT=50 diff --git a/src/test/TestUtils.cpp b/src/test/TestUtils.cpp index 4848c39b05..bfbe5eecd5 100644 --- a/src/test/TestUtils.cpp +++ b/src/test/TestUtils.cpp @@ -142,14 +142,14 @@ computeMultiplier(LedgerEntry const& le) } } -template +template BucketListDepthModifier::BucketListDepthModifier(uint32_t newDepth) : mPrevDepth(BucketListBase::kNumLevels) { BucketListBase::kNumLevels = newDepth; } -template +template BucketListDepthModifier::~BucketListDepthModifier() { BucketListBase::kNumLevels = mPrevDepth; diff --git a/src/test/TestUtils.h b/src/test/TestUtils.h index b8b8a24dee..9a60ff9ce2 100644 --- a/src/test/TestUtils.h +++ b/src/test/TestUtils.h @@ -11,6 +11,7 @@ #include "ledger/LedgerManagerImpl.h" #include "main/ApplicationImpl.h" #include "util/ProtocolVersion.h" +#include #include namespace stellar @@ -34,10 +35,8 @@ std::vector getInvalidAssets(SecretKey const& issuer); int32_t computeMultiplier(LedgerEntry const& le); -template class BucketListDepthModifier +template class BucketListDepthModifier { - BUCKET_TYPE_ASSERT(BucketT); - uint32_t const mPrevDepth; public: @@ -83,9 +82,8 @@ class TestApplication : public ApplicationImpl std::unique_ptr createInvariantManager() override; }; -template ::value>::type> +template + requires std::derived_from std::shared_ptr createTestApplication(VirtualClock& clock, Config const& cfg, Args&&... args, bool newDB = true, bool startApp = true) diff --git a/src/test/test.cpp b/src/test/test.cpp index 3c49c304df..cef04ae0bd 100644 --- a/src/test/test.cpp +++ b/src/test/test.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include diff --git a/src/transactions/TransactionSQL.cpp b/src/transactions/TransactionSQL.cpp index b6167ca86e..98388ca9f2 100644 --- a/src/transactions/TransactionSQL.cpp +++ b/src/transactions/TransactionSQL.cpp @@ -16,6 +16,7 @@ #include "xdrpp/marshal.h" #include "xdrpp/message.h" #include +#include namespace stellar { @@ -35,8 +36,8 @@ class GeneralizedTxSetUnpacker } template - typename std::enable_if< - std::is_same::uint_type>::value>::type + requires std::same_as::uint_type> + void operator()(T& t) { uint32_t v; @@ -45,8 +46,8 @@ class GeneralizedTxSetUnpacker } template - typename std::enable_if< - std::is_same::uint_type>::value>::type + requires std::same_as::uint_type> + void operator()(T& t) { uint64_t v; @@ -55,7 +56,8 @@ class GeneralizedTxSetUnpacker } template - typename std::enable_if::is_bytes>::type + requires xdr_traits::is_bytes + void operator()(T& t) { if (xdr_traits::variable_nelem) @@ -68,17 +70,15 @@ class GeneralizedTxSetUnpacker } template - typename std::enable_if::value && - (xdr_traits::is_class || - xdr_traits::is_container)>::type + requires xdr_traits::is_class || xdr_traits::is_container + void operator()(T& t) { xdr_traits::load(*this, t); } - template - typename std::enable_if::value>::type - operator()(T& tx) + void + operator()(TransactionEnvelope& tx) { Hash hash; getBytes(hash.data(), hash.size()); diff --git a/src/transactions/TransactionUtils.cpp b/src/transactions/TransactionUtils.cpp index 64eb2afe50..c89f408777 100644 --- a/src/transactions/TransactionUtils.cpp +++ b/src/transactions/TransactionUtils.cpp @@ -1287,8 +1287,9 @@ struct MuxChecker } template - std::enable_if_t<(xdr::xdr_traits::is_container || - xdr::xdr_traits::is_class)> + requires xdr::xdr_traits::is_container || + xdr::xdr_traits::is_class + void operator()(T const& t) { if (!mHasMuxedAccount) @@ -1298,8 +1299,7 @@ struct MuxChecker } template - std::enable_if_t::is_container || - xdr::xdr_traits::is_class)> + void operator()(T const& t) { } diff --git a/src/util/BinaryFuseFilter.cpp b/src/util/BinaryFuseFilter.cpp index f94d9f3d57..8e33afb68f 100644 --- a/src/util/BinaryFuseFilter.cpp +++ b/src/util/BinaryFuseFilter.cpp @@ -10,14 +10,14 @@ namespace stellar { -template +template BinaryFuseFilter::BinaryFuseFilter(std::vector& keyHashes, binary_fuse_seed_t const& seed) : mFilter(keyHashes.size(), keyHashes, seed), mHashSeed(seed) { } -template +template BinaryFuseFilter::BinaryFuseFilter( SerializedBinaryFuseFilter const& xdrFilter) : mFilter(xdrFilter), mHashSeed([&] { @@ -29,7 +29,7 @@ BinaryFuseFilter::BinaryFuseFilter( { } -template +template bool BinaryFuseFilter::contains(LedgerKey const& key) const { @@ -39,7 +39,7 @@ BinaryFuseFilter::contains(LedgerKey const& key) const return mFilter.contain(hasher.digest()); } -template +template bool BinaryFuseFilter::operator==(BinaryFuseFilter const& other) const { diff --git a/src/util/BinaryFuseFilter.h b/src/util/BinaryFuseFilter.h index 480f28810c..4be59f24ac 100644 --- a/src/util/BinaryFuseFilter.h +++ b/src/util/BinaryFuseFilter.h @@ -10,19 +10,22 @@ #include "xdr/Stellar-types.h" #include +#include namespace stellar { +template +concept IsSupportedBinaryFuseFilterType = + std::same_as || std::same_as || + std::same_as; + // This class is a wrapper around the binary_fuse_t library that provides // serialization for the XDR BinaryFuseFilter type and provides a deterministic // LedgerKey interface. -template class BinaryFuseFilter : public NonMovableOrCopyable +template +class BinaryFuseFilter : public NonMovableOrCopyable { - static_assert(std::is_same_v || std::is_same_v || - std::is_same_v, - "Binary Fuse Filter only supports 8, 16, or 32 bit width"); - private: binary_fuse_t const mFilter; diff --git a/src/util/BufferedAsioCerealOutputArchive.h b/src/util/BufferedAsioCerealOutputArchive.h index 1d72d600e1..93d4bca4aa 100644 --- a/src/util/BufferedAsioCerealOutputArchive.h +++ b/src/util/BufferedAsioCerealOutputArchive.h @@ -14,9 +14,9 @@ namespace cereal // Mirrors CEREAL_ARCHIVE_RESTRICT from cereal/details/traits.hpp for single // types -#define CEREAL_ARCHIVE_RESTRICT_SINGLE_TYPE(TYPE) \ - typename std::enable_if< \ - cereal::traits::is_same_archive::value, void>::type +template +concept IsRestrictedToSingleArchiveType = + cereal::traits::is_same_archive::value; // This is a basic reimplementation of BinaryOutputArchive // (cereal/archives/binary.hpp) that uses our own OutputFileStream instead of @@ -50,7 +50,8 @@ class BufferedAsioOutputArchive // Saving for POD types to binary template -inline typename std::enable_if::value, void>::type + requires std::is_arithmetic_v +void CEREAL_SAVE_FUNCTION_NAME(BufferedAsioOutputArchive& ar, T const& t) { ar.saveBinary(std::addressof(t), sizeof(t)); @@ -58,17 +59,18 @@ CEREAL_SAVE_FUNCTION_NAME(BufferedAsioOutputArchive& ar, T const& t) // Serializing NVP types to binary template - -inline CEREAL_ARCHIVE_RESTRICT_SINGLE_TYPE(BufferedAsioOutputArchive) - CEREAL_SERIALIZE_FUNCTION_NAME(Archive& ar, NameValuePair& t) + requires IsRestrictedToSingleArchiveType +inline void +CEREAL_SERIALIZE_FUNCTION_NAME(Archive& ar, NameValuePair& t) { ar(t.value); } // Serializing SizeTags to binary template -inline CEREAL_ARCHIVE_RESTRICT_SINGLE_TYPE(BufferedAsioOutputArchive) - CEREAL_SERIALIZE_FUNCTION_NAME(Archive& ar, SizeTag& t) + requires IsRestrictedToSingleArchiveType +inline void +CEREAL_SERIALIZE_FUNCTION_NAME(Archive& ar, SizeTag& t) { ar(t.size); } diff --git a/src/util/DebugMetaUtils.h b/src/util/DebugMetaUtils.h index a70f3e826a..57042b59c9 100644 --- a/src/util/DebugMetaUtils.h +++ b/src/util/DebugMetaUtils.h @@ -15,7 +15,7 @@ namespace metautils std::string const META_DEBUG_DIRNAME{"meta-debug"}; std::string const DEBUG_TX_SET_FILENAME{"debug-tx-set.xdr"}; -std::string const META_DEBUG_FILE_FMT_STR{"meta-debug-{:08x}-{}.xdr"}; +constexpr char META_DEBUG_FILE_FMT_STR[]{"meta-debug-{:08x}-{}.xdr"}; std::regex const META_DEBUG_FILE_REGEX{ "meta-debug-[[:xdigit:]]+-[[:xdigit:]]+\\.xdr(\\.gz)?"}; std::regex const META_DEBUG_ZIP_FILE_REGEX{ diff --git a/src/util/Logging.cpp b/src/util/Logging.cpp index 1e2ed5d264..703241f4a4 100644 --- a/src/util/Logging.cpp +++ b/src/util/Logging.cpp @@ -109,8 +109,8 @@ Logging::init(bool truncate) VirtualClock clock(VirtualClock::REAL_TIME); std::time_t time = VirtualClock::to_time_t(clock.system_now()); auto filename = - fmt::format(mLastFilenamePattern, - fmt::arg("datetime", fmt::localtime(time))); + fmt::format(fmt::runtime(mLastFilenamePattern), + fmt::arg("datetime", *std::localtime(&time))); // NB: We do _not_ pass 'truncate' through to spdlog here -- spdlog // interprets 'truncate=true' as a request to open the file in "wb" diff --git a/src/util/Logging.h b/src/util/Logging.h index cd20817259..6842201639 100644 --- a/src/util/Logging.h +++ b/src/util/Logging.h @@ -34,46 +34,46 @@ #define CLOG_TRACE(partition, f, ...) \ LOG_CHECK(Logging::get##partition##LogPtr(), spdlog::level::trace, \ - SPDLOG_LOGGER_TRACE(lg, FMT_STRING(f), ##__VA_ARGS__)) + SPDLOG_LOGGER_TRACE(lg, f __VA_OPT__(, ) __VA_ARGS__)) #define CLOG_DEBUG(partition, f, ...) \ LOG_CHECK(Logging::get##partition##LogPtr(), spdlog::level::debug, \ - SPDLOG_LOGGER_DEBUG(lg, FMT_STRING(f), ##__VA_ARGS__)) + SPDLOG_LOGGER_DEBUG(lg, f __VA_OPT__(, ) __VA_ARGS__)) #define CLOG_INFO(partition, f, ...) \ LOG_CHECK(Logging::get##partition##LogPtr(), spdlog::level::info, \ - SPDLOG_LOGGER_INFO(lg, FMT_STRING(f), ##__VA_ARGS__)) + SPDLOG_LOGGER_INFO(lg, f __VA_OPT__(, ) __VA_ARGS__)) #define CLOG_WARNING(partition, f, ...) \ LOG_CHECK(Logging::get##partition##LogPtr(), spdlog::level::warn, \ - SPDLOG_LOGGER_WARN(lg, FMT_STRING(f), ##__VA_ARGS__)) + SPDLOG_LOGGER_WARN(lg, f __VA_OPT__(, ) __VA_ARGS__)) #define CLOG_ERROR(partition, f, ...) \ LOG_CHECK(Logging::get##partition##LogPtr(), spdlog::level::err, \ - SPDLOG_LOGGER_ERROR(lg, FMT_STRING(f), ##__VA_ARGS__)) + SPDLOG_LOGGER_ERROR(lg, f __VA_OPT__(, ) __VA_ARGS__)) #define CLOG_FATAL(partition, f, ...) \ LOG_CHECK(Logging::get##partition##LogPtr(), spdlog::level::critical, \ - SPDLOG_LOGGER_CRITICAL(lg, FMT_STRING(f), ##__VA_ARGS__)) + SPDLOG_LOGGER_CRITICAL(lg, f __VA_OPT__(, ) __VA_ARGS__)) #define LOG_TRACE(lg, fmt, ...) \ LOG_CHECK(lg, spdlog::level::trace, \ - SPDLOG_LOGGER_TRACE(lg, FMT_STRING(fmt), ##__VA_ARGS__)) + SPDLOG_LOGGER_TRACE(lg, fmt __VA_OPT__(, ) __VA_ARGS__)) #define LOG_DEBUG(lg, fmt, ...) \ LOG_CHECK(lg, spdlog::level::debug, \ - SPDLOG_LOGGER_DEBUG(lg, FMT_STRING(fmt), ##__VA_ARGS__)) + SPDLOG_LOGGER_DEBUG(lg, fmt __VA_OPT__(, ) __VA_ARGS__)) #define LOG_INFO(lg, fmt, ...) \ LOG_CHECK(lg, spdlog::level::info, \ - SPDLOG_LOGGER_INFO(lg, FMT_STRING(fmt), ##__VA_ARGS__)) + SPDLOG_LOGGER_INFO(lg, fmt __VA_OPT__(, ) __VA_ARGS__)) #define LOG_WARNING(lg, fmt, ...) \ LOG_CHECK(lg, spdlog::level::warn, \ - SPDLOG_LOGGER_WARN(lg, FMT_STRING(fmt), ##__VA_ARGS__)) + SPDLOG_LOGGER_WARN(lg, fmt __VA_OPT__(, ) __VA_ARGS__)) #define LOG_ERROR(lg, fmt, ...) \ LOG_CHECK(lg, spdlog::level::err, \ - SPDLOG_LOGGER_ERROR(lg, FMT_STRING(fmt), ##__VA_ARGS__)) + SPDLOG_LOGGER_ERROR(lg, fmt __VA_OPT__(, ) __VA_ARGS__)) #define LOG_FATAL(lg, fmt, ...) \ LOG_CHECK(lg, spdlog::level::critical, \ - SPDLOG_LOGGER_CRITICAL(lg, FMT_STRING(fmt), ##__VA_ARGS__)) + SPDLOG_LOGGER_CRITICAL(lg, fmt __VA_OPT__(, ) __VA_ARGS__)) #define GET_LOG(name) spdlog::get(name) #define DEFAULT_LOG spdlog::default_logger() @@ -90,30 +90,36 @@ typedef std::shared_ptr LogPtr; #define LOG(LEVEL) CLOG(LEVEL) #define CLOG_TRACE(partition, f, ...) \ - CLOG(LVL_TRACE, #partition) << fmt::format(FMT_STRING(f), ##__VA_ARGS__) + CLOG(LVL_TRACE, #partition) \ + << fmt::format(FMT_STRING(f) __VA_OPT__(, ) __VA_ARGS__) #define CLOG_DEBUG(partition, f, ...) \ - CLOG(LVL_DEBUG, #partition) << fmt::format(FMT_STRING(f), ##__VA_ARGS__) + CLOG(LVL_DEBUG, #partition) \ + << fmt::format(FMT_STRING(f) __VA_OPT__(, ) __VA_ARGS__) #define CLOG_INFO(partition, f, ...) \ - CLOG(LVL_INFO, #partition) << fmt::format(FMT_STRING(f), ##__VA_ARGS__) + CLOG(LVL_INFO, #partition) \ + << fmt::format(FMT_STRING(f) __VA_OPT__(, ) __VA_ARGS__) #define CLOG_WARNING(partition, f, ...) \ - CLOG(LVL_WARNING, #partition) << fmt::format(FMT_STRING(f), ##__VA_ARGS__) + CLOG(LVL_WARNING, #partition) \ + << fmt::format(FMT_STRING(f) __VA_OPT__(, ) __VA_ARGS__) #define CLOG_ERROR(partition, f, ...) \ - CLOG(LVL_ERROR, #partition) << fmt::format(FMT_STRING(f), ##__VA_ARGS__) + CLOG(LVL_ERROR, #partition) \ + << fmt::format(FMT_STRING(f) __VA_OPT__(, ) __VA_ARGS__) #define CLOG_FATAL(partition, f, ...) \ - CLOG(LVL_FATAL, #partition) << fmt::format(FMT_STRING(f), ##__VA_ARGS__) + CLOG(LVL_FATAL, #partition) \ + << fmt::format(FMT_STRING(f) __VA_OPT__(, ) __VA_ARGS__) #define LOG_TRACE(logger, f, ...) \ - CLOG(LVL_TRACE, logger) << fmt::format(f, ##__VA_ARGS__) + CLOG(LVL_TRACE, logger) << fmt::format(f __VA_OPT__(, ) __VA_ARGS__) #define LOG_DEBUG(logger, f, ...) \ - CLOG(LVL_DEBUG, logger) << fmt::format(f, ##__VA_ARGS__) + CLOG(LVL_DEBUG, logger) << fmt::format(f __VA_OPT__(, ) __VA_ARGS__) #define LOG_INFO(logger, f, ...) \ - CLOG(LVL_INFO, logger) << fmt::format(f, ##__VA_ARGS__) + CLOG(LVL_INFO, logger) << fmt::format(f __VA_OPT__(, ) __VA_ARGS__) #define LOG_WARNING(logger, f, ...) \ - CLOG(LVL_WARNING, logger) << fmt::format(f, ##__VA_ARGS__) + CLOG(LVL_WARNING, logger) << fmt::format(f __VA_OPT__(, ) __VA_ARGS__) #define LOG_ERROR(logger, f, ...) \ - CLOG(LVL_ERROR, logger) << fmt::format(f, ##__VA_ARGS__) + CLOG(LVL_ERROR, logger) << fmt::format(f __VA_OPT__(, ) __VA_ARGS__) #define LOG_FATAL(logger, f, ...) \ - CLOG(LVL_FATAL, logger) << fmt::format(f, ##__VA_ARGS__) + CLOG(LVL_FATAL, logger) << fmt::format(f __VA_OPT__(, ) __VA_ARGS__) #define GET_LOG(name) name #define DEFAULT_LOG nullptr namespace stellar @@ -204,7 +210,8 @@ class Logging // custom formatters that can be used by fmt::format template -inline typename std::enable_if::is_enum, std::string>::type + requires xdr::xdr_traits::is_enum +inline std::string format_as(T const& u) { auto res = xdr::xdr_traits::enum_name(u); diff --git a/src/util/XDROperators.h b/src/util/XDROperators.h index e4d15018df..8a3591273e 100644 --- a/src/util/XDROperators.h +++ b/src/util/XDROperators.h @@ -9,5 +9,5 @@ namespace stellar { using xdr::operator==; -using xdr::operator<; +using xdr::operator<=>; } diff --git a/src/util/xdrquery/XDRFieldResolver.h b/src/util/xdrquery/XDRFieldResolver.h index 805c7e8155..9181beb025 100644 --- a/src/util/xdrquery/XDRFieldResolver.h +++ b/src/util/xdrquery/XDRFieldResolver.h @@ -4,8 +4,10 @@ #pragma once +#include #include #include +#include #include #include "crypto/Hex.h" @@ -26,6 +28,13 @@ namespace internal using namespace xdr; using namespace stellar; +// We need to use concepts to get subsumption +template +concept IsXdrClass = xdr_traits::is_class; + +template +concept IsXdrUnion = IsXdrClass && xdr_traits::is_union; + struct XDRFieldResolver { XDRFieldResolver(std::vector const& fieldPath, bool validate) @@ -50,8 +59,8 @@ struct XDRFieldResolver } template - typename std::enable_if_t::is_numeric && - !xdr_traits::is_enum> + requires xdr_traits::is_numeric + void operator()(T const& t, char const* fieldName) { if (checkLeafField(fieldName)) @@ -62,7 +71,8 @@ struct XDRFieldResolver // Retrieve enums as their XDR string representation. template - typename std::enable_if_t::is_enum> + requires xdr_traits::is_enum + void operator()(T const& t, char const* fieldName) { if (checkLeafField(fieldName)) @@ -72,9 +82,8 @@ struct XDRFieldResolver } // Retrieve public keys in standard string representation. - template - typename std::enable_if_t> - operator()(T const& k, char const* fieldName) + void + operator()(PublicKey const& k, char const* fieldName) { if (checkLeafField(fieldName)) { @@ -83,9 +92,8 @@ struct XDRFieldResolver } // Retrieve SCAddresses in standard string representation. - template - typename std::enable_if_t> - operator()(T const& k, char const* fieldName) + void + operator()(SCAddress const& k, char const* fieldName) { if (checkLeafField(fieldName)) { @@ -106,9 +114,9 @@ struct XDRFieldResolver } } - template - typename std::enable_if_t || - std::is_same_v> + template + requires std::same_as || std::same_as + void operator()(T const& asset, char const* fieldName) { if (!matchFieldToPath(fieldName)) @@ -213,7 +221,8 @@ struct XDRFieldResolver } template - typename std::enable_if_t::is_container> + requires xdr_traits::is_container + void operator()(T const& t, char const* fieldName) { if (matchFieldToPath(fieldName)) @@ -224,11 +233,8 @@ struct XDRFieldResolver } } - template - typename std::enable_if_t< - xdr_traits::is_union && !std::is_same_v && - !std::is_same_v && !std::is_same_v && - !xdr_traits::is_container && !std::is_same_v> + template + void operator()(T const& t, char const* fieldName) { if (!matchFieldToPath(fieldName)) @@ -252,12 +258,8 @@ struct XDRFieldResolver } } - template - typename std::enable_if_t< - xdr_traits::is_class && !std::is_same_v && - !std::is_same_v && !std::is_same_v && - !xdr_traits::is_union && !xdr_traits::is_container && - !std::is_same_v> + template + void operator()(T const& t, char const* fieldName) { if (!matchFieldToPath(fieldName)) @@ -333,8 +335,8 @@ struct XDRFieldResolver (*this)(asset.liquidityPoolID(), "liquidityPoolID"); } - template - typename std::enable_if_t::is_union> + template + void validateUnion(T const& t, char const* fieldName) { // The field could have been already matched if it was XDR discriminant. @@ -357,9 +359,9 @@ struct XDRFieldResolver } } - template - typename std::enable_if_t || - std::is_same_v> + template + requires std::same_as || std::same_as + void validateAsset(T const& asset, char const* fieldName) { // The field could have been already matched if it was a native asset. diff --git a/src/util/xdrquery/XDRQueryEval.cpp b/src/util/xdrquery/XDRQueryEval.cpp index 1d312d51dd..d1b6e763c6 100644 --- a/src/util/xdrquery/XDRQueryEval.cpp +++ b/src/util/xdrquery/XDRQueryEval.cpp @@ -4,6 +4,7 @@ #include "util/xdrquery/XDRQueryEval.h" #include "fmt/format.h" +#include "fmt/ranges.h" #include "util/xdrquery/XDRQueryError.h" namespace xdrquery