Files
rippled/include
Bart c2b1c5a551 refactor: 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 the pointee's atomic strong count and the
original's destructor then released it. `releaseNode()` moves the pointer out
instead, a plain swap with no atomic at all. `dirtyUp` and `delItem` walk up to
64 levels per insert or delete on the ledger write path, so this removes up to 64
increments and 64 release sequences per call. The sites that also want the ID
read `top().second` first, which costs the same either way, and the two that read
without popping now bind a reference.

`staticPointerCast` and `dynamicPointerCast` had only a `TT const&` overload, so
no caller could move into them. Each gains an rvalue overload, tied to
`SharedIntrusive<TT>&&` rather than a bare `TT&&` so it cannot bind to an lvalue
in preference to the const-ref one, and the sites that own a discarded pointer
now pass `std::move`. `SharedIntrusive`'s move constructors also become
`noexcept`, so a `std::vector` of them relocates by moving; without that,
`move_if_noexcept` copies every element, since the type is copy constructible.

Three of the casts become static, and a fourth that already was gains the same
live type test, so no traversal path is left paying for a `dynamic_cast`.
`dirtyUp` and `delItem`'s loop rest on every remaining entry being inner, which
holds but was only an `XRPL_ASSERT`, a no-op under `NDEBUG`, so both report
`UNREACHABLE` and throw rather than writing through a misread node.
`updateGiveItem` and `delItem`'s leaf cast need the test for a different reason:
an absent tag leaves an inner node on top, which the public API permits, so they
return false rather than aborting an instrumented build. A test pins that.
2026-09-23 21:48:41 +02:00
..