Compare commits

...

285 Commits

Author SHA1 Message Date
Ed Hennis
9a56cbbff0 Merge remote-tracking branch 'sophiax851/fix/rotation-missing-node' into ximinez/online-delete-gaps2
* sophiax851/fix/rotation-missing-node:
  fix: Copy archive reads forward during rotation to prevent node loss
2026-07-13 14:10:52 -04:00
Ed Hennis
d5ab8c2a4c Merge remote-tracking branch 'XRPLF/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* XRPLF/ximinez/online-delete-gaps:
  test: Add tests for check doxygen style (7795)
  style: Add pre-commit hook to check doxygen style (7794)
  style: Unify style for all Doxygen comments (7776)
2026-07-13 14:09:37 -04:00
Ed Hennis
7f58c3d7d6 Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  test: Add tests for check doxygen style (7795)
  style: Add pre-commit hook to check doxygen style (7794)
  style: Unify style for all Doxygen comments (7776)
2026-07-13 12:21:59 -04:00
Ayaz Salikhov
2b4d067ace test: Add tests for check doxygen style (#7795) 2026-07-13 14:38:33 +00:00
Ayaz Salikhov
62634463f4 style: Add pre-commit hook to check doxygen style (#7794) 2026-07-13 13:27:14 +00:00
Ayaz Salikhov
73b6852a12 style: Unify style for all Doxygen comments (#7776) 2026-07-13 10:40:40 +00:00
Ed Hennis
8d8c53b5d2 Merge remote-tracking branch 'mywork/ximinez/online-delete-gaps' into ximinez/online-delete-gaps2
* mywork/ximinez/online-delete-gaps:
  fix: Improve Number addition/subtraction rounding (7369)
  feat: XLS-68: Sponsor, 5887 continuation  (7350)
2026-07-12 18:42:47 -04:00
Ed Hennis
86f52c412c Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-12 18:38:08 -04:00
Ed Hennis
8485f491b9 Include the location from which a SHAMapMissingNode is thrown 2026-07-12 18:26:14 -04:00
Ed Hennis
22d2501360 Speed up rotation when disconnected, log resurrected fields
- Logs whether any recovered nodes are in the TreeNodeCache.
- Adds a special case to healthWait() to not pause when the server is
  DISCONNECTED.
2026-07-12 17:30:06 -04:00
Sophia Xie
ae3898d8b4 fix: Copy archive reads forward during rotation to prevent node loss 2026-07-11 16:35:22 -07:00
Ed Hennis
8306ac7710 fix: Improve Number addition/subtraction rounding (#7369)
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-11 00:18:31 +00:00
Ed Hennis
d4005e3393 Merge remote-tracking branch 'sophiax851/fix/rotation-missing-node' into ximinez/online-delete-gaps
* sophiax851/fix/rotation-missing-node:
  fix: Persist RAM-only clean nodes during online-delete rotation
2026-07-10 19:58:12 -04:00
Ed Hennis
0c5c3d88f4 Merge remote-tracking branch 'mathbunnyru/set_min_osx_target' into ximinez/online-delete-gaps
* mathbunnyru/set_min_osx_target:
  Document minimum macOS supported version
  build: Set CMAKE_OSX_DEPLOYMENT_TARGET to 26.0
2026-07-10 19:04:08 -04:00
Olek
fd2cc6dcb3 feat: XLS-68: Sponsor, #5887 continuation (#7350)
Co-authored-by: tequ <git@tequ.dev>
Co-authored-by: yinyiqian1 <yqian@ripple.com>
Co-authored-by: Mayukha Vadari <mvadari@ripple.com>
Co-authored-by: Mayukha Vadari <mvadari@gmail.com>
Co-authored-by: xrplf-ai-reviewer[bot] <266832837+xrplf-ai-reviewer[bot]@users.noreply.github.com>
Co-authored-by: Peter Chen <34582813+PeterChen13579@users.noreply.github.com>
Co-authored-by: Zhiyuan Wang <96991820+Kassaking7@users.noreply.github.com>
Co-authored-by: Ayaz Salikhov <asalikhov@ripple.com>
Co-authored-by: Ayaz Salikhov <mathbunnyru@users.noreply.github.com>
Co-authored-by: Zhiyuan Wang <1830604455@qq.com>
2026-07-10 21:58:19 +00:00
Ayaz Salikhov
348e7165be Document minimum macOS supported version 2026-07-10 14:01:31 +01:00
Ayaz Salikhov
3ecb992ef7 build: Set CMAKE_OSX_DEPLOYMENT_TARGET to 26.0 2026-07-10 13:50:11 +01:00
Sophia Xie
fee6e32060 Merge branch 'develop' into fix/rotation-missing-node 2026-07-08 14:38:50 -07:00
Sophia Xie
c364ebbbeb fix: Persist RAM-only clean nodes during online-delete rotation
fix: Log when a clean node missing from both backends is re-stored

Addional guardrails and logging
2026-07-08 14:35:13 -07:00
Ed Hennis
4dce2f22b6 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-08 17:23:11 -04:00
Sergey Kuznetsov
c7adb215ed chore: Add .envrc for automatic devshell switch by direnv (#7756) 2026-07-08 17:28:48 +00:00
Ayaz Salikhov
71ee0f400b chore: Use same compiler in Nix devshell as in CI (#7751) 2026-07-08 14:51:39 +00:00
Ed Hennis
fe8368b970 Update test to ensure correct starting conditions 2026-07-07 20:26:55 -04:00
Ed Hennis
d68273c755 Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-07 19:32:20 -04:00
Ed Hennis
df489c7a6e Tweak log message levels
- lastGoodValidatedLedger_ update is now trace.
- Log the first healthWait failure for a given validated ledger as
  trace.
2026-07-07 17:29:42 -04:00
Ed Hennis
b45038f70a Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-07 15:50:15 -04:00
Ed Hennis
44cc4e656f Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-06 13:32:00 -04:00
Ed Hennis
ac3435bf0a Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-02 19:03:48 -04:00
Ed Hennis
bd2f5dbd35 AI review feedback: variable initialization, comments, headers 2026-07-02 19:01:51 -04:00
Ed Hennis
4644347d21 Apply suggestions from code review: fix typos
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
2026-07-02 18:48:43 -04:00
Ed Hennis
e34e05ebec Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  refactor: Retire DisallowIncomingV1 fix (7364)
  build: Add verify-headers target to cleanup headers (7670)
2026-07-02 11:17:33 -04:00
Ed Hennis
9b22c6c80b Reorganize healthWait to avoid deadlock and duplicated code 2026-07-01 18:38:03 -04:00
Ed Hennis
d4e166bbdc Merge branch 'develop' into ximinez/online-delete-gaps 2026-07-01 13:24:20 -04:00
Ed Hennis
b80776b0fe Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-30 14:38:54 -04:00
Ed Hennis
9af4fb521e Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-29 20:05:54 -04:00
Ed Hennis
7ee290674c Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-25 11:43:17 -04:00
Ed Hennis
68f050b186 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-24 19:59:59 -04:00
Ed Hennis
2be13c18a1 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-23 11:09:48 -04:00
Ed Hennis
df5fa5aade Correct a couple of comments 2026-06-22 16:48:00 -04:00
Ed Hennis
51ef3a7343 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-22 16:41:46 -04:00
Ed Hennis
dd4eca22b7 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-17 15:01:23 -04:00
Ed Hennis
1116dbfd0e Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-16 18:56:01 -04:00
Ed Hennis
258d5e1f1f clang-tidy: nodiscard rendezvous, headers, const correctness, {}s 2026-06-16 18:47:40 -04:00
Ed Hennis
4270367efc Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-15 21:32:49 -04:00
Ed Hennis
fad34e852d More AI review feedback:
- Move a log message into the same block as the thing it's logging.
- Change default recovery time from 1s to 2s. This may need some more
  tuning.
- Rename the online_delete test config helper function to onlineDelete.
- Copy some class values while under lock, even though they can't
  change, as defense in depth.
- Use RAII scope unlock in healthWait().
2026-06-15 21:28:23 -04:00
Ed Hennis
f5b4ac358f AI review feedback
- Remove extraneous function declaration.
- Add a timeout to SHAMapStore_test::testLedgerGaps so it won't hang in
  case of regression.
- Add an optional timeout parameter to SHAMapStore::rendezvous, and
  return a success flag.
  - Use the timeout in SHAMapStore_test::testLedgerGaps to show lack of
    progress in the Store without an arbitrary sleep delay.
- Refactor LedgerMaster::missingFromCompleteLedgerRange to use RangeSet
  functions instead of a naive iteration.
- If lastGoodValidatedLedger_ is default (0) in healthWait(), then act
  as if no ledgers are missing.
2026-06-15 20:13:40 -04:00
Ed Hennis
875bcc530e Correct a couple of variable names 2026-06-15 16:47:29 -04:00
Ed Hennis
e75f5b101b Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-15 15:28:44 -04:00
Ed Hennis
95f74d61b2 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-15 12:11:54 -04:00
Ed Hennis
4e12b787be Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop: (22 commits)
  test: Add null check unit test for `Oracle::aggregatePrice` (7306)
  ci: Patch conan recipe for Nix to be able to use on macOS (7532)
  ci: Run sanitizers on release builds too (7527)
  fix: Correct hybrid offer deletion on credential expiry (6843)
  ci: Make sanitizer flags lists in the profile, not a string (7449)
  ci: Make configurations launch on certain event types (7447)
  fix: Add [[maybe_unused]] to fix320Enabled for assert=OFF builds (7446)
  ci: Add `gh` and `file` to nix packages (7444)
  fix: Disable transaction invariants (7409)
  perf: Dispatch "hasInvalidAmount()" on type tag instead of dynamic_cast (7402)
  refactor: Retire fixUniversalNumber amendment (5962)
  test: Do not create data directory for memory databases (7323)
  ci: Launch upload-conan-deps on profile change (7442)
  fix: Fix Number comparison operator (7406)
  feat: Use C++ 23 standard (7431)
  refactor: Introduce XRPL_ASSERT_IF for amendment-gated assertions (7378)
  refactor: Change config section and key string literals into constants (7095)
  refactor: Use `std::move` and `std::string_view` where possible (7424)
  refactor: Use const function arguments where possible (7423)
  ci: Use XRPLF/actions build-multiarch-image workflow (7428)
  ...
2026-06-11 21:34:19 -04:00
Ed Hennis
8b6c80027b Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-05 18:48:40 -04:00
Ed Hennis
ace73678cf Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-04 13:32:19 -04:00
Ed Hennis
12bbba00b0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-04 10:08:25 -04:00
Ed Hennis
2affb66f50 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-02 11:58:29 -04:00
Ed Hennis
d09e785c39 Merge branch 'develop' into ximinez/online-delete-gaps 2026-06-01 14:24:26 -04:00
Ed Hennis
97fdf310f9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-28 23:47:49 -04:00
Ed Hennis
d3ce76825c Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-27 17:00:52 -04:00
Ed Hennis
1e7e274727 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-27 15:18:10 -04:00
Ed Hennis
b272d71cc7 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-27 12:06:52 -04:00
Ed Hennis
21268d9c36 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-26 19:20:55 -04:00
Ed Hennis
932e22df7d Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-26 16:56:36 -04:00
Ed Hennis
652a7cd225 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-26 16:01:32 -04:00
Ed Hennis
4a224dbfa4 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-22 17:56:07 -04:00
Ed Hennis
d2a5981f87 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-21 14:25:41 -04:00
Ed Hennis
a977836630 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-21 10:09:42 -04:00
Ed Hennis
bf075200bb Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  docs: Add --parallel flag to cmake build commands in BUILD.md (7302)
  fix: Fix wrong hybrid offer orderbook placement and update `LedgerStateFix` to amend `ExchangeRate` meta (7087)
  style: More clang-tidy identifier renaming (7290)
  fix: Update pDEX invariant firing under a valid offer deletion (7118)
  fix: Fix multisign and signfor to check for delegate (7064)
  refactor: Fix `sfGeneric` and `sfInvalid` field names (7300)
  docs: Fix some comments to improve readability (7122)
  feat: Propagate underlying MPT flags to vault shares (7077)
2026-05-21 11:59:26 +01:00
Ed Hennis
ee49e76a16 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-19 16:53:27 -04:00
Ed Hennis
c1318990f3 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-19 10:15:02 -04:00
Ed Hennis
69128294f8 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-19 05:15:40 -04:00
Ed Hennis
149e884ebc Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-15 21:32:03 -04:00
Ed Hennis
d27353225c Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  release: Set version to 3.3.0-b0 (7280)
  refactor: Rename static constants (7120)
  refactor: Use `isFlag` where possible instead of bitwise math (7278)
  ci: Update XRPLF/actions (7281)
2026-05-15 15:47:01 -04:00
Ed Hennis
13a0f77eb5 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-14 20:39:04 -04:00
Ed Hennis
549c093398 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-13 20:16:12 -04:00
Ed Hennis
fb66ca7a2e Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-13 12:03:27 -04:00
Ed Hennis
e2af73b0a0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-12 19:18:39 -04:00
Ed Hennis
14c3c9a256 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-12 16:26:02 -04:00
Ed Hennis
4b6851a287 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-12 15:59:13 -04:00
Ed Hennis
d182673d24 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-11 13:33:56 -04:00
Ed Hennis
bea609d805 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-07 18:09:54 -04:00
Ed Hennis
56eeb20bc8 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-07 14:18:14 -04:00
Ed Hennis
e293a3d918 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-07 13:28:18 -04:00
Ed Hennis
3dff580d39 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-06 22:34:11 -04:00
Ed Hennis
487f5a0fd3 clang-tidy fix: lock_guard -> scoped_lock 2026-05-06 18:44:16 -04:00
Ed Hennis
d8134f98e9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-06 14:17:47 -04:00
Ed Hennis
450a623d4b Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-05 16:46:26 -04:00
Ed Hennis
9e517be4ce Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-05 10:50:18 -04:00
Ed Hennis
b8370438fb Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  ci: Rewrite clang-tidy workflow(s) in a reusable manner (7062)
  chore: Ignore identifier-naming update in git blame (7066)
  refactor: Enable clang-tidy `readability-identifier-naming` check (6571)
2026-05-04 21:36:05 -04:00
Ed Hennis
ecb5604d3b Merge branch 'develop' into ximinez/online-delete-gaps 2026-05-01 12:54:31 -04:00
Ed Hennis
c4527e7b0f Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  fix: Gate -mcmodel flags to x86_64 in sanitizer builds (7049)
  fix: Prevents overwriting a bool value in an invariant (6609)
  fix: Address code review comments regarding `boost::coroutine2` (6977)
  refactor: Apply various minor improvements and corrections (7045)
  fix: Store `Delegate` object in delegating and authorized account directories for proper deletion (6681)
  ci: Use print-env from XRPLF/actions (7052)
  fix: Make assorted RPC fixes (6529)
  chore: Enable clang-tidy v21 new checks (7031)
2026-04-30 14:30:36 -04:00
Ed Hennis
778e2b3ce8 Fix clang-tidy: missing include 2026-04-28 15:44:14 -05:00
Ed Hennis
295d03aec8 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-28 16:23:08 -04:00
Ed Hennis
9262c2e624 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-25 14:41:57 -04:00
Ed Hennis
b385a41aa5 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-23 15:55:43 -04:00
Ed Hennis
4eb9726097 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-22 23:39:00 -04:00
Ed Hennis
28a38ef1cc Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-22 14:48:51 -04:00
Ed Hennis
39f9380b2b Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-22 11:36:03 -04:00
Ed Hennis
239fcaceb4 clang-tidy fix: Use std::to_string for std::uint32_t 2026-04-21 19:30:05 -04:00
Ed Hennis
8ab86f009e Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-21 18:47:53 -04:00
Ed Hennis
d4b58a74f4 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-21 14:37:52 -04:00
Ed Hennis
ff900591ae Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-21 10:40:45 -04:00
Ed Hennis
a5b7471af6 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-20 17:49:20 -04:00
Ed Hennis
e0734986dd Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-20 15:44:37 -04:00
Ed Hennis
8440f479e5 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-20 11:37:54 -04:00
Ed Hennis
ac390622e0 Fix clang-tidy issues 2026-04-17 17:54:37 -04:00
Ed Hennis
5d807f0d6d Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  chore: Enable clang-tidy include cleaner (6947)
  fix: Change AMMClawback return code to tecNO_PERMISSION (6946)
  ci: [DEPENDABOT] bump actions/upload-pages-artifact from 4.0.0 to 5.0.0 (6927)
  ci: [DEPENDABOT] bump actions/upload-artifact from 7.0.0 to 7.0.1 (6928)
  chore: Enable clang-tidy readability checks (6930)
2026-04-17 15:23:33 -04:00
Ed Hennis
b93294f26b Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-16 13:44:23 -04:00
Ed Hennis
ef95ace0f9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-15 19:06:15 -04:00
Ed Hennis
fc58bf6edf Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-15 14:28:41 -04:00
Ed Hennis
348555d5ba Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-13 20:28:29 -04:00
Ed Hennis
302802e42d Fix clang-tidy issues 2026-04-13 20:23:23 -04:00
Ed Hennis
5d881f87a3 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-10 12:12:27 -04:00
Ed Hennis
a8a8035b32 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-10 09:10:39 -04:00
Ed Hennis
45af14231f Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-09 11:39:55 -04:00
Ed Hennis
380bf274d0 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-08 16:56:56 -04:00
Ed Hennis
460ec5eeea Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-08 15:12:46 -04:00
Ed Hennis
14be8ca4ea Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-07 16:47:32 -04:00
Ed Hennis
948264d44c Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-06 19:06:51 -04:00
Ed Hennis
9c816b2043 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-06 18:33:20 -04:00
Ed Hennis
f68402acd1 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-06 16:52:50 -04:00
Ed Hennis
5358e25eaa Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-06 13:24:22 -04:00
Ed Hennis
a34d1e5537 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-01 17:26:14 -04:00
Ed Hennis
78a122943d Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-01 13:39:05 -04:00
Ed Hennis
06135e7203 Merge branch 'develop' into ximinez/online-delete-gaps 2026-04-01 11:45:32 -04:00
Ed Hennis
f20425fa4f Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-30 21:29:37 -04:00
Ed Hennis
3e94546acc Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-12 15:05:04 -04:00
Ed Hennis
3b088ed0dc Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-10 12:46:18 -04:00
Ed Hennis
26182ed52e Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-06 13:04:00 -04:00
Ed Hennis
de2a3e10f5 Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-05 21:34:29 -04:00
Ed Hennis
e17f8554fc Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-04 17:11:27 -04:00
Ed Hennis
386a7192ba Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-03 20:46:41 -04:00
Ed Hennis
12cc6e424d Merge branch 'develop' into ximinez/online-delete-gaps 2026-03-03 15:54:32 -04:00
Ed Hennis
c9deecf1b7 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-24 17:34:32 -04:00
Ed Hennis
ddd1b49f38 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-24 16:45:55 -04:00
Ed Hennis
c1b2a24005 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 18:49:39 -04:00
Ed Hennis
86d88eca31 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 18:25:58 -04:00
Ed Hennis
ef09eaea00 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 17:31:41 -04:00
Ed Hennis
c504cfb291 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 17:21:03 -04:00
Ed Hennis
0c217dfa2b Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-20 15:14:23 -04:00
Ed Hennis
b0198d2566 Merge remote-tracking branch 'upstream/develop' into ximinez/online-delete-gaps
* upstream/develop:
  ci: Add dependabot config (6379)
  Fix tautological assertion (6393)
  chore: Apply clang-format width 100 (6387)
2026-02-20 12:20:07 -05:00
Ed Hennis
7eee8ca802 Update formatting 2026-02-20 12:15:30 -05:00
Ed Hennis
2a079a0154 Merge commit '25cca465538a56cce501477f9e5e2c1c7ea2d84c' into ximinez/online-delete-gaps
* commit '25cca465538a56cce501477f9e5e2c1c7ea2d84c':
  chore: Set clang-format width to 100 in config file (6387)
2026-02-20 12:12:56 -05:00
Ed Hennis
40989c1178 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-19 16:21:11 -05:00
Ed Hennis
addc831eb3 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-18 18:06:20 -04:00
Ed Hennis
b4efc6d116 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-04 16:29:49 -04:00
Ed Hennis
125d075d6e Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-04 14:16:24 -04:00
Ed Hennis
370a775479 Merge branch 'develop' into ximinez/online-delete-gaps 2026-02-03 16:07:47 -04:00
Ed Hennis
1a2ee706eb Fix formatting 2026-01-28 19:43:23 -05:00
Ed Hennis
2a981357ba Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-28 18:40:24 -04:00
Ed Hennis
1ae475e724 Merge commit '5f638f55536def0d88b970d1018a465a238e55f4' into ximinez/online-delete-gaps
* commit '5f638f55536def0d88b970d1018a465a238e55f4':
  chore: Set ColumnLimit to 120 in clang-format (6288)
2026-01-28 17:38:29 -05:00
Ed Hennis
a3e9401fbc Merge commit '92046785d1fea5f9efe5a770d636792ea6cab78b' into ximinez/online-delete-gaps
* commit '92046785d1fea5f9efe5a770d636792ea6cab78b':
  test: Fix the `xrpl.net` unit test using async read (6241)
  ci: Upload Conan recipes for develop, release candidates, and releases (6286)
  fix: Stop embedded tests from hanging on ARM by using `atomic_flag` (6248)
  fix:  Remove DEFAULT fields that change to the default in associateAsset (6259) (6273)
  refactor: Update Boost to 1.90 (6280)
  refactor: clean up uses of `std::source_location` (6272)
  ci: Pass missing sanitizers input to actions (6266)
  ci: Properly propagate Conan credentials (6265)
  ci: Explicitly set version when exporting the Conan recipe (6264)
  ci: Use plus instead of hyphen for Conan recipe version suffix (6261)
  chore: Detect uninitialized variables in CMake files (6247)
  ci: Run on-trigger and on-pr when generate-version is modified (6257)
  refactor: Enforce 15-char limit and simplify labels for thread naming (6212)
  docs: Update Ripple Bug Bounty public key (6258)
  ci: Add missing commit hash to Conan recipe version (6256)
  fix: Include `<functional>` header in `Number.h` (6254)
  ci: Upload Conan recipe for merges into develop and commits to release (6235)
  Limit reply size on `TMGetObjectByHash` queries (6110)
  ci: remove 'master' branch as a trigger (6234)
  Improve ledger_entry lookups for fee, amendments, NUNL, and hashes (5644)
2026-01-28 17:38:13 -05:00
Ed Hennis
9091469f9e Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-15 13:03:03 -04:00
Ed Hennis
17fa54f1f9 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-15 12:05:41 -04:00
Ed Hennis
8fb5347c2d Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-14 19:20:11 -04:00
Ed Hennis
6739bf998f Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-13 18:04:18 -04:00
Ed Hennis
6eea38ba67 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-13 16:15:44 -04:00
Ed Hennis
e9cf88b359 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-13 15:01:56 -04:00
Ed Hennis
645b203476 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-12 21:07:23 -04:00
Ed Hennis
be2aff1f4c Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-12 14:51:34 -04:00
Ed Hennis
56ed237e82 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-11 00:48:27 -04:00
Ed Hennis
fd7b0fd135 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-08 17:05:28 -04:00
Ed Hennis
e700994891 Merge branch 'develop' into ximinez/online-delete-gaps 2026-01-08 13:03:41 -04:00
Ed Hennis
c76f7029ac Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  test: add more tests for `ledger_entry` RPC (5858)
  refactor: Rename `rippled.cfg` to `xrpld.cfg` (6098)
  Revert "chore: Pin ruamel.yaml<0.19 in pre-commit-hooks (6166)" (6167)
  chore: Pin ruamel.yaml<0.19 in pre-commit-hooks (6166)
  fix: Remove cryptographic libs from libxrpl Conan package (6163)
2026-01-06 11:27:23 -05:00
Ed Hennis
d535c5fb2a Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-22 17:39:25 -05:00
Ed Hennis
54f860463e Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-18 18:15:15 -05:00
Ed Hennis
950434b8ff Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-17 12:12:39 -05:00
Ed Hennis
ee365e876d Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-12 20:34:29 -05:00
Ed Hennis
c6c59834b9 Update View info() to header() 2025-12-12 15:35:07 -05:00
Ed Hennis
63b47914b8 Merge remote-tracking branch 'XRPLF/develop' into ximinez/online-delete-gaps
* XRPLF/develop:
  refactor: Rename `ripple` namespace to `xrpl` (5982)
  refactor: Move JobQueue and related classes into xrpl.core module (6121)
  refactor: Rename `rippled` binary to `xrpld` (5983)
2025-12-11 15:25:43 -05:00
Ed Hennis
9e02e5be2e Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-10 18:55:14 -05:00
Ed Hennis
093cd70fa1 Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-05 21:12:43 -05:00
Ed Hennis
376d65a483 Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-02 17:21:39 -05:00
Ed Hennis
a0d9a2458e Merge branch 'develop' into ximinez/online-delete-gaps 2025-12-01 14:40:15 -05:00
Ed Hennis
456f639cf7 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-28 15:46:19 -05:00
Ed Hennis
2c559ec2f3 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-27 01:48:33 -05:00
Ed Hennis
619c81f463 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-26 00:24:50 -05:00
Ed Hennis
f1490df960 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-25 14:54:38 -05:00
Ed Hennis
7bdf74de98 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-24 21:48:42 -05:00
Ed Hennis
1743d6fb98 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-24 21:29:52 -05:00
Ed Hennis
ca7a5bb926 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-21 12:47:28 -05:00
Ed Hennis
ce8b1a3f1e Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-18 22:39:06 -05:00
Ed Hennis
486fa75a10 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-15 03:08:18 -05:00
Ed Hennis
f8d68cd3d3 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-13 12:18:08 -05:00
Ed Hennis
ef7a3f5606 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-12 13:59:45 -05:00
Ed Hennis
4f84ed7490 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-10 19:52:42 -05:00
Ed Hennis
d534103131 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-10 15:34:55 -05:00
Ed Hennis
82dff3c2ce Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-08 22:49:26 -05:00
Ed Hennis
30d73eb5ba Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-06 23:50:23 -05:00
Ed Hennis
1b2754bac2 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-05 22:23:07 -05:00
Ed Hennis
cf80cafc75 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-04 18:02:30 -05:00
Ed Hennis
b8897d51de Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-03 18:03:56 -05:00
Ed Hennis
3ff25eeb65 Merge branch 'develop' into ximinez/online-delete-gaps 2025-11-03 12:41:48 -05:00
Ed Hennis
2bbfc4e786 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-31 13:51:15 -04:00
Ed Hennis
2b1eb052e6 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-31 12:51:24 -04:00
Ed Hennis
360e214e54 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-29 14:23:10 -04:00
Ed Hennis
2618afed94 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-29 13:42:21 -04:00
Ed Hennis
698ba2c788 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-29 12:54:16 -04:00
Ed Hennis
b614e99588 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-28 17:38:21 -04:00
Ed Hennis
fe8e4af2fa Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-26 19:12:33 -04:00
Ed Hennis
0a897f1528 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-23 13:24:25 -04:00
Ed Hennis
cf8a3f5779 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-22 11:38:49 -04:00
Ed Hennis
db39a39868 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-21 22:20:04 -04:00
Ed Hennis
37a03d28c2 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-17 18:21:36 -04:00
Ed Hennis
19d275425a Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-16 13:12:08 -04:00
Ed Hennis
88e9045602 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-16 10:48:43 -04:00
Ed Hennis
5adbc536b6 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-10 13:01:32 -04:00
Ed Hennis
e27af94ba9 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-09 15:14:47 -04:00
Ed Hennis
43fe1e7e9c Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-08 14:21:34 -04:00
Ed Hennis
f456a858c8 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-02 11:03:07 -04:00
Ed Hennis
084c3aa88e Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-01 18:10:57 -04:00
Ed Hennis
34f9b63921 Merge branch 'develop' into ximinez/online-delete-gaps 2025-10-01 13:14:22 -04:00
Ed Hennis
bd3de79817 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-30 22:28:53 -04:00
Ed Hennis
304eee2259 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-29 18:34:43 -04:00
Ed Hennis
9e729b7f59 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-29 17:37:16 -04:00
Ed Hennis
dd141468c4 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-29 13:32:03 -04:00
Ed Hennis
933147c21f Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-26 19:25:58 -04:00
Ed Hennis
9201a4f591 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-26 13:41:27 -04:00
Ed Hennis
5adb1e9b8b Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-26 12:09:09 -04:00
Ed Hennis
4df84d7988 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-25 13:27:09 -04:00
Bart
cd87c0968b Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-24 09:35:19 +02:00
Ed Hennis
8a8e7c90bf Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-20 15:44:32 -04:00
Ed Hennis
e806069065 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-18 14:08:23 -04:00
Ed Hennis
ce948cbec0 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-18 12:26:34 -04:00
Ed Hennis
6ed34b3294 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-18 11:54:30 -04:00
Ed Hennis
7161a235ca Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-17 10:49:03 -04:00
Ed Hennis
71463810de Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-16 10:46:37 -04:00
Ed Hennis
e997219a85 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-15 11:13:28 -04:00
Ed Hennis
895cc13fa6 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-11 10:33:14 -04:00
Ed Hennis
8d3c3ca29a Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-10 18:53:24 -04:00
Ed Hennis
9829553807 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-09 17:14:20 -04:00
Ed Hennis
e551f9731a Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-08 11:41:46 -04:00
Ed Hennis
fd827bf58b Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-05 17:44:06 -04:00
Ed Hennis
5a3baba34d Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-04 20:24:55 -04:00
Ed Hennis
c78f5b160f Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-04 16:43:48 -04:00
Ed Hennis
485f78761a Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-04 12:26:55 -04:00
Ed Hennis
23cd2f7b21 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-04 10:14:10 -04:00
Ed Hennis
5753266c43 Merge branch 'develop' into ximinez/online-delete-gaps 2025-09-03 14:04:01 -04:00
Ed Hennis
4722d2607d Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-29 15:52:53 -04:00
Ed Hennis
85b5b4f855 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-29 10:42:50 -04:00
Ed Hennis
a16f492f0f Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-28 18:17:26 -04:00
Ed Hennis
3633dc632c Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-27 11:14:59 -04:00
Ed Hennis
b3b30c3a86 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-25 14:10:52 -04:00
Ed Hennis
c78a7684f4 Remove trailing space 2025-08-25 14:09:57 -04:00
Ed Hennis
cf83d92630 Merge remote-tracking branch 'upstream/develop' into ximinez/online-delete-gaps
* upstream/develop:
  chore: Remove codecov token check to support tokenless uploads on forks (5722)
  Set version to 2.6.0-rc3
  Revert "perf: Move mutex to the partition level (5486)"
  chore: Update clang-format and prettier with pre-commit (5709)
  fix(test): handle null metadata for unvalidated tx in Env::meta (5715)
  chore: Workaround for CI build errors on arm64 (5717)
  chore: Fix file formatting (5718)
  fix: Skip notify-clio when running in a fork, reorder config fields (5712)
  chore: Reverts formatting changes to external files, adds formatting changes to proto files (5711)
2025-08-25 14:05:49 -04:00
Ed Hennis
a56b1274d8 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-21 11:38:54 -04:00
Ed Hennis
ae4bdd0492 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-19 16:05:17 -04:00
Ed Hennis
e90102dd3b Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-18 12:15:38 -04:00
Ed Hennis
71f0e8db3d Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-08 18:23:24 -04:00
Ed Hennis
638929373a Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-08 11:10:20 -04:00
Ed Hennis
8440654377 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-06 21:03:00 -04:00
Ed Hennis
9fa66c4741 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-05 21:16:44 -04:00
Ed Hennis
38a9235145 Merge branch 'develop' into ximinez/online-delete-gaps 2025-08-04 13:04:52 -04:00
Ed Hennis
c7a3cc9108 Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-29 20:33:29 -04:00
Ed Hennis
248337908d Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-29 11:54:16 -04:00
Ed Hennis
3d003619fd Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-28 20:57:13 -04:00
Ed Hennis
f163dca12c Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-24 15:50:09 -04:00
Ed Hennis
6e0ce458e5 Revert "TEMP: Change some logging to fatal to diagnose CI failures"
This reverts commit 69cf18158b.
2025-07-22 19:41:02 -04:00
Ed Hennis
5fae8480f1 Revert "TEMP: Add logging to SHAMapStore test"
This reverts commit fe7d0798a7.
2025-07-22 19:40:58 -04:00
Ed Hennis
e6587d374a fixup! Tweak SHAMapStore test timing more 2025-07-22 19:39:58 -04:00
Ed Hennis
376cc404e0 Tweak SHAMapStore test timing more 2025-07-22 18:44:07 -04:00
Ed Hennis
9898ca638f Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-22 14:09:33 -04:00
Ed Hennis
34b46d8f7c Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-21 18:20:41 -04:00
Ed Hennis
fe7d0798a7 TEMP: Add logging to SHAMapStore test 2025-07-21 18:19:53 -04:00
Ed Hennis
0cecc09d71 Tweak timing of SHAMapStore test 2025-07-21 18:19:28 -04:00
Ed Hennis
e091d55561 Try to fix timing of LedgerMaster test 2025-07-21 15:14:42 -04:00
Ed Hennis
69cf18158b TEMP: Change some logging to fatal to diagnose CI failures 2025-07-21 14:32:08 -04:00
Ed Hennis
6513c53817 Improve logging
- There's still a race condition in there
2025-07-21 14:30:49 -04:00
Ed Hennis
e13baa58a5 Fix build errors 2025-07-21 13:31:09 -04:00
Ed Hennis
951056fe9b Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-18 18:33:10 -04:00
Ed Hennis
67700ea6bd Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-16 12:54:23 -04:00
Ed Hennis
e5442cf3f1 Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-15 19:36:25 -04:00
Ed Hennis
da68076f04 Change default recovery wait time to 1s
See https://github.com/XRPLF/rippled/pull/5531#issuecomment-3058218837
2025-07-14 14:13:32 -04:00
Ed Hennis
b24116a118 Improve locking, logging, and test output
- Add more info to the error message on some failed tests.
- Add logging details to SHAMapStoreImp
2025-07-14 14:13:27 -04:00
Ed Hennis
f67398c6bf Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-11 19:27:31 -04:00
Ed Hennis
43d3eb1a24 Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-10 21:25:22 -04:00
Ed Hennis
0993315ed5 Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-10 12:30:18 -04:00
Ed Hennis
0bc383ada9 Fix build errors 2025-07-08 20:15:05 -04:00
Ed Hennis
1841ceca43 Add more logging to SHAMapStore rotation 2025-07-08 16:05:03 -04:00
Ed Hennis
2714cebabd Revert "TEMP: Change logging to show progress during unit test"
This reverts commit e184db4ce2.
2025-07-08 16:02:45 -04:00
Ed Hennis
e184db4ce2 TEMP: Change logging to show progress during unit test 2025-07-08 16:02:19 -04:00
Ed Hennis
ac6dc6943c Tweak when the starting range of ledger gap detection is set
- Add a test to exercise online delete ledger gap detection
2025-07-08 16:01:23 -04:00
Ed Hennis
ddd53806df Add a test to exercise LedgerMaster::missingFromCompleteLedgerRange 2025-07-08 13:22:47 -04:00
Ed Hennis
e629a1f70e Merge branch 'develop' into ximinez/online-delete-gaps 2025-07-03 15:51:23 -04:00
Ed Hennis
68076d969c fixup! fixup! Pause online delete if there any any gaps in recent ledger history 2025-07-02 19:05:06 -04:00
Ed Hennis
d3009d3e1c fixup! Pause online delete if there any any gaps in recent ledger history 2025-07-02 18:51:42 -04:00
Ed Hennis
54f7f3c894 Pause online delete if there any any gaps in recent ledger history 2025-07-02 18:45:48 -04:00
797 changed files with 33425 additions and 13958 deletions

View File

@@ -279,6 +279,8 @@ words:
- sles
- soci
- socidb
- sponsee
- sponsees
- SRPMS
- sslws
- statsd
@@ -300,6 +302,7 @@ words:
- takerpays
- ters
- TMEndpointv2
- tparam
- trixie
- tx
- txid
@@ -327,6 +330,7 @@ words:
- unserviced
- unshareable
- unshares
- unsponsored
- unsquelch
- unsquelched
- unsquelching

1
.envrc Normal file
View File

@@ -0,0 +1 @@
use flake

View File

@@ -43,6 +43,11 @@ repos:
language: python
entry: ./bin/pre-commit/fix_pragma_once.py
files: \.(h|hpp)$
- id: check-doxygen-style
name: check Doxygen comment style
entry: ./bin/pre-commit/check_doxygen_style.py
language: python
types_or: [c++, c]
- repo: https://github.com/pre-commit/mirrors-clang-format
rev: dd18dad857d6133e90bbe478f4f2f22ec0030269 # frozen: v22.1.5

View File

@@ -41,7 +41,10 @@ Our Linux CI tooling is distro-independent and uses a Nix-based environment, so
### macOS
Many `xrpld` engineers use macOS for development.
Many `xrpld` engineers use macOS for development. The minimum supported version
is macOS 26, which is also what our CI builds and tests against. The build
defaults `CMAKE_OSX_DEPLOYMENT_TARGET` accordingly, so you do not need to pass it
yourself.
### Windows

View File

@@ -13,6 +13,21 @@ if(DEFINED CMAKE_MODULE_PATH)
endif()
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
# Default the macOS deployment target so it does not have to be passed on the
# command line. Must be set before project() because project() consumes it when
# configuring the compiler and SDK. A user-provided -DCMAKE_OSX_DEPLOYMENT_TARGET
# still takes precedence.
if(
CMAKE_HOST_SYSTEM_NAME STREQUAL "Darwin"
AND NOT DEFINED CMAKE_OSX_DEPLOYMENT_TARGET
)
set(CMAKE_OSX_DEPLOYMENT_TARGET
"26.0"
CACHE STRING
"Minimum macOS deployment version"
)
endif()
project(xrpl)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 23)

View File

@@ -0,0 +1,440 @@
#!/usr/bin/env python3
"""
Check C++ Doxygen comment style.
Enforces the house convention for documentation comments:
* Use ``/** ... */`` blocks, not ``///``, ``//!`` or ``/*! ... */``; a plain
``/* ... */`` that contains Doxygen commands is a doc comment missing its
second star. Trailing member-after comments use ``///<`` (not ``//!<``,
``/*!< ... */`` or ``/**< ... */`` -- the block forms get reflowed and
mis-attached by clang-format on packed enum values, the line form does not).
* ``/**`` sits alone on its line; the closing ``*/`` sits alone on its line.
* Every content line is prefixed with `` * `` (no bare-indented continuation).
* The first content line is flush (not over-indented).
* Doxygen commands use the ``@cmd`` form, not ``\\cmd``.
* Use ``@return`` / ``@throws`` rather than prose ``Returns:`` / ``Throws:``.
* A plain ``//`` comment carrying a block-level ``@command`` (``@param``,
``@return``, ``@see``, ...) is documentation and must be a ``/** ... */``
block (Doxygen ignores ``//``).
* Use canonical command spellings: ``@return`` (not ``@returns``),
``@throws`` (not ``@throw``), ``@see`` (not ``@sa``).
* Order block tags ``@tparam`` -> ``@param`` -> ``@return``. (Whether
``@param`` order matches the signature is not checked here -- too fragile to
parse; Doxygen's WARN_IF_DOC_ERROR covers name mismatches.)
* One-liners are expanded to three lines, EXCEPT bare markers ``@{`` / ``@}``
/ ``@cond [label]`` / ``@endcond`` / ``@file [name]`` which stay on one line.
Left intentionally alone (recognized, valid Doxygen that is not this style's
concern):
* ``///<`` trailing "member-after" comments (the house form).
* Divider lines made only of slashes (``//////////``).
* Plain ``/* ... */`` (non-Doxygen) comments.
Usage:
check_doxygen_style.py [FILE ...] # explicit files
check_doxygen_style.py # default: src/ and include/ trees
Exit status is non-zero if any violation is found.
"""
import argparse
import re
import sys
from collections.abc import Iterable, Iterator
from dataclasses import dataclass
from enum import Enum
from pathlib import Path
class Category(Enum):
"""A kind of style violation: a printed ``label`` and its ``description``.
The description is the default message; a few categories whose wording
depends on the offending text (see ``Finding.detail``) override it.
"""
def __init__(self, label: str, description: str) -> None:
self.label = label
self.description = description
BACKSLASH_COMMAND = ("backslash-command", "use the @cmd form, not \\cmd")
WRONG_COMMAND = ("wrong-command", "use the canonical command spelling")
TRIPLE_SLASH = ("triple-slash", "use a /** ... */ block instead of ///")
QT_MEMBER = ("qt-member", "use ///< instead of //!<")
QT_LINE = ("qt-line", "use a /** ... */ block instead of //!")
BLOCK_MEMBER = ("block-member", "use ///< instead of /**<")
QT_BLOCK_MEMBER = ("qt-block-member", "use ///< instead of /*!<")
DOC_IN_LINE_COMMENT = (
"doc-in-line-comment",
"use a /** ... */ block for documentation, not //",
)
QT_COMMENT = ("qt-comment", "use /** instead of /*!")
SINGLE_LINE_BLOCK = (
"single-line-block",
"expand one-line /** ... */ to a multi-line block "
"(markers @{ @} @cond @endcond @file may stay)",
)
TEXT_ON_OPENER = ("text-on-opener", "move text off the /** opener line")
BARE_CONTINUATION = ("bare-continuation", 'prefix continuation lines with " * "')
OVER_INDENTED = ("over-indented", "first content line is over-indented")
OVER_INDENTED_TAG = (
"over-indented-tag",
'Doxygen tag over-indented; use a single space after "*"',
)
COMBINED_MARKER = (
"combined-marker",
"scope marker @{ / @} should be its own single-line /** @{ */ block",
)
PROSE_LABEL = ("prose-label", "use a Doxygen tag instead of a prose label")
CONTENT_ON_CLOSER = ("content-on-closer", "move content off the closing */ line")
PLAIN_BLOCK_DOC = (
"plain-block-doc",
"documentation comment must open with /** not /*",
)
TAG_ORDER = (
"tag-order",
"block tags out of order; expected @tparam, then @param, then @return",
)
@dataclass(frozen=True)
class Finding:
"""A single style violation at a 1-based line number.
``detail`` overrides the category's default description when the message
depends on the offending text (e.g. which command was misspelled).
"""
line: int
category: Category
detail: str | None = None
@property
def message(self) -> str:
return self.detail if self.detail is not None else self.category.description
DEFAULT_ROOTS = ("src", "include")
EXTS = {".h", ".hpp", ".cpp", ".ipp", ".cxx", ".cc"}
# Every Doxygen command we recognize when written with a backslash (\cmd).
_ALL_COMMANDS = (
"brief|param|tparam|return|returns|retval|note|warning|pre|post|see|sa|ref|"
"throw|throws|exception|deprecated|details|code|endcode|verbatim|endverbatim|"
"li|arg|c|internal|since|todo|attention|remark|remarks|ingroup|defgroup"
)
# Block-level tags whose over-indentation we flag inside a block body.
_BLOCK_TAGS = (
"param|tparam|returns?|retval|brief|throws?|note|warning|"
"pre|post|see|sa|details|deprecated"
)
# Tags that, appearing anywhere in a comment, mark it as documentation.
_ANY_DOC_TAGS = (
"param|tparam|returns?|retval|brief|throws?|note|warning|pre|post|see|sa"
)
# Tags that make a plain // comment a mis-styled doc comment.
_LINE_DOC_TAGS = "brief|param|tparam|returns?|retval|throws?|note|see|pre|post"
# \cmd that should be @cmd.
RE_BACKSLASH_CMD = re.compile(r"\\(" + _ALL_COMMANDS + r")\b")
# Bare markers that may legitimately stay on a single line.
RE_MARKER = re.compile(r"^@(\{|\}|cond(\s.*)?|endcond|file(\s.*)?)$")
# Prose section labels that should be Doxygen tags.
RE_PROSE_LABEL = re.compile(r"^\*\s(Returns|Throws|Exceptions):\s*$")
# An over-indented block tag: "*" followed by 2+ spaces then the tag.
RE_OVERINDENTED_TAG = re.compile(r"^\*\s{2,}@(" + _BLOCK_TAGS + r")\b")
# Any documentation tag (used to spot a doc comment hiding in a plain /* */).
RE_ANY_DOC_TAG = re.compile(r"@(" + _ANY_DOC_TAGS + r")\b")
# A documentation tag inside a // comment.
RE_LINE_DOC_TAG = re.compile(r"@(" + _LINE_DOC_TAGS + r")\b")
# Order-relevant tags, for the @tparam -> @param -> @return ordering check.
RE_ORDER_TAG = re.compile(r"^\*\s*@(param|tparam|returns?|retval)\b")
# First content line indented by 2+ spaces after the "*".
RE_FIRST_OVERINDENT = re.compile(r"^\s*\*\s{2,}\S")
# A scope marker @{ / @} sharing a comment with other text.
RE_COMBINED_MARKER = re.compile(r"^\*\s*@[{}]\s*$")
# Non-canonical command spellings -> the house spelling (bare command names).
# Used both to flag a wrong @form and to suggest the right @form for a \wrong.
CANONICAL_COMMAND = {"returns": "return", "throw": "throws", "sa": "see"}
WRONG_SPELLINGS = [
(re.compile(rf"@{wrong}\b"), f"@{right}")
for wrong, right in CANONICAL_COMMAND.items()
]
# Order block tags should appear in; a body out of this order is a violation.
EXPECTED_TAG_ORDER = ("tparam", "param", "return")
def is_doxy_open(stripped: str) -> bool:
"""True for a line-start Doxygen block opener we should normalize."""
if stripped.startswith("/*!"): # Qt-style Doxygen
return not stripped.startswith("/*!<") # member-after, leave inline
return (
stripped.startswith("/**")
and not stripped.startswith("/***")
and not stripped.startswith("/**/")
and not stripped.startswith("/**<")
)
def _flag_commands(raw_line: str, stripped: str, index: int) -> list[Finding]:
"""Flag \\cmd and misspelled @cmd on a comment line (opener, body, or closer)."""
if not stripped.startswith(("*", "//", "/*")):
return []
findings: list[Finding] = []
backslash = RE_BACKSLASH_CMD.search(raw_line)
if backslash:
command = backslash.group(1)
canonical = CANONICAL_COMMAND.get(command, command)
findings.append(
Finding(
index + 1,
Category.BACKSLASH_COMMAND,
f"use @{canonical} instead of \\{command}",
)
)
for pattern, replacement in WRONG_SPELLINGS:
wrong = pattern.search(raw_line)
if wrong:
findings.append(
Finding(
index + 1,
Category.WRONG_COMMAND,
f"use {replacement} instead of {wrong.group(0)}",
)
)
return findings
def _flag_line_comment(raw_line: str, stripped: str, index: int) -> Finding | None:
"""Return the finding for a single-line comment form (///, //!, /**<, ...), else None."""
if stripped.startswith("///") and not stripped.startswith(("////", "///<")):
return Finding(index + 1, Category.TRIPLE_SLASH)
if "//!<" in raw_line:
return Finding(index + 1, Category.QT_MEMBER)
if stripped.startswith("//!"):
return Finding(index + 1, Category.QT_LINE)
if "/**<" in raw_line:
return Finding(index + 1, Category.BLOCK_MEMBER)
if "/*!<" in raw_line:
return Finding(index + 1, Category.QT_BLOCK_MEMBER)
if stripped.startswith("//") and RE_LINE_DOC_TAG.search(stripped):
return Finding(index + 1, Category.DOC_IN_LINE_COMMENT)
return None
def _flag_single_line_block(stripped: str, line_no: int, is_qt: bool) -> list[Finding]:
"""Findings for a whole /** ... */ or /*! ... */ block on one line."""
inner = re.sub(r"^/\*[*!]", "", stripped)
inner = re.sub(r"\*/\s*$", "", inner).strip()
findings: list[Finding] = []
if is_qt:
findings.append(Finding(line_no, Category.QT_COMMENT))
if inner and not RE_MARKER.match(inner):
findings.append(Finding(line_no, Category.SINGLE_LINE_BLOCK))
return findings
def _canonical_order_tag(body: str) -> str | None:
"""The order-relevant tag (tparam/param/return) a body line opens with, if any."""
match = RE_ORDER_TAG.match(body)
if match is None:
return None
command = match.group(1)
return "return" if command in ("return", "returns", "retval") else command
def _flag_body_line(
body_line: str, line_no: int, is_first_content: bool
) -> list[Finding]:
"""Findings for one interior line of a multi-line block."""
body = body_line.strip()
findings: list[Finding] = []
if body and not body.startswith("*"):
findings.append(Finding(line_no, Category.BARE_CONTINUATION))
if body.startswith("*"):
if is_first_content and RE_FIRST_OVERINDENT.match(body_line):
findings.append(Finding(line_no, Category.OVER_INDENTED))
if RE_OVERINDENTED_TAG.match(body):
findings.append(Finding(line_no, Category.OVER_INDENTED_TAG))
if RE_COMBINED_MARKER.match(body):
findings.append(Finding(line_no, Category.COMBINED_MARKER))
label = RE_PROSE_LABEL.match(body)
if label:
suggested_tag = "@return" if label.group(1) == "Returns" else "@throws"
findings.append(
Finding(
line_no,
Category.PROSE_LABEL,
f'use {suggested_tag} instead of prose "{label.group(1)}:"',
)
)
return findings
def _flag_closer(closer_line: str, line_no: int) -> list[Finding]:
"""Findings for content sharing the closing */ line."""
before = closer_line[: closer_line.index("*/")].strip()
if before and before != "*":
return [Finding(line_no, Category.CONTENT_ON_CLOSER)]
return []
def _flag_tag_order(first_tag_line: dict[str, int]) -> list[Finding]:
"""One finding if the present block tags are not in EXPECTED_TAG_ORDER."""
tag_lines = [
first_tag_line[tag] for tag in EXPECTED_TAG_ORDER if tag in first_tag_line
]
if tag_lines != sorted(tag_lines):
return [Finding(min(tag_lines), Category.TAG_ORDER)]
return []
def _flag_doxy_block(lines: list[str], start: int) -> tuple[int, list[Finding]]:
"""Handle a /** or /*! block opening at ``start``; return (next index, findings)."""
raw_line = lines[start]
stripped = raw_line.lstrip()
open_pos = raw_line.index("/*")
is_qt = stripped.startswith("/*!")
# A whole block on one line: /** ... */.
if "*/" in raw_line[open_pos + 2 :]:
return start + 1, _flag_single_line_block(stripped, start + 1, is_qt)
# Multi-line block: opener, then scan the body to the closer.
findings: list[Finding] = []
if is_qt:
findings.append(Finding(start + 1, Category.QT_COMMENT))
if raw_line[open_pos + 3 :].strip():
findings.append(Finding(start + 1, Category.TEXT_ON_OPENER))
line_count = len(lines)
cursor = start + 1
is_first_content = True
first_tag_line: dict[str, int] = {} # canonical tag -> 1-based first line
while cursor < line_count and "*/" not in lines[cursor]:
body_line = lines[cursor]
body = body_line.strip()
findings.extend(_flag_commands(body_line, body, cursor))
tag = _canonical_order_tag(body)
if tag is not None:
first_tag_line.setdefault(tag, cursor + 1)
findings.extend(_flag_body_line(body_line, cursor + 1, is_first_content))
if body.startswith("*"):
is_first_content = False
cursor += 1
if cursor < line_count:
closer_line = lines[cursor]
findings.extend(_flag_commands(closer_line, closer_line.strip(), cursor))
findings.extend(_flag_closer(closer_line, cursor + 1))
findings.extend(_flag_tag_order(first_tag_line))
return cursor + 1, findings
def _flag_plain_block(lines: list[str], start: int) -> tuple[int, list[Finding]]:
"""Handle a line-start plain /* ... */ block; return (next index, findings).
Only flagged when it hides a documentation command (a missing second star).
"""
line_count = len(lines)
cursor = start
while cursor < line_count and "*/" not in lines[cursor]:
cursor += 1
findings: list[Finding] = []
# The opener (start) is command-checked by check_file; check the rest here.
for i in range(start + 1, min(cursor + 1, line_count)):
findings.extend(_flag_commands(lines[i], lines[i].strip(), i))
block_text = "\n".join(
lines[start : cursor + 1] if cursor < line_count else lines[start:]
)
if RE_ANY_DOC_TAG.search(block_text):
findings.append(Finding(start + 1, Category.PLAIN_BLOCK_DOC))
next_index = cursor + 1 if cursor < line_count else line_count
return next_index, findings
def check_source(text: str) -> list[Finding]:
"""Return all style violations found in the given source text."""
lines = text.split("\n")
findings: list[Finding] = []
line_count = len(lines)
index = 0
in_plain_block = False # inside a mid-line, non-Doxygen /* ... */
while index < line_count:
raw_line = lines[index]
stripped = raw_line.lstrip()
# Skip the interior of a plain block opened on an earlier line.
if in_plain_block:
in_plain_block = "*/" not in raw_line
index += 1
continue
findings.extend(_flag_commands(raw_line, stripped, index))
line_finding = _flag_line_comment(raw_line, stripped, index)
if line_finding is not None:
findings.append(line_finding)
index += 1
elif is_doxy_open(stripped):
index, block_findings = _flag_doxy_block(lines, index)
findings.extend(block_findings)
elif stripped.startswith("/*"):
index, block_findings = _flag_plain_block(lines, index)
findings.extend(block_findings)
else:
# A /* that opens mid-line without closing starts a plain block.
if "/*" in raw_line and not stripped.startswith("//"):
if "*/" not in raw_line[raw_line.index("/*") + 2 :]:
in_plain_block = True
index += 1
return findings
def check_file(path: Path) -> list[Finding]:
"""Return all style violations found in one file."""
return check_source(path.read_text(encoding="utf-8"))
def iter_files(paths: Iterable[str]) -> Iterator[Path]:
"""Yield every C++ source file among the given files and directories."""
for raw_path in paths:
path = Path(raw_path)
if path.is_dir():
for candidate in path.rglob("*"):
if candidate.is_file() and candidate.suffix in EXTS:
yield candidate
elif path.suffix in EXTS:
yield path
def main() -> int:
parser = argparse.ArgumentParser(description="Check Doxygen comment style.")
parser.add_argument(
"files", nargs="*", help="files or directories (default: src/ include/)"
)
parser.add_argument(
"-q", "--quiet", action="store_true", help="only print the summary count"
)
args = parser.parse_args()
roots = args.files or [root for root in DEFAULT_ROOTS if Path(root).is_dir()]
total = 0
for path in sorted(set(iter_files(roots)), key=str):
for finding in check_file(path):
total += 1
if not args.quiet:
print(
f"{path}:{finding.line}: {finding.category.label}: {finding.message}"
)
print(f"\n{total} doxygen-style violation(s)", file=sys.stderr)
return 1 if total else 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -0,0 +1,406 @@
#!/usr/bin/env python3
"""
Tests for check_doxygen_style.py.
Run directly (no test framework needed):
./bin/pre-commit/test_check_doxygen_style.py
or under pytest:
pytest bin/pre-commit/test_check_doxygen_style.py
"""
import sys
import textwrap
from check_doxygen_style import Finding, check_source
def findings_for(text: str) -> list[Finding]:
"""Return the style violations for the given source text.
The text is dedented and its leading newline stripped, so fixtures can be
written as indented triple-quoted here-docs while keeping honest 1-based
line numbers.
"""
text = textwrap.dedent(text).lstrip("\n")
return check_source(text)
def labels_for(text: str) -> list[str]:
return [f.category.label for f in findings_for(text)]
def messages_for(text: str) -> list[str]:
return [f.message for f in findings_for(text)]
# --- well-formed input produces nothing -------------------------------------
def test_clean_block_ok() -> None:
code = """
/**
* Brief.
*
* @tparam T a type
* @param x the x
* @return the result
*/
"""
assert findings_for(code) == []
def test_blank_lines_inside_block_ok() -> None:
code = """
/**
* a
*
* b
*/
"""
assert findings_for(code) == []
def test_member_and_divider_allowed() -> None:
assert findings_for("int x; ///< ok member\n") == []
assert findings_for("//////////\n") == []
assert findings_for("//// text\n") == []
# --- line-comment forms ------------------------------------------------------
def test_triple_slash() -> None:
code = "/// doc\n"
assert labels_for(code) == ["triple-slash"]
def test_qt_line() -> None:
code = "//! doc\n"
assert labels_for(code) == ["qt-line"]
def test_qt_member() -> None:
code = "int x; //!< doc\n"
assert labels_for(code) == ["qt-member"]
def test_block_member() -> None:
code = "int x; /**< doc */\n"
assert labels_for(code) == ["block-member"]
def test_qt_block_member() -> None:
code = "int x; /*!< doc */\n"
assert labels_for(code) == ["qt-block-member"]
def test_doc_in_line_comment() -> None:
code = "// @param x\n"
assert labels_for(code) == ["doc-in-line-comment"]
# --- block forms -------------------------------------------------------------
def test_qt_comment() -> None:
code = """
/*!
* brief
*/
"""
assert labels_for(code) == ["qt-comment"]
def test_qt_comment_single_line() -> None:
# /*! ... */ on one line -> qt-comment (plus single-line-block)
code = "/*! brief */\n"
assert labels_for(code) == ["qt-comment", "single-line-block"]
def test_single_line_block() -> None:
code = "/** brief */\n"
assert labels_for(code) == ["single-line-block"]
def test_single_line_markers_allowed() -> None:
for marker in ("@{", "@}", "@cond LABEL", "@endcond", "@file foo.h"):
code = f"/** {marker} */\n"
assert findings_for(code) == [], marker
def test_text_on_opener() -> None:
code = """
/** text here
* more
*/
"""
assert labels_for(code) == ["text-on-opener"]
def test_bare_continuation() -> None:
code = """
/**
* a
bare line
*/
"""
assert labels_for(code) == ["bare-continuation"]
def test_over_indented_first_line() -> None:
code = """
/**
* over
*/
"""
assert labels_for(code) == ["over-indented"]
def test_over_indented_tag() -> None:
# a flush first line consumes "first content", isolating the tag check
code = """
/**
* brief
* @param x
*/
"""
assert labels_for(code) == ["over-indented-tag"]
def test_combined_marker() -> None:
code = """
/**
* @{
*/
"""
assert labels_for(code) == ["combined-marker"]
def test_prose_label() -> None:
for word in ("Returns", "Throws", "Exceptions"):
code = f"""
/**
* {word}:
*/
"""
assert labels_for(code) == ["prose-label"], word
def test_content_on_closer() -> None:
code = """
/**
* a
* b */
"""
assert labels_for(code) == ["content-on-closer"]
def test_plain_block_doc() -> None:
assert labels_for("/* @param x */\n") == ["plain-block-doc"]
assert findings_for("/* just an ordinary note */\n") == []
def test_tag_order() -> None:
out_of_order = """
/**
* @param x
* @tparam T
*/
"""
assert labels_for(out_of_order) == ["tag-order"]
correct = """
/**
* @tparam T
* @param x
* @return r
*/
"""
assert findings_for(correct) == []
single = """
/**
* @param x
*/
"""
assert findings_for(single) == [] # single tag: never out of order
# --- command spelling (must work on body/closer lines, not just the opener) --
def test_backslash_command_on_body_line() -> None:
code = r"""
/**
* \brief x
*/
"""
assert labels_for(code) == ["backslash-command"]
def test_backslash_command_suggests_canonical_spelling() -> None:
# a backslash + non-canonical spelling is fixed in one pass, not two:
# \sa -> @see (not @sa), \returns -> @return (not @returns)
sa = r"""
/**
* \sa other
*/
"""
assert messages_for(sa) == [r"use @see instead of \sa"]
returns = r"""
/**
* \returns x
*/
"""
assert messages_for(returns) == [r"use @return instead of \returns"]
def test_wrong_command_on_body_line() -> None:
code = """
/**
* @returns x
*/
"""
assert labels_for(code) == ["wrong-command"]
def test_body_line_commands_regression() -> None:
# regression: these live on body lines of a multi-line block
code = r"""
/**
* @returns bad
* @throw ex
* @sa other
* \param y
*/
"""
assert labels_for(code) == [
"wrong-command",
"wrong-command",
"wrong-command",
"backslash-command",
]
def test_command_on_closer_line() -> None:
code = """
/**
* a
* @sa b */
"""
assert labels_for(code) == ["wrong-command", "content-on-closer"]
def test_no_double_count_across_opener_body_closer() -> None:
code = """
/** @returns opener
* @throw body
* @sa closer */
"""
assert labels_for(code).count("wrong-command") == 3
def test_code_with_word_allowed() -> None:
# @code{.cpp} is valid Doxygen and must not be flagged
code = """
/**
* @code{.cpp}
* int x;
* @endcode
*/
"""
assert findings_for(code) == []
# --- rendered message text ---------------------------------------------------
def test_message_uses_category_description() -> None:
# a static category renders its default description
code = "/// doc\n"
assert messages_for(code) == ["use a /** ... */ block instead of ///"]
def test_message_detail_overrides() -> None:
# dynamic categories render the offending text via Finding.detail
backslash = r"""
/**
* \param y
*/
"""
assert messages_for(backslash) == [r"use @param instead of \param"]
wrong = """
/**
* @returns x
*/
"""
assert messages_for(wrong) == ["use @return instead of @returns"]
prose = """
/**
* Throws:
*/
"""
assert messages_for(prose) == ['use @throws instead of prose "Throws:"']
# --- robustness --------------------------------------------------------------
def test_empty_file_no_crash() -> None:
assert findings_for("") == []
def test_mid_line_plain_block_skipped() -> None:
# a /* opened mid-line (after code) and spanning lines is skipped, so its
# comment-like contents are not analyzed
code = """
int x = 0; /* note: @returns is not a real tag here
* @param also not real
*/
int y = 0;
"""
assert findings_for(code) == []
def test_unclosed_block_scanned_to_eof() -> None:
# an unterminated /** block is still scanned to EOF (no crash, body checked)
code = """
/**
* @returns x
"""
assert labels_for(code) == ["wrong-command"]
def test_banner_and_empty_comment_not_flagged() -> None:
code = """
/***
* banner
***/
"""
assert findings_for(code) == []
assert findings_for("/**/\n") == []
def main() -> int:
tests = sorted(
(name, fn)
for name, fn in globals().items()
if name.startswith("test_") and callable(fn)
)
failed = 0
for name, fn in tests:
try:
fn()
print(f"PASS {name}")
except AssertionError as exc:
failed += 1
print(f"FAIL {name}: {exc!r}")
print(f"\n{len(tests) - failed}/{len(tests)} passed")
return 1 if failed else 0
if __name__ == "__main__":
sys.exit(main())

View File

@@ -1059,10 +1059,11 @@
# The online delete process checks periodically
# that xrpld is still in sync with the network,
# and that the validated ledger is less than
# 'age_threshold_seconds' old. If not, then continue
# 'age_threshold_seconds' old, and that all
# recent ledgers are available. If not, then continue
# sleeping for this number of seconds and
# checking until healthy.
# Default is 5.
# Default is 2.
#
# Notes:
# The 'node_db' entry configures the primary, persistent storage.

View File

@@ -177,7 +177,9 @@ ${field['typeData']['setter_type']} ${field['paramName']}${',' if i < len(requir
object_ = *sle;
}
/** @brief Ledger entry-specific field setters */
/**
* @brief Ledger entry-specific field setters
*/
% for field in fields:
/**

View File

@@ -185,7 +185,9 @@ public:
object_ = *tx;
}
/** @brief Transaction-specific field setters */
/**
* @brief Transaction-specific field setters
*/
% for field in fields:
/**

View File

@@ -33,9 +33,10 @@ with a single command and without installing anything system-wide:
nix --experimental-features 'nix-command flakes' develop
```
On **Linux**, Nix also provides the compiler (GCC). On **macOS**, the shell uses
your **system-wide Apple Clang** as the compiler, so you still need to manage
its version (see below).
On **Linux**, Nix also provides the compiler (GCC); on **macOS**, it provides
Clang. If you instead opt to use your system-wide Apple Clang (via
`nix develop .#apple-clang`), you need to manage its version yourself (see
below).
See [Using the Nix development shell](./nix.md) for installation and usage
details, including how to select a different compiler.
@@ -48,10 +49,10 @@ details, including how to select a different compiler.
### macOS: managing the Apple Clang version
Because the Nix shell uses the system-wide Apple Clang on macOS, the compiler
version is whatever your installed Xcode (or Command Line Tools) provides. The
following command should return a version greater than or equal to the
[minimum required](#tested-compiler-versions):
If you use your system-wide Apple Clang on macOS (via `nix develop .#apple-clang`),
the compiler version is whatever your installed Xcode (or Command Line Tools)
provides. The following command should return a version greater than or equal to
the [minimum required](#tested-compiler-versions):
```bash
clang --version

40
docs/build/nix.md vendored
View File

@@ -9,7 +9,7 @@ This guide explains how to use Nix to set up a reproducible development environm
- **Reproducible environment**: Everyone gets the same versions of tools and compilers
- **Matches CI**: The Linux CI runs in Docker images built from this exact Nix environment
- **No system pollution**: Dependencies are isolated and don't affect your system packages
- **Multiple compiler versions**: Easily switch between different GCC and Clang versions
- **Consistent compilers**: The GCC and Clang shells use the same versions as CI
- **Quick setup**: Get started with a single command
- **Works on Linux and macOS**: Consistent experience across platforms
@@ -31,8 +31,8 @@ This will:
- Download and set up all required development tools (CMake, Ninja, Conan, etc.)
- Configure the appropriate compiler for your platform:
- **Linux**: GCC 15.2 (provided by Nix)
- **macOS**: Apple Clang (your system compiler)
- **Linux**: GCC (provided by Nix)
- **macOS**: Clang (provided by Nix)
The first time you run this command, it will take a few minutes to download and build the environment. Subsequent runs will be much faster.
@@ -40,12 +40,12 @@ The first time you run this command, it will take a few minutes to download and
- **Linux**: `nix develop` gives you a shell with all the tooling necessary to
develop xrpld and with GCC 15.2 (also provided by Nix). There are no caveats.
- **macOS**: `nix develop` gives you a full environment too. The compiler is
your system-wide Apple Clang, while every other tool including Conan — is
provided by Nix. Conan has no binary in the Nix cache for macOS, so it is
built from source the first time you enter the shell, which makes the initial
setup slower (this is handled automatically; see
[`nix/devshell.nix`](../../nix/devshell.nix)).
- **macOS**: `nix develop` gives you a full environment too, with Clang (and
every other tool, including Conan) provided by Nix. To use your system-wide
Apple Clang instead, enter `nix develop .#apple-clang`. Conan has no binary in
the Nix cache for macOS, so it is built from source the first time you enter
the shell, which makes the initial setup slower (this is handled
automatically; see [`nix/devshell.nix`](../../nix/devshell.nix)).
> [!TIP]
> To avoid typing `--experimental-features 'nix-command flakes'` every time, you can permanently enable flakes by creating `~/.config/nix/nix.conf`:
@@ -62,7 +62,9 @@ The first time you run this command, it will take a few minutes to download and
### Choosing a different compiler
A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#gcc15`.
A compiler can be chosen by providing its name with the `.#` prefix, e.g. `nix develop .#clang`.
The `.#gcc` and `.#clang` shells provide the same GCC and Clang versions used in CI
(pinned in [`nix/packages.nix`](../../nix/packages.nix)).
Use `nix flake show` to see all the available development shells.
Use `nix develop .#no-compiler` to use the compiler from your system.
@@ -70,11 +72,11 @@ Use `nix develop .#no-compiler` to use the compiler from your system.
### Example Usage
```bash
# Use GCC 14
nix develop .#gcc14
# Use GCC (same version as CI)
nix develop .#gcc
# Use Clang 19
nix develop .#clang19
# Use Clang (same version as CI)
nix develop .#clang
# Use default for your platform
nix develop
@@ -112,7 +114,15 @@ Once inside the Nix development shell, follow the standard [build instructions](
[direnv](https://direnv.net/) or [nix-direnv](https://github.com/nix-community/nix-direnv) can automatically activate the Nix development shell when you enter the repository directory.
This is also the most robust way to use the environment from **any shell** (bash, zsh, fish, …): direnv stays in your current shell and loads the environment _after_ your shell's startup files have run, so the Nix-provided tools take precedence over anything your shell configuration adds to `$PATH`. To use it, install direnv for your shell, then add an `.envrc` containing `use flake` at the repository root and run `direnv allow`.
This is also the most robust way to use the environment from **any shell** (bash, zsh, fish, …): direnv stays in your current shell and loads the environment _after_ your shell's startup files have run, so the Nix-provided tools take precedence over anything your shell configuration adds to `$PATH`.
The repository already ships an `.envrc` at its root that activates the Nix flake development shell, so you don't need to create one. To use it:
1. [Install direnv](https://direnv.net/docs/installation.html) and [hook it into your shell](https://direnv.net/docs/hook.html) (bash, zsh, fish, …). Installing [nix-direnv](https://github.com/nix-community/nix-direnv) as well is recommended: it caches the shell so that activation is near-instant after the first run.
2. Run `direnv allow` once in the repository root. direnv will then load (and reload) the Nix development shell automatically whenever you enter the directory.
> [!NOTE]
> direnv only caches the `.direnv` directory (already listed in `.gitignore`); no other repository files are affected.
## Conan and Prebuilt Packages

View File

@@ -4,13 +4,14 @@
namespace xrpl {
/** Extract a tar archive compressed with lz4
@param src the path of the archive to be extracted
@param dst the directory to extract to
@throws runtime_error
*/
/**
* Extract a tar archive compressed with lz4
*
* @param src the path of the archive to be extracted
* @param dst the directory to extract to
*
* @throws runtime_error
*/
void
extractTarLz4(boost::filesystem::path const& src, boost::filesystem::path const& dst);

View File

@@ -4,9 +4,10 @@
namespace xrpl {
/** Storage for linear binary data.
Blocks of binary data appear often in various idioms and structures.
*/
/**
* Storage for linear binary data.
* Blocks of binary data appear often in various idioms and structures.
*/
using Blob = std::vector<unsigned char>;
} // namespace xrpl

View File

@@ -10,9 +10,10 @@
namespace xrpl {
/** Like std::vector<char> but better.
Meets the requirements of BufferFactory.
*/
/**
* Like std::vector<char> but better.
* Meets the requirements of BufferFactory.
*/
class Buffer
{
private:
@@ -24,30 +25,37 @@ public:
Buffer() = default;
/** Create an uninitialized buffer with the given size. */
/**
* Create an uninitialized buffer with the given size.
*/
explicit Buffer(std::size_t size)
: p_((size != 0u) ? new std::uint8_t[size] : nullptr), size_(size)
{
}
/** Create a buffer as a copy of existing memory.
@param data a pointer to the existing memory. If
size is non-zero, it must not be null.
@param size size of the existing memory block.
*/
/**
* Create a buffer as a copy of existing memory.
*
* @param data a pointer to the existing memory. If
* size is non-zero, it must not be null.
* @param size size of the existing memory block.
*/
Buffer(void const* data, std::size_t size) : Buffer(size)
{
if (size != 0u)
std::memcpy(p_.get(), data, size);
}
/** Copy-construct */
/**
* Copy-construct
*/
Buffer(Buffer const& other) : Buffer(other.p_.get(), other.size_)
{
}
/** Copy assign */
/**
* Copy assign
*/
Buffer&
operator=(Buffer const& other)
{
@@ -59,17 +67,19 @@ public:
return *this;
}
/** Move-construct.
The other buffer is reset.
*/
/**
* Move-construct.
* The other buffer is reset.
*/
Buffer(Buffer&& other) noexcept : p_(std::move(other.p_)), size_(other.size_)
{
other.size_ = 0;
}
/** Move-assign.
The other buffer is reset.
*/
/**
* Move-assign.
* The other buffer is reset.
*/
Buffer&
operator=(Buffer&& other) noexcept
{
@@ -82,12 +92,16 @@ public:
return *this;
}
/** Construct from a slice */
/**
* Construct from a slice
*/
explicit Buffer(Slice s) : Buffer(s.data(), s.size())
{
}
/** Assign from slice */
/**
* Assign from slice
*/
Buffer&
operator=(Slice s)
{
@@ -101,7 +115,9 @@ public:
return *this;
}
/** Returns the number of bytes in the buffer. */
/**
* Returns the number of bytes in the buffer.
*/
[[nodiscard]] std::size_t
size() const noexcept
{
@@ -121,10 +137,11 @@ public:
return Slice{p_.get(), size_};
}
/** Return a pointer to beginning of the storage.
@note The return type is guaranteed to be a pointer
to a single byte, to facilitate pointer arithmetic.
*/
/**
* Return a pointer to beginning of the storage.
* @note The return type is guaranteed to be a pointer
* to a single byte, to facilitate pointer arithmetic.
*/
/** @{ */
[[nodiscard]] std::uint8_t const*
data() const noexcept
@@ -139,9 +156,10 @@ public:
}
/** @} */
/** Reset the buffer.
All memory is deallocated. The resulting size is 0.
*/
/**
* Reset the buffer.
* All memory is deallocated. The resulting size is 0.
*/
void
clear() noexcept
{
@@ -149,9 +167,10 @@ public:
size_ = 0;
}
/** Reallocate the storage.
Existing data, if any, is discarded.
*/
/**
* Reallocate the storage.
* Existing data, if any, is discarded.
*/
std::uint8_t*
alloc(std::size_t n)
{

View File

@@ -12,7 +12,8 @@
namespace xrpl::compression_algorithms {
/** LZ4 block compression.
/**
* LZ4 block compression.
* @tparam BufferFactory Callable object or lambda.
* Takes the requested buffer size and returns allocated buffer pointer.
* @param in Data to compress
@@ -80,7 +81,8 @@ lz4Decompress(
return decompressedSize;
}
/** LZ4 block decompression.
/**
* LZ4 block decompression.
* @tparam InputStream ZeroCopyInputStream
* @param in Input source stream
* @param inSize Size of compressed data

View File

@@ -9,7 +9,9 @@
namespace xrpl {
/** Manages all counted object types. */
/**
* Manages all counted object types.
*/
class CountedObjects
{
public:
@@ -23,10 +25,11 @@ public:
getCounts(int minimumThreshold) const;
public:
/** Implementation for @ref CountedObject.
@internal
*/
/**
* Implementation for @ref CountedObject.
*
* @internal
*/
class Counter
{
public:
@@ -94,13 +97,14 @@ private:
//------------------------------------------------------------------------------
/** Tracks the number of instances of an object.
Derived classes have their instances counted automatically. This is used
for reporting purposes.
@ingroup basics
*/
/**
* Tracks the number of instances of an object.
*
* Derived classes have their instances counted automatically. This is used
* for reporting purposes.
*
* @ingroup basics
*/
template <class Object>
class CountedObject
{

View File

@@ -6,9 +6,10 @@
namespace xrpl {
/** Sampling function using exponential decay to provide a continuous value.
@tparam The number of seconds in the decay window.
*/
/**
* Sampling function using exponential decay to provide a continuous value.
* @tparam The number of seconds in the decay window.
*/
template <int Window, typename Clock>
class DecayingSample
{
@@ -19,15 +20,16 @@ public:
DecayingSample() = delete;
/**
@param now Start time of DecayingSample.
*/
* @param now Start time of DecayingSample.
*/
explicit DecayingSample(time_point now) : value_(value_type()), when_(now)
{
}
/** Add a new sample.
The value is first aged according to the specified time.
*/
/**
* Add a new sample.
* The value is first aged according to the specified time.
*/
value_type
add(value_type value, time_point now)
{
@@ -36,9 +38,10 @@ public:
return value_ / Window;
}
/** Retrieve the current value in normalized units.
The samples are first aged according to the specified time.
*/
/**
* Retrieve the current value in normalized units.
* The samples are first aged according to the specified time.
*/
value_type
value(time_point now)
{
@@ -87,9 +90,10 @@ private:
//------------------------------------------------------------------------------
/** Sampling function using exponential decay to provide a continuous value.
@tparam HalfLife The half life of a sample, in seconds.
*/
/**
* Sampling function using exponential decay to provide a continuous value.
* @tparam HalfLife The half life of a sample, in seconds.
*/
template <int HalfLife, class Clock>
class DecayWindow
{

View File

@@ -10,33 +10,37 @@ namespace xrpl {
//------------------------------------------------------------------------------
/** Tag to create an intrusive pointer from another intrusive pointer by using a
static cast. This is useful to create an intrusive pointer to a derived
class from an intrusive pointer to a base class.
*/
/**
* Tag to create an intrusive pointer from another intrusive pointer by using a
* static cast. This is useful to create an intrusive pointer to a derived
* class from an intrusive pointer to a base class.
*/
struct StaticCastTagSharedIntrusive
{
};
/** Tag to create an intrusive pointer from another intrusive pointer by using a
dynamic cast. This is useful to create an intrusive pointer to a derived
class from an intrusive pointer to a base class. If the cast fails an empty
(null) intrusive pointer is created.
*/
/**
* Tag to create an intrusive pointer from another intrusive pointer by using a
* dynamic cast. This is useful to create an intrusive pointer to a derived
* class from an intrusive pointer to a base class. If the cast fails an empty
* (null) intrusive pointer is created.
*/
struct DynamicCastTagSharedIntrusive
{
};
/** When creating or adopting a raw pointer, controls whether the strong count
is incremented or not. Use this tag to increment the strong count.
*/
/**
* When creating or adopting a raw pointer, controls whether the strong count
* is incremented or not. Use this tag to increment the strong count.
*/
struct SharedIntrusiveAdoptIncrementStrongTag
{
};
/** When creating or adopting a raw pointer, controls whether the strong count
is incremented or not. Use this tag to leave the strong count unchanged.
*/
/**
* When creating or adopting a raw pointer, controls whether the strong count
* is incremented or not. Use this tag to leave the strong count unchanged.
*/
struct SharedIntrusiveAdoptNoIncrementTag
{
};
@@ -50,20 +54,21 @@ concept CAdoptTag = std::is_same_v<T, SharedIntrusiveAdoptIncrementStrongTag> ||
//------------------------------------------------------------------------------
/** A shared intrusive pointer class that supports weak pointers.
This is meant to be used for SHAMapInnerNodes, but may be useful for other
cases. Since the reference counts are stored on the pointee, the pointee is
not destroyed until both the strong _and_ weak pointer counts go to zero.
When the strong pointer count goes to zero, the "partialDestructor" is
called. This can be used to destroy as much of the object as possible while
still retaining the reference counts. For example, for SHAMapInnerNodes the
children may be reset in that function. Note that std::shared_pointer WILL
run the destructor when the strong count reaches zero, but may not free the
memory used by the object until the weak count reaches zero. In xrpld, we
typically allocate shared pointers with the `make_shared` function. When
that is used, the memory is not reclaimed until the weak count reaches zero.
*/
/**
* A shared intrusive pointer class that supports weak pointers.
*
* This is meant to be used for SHAMapInnerNodes, but may be useful for other
* cases. Since the reference counts are stored on the pointee, the pointee is
* not destroyed until both the strong _and_ weak pointer counts go to zero.
* When the strong pointer count goes to zero, the "partialDestructor" is
* called. This can be used to destroy as much of the object as possible while
* still retaining the reference counts. For example, for SHAMapInnerNodes the
* children may be reset in that function. Note that std::shared_pointer WILL
* run the destructor when the strong count reaches zero, but may not free the
* memory used by the object until the weak count reaches zero. In xrpld, we
* typically allocate shared pointers with the `make_shared` function. When
* that is used, the memory is not reclaimed until the weak count reaches zero.
*/
template <class T>
class SharedIntrusive
{
@@ -111,8 +116,9 @@ public:
operator=(
SharedIntrusive<TT>&& rhs); // NOLINT(cppcoreguidelines-rvalue-reference-param-not-moved)
/** Adopt the raw pointer. The strong reference may or may not be
incremented, depending on the TAdoptTag
/**
* Adopt the raw pointer. The strong reference may or may not be
* incremented, depending on the TAdoptTag
*/
template <CAdoptTag TAdoptTag = SharedIntrusiveAdoptIncrementStrongTag>
void
@@ -120,27 +126,31 @@ public:
~SharedIntrusive();
/** Create a new SharedIntrusive by statically casting the pointer
controlled by the rhs param.
*/
/**
* Create a new SharedIntrusive by statically casting the pointer
* controlled by the rhs param.
*/
template <class TT>
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs);
/** Create a new SharedIntrusive by statically casting the pointer
controlled by the rhs param.
*/
/**
* Create a new SharedIntrusive by statically casting the pointer
* controlled by the rhs param.
*/
template <class TT>
SharedIntrusive(StaticCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs);
/** Create a new SharedIntrusive by dynamically casting the pointer
controlled by the rhs param.
*/
/**
* Create a new SharedIntrusive by dynamically casting the pointer
* controlled by the rhs param.
*/
template <class TT>
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT> const& rhs);
/** Create a new SharedIntrusive by dynamically casting the pointer
controlled by the rhs param.
*/
/**
* Create a new SharedIntrusive by dynamically casting the pointer
* controlled by the rhs param.
*/
template <class TT>
SharedIntrusive(DynamicCastTagSharedIntrusive, SharedIntrusive<TT>&& rhs);
@@ -153,17 +163,22 @@ public:
explicit
operator bool() const noexcept;
/** Set the pointer to null, decrement the strong count, and run the
appropriate release action.
*/
/**
* Set the pointer to null, decrement the strong count, and run the
* appropriate release action.
*/
void
reset();
/** Get the raw pointer */
/**
* Get the raw pointer
*/
[[nodiscard]] T*
get() const;
/** Return the strong count */
/**
* Return the strong count
*/
[[nodiscard]] std::size_t
useCount() const;
@@ -181,43 +196,51 @@ public:
friend class WeakIntrusive;
private:
/** Return the raw pointer held by this object. */
/**
* Return the raw pointer held by this object.
*/
[[nodiscard]] T*
unsafeGetRawPtr() const;
/** Exchange the current raw pointer held by this object with the given
pointer. Decrement the strong count of the raw pointer previously held
by this object and run the appropriate release action.
/**
* Exchange the current raw pointer held by this object with the given
* pointer. Decrement the strong count of the raw pointer previously held
* by this object and run the appropriate release action.
*/
void
unsafeReleaseAndStore(T* next);
/** Set the raw pointer directly. This is wrapped in a function so the class
can support both atomic and non-atomic pointers in a future patch.
/**
* Set the raw pointer directly. This is wrapped in a function so the class
* can support both atomic and non-atomic pointers in a future patch.
*/
void
unsafeSetRawPtr(T* p);
/** Exchange the raw pointer directly.
This sets the raw pointer to the given value and returns the previous
value. This is wrapped in a function so the class can support both
atomic and non-atomic pointers in a future patch.
/**
* Exchange the raw pointer directly.
* This sets the raw pointer to the given value and returns the previous
* value. This is wrapped in a function so the class can support both
* atomic and non-atomic pointers in a future patch.
*/
T*
unsafeExchange(T* p);
/** pointer to the type with an intrusive count */
/**
* pointer to the type with an intrusive count
*/
T* ptr_{nullptr};
};
//------------------------------------------------------------------------------
/** A weak intrusive pointer class for the SharedIntrusive pointer class.
Note that this weak pointer class asks differently from normal weak pointer
classes. When the strong pointer count goes to zero, the "partialDestructor"
is called. See the comment on SharedIntrusive for a fuller explanation.
*/
/**
* A weak intrusive pointer class for the SharedIntrusive pointer class.
*
* Note that this weak pointer class asks differently from normal weak pointer
* classes. When the strong pointer count goes to zero, the "partialDestructor"
* is called. See the comment on SharedIntrusive for a fuller explanation.
*/
template <class T>
class WeakIntrusive
{
@@ -247,54 +270,62 @@ public:
WeakIntrusive&
operator=(SharedIntrusive<TT> const& rhs);
/** Adopt the raw pointer and increment the weak count. */
/**
* Adopt the raw pointer and increment the weak count.
*/
void
adopt(T* ptr);
~WeakIntrusive();
/** Get a strong pointer from the weak pointer, if possible. This will
only return a seated pointer if the strong count on the raw pointer
is non-zero before locking.
/**
* Get a strong pointer from the weak pointer, if possible. This will
* only return a seated pointer if the strong count on the raw pointer
* is non-zero before locking.
*/
SharedIntrusive<T>
lock() const;
/** Return true if the strong count is zero. */
/**
* Return true if the strong count is zero.
*/
[[nodiscard]] bool
expired() const;
/** Set the pointer to null and decrement the weak count.
Note: This may run the destructor if the strong count is zero.
*/
/**
* Set the pointer to null and decrement the weak count.
*
* Note: This may run the destructor if the strong count is zero.
*/
void
reset();
private:
T* ptr_ = nullptr;
/** Decrement the weak count. This does _not_ set the raw pointer to
null.
Note: This may run the destructor if the strong count is zero.
*/
/**
* Decrement the weak count. This does _not_ set the raw pointer to
* null.
*
* Note: This may run the destructor if the strong count is zero.
*/
void
unsafeReleaseNoStore();
};
//------------------------------------------------------------------------------
/** A combination of a strong and a weak intrusive pointer stored in the
space of a single pointer.
This class is similar to a `std::variant<SharedIntrusive,WeakIntrusive>`
with some optimizations. In particular, it uses a low-order bit to
determine if the raw pointer represents a strong pointer or a weak
pointer. It can also be quickly switched between its strong pointer and
weak pointer representations. This class is useful for storing intrusive
pointers in tagged caches.
*/
/**
* A combination of a strong and a weak intrusive pointer stored in the
* space of a single pointer.
*
* This class is similar to a `std::variant<SharedIntrusive,WeakIntrusive>`
* with some optimizations. In particular, it uses a low-order bit to
* determine if the raw pointer represents a strong pointer or a weak
* pointer. It can also be quickly switched between its strong pointer and
* weak pointer representations. This class is useful for storing intrusive
* pointers in tagged caches.
*/
template <class T>
class SharedWeakUnion
@@ -336,69 +367,83 @@ public:
~SharedWeakUnion();
/** Return a strong pointer if this is already a strong pointer (i.e.
don't lock the weak pointer. Use the `lock` method if that's what's
needed)
/**
* Return a strong pointer if this is already a strong pointer (i.e.
* don't lock the weak pointer. Use the `lock` method if that's what's
* needed)
*/
[[nodiscard]] SharedIntrusive<T>
getStrong() const;
/** Return true if this is a strong pointer and the strong pointer is
seated.
/**
* Return true if this is a strong pointer and the strong pointer is
* seated.
*/
explicit
operator bool() const noexcept;
/** Set the pointer to null, decrement the appropriate ref count, and
run the appropriate release action.
/**
* Set the pointer to null, decrement the appropriate ref count, and
* run the appropriate release action.
*/
void
reset();
/** If this is a strong pointer, return the raw pointer. Otherwise
return null.
/**
* If this is a strong pointer, return the raw pointer. Otherwise
* return null.
*/
[[nodiscard]] T*
get() const;
/** If this is a strong pointer, return the strong count. Otherwise
/**
* If this is a strong pointer, return the strong count. Otherwise
* return 0
*/
[[nodiscard]] std::size_t
useCount() const;
/** Return true if there is a non-zero strong count. */
/**
* Return true if there is a non-zero strong count.
*/
[[nodiscard]] bool
expired() const;
/** If this is a strong pointer, return the strong pointer. Otherwise
attempt to lock the weak pointer.
/**
* If this is a strong pointer, return the strong pointer. Otherwise
* attempt to lock the weak pointer.
*/
[[nodiscard]] SharedIntrusive<T>
lock() const;
/** Return true is this represents a strong pointer. */
/**
* Return true is this represents a strong pointer.
*/
[[nodiscard]] bool
isStrong() const;
/** Return true is this represents a weak pointer. */
/**
* Return true is this represents a weak pointer.
*/
[[nodiscard]] bool
isWeak() const;
/** If this is a weak pointer, attempt to convert it to a strong
pointer.
@return true if successfully converted to a strong pointer (or was
already a strong pointer). Otherwise false.
*/
/**
* If this is a weak pointer, attempt to convert it to a strong
* pointer.
*
* @return true if successfully converted to a strong pointer (or was
* already a strong pointer). Otherwise false.
*/
bool
convertToStrong();
/** If this is a strong pointer, attempt to convert it to a weak
pointer.
@return false if the pointer is null. Otherwise return true.
*/
/**
* If this is a strong pointer, attempt to convert it to a weak
* pointer.
*
* @return false if the pointer is null. Otherwise return true.
*/
bool
convertToWeak();
@@ -411,23 +456,27 @@ private:
static constexpr std::uintptr_t kPtrMask = ~kTagMask;
private:
/** Return the raw pointer held by this object.
/**
* Return the raw pointer held by this object.
*/
[[nodiscard]] T*
unsafeGetRawPtr() const;
enum class RefStrength { Strong, Weak };
/** Set the raw pointer and tag bit directly.
/**
* Set the raw pointer and tag bit directly.
*/
void
unsafeSetRawPtr(T* p, RefStrength rs);
/** Set the raw pointer and tag bit to all zeros (strong null pointer).
/**
* Set the raw pointer and tag bit to all zeros (strong null pointer).
*/
void unsafeSetRawPtr(std::nullptr_t);
/** Decrement the appropriate ref count, and run the appropriate release
action. Note: this does _not_ set the raw pointer to null.
/**
* Decrement the appropriate ref count, and run the appropriate release
* action. Note: this does _not_ set the raw pointer to null.
*/
void
unsafeReleaseNoStore();
@@ -435,12 +484,13 @@ private:
//------------------------------------------------------------------------------
/** Create a shared intrusive pointer.
Note: unlike std::shared_ptr, where there is an advantage of allocating
the pointer and control block together, there is no benefit for intrusive
pointers.
*/
/**
* Create a shared intrusive pointer.
*
* Note: unlike std::shared_ptr, where there is an advantage of allocating
* the pointer and control block together, there is no benefit for intrusive
* pointers.
*/
template <class TT, class... Args>
SharedIntrusive<TT>
makeSharedIntrusive(Args&&... args)

View File

@@ -8,35 +8,38 @@
namespace xrpl {
/** Action to perform when releasing a strong pointer.
noop: Do nothing. For example, a `noop` action will occur when a count is
decremented to a non-zero value.
partialDestroy: Run the `partialDestructor`. This action will happen when a
strong count is decremented to zero and the weak count is non-zero.
destroy: Run the destructor. This action will occur when either the strong
count or weak count is decremented and the other count is also zero.
/**
* Action to perform when releasing a strong pointer.
*
* noop: Do nothing. For example, a `noop` action will occur when a count is
* decremented to a non-zero value.
*
* partialDestroy: Run the `partialDestructor`. This action will happen when a
* strong count is decremented to zero and the weak count is non-zero.
*
* destroy: Run the destructor. This action will occur when either the strong
* count or weak count is decremented and the other count is also zero.
*/
enum class ReleaseStrongRefAction { NoOp, PartialDestroy, Destroy };
/** Action to perform when releasing a weak pointer.
noop: Do nothing. For example, a `noop` action will occur when a count is
decremented to a non-zero value.
destroy: Run the destructor. This action will occur when either the strong
count or weak count is decremented and the other count is also zero.
/**
* Action to perform when releasing a weak pointer.
*
* noop: Do nothing. For example, a `noop` action will occur when a count is
* decremented to a non-zero value.
*
* destroy: Run the destructor. This action will occur when either the strong
* count or weak count is decremented and the other count is also zero.
*/
enum class ReleaseWeakRefAction { NoOp, Destroy };
/** Implement the strong count, weak count, and bit flags for an intrusive
pointer.
A class can satisfy the requirements of an xrpl::IntrusivePointer by
inheriting from this class.
*/
/**
* Implement the strong count, weak count, and bit flags for an intrusive
* pointer.
*
* A class can satisfy the requirements of an xrpl::IntrusivePointer by
* inheriting from this class.
*/
struct IntrusiveRefCounts
{
virtual ~IntrusiveRefCounts() noexcept;
@@ -105,109 +108,123 @@ private:
static constexpr size_t kFieldTypeBits = sizeof(FieldType) * 8;
static constexpr FieldType kOne = 1;
/** `refCounts` consists of four fields that are treated atomically:
1. Strong count. This is a count of the number of shared pointers that
hold a reference to this object. When the strong counts goes to zero,
if the weak count is zero, the destructor is run. If the weak count is
non-zero when the strong count goes to zero then the partialDestructor
is run.
2. Weak count. This is a count of the number of weak pointer that hold
a reference to this object. When the weak count goes to zero and the
strong count is also zero, then the destructor is run.
3. Partial destroy started bit. This bit is set if the
`partialDestructor` function has been started (or is about to be
started). This is used to prevent the destructor from running
concurrently with the partial destructor. This can easily happen when
the last strong pointer release its reference in one thread and starts
the partialDestructor, while in another thread the last weak pointer
goes out of scope and starts the destructor while the partialDestructor
is still running. Both a start and finished bit is needed to handle a
corner-case where the last strong pointer goes out of scope, then then
last `weakPointer` goes out of scope, but this happens before the
`partialDestructor` bit is set. It would be possible to use a single
bit if it could also be set atomically when the strong count goes to
zero and the weak count is non-zero, but that would add complexity (and
likely slow down common cases as well).
4. Partial destroy finished bit. This bit is set when the
`partialDestructor` has finished running. See (3) above for more
information.
*/
/**
* `refCounts` consists of four fields that are treated atomically:
*
* 1. Strong count. This is a count of the number of shared pointers that
* hold a reference to this object. When the strong counts goes to zero,
* if the weak count is zero, the destructor is run. If the weak count is
* non-zero when the strong count goes to zero then the partialDestructor
* is run.
*
* 2. Weak count. This is a count of the number of weak pointer that hold
* a reference to this object. When the weak count goes to zero and the
* strong count is also zero, then the destructor is run.
*
* 3. Partial destroy started bit. This bit is set if the
* `partialDestructor` function has been started (or is about to be
* started). This is used to prevent the destructor from running
* concurrently with the partial destructor. This can easily happen when
* the last strong pointer release its reference in one thread and starts
* the partialDestructor, while in another thread the last weak pointer
* goes out of scope and starts the destructor while the partialDestructor
* is still running. Both a start and finished bit is needed to handle a
* corner-case where the last strong pointer goes out of scope, then then
* last `weakPointer` goes out of scope, but this happens before the
* `partialDestructor` bit is set. It would be possible to use a single
* bit if it could also be set atomically when the strong count goes to
* zero and the weak count is non-zero, but that would add complexity (and
* likely slow down common cases as well).
*
* 4. Partial destroy finished bit. This bit is set when the
* `partialDestructor` has finished running. See (3) above for more
* information.
*/
mutable std::atomic<FieldType> refCounts_{kStrongDelta};
/** Amount to change the strong count when adding or releasing a reference
Note: The strong count is stored in the low `StrongCountNumBits` bits
of refCounts
*/
/**
* Amount to change the strong count when adding or releasing a reference
*
* Note: The strong count is stored in the low `StrongCountNumBits` bits
* of refCounts
*/
static constexpr FieldType kStrongDelta = 1;
/** Amount to change the weak count when adding or releasing a reference
Note: The weak count is stored in the high `WeakCountNumBits` bits of
refCounts
*/
/**
* Amount to change the weak count when adding or releasing a reference
*
* Note: The weak count is stored in the high `WeakCountNumBits` bits of
* refCounts
*/
static constexpr FieldType kWeakDelta = (kOne << kStrongCountNumBits);
/** Flag that is set when the partialDestroy function has started running
(or is about to start running).
See description of the `refCounts` field for a fuller description of
this field.
*/
/**
* Flag that is set when the partialDestroy function has started running
* (or is about to start running).
*
* See description of the `refCounts` field for a fuller description of
* this field.
*/
static constexpr FieldType kPartialDestroyStartedMask = (kOne << (kFieldTypeBits - 1));
/** Flag that is set when the partialDestroy function has finished running
See description of the `refCounts` field for a fuller description of
this field.
*/
/**
* Flag that is set when the partialDestroy function has finished running
*
* See description of the `refCounts` field for a fuller description of
* this field.
*/
static constexpr FieldType kPartialDestroyFinishedMask = (kOne << (kFieldTypeBits - 2));
/** Mask that will zero out all the `count` bits and leave the tag bits
unchanged.
*/
/**
* Mask that will zero out all the `count` bits and leave the tag bits
* unchanged.
*/
static constexpr FieldType kTagMask = kPartialDestroyStartedMask | kPartialDestroyFinishedMask;
/** Mask that will zero out the `tag` bits and leave the count bits
unchanged.
*/
/**
* Mask that will zero out the `tag` bits and leave the count bits
* unchanged.
*/
static constexpr FieldType kValueMask = ~kTagMask;
/** Mask that will zero out everything except the strong count.
/**
* Mask that will zero out everything except the strong count.
*/
static constexpr FieldType kStrongMask = ((kOne << kStrongCountNumBits) - 1) & kValueMask;
/** Mask that will zero out everything except the weak count.
/**
* Mask that will zero out everything except the weak count.
*/
static constexpr FieldType kWeakMask =
(((kOne << kWeakCountNumBits) - 1) << kStrongCountNumBits) & kValueMask;
/** Unpack the count and tag fields from the packed atomic integer form. */
/**
* Unpack the count and tag fields from the packed atomic integer form.
*/
struct RefCountPair
{
CountType strong;
CountType weak;
/** The `partialDestroyStartedBit` is set to on when the partial
destroy function is started. It is not a boolean; it is a uint32
with all bits zero with the possible exception of the
`partialDestroyStartedMask` bit. This is done so it can be directly
masked into the `combinedValue`.
/**
* The `partialDestroyStartedBit` is set to on when the partial
* destroy function is started. It is not a boolean; it is a uint32
* with all bits zero with the possible exception of the
* `partialDestroyStartedMask` bit. This is done so it can be directly
* masked into the `combinedValue`.
*/
FieldType partialDestroyStartedBit{0};
/** The `partialDestroyFinishedBit` is set to on when the partial
destroy function has finished.
/**
* The `partialDestroyFinishedBit` is set to on when the partial
* destroy function has finished.
*/
FieldType partialDestroyFinishedBit{0};
RefCountPair(FieldType v) noexcept;
RefCountPair(CountType s, CountType w) noexcept;
/** Convert back to the packed integer form. */
/**
* Convert back to the packed integer form.
*/
[[nodiscard]] FieldType
combinedValue() const noexcept;
@@ -215,9 +232,10 @@ private:
static_cast<CountType>((kOne << kStrongCountNumBits) - 1);
static constexpr CountType kMaxWeakValue =
static_cast<CountType>((kOne << kWeakCountNumBits) - 1);
/** Put an extra margin to detect when running up against limits.
This is only used in debug code, and is useful if we reduce the
number of bits in the strong and weak counts (to 16 and 14 bits).
/**
* Put an extra margin to detect when running up against limits.
* This is only used in debug code, and is useful if we reduce the
* number of bits in the strong and weak counts (to 16 and 14 bits).
*/
static constexpr CountType kCheckStrongMaxValue = kMaxStrongValue - 32;
static constexpr CountType kCheckWeakMaxValue = kMaxWeakValue - 32;

View File

@@ -70,11 +70,15 @@ public:
{
}
/** Stores instance of T specific to the calling coroutine or thread. */
/**
* Stores instance of T specific to the calling coroutine or thread.
*/
T&
operator*();
/** Stores instance of T specific to the calling coroutine or thread. */
/**
* Stores instance of T specific to the calling coroutine or thread.
*/
T*
operator->()
{

View File

@@ -16,7 +16,9 @@
namespace xrpl {
/** Manages partitions for logging. */
/**
* Manages partitions for logging.
*/
class Logs
{
private:
@@ -40,69 +42,81 @@ private:
writeAlways(beast::Severity level, std::string const& text) override;
};
/** Manages a system file containing logged output.
The system file remains open during program execution. Interfaces
are provided for interoperating with standard log management
tools like logrotate(8):
http://linuxcommand.org/man_pages/logrotate8.html
@note None of the listed interfaces are thread-safe.
*/
/**
* Manages a system file containing logged output.
* The system file remains open during program execution. Interfaces
* are provided for interoperating with standard log management
* tools like logrotate(8):
* http://linuxcommand.org/man_pages/logrotate8.html
* @note None of the listed interfaces are thread-safe.
*/
class File
{
public:
/** Construct with no associated system file.
A system file may be associated later with @ref open.
@see open
*/
/**
* Construct with no associated system file.
* A system file may be associated later with @ref open.
* @see open
*/
File();
/** Destroy the object.
If a system file is associated, it will be flushed and closed.
*/
/**
* Destroy the object.
* If a system file is associated, it will be flushed and closed.
*/
~File() = default;
/** Determine if a system file is associated with the log.
@return `true` if a system file is associated and opened for
writing.
*/
/**
* Determine if a system file is associated with the log.
* @return `true` if a system file is associated and opened for
* writing.
*/
[[nodiscard]] bool
isOpen() const noexcept;
/** Associate a system file with the log.
If the file does not exist an attempt is made to create it
and open it for writing. If the file already exists an attempt is
made to open it for appending.
If a system file is already associated with the log, it is closed
first.
@return `true` if the file was opened.
*/
/**
* Associate a system file with the log.
* If the file does not exist an attempt is made to create it
* and open it for writing. If the file already exists an attempt is
* made to open it for appending.
* If a system file is already associated with the log, it is closed
* first.
* @return `true` if the file was opened.
*/
bool
open(boost::filesystem::path const& path);
/** Close and re-open the system file associated with the log
This assists in interoperating with external log management tools.
@return `true` if the file was opened.
*/
/**
* Close and re-open the system file associated with the log
* This assists in interoperating with external log management tools.
* @return `true` if the file was opened.
*/
bool
closeAndReopen();
/** Close the system file if it is open. */
/**
* Close the system file if it is open.
*/
void
close();
/** write to the log file.
Does nothing if there is no associated system file.
*/
/**
* write to the log file.
* Does nothing if there is no associated system file.
*/
void
write(char const* text);
/** write to the log file and append an end of line marker.
Does nothing if there is no associated system file.
*/
/**
* write to the log file and append an end of line marker.
* Does nothing if there is no associated system file.
*/
void
writeln(char const* text);
/** Write to the log file using std::string. */
/**
* Write to the log file using std::string.
*/
/** @{ */
void
write(std::string const& str)
@@ -223,19 +237,21 @@ private:
//------------------------------------------------------------------------------
// Debug logging:
/** Set the sink for the debug journal.
@param sink unique_ptr to new debug Sink.
@return unique_ptr to the previous Sink. nullptr if there was no Sink.
*/
/**
* Set the sink for the debug journal.
*
* @param sink unique_ptr to new debug Sink.
* @return unique_ptr to the previous Sink. nullptr if there was no Sink.
*/
std::unique_ptr<beast::Journal::Sink>
setDebugLogSink(std::unique_ptr<beast::Journal::Sink> sink);
/** Returns a debug journal.
The journal may drain to a null sink, so its output
may never be seen. Never use it for critical
information.
*/
/**
* Returns a debug journal.
* The journal may drain to a null sink, so its output
* may never be seen. Never use it for critical
* information.
*/
beast::Journal
debugLog();

View File

@@ -6,7 +6,8 @@
namespace xrpl {
/** Calculate one number divided by another number in percentage.
/**
* Calculate one number divided by another number in percentage.
* The result is rounded up to the next integer, and capped in the range [0,100]
* E.g. calculatePercent(1, 100) = 1 because 1/100 = 0.010000
* calculatePercent(1, 99) = 2 because 1/99 = 0.010101
@@ -19,7 +20,7 @@ namespace xrpl {
* @return the percentage, in [0, 100]
*
* @note total cannot be zero.
* */
*/
constexpr std::size_t
calculatePercent(std::size_t count, std::size_t total)
{

View File

@@ -14,7 +14,6 @@
#include <stdexcept>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <utility>
namespace xrpl {
@@ -48,46 +47,54 @@ isPowerOfTen(T value)
namespace detail {
/** Builds a table of the powers of 10
/**
* Builds a table of the powers of 10
*
* This function is marked consteval, so it can only be run in
* a constexpr context. This assures that it is and can only be run at
* compile time. Doing it at runtime would be pretty wasteful and
* inefficient.
*/
constexpr std::size_t kInt64Digits = 20;
consteval std::array<std::uint64_t, kInt64Digits>
constexpr std::size_t kUint64Digits = 20;
[[maybe_unused]] constexpr std::size_t kUint128Digits = 39;
template <typename T, std::size_t Digits>
consteval std::array<T, Digits>
buildPowersOfTen()
{
std::array<std::uint64_t, kInt64Digits> result{};
std::array<T, Digits> result{};
std::uint64_t power = 1;
T power = 1;
std::size_t exponent = 0;
// end the loop early so it doesn't overflow;
for (; exponent < result.size() - 1; ++exponent, power *= 10)
{
result[exponent] = power;
if (power > std::numeric_limits<std::uint64_t>::max() / 10)
if (power > std::numeric_limits<T>::max() / 10)
throw std::logic_error("Power of 10 table is too big");
}
result[exponent] = power;
if (power < std::numeric_limits<std::uint64_t>::max() / 10)
throw std::logic_error("Power of 10 table is not big enough for the uint64_t type");
if (power < std::numeric_limits<T>::max() / 10)
throw std::logic_error("Power of 10 table is not big enough for the given type");
return result;
}
} // namespace detail
constexpr std::array<std::uint64_t, detail::kInt64Digits> kPowerOfTen = detail::buildPowersOfTen();
template <typename T = std::uint64_t, std::size_t Digits = detail::kUint64Digits>
constexpr std::array<T, Digits> kPowerOfTenImpl = detail::buildPowersOfTen<T, Digits>();
constexpr auto kPowerOfTen = kPowerOfTenImpl<std::uint64_t, detail::kUint64Digits>;
static_assert(kPowerOfTen[0] == 1);
static_assert(kPowerOfTen[1] == 10);
static_assert(kPowerOfTen[10] == 10'000'000'000);
static_assert(
isPowerOfTen(kPowerOfTen.back()) && *logTen(kPowerOfTen.back()) == detail::kInt64Digits - 1);
isPowerOfTen(kPowerOfTen.back()) && *logTen(kPowerOfTen.back()) == detail::kUint64Digits - 1);
/** MantissaRange defines a range for the mantissa of a normalized Number.
/**
* MantissaRange defines a range for the mantissa of a normalized Number.
*
* The mantissa is in the range [min, max], where
* * min is a power of 10, and
@@ -124,17 +131,37 @@ struct MantissaRange final
{
using rep = std::uint64_t;
// NOLINTBEGIN(readability-enum-initial-value)
// The values don't matter, except for Large
enum class MantissaScale {
// Small can be removed when either featureSingleAssetVault or featureLendingProtocol are
// retired
Small,
// LargeLegacy can be removed when fixCleanup3_2_0 is retired
LargeLegacy,
Large,
// Large320 can be removed when fixCleanup3_3_0 is retired
Large320,
// If Large330 is ever the only remaining "Large*" entry, it can be renamed to just "Large".
Large330,
// Large is a de-facto alias for "the latest", and is only here for backward compatibility
// in the extremely unlikely case that a downstream project made use of it. Note that
// because the behavior changed, this may still be a breaking change.
Large = Large330,
};
// NOLINTEND(readability-enum-initial-value)
// This entire enum can be removed when fixCleanup3_2_0 is retired
enum class CuspRoundingFix : bool {
Disabled = false,
Enabled = true,
// This entire enum can be removed when the last relevant amendment is retired
enum class CuspRoundingFix : std::uint8_t {
// Disabled can be removed when fixCleanup3_2_0 is retired
Disabled = 0,
// Enabled320 can be removed when fixCleanup3_3_0 is retired
Enabled320 = 1,
// If we ever get to the point that there's only one entry, remove the entire enum
Enabled330 = 2,
// Enabled is a de-facto alias for "the latest", and is only here for backward compatibility
// in the extremely unlikely case that a downstream project made use of it. Note that
// because the behavior changed, this may still be a breaking change.
Enabled = Enabled330,
};
explicit constexpr MantissaRange(MantissaScale sc) : scale(sc)
@@ -145,13 +172,27 @@ struct MantissaRange final
int const log{getExponent(scale)};
rep const min{getMin(scale, log)};
rep const max{(min * 10) - 1};
CuspRoundingFix const cuspRoundingFixEnabled{isCuspFixEnabled(scale)};
static MantissaRange const&
getMantissaRange(MantissaScale scale);
CuspRoundingFix const cuspRoundingFix{isCuspFixEnabled(scale)};
static std::set<MantissaScale> const&
getAllScales();
getAllScales()
{
static std::set<MantissaRange::MantissaScale> const kScales = {
MantissaRange::MantissaScale::Small,
MantissaRange::MantissaScale::LargeLegacy,
MantissaRange::MantissaScale::Large320,
MantissaRange::MantissaScale::Large330,
};
return kScales;
}
class Access
{
static constexpr MantissaRange const&
mantissaRange(MantissaScale scale);
friend Number;
};
private:
static constexpr int
@@ -162,7 +203,8 @@ private:
case MantissaScale::Small:
return 15;
case MantissaScale::LargeLegacy:
case MantissaScale::Large:
case MantissaScale::Large320:
case MantissaScale::Large330:
return 18;
// LCOV_EXCL_START
default:
@@ -191,24 +233,24 @@ private:
case MantissaScale::Small:
case MantissaScale::LargeLegacy:
return CuspRoundingFix::Disabled;
case MantissaScale::Large:
return CuspRoundingFix::Enabled;
case MantissaScale::Large320:
return CuspRoundingFix::Enabled320;
case MantissaScale::Large330:
return CuspRoundingFix::Enabled330;
default:
// If called in a constexpr context, this throw assures that the build fails if an
// invalid scale is used.
throw std::runtime_error("Unknown mantissa scale"); // LCOV_EXCL_LINE
}
}
static std::unordered_map<MantissaScale, MantissaRange> const&
getRanges();
};
// Like std::integral, but only 64-bit integral types.
template <class T>
concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::uint64_t>;
/** Number is a floating point type that can represent a wide range of values.
/**
* Number is a floating point type that can represent a wide range of values.
*
* It can represent all values that can be represented by an STAmount -
* regardless of asset type - XRPAmount, MPTAmount, and IOUAmount, with at least
@@ -304,7 +346,6 @@ concept Integral64 = std::is_same_v<T, std::int64_t> || std::is_same_v<T, std::u
* disable the amendments that control the mantissa range choice
* (SingleAssetVault and LendingProtocol), and/or check if either of those
* amendments are enabled to determine which result to expect.
*
*/
class Number final
{
@@ -390,10 +431,11 @@ public:
static Number
lowest() noexcept;
/** Conversions to Number are implicit and conversions away from Number
* are explicit. This design encourages and facilitates the use of Number
* as the preferred type for floating point arithmetic as it makes
* "mixed mode" more convenient, e.g. MPTAmount + Number.
/**
* Conversions to Number are implicit and conversions away from Number
* are explicit. This design encourages and facilitates the use of Number
* as the preferred type for floating point arithmetic as it makes
* "mixed mode" more convenient, e.g. MPTAmount + Number.
*/
explicit
operator rep() const; // round to nearest, even on tie
@@ -448,7 +490,9 @@ public:
return l.mantissa_ < r.mantissa_;
}
/** Return the sign of the amount */
/**
* Return the sign of the amount
*/
[[nodiscard]] constexpr int
signum() const noexcept
{
@@ -502,14 +546,16 @@ public:
static RoundingMode
setround(RoundingMode inMode);
/** Returns which mantissa scale is currently in use for normalization.
/**
* Returns which mantissa scale is currently in use for normalization.
*
* If you think you need to call this outside of unit tests, no you don't.
*/
static MantissaRange::MantissaScale
getMantissaScale();
/** Changes which mantissa scale is used for normalization.
/**
* Changes which mantissa scale is used for normalization.
*
* If you think you need to call this outside of unit tests, no you don't.
*/
@@ -554,10 +600,17 @@ private:
// changing the values inside the range.
static thread_local std::reference_wrapper<MantissaRange const> kRange;
class Guard;
void
normalize(MantissaRange const& range);
/** Normalize Number components to an arbitrary range.
// Guard has the fields that we need, as well as MantissaRange, so if we have a guard, use that
void
normalize(Guard const& guard);
/**
* Normalize Number components to an arbitrary range.
*
* min/maxMantissa are parameters because this function is used by both
* normalize(), which reads from kRange, and by normalizeToRange,
@@ -571,7 +624,7 @@ private:
int& exponent,
internalrep const& minMantissa,
internalrep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled);
MantissaRange::CuspRoundingFix cuspRoundingFix);
template <class T>
friend void
@@ -581,7 +634,7 @@ private:
int& exponent,
MantissaRange::rep const& minMantissa,
MantissaRange::rep const& maxMantissa,
MantissaRange::CuspRoundingFix cuspRoundingFixEnabled,
MantissaRange::CuspRoundingFix cuspRoundingFix,
bool dropped);
[[nodiscard]] bool
@@ -599,8 +652,6 @@ private:
// UB, and can vary across compilers.
static internalrep
externalToInternal(rep mantissa);
class Guard;
};
constexpr Number::Number(bool negative, internalrep mantissa, int exponent, Unchecked) noexcept
@@ -635,7 +686,8 @@ inline Number::Number(rep mantissa) : Number{mantissa, 0}
{
}
/** Returns the mantissa of the external view of the Number.
/**
* Returns the mantissa of the external view of the Number.
*
* Please see the "---- External Interface ----" section of the class
* documentation for an explanation of why the internal value may be modified.
@@ -656,7 +708,8 @@ Number::mantissa() const noexcept
return sign * static_cast<Number::rep>(m);
}
/** Returns the exponent of the external view of the Number.
/**
* Returns the exponent of the external view of the Number.
*
* Please see the "---- External Interface ----" section of the class
* documentation for an explanation of why the internal value may be modified.
@@ -862,21 +915,11 @@ squelch(Number const& x, Number const& limit) noexcept
return x;
}
inline std::string
to_string(MantissaRange::MantissaScale const& scale)
{
switch (scale)
{
case MantissaRange::MantissaScale::Small:
return "small";
case MantissaRange::MantissaScale::LargeLegacy:
return "largeLegacy";
case MantissaRange::MantissaScale::Large:
return "large";
default:
throw std::runtime_error("Bad scale");
}
}
std::string
to_string(MantissaRange::MantissaScale const& scale);
std::string
to_string(Number::RoundingMode const& round);
class SaveNumberRoundMode
{
@@ -915,10 +958,10 @@ public:
operator=(NumberRoundModeGuard const&) = delete;
};
/** Sets the new scale and restores the old scale when it leaves scope.
/**
* Sets the new scale and restores the old scale when it leaves scope.
*
* If you think you need to use this class outside of unit tests, no you don't.
*
*/
class NumberMantissaScaleGuard
{

View File

@@ -13,23 +13,25 @@
namespace xrpl {
/** A closed interval over the domain T.
For an instance ClosedInterval c, this represents the closed interval
(c.first(), c.last()). A single element interval has c.first() == c.last().
This is simply a type-alias for boost interval container library interval
set, so users should consult that documentation for available supporting
member and free functions.
*/
/**
* A closed interval over the domain T.
*
* For an instance ClosedInterval c, this represents the closed interval
* (c.first(), c.last()). A single element interval has c.first() == c.last().
*
* This is simply a type-alias for boost interval container library interval
* set, so users should consult that documentation for available supporting
* member and free functions.
*/
template <class T>
using ClosedInterval = boost::icl::closed_interval<T>;
/** Create a closed range interval
Helper function to create a closed range interval without having to qualify
the template argument.
*/
/**
* Create a closed range interval
*
* Helper function to create a closed range interval without having to qualify
* the template argument.
*/
template <class T>
ClosedInterval<T>
range(T low, T high)
@@ -37,28 +39,30 @@ range(T low, T high)
return ClosedInterval<T>(low, high);
}
/** A set of closed intervals over the domain T.
Represents a set of values of the domain T using the minimum number
of disjoint ClosedInterval<T>. This is useful to represent ranges of
T where a few instances are missing, e.g. the set 1-5,8-9,11-14.
This is simply a type-alias for boost interval container library interval
set, so users should consult that documentation for available supporting
member and free functions.
*/
/**
* A set of closed intervals over the domain T.
*
* Represents a set of values of the domain T using the minimum number
* of disjoint ClosedInterval<T>. This is useful to represent ranges of
* T where a few instances are missing, e.g. the set 1-5,8-9,11-14.
*
* This is simply a type-alias for boost interval container library interval
* set, so users should consult that documentation for available supporting
* member and free functions.
*/
template <class T>
using RangeSet = boost::icl::interval_set<T, std::less, ClosedInterval<T>>;
/** Convert a ClosedInterval to a styled string
The styled string is
"c.first()-c.last()" if c.first() != c.last()
"c.first()" if c.first() == c.last()
@param ci The closed interval to convert
@return The style string
*/
/**
* Convert a ClosedInterval to a styled string
*
* The styled string is
* "c.first()-c.last()" if c.first() != c.last()
* "c.first()" if c.first() == c.last()
*
* @param ci The closed interval to convert
* @return The style string
*/
template <class T>
std::string
to_string(ClosedInterval<T> const& ci)
@@ -68,14 +72,15 @@ to_string(ClosedInterval<T> const& ci)
return std::to_string(ci.first()) + "-" + std::to_string(ci.last());
}
/** Convert the given RangeSet to a styled string.
The styled string representation is the set of disjoint intervals joined
by commas. The string "empty" is returned if the set is empty.
@param rs The rangeset to convert
@return The styled string
*/
/**
* Convert the given RangeSet to a styled string.
*
* The styled string representation is the set of disjoint intervals joined
* by commas. The string "empty" is returned if the set is empty.
*
* @param rs The rangeset to convert
* @return The styled string
*/
template <class T>
std::string
to_string(RangeSet<T> const& rs)
@@ -91,15 +96,16 @@ to_string(RangeSet<T> const& rs)
return s;
}
/** Convert the given styled string to a RangeSet.
The styled string representation is the set
of disjoint intervals joined by commas.
@param rs The set to be populated
@param s The styled string to convert
@return True on successfully converting styled string
*/
/**
* Convert the given styled string to a RangeSet.
*
* The styled string representation is the set
* of disjoint intervals joined by commas.
*
* @param rs The set to be populated
* @param s The styled string to convert
* @return True on successfully converting styled string
*/
template <class T>
[[nodiscard]] bool
fromString(RangeSet<T>& rs, std::string const& s)
@@ -161,14 +167,15 @@ fromString(RangeSet<T>& rs, std::string const& s)
return result;
}
/** Find the largest value not in the set that is less than a given value.
@param rs The set of interest
@param t The value that must be larger than the result
@param minVal (Default is 0) The smallest allowed value
@return The largest v such that minV <= v < t and !contains(rs, v) or
std::nullopt if no such v exists.
*/
/**
* Find the largest value not in the set that is less than a given value.
*
* @param rs The set of interest
* @param t The value that must be larger than the result
* @param minVal (Default is 0) The smallest allowed value
* @return The largest v such that minV <= v < t and !contains(rs, v) or
* std::nullopt if no such v exists.
*/
template <class T>
std::optional<T>
prevMissing(RangeSet<T> const& rs, T t, T minVal = 0)

View File

@@ -15,22 +15,29 @@ public:
virtual ~Resolver() = 0;
/** Issue an asynchronous stop request. */
/**
* Issue an asynchronous stop request.
*/
virtual void
stopAsync() = 0;
/** Issue a synchronous stop request. */
/**
* Issue a synchronous stop request.
*/
virtual void
stop() = 0;
/** Issue a synchronous start request. */
/**
* Issue a synchronous start request.
*/
virtual void
start() = 0;
/** resolve all hostnames on the list
@param names the names to be resolved
@param handler the handler to call
*/
/**
* resolve all hostnames on the list
* @param names the names to be resolved
* @param handler the handler to call
*/
/** @{ */
template <class Handler>
void

View File

@@ -7,13 +7,14 @@
namespace xrpl {
/** A combination of a std::shared_ptr and a std::weak_pointer.
This class is a wrapper to a `std::variant<std::shared_ptr,std::weak_ptr>`
This class is useful for storing intrusive pointers in tagged caches using less
memory than storing both pointers directly.
*/
/**
* A combination of a std::shared_ptr and a std::weak_pointer.
*
*
* This class is a wrapper to a `std::variant<std::shared_ptr,std::weak_ptr>`
* This class is useful for storing intrusive pointers in tagged caches using less
* memory than storing both pointers directly.
*/
template <class T>
class SharedWeakCachePointer
@@ -48,65 +49,79 @@ public:
~SharedWeakCachePointer();
/** Return a strong pointer if this is already a strong pointer (i.e. don't
lock the weak pointer. Use the `lock` method if that's what's needed)
/**
* Return a strong pointer if this is already a strong pointer (i.e. don't
* lock the weak pointer. Use the `lock` method if that's what's needed)
*/
[[nodiscard]] std::shared_ptr<T> const&
getStrong() const;
/** Return true if this is a strong pointer and the strong pointer is
seated.
/**
* Return true if this is a strong pointer and the strong pointer is
* seated.
*/
explicit
operator bool() const noexcept;
/** Set the pointer to null, decrement the appropriate ref count, and run
the appropriate release action.
/**
* Set the pointer to null, decrement the appropriate ref count, and run
* the appropriate release action.
*/
void
reset();
/** If this is a strong pointer, return the raw pointer. Otherwise return
null.
/**
* If this is a strong pointer, return the raw pointer. Otherwise return
* null.
*/
[[nodiscard]] T*
get() const;
/** If this is a strong pointer, return the strong count. Otherwise return 0
/**
* If this is a strong pointer, return the strong count. Otherwise return 0
*/
[[nodiscard]] std::size_t
useCount() const;
/** Return true if there is a non-zero strong count. */
/**
* Return true if there is a non-zero strong count.
*/
[[nodiscard]] bool
expired() const;
/** If this is a strong pointer, return the strong pointer. Otherwise
attempt to lock the weak pointer.
/**
* If this is a strong pointer, return the strong pointer. Otherwise
* attempt to lock the weak pointer.
*/
[[nodiscard]] std::shared_ptr<T>
lock() const;
/** Return true is this represents a strong pointer. */
/**
* Return true is this represents a strong pointer.
*/
[[nodiscard]] bool
isStrong() const;
/** Return true is this represents a weak pointer. */
/**
* Return true is this represents a weak pointer.
*/
[[nodiscard]] bool
isWeak() const;
/** If this is a weak pointer, attempt to convert it to a strong pointer.
@return true if successfully converted to a strong pointer (or was
already a strong pointer). Otherwise false.
*/
/**
* If this is a weak pointer, attempt to convert it to a strong pointer.
*
* @return true if successfully converted to a strong pointer (or was
* already a strong pointer). Otherwise false.
*/
bool
convertToStrong();
/** If this is a strong pointer, attempt to convert it to a weak pointer.
@return false if the pointer is null. Otherwise return true.
*/
/**
* If this is a strong pointer, attempt to convert it to a weak pointer.
*
* @return false if the pointer is null. Otherwise return true.
*/
bool
convertToWeak();

View File

@@ -33,7 +33,9 @@ class SlabAllocator
static_assert(alignof(Type) == 8 || alignof(Type) == 4);
/** A block of memory that is owned by a slab allocator */
/**
* A block of memory that is owned by a slab allocator
*/
struct SlabBlock
{
// A mutex to protect the freelist for this block:
@@ -80,7 +82,9 @@ class SlabAllocator
SlabBlock&
operator=(SlabBlock&& other) = delete;
/** Determines whether the given pointer belongs to this allocator */
/**
* Determines whether the given pointer belongs to this allocator
*/
bool
own(std::uint8_t const* pIn) const noexcept
{
@@ -107,14 +111,15 @@ class SlabAllocator
return ret;
}
/** Return an item to this allocator's freelist.
@param ptr The pointer to the chunk of memory being deallocated.
@note This is a dangerous, private interface; the item being
returned should belong to this allocator. Debug builds
will check and assert if this is not the case. Release
builds will not.
/**
* Return an item to this allocator's freelist.
*
* @param ptr The pointer to the chunk of memory being deallocated.
*
* @note This is a dangerous, private interface; the item being
* returned should belong to this allocator. Debug builds
* will check and assert if this is not the case. Release
* builds will not.
*/
void
deallocate(std::uint8_t* ptr) noexcept
@@ -145,13 +150,14 @@ private:
std::size_t const slabSize_;
public:
/** Constructs a slab allocator able to allocate objects of a fixed size
@param count the number of items the slab allocator can allocate; note
that a count of 0 is valid and means that the allocator
is, effectively, disabled. This can be very useful in some
contexts (e.g. when minimal memory usage is needed) and
allows for graceful failure.
/**
* Constructs a slab allocator able to allocate objects of a fixed size
*
* @param count the number of items the slab allocator can allocate; note
* that a count of 0 is valid and means that the allocator
* is, effectively, disabled. This can be very useful in some
* contexts (e.g. when minimal memory usage is needed) and
* allows for graceful failure.
*/
constexpr explicit SlabAllocator(
std::size_t extra,
@@ -179,17 +185,20 @@ public:
// shutdown process up could make this possible.
~SlabAllocator() = default;
/** Returns the size of the memory block this allocator returns. */
/**
* Returns the size of the memory block this allocator returns.
*/
[[nodiscard]] constexpr std::size_t
size() const noexcept
{
return itemSize_;
}
/** Returns a suitably aligned pointer, if one is available.
@return a pointer to a block of memory from the allocator, or
nullptr if the allocator can't satisfy this request.
/**
* Returns a suitably aligned pointer, if one is available.
*
* @return a pointer to a block of memory from the allocator, or
* nullptr if the allocator can't satisfy this request.
*/
std::uint8_t*
allocate() noexcept
@@ -250,12 +259,13 @@ public:
return slab->allocate();
}
/** Returns the memory block to the allocator.
@param ptr A pointer to a memory block.
@param size If non-zero, a hint as to the size of the block.
@return true if this memory block belonged to the allocator and has
been released; false otherwise.
/**
* Returns the memory block to the allocator.
*
* @param ptr A pointer to a memory block.
* @param size If non-zero, a hint as to the size of the block.
* @return true if this memory block belonged to the allocator and has
* been released; false otherwise.
*/
bool
deallocate(std::uint8_t* ptr) noexcept
@@ -278,7 +288,9 @@ public:
}
};
/** A collection of slab allocators of various sizes for a given type. */
/**
* A collection of slab allocators of various sizes for a given type.
*/
template <typename Type>
class SlabAllocatorSet
{
@@ -345,13 +357,14 @@ public:
~SlabAllocatorSet() = default;
/** Returns a suitably aligned pointer, if one is available.
@param extra The number of extra bytes, above and beyond the size of
the object, that should be returned by the allocator.
@return a pointer to a block of memory, or nullptr if the allocator
can't satisfy this request.
/**
* Returns a suitably aligned pointer, if one is available.
*
* @param extra The number of extra bytes, above and beyond the size of
* the object, that should be returned by the allocator.
*
* @return a pointer to a block of memory, or nullptr if the allocator
* can't satisfy this request.
*/
std::uint8_t*
allocate(std::size_t extra) noexcept
@@ -368,12 +381,13 @@ public:
return nullptr;
}
/** Returns the memory block to the allocator.
@param ptr A pointer to a memory block.
@return true if this memory block belonged to one of the allocators
in this set and has been released; false otherwise.
/**
* Returns the memory block to the allocator.
*
* @param ptr A pointer to a memory block.
*
* @return true if this memory block belonged to one of the allocators
* in this set and has been released; false otherwise.
*/
bool
deallocate(std::uint8_t* ptr) noexcept

View File

@@ -16,12 +16,13 @@
namespace xrpl {
/** An immutable linear range of bytes.
A fully constructed Slice is guaranteed to be in a valid state.
A Slice is lightweight and copyable, it retains no ownership
of the underlying memory.
*/
/**
* An immutable linear range of bytes.
*
* A fully constructed Slice is guaranteed to be in a valid state.
* A Slice is lightweight and copyable, it retains no ownership
* of the underlying memory.
*/
class Slice
{
private:
@@ -32,30 +33,37 @@ public:
using value_type = std::uint8_t;
using const_iterator = value_type const*;
/** Default constructed Slice has length 0. */
/**
* Default constructed Slice has length 0.
*/
Slice() noexcept = default;
Slice(Slice const&) noexcept = default;
Slice&
operator=(Slice const&) noexcept = default;
/** Create a slice pointing to existing memory. */
/**
* Create a slice pointing to existing memory.
*/
Slice(void const* data, std::size_t size) noexcept
: data_(reinterpret_cast<std::uint8_t const*>(data)), size_(size)
{
}
/** Return `true` if the byte range is empty. */
/**
* Return `true` if the byte range is empty.
*/
[[nodiscard]] bool
empty() const noexcept
{
return size_ == 0;
}
/** Returns the number of bytes in the storage.
This may be zero for an empty range.
*/
/**
* Returns the number of bytes in the storage.
*
* This may be zero for an empty range.
*/
/** @{ */
[[nodiscard]] std::size_t
size() const noexcept
@@ -70,17 +78,20 @@ public:
}
/** @} */
/** Return a pointer to beginning of the storage.
@note The return type is guaranteed to be a pointer
to a single byte, to facilitate pointer arithmetic.
*/
/**
* Return a pointer to beginning of the storage.
* @note The return type is guaranteed to be a pointer
* to a single byte, to facilitate pointer arithmetic.
*/
[[nodiscard]] std::uint8_t const*
data() const noexcept
{
return data_;
}
/** Access raw bytes. */
/**
* Access raw bytes.
*/
std::uint8_t
operator[](std::size_t i) const noexcept
{
@@ -88,7 +99,9 @@ public:
return data_[i];
}
/** Advance the buffer. */
/**
* Advance the buffer.
*/
/** @{ */
Slice&
operator+=(std::size_t n)
@@ -108,7 +121,9 @@ public:
}
/** @} */
/** Shrinks the slice by moving its start forward by n characters. */
/**
* Shrinks the slice by moving its start forward by n characters.
*/
void
removePrefix(std::size_t n)
{
@@ -116,7 +131,9 @@ public:
size_ -= n;
}
/** Shrinks the slice by moving its end backward by n characters. */
/**
* Shrinks the slice by moving its end backward by n characters.
*/
void
removeSuffix(std::size_t n)
{
@@ -147,16 +164,17 @@ public:
return data_ + size_;
}
/** Return a "sub slice" of given length starting at the given position
Note that the subslice encompasses the range [pos, pos + rCount),
where rCount is the smaller of count and size() - pos.
@param pos position of the first character
@count requested length
@returns The requested subslice, if the request is valid.
@throws std::out_of_range if pos > size()
/**
* Return a "sub slice" of given length starting at the given position
*
* Note that the subslice encompasses the range [pos, pos + rCount),
* where rCount is the smaller of count and size() - pos.
*
* @param pos position of the first character
* @count requested length
*
* @return The requested subslice, if the request is valid.
* @throws std::out_of_range if pos > size()
*/
[[nodiscard]] Slice
substr(std::size_t pos, std::size_t count = std::numeric_limits<std::size_t>::max()) const

View File

@@ -17,15 +17,16 @@
namespace xrpl {
/** Format arbitrary binary data as an SQLite "blob literal".
In SQLite, blob literals must be encoded when used in a query. Per
https://sqlite.org/lang_expr.html#literal_values_constants_ they are
encoded as string literals containing hexadecimal data and preceded
by a single 'X' character.
@param blob An arbitrary blob of binary data
@return The input, encoded as a blob literal.
/**
* Format arbitrary binary data as an SQLite "blob literal".
*
* In SQLite, blob literals must be encoded when used in a query. Per
* https://sqlite.org/lang_expr.html#literal_values_constants_ they are
* encoded as string literals containing hexadecimal data and preceded
* by a single 'X' character.
*
* @param blob An arbitrary blob of binary data
* @return The input, encoded as a blob literal.
*/
std::string
sqlBlobLiteral(Blob const& blob);
@@ -130,11 +131,12 @@ trimWhitespace(std::string str);
std::optional<std::uint64_t>
toUInt64(std::string const& s);
/** Determines if the given string looks like a TOML-file hosting domain.
Do not use this function to determine if a particular string is a valid
domain, as this function may reject domains that are otherwise valid and
doesn't check whether the TLD is valid.
/**
* Determines if the given string looks like a TOML-file hosting domain.
*
* Do not use this function to determine if a particular string is a valid
* domain, as this function may reject domains that are otherwise valid and
* doesn't check whether the TLD is valid.
*/
bool
isProperlyFormedTomlDomain(std::string_view domain);

View File

@@ -41,18 +41,19 @@ struct ReplaceDynamically;
} // namespace detail
/** Map/cache combination.
This class implements a cache and a map. The cache keeps objects alive
in the map. The map allows multiple code paths that reference objects
with the same tag to get the same actual object.
So long as data is in the cache, it will stay in memory.
If it stays in memory even after it is ejected from the cache,
the map will track it.
@note Callers must not modify data objects that are stored in the cache
unless they hold their own lock over all cache operations.
*/
/**
* Map/cache combination.
* This class implements a cache and a map. The cache keeps objects alive
* in the map. The map allows multiple code paths that reference objects
* with the same tag to get the same actual object.
*
* So long as data is in the cache, it will stay in memory.
* If it stays in memory even after it is ejected from the cache,
* the map will track it.
*
* @note Callers must not modify data objects that are stored in the cache
* unless they hold their own lock over all cache operations.
*/
template <
class Key,
class T,
@@ -82,11 +83,15 @@ public:
beast::insight::Collector::ptr const& collector = beast::insight::NullCollector::make());
public:
/** Return the clock associated with the cache. */
/**
* Return the clock associated with the cache.
*/
clock_type&
clock();
/** Returns the number of items in the container. */
/**
* Returns the number of items in the container.
*/
std::size_t
size() const;
@@ -105,9 +110,10 @@ public:
void
reset();
/** Refresh the last access time on a key if present.
@return `true` If the key was found.
*/
/**
* Refresh the last access time on a key if present.
* @return `true` If the key was found.
*/
template <class KeyComparable>
bool
touchIfExists(KeyComparable const& key);
@@ -130,14 +136,15 @@ private:
SharedPointerType const&,
SharedPointerType&>;
/** Shared implementation of the canonicalize family.
`policy` selects how a collision is resolved when `key` already exists:
detail::ReplaceCached, detail::ReplaceClient or
detail::ReplaceDynamically. For ReplaceDynamically `replaceCallback` is
invoked with the existing strong pointer and returns whether to replace
the cached value with `data`; for the tag policies it is unused.
*/
/**
* Shared implementation of the canonicalize family.
*
* `policy` selects how a collision is resolved when `key` already exists:
* detail::ReplaceCached, detail::ReplaceClient or
* detail::ReplaceDynamically. For ReplaceDynamically `replaceCallback` is
* invoked with the existing strong pointer and returns whether to replace
* the cached value with `data`; for the tag policies it is unused.
*/
template <class Policy, class Callback = std::nullptr_t>
bool
canonicalizeImpl(
@@ -147,69 +154,73 @@ private:
Callback&& replaceCallback = nullptr);
public:
/** Replace aliased objects with originals.
Due to concurrency it is possible for two separate objects with
the same content and referring to the same unique "thing" to exist.
This routine eliminates the duplicate and performs a replacement
on the callers shared pointer if needed.
`replaceCallback` is a callable taking the existing strong pointer and
returning whether to replace the cached value with `data` (true) or to
keep the cached value and write it back into `data` (false). Because the
write-back case mutates `data`, `data` must be writable.
@param key The key corresponding to the object
@param data A shared pointer to the data corresponding to the object.
@param replaceCallback A callable (existing strong pointer -> bool).
@return `true` if an existing live entry was found and used; `false` if a new entry was
inserted or an expired tracked entry was re-cached.
**/
/**
* Replace aliased objects with originals.
*
* Due to concurrency it is possible for two separate objects with
* the same content and referring to the same unique "thing" to exist.
* This routine eliminates the duplicate and performs a replacement
* on the callers shared pointer if needed.
*
* `replaceCallback` is a callable taking the existing strong pointer and
* returning whether to replace the cached value with `data` (true) or to
* keep the cached value and write it back into `data` (false). Because the
* write-back case mutates `data`, `data` must be writable.
*
* @param key The key corresponding to the object
* @param data A shared pointer to the data corresponding to the object.
* @param replaceCallback A callable (existing strong pointer -> bool).
*
* @return `true` if an existing live entry was found and used; `false` if a new entry was
* inserted or an expired tracked entry was re-cached.
*/
template <class Callback>
bool
canonicalize(key_type const& key, SharedPointerType& data, Callback&& replaceCallback);
/** Insert/update the canonical entry for `key`, always replacing the
cached value with `data`.
If an entry already exists for `key`, the cached value is unconditionally
replaced with `data`; otherwise `data` is inserted. `data` is never
written back, so it may be const.
@param key The key corresponding to the object.
@param data A shared pointer to the data corresponding to the object.
@return `true` if an existing live entry was found and used; `false` if a new entry was
inserted or an expired tracked entry was re-cached.
**/
/**
* Insert/update the canonical entry for `key`, always replacing the
* cached value with `data`.
*
* If an entry already exists for `key`, the cached value is unconditionally
* replaced with `data`; otherwise `data` is inserted. `data` is never
* written back, so it may be const.
*
* @param key The key corresponding to the object.
* @param data A shared pointer to the data corresponding to the object.
*
* @return `true` if an existing live entry was found and used; `false` if a new entry was
* inserted or an expired tracked entry was re-cached.
*/
bool
canonicalizeReplaceCache(key_type const& key, SharedPointerType const& data);
/** Insert the canonical entry for `key`, keeping any existing cached value.
If an entry already exists for `key`, the cached value is kept and
written back into `data` so the caller ends up with the canonical
object; otherwise `data` is inserted. Because `data` may be overwritten
it must be writable.
@param key The key corresponding to the object.
@param data A shared pointer to the data corresponding to the object;
updated to the canonical value when one already exists.
@return `true` if an existing live entry was found and used; `false` if a new entry was
inserted or an expired tracked entry was re-cached.
**/
/**
* Insert the canonical entry for `key`, keeping any existing cached value.
*
* If an entry already exists for `key`, the cached value is kept and
* written back into `data` so the caller ends up with the canonical
* object; otherwise `data` is inserted. Because `data` may be overwritten
* it must be writable.
*
* @param key The key corresponding to the object.
* @param data A shared pointer to the data corresponding to the object;
* updated to the canonical value when one already exists.
*
* @return `true` if an existing live entry was found and used; `false` if a new entry was
* inserted or an expired tracked entry was re-cached.
*/
bool
canonicalizeReplaceClient(key_type const& key, SharedPointerType& data);
SharedPointerType
fetch(key_type const& key);
/** Insert the element into the container.
If the key already exists, nothing happens.
@return `true` If the element was inserted
*/
/**
* Insert the element into the container.
* If the key already exists, nothing happens.
* @return `true` If the element was inserted
*/
template <class ReturnType = bool>
auto
insert(key_type const& key, T const& value) -> ReturnType
@@ -235,15 +246,18 @@ public:
getKeys() const;
// CachedSLEs functions.
/** Returns the fraction of cache hits. */
/**
* Returns the fraction of cache hits.
*/
double
rate() const;
/** Fetch an item from the cache.
If the digest was not found, Handler
will be called with this signature:
SLE::const_pointer(void)
*/
/**
* Fetch an item from the cache.
* If the digest was not found, Handler
* will be called with this signature:
* SLE::const_pointer(void)
*/
template <class Handler>
SharedPointerType
fetch(key_type const& digest, Handler const& h);

View File

@@ -5,10 +5,11 @@
namespace xrpl {
/** to_string() generalizes std::to_string to handle bools, chars, and strings.
It's also possible to provide implementation of to_string for a class
which needs a string implementation.
/**
* to_string() generalizes std::to_string to handle bools, chars, and strings.
*
* It's also possible to provide implementation of to_string for a class
* which needs a string implementation.
*/
template <class T>

View File

@@ -7,12 +7,13 @@
namespace xrpl {
/** Tracks program uptime to seconds precision.
The timer caches the current time as a performance optimization.
This allows clients to query the current time thousands of times
per second.
*/
/**
* Tracks program uptime to seconds precision.
*
* The timer caches the current time as a performance optimization.
* This allows clients to query the current time thousands of times
* per second.
*/
class UptimeClock
{

View File

@@ -63,18 +63,19 @@ struct AlwaysFalseT : std::bool_constant<false>
} // namespace detail
/** Integers of any length that is a multiple of 32-bits
@note This class stores its values internally in big-endian
form and that internal representation is part of the
binary protocol of the XRP Ledger and cannot be changed
arbitrarily without causing breakage.
@tparam Bits The number of bits this integer should have; must
be at least 64 and a multiple of 32.
@tparam Tag An arbitrary type that functions as a tag and allows
the instantiation of "distinct" types that the same
number of bits.
/**
* Integers of any length that is a multiple of 32-bits
*
* @note This class stores its values internally in big-endian
* form and that internal representation is part of the
* binary protocol of the XRP Ledger and cannot be changed
* arbitrarily without causing breakage.
*
* @tparam Bits The number of bits this integer should have; must
* be at least 64 and a multiple of 32.
* @tparam Tag An arbitrary type that functions as a tag and allows
* the instantiation of "distinct" types that the same
* number of bits.
*/
template <std::size_t Bits, class Tag = void>
class BaseUInt
@@ -154,21 +155,23 @@ public:
return data() + kBytes;
}
/** Value hashing function.
The seed prevents crafted inputs from causing degenerate parent
containers.
*/
/**
* Value hashing function.
* The seed prevents crafted inputs from causing degenerate parent
* containers.
*/
using hasher = HardenedHash<>;
//--------------------------------------------------------------------------
private:
/** Construct from a raw pointer.
The buffer pointed to by `data` must be at least Bits/8 bytes.
@note the structure is used to disambiguate this from the std::uint64_t
constructor: something like base_uint(0) is ambiguous.
*/
/**
* Construct from a raw pointer.
* The buffer pointed to by `data` must be at least Bits/8 bytes.
*
* @note the structure is used to disambiguate this from the std::uint64_t
* constructor: something like base_uint(0) is ambiguous.
*/
// NIKB TODO Remove the need for this constructor.
struct VoidHelper
{
@@ -503,13 +506,14 @@ public:
h(a.data_.data(), sizeof(a.data_));
}
/** Parse a hex string into a base_uint
The input must be precisely `2 * bytes` hexadecimal characters
long, with one exception: the value '0'.
@param sv A null-terminated string of hexadecimal characters
@return true if the input was parsed properly; false otherwise.
/**
* Parse a hex string into a base_uint
*
* The input must be precisely `2 * bytes` hexadecimal characters
* long, with one exception: the value '0'.
*
* @param sv A null-terminated string of hexadecimal characters
* @return true if the input was parsed properly; false otherwise.
*/
[[nodiscard]] constexpr bool
parseHex(std::string_view sv)
@@ -595,7 +599,7 @@ template <std::size_t Bits, typename Tag>
[[nodiscard]] constexpr bool
operator==(BaseUInt<Bits, Tag> const& lhs, BaseUInt<Bits, Tag> const& rhs)
{
return (lhs <=> rhs) == 0;
return (lhs <=> rhs) == 0; // NOLINT(modernize-use-nullptr)
}
//------------------------------------------------------------------------------

View File

@@ -21,15 +21,16 @@ using days =
using weeks = std::chrono::duration<int, std::ratio_multiply<days::period, std::ratio<7>>>;
/** Clock for measuring the network time.
The epoch is January 1, 2000
epoch_offset
= date(2000-01-01) - date(1970-0-01)
= days(10957)
= seconds(946684800)
*/
/**
* Clock for measuring the network time.
*
* The epoch is January 1, 2000
*
* epoch_offset
* = date(2000-01-01) - date(1970-0-01)
* = days(10957)
* = seconds(946684800)
*/
static constexpr std::chrono::seconds kEpochOffset =
date::sys_days{date::year{2000} / 1 / 1} - date::sys_days{date::year{1970} / 1 / 1};
@@ -81,16 +82,21 @@ toStringIso(NetClock::time_point tp)
return toStringIso(date::sys_time<NetClock::duration>{tp.time_since_epoch() + kEpochOffset});
}
/** A clock for measuring elapsed time.
The epoch is unspecified.
*/
/**
* A clock for measuring elapsed time.
*
* The epoch is unspecified.
*/
using Stopwatch = beast::AbstractClock<std::chrono::steady_clock>;
/** A manual Stopwatch for unit tests. */
/**
* A manual Stopwatch for unit tests.
*/
using TestStopwatch = beast::ManualClock<std::chrono::steady_clock>;
/** Returns an instance of a wall clock. */
/**
* Returns an instance of a wall clock.
*/
inline Stopwatch&
stopwatch()
{

View File

@@ -15,20 +15,23 @@ namespace xrpl {
preconditions, postconditions, and invariants.
*/
/** Generates and logs a call stack */
/**
* Generates and logs a call stack
*/
void
logThrow(std::string const& title);
/** Rethrow the exception currently being handled.
When called from within a catch block, it will pass
control to the next matching exception handler, if any.
Otherwise, std::terminate will be called.
ASAN can't handle sudden jumps in control flow very well. This
function is marked as XRPL_NO_SANITIZE_ADDRESS to prevent it from
triggering false positives, since it throws.
*/
/**
* Rethrow the exception currently being handled.
*
* When called from within a catch block, it will pass
* control to the next matching exception handler, if any.
* Otherwise, std::terminate will be called.
*
* ASAN can't handle sudden jumps in control flow very well. This
* function is marked as XRPL_NO_SANITIZE_ADDRESS to prevent it from
* triggering false positives, since it throws.
*/
[[noreturn]] XRPL_NO_SANITIZE_ADDRESS inline void
rethrow()
{
@@ -56,7 +59,9 @@ Throw(Args&&... args)
throw std::move(e);
}
/** Called when faulty logic causes a broken invariant. */
/**
* Called when faulty logic causes a broken invariant.
*/
[[noreturn]] void
logicError(std::string const& how) noexcept;

View File

@@ -39,33 +39,33 @@ makeSeedPair() noexcept
/**
* Seed functor once per construction
A std compatible hash adapter that resists adversarial inputs.
For this to work, T must implement in its own namespace:
@code
template <class Hasher>
void
hash_append (Hasher& h, T const& t) noexcept
{
// hash_append each base and member that should
// participate in forming the hash
using beast::hash_append;
hash_append (h, static_cast<T::base1 const&>(t));
hash_append (h, static_cast<T::base2 const&>(t));
// ...
hash_append (h, t.member1);
hash_append (h, t.member2);
// ...
}
@endcode
Do not use any version of Murmur or CityHash for the Hasher
template parameter (the hashing algorithm). For details
see https://131002.net/siphash/#at
*/
*
* A std compatible hash adapter that resists adversarial inputs.
* For this to work, T must implement in its own namespace:
*
* @code
*
* template <class Hasher>
* void
* hash_append (Hasher& h, T const& t) noexcept
* {
* // hash_append each base and member that should
* // participate in forming the hash
* using beast::hash_append;
* hash_append (h, static_cast<T::base1 const&>(t));
* hash_append (h, static_cast<T::base2 const&>(t));
* // ...
* hash_append (h, t.member1);
* hash_append (h, t.member2);
* // ...
* }
*
* @endcode
*
* Do not use any version of Murmur or CityHash for the Hasher
* template parameter (the hashing algorithm). For details
* see https://131002.net/siphash/#at
*/
template <class HashAlgorithm = beast::Xxhasher>
class HardenedHash

View File

@@ -7,11 +7,15 @@
namespace xrpl {
/** Create a self-signed SSL context that allows anonymous Diffie Hellman. */
/**
* Create a self-signed SSL context that allows anonymous Diffie Hellman.
*/
std::shared_ptr<boost::asio::ssl::context>
makeSslContext(std::string const& cipherList);
/** Create an authenticated SSL context using the specified files. */
/**
* Create an authenticated SSL context using the specified files.
*/
std::shared_ptr<boost::asio::ssl::context>
makeSslContextAuthed(
std::string const& keyFile,

View File

@@ -7,16 +7,16 @@
namespace xrpl {
constexpr auto kMuldivMax = std::numeric_limits<std::uint64_t>::max();
/** Return value*mul/div accurately.
Computes the result of the multiplication and division in
a single step, avoiding overflow and retaining precision.
Throws:
None
Returns:
`std::optional`:
`std::nullopt` if the calculation overflows. Otherwise, `value * mul
/ div`.
*/
/**
* Return value*mul/div accurately.
*
* Computes the result of the multiplication and division in
* a single step, avoiding overflow and retaining precision.
*
* @throws None
* @return `std::nullopt` if the calculation overflows. Otherwise,
* `value * mul / div`.
*/
std::optional<std::uint64_t>
mulDiv(std::uint64_t value, std::uint64_t mul, std::uint64_t div);

View File

@@ -33,16 +33,17 @@ template <class Engine, class Result = typename Engine::result_type>
using is_engine = std::is_invocable_r<Result, Engine>;
} // namespace detail
/** Return the default random engine.
This engine is guaranteed to be deterministic, but by
default will be randomly seeded. It is NOT cryptographically
secure and MUST NOT be used to generate randomness that
will be used for keys, secure cookies, IVs, padding, etc.
Each thread gets its own instance of the engine which
will be randomly seeded.
*/
/**
* Return the default random engine.
*
* This engine is guaranteed to be deterministic, but by
* default will be randomly seeded. It is NOT cryptographically
* secure and MUST NOT be used to generate randomness that
* will be used for keys, secure cookies, IVs, padding, etc.
*
* Each thread gets its own instance of the engine which
* will be randomly seeded.
*/
inline beast::xor_shift_engine&
defaultPrng()
{
@@ -70,25 +71,26 @@ defaultPrng()
return kEngine;
}
/** Return a uniformly distributed random integer.
@param min The smallest value to return. If not specified
the value defaults to 0.
@param max The largest value to return. If not specified
the value defaults to the largest value that
can be represented.
The randomness is generated by the specified engine (or
the default engine if one is not specified). The result
is cryptographically secure only when the engine passed
into the function is cryptographically secure.
@note The range is always a closed interval, so calling
rand_int(-5, 15) can return any integer in the
closed interval [-5, 15]; similarly, calling
rand_int(7) can return any integer in the closed
interval [0, 7].
*/
/**
* Return a uniformly distributed random integer.
*
* @param min The smallest value to return. If not specified
* the value defaults to 0.
* @param max The largest value to return. If not specified
* the value defaults to the largest value that
* can be represented.
*
* The randomness is generated by the specified engine (or
* the default engine if one is not specified). The result
* is cryptographically secure only when the engine passed
* into the function is cryptographically secure.
*
* @note The range is always a closed interval, so calling
* rand_int(-5, 15) can return any integer in the
* closed interval [-5, 15]; similarly, calling
* rand_int(7) can return any integer in the closed
* interval [0, 7].
*/
/** @{ */
template <class Engine, class Integral>
Integral
@@ -144,7 +146,9 @@ randInt()
}
/** @} */
/** Return a random byte */
/**
* Return a random byte
*/
/** @{ */
template <class Byte, class Engine>
Byte
@@ -166,7 +170,9 @@ randByte()
}
/** @} */
/** Return a random boolean value */
/**
* Return a random boolean value
*/
/** @{ */
template <class Engine>
inline bool

View File

@@ -156,41 +156,41 @@ template <class EF>
ScopeSuccess(EF) -> ScopeSuccess<EF>;
/**
Automatically unlocks and re-locks a unique_lock object.
This is the reverse of a std::unique_lock object - instead of locking the
mutex for the lifetime of this object, it unlocks it.
Make sure you don't try to unlock mutexes that aren't actually locked!
This is essentially a less-versatile boost::reverse_lock.
e.g. @code
std::mutex mut;
for (;;)
{
std::unique_lock myScopedLock{mut};
// mut is now locked
... do some stuff with it locked ..
while (xyz)
{
... do some stuff with it locked ..
scope_unlock unlocker{myScopedLock};
// mut is now unlocked for the remainder of this block,
// and re-locked at the end.
...do some stuff with it unlocked ...
} // mut gets locked here.
} // mut gets unlocked here
@endcode
*/
* Automatically unlocks and re-locks a unique_lock object.
*
* This is the reverse of a std::unique_lock object - instead of locking the
* mutex for the lifetime of this object, it unlocks it.
*
* Make sure you don't try to unlock mutexes that aren't actually locked!
*
* This is essentially a less-versatile boost::reverse_lock.
*
* e.g. @code
*
* std::mutex mut;
*
* for (;;)
* {
* std::unique_lock myScopedLock{mut};
* // mut is now locked
*
* ... do some stuff with it locked ..
*
* while (xyz)
* {
* ... do some stuff with it locked ..
*
* scope_unlock unlocker{myScopedLock};
*
* // mut is now unlocked for the remainder of this block,
* // and re-locked at the end.
*
* ...do some stuff with it unlocked ...
* } // mut gets locked here.
*
* } // mut gets unlocked here
* @endcode
*/
template <class Mutex>
class ScopeUnlock

View File

@@ -15,15 +15,16 @@
namespace xrpl {
namespace detail {
/** Inform the processor that we are in a tight spin-wait loop.
Spinlocks caught in tight loops can result in the processor's pipeline
filling up with comparison operations, resulting in a misprediction at
the time the lock is finally acquired, necessitating pipeline flushing
which is ridiculously expensive and results in very high latency.
This function instructs the processor to "pause" for some architecture
specific amount of time, to prevent this.
/**
* Inform the processor that we are in a tight spin-wait loop.
*
* Spinlocks caught in tight loops can result in the processor's pipeline
* filling up with comparison operations, resulting in a misprediction at
* the time the lock is finally acquired, necessitating pipeline flushing
* which is ridiculously expensive and results in very high latency.
*
* This function instructs the processor to "pause" for some architecture
* specific amount of time, to prevent this.
*/
inline void
spinPause() noexcept
@@ -38,37 +39,39 @@ spinPause() noexcept
} // namespace detail
/** @{ */
/** Classes to handle arrays of spinlocks packed into a single atomic integer:
Packed spinlocks allow for tremendously space-efficient lock-sharding
but they come at a cost.
First, the implementation is necessarily low-level and uses advanced
features like memory ordering and highly platform-specific tricks to
maximize performance. This imposes a significant and ongoing cost to
developers.
Second, and perhaps most important, is that the packing of multiple
locks into a single integer which, albeit space-efficient, also has
performance implications stemming from data dependencies, increased
cache-coherency traffic between processors and heavier loads on the
processor's load/store units.
To be sure, these locks can have advantages but they are definitely
not general purpose locks and should not be thought of or used that
way. The use cases for them are likely few and far between; without
a compelling reason to use them, backed by profiling data, it might
be best to use one of the standard locking primitives instead. Note
that in most common platforms, `std::mutex` is so heavily optimized
that it can, usually, outperform spinlocks.
@tparam T An unsigned integral type (e.g. std::uint16_t)
/**
* Classes to handle arrays of spinlocks packed into a single atomic integer:
*
* Packed spinlocks allow for tremendously space-efficient lock-sharding
* but they come at a cost.
*
* First, the implementation is necessarily low-level and uses advanced
* features like memory ordering and highly platform-specific tricks to
* maximize performance. This imposes a significant and ongoing cost to
* developers.
*
* Second, and perhaps most important, is that the packing of multiple
* locks into a single integer which, albeit space-efficient, also has
* performance implications stemming from data dependencies, increased
* cache-coherency traffic between processors and heavier loads on the
* processor's load/store units.
*
* To be sure, these locks can have advantages but they are definitely
* not general purpose locks and should not be thought of or used that
* way. The use cases for them are likely few and far between; without
* a compelling reason to use them, backed by profiling data, it might
* be best to use one of the standard locking primitives instead. Note
* that in most common platforms, `std::mutex` is so heavily optimized
* that it can, usually, outperform spinlocks.
*
* @tparam T An unsigned integral type (e.g. std::uint16_t)
*/
/** A class that grabs a single packed spinlock from an atomic integer.
This class meets the requirements of Lockable:
https://en.cppreference.com/w/cpp/named_req/Lockable
/**
* A class that grabs a single packed spinlock from an atomic integer.
*
* This class meets the requirements of Lockable:
* https://en.cppreference.com/w/cpp/named_req/Lockable
*/
template <class T>
class PackedSpinlock
@@ -91,13 +94,14 @@ public:
PackedSpinlock&
operator=(PackedSpinlock const&) = delete;
/** A single spinlock packed inside the specified atomic
@param lock The atomic integer inside which the spinlock is packed.
@param index The index of the spinlock this object acquires.
@note For performance reasons, you should strive to have `lock` be
on a cacheline by itself.
/**
* A single spinlock packed inside the specified atomic
*
* @param lock The atomic integer inside which the spinlock is packed.
* @param index The index of the spinlock this object acquires.
*
* @note For performance reasons, you should strive to have `lock` be
* on a cacheline by itself.
*/
PackedSpinlock(std::atomic<T>& lock, int index) : bits_(lock), mask_(static_cast<T>(1) << index)
{
@@ -133,17 +137,18 @@ public:
}
};
/** A spinlock implemented on top of an atomic integer.
@note Using `packed_spinlock` and `spinlock` against the same underlying
atomic integer can result in `spinlock` not being able to actually
acquire the lock during periods of high contention, because of how
the two locks operate: `spinlock` will spin trying to grab all the
bits at once, whereas any given `packed_spinlock` will only try to
grab one bit at a time. Caveat emptor.
This class meets the requirements of Lockable:
https://en.cppreference.com/w/cpp/named_req/Lockable
/**
* A spinlock implemented on top of an atomic integer.
*
* @note Using `packed_spinlock` and `spinlock` against the same underlying
* atomic integer can result in `spinlock` not being able to actually
* acquire the lock during periods of high contention, because of how
* the two locks operate: `spinlock` will spin trying to grab all the
* bits at once, whereas any given `packed_spinlock` will only try to
* grab one bit at a time. Caveat emptor.
*
* This class meets the requirements of Lockable:
* https://en.cppreference.com/w/cpp/named_req/Lockable
*/
template <class T>
class Spinlock
@@ -159,12 +164,13 @@ public:
Spinlock&
operator=(Spinlock const&) = delete;
/** Grabs the
@param lock The atomic integer to spin against.
@note For performance reasons, you should strive to have `lock` be
on a cacheline by itself.
/**
* Grabs the
*
* @param lock The atomic integer to spin against.
*
* @note For performance reasons, you should strive to have `lock` be
* on a cacheline by itself.
*/
Spinlock(std::atomic<T>& lock) : lock_(lock)
{

View File

@@ -12,17 +12,18 @@
namespace xrpl {
/** A type-safe wrap around standard integral types
The tag is used to implement type safety, catching mismatched types at
compile time. Multiple instantiations wrapping the same underlying integral
type are distinct types (distinguished by tag) and will not interoperate. A
tagged_integer supports all the usual assignment, arithmetic, comparison and
shifting operations defined for the underlying type
The tag is not meant as a unit, which would require restricting the set of
allowed arithmetic operations.
*/
/**
* A type-safe wrap around standard integral types
*
* The tag is used to implement type safety, catching mismatched types at
* compile time. Multiple instantiations wrapping the same underlying integral
* type are distinct types (distinguished by tag) and will not interoperate. A
* tagged_integer supports all the usual assignment, arithmetic, comparison and
* shifting operations defined for the underlying type
*
* The tag is not meant as a unit, which would require restricting the set of
* allowed arithmetic operations.
*/
template <class Int, class Tag>
class TaggedInteger : boost::totally_ordered<
TaggedInteger<Int, Tag>,

View File

@@ -14,7 +14,9 @@
namespace beast {
/** Measures handler latency on an io_context queue. */
/**
* Measures handler latency on an io_context queue.
*/
template <class Clock>
class IOLatencyProbe
{
@@ -42,7 +44,9 @@ public:
cancel(lock, true);
}
/** Return the io_context associated with the latency probe. */
/**
* Return the io_context associated with the latency probe.
*/
/** @{ */
boost::asio::io_context&
getIoContext()
@@ -57,9 +61,10 @@ public:
}
/** @} */
/** Cancel all pending i/o.
Any handlers which have already been queued will still be called.
*/
/**
* Cancel all pending i/o.
* Any handlers which have already been queued will still be called.
*/
/** @{ */
void
cancel()
@@ -76,10 +81,11 @@ public:
}
/** @} */
/** Measure one sample of i/o latency.
Handler will be called with this signature:
void Handler (Duration d);
*/
/**
* Measure one sample of i/o latency.
* Handler will be called with this signature:
* void Handler (Duration d);
*/
template <class Handler>
void
sampleOne(Handler&& handler)
@@ -91,10 +97,11 @@ public:
ios_, SampleOp<Handler>(std::forward<Handler>(handler), Clock::now(), false, this));
}
/** Initiate continuous i/o latency sampling.
Handler will be called with this signature:
void Handler (std::chrono::milliseconds);
*/
/**
* Initiate continuous i/o latency sampling.
* Handler will be called with this signature:
* void Handler (std::chrono::milliseconds);
*/
template <class Handler>
void
sample(Handler&& handler)

View File

@@ -2,34 +2,35 @@
namespace beast {
/** Abstract interface to a clock.
This makes now() a member function instead of a static member, so
an instance of the class can be dependency injected, facilitating
unit tests where time may be controlled.
An abstract_clock inherits all the nested types of the Clock
template parameter.
Example:
@code
struct Implementation
{
using clock_type = abstract_clock <std::chrono::steady_clock>;
clock_type& clock_;
explicit Implementation (clock_type& clock)
: clock_(clock)
{
}
};
@endcode
@tparam Clock A type meeting these requirements:
http://en.cppreference.com/w/cpp/concept/Clock
*/
/**
* Abstract interface to a clock.
*
* This makes now() a member function instead of a static member, so
* an instance of the class can be dependency injected, facilitating
* unit tests where time may be controlled.
*
* An abstract_clock inherits all the nested types of the Clock
* template parameter.
*
* Example:
*
* @code
*
* struct Implementation
* {
* using clock_type = abstract_clock <std::chrono::steady_clock>;
* clock_type& clock_;
* explicit Implementation (clock_type& clock)
* : clock_(clock)
* {
* }
* };
*
* @endcode
*
* @tparam Clock A type meeting these requirements:
* http://en.cppreference.com/w/cpp/concept/Clock
*/
template <class Clock>
class AbstractClock
{
@@ -46,7 +47,9 @@ public:
AbstractClock() = default;
AbstractClock(AbstractClock const&) = default;
/** Returns the current time. */
/**
* Returns the current time.
*/
[[nodiscard]] virtual time_point
now() const = 0;
};
@@ -74,11 +77,12 @@ struct AbstractClockWrapper : public AbstractClock<Facade>
//------------------------------------------------------------------------------
/** Returns a global instance of an abstract clock.
@tparam Facade A type meeting these requirements:
http://en.cppreference.com/w/cpp/concept/Clock
@tparam Clock The actual concrete clock to use.
*/
/**
* Returns a global instance of an abstract clock.
* @tparam Facade A type meeting these requirements:
* http://en.cppreference.com/w/cpp/concept/Clock
* @tparam Clock The actual concrete clock to use.
*/
template <class Facade, class Clock = Facade>
AbstractClock<Facade>&
getAbstractClock()

View File

@@ -4,15 +4,16 @@
namespace beast {
/** A clock whose minimum resolution is one second.
The purpose of this class is to optimize the performance of the now()
member function call. It uses a dedicated thread that wakes up at least
once per second to sample the requested trivial clock.
@tparam Clock A type meeting these requirements:
http://en.cppreference.com/w/cpp/concept/Clock
*/
/**
* A clock whose minimum resolution is one second.
*
* The purpose of this class is to optimize the performance of the now()
* member function call. It uses a dedicated thread that wakes up at least
* once per second to sample the requested trivial clock.
*
* @tparam Clock A type meeting these requirements:
* http://en.cppreference.com/w/cpp/concept/Clock
*/
class BasicSecondsClock
{
public:

View File

@@ -7,15 +7,16 @@
namespace beast {
/** Manual clock implementation.
This concrete class implements the @ref abstract_clock interface and
allows the time to be advanced manually, mainly for the purpose of
providing a clock in unit tests.
@tparam Clock A type meeting these requirements:
http://en.cppreference.com/w/cpp/concept/Clock
*/
/**
* Manual clock implementation.
*
* This concrete class implements the @ref abstract_clock interface and
* allows the time to be advanced manually, mainly for the purpose of
* providing a clock in unit tests.
*
* @tparam Clock A type meeting these requirements:
* http://en.cppreference.com/w/cpp/concept/Clock
*/
template <class Clock>
class ManualClock : public AbstractClock<Clock>
{
@@ -38,7 +39,9 @@ public:
return now_;
}
/** Set the current time of the manual clock. */
/**
* Set the current time of the manual clock.
*/
void
set(time_point const& when)
{
@@ -48,7 +51,9 @@ public:
now_ = when;
}
/** Convenience for setting the time in seconds from epoch. */
/**
* Convenience for setting the time in seconds from epoch.
*/
template <class Integer>
void
set(Integer secondsFromEpoch)
@@ -56,7 +61,9 @@ public:
set(time_point(duration(std::chrono::seconds(secondsFromEpoch))));
}
/** Advance the clock by a duration. */
/**
* Advance the clock by a duration.
*/
template <class Rep, class Period>
void
advance(std::chrono::duration<Rep, Period> const& elapsed)
@@ -67,7 +74,9 @@ public:
now_ += elapsed;
}
/** Convenience for advancing the clock by one second. */
/**
* Convenience for advancing the clock by one second.
*/
ManualClock&
operator++()
{

View File

@@ -7,7 +7,9 @@
namespace beast {
/** Expire aged container items past the specified age. */
/**
* Expire aged container items past the specified age.
*/
template <class AgedContainer, class Rep, class Period>
std::size_t
expire(AgedContainer& c, std::chrono::duration<Rep, Period> const& age)

View File

@@ -39,22 +39,23 @@ struct IsBoostReverseIterator<boost::intrusive::reverse_iterator<It>> : std::tru
explicit IsBoostReverseIterator() = default;
};
/** Associative container where each element is also indexed by time.
This container mirrors the interface of the standard library ordered
associative containers, with the addition that each element is associated
with a `when` `time_point` which is obtained from the value of the clock's
`now`. The function `touch` updates the time for an element to the current
time as reported by the clock.
An extra set of iterator types and member functions are provided in the
`chronological` memberspace that allow traversal in temporal or reverse
temporal order. This container is useful as a building block for caches
whose items expire after a certain amount of time. The chronological
iterators allow for fully customizable expiration strategies.
@see aged_set, aged_multiset, aged_map, aged_multimap
*/
/**
* Associative container where each element is also indexed by time.
*
* This container mirrors the interface of the standard library ordered
* associative containers, with the addition that each element is associated
* with a `when` `time_point` which is obtained from the value of the clock's
* `now`. The function `touch` updates the time for an element to the current
* time as reported by the clock.
*
* An extra set of iterator types and member functions are provided in the
* `chronological` memberspace that allow traversal in temporal or reverse
* temporal order. This container is useful as a building block for caches
* whose items expire after a certain amount of time. The chronological
* iterators allow for fully customizable expiration strategies.
*
* @see aged_set, aged_multiset, aged_map, aged_multimap
*/
template <
bool IsMulti,
bool IsMap,
@@ -1795,7 +1796,9 @@ swap(
lhs.swap(rhs);
}
/** Expire aged container items past the specified age. */
/**
* Expire aged container items past the specified age.
*/
template <
bool IsMulti,
bool IsMap,

View File

@@ -43,23 +43,24 @@ TODO
namespace beast {
namespace detail {
/** Associative container where each element is also indexed by time.
This container mirrors the interface of the standard library unordered
associative containers, with the addition that each element is associated
with a `when` `time_point` which is obtained from the value of the clock's
`now`. The function `touch` updates the time for an element to the current
time as reported by the clock.
An extra set of iterator types and member functions are provided in the
`chronological` memberspace that allow traversal in temporal or reverse
temporal order. This container is useful as a building block for caches
whose items expire after a certain amount of time. The chronological
iterators allow for fully customizable expiration strategies.
@see aged_unordered_set, aged_unordered_multiset
@see aged_unordered_map, aged_unordered_multimap
*/
/**
* Associative container where each element is also indexed by time.
*
* This container mirrors the interface of the standard library unordered
* associative containers, with the addition that each element is associated
* with a `when` `time_point` which is obtained from the value of the clock's
* `now`. The function `touch` updates the time for an element to the current
* time as reported by the clock.
*
* An extra set of iterator types and member functions are provided in the
* `chronological` memberspace that allow traversal in temporal or reverse
* temporal order. This container is useful as a building block for caches
* whose items expire after a certain amount of time. The chronological
* iterators allow for fully customizable expiration strategies.
*
* @see aged_unordered_set, aged_unordered_multiset
* @see aged_unordered_map, aged_unordered_multimap
*/
template <
bool IsMulti,
bool IsMap,
@@ -2709,7 +2710,9 @@ swap(
lhs.swap(rhs);
}
/** Expire aged container items past the specified age. */
/**
* Expire aged container items past the specified age.
*/
template <
bool IsMulti,
bool IsMap,

View File

@@ -12,9 +12,10 @@
namespace beast {
/** Changes the name of the caller thread.
Different OSes may place different length or content limits on this name.
*/
/**
* Changes the name of the caller thread.
* Different OSes may place different length or content limits on this name.
*/
void
setCurrentThreadName(std::string_view newThreadName);
@@ -24,13 +25,14 @@ setCurrentThreadName(std::string_view newThreadName);
// Maximum number of characters is therefore 15.
constexpr std::size_t kMaxThreadNameLength = 15;
/** Sets the name of the caller thread with compile-time size checking.
@tparam N The size of the string literal including null terminator
@param newThreadName A string literal to set as the thread name
This template overload enforces that thread names are at most 16 characters
(including null terminator) at compile time, matching Linux's limit.
*/
/**
* Sets the name of the caller thread with compile-time size checking.
* @tparam N The size of the string literal including null terminator
* @param newThreadName A string literal to set as the thread name
*
* This template overload enforces that thread names are at most 16 characters
* (including null terminator) at compile time, matching Linux's limit.
*/
template <std::size_t N>
void
setCurrentThreadName(char const (&newThreadName)[N])
@@ -41,14 +43,15 @@ setCurrentThreadName(char const (&newThreadName)[N])
}
#endif
/** Returns the name of the caller thread.
The name returned is the name as set by a call to setCurrentThreadName().
If the thread name is set by an external force, then that name change
will not be reported.
If no name has ever been set, then the empty string is returned.
*/
/**
* Returns the name of the caller thread.
*
* The name returned is the name as set by a call to setCurrentThreadName().
* If the thread name is set by an external force, then that name change
* will not be reported.
*
* If no name has ever been set, then the empty string is returned.
*/
std::string
getCurrentThreadName();

View File

@@ -163,17 +163,19 @@ struct LexicalCast<Out, char*>
//------------------------------------------------------------------------------
/** Thrown when a conversion is not possible with LexicalCast.
Only used in the throw variants of lexicalCast.
*/
/**
* Thrown when a conversion is not possible with LexicalCast.
* Only used in the throw variants of lexicalCast.
*/
struct BadLexicalCast : public std::bad_cast
{
explicit BadLexicalCast() = default;
};
/** Intelligently convert from one type to another.
@return `false` if there was a parsing or range error
*/
/**
* Intelligently convert from one type to another.
* @return `false` if there was a parsing or range error
*/
template <class Out, class In>
bool
lexicalCastChecked(Out& out, In in)
@@ -181,12 +183,13 @@ lexicalCastChecked(Out& out, In in)
return detail::LexicalCast<Out, In>()(out, in);
}
/** Convert from one type to another, throw on error
An exception of type BadLexicalCast is thrown if the conversion fails.
@return The new type.
*/
/**
* Convert from one type to another, throw on error
*
* An exception of type BadLexicalCast is thrown if the conversion fails.
*
* @return The new type.
*/
template <class Out, class In>
Out
lexicalCastThrow(In in)
@@ -197,11 +200,12 @@ lexicalCastThrow(In in)
throw BadLexicalCast();
}
/** Convert from one type to another.
@param defaultValue The value returned if parsing fails
@return The new type.
*/
/**
* Convert from one type to another.
*
* @param defaultValue The value returned if parsing fails
* @return The new type.
*/
template <class Out, class In>
Out
lexicalCast(In in, Out defaultValue = Out())

View File

@@ -11,7 +11,9 @@ class List;
namespace detail {
/** Copy `const` attribute from T to U if present. */
/**
* Copy `const` attribute from T to U if present.
*/
/** @{ */
template <typename T, typename U>
struct CopyConst
@@ -153,110 +155,111 @@ private:
} // namespace detail
/** Intrusive doubly linked list.
This intrusive List is a container similar in operation to std::list in the
Standard Template Library (STL). Like all @ref intrusive containers, List
requires you to first derive your class from List<>::Node:
@code
struct Object : List <Object>::Node
{
explicit Object (int value) : value_ (value)
{
}
int value_;
};
@endcode
Now we define the list, and add a couple of items.
@code
List <Object> list;
list.push_back (* (new Object (1)));
list.push_back (* (new Object (2)));
@endcode
For compatibility with the standard containers, push_back() expects a
reference to the object. Unlike the standard container, however, push_back()
places the actual object in the list and not a copy-constructed duplicate.
Iterating over the list follows the same idiom as the STL:
@code
for (List <Object>::iterator iter = list.begin(); iter != list.end; ++iter)
std::cout << iter->value_;
@endcode
You can even use BOOST_FOREACH, or range based for loops:
@code
BOOST_FOREACH (Object& object, list) // boost only
std::cout << object.value_;
for (Object& object : list) // C++11 only
std::cout << object.value_;
@endcode
Because List is mostly STL compliant, it can be passed into STL algorithms:
e.g. `std::for_each()` or `std::find_first_of()`.
In general, objects placed into a List should be dynamically allocated
although this cannot be enforced at compile time. Since the caller provides
the storage for the object, the caller is also responsible for deleting the
object. An object still exists after being removed from a List, until the
caller deletes it. This means an element can be moved from one List to
another with practically no overhead.
Unlike the standard containers, an object may only exist in one list at a
time, unless special preparations are made. The Tag template parameter is
used to distinguish between different list types for the same object,
allowing the object to exist in more than one list simultaneously.
For example, consider an actor system where a global list of actors is
maintained, so that they can each be periodically receive processing
time. We wish to also maintain a list of the subset of actors that require
a domain-dependent update. To achieve this, we declare two tags, the
associated list types, and the list element thusly:
@code
struct Actor; // Forward declaration required
struct ProcessTag { };
struct UpdateTag { };
using ProcessList = List <Actor, ProcessTag>;
using UpdateList = List <Actor, UpdateTag>;
// Derive from both node types so we can be in each list at once.
//
struct Actor : ProcessList::Node, UpdateList::Node
{
bool process (); // returns true if we need an update
void update ();
};
@endcode
@tparam T The base type of element which the list will store
pointers to.
@tparam Tag An optional unique type name used to distinguish lists and
nodes, when the object can exist in multiple lists simultaneously.
@ingroup beast_core intrusive
*/
/**
* Intrusive doubly linked list.
*
* This intrusive List is a container similar in operation to std::list in the
* Standard Template Library (STL). Like all @ref intrusive containers, List
* requires you to first derive your class from List<>::Node:
*
* @code
*
* struct Object : List <Object>::Node
* {
* explicit Object (int value) : value_ (value)
* {
* }
*
* int value_;
* };
*
* @endcode
*
* Now we define the list, and add a couple of items.
*
* @code
*
* List <Object> list;
*
* list.push_back (* (new Object (1)));
* list.push_back (* (new Object (2)));
*
* @endcode
*
* For compatibility with the standard containers, push_back() expects a
* reference to the object. Unlike the standard container, however, push_back()
* places the actual object in the list and not a copy-constructed duplicate.
*
* Iterating over the list follows the same idiom as the STL:
*
* @code
*
* for (List <Object>::iterator iter = list.begin(); iter != list.end; ++iter)
* std::cout << iter->value_;
*
* @endcode
*
* You can even use BOOST_FOREACH, or range based for loops:
*
* @code
*
* BOOST_FOREACH (Object& object, list) // boost only
* std::cout << object.value_;
*
* for (Object& object : list) // C++11 only
* std::cout << object.value_;
*
* @endcode
*
* Because List is mostly STL compliant, it can be passed into STL algorithms:
* e.g. `std::for_each()` or `std::find_first_of()`.
*
* In general, objects placed into a List should be dynamically allocated
* although this cannot be enforced at compile time. Since the caller provides
* the storage for the object, the caller is also responsible for deleting the
* object. An object still exists after being removed from a List, until the
* caller deletes it. This means an element can be moved from one List to
* another with practically no overhead.
*
* Unlike the standard containers, an object may only exist in one list at a
* time, unless special preparations are made. The Tag template parameter is
* used to distinguish between different list types for the same object,
* allowing the object to exist in more than one list simultaneously.
*
* For example, consider an actor system where a global list of actors is
* maintained, so that they can each be periodically receive processing
* time. We wish to also maintain a list of the subset of actors that require
* a domain-dependent update. To achieve this, we declare two tags, the
* associated list types, and the list element thusly:
*
* @code
*
* struct Actor; // Forward declaration required
*
* struct ProcessTag { };
* struct UpdateTag { };
*
* using ProcessList = List <Actor, ProcessTag>;
* using UpdateList = List <Actor, UpdateTag>;
*
* // Derive from both node types so we can be in each list at once.
* //
* struct Actor : ProcessList::Node, UpdateList::Node
* {
* bool process (); // returns true if we need an update
* void update ();
* };
*
* @endcode
*
* @tparam T The base type of element which the list will store
* pointers to.
*
* @tparam Tag An optional unique type name used to distinguish lists and
* nodes, when the object can exist in multiple lists simultaneously.
*
* @ingroup beast_core intrusive
*/
template <typename T, typename Tag = void>
class List
{
@@ -274,7 +277,9 @@ public:
using iterator = detail::ListIterator<Node>;
using const_iterator = detail::ListIterator<Node const>;
/** Create an empty list. */
/**
* Create an empty list.
*/
List()
{
head_.prev_ = nullptr; // identifies the head
@@ -286,119 +291,133 @@ public:
List&
operator=(List const&) = delete;
/** Determine if the list is empty.
@return `true` if the list is empty.
*/
/**
* Determine if the list is empty.
* @return `true` if the list is empty.
*/
[[nodiscard]] bool
empty() const noexcept
{
return size() == 0;
}
/** Returns the number of elements in the list. */
/**
* Returns the number of elements in the list.
*/
[[nodiscard]] size_type
size() const noexcept
{
return size_;
}
/** Obtain a reference to the first element.
@invariant The list may not be empty.
@return A reference to the first element.
*/
/**
* Obtain a reference to the first element.
* @invariant The list may not be empty.
* @return A reference to the first element.
*/
reference
front() noexcept
{
return element_from(head_.next_);
}
/** Obtain a const reference to the first element.
@invariant The list may not be empty.
@return A const reference to the first element.
*/
/**
* Obtain a const reference to the first element.
* @invariant The list may not be empty.
* @return A const reference to the first element.
*/
[[nodiscard]] const_reference
front() const noexcept
{
return element_from(head_.next_);
}
/** Obtain a reference to the last element.
@invariant The list may not be empty.
@return A reference to the last element.
*/
/**
* Obtain a reference to the last element.
* @invariant The list may not be empty.
* @return A reference to the last element.
*/
reference
back() noexcept
{
return element_from(tail_.prev_);
}
/** Obtain a const reference to the last element.
@invariant The list may not be empty.
@return A const reference to the last element.
*/
/**
* Obtain a const reference to the last element.
* @invariant The list may not be empty.
* @return A const reference to the last element.
*/
[[nodiscard]] const_reference
back() const noexcept
{
return element_from(tail_.prev_);
}
/** Obtain an iterator to the beginning of the list.
@return An iterator pointing to the beginning of the list.
*/
/**
* Obtain an iterator to the beginning of the list.
* @return An iterator pointing to the beginning of the list.
*/
iterator
begin() noexcept
{
return iterator(head_.next_);
}
/** Obtain a const iterator to the beginning of the list.
@return A const iterator pointing to the beginning of the list.
*/
/**
* Obtain a const iterator to the beginning of the list.
* @return A const iterator pointing to the beginning of the list.
*/
[[nodiscard]] const_iterator
begin() const noexcept
{
return const_iterator(head_.next_);
}
/** Obtain a const iterator to the beginning of the list.
@return A const iterator pointing to the beginning of the list.
*/
/**
* Obtain a const iterator to the beginning of the list.
* @return A const iterator pointing to the beginning of the list.
*/
[[nodiscard]] const_iterator
cbegin() const noexcept
{
return const_iterator(head_.next_);
}
/** Obtain a iterator to the end of the list.
@return An iterator pointing to the end of the list.
*/
/**
* Obtain a iterator to the end of the list.
* @return An iterator pointing to the end of the list.
*/
iterator
end() noexcept
{
return iterator(&tail_);
}
/** Obtain a const iterator to the end of the list.
@return A constiterator pointing to the end of the list.
*/
/**
* Obtain a const iterator to the end of the list.
* @return A constiterator pointing to the end of the list.
*/
[[nodiscard]] const_iterator
end() const noexcept
{
return const_iterator(&tail_);
}
/** Obtain a const iterator to the end of the list
@return A constiterator pointing to the end of the list.
*/
/**
* Obtain a const iterator to the end of the list
* @return A constiterator pointing to the end of the list.
*/
[[nodiscard]] const_iterator
cend() const noexcept
{
return const_iterator(&tail_);
}
/** Clear the list.
@note This does not free the elements.
*/
/**
* Clear the list.
* @note This does not free the elements.
*/
void
clear() noexcept
{
@@ -407,12 +426,13 @@ public:
size_ = 0;
}
/** Insert an element.
@invariant The element must not already be in the list.
@param pos The location to insert after.
@param element The element to insert.
@return An iterator pointing to the newly inserted element.
*/
/**
* Insert an element.
* @invariant The element must not already be in the list.
* @param pos The location to insert after.
* @param element The element to insert.
* @return An iterator pointing to the newly inserted element.
*/
iterator
insert(iterator pos, T& element) noexcept
{
@@ -425,11 +445,12 @@ public:
return iterator(node);
}
/** Insert another list into this one.
The other list is cleared.
@param pos The location to insert after.
@param other The list to insert.
*/
/**
* Insert another list into this one.
* The other list is cleared.
* @param pos The location to insert after.
* @param other The list to insert.
*/
void
insert(iterator pos, List& other) noexcept
{
@@ -445,11 +466,12 @@ public:
}
}
/** Remove an element.
@invariant The element must exist in the list.
@param pos An iterator pointing to the element to remove.
@return An iterator pointing to the next element after the one removed.
*/
/**
* Remove an element.
* @invariant The element must exist in the list.
* @param pos An iterator pointing to the element to remove.
* @return An iterator pointing to the next element after the one removed.
*/
iterator
erase(iterator pos) noexcept
{
@@ -461,20 +483,22 @@ public:
return pos;
}
/** Insert an element at the beginning of the list.
@invariant The element must not exist in the list.
@param element The element to insert.
*/
/**
* Insert an element at the beginning of the list.
* @invariant The element must not exist in the list.
* @param element The element to insert.
*/
iterator
pushFront(T& element) noexcept
{
return insert(begin(), element);
}
/** Remove the element at the beginning of the list.
@invariant The list must not be empty.
@return A reference to the popped element.
*/
/**
* Remove the element at the beginning of the list.
* @invariant The list must not be empty.
* @return A reference to the popped element.
*/
T&
popFront() noexcept
{
@@ -483,20 +507,22 @@ public:
return element;
}
/** Append an element at the end of the list.
@invariant The element must not exist in the list.
@param element The element to append.
*/
/**
* Append an element at the end of the list.
* @invariant The element must not exist in the list.
* @param element The element to append.
*/
iterator
pushBack(T& element) noexcept
{
return insert(end(), element);
}
/** Remove the element at the end of the list.
@invariant The list must not be empty.
@return A reference to the popped element.
*/
/**
* Remove the element at the end of the list.
* @invariant The list must not be empty.
* @return A reference to the popped element.
*/
T&
popBack() noexcept
{
@@ -505,7 +531,9 @@ public:
return element;
}
/** Swap contents with another list. */
/**
* Swap contents with another list.
*/
void
swap(List& other) noexcept
{
@@ -515,42 +543,46 @@ public:
append(temp);
}
/** Insert another list at the beginning of this list.
The other list is cleared.
@param list The other list to insert.
*/
/**
* Insert another list at the beginning of this list.
* The other list is cleared.
* @param list The other list to insert.
*/
iterator
prepend(List& list) noexcept
{
return insert(begin(), list);
}
/** Append another list at the end of this list.
The other list is cleared.
@param list the other list to append.
*/
/**
* Append another list at the end of this list.
* The other list is cleared.
* @param list the other list to append.
*/
iterator
append(List& list) noexcept
{
return insert(end(), list);
}
/** Obtain an iterator from an element.
@invariant The element must exist in the list.
@param element The element to obtain an iterator for.
@return An iterator to the element.
*/
/**
* Obtain an iterator from an element.
* @invariant The element must exist in the list.
* @param element The element to obtain an iterator for.
* @return An iterator to the element.
*/
iterator
iteratorTo(T& element) const noexcept
{
return iterator(static_cast<Node*>(&element));
}
/** Obtain a const iterator from an element.
@invariant The element must exist in the list.
@param element The element to obtain an iterator for.
@return A const iterator to the element.
*/
/**
* Obtain a const iterator from an element.
* @invariant The element must exist in the list.
* @param element The element to obtain an iterator for.
* @return A const iterator to the element.
*/
[[nodiscard]] const_iterator
constIteratorTo(T const& element) const noexcept
{

View File

@@ -103,18 +103,19 @@ operator!=(
//------------------------------------------------------------------------------
/** Multiple Producer, Multiple Consumer (MPMC) intrusive stack.
This stack is implemented using the same intrusive interface as List.
All mutations are lock-free.
The caller is responsible for preventing the "ABA" problem:
http://en.wikipedia.org/wiki/ABA_problem
@param Tag A type name used to distinguish lists and nodes, for
putting objects in multiple lists. If this parameter is
omitted, the default tag is used.
*/
/**
* Multiple Producer, Multiple Consumer (MPMC) intrusive stack.
*
* This stack is implemented using the same intrusive interface as List.
* All mutations are lock-free.
*
* The caller is responsible for preventing the "ABA" problem:
* http://en.wikipedia.org/wiki/ABA_problem
*
* @param Tag A type name used to distinguish lists and nodes, for
* putting objects in multiple lists. If this parameter is
* omitted, the default tag is used.
*/
template <class Element, class Tag = void>
class LockFreeStack
{
@@ -162,24 +163,27 @@ public:
LockFreeStack&
operator=(LockFreeStack const&) = delete;
/** Returns true if the stack is empty. */
/**
* Returns true if the stack is empty.
*/
[[nodiscard]] bool
empty() const
{
return head_.load() == &end_;
}
/** Push a node onto the stack.
The caller is responsible for preventing the ABA problem.
This operation is lock-free.
Thread safety:
Safe to call from any thread.
@param node The node to push.
@return `true` if the stack was previously empty. If multiple threads
are attempting to push, only one will receive `true`.
*/
/**
* Push a node onto the stack.
* The caller is responsible for preventing the ABA problem.
* This operation is lock-free.
* Thread safety:
* Safe to call from any thread.
*
* @param node The node to push.
*
* @return `true` if the stack was previously empty. If multiple threads
* are attempting to push, only one will receive `true`.
*/
// VFALCO NOTE Fix this, shouldn't it be a reference like intrusive list?
bool
pushFront(Node* node)
@@ -195,15 +199,16 @@ public:
return first;
}
/** Pop an element off the stack.
The caller is responsible for preventing the ABA problem.
This operation is lock-free.
Thread safety:
Safe to call from any thread.
@return The element that was popped, or `nullptr` if the stack
was empty.
*/
/**
* Pop an element off the stack.
* The caller is responsible for preventing the ABA problem.
* This operation is lock-free.
* Thread safety:
* Safe to call from any thread.
*
* @return The element that was popped, or `nullptr` if the stack
* was empty.
*/
Element*
popFront()
{
@@ -219,12 +224,13 @@ public:
return static_cast<Element*>(node);
}
/** Return a forward iterator to the beginning or end of the stack.
Undefined behavior results if push_front or pop_front is called
while an iteration is in progress.
Thread safety:
Caller is responsible for synchronization.
*/
/**
* Return a forward iterator to the beginning or end of the stack.
* Undefined behavior results if push_front or pop_front is called
* while an iteration is in progress.
* Thread safety:
* Caller is responsible for synchronization.
*/
/** @{ */
iterator
begin()

View File

@@ -6,13 +6,14 @@
namespace beast {
/** A Semantic Version number.
Identifies the build of a particular version of software using
the Semantic Versioning Specification described here:
http://semver.org/
*/
/**
* A Semantic Version number.
*
* Identifies the build of a particular version of software using
* the Semantic Versioning Specification described here:
*
* http://semver.org/
*/
class SemanticVersion
{
public:
@@ -29,14 +30,17 @@ public:
SemanticVersion(std::string_view version);
/** Parse a semantic version string.
The parsing is as strict as possible.
@return `true` if the string was parsed.
*/
/**
* Parse a semantic version string.
* The parsing is as strict as possible.
* @return `true` if the string was parsed.
*/
bool
parse(std::string_view input);
/** Produce a string from semantic version components. */
/**
* Produce a string from semantic version components.
*/
[[nodiscard]] std::string
print() const;
@@ -52,9 +56,10 @@ public:
}
};
/** Compare two SemanticVersions against each other.
The comparison follows the rules as per the specification.
*/
/**
* Compare two SemanticVersions against each other.
* The comparison follows the rules as per the specification.
*/
int
compare(SemanticVersion const& lhs, SemanticVersion const& rhs);

View File

@@ -135,19 +135,20 @@ struct IsUniquelyRepresented<std::array<T, N>>
explicit IsUniquelyRepresented() = default;
};
/** Metafunction returning `true` if the type can be hashed in one call.
For `IsContiguouslyHashable<T>::value` to be true, then for every
combination of possible values of `T` held in `x` and `y`,
if `x == y`, then it must be true that `memcmp(&x, &y, sizeof(T))`
return 0; i.e. that `x` and `y` are represented by the same bit pattern.
For example: A two's complement `int` should be contiguously hashable.
Every bit pattern produces a unique value that does not compare equal to
any other bit pattern's value. A IEEE floating point should not be
contiguously hashable because -0. and 0. have different bit patterns,
though they compare equal.
*/
/**
* Metafunction returning `true` if the type can be hashed in one call.
*
* For `IsContiguouslyHashable<T>::value` to be true, then for every
* combination of possible values of `T` held in `x` and `y`,
* if `x == y`, then it must be true that `memcmp(&x, &y, sizeof(T))`
* return 0; i.e. that `x` and `y` are represented by the same bit pattern.
*
* For example: A two's complement `int` should be contiguously hashable.
* Every bit pattern produces a unique value that does not compare equal to
* any other bit pattern's value. A IEEE floating point should not be
* contiguously hashable because -0. and 0. have different bit patterns,
* though they compare equal.
*/
/** @{ */
template <class T, class HashAlgorithm>
struct IsContiguouslyHashable
@@ -172,29 +173,30 @@ struct IsContiguouslyHashable<T[N], HashAlgorithm>
//------------------------------------------------------------------------------
/** Logically concatenate input data to a `Hasher`.
Hasher requirements:
`X` is the type `Hasher`
`h` is a value of type `x`
`p` is a value convertible to `void const*`
`n` is a value of type `std::size_t`, greater than zero
Expression:
`h.append (p, n);`
Throws:
Never
Effect:
Adds the input data to the hasher state.
Expression:
`static_cast<std::size_t>(j)`
Throws:
Never
Effect:
Returns the resulting hash of all the input data.
*/
/**
* Logically concatenate input data to a `Hasher`.
*
* Hasher requirements:
*
* `X` is the type `Hasher`
* `h` is a value of type `x`
* `p` is a value convertible to `void const*`
* `n` is a value of type `std::size_t`, greater than zero
*
* Expression:
* `h.append (p, n);`
* Throws:
* Never
* Effect:
* Adds the input data to the hasher state.
*
* Expression:
* `static_cast<std::size_t>(j)`
* Throws:
* Never
* Effect:
* Returns the resulting hash of all the input data.
*/
/** @{ */
// scalars

View File

@@ -12,16 +12,17 @@
namespace beast::insight {
/** Interface for a manager that allows collection of metrics.
To export metrics from a class, pass and save a shared_ptr to this
interface in the class constructor. Create the metric objects
as desired (counters, events, gauges, meters, and an optional hook)
using the interface.
@see Counter, Event, Gauge, Hook, Meter
@see NullCollector, StatsDCollector
*/
/**
* Interface for a manager that allows collection of metrics.
*
* To export metrics from a class, pass and save a shared_ptr to this
* interface in the class constructor. Create the metric objects
* as desired (counters, events, gauges, meters, and an optional hook)
* using the interface.
*
* @see Counter, Event, Gauge, Hook, Meter
* @see NullCollector, StatsDCollector
*/
class Collector
{
public:
@@ -29,18 +30,19 @@ public:
virtual ~Collector() = 0;
/** Create a hook.
A hook is called at each collection interval, on an implementation
defined thread. This is a convenience facility for gathering metrics
in the polling style. The typical usage is to update all the metrics
of interest in the handler.
Handler will be called with this signature:
void handler (void)
@see Hook
*/
/**
* Create a hook.
*
* A hook is called at each collection interval, on an implementation
* defined thread. This is a convenience facility for gathering metrics
* in the polling style. The typical usage is to update all the metrics
* of interest in the handler.
*
* Handler will be called with this signature:
* void handler (void)
*
* @see Hook
*/
/** @{ */
template <class Handler>
Hook
@@ -53,9 +55,10 @@ public:
makeHook(HookImpl::HandlerType const& handler) = 0;
/** @} */
/** Create a counter with the specified name.
@see Counter
*/
/**
* Create a counter with the specified name.
* @see Counter
*/
/** @{ */
virtual Counter
makeCounter(std::string const& name) = 0;
@@ -69,9 +72,10 @@ public:
}
/** @} */
/** Create an event with the specified name.
@see Event
*/
/**
* Create an event with the specified name.
* @see Event
*/
/** @{ */
virtual Event
makeEvent(std::string const& name) = 0;
@@ -85,9 +89,10 @@ public:
}
/** @} */
/** Create a gauge with the specified name.
@see Gauge
*/
/**
* Create a gauge with the specified name.
* @see Gauge
*/
/** @{ */
virtual Gauge
makeGauge(std::string const& name) = 0;
@@ -101,9 +106,10 @@ public:
}
/** @} */
/** Create a meter with the specified name.
@see Meter
*/
/**
* Create a meter with the specified name.
* @see Meter
*/
/** @{ */
virtual Meter
makeMeter(std::string const& name) = 0;

View File

@@ -7,34 +7,39 @@
namespace beast::insight {
/** A metric for measuring an integral value.
A counter is a gauge calculated at the server. The owner of the counter
may increment and decrement the value by an amount.
This is a lightweight reference wrapper which is cheap to copy and assign.
When the last reference goes away, the metric is no longer collected.
*/
/**
* A metric for measuring an integral value.
*
* A counter is a gauge calculated at the server. The owner of the counter
* may increment and decrement the value by an amount.
*
* This is a lightweight reference wrapper which is cheap to copy and assign.
* When the last reference goes away, the metric is no longer collected.
*/
class Counter final
{
public:
using value_type = CounterImpl::value_type;
/** Create a null metric.
A null metric reports no information.
*/
/**
* Create a null metric.
* A null metric reports no information.
*/
Counter() = default;
/** Create the metric reference the specified implementation.
Normally this won't be called directly. Instead, call the appropriate
factory function in the Collector interface.
@see Collector.
*/
/**
* Create the metric reference the specified implementation.
* Normally this won't be called directly. Instead, call the appropriate
* factory function in the Collector interface.
* @see Collector.
*/
explicit Counter(std::shared_ptr<CounterImpl> impl) : impl_(std::move(impl))
{
}
/** Increment the counter. */
/**
* Increment the counter.
*/
/** @{ */
void
increment(value_type amount) const

View File

@@ -8,35 +8,40 @@
namespace beast::insight {
/** A metric for reporting event timing.
An event is an operation that has an associated millisecond time, or
other integral value. Because events happen at a specific moment, the
metric only supports a push-style interface.
This is a lightweight reference wrapper which is cheap to copy and assign.
When the last reference goes away, the metric is no longer collected.
*/
/**
* A metric for reporting event timing.
*
* An event is an operation that has an associated millisecond time, or
* other integral value. Because events happen at a specific moment, the
* metric only supports a push-style interface.
*
* This is a lightweight reference wrapper which is cheap to copy and assign.
* When the last reference goes away, the metric is no longer collected.
*/
class Event final
{
public:
using value_type = EventImpl::value_type;
/** Create a null metric.
A null metric reports no information.
*/
/**
* Create a null metric.
* A null metric reports no information.
*/
Event() = default;
/** Create the metric reference the specified implementation.
Normally this won't be called directly. Instead, call the appropriate
factory function in the Collector interface.
@see Collector.
*/
/**
* Create the metric reference the specified implementation.
* Normally this won't be called directly. Instead, call the appropriate
* factory function in the Collector interface.
* @see Collector.
*/
explicit Event(std::shared_ptr<EventImpl> impl) : impl_(std::move(impl))
{
}
/** Push an event notification. */
/**
* Push an event notification.
*/
template <class Rep, class Period>
void
notify(std::chrono::duration<Rep, Period> const& value) const

View File

@@ -7,40 +7,44 @@
namespace beast::insight {
/** A metric for measuring an integral value.
A gauge is an instantaneous measurement of a value, like the gas gauge
in a car. The caller directly sets the value, or adjusts it by a
specified amount. The value is kept in the client rather than the collector.
This is a lightweight reference wrapper which is cheap to copy and assign.
When the last reference goes away, the metric is no longer collected.
*/
/**
* A metric for measuring an integral value.
*
* A gauge is an instantaneous measurement of a value, like the gas gauge
* in a car. The caller directly sets the value, or adjusts it by a
* specified amount. The value is kept in the client rather than the collector.
*
* This is a lightweight reference wrapper which is cheap to copy and assign.
* When the last reference goes away, the metric is no longer collected.
*/
class Gauge final
{
public:
using value_type = GaugeImpl::value_type;
using difference_type = GaugeImpl::difference_type;
/** Create a null metric.
A null metric reports no information.
*/
/**
* Create a null metric.
* A null metric reports no information.
*/
Gauge() = default;
/** Create the metric reference the specified implementation.
Normally this won't be called directly. Instead, call the appropriate
factory function in the Collector interface.
@see Collector.
*/
/**
* Create the metric reference the specified implementation.
* Normally this won't be called directly. Instead, call the appropriate
* factory function in the Collector interface.
* @see Collector.
*/
explicit Gauge(std::shared_ptr<GaugeImpl> impl) : impl_(std::move(impl))
{
}
/** Set the value on the gauge.
A Collector implementation should combine multiple calls to value
changes into a single change if the calls occur within a single
collection interval.
*/
/**
* Set the value on the gauge.
* A Collector implementation should combine multiple calls to value
* changes into a single change if the calls occur within a single
* collection interval.
*/
/** @{ */
void
set(value_type value) const
@@ -62,7 +66,9 @@ public:
}
/** @} */
/** Adjust the value of the gauge. */
/**
* Adjust the value of the gauge.
*/
/** @{ */
void
increment(difference_type amount) const

View File

@@ -7,13 +7,17 @@
namespace beast::insight {
/** A collector front-end that manages a group of metrics. */
/**
* A collector front-end that manages a group of metrics.
*/
class Group : public Collector
{
public:
using ptr = std::shared_ptr<Group>;
/** Returns the name of this group, for diagnostics. */
/**
* Returns the name of this group, for diagnostics.
*/
[[nodiscard]] virtual std::string const&
name() const = 0;
};

View File

@@ -8,13 +8,17 @@
namespace beast::insight {
/** A container for managing a set of metric groups. */
/**
* A container for managing a set of metric groups.
*/
class Groups
{
public:
virtual ~Groups() = 0;
/** Find or create a new collector with a given name. */
/**
* Find or create a new collector with a given name.
*/
/** @{ */
virtual Group::ptr const&
get(std::string const& name) = 0;
@@ -27,7 +31,9 @@ public:
/** @} */
};
/** Create a group container that uses the specified collector. */
/**
* Create a group container that uses the specified collector.
*/
std::unique_ptr<Groups>
makeGroups(Collector::ptr const& collector);

View File

@@ -7,20 +7,24 @@
namespace beast::insight {
/** A reference to a handler for performing polled collection. */
/**
* A reference to a handler for performing polled collection.
*/
class Hook final
{
public:
/** Create a null hook.
A null hook has no associated handler.
*/
/**
* Create a null hook.
* A null hook has no associated handler.
*/
Hook() = default;
/** Create a hook referencing the specified implementation.
Normally this won't be called directly. Instead, call the appropriate
factory function in the Collector interface.
@see Collector.
*/
/**
* Create a hook referencing the specified implementation.
* Normally this won't be called directly. Instead, call the appropriate
* factory function in the Collector interface.
* @see Collector.
*/
explicit Hook(std::shared_ptr<HookImpl> impl) : impl_(std::move(impl))
{
}

View File

@@ -7,33 +7,38 @@
namespace beast::insight {
/** A metric for measuring an integral value.
A meter may be thought of as an increment-only counter.
This is a lightweight reference wrapper which is cheap to copy and assign.
When the last reference goes away, the metric is no longer collected.
*/
/**
* A metric for measuring an integral value.
*
* A meter may be thought of as an increment-only counter.
*
* This is a lightweight reference wrapper which is cheap to copy and assign.
* When the last reference goes away, the metric is no longer collected.
*/
class Meter final
{
public:
using value_type = MeterImpl::value_type;
/** Create a null metric.
A null metric reports no information.
*/
/**
* Create a null metric.
* A null metric reports no information.
*/
Meter() = default;
/** Create the metric reference the specified implementation.
Normally this won't be called directly. Instead, call the appropriate
factory function in the Collector interface.
@see Collector.
*/
/**
* Create the metric reference the specified implementation.
* Normally this won't be called directly. Instead, call the appropriate
* factory function in the Collector interface.
* @see Collector.
*/
explicit Meter(std::shared_ptr<MeterImpl> impl) : impl_(std::move(impl))
{
}
/** Increment the meter. */
/**
* Increment the meter.
*/
/** @{ */
void
increment(value_type amount) const

View File

@@ -6,7 +6,9 @@
namespace beast::insight {
/** A Collector which does not collect metrics. */
/**
* A Collector which does not collect metrics.
*/
class NullCollector : public Collector
{
public:

View File

@@ -9,20 +9,22 @@
namespace beast::insight {
/** A Collector that reports metrics to a StatsD server.
Reference:
https://github.com/b/statsd_spec
*/
/**
* A Collector that reports metrics to a StatsD server.
* Reference:
* https://github.com/b/statsd_spec
*/
class StatsDCollector : public Collector
{
public:
explicit StatsDCollector() = default;
/** Create a StatsD collector.
@param address The IP address and port of the StatsD server.
@param prefix A string pre-pended before each metric name.
@param journal Destination for logging output.
*/
/**
* Create a StatsD collector.
* @param address The IP address and port of the StatsD server.
* @param prefix A string pre-pended before each metric name.
* @param journal Destination for logging output.
*/
static std::shared_ptr<StatsDCollector>
make(IP::Endpoint const& address, std::string const& prefix, Journal journal);
};

View File

@@ -19,42 +19,54 @@ namespace IP {
using Address = boost::asio::ip::address;
/** Returns the address represented as a string. */
/**
* Returns the address represented as a string.
*/
inline std::string
to_string(Address const& addr)
{
return addr.to_string();
}
/** Returns `true` if this is a loopback address. */
/**
* Returns `true` if this is a loopback address.
*/
inline bool
isLoopback(Address const& addr)
{
return addr.is_loopback();
}
/** Returns `true` if the address is unspecified. */
/**
* Returns `true` if the address is unspecified.
*/
inline bool
isUnspecified(Address const& addr)
{
return addr.is_unspecified();
}
/** Returns `true` if the address is a multicast address. */
/**
* Returns `true` if the address is a multicast address.
*/
inline bool
isMulticast(Address const& addr)
{
return addr.is_multicast();
}
/** Returns `true` if the address is a private unroutable address. */
/**
* Returns `true` if the address is a private unroutable address.
*/
inline bool
isPrivate(Address const& addr)
{
return (addr.is_v4()) ? isPrivate(addr.to_v4()) : isPrivate(addr.to_v6());
}
/** Returns `true` if the address is a public routable address. */
/**
* Returns `true` if the address is a public routable address.
*/
inline bool
isPublic(Address const& addr)
{

View File

@@ -6,23 +6,29 @@
namespace beast::IP {
/** Convert to Endpoint.
The port is set to zero.
*/
/**
* Convert to Endpoint.
* The port is set to zero.
*/
Endpoint
fromAsio(boost::asio::ip::address const& address);
/** Convert to Endpoint. */
/**
* Convert to Endpoint.
*/
Endpoint
fromAsio(boost::asio::ip::tcp::endpoint const& endpoint);
/** Convert to asio::ip::address.
The port is ignored.
*/
/**
* Convert to asio::ip::address.
* The port is ignored.
*/
boost::asio::ip::address
toAsioAddress(Endpoint const& endpoint);
/** Convert to asio::ip::tcp::endpoint. */
/**
* Convert to asio::ip::tcp::endpoint.
*/
boost::asio::ip::tcp::endpoint
toAsioEndpoint(Endpoint const& endpoint);

View File

@@ -6,17 +6,22 @@ namespace beast::IP {
using AddressV4 = boost::asio::ip::address_v4;
/** Returns `true` if the address is a private unroutable address. */
/**
* Returns `true` if the address is a private unroutable address.
*/
bool
isPrivate(AddressV4 const& addr);
/** Returns `true` if the address is a public routable address. */
/**
* Returns `true` if the address is a public routable address.
*/
bool
isPublic(AddressV4 const& addr);
/** Returns the address class for the given address.
@note Class 'D' represents multicast addresses (224.*.*.*).
*/
/**
* Returns the address class for the given address.
* @note Class 'D' represents multicast addresses (224.*.*.*).
*/
char
getClass(AddressV4 const& address);

View File

@@ -6,11 +6,15 @@ namespace beast::IP {
using AddressV6 = boost::asio::ip::address_v6;
/** Returns `true` if the address is a private unroutable address. */
/**
* Returns `true` if the address is a private unroutable address.
*/
bool
isPrivate(AddressV6 const& addr);
/** Returns `true` if the address is a public routable address. */
/**
* Returns `true` if the address is a public routable address.
*/
bool
isPublic(AddressV6 const& addr);

View File

@@ -17,51 +17,68 @@ namespace beast::IP {
using Port = std::uint16_t;
/** A version-independent IP address and port combination. */
/**
* A version-independent IP address and port combination.
*/
class Endpoint
{
public:
/** Create an unspecified endpoint. */
/**
* Create an unspecified endpoint.
*/
Endpoint();
/** Create an endpoint from the address and optional port. */
/**
* Create an endpoint from the address and optional port.
*/
explicit Endpoint(Address addr, Port port = 0);
/** Create an Endpoint from a string.
If the port is omitted, the endpoint will have a zero port.
@return An optional endpoint; will be `std::nullopt` on failure
*/
/**
* Create an Endpoint from a string.
* If the port is omitted, the endpoint will have a zero port.
* @return An optional endpoint; will be `std::nullopt` on failure
*/
static std::optional<Endpoint>
fromStringChecked(std::string const& s);
static Endpoint
fromString(std::string const& s);
/** Returns a string representing the endpoint. */
/**
* Returns a string representing the endpoint.
*/
[[nodiscard]] std::string
toString() const;
/** Returns the port number on the endpoint. */
/**
* Returns the port number on the endpoint.
*/
[[nodiscard]] Port
port() const
{
return port_;
}
/** Returns a new Endpoint with a different port. */
/**
* Returns a new Endpoint with a different port.
*/
[[nodiscard]] Endpoint
atPort(Port port) const
{
return Endpoint(addr_, port);
}
/** Returns the address portion of this endpoint. */
/**
* Returns the address portion of this endpoint.
*/
[[nodiscard]] Address const&
address() const
{
return addr_;
}
/** Convenience accessors for the address part. */
/**
* Convenience accessors for the address part.
*/
/** @{ */
[[nodiscard]] bool
isV4() const
@@ -85,7 +102,9 @@ public:
}
/** @} */
/** Arithmetic comparison. */
/**
* Arithmetic comparison.
*/
/** @{ */
friend bool
operator==(Endpoint const& lhs, Endpoint const& rhs);
@@ -131,35 +150,45 @@ private:
// Properties
/** Returns `true` if the endpoint is a loopback address. */
/**
* Returns `true` if the endpoint is a loopback address.
*/
inline bool
isLoopback(Endpoint const& endpoint)
{
return isLoopback(endpoint.address());
}
/** Returns `true` if the endpoint is unspecified. */
/**
* Returns `true` if the endpoint is unspecified.
*/
inline bool
isUnspecified(Endpoint const& endpoint)
{
return isUnspecified(endpoint.address());
}
/** Returns `true` if the endpoint is a multicast address. */
/**
* Returns `true` if the endpoint is a multicast address.
*/
inline bool
isMulticast(Endpoint const& endpoint)
{
return isMulticast(endpoint.address());
}
/** Returns `true` if the endpoint is a private unroutable address. */
/**
* Returns `true` if the endpoint is a private unroutable address.
*/
inline bool
isPrivate(Endpoint const& endpoint)
{
return isPrivate(endpoint.address());
}
/** Returns `true` if the endpoint is a public routable address. */
/**
* Returns `true` if the endpoint is a public routable address.
*/
inline bool
isPublic(Endpoint const& endpoint)
{
@@ -168,14 +197,18 @@ isPublic(Endpoint const& endpoint)
//------------------------------------------------------------------------------
/** Returns the endpoint represented as a string. */
/**
* Returns the endpoint represented as a string.
*/
inline std::string
to_string(Endpoint const& endpoint)
{
return endpoint.toString();
}
/** Output stream conversion. */
/**
* Output stream conversion.
*/
template <typename OutputStream>
OutputStream&
operator<<(OutputStream& os, Endpoint const& endpoint)
@@ -184,7 +217,9 @@ operator<<(OutputStream& os, Endpoint const& endpoint)
return os;
}
/** Input stream conversion. */
/**
* Input stream conversion.
*/
std::istream&
operator>>(std::istream& is, Endpoint& endpoint);
@@ -193,7 +228,9 @@ operator>>(std::istream& is, Endpoint& endpoint);
//------------------------------------------------------------------------------
namespace std {
/** std::hash support. */
/**
* std::hash support.
*/
template <>
struct hash<::beast::IP::Endpoint>
{
@@ -208,7 +245,9 @@ struct hash<::beast::IP::Endpoint>
} // namespace std
namespace boost {
/** boost::hash support. */
/**
* boost::hash support.
*/
template <>
struct hash<::beast::IP::Endpoint>
{

View File

@@ -30,17 +30,20 @@ struct CiEqualPred
}
};
/** Returns `true` if `c` is linear white space.
This excludes the CRLF sequence allowed for line continuations.
*/
/**
* Returns `true` if `c` is linear white space.
*
* This excludes the CRLF sequence allowed for line continuations.
*/
inline bool
isLws(char c)
{
return c == ' ' || c == '\t';
}
/** Returns `true` if `c` is any whitespace character. */
/**
* Returns `true` if `c` is any whitespace character.
*/
inline bool
isWhite(char c)
{
@@ -87,14 +90,15 @@ trimRight(String const& s)
} // namespace detail
/** Parse a character sequence of values separated by commas.
Double quotes and escape sequences will be converted. Excess white
space, commas, double quotes, and empty elements are not copied.
Format:
#(token|quoted-string)
Reference:
http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2
*/
/**
* Parse a character sequence of values separated by commas.
* Double quotes and escape sequences will be converted. Excess white
* space, commas, double quotes, and empty elements are not copied.
* Format:
* #(token|quoted-string)
* Reference:
* http://www.w3.org/Protocols/rfc2616/rfc2616-sec2.html#sec2
*/
template <
class FwdIt,
class Result = std::vector<std::basic_string<typename std::iterator_traits<FwdIt>::value_type>>,
@@ -189,14 +193,15 @@ splitCommas(boost::beast::string_view const& s)
//------------------------------------------------------------------------------
/** Iterates through a comma separated list.
Meets the requirements of ForwardIterator.
List defined in rfc2616 2.1.
@note Values returned may contain backslash escapes.
*/
/**
* Iterates through a comma separated list.
*
* Meets the requirements of ForwardIterator.
*
* List defined in rfc2616 2.1.
*
* @note Values returned may contain backslash escapes.
*/
class ListIterator
{
using iter_type = boost::string_ref::const_iterator;
@@ -323,17 +328,20 @@ ListIterator::increment()
}
}
}
/** Returns true if two strings are equal.
A case-insensitive comparison is used.
*/
/**
* Returns true if two strings are equal.
*
* A case-insensitive comparison is used.
*/
inline bool
ciEqual(boost::string_ref s1, boost::string_ref s2)
{
return boost::range::equal(s1, s2, detail::CiEqualPred{});
}
/** Returns a range representing the list. */
/**
* Returns a range representing the list.
*/
inline boost::iterator_range<ListIterator>
makeList(boost::string_ref const& field)
{
@@ -341,10 +349,11 @@ makeList(boost::string_ref const& field)
ListIterator{field.begin(), field.end()}, ListIterator{field.end(), field.end()}};
}
/** Returns true if the specified token exists in the list.
A case-insensitive comparison is used.
*/
/**
* Returns true if the specified token exists in the list.
*
* A case-insensitive comparison is used.
*/
template <class = void>
bool
tokenInList(boost::string_ref const& value, boost::string_ref const& token)

View File

@@ -19,12 +19,13 @@
namespace beast::test {
/** Mix-in to support tests using asio coroutines.
Derive from this class and use yield_to to launch test
functions inside coroutines. This is handy for testing
asynchronous asio code.
*/
/**
* Mix-in to support tests using asio coroutines.
*
* Derive from this class and use yield_to to launch test
* functions inside coroutines. This is handy for testing
* asynchronous asio code.
*/
class EnableYieldTo
{
protected:
@@ -38,7 +39,9 @@ private:
std::size_t running_ = 0;
public:
/// The type of yield context passed to functions.
/**
* The type of yield context passed to functions.
*/
using yield_context = boost::asio::yield_context;
explicit EnableYieldTo(std::size_t concurrency = 1) : work_(boost::asio::make_work_guard(ios_))
@@ -57,24 +60,27 @@ public:
t.join();
}
/// Return the `io_context` associated with the object
/**
* Return the `io_context` associated with the object
*/
boost::asio::io_context&
getIoContext()
{
return ios_;
}
/** Run one or more functions, each in a coroutine.
This call will block until all coroutines terminate.
Each functions should have this signature:
@code
void f(yield_context);
@endcode
@param fn... One or more functions to invoke.
*/
/**
* Run one or more functions, each in a coroutine.
*
* This call will block until all coroutines terminate.
*
* Each functions should have this signature:
* @code
* void f(yield_context);
* @endcode
*
* @param fn... One or more functions to invoke.
*/
#if BEAST_DOXYGEN
template <class... FN>
void

View File

@@ -10,7 +10,9 @@
namespace beast::unit_test {
/** Utility for producing nicely composed output of amounts with units. */
/**
* Utility for producing nicely composed output of amounts with units.
*/
class Amount
{
private:

View File

@@ -6,10 +6,11 @@
namespace beast::unit_test::detail {
/** Adapter to constrain a container interface.
The interface allows for limited read only operations. Derived classes
provide additional behavior.
*/
/**
* Adapter to constrain a container interface.
* The interface allows for limited read only operations. Derived classes
* provide additional behavior.
*/
template <class Container>
class ConstContainer
{
@@ -38,21 +39,27 @@ public:
using iterator = cont_type::const_iterator;
using const_iterator = cont_type::const_iterator;
/** Returns `true` if the container is empty. */
/**
* Returns `true` if the container is empty.
*/
[[nodiscard]] bool
empty() const
{
return cont_.empty();
}
/** Returns the number of items in the container. */
/**
* Returns the number of items in the container.
*/
[[nodiscard]] size_type
size() const
{
return cont_.size();
}
/** Returns forward iterators for traversal. */
/**
* Returns forward iterators for traversal.
*/
/** @{ */
[[nodiscard]] const_iterator
begin() const

View File

@@ -10,7 +10,9 @@ namespace beast::unit_test {
namespace detail {
/// Holds test suites registered during static initialization.
/**
* Holds test suites registered during static initialization.
*/
inline SuiteList&
globalSuites()
{
@@ -34,7 +36,9 @@ struct InsertSuite
} // namespace detail
/// Holds test suites registered during static initialization.
/**
* Holds test suites registered during static initialization.
*/
inline SuiteList const&
globalSuites()
{

View File

@@ -121,42 +121,48 @@ Selector::operator()(SuiteInfo const& s)
// Utility functions for producing predicates to select suites.
/** Returns a predicate that implements a smart matching rule.
The predicate checks the suite, module, and library fields of the
SuiteInfo in that order. When it finds a match, it changes modes
depending on what was found:
If a suite is matched first, then only the suite is selected. The
suite may be marked manual.
If a module is matched first, then only suites from that module
and library not marked manual are selected from then on.
If a library is matched first, then only suites from that library
not marked manual are selected from then on.
*/
/**
* Returns a predicate that implements a smart matching rule.
* The predicate checks the suite, module, and library fields of the
* SuiteInfo in that order. When it finds a match, it changes modes
* depending on what was found:
*
* If a suite is matched first, then only the suite is selected. The
* suite may be marked manual.
*
* If a module is matched first, then only suites from that module
* and library not marked manual are selected from then on.
*
* If a library is matched first, then only suites from that library
* not marked manual are selected from then on.
*/
inline Selector
matchAuto(std::string const& name)
{
return Selector(Selector::ModeT::Automatch, name);
}
/** Return a predicate that matches all suites not marked manual. */
/**
* Return a predicate that matches all suites not marked manual.
*/
inline Selector
matchAll()
{
return Selector(Selector::ModeT::All);
}
/** Returns a predicate that matches a specific suite. */
/**
* Returns a predicate that matches a specific suite.
*/
inline Selector
matchSuite(std::string const& name)
{
return Selector(Selector::ModeT::Suite, name);
}
/** Returns a predicate that matches all suites in a library. */
/**
* Returns a predicate that matches all suites in a library.
*/
inline Selector
matchLibrary(std::string const& name)
{

View File

@@ -13,7 +13,9 @@
namespace beast::unit_test {
/** A test runner that stores the results. */
/**
* A test runner that stores the results.
*/
class Recorder : public Runner
{
private:
@@ -24,7 +26,9 @@ private:
public:
Recorder() = default;
/** Returns a report with the results of all completed suites. */
/**
* Returns a report with the results of all completed suites.
*/
[[nodiscard]] Results const&
report() const
{

View File

@@ -25,9 +25,10 @@ namespace beast::unit_test {
namespace detail {
/** A simple test runner that writes everything to a stream in real time.
The totals are output when the object is destroyed.
*/
/**
* A simple test runner that writes everything to a stream in real time.
* The totals are output when the object is destroyed.
*/
template <class = void>
class Reporter : public Runner
{

View File

@@ -13,11 +13,15 @@
namespace beast::unit_test {
/** Holds a set of test condition outcomes in a testcase. */
/**
* Holds a set of test condition outcomes in a testcase.
*/
class CaseResults
{
public:
/** Holds the result of evaluating one test condition. */
/**
* Holds the result of evaluating one test condition.
*/
struct Test
{
explicit Test(bool pass) : pass(pass)
@@ -41,28 +45,36 @@ private:
public:
TestsT() = default;
/** Returns the total number of test conditions. */
/**
* Returns the total number of test conditions.
*/
[[nodiscard]] std::size_t
total() const
{
return cont().size();
}
/** Returns the number of failed test conditions. */
/**
* Returns the number of failed test conditions.
*/
[[nodiscard]] std::size_t
failed() const
{
return failed_;
}
/** Register a successful test condition. */
/**
* Register a successful test condition.
*/
void
pass()
{
cont().emplace_back(true);
}
/** Register a failed test condition. */
/**
* Register a failed test condition.
*/
void
fail(std::string const& reason = "")
{
@@ -74,7 +86,9 @@ private:
class LogT : public detail::ConstContainer<std::vector<std::string>>
{
public:
/** Insert a string into the log. */
/**
* Insert a string into the log.
*/
void
insert(std::string const& s)
{
@@ -89,23 +103,31 @@ public:
{
}
/** Returns the name of this testcase. */
/**
* Returns the name of this testcase.
*/
[[nodiscard]] std::string const&
name() const
{
return name_;
}
/** Memberspace for a container of test condition outcomes. */
/**
* Memberspace for a container of test condition outcomes.
*/
TestsT tests;
/** Memberspace for a container of testcase log messages. */
/**
* Memberspace for a container of testcase log messages.
*/
LogT log;
};
//--------------------------------------------------------------------------
/** Holds the set of testcase results in a suite. */
/**
* Holds the set of testcase results in a suite.
*/
class SuiteResults : public detail::ConstContainer<std::vector<CaseResults>>
{
private:
@@ -118,28 +140,36 @@ public:
{
}
/** Returns the name of this suite. */
/**
* Returns the name of this suite.
*/
[[nodiscard]] std::string const&
name() const
{
return name_;
}
/** Returns the total number of test conditions. */
/**
* Returns the total number of test conditions.
*/
[[nodiscard]] std::size_t
total() const
{
return total_;
}
/** Returns the number of failures. */
/**
* Returns the number of failures.
*/
[[nodiscard]] std::size_t
failed() const
{
return failed_;
}
/** Insert a set of testcase results. */
/**
* Insert a set of testcase results.
*/
/** @{ */
void
insert(CaseResults&& r)
@@ -162,7 +192,9 @@ public:
//------------------------------------------------------------------------------
// VFALCO TODO Make this a template class using scoped allocators
/** Holds the results of running a set of testsuites. */
/**
* Holds the results of running a set of testsuites.
*/
class Results : public detail::ConstContainer<std::vector<SuiteResults>>
{
private:
@@ -173,28 +205,36 @@ private:
public:
Results() = default;
/** Returns the total number of test cases. */
/**
* Returns the total number of test cases.
*/
[[nodiscard]] std::size_t
cases() const
{
return cases_;
}
/** Returns the total number of test conditions. */
/**
* Returns the total number of test conditions.
*/
[[nodiscard]] std::size_t
total() const
{
return total_;
}
/** Returns the number of failures. */
/**
* Returns the number of failures.
*/
[[nodiscard]] std::size_t
failed() const
{
return failed_;
}
/** Insert a set of suite results. */
/**
* Insert a set of suite results.
*/
/** @{ */
void
insert(SuiteResults&& r)

View File

@@ -13,11 +13,12 @@
namespace beast::unit_test {
/** Unit test runner interface.
Derived classes can customize the reporting behavior. This interface is
injected into the unit_test class to receive the results of the tests.
*/
/**
* Unit test runner interface.
*
* Derived classes can customize the reporting behavior. This interface is
* injected into the unit_test class to receive the results of the tests.
*/
class Runner
{
std::string arg_;
@@ -33,110 +34,132 @@ public:
Runner&
operator=(Runner const&) = delete;
/** Set the argument string.
The argument string is available to suites and
allows for customization of the test. Each suite
defines its own syntax for the argument string.
The same argument is passed to all suites.
*/
/**
* Set the argument string.
*
* The argument string is available to suites and
* allows for customization of the test. Each suite
* defines its own syntax for the argument string.
* The same argument is passed to all suites.
*/
void
arg(std::string const& s)
{
arg_ = s;
}
/** Returns the argument string. */
/**
* Returns the argument string.
*/
[[nodiscard]] std::string const&
arg() const
{
return arg_;
}
/** Run the specified suite.
@return `true` if any conditions failed.
*/
/**
* Run the specified suite.
* @return `true` if any conditions failed.
*/
template <class = void>
bool
run(SuiteInfo const& s);
/** Run a sequence of suites.
The expression
`FwdIter::value_type`
must be convertible to `SuiteInfo`.
@return `true` if any conditions failed.
*/
/**
* Run a sequence of suites.
* The expression
* `FwdIter::value_type`
* must be convertible to `SuiteInfo`.
* @return `true` if any conditions failed.
*/
template <class FwdIter>
bool
run(FwdIter first, FwdIter last);
/** Conditionally run a sequence of suites.
pred will be called as:
@code
bool pred(SuiteInfo const&);
@endcode
@return `true` if any conditions failed.
*/
/**
* Conditionally run a sequence of suites.
* pred will be called as:
* @code
* bool pred(SuiteInfo const&);
* @endcode
* @return `true` if any conditions failed.
*/
template <class FwdIter, class Pred>
bool
runIf(FwdIter first, FwdIter last, Pred pred = Pred{});
/** Run all suites in a container.
@return `true` if any conditions failed.
*/
/**
* Run all suites in a container.
* @return `true` if any conditions failed.
*/
template <class SequenceContainer>
bool
runEach(SequenceContainer const& c);
/** Conditionally run suites in a container.
pred will be called as:
@code
bool pred(SuiteInfo const&);
@endcode
@return `true` if any conditions failed.
*/
/**
* Conditionally run suites in a container.
* pred will be called as:
* @code
* bool pred(SuiteInfo const&);
* @endcode
* @return `true` if any conditions failed.
*/
template <class SequenceContainer, class Pred>
bool
runEachIf(SequenceContainer const& c, Pred pred = Pred{});
protected:
/// Called when a new suite starts.
/**
* Called when a new suite starts.
*/
virtual void
onSuiteBegin(SuiteInfo const&)
{
}
/// Called when a suite ends.
/**
* Called when a suite ends.
*/
virtual void
onSuiteEnd()
{
}
/// Called when a new case starts.
/**
* Called when a new case starts.
*/
virtual void
onCaseBegin(std::string const&)
{
}
/// Called when a new case ends.
/**
* Called when a new case ends.
*/
virtual void
onCaseEnd()
{
}
/// Called for each passing condition.
/**
* Called for each passing condition.
*/
virtual void
onPass()
{
}
/// Called for each failing condition.
/**
* Called for each failing condition.
*/
virtual void
onFail(std::string const&)
{
}
/// Called when a test logs output.
/**
* Called when a test logs output.
*/
virtual void
onLog(std::string const&)
{

View File

@@ -41,13 +41,14 @@ class Thread;
enum class AbortT { NoAbortOnFail, AbortOnFail };
/** A testsuite class.
Derived classes execute a series of testcases, where each testcase is
a series of pass/fail tests. To provide a unit test using this class,
derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a
translation unit.
*/
/**
* A testsuite class.
*
* Derived classes execute a series of testcases, where each testcase is
* a series of pass/fail tests. To provide a unit test using this class,
* derive from it and use the BEAST_DEFINE_UNIT_TEST macro in a
* translation unit.
*/
class Suite
{
private:
@@ -118,16 +119,17 @@ private:
{
}
/** Open a new testcase.
A testcase is a series of evaluated test conditions. A test
suite may have multiple test cases. A test is associated with
the last opened testcase. When the test first runs, a default
unnamed case is opened. Tests with only one case may omit the
call to testcase.
@param abort Determines if suite continues running after a failure.
*/
/**
* Open a new testcase.
*
* A testcase is a series of evaluated test conditions. A test
* suite may have multiple test cases. A test is associated with
* the last opened testcase. When the test first runs, a default
* unnamed case is opened. Tests with only one case may omit the
* call to testcase.
*
* @param abort Determines if suite continues running after a failure.
*/
void
operator()(std::string const& name, AbortT abort = AbortT::NoAbortOnFail);
@@ -140,19 +142,23 @@ private:
};
public:
/** Logging output stream.
Text sent to the log output stream will be forwarded to
the output stream associated with the runner.
*/
/**
* Logging output stream.
*
* Text sent to the log output stream will be forwarded to
* the output stream associated with the runner.
*/
LogOs<char> log;
/** Memberspace for declaring test cases. */
/**
* Memberspace for declaring test cases.
*/
TestcaseT testcase;
/** Returns the "current" running suite.
If no suite is running, nullptr is returned.
*/
/**
* Returns the "current" running suite.
* If no suite is running, nullptr is returned.
*/
static Suite*
thisSuite()
{
@@ -168,30 +174,34 @@ public:
Suite&
operator=(Suite const&) = delete;
/** Invokes the test using the specified runner.
Data members are set up here instead of the constructor as a
convenience to writing the derived class to avoid repetition of
forwarded constructor arguments to the base.
Normally this is called by the framework for you.
*/
/**
* Invokes the test using the specified runner.
*
* Data members are set up here instead of the constructor as a
* convenience to writing the derived class to avoid repetition of
* forwarded constructor arguments to the base.
* Normally this is called by the framework for you.
*/
template <class = void>
void
operator()(Runner& r);
/** Record a successful test condition. */
/**
* Record a successful test condition.
*/
template <class = void>
void
pass();
/** Record a failure.
@param reason Optional text added to the output on a failure.
@param file The source code file where the test failed.
@param line The source code line number where the test failed.
*/
/**
* Record a failure.
*
* @param reason Optional text added to the output on a failure.
*
* @param file The source code file where the test failed.
*
* @param line The source code line number where the test failed.
*/
/** @{ */
template <class String>
void
@@ -202,23 +212,24 @@ public:
fail(std::string const& reason = "");
/** @} */
/** Evaluate a test condition.
This function provides improved logging by incorporating the
file name and line number into the reported output on failure,
as well as additional text specified by the caller.
@param shouldBeTrue The condition to test. The condition
is evaluated in a boolean context.
@param reason Optional added text to output on a failure.
@param file The source code file where the test failed.
@param line The source code line number where the test failed.
@return `true` if the test condition indicates success.
*/
/**
* Evaluate a test condition.
*
* This function provides improved logging by incorporating the
* file name and line number into the reported output on failure,
* as well as additional text specified by the caller.
*
* @param shouldBeTrue The condition to test. The condition
* is evaluated in a boolean context.
*
* @param reason Optional added text to output on a failure.
*
* @param file The source code file where the test failed.
*
* @param line The source code line number where the test failed.
*
* @return `true` if the test condition indicates success.
*/
/** @{ */
template <class Condition>
bool
@@ -275,15 +286,19 @@ public:
return unexcept(f, "");
}
/** Return the argument associated with the runner. */
/**
* Return the argument associated with the runner.
*/
std::string const&
arg() const
{
return runner_->arg();
}
// DEPRECATED
// @return `true` if the test condition indicates success(a false value)
/**
* DEPRECATED
* @return `true` if the test condition indicates success(a false value)
*/
template <class Condition, class String>
bool
unexpected(Condition shouldBeFalse, String const& reason);
@@ -305,7 +320,9 @@ private:
return &kPTs;
}
/** Runs the suite. */
/**
* Runs the suite.
*/
virtual void
run() = 0;
@@ -558,18 +575,20 @@ Suite::run(Runner& r)
}
#ifndef BEAST_EXPECT
/** Check a precondition.
If the condition is false, the file and line number are reported.
*/
/**
* Check a precondition.
*
* If the condition is false, the file and line number are reported.
*/
#define BEAST_EXPECT(cond) expect(cond, __FILE__, __LINE__)
#endif
#ifndef BEAST_EXPECTS
/** Check a precondition.
If the condition is false, the file and line number are reported.
*/
/**
* Check a precondition.
*
* If the condition is false, the file and line number are reported.
*/
#define BEAST_EXPECTS(cond, reason) \
((cond) ? (pass(), true) : (fail((reason), __FILE__, __LINE__), false))
#endif
@@ -593,41 +612,43 @@ Suite::run(Runner& r)
//
#ifndef BEAST_DEFINE_TESTSUITE
/** Enables insertion of test suites into the global container.
The default is to insert all test suite definitions into the global
container. If BEAST_DEFINE_TESTSUITE is user defined, this macro
has no effect.
*/
/**
* Enables insertion of test suites into the global container.
* The default is to insert all test suite definitions into the global
* container. If BEAST_DEFINE_TESTSUITE is user defined, this macro
* has no effect.
*/
#ifndef BEAST_NO_UNIT_TEST_INLINE
#define BEAST_NO_UNIT_TEST_INLINE 0
#endif
/** Define a unit test suite.
Class The type representing the class being tested.
Module Identifies the module.
Library Identifies the library.
The declaration for the class implementing the test should be the same
as Class ## _test. For example, if Class is aged_ordered_container, the
test class must be declared as:
@code
struct aged_ordered_container_test : beast::unit_test::suite
{
//...
};
@endcode
The macro invocation must appear in the same namespace as the test class.
Unit test priorities were introduced so parallel unit_test::suites would
execute faster. Suites with longer running times have higher priorities
than unit tests with shorter running times. Suites with no priorities
are assumed to run most quickly, so they run last.
*/
/**
* Define a unit test suite.
*
* Class The type representing the class being tested.
* Module Identifies the module.
* Library Identifies the library.
*
* The declaration for the class implementing the test should be the same
* as Class ## _test. For example, if Class is aged_ordered_container, the
* test class must be declared as:
*
* @code
*
* struct aged_ordered_container_test : beast::unit_test::suite
* {
* //...
* };
*
* @endcode
*
* The macro invocation must appear in the same namespace as the test class.
*
* Unit test priorities were introduced so parallel unit_test::suites would
* execute faster. Suites with longer running times have higher priorities
* than unit tests with shorter running times. Suites with no priorities
* are assumed to run most quickly, so they run last.
*/
#if BEAST_NO_UNIT_TEST_INLINE
#define BEAST_DEFINE_TESTSUITE(Class, Module, Library)

View File

@@ -13,7 +13,9 @@ namespace beast::unit_test {
class Runner;
/** Associates a unit test type with metadata. */
/**
* Associates a unit test type with metadata.
*/
class SuiteInfo
{
using run_type = std::function<void(Runner&)>;
@@ -60,21 +62,27 @@ public:
return library_;
}
/// Returns `true` if this suite only runs manually.
/**
* Returns `true` if this suite only runs manually.
*/
[[nodiscard]] bool
manual() const
{
return manual_;
}
/// Return the canonical suite name as a string.
/**
* Return the canonical suite name as a string.
*/
[[nodiscard]] std::string
fullName() const
{
return library_ + "." + module_ + "." + name_;
}
/// Run a new instance of the associated test suite.
/**
* Run a new instance of the associated test suite.
*/
void
run(Runner& r) const
{
@@ -93,7 +101,9 @@ public:
//------------------------------------------------------------------------------
/// Convenience for producing SuiteInfo for a given test type.
/**
* Convenience for producing SuiteInfo for a given test type.
*/
template <class Suite>
SuiteInfo
makeSuiteInfo(std::string name, std::string module, std::string library, bool manual, int priority)

View File

@@ -16,7 +16,9 @@
namespace beast::unit_test {
/// A container of test suites.
/**
* A container of test suites.
*/
class SuiteList : public detail::ConstContainer<std::set<SuiteInfo>>
{
private:
@@ -26,10 +28,11 @@ private:
#endif
public:
/** Insert a suite into the set.
The suite must not already exist.
*/
/**
* Insert a suite into the set.
*
* The suite must not already exist.
*/
template <class Suite>
void
insert(char const* name, char const* module, char const* library, bool manual, int priority);

View File

@@ -14,7 +14,9 @@
namespace beast::unit_test {
/** Replacement for std::thread that handles exceptions in unit tests. */
/**
* Replacement for std::thread that handles exceptions in unit tests.
*/
class Thread
{
private:

View File

@@ -10,7 +10,9 @@
namespace beast {
/** Severity level / threshold of a Journal message. */
/**
* Severity level / threshold of a Journal message.
*/
enum class Severity : std::uint8_t {
All = 0,
@@ -25,18 +27,19 @@ enum class Severity : std::uint8_t {
None = Disabled
};
/** A generic endpoint for log messages.
The Journal has a few simple goals:
* To be light-weight and copied by value.
* To allow logging statements to be left in source code.
* The logging is controlled at run-time based on a logging threshold.
It is advisable to check Journal::active(level) prior to formatting log
text. Doing so sidesteps expensive text formatting when the results
will not be sent to the log.
*/
/**
* A generic endpoint for log messages.
*
* The Journal has a few simple goals:
*
* * To be light-weight and copied by value.
* * To allow logging statements to be left in source code.
* * The logging is controlled at run-time based on a logging threshold.
*
* It is advisable to check Journal::active(level) prior to formatting log
* text. Doing so sidesteps expensive text formatting when the results
* will not be sent to the log.
*/
class Journal
{
public:
@@ -49,7 +52,9 @@ private:
public:
//--------------------------------------------------------------------------
/** Abstraction for the underlying message destination. */
/**
* Abstraction for the underlying message destination.
*/
class Sink
{
protected:
@@ -63,36 +68,47 @@ public:
Sink&
operator=(Sink const& lhs) = delete;
/** Returns `true` if text at the passed severity produces output. */
/**
* Returns `true` if text at the passed severity produces output.
*/
[[nodiscard]] virtual bool
active(Severity level) const;
/** Returns `true` if a message is also written to the Output Window
* (MSVC). */
/**
* Returns `true` if a message is also written to the Output Window
* (MSVC).
*/
[[nodiscard]] virtual bool
console() const;
/** Set whether messages are also written to the Output Window (MSVC).
/**
* Set whether messages are also written to the Output Window (MSVC).
*/
virtual void
console(bool output);
/** Returns the minimum severity level this sink will report. */
/**
* Returns the minimum severity level this sink will report.
*/
[[nodiscard]] virtual Severity
threshold() const;
/** Set the minimum severity this sink will report. */
/**
* Set the minimum severity this sink will report.
*/
virtual void
threshold(Severity thresh);
/** Write text to the sink at the specified severity.
A conforming implementation will not write the text if the passed
level is below the current threshold().
*/
/**
* Write text to the sink at the specified severity.
* A conforming implementation will not write the text if the passed
* level is below the current threshold().
*/
virtual void
write(Severity level, std::string const& text) = 0;
/** Bypass filter and write text to the sink at the specified severity.
/**
* Bypass filter and write text to the sink at the specified severity.
* Always write the message, but maintain the same formatting as if
* it passed through a level filter.
*
@@ -116,7 +132,9 @@ public:
static_assert(std::is_nothrow_destructible_v<Sink>);
#endif
/** Returns a Sink which does nothing. */
/**
* Returns a Sink which does nothing.
*/
static Sink&
getNullSink();
@@ -174,26 +192,33 @@ public:
//--------------------------------------------------------------------------
public:
/** Provide a light-weight way to check active() before string formatting */
/**
* Provide a light-weight way to check active() before string formatting
*/
class Stream
{
public:
/** Create a stream which produces no output. */
/**
* Create a stream which produces no output.
*/
explicit Stream() : sink_(getNullSink()), level_(Severity::Disabled)
{
}
/** Create a stream that writes at the given level.
Constructor is inlined so checking active() very inexpensive.
*/
/**
* Create a stream that writes at the given level.
*
* Constructor is inlined so checking active() very inexpensive.
*/
Stream(Sink& sink, Severity level) : sink_(sink), level_(level)
{
XRPL_ASSERT(
level_ < Severity::Disabled, "beast::Journal::Stream::Stream : maximum level");
}
/** Construct or copy another Stream. */
/**
* Construct or copy another Stream.
*/
Stream(Stream const& other) : Stream(other.sink_, other.level_)
{
}
@@ -201,21 +226,27 @@ public:
Stream&
operator=(Stream const& other) = delete;
/** Returns the Sink that this Stream writes to. */
/**
* Returns the Sink that this Stream writes to.
*/
[[nodiscard]] Sink&
sink() const
{
return sink_;
}
/** Returns the Severity level of messages this Stream reports. */
/**
* Returns the Severity level of messages this Stream reports.
*/
[[nodiscard]] Severity
level() const
{
return level_;
}
/** Returns `true` if sink logs anything at this stream's level. */
/**
* Returns `true` if sink logs anything at this stream's level.
*/
/** @{ */
[[nodiscard]] bool
active() const
@@ -230,7 +261,9 @@ public:
}
/** @} */
/** Output stream support. */
/**
* Output stream support.
*/
/** @{ */
ScopedStream
operator<<(std::ostream& manip(std::ostream&)) const;
@@ -256,39 +289,50 @@ public:
//--------------------------------------------------------------------------
/** Journal has no default constructor. */
/**
* Journal has no default constructor.
*/
Journal() = delete;
/** Create a journal that writes to the specified sink. */
/**
* Create a journal that writes to the specified sink.
*/
explicit Journal(Sink& sink) : sink_(&sink)
{
}
/** Returns the Sink associated with this Journal. */
/**
* Returns the Sink associated with this Journal.
*/
[[nodiscard]] Sink&
sink() const
{
return *sink_;
}
/** Returns a stream for this sink, with the specified severity level. */
/**
* Returns a stream for this sink, with the specified severity level.
*/
[[nodiscard]] Stream
stream(Severity level) const
{
return Stream(*sink_, level);
}
/** Returns `true` if any message would be logged at this severity level.
For a message to be logged, the severity must be at or above the
sink's severity threshold.
*/
/**
* Returns `true` if any message would be logged at this severity level.
* For a message to be logged, the severity must be at or above the
* sink's severity threshold.
*/
[[nodiscard]] bool
active(Severity level) const
{
return sink_->active(level);
}
/** Severity stream access functions. */
/**
* Severity stream access functions.
*/
/** @{ */
[[nodiscard]] Stream
trace() const

View File

@@ -12,7 +12,9 @@ namespace beast {
//------------------------------------------------------------------------------
/** Abstract stream with RAII containers that produce a property tree. */
/**
* Abstract stream with RAII containers that produce a property tree.
*/
class PropertyStream
{
public:
@@ -306,7 +308,9 @@ public:
//
//------------------------------------------------------------------------------
/** Subclasses can be called to write to a stream and have children. */
/**
* Subclasses can be called to write to a stream and have children.
*/
class PropertyStream::Source
{
private:
@@ -324,17 +328,22 @@ public:
Source&
operator=(Source const&) = delete;
/** Returns the name of this source. */
/**
* Returns the name of this source.
*/
[[nodiscard]] std::string const&
name() const;
/** Add a child source. */
/**
* Add a child source.
*/
void
add(Source& source);
/** Add a child source by pointer.
The source pointer is returned so it can be used in ctor-initializers.
*/
/**
* Add a child source by pointer.
* The source pointer is returned so it can be used in ctor-initializers.
*/
template <class Derived>
Derived*
add(Derived* child)
@@ -343,45 +352,55 @@ public:
return child;
}
/** Remove a child source from this Source. */
/**
* Remove a child source from this Source.
*/
void
remove(Source& child);
/** Remove all child sources from this Source. */
/**
* Remove all child sources from this Source.
*/
void
removeAll();
/** Write only this Source to the stream. */
/**
* Write only this Source to the stream.
*/
void
writeOne(PropertyStream& stream);
/** write this source and all its children recursively to the stream. */
/**
* write this source and all its children recursively to the stream.
*/
void
write(PropertyStream& stream);
/** Parse the path and write the corresponding Source and optional children.
If the source is found, it is written. If the wildcard character '*'
exists as the last character in the path, then all the children are
written recursively.
*/
/**
* Parse the path and write the corresponding Source and optional children.
* If the source is found, it is written. If the wildcard character '*'
* exists as the last character in the path, then all the children are
* written recursively.
*/
void
write(PropertyStream& stream, std::string const& path);
/** Parse the dot-delimited Source path and return the result.
The first value will be a pointer to the Source object corresponding
to the given path. If no Source object exists, then the first value
will be nullptr and the second value will be undefined.
The second value is a boolean indicating whether or not the path string
specifies the wildcard character '*' as the last character.
print statement examples
"parent.child" prints child and all of its children
"parent.child." start at the parent and print down to child
"parent.grandchild" prints nothing- grandchild not direct descendent
"parent.grandchild." starts at the parent and prints down to grandchild
"parent.grandchild.*" starts at parent, print through grandchild
children
*/
/**
* Parse the dot-delimited Source path and return the result.
* The first value will be a pointer to the Source object corresponding
* to the given path. If no Source object exists, then the first value
* will be nullptr and the second value will be undefined.
* The second value is a boolean indicating whether or not the path string
* specifies the wildcard character '*' as the last character.
*
* print statement examples
* "parent.child" prints child and all of its children
* "parent.child." start at the parent and print down to child
* "parent.grandchild" prints nothing- grandchild not direct descendent
* "parent.grandchild." starts at the parent and prints down to grandchild
* "parent.grandchild.*" starts at parent, print through grandchild
* children
*/
std::pair<Source*, bool>
find(std::string path);
@@ -401,9 +420,10 @@ public:
//--------------------------------------------------------------------------
/** Subclass override.
The default version does nothing.
*/
/**
* Subclass override.
* The default version does nothing.
*/
virtual void
onWrite(Map&);
};

View File

@@ -7,7 +7,9 @@
namespace beast {
/** Wraps a Journal::Sink to prefix its output with a string. */
/**
* Wraps a Journal::Sink to prefix its output with a string.
*/
// A WrappedSink both is a Sink and has a Sink:
// o It inherits from Sink so it has the correct interface.

View File

@@ -4,22 +4,23 @@
namespace beast {
/** Zero allows classes to offer efficient comparisons to zero.
Zero is a struct to allow classes to efficiently compare with zero without
requiring an rvalue construction.
It's often the case that we have classes which combine a number and a unit.
In such cases, comparisons like t > 0 or t != 0 make sense, but comparisons
like t > 1 or t != 1 do not.
The class Zero allows such comparisons to be easily made.
The comparing class T either needs to have a method called signum() which
returns a positive number, 0, or a negative; or there needs to be a signum
function which resolves in the namespace which takes an instance of T and
returns a positive, zero or negative number.
*/
/**
* Zero allows classes to offer efficient comparisons to zero.
*
* Zero is a struct to allow classes to efficiently compare with zero without
* requiring an rvalue construction.
*
* It's often the case that we have classes which combine a number and a unit.
* In such cases, comparisons like t > 0 or t != 0 make sense, but comparisons
* like t > 1 or t != 1 do not.
*
* The class Zero allows such comparisons to be easily made.
*
* The comparing class T either needs to have a method called signum() which
* returns a positive number, 0, or a negative; or there needs to be a signum
* function which resolves in the namespace which takes an instance of T and
* returns a positive, zero or negative number.
*/
struct Zero
{
@@ -28,7 +29,9 @@ struct Zero
inline constexpr Zero kZero{};
/** Default implementation of signum calls the method on the class. */
/**
* Default implementation of signum calls the method on the class.
*/
template <typename T>
auto
signum(T const& t)

View File

@@ -4,7 +4,9 @@
namespace beast {
/** Makes T const or non const depending on a bool. */
/**
* Makes T const or non const depending on a bool.
*/
template <bool IsConst, class T>
struct MaybeConst
{
@@ -13,7 +15,9 @@ struct MaybeConst
conditional_t<IsConst, typename std::remove_const<T>::type const, std::remove_const_t<T>>;
};
/** Alias for omitting `typename`. */
/**
* Alias for omitting `typename`.
*/
template <bool IsConst, class T>
using maybe_const_t = MaybeConst<IsConst, T>::type;

View File

@@ -6,11 +6,12 @@
namespace beast {
/** RAII temporary directory.
The directory and all its contents are deleted when
the instance of `temp_dir` is destroyed.
*/
/**
* RAII temporary directory.
*
* The directory and all its contents are deleted when
* the instance of `temp_dir` is destroyed.
*/
class TempDir
{
boost::filesystem::path path_;
@@ -22,7 +23,9 @@ public:
operator=(TempDir const&) = delete;
#endif
/// Construct a temporary directory.
/**
* Construct a temporary directory.
*/
TempDir()
{
auto const dir = boost::filesystem::temp_directory_path();
@@ -33,7 +36,9 @@ public:
boost::filesystem::create_directory(path_);
}
/// Destroy a temporary directory.
/**
* Destroy a temporary directory.
*/
~TempDir()
{
// use non-throwing calls in the destructor
@@ -42,17 +47,20 @@ public:
// TODO: warn/notify if ec set ?
}
/// Get the native path for the temporary directory
/**
* Get the native path for the temporary directory
*/
[[nodiscard]] std::string
path() const
{
return path_.string();
}
/** Get the native path for the a file.
The file does not need to exist.
*/
/**
* Get the native path for the a file.
*
* The file does not need to exist.
*/
[[nodiscard]] std::string
file(std::string const& name) const
{

View File

@@ -85,14 +85,15 @@ XorShiftEngine<Unused>::murmurhash3(result_type x) -> result_type
} // namespace detail
/** XOR-shift Generator.
Meets the requirements of UniformRandomNumberGenerator.
Simple and fast RNG based on:
http://xorshift.di.unimi.it/xorshift128plus.c
does not accept seed==0
*/
/**
* XOR-shift Generator.
*
* Meets the requirements of UniformRandomNumberGenerator.
*
* Simple and fast RNG based on:
* http://xorshift.di.unimi.it/xorshift128plus.c
* does not accept seed==0
*/
using xor_shift_engine = detail::XorShiftEngine<>;
} // namespace beast

View File

@@ -24,42 +24,49 @@ enum class Type : std::uint8_t {
class Condition
{
public:
/** The largest binary condition we support.
@note This value will be increased in the future, but it
must never decrease, as that could cause conditions
that were previously considered valid to no longer
be allowed.
*/
/**
* The largest binary condition we support.
*
* @note This value will be increased in the future, but it
* must never decrease, as that could cause conditions
* that were previously considered valid to no longer
* be allowed.
*/
static constexpr std::size_t kMaxSerializedCondition = 128;
/** Load a condition from its binary form
@param s The buffer containing the fulfillment to load.
@param ec Set to the error, if any occurred.
The binary format for a condition is specified in the
cryptoconditions RFC. See:
https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.2
*/
/**
* Load a condition from its binary form
*
* @param s The buffer containing the fulfillment to load.
* @param ec Set to the error, if any occurred.
*
* The binary format for a condition is specified in the
* cryptoconditions RFC. See:
*
* https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.2
*/
static std::unique_ptr<Condition>
deserialize(Slice s, std::error_code& ec);
public:
Type type;
/** An identifier for this condition.
This fingerprint is meant to be unique only with
respect to other conditions of the same type.
*/
/**
* An identifier for this condition.
*
* This fingerprint is meant to be unique only with
* respect to other conditions of the same type.
*/
Buffer fingerprint;
/** The cost associated with this condition. */
/**
* The cost associated with this condition.
*/
std::uint32_t cost;
/** For compound conditions, set of conditions includes */
/**
* For compound conditions, set of conditions includes
*/
std::set<Type> subtypes;
Condition(Type t, std::uint32_t c, Slice fp) : type(t), fingerprint(fp), cost(c)

View File

@@ -14,64 +14,73 @@ namespace xrpl::cryptoconditions {
struct Fulfillment
{
public:
/** The largest binary fulfillment we support.
@note This value will be increased in the future, but it
must never decrease, as that could cause fulfillments
that were previously considered valid to no longer
be allowed.
*/
/**
* The largest binary fulfillment we support.
*
* @note This value will be increased in the future, but it
* must never decrease, as that could cause fulfillments
* that were previously considered valid to no longer
* be allowed.
*/
static constexpr std::size_t kMaxSerializedFulfillment = 256;
/** Load a fulfillment from its binary form
@param s The buffer containing the fulfillment to load.
@param ec Set to the error, if any occurred.
The binary format for a fulfillment is specified in the
cryptoconditions RFC. See:
https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.3
*/
/**
* Load a fulfillment from its binary form
*
* @param s The buffer containing the fulfillment to load.
* @param ec Set to the error, if any occurred.
*
* The binary format for a fulfillment is specified in the
* cryptoconditions RFC. See:
*
* https://tools.ietf.org/html/draft-thomas-crypto-conditions-02#section-7.3
*/
static std::unique_ptr<Fulfillment>
deserialize(Slice s, std::error_code& ec);
public:
virtual ~Fulfillment() = default;
/** Returns the fulfillment's fingerprint:
The fingerprint is an octet string uniquely
representing this fulfillment's condition
with respect to other conditions of the
same type.
*/
/**
* Returns the fulfillment's fingerprint:
*
* The fingerprint is an octet string uniquely
* representing this fulfillment's condition
* with respect to other conditions of the
* same type.
*/
[[nodiscard]] virtual Buffer
fingerprint() const = 0;
/** Returns the type of this condition. */
/**
* Returns the type of this condition.
*/
[[nodiscard]] virtual Type
type() const = 0;
/** Validates a fulfillment. */
/**
* Validates a fulfillment.
*/
[[nodiscard]] virtual bool
validate(Slice data) const = 0;
/** Calculates the cost associated with this fulfillment. *
The cost function is deterministic and depends on the
type and properties of the condition and the fulfillment
that the condition is generated from.
*/
/**
* Calculates the cost associated with this fulfillment. *
*
* The cost function is deterministic and depends on the
* type and properties of the condition and the fulfillment
* that the condition is generated from.
*/
[[nodiscard]] virtual std::uint32_t
cost() const = 0;
/** Returns the condition associated with the given fulfillment.
This process is completely deterministic. All implementations
will, if compliant, produce the identical condition for the
same fulfillment.
*/
/**
* Returns the condition associated with the given fulfillment.
*
* This process is completely deterministic. All implementations
* will, if compliant, produce the identical condition for the
* same fulfillment.
*/
[[nodiscard]] virtual Condition
condition() const = 0;
};
@@ -90,36 +99,40 @@ operator!=(Fulfillment const& lhs, Fulfillment const& rhs)
return !(lhs == rhs);
}
/** Determine whether the given fulfillment and condition match */
/**
* Determine whether the given fulfillment and condition match
*/
bool
match(Fulfillment const& f, Condition const& c);
/** Verify if the given message satisfies the fulfillment.
@param f The fulfillment
@param c The condition
@param m The message
@note the message is not relevant for some conditions
and a fulfillment will successfully satisfy its
condition for any given message.
*/
/**
* Verify if the given message satisfies the fulfillment.
*
* @param f The fulfillment
* @param c The condition
* @param m The message
*
* @note the message is not relevant for some conditions
* and a fulfillment will successfully satisfy its
* condition for any given message.
*/
bool
validate(Fulfillment const& f, Condition const& c, Slice m);
/** Verify a cryptoconditional trigger.
A cryptoconditional trigger is a cryptocondition with
an empty message.
When using such triggers, it is recommended that the
trigger be of type preimage, prefix or threshold. If
a signature type is used (i.e. Ed25519 or RSA-SHA256)
then the Ed25519 or RSA keys should be single-use keys.
@param f The fulfillment
@param c The condition
*/
/**
* Verify a cryptoconditional trigger.
*
* A cryptoconditional trigger is a cryptocondition with
* an empty message.
*
* When using such triggers, it is recommended that the
* trigger be of type preimage, prefix or threshold. If
* a signature type is used (i.e. Ed25519 or RSA-SHA256)
* then the Ed25519 or RSA keys should be single-use keys.
*
* @param f The fulfillment
* @param c The condition
*/
bool
validate(Fulfillment const& f, Condition const& c);

View File

@@ -18,23 +18,25 @@ namespace xrpl::cryptoconditions {
class PreimageSha256 final : public Fulfillment
{
public:
/** The maximum allowed length of a preimage.
The specification does not specify a minimum supported
length, nor does it require all conditions to support
the same minimum length.
While future versions of this code will never lower
this limit, they may opt to raise it.
*/
/**
* The maximum allowed length of a preimage.
*
* The specification does not specify a minimum supported
* length, nor does it require all conditions to support
* the same minimum length.
*
* While future versions of this code will never lower
* this limit, they may opt to raise it.
*/
static constexpr std::size_t kMaxPreimageLength = 128;
/** Parse the payload for a PreimageSha256 condition
@param s A slice containing the DER encoded payload
@param ec indicates success or failure of the operation
@return the preimage, if successful; empty pointer otherwise.
*/
/**
* Parse the payload for a PreimageSha256 condition
*
* @param s A slice containing the DER encoded payload
* @param ec indicates success or failure of the operation
* @return the preimage, if successful; empty pointer otherwise.
*/
static std::unique_ptr<Fulfillment>
deserialize(Slice s, std::error_code& ec)
{

View File

@@ -21,9 +21,10 @@ using IniFileSections = std::unordered_map<std::string, std::vector<std::string>
//------------------------------------------------------------------------------
/** Holds a collection of configuration values.
A configuration file contains zero or more sections.
*/
/**
* Holds a collection of configuration values.
* A configuration file contains zero or more sections.
*/
class Section
{
private:
@@ -36,28 +37,34 @@ private:
using const_iterator = decltype(lookup_)::const_iterator;
public:
/** Create an empty section. */
/**
* Create an empty section.
*/
explicit Section(std::string name = "");
/** Returns the name of this section. */
/**
* Returns the name of this section.
*/
[[nodiscard]] std::string const&
name() const
{
return name_;
}
/** Returns all the lines in the section.
This includes everything.
*/
/**
* Returns all the lines in the section.
* This includes everything.
*/
[[nodiscard]] std::vector<std::string> const&
lines() const
{
return lines_;
}
/** Returns all the values in the section.
Values are non-empty lines which are not key/value pairs.
*/
/**
* Returns all the values in the section.
* Values are non-empty lines which are not key/value pairs.
*/
[[nodiscard]] std::vector<std::string> const&
values() const
{
@@ -84,7 +91,7 @@ public:
* Get the legacy value for this section.
*
* @return The retrieved value. A section with an empty legacy value returns
an empty string.
* an empty string.
*/
[[nodiscard]] std::string
legacy() const
@@ -99,28 +106,34 @@ public:
return lines_[0];
}
/** Set a key/value pair.
The previous value is discarded.
*/
/**
* Set a key/value pair.
* The previous value is discarded.
*/
void
set(std::string const& key, std::string const& value);
/** Append a set of lines to this section.
Lines containing key/value pairs are added to the map,
else they are added to the values list. Everything is
added to the lines list.
*/
/**
* Append a set of lines to this section.
* Lines containing key/value pairs are added to the map,
* else they are added to the values list. Everything is
* added to the lines list.
*/
void
append(std::vector<std::string> const& lines);
/** Append a line to this section. */
/**
* Append a line to this section.
*/
void
append(std::string const& line)
{
append(std::vector<std::string>{line});
}
/** Returns `true` if a key with the given name exists. */
/**
* Returns `true` if a key with the given name exists.
*/
[[nodiscard]] bool
exists(std::string const& name) const;
@@ -134,7 +147,9 @@ public:
return boost::lexical_cast<T>(iter->second);
}
/// Returns a value if present, else another value.
/**
* Returns a value if present, else another value.
*/
template <class T>
[[nodiscard]] T
valueOr(std::string const& name, T const& other) const
@@ -199,23 +214,27 @@ public:
//------------------------------------------------------------------------------
/** Holds unparsed configuration information.
The raw data sections are processed with intermediate parsers specific
to each module instead of being all parsed in a central location.
*/
/**
* Holds unparsed configuration information.
* The raw data sections are processed with intermediate parsers specific
* to each module instead of being all parsed in a central location.
*/
class BasicConfig
{
private:
std::unordered_map<std::string, Section> map_;
public:
/** Returns `true` if a section with the given name exists. */
/**
* Returns `true` if a section with the given name exists.
*/
[[nodiscard]] bool
exists(std::string const& name) const;
/** Returns the section with the given name.
If the section does not exist, an empty section is returned.
*/
/**
* Returns the section with the given name.
* If the section does not exist, an empty section is returned.
*/
/** @{ */
Section&
section(std::string const& name);
@@ -236,37 +255,39 @@ public:
}
/** @} */
/** Overwrite a key/value pair with a command line argument
If the section does not exist it is created.
The previous value, if any, is overwritten.
*/
/**
* Overwrite a key/value pair with a command line argument
* If the section does not exist it is created.
* The previous value, if any, is overwritten.
*/
void
overwrite(std::string const& section, std::string const& key, std::string const& value);
/** Remove all the key/value pairs from the section.
/**
* Remove all the key/value pairs from the section.
*/
void
deprecatedClearSection(std::string const& section);
/**
* Set a value that is not a key/value pair.
* Set a value that is not a key/value pair.
*
* The value is stored as the section's first value and may be retrieved
* through section::legacy.
* The value is stored as the section's first value and may be retrieved
* through section::legacy.
*
* @param section Name of the section to modify.
* @param value Contents of the legacy value.
* @param section Name of the section to modify.
* @param value Contents of the legacy value.
*/
void
legacy(std::string const& section, std::string value);
/**
* Get the legacy value of a section. A section with a
* single-line value may be retrieved as a legacy value.
* Get the legacy value of a section. A section with a
* single-line value may be retrieved as a legacy value.
*
* @param sectionName Retrieve the contents of this section's
* legacy value.
* @return Contents of the legacy value.
* @param sectionName Retrieve the contents of this section's
* legacy value.
* @return Contents of the legacy value.
*/
[[nodiscard]] std::string
legacy(std::string const& sectionName) const;
@@ -289,11 +310,12 @@ protected:
//------------------------------------------------------------------------------
/** Set a value from a configuration Section
If the named value is not found or doesn't parse as a T,
the variable is unchanged.
@return `true` if value was set.
*/
/**
* Set a value from a configuration Section
* If the named value is not found or doesn't parse as a T,
* the variable is unchanged.
* @return `true` if value was set.
*/
template <class T>
bool
set(T& target, std::string const& name, Section const& section)
@@ -312,11 +334,12 @@ set(T& target, std::string const& name, Section const& section)
return foundAndValid;
}
/** Set a value from a configuration Section
If the named value is not found or doesn't cast to T,
the variable is assigned the default.
@return `true` if the named value was found and is valid.
*/
/**
* Set a value from a configuration Section
* If the named value is not found or doesn't cast to T,
* the variable is assigned the default.
* @return `true` if the named value was found and is valid.
*/
template <class T>
bool
set(T& target, T const& defaultValue, std::string const& name, Section const& section)
@@ -327,10 +350,11 @@ set(T& target, T const& defaultValue, std::string const& name, Section const& se
return foundAndValid;
}
/** Retrieve a key/value pair from a section.
@return The value string converted to T if it exists
and can be parsed, or else defaultValue.
*/
/**
* Retrieve a key/value pair from a section.
* @return The value string converted to T if it exists
* and can be parsed, or else defaultValue.
*/
// NOTE This routine might be more clumsy than the previous two
template <class T = std::string>
T

View File

@@ -30,8 +30,8 @@ namespace xrpl {
* the caller that they should drop the closure and cancel their operation.
* `join` blocks until all existing closure substitutes are destroyed.
*
* \tparam Ret The return type of the closure.
* \tparam Args The argument types of the closure.
* @tparam Ret The return type of the closure.
* @tparam Args The argument types of the closure.
*/
template <typename Ret, typename... Args>
class ClosureCounter
@@ -131,18 +131,21 @@ public:
ClosureCounter&
operator=(ClosureCounter const&) = delete;
/** Destructor verifies all in-flight closures are complete. */
/**
* Destructor verifies all in-flight closures are complete.
*/
~ClosureCounter()
{
using namespace std::chrono_literals;
join("ClosureCounter", 1s, debugLog());
}
/** Returns once all counted in-flight closures are destroyed.
@param name Name reported if join time exceeds wait.
@param wait If join() exceeds this duration report to Journal.
@param j Journal written to if wait is exceeded.
/**
* Returns once all counted in-flight closures are destroyed.
*
* @param name Name reported if join time exceeds wait.
* @param wait If join() exceeds this duration report to Journal.
* @param j Journal written to if wait is exceeded.
*/
void
join(char const* name, std::chrono::milliseconds wait, beast::Journal j)
@@ -160,13 +163,14 @@ public:
}
}
/** Wrap the passed closure with a reference counter.
@param closure Closure that accepts Args parameters and returns Ret.
@return If join() has been called returns std::nullopt. Otherwise
returns a std::optional that wraps closure with a
reference counter.
*/
/**
* Wrap the passed closure with a reference counter.
*
* @param closure Closure that accepts Args parameters and returns Ret.
* @return If join() has been called returns std::nullopt. Otherwise
* returns a std::optional that wraps closure with a
* reference counter.
*/
template <class Closure>
std::optional<Substitute<Closure>>
wrap(Closure&& closure)
@@ -180,19 +184,22 @@ public:
return ret;
}
/** Current number of Closures outstanding. Only useful for testing. */
/**
* Current number of Closures outstanding. Only useful for testing.
*/
int
count() const
{
return closureCount_;
}
/** Returns true if this has been joined.
Even if true is returned, counted closures may still be in flight.
However if (joined() && (count() == 0)) there should be no more
counted closures in flight.
*/
/**
* Returns true if this has been joined.
*
* Even if true is returned, counted closures may still be in flight.
* However if (joined() && (count() == 0)) there should be no more
* counted closures in flight.
*/
bool
joined() const
{

View File

@@ -4,8 +4,10 @@
namespace xrpl {
/// Coroutine stack size (1.5 MB). Increased from 1 MB because
/// ASAN-instrumented deep call stacks exceeded the original limit.
/**
* Coroutine stack size (1.5 MB). Increased from 1 MB because
* ASAN-instrumented deep call stacks exceeded the original limit.
*/
constexpr std::size_t kCoroStackSize = 1536 * 1024;
template <class F>

View File

@@ -75,19 +75,21 @@ any(HashRouterFlags flags)
class Config;
/** Routing table for objects identified by hash.
This table keeps track of which hashes have been received by which peers.
It is used to manage the routing and broadcasting of messages in the peer
to peer overlay.
*/
/**
* Routing table for objects identified by hash.
*
* This table keeps track of which hashes have been received by which peers.
* It is used to manage the routing and broadcasting of messages in the peer
* to peer overlay.
*/
class HashRouter
{
public:
// The type here *MUST* match the type of Peer::id_t
using PeerShortID = std::uint32_t;
/** Structure used to customize @ref HashRouter behavior.
/**
* Structure used to customize @ref HashRouter behavior.
*
* Even though these items are configurable, they are undocumented. Don't
* change them unless there is a good reason, and network-wide coordination
@@ -97,22 +99,27 @@ public:
*/
struct Setup
{
/// Default constructor
/**
* Default constructor
*/
explicit Setup() = default;
using seconds = std::chrono::seconds;
/** Expiration time for a hash entry
/**
* Expiration time for a hash entry
*/
seconds holdTime{300};
/** Amount of time required before a relayed item will be relayed again.
/**
* Amount of time required before a relayed item will be relayed again.
*/
seconds relayTime{30};
};
private:
/** An entry in the routing table.
/**
* An entry in the routing table.
*/
class Entry : public CountedObject<Entry>
{
@@ -138,26 +145,31 @@ private:
flags_ |= flagsToSet;
}
/** Return set of peers we've relayed to and reset tracking */
/**
* Return set of peers we've relayed to and reset tracking
*/
std::set<PeerShortID>
releasePeerSet()
{
return std::move(peers_);
}
/** Return seated relay time point if the message has been relayed */
/**
* Return seated relay time point if the message has been relayed
*/
[[nodiscard]] std::optional<Stopwatch::time_point>
relayed() const
{
return relayed_;
}
/** Determines if this item should be relayed.
Checks whether the item has been recently relayed.
If it has, return false. If it has not, update the
last relay timestamp and return true.
*/
/**
* Determines if this item should be relayed.
*
* Checks whether the item has been recently relayed.
* If it has, return false. If it has not, update the
* last relay timestamp and return true.
*/
bool
shouldRelay(Stopwatch::time_point const& now, std::chrono::seconds relayTime)
{
@@ -203,11 +215,13 @@ public:
bool
addSuppressionPeer(uint256 const& key, PeerShortID peer);
/** Add a suppression peer and get message's relay status.
/**
* Add a suppression peer and get message's relay status.
* Return pair:
* element 1: true if the peer is added.
* element 2: optional is seated to the relay time point or
* is unseated if has not relayed yet. */
* is unseated if has not relayed yet.
*/
std::pair<bool, std::optional<Stopwatch::time_point>>
addSuppressionPeerWithStatus(uint256 const& key, PeerShortID peer);
@@ -222,28 +236,30 @@ public:
HashRouterFlags& flags,
std::chrono::seconds txInterval);
/** Set the flags on a hash.
@return `true` if the flags were changed. `false` if unchanged.
*/
/**
* Set the flags on a hash.
*
* @return `true` if the flags were changed. `false` if unchanged.
*/
bool
setFlags(uint256 const& key, HashRouterFlags flags);
HashRouterFlags
getFlags(uint256 const& key);
/** Determines whether the hashed item should be relayed.
Effects:
If the item should be relayed, this function will not
return a seated optional again until the relay time has expired.
The internal set of peers will also be reset.
@return A `std::optional` set of peers which do not need to be
relayed to. If the result is unseated, the item should
_not_ be relayed.
*/
/**
* Determines whether the hashed item should be relayed.
*
* Effects:
*
* If the item should be relayed, this function will not
* return a seated optional again until the relay time has expired.
* The internal set of peers will also be reset.
*
* @return A `std::optional` set of peers which do not need to be
* relayed to. If the result is unseated, the item should
* _not_ be relayed.
*/
std::optional<std::set<PeerShortID>>
shouldRelay(uint256 const& key);

View File

@@ -83,12 +83,13 @@ class Job : public CountedObject<Job>
public:
using clock_type = std::chrono::steady_clock;
/** Default constructor.
Allows Job to be used as a container type.
This is used to allow things like jobMap [key] = value.
*/
/**
* Default constructor.
*
* Allows Job to be used as a container type.
*
* This is used to allow things like jobMap [key] = value.
*/
// VFALCO NOTE I'd prefer not to have a default constructed object.
// What is the semantic meaning of a Job with no associated
// function? Having the invariant "all Job objects refer to
@@ -108,7 +109,9 @@ public:
[[nodiscard]] JobType
getType() const;
/** Returns the time when the job was queued. */
/**
* Returns the time when the job was queued.
*/
[[nodiscard]] clock_type::time_point const&
queueTime() const;

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