From 9e0d350fca688cfa6adae8ee0b16ec8ed8653f69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 9 Mar 2026 15:27:03 +0100 Subject: [PATCH 01/74] ci: [DEPENDABOT] bump tj-actions/changed-files from 47.0.4 to 47.0.5 (#6501) --- .github/workflows/on-pr.yml | 2 +- .github/workflows/reusable-clang-tidy.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/on-pr.yml b/.github/workflows/on-pr.yml index be6a92eea2..b0010fe0ba 100644 --- a/.github/workflows/on-pr.yml +++ b/.github/workflows/on-pr.yml @@ -46,7 +46,7 @@ jobs: # that Github considers any skipped jobs to have passed, and in # turn the required checks as well. id: changes - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | # These paths are unique to `on-pr.yml`. diff --git a/.github/workflows/reusable-clang-tidy.yml b/.github/workflows/reusable-clang-tidy.yml index 7050d3509f..5319c1627a 100644 --- a/.github/workflows/reusable-clang-tidy.yml +++ b/.github/workflows/reusable-clang-tidy.yml @@ -31,7 +31,7 @@ jobs: - name: Get changed C++ files id: changed_files - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | **/*.cpp @@ -41,7 +41,7 @@ jobs: - name: Get changed clang-tidy configuration id: changed_clang_tidy - uses: tj-actions/changed-files@7dee1b0c1557f278e5c7dc244927139d78c0e22a # v47.0.4 + uses: tj-actions/changed-files@22103cc46bda19c2b464ffe86db46df6922fd323 # v47.0.5 with: files: | .clang-tidy From 6b301efc8c0e66e29b57491b5c26640cd8b3bb54 Mon Sep 17 00:00:00 2001 From: Alex Kremer Date: Mon, 9 Mar 2026 15:25:52 +0000 Subject: [PATCH 02/74] chore: Enable clang-tidy `bugprone-unused-local-non-trivial-variable` check (#6458) --- .clang-tidy | 4 ++-- src/test/app/Manifest_test.cpp | 1 - src/test/rpc/LedgerEntry_test.cpp | 12 ++++-------- src/test/rpc/Peers_test.cpp | 4 ++-- src/xrpld/app/consensus/RCLConsensus.cpp | 2 -- 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 26c7995631..8eefa5fe37 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -60,6 +60,7 @@ Checks: "-*, bugprone-unhandled-exception-at-new, bugprone-unique-ptr-array-mismatch, bugprone-unsafe-functions, + bugprone-unused-local-non-trivial-variable, bugprone-virtual-near-miss, cppcoreguidelines-no-suspend-with-lock, cppcoreguidelines-virtual-class-destructor, @@ -85,13 +86,12 @@ Checks: "-*, performance-trivially-destructible " # --- -# more checks that have some issues that need to be resolved: +# checks that have some issues that need to be resolved: # # bugprone-crtp-constructor-accessibility, # bugprone-inc-dec-in-conditions, # bugprone-reserved-identifier, # bugprone-move-forwarding-reference, -# bugprone-unused-local-non-trivial-variable, # bugprone-switch-missing-default-case, # bugprone-suspicious-stringview-data-usage, # bugprone-suspicious-missing-comma, diff --git a/src/test/app/Manifest_test.cpp b/src/test/app/Manifest_test.cpp index 294d5210d9..dfa67e350f 100644 --- a/src/test/app/Manifest_test.cpp +++ b/src/test/app/Manifest_test.cpp @@ -248,7 +248,6 @@ public: // save should store all trusted master keys to db std::vector s1; std::vector keys; - std::string cfgManifest; for (auto const& man : inManifests) s1.push_back(toBase58(TokenType::NodePublic, man->masterKey)); unl->load({}, s1, keys); diff --git a/src/test/rpc/LedgerEntry_test.cpp b/src/test/rpc/LedgerEntry_test.cpp index 9d274b3549..ffc4329109 100644 --- a/src/test/rpc/LedgerEntry_test.cpp +++ b/src/test/rpc/LedgerEntry_test.cpp @@ -2583,13 +2583,10 @@ class LedgerEntry_test : public beast::unit_test::suite env(check::create(env.master, alice, XRP(100))); env.close(); - std::string const ledgerHash{to_string(env.closed()->header().hash)}; - { - // Request a check. - Json::Value const jrr = env.rpc("ledger_entry", to_string(checkId.key))[jss::result]; - BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check); - BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] == "100000000"); - } + // Request a check. + Json::Value const jrr = env.rpc("ledger_entry", to_string(checkId.key))[jss::result]; + BEAST_EXPECT(jrr[jss::node][sfLedgerEntryType.jsonName] == jss::Check); + BEAST_EXPECT(jrr[jss::node][sfSendMax.jsonName] == "100000000"); } public: @@ -2753,7 +2750,6 @@ class LedgerEntry_XChain_test : public beast::unit_test::suite, scEnv(xchain_create_claim_id(scBob, jvb, reward, mcBob)); scEnv.close(); - std::string bridge_index; { // request the xchain_claim_id via RPC Json::Value jvParams; diff --git a/src/test/rpc/Peers_test.cpp b/src/test/rpc/Peers_test.cpp index 8e4e560f3e..d72ad6d878 100644 --- a/src/test/rpc/Peers_test.cpp +++ b/src/test/rpc/Peers_test.cpp @@ -53,8 +53,8 @@ class Peers_test : public beast::unit_test::suite continue; if (!BEAST_EXPECT((*it).isMember(jss::tag))) continue; - auto tag = (*it)[jss::tag].asString(); - BEAST_EXPECTS((*it)[jss::tag].asString() == nodes[key], key); + auto const tag = (*it)[jss::tag].asString(); + BEAST_EXPECTS(tag == nodes[key], key); } BEAST_EXPECT(peers.isMember(jss::peers) && peers[jss::peers].isNull()); } diff --git a/src/xrpld/app/consensus/RCLConsensus.cpp b/src/xrpld/app/consensus/RCLConsensus.cpp index 98dccc0089..91f24a650c 100644 --- a/src/xrpld/app/consensus/RCLConsensus.cpp +++ b/src/xrpld/app/consensus/RCLConsensus.cpp @@ -78,8 +78,6 @@ RCLConsensus::Adaptor::Adaptor( if (validatorKeys_.nodeID != beast::zero && validatorKeys_.keys) { - std::stringstream ss; - JLOG(j_.info()) << "Validator identity: " << toBase58(TokenType::NodePublic, validatorKeys_.keys->masterPublicKey); From 1ee0567b140bf77a229c7699aa86d9c419f64d0f Mon Sep 17 00:00:00 2001 From: Alex Kremer Date: Mon, 9 Mar 2026 15:48:38 +0000 Subject: [PATCH 03/74] chore: Enable clang-tidy `bugprone-suspicious-missing-comma` check (#6468) --- .clang-tidy | 2 +- src/test/app/Invariants_test.cpp | 13 ++++++----- src/test/app/Manifest_test.cpp | 27 ++++++++-------------- src/test/app/ValidatorKeys_test.cpp | 19 +++++++--------- src/test/rpc/DepositAuthorized_test.cpp | 28 +++++++++-------------- src/test/rpc/ValidatorInfo_test.cpp | 30 ++++++++----------------- 6 files changed, 44 insertions(+), 75 deletions(-) diff --git a/.clang-tidy b/.clang-tidy index 8eefa5fe37..42cad608c4 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -49,6 +49,7 @@ Checks: "-*, bugprone-suspicious-include, bugprone-suspicious-memory-comparison, bugprone-suspicious-memset-usage, + bugprone-suspicious-missing-comma, bugprone-suspicious-realloc-usage, bugprone-suspicious-semicolon, bugprone-suspicious-string-compare, @@ -94,7 +95,6 @@ Checks: "-*, # bugprone-move-forwarding-reference, # bugprone-switch-missing-default-case, # bugprone-suspicious-stringview-data-usage, -# bugprone-suspicious-missing-comma, # bugprone-pointer-arithmetic-on-polymorphic-object, # bugprone-optional-value-conversion, # bugprone-too-small-loop-variable, diff --git a/src/test/app/Invariants_test.cpp b/src/test/app/Invariants_test.cpp index a01026c8ef..6a010a7e82 100644 --- a/src/test/app/Invariants_test.cpp +++ b/src/test/app/Invariants_test.cpp @@ -3499,12 +3499,13 @@ class Invariants_test : public beast::unit_test::suite precloseXrp); doInvariantCheck( - {"withdrawal must change vault and destination balance by " - "equal amount", - "withdrawal must decrease vault balance", - "withdrawal must increase destination balance", - "withdrawal and assets outstanding must add up", - "withdrawal and assets available must add up"}, + { + "withdrawal must change vault and destination balance by equal amount", + "withdrawal must decrease vault balance", + "withdrawal must increase destination balance", + "withdrawal and assets outstanding must add up", + "withdrawal and assets available must add up", + }, [&](Account const& A1, Account const& A2, ApplyContext& ac) { auto const keylet = keylet::vault(A1.id(), ac.view().seq()); diff --git a/src/test/app/Manifest_test.cpp b/src/test/app/Manifest_test.cpp index dfa67e350f..d9ecf89b26 100644 --- a/src/test/app/Manifest_test.cpp +++ b/src/test/app/Manifest_test.cpp @@ -423,24 +423,15 @@ public: // Format token string to test trim() std::vector const tokenBlob = { - " " - "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3ND" - "diNT\n", - " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2Iiwib" - "WFuaWZl \n", - "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncx" - "L3ZDeE\n", - "\t " - "hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4" - "U0tG\t \t\n", - "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUz" - "ZQU2\n", - "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZ" - "eXd1\n", - "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZW" - "RGdj\n", - "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0i" - "fQ==\n"}; + " eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n", + " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl \n", + "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE\n", + "\t hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t \t\n", + "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n", + "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n", + "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n", + "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n", + }; auto const manifest = "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/" diff --git a/src/test/app/ValidatorKeys_test.cpp b/src/test/app/ValidatorKeys_test.cpp index 32f6305a37..925c02131b 100644 --- a/src/test/app/ValidatorKeys_test.cpp +++ b/src/test/app/ValidatorKeys_test.cpp @@ -22,19 +22,15 @@ class ValidatorKeys_test : public beast::unit_test::suite std::string const tokenSecretStr = "paQmjZ37pKKPMrgadBLsuf9ab7Y7EUNzh27LQrZqoexpAs31nJi"; std::vector const tokenBlob = { - " " - "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n", - " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl " - " \n", - "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE" - "\n", - "\t " - "hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t " - "\t\n", + " eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n", + " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl \n", + "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE\n", + "\t hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t \t\n", "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n", "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n", "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n", - "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n"}; + "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n", + }; std::string const tokenManifest = "JAAAAAFxIe1FtwmimvGtH2iCcMJqC9gVFKilGfw1/vCxHXXLplc2GnMhAkE1agqXxBwD" @@ -52,7 +48,8 @@ class ValidatorKeys_test : public beast::unit_test::suite "NWF6dTJMVHlqL1pjQkpBbitmNGhtQTQ0U0tYbGtTTUFqak1rSWRyR1Rxa21SNjBzVG\n", "JaTjZOOUYwdk9UV3VYcUZ6eDFoSGIyL0RqWElVZXhDVGlITEcxTG9UdUp1eXdXbk55\n", "RFE9PSIsInZhbGlkYXRpb25fc2VjcmV0X2tleSI6IjkyRDhCNDBGMzYwMTc5MTkwMU\n", - "MzQTUzMzI3NzBDMkUwMTA4MDI0NTZFOEM2QkI0NEQ0N0FFREQ0NzJGMDQ2RkYifQ==\n"}; + "MzQTUzMzI3NzBDMkUwMTA4MDI0NTZFOEM2QkI0NEQ0N0FFREQ0NzJGMDQ2RkYifQ==\n", + }; public: void diff --git a/src/test/rpc/DepositAuthorized_test.cpp b/src/test/rpc/DepositAuthorized_test.cpp index 755609439c..9d6de94ccc 100644 --- a/src/test/rpc/DepositAuthorized_test.cpp +++ b/src/test/rpc/DepositAuthorized_test.cpp @@ -398,24 +398,16 @@ public: { static std::vector const credIds = { - "18004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4", - "28004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4", - "38004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4", - "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4", - "58004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4", - "68004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4", - "78004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4", - "88004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4", - "98004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288B" - "E4"}; + "18004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + "28004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + "38004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + "48004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + "58004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + "68004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + "78004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + "88004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + "98004829F915654A81B11C4AB8218D96FED67F209B58328A72314FB6EA288BE4", + }; assert(credIds.size() > maxCredentialsArraySize); testcase("deposit_authorized too long credentials"); diff --git a/src/test/rpc/ValidatorInfo_test.cpp b/src/test/rpc/ValidatorInfo_test.cpp index 41fa95940b..d4769f40fb 100644 --- a/src/test/rpc/ValidatorInfo_test.cpp +++ b/src/test/rpc/ValidatorInfo_test.cpp @@ -46,27 +46,15 @@ public: using namespace jtx; std::vector const tokenBlob = { - " " - "eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT" - "\n", - " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFua" - "WZl " - " \n", - "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZD" - "eE" - "\n", - "\t " - "hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG" - "\t " - "\t\n", - "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2" - "\n", - "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1" - "\n", - "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj" - "\n", - "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==" - "\n"}; + " eyJ2YWxpZGF0aW9uX3NlY3JldF9rZXkiOiI5ZWQ0NWY4NjYyNDFjYzE4YTI3NDdiNT\n", + " \tQzODdjMDYyNTkwNzk3MmY0ZTcxOTAyMzFmYWE5Mzc0NTdmYTlkYWY2IiwibWFuaWZl \n", + "\tc3QiOiJKQUFBQUFGeEllMUZ0d21pbXZHdEgyaUNjTUpxQzlnVkZLaWxHZncxL3ZDeE\n", + "\t hYWExwbGMyR25NaEFrRTFhZ3FYeEJ3RHdEYklENk9NU1l1TTBGREFscEFnTms4U0tG\t \t\n", + "bjdNTzJmZGtjd1JRSWhBT25ndTlzQUtxWFlvdUorbDJWMFcrc0FPa1ZCK1pSUzZQU2\n", + "hsSkFmVXNYZkFpQnNWSkdlc2FhZE9KYy9hQVpva1MxdnltR21WcmxIUEtXWDNZeXd1\n", + "NmluOEhBU1FLUHVnQkQ2N2tNYVJGR3ZtcEFUSGxHS0pkdkRGbFdQWXk1QXFEZWRGdj\n", + "VUSmEydzBpMjFlcTNNWXl3TFZKWm5GT3I3QzBrdzJBaVR6U0NqSXpkaXRROD0ifQ==\n", + }; std::string const master_key = "nHBt9fsb4849WmZiCds4r5TXyBeQjqnH5kzPtqgMAQMgi39YZRPa"; std::string const ephemeral_key = "n9KsDYGKhABVc4wK5u3MnVhgPinyJimyKGpr9VJYuBaY8EnJXR2x"; From e2290b1a0af2d90ca58b67c7d8b38cd8db1c2879 Mon Sep 17 00:00:00 2001 From: Sergey Kuznetsov Date: Mon, 9 Mar 2026 16:33:20 +0000 Subject: [PATCH 04/74] feat: Add mutex wrapper from clio (#6447) This change adds a mutex wrapper copied from clio. The wrapper attaches a mutex to the data it protects, which improves safety and readability. --- include/xrpl/basics/Mutex.hpp | 155 ++++++++++++++++ src/tests/libxrpl/basics/Mutex.cpp | 288 +++++++++++++++++++++++++++++ 2 files changed, 443 insertions(+) create mode 100644 include/xrpl/basics/Mutex.hpp create mode 100644 src/tests/libxrpl/basics/Mutex.cpp diff --git a/include/xrpl/basics/Mutex.hpp b/include/xrpl/basics/Mutex.hpp new file mode 100644 index 0000000000..18c57370b1 --- /dev/null +++ b/include/xrpl/basics/Mutex.hpp @@ -0,0 +1,155 @@ +/* + This file is part of clio: https://github.com/XRPLF/clio + Copyright (c) 2024, the clio developers. + + Permission to use, copy, modify, and distribute this software for any + purpose with or without fee is hereby granted, provided that the above + copyright notice and this permission notice appear in all copies. +*/ + +#pragma once + +#include +#include + +namespace xrpl { + +template +class Mutex; + +/** + * @brief A lock on a mutex that provides access to the protected data. + * + * @tparam ProtectedDataType data type to hold + * @tparam LockType type of lock + * @tparam MutexType type of mutex + */ +template typename LockType, typename MutexType> +class Lock +{ + LockType lock_; + ProtectedDataType& data_; + +public: + /** @cond */ + ProtectedDataType const& + operator*() const + { + return data_; + } + + ProtectedDataType& + operator*() + { + return data_; + } + + ProtectedDataType const& + get() const + { + return data_; + } + + ProtectedDataType& + get() + { + return data_; + } + + ProtectedDataType const* + operator->() const + { + return &data_; + } + + ProtectedDataType* + operator->() + { + return &data_; + } + + operator LockType&() & + { + return lock_; + } + + operator LockType const&() const& + { + return lock_; + } + /** @endcond */ + +private: + friend class Mutex, MutexType>; + + Lock(MutexType& mutex, ProtectedDataType& data) : lock_(mutex), data_(data) + { + } +}; + +/** + * @brief A container for data that is protected by a mutex. Inspired by Mutex in Rust. + * + * @tparam ProtectedDataType data type to hold + * @tparam MutexType type of mutex + */ +template +class Mutex +{ + mutable MutexType mutex_; + ProtectedDataType data_{}; + +public: + Mutex() = default; + + /** + * @brief Construct a new Mutex object with the given data + * + * @param data The data to protect + */ + explicit Mutex(ProtectedDataType data) : data_(std::move(data)) + { + } + + /** + * @brief Make a new Mutex object with the given data + * + * @tparam Args The types of the arguments to forward to the constructor of the protected data + * @param args The arguments to forward to the constructor of the protected data + * @return The Mutex object that protects the given data + */ + template + static Mutex + make(Args&&... args) + { + return Mutex{ProtectedDataType{std::forward(args)...}}; + } + + /** + * @brief Lock the mutex and get a lock object allowing access to the protected data + * + * @tparam LockType The type of lock to use + * @return A lock on the mutex and a reference to the protected data + */ + template