Files
rippled/include/xrpl/basics
Bart e41e469e02 perf: Move entries off NodePathStack instead of copying them
Five sites copied the top entry out and then popped it. `SHAMapTreeNodePtr` is
refcounted, so each copy bumped its atomic strong-ref count; `release()` moves
the pointer out instead, a plain pointer swap with no atomic. `SHAMapNodeID`
also derives from `CountedObject`, but `CountedObject` declares no move
constructor, so moving a `SHAMapNodeID` still runs its copy constructor;
`release()` saves nothing on the ID half of the pair. `dirtyUp` and `delItem`
walk up to 64 levels per insert or delete on the ledger write path, so this
removes up to 64 atomic operations per call, not 128. The two sites that read
without popping now bind a reference rather than copying.

`dirtyUp` and `delItem` both drop a `dynamicPointerCast`/null check for a
static cast, on the reasoning that by the time either receives the stack,
`addGiveItem`/`updateGiveItem` have already consumed the terminal leaf entry
via `release()`, so every remaining entry is provably an inner node. That
reasoning holds today, but an `XRPL_ASSERT` is a no-op under `NDEBUG`, so
both get a real `UNREACHABLE`-guarded check instead: a release build that
somehow violated the invariant would otherwise write through a
misinterpreted node via `setChild`, silent memory corruption in place of the
clean crash `dynamicPointerCast` used to produce. `updateGiveItem`'s own
cast needed the same treatment for a different reason: an absent tag leaves
an inner node on top of the stack, and the cast that followed the assertion
there would have reinterpreted an `SHAMapInnerNode` as a `SHAMapLeafNode`.
Replaced with `if (!top->isLeaf()) return false;`, pinned by a regression
test.

The `std::move` these sites previously applied to
`staticPointerCast`/`dynamicPointerCast` was dropped rather than fixed: both
only had a `TT const&` overload, so the move bound to that const ref and
copied anyway, silently defeating the `SHAMapTreeNodePtr` refcount saving
described above. Adds the missing rvalue overload to each, tied to
`SharedIntrusive<TT>&&` rather than a bare `TT&&` so it cannot also bind to
an lvalue in preference to the const-ref overload, and restores `std::move`
at the three call sites that own a soon-to-be-discarded pointer.
2026-08-18 10:20:12 -04:00
..
2026-07-06 15:22:02 +00:00

Basics

Utility functions and classes.

The module xrpl/basics should contain no dependencies on other modules.

Choosing an xrpld container.

  • std::vector

    • For ordered containers with most insertions or erases at the end.
  • std::deque

    • For ordered containers with most insertions or erases at the start or end.
  • std::list

    • For ordered containers with inserts and erases to the middle.
    • For containers with iterators stable over insert and erase.
    • Generally slower and bigger than std::vector or std::deque except for those cases.
  • std::set

    • For sorted containers.
  • xrpl::hash_set

    • Where inserts and contains need to be O(1).
    • For "small" sets, std::set might be faster and smaller.
  • xrpl::hardened_hash_set

The following container is deprecated

  • std::unordered_set
  • Use xrpl::hash_set instead, which uses a better hashing algorithm.
  • Or use xrpl::hardened_hash_set to prevent algorithmic complexity attacks.