mirror of
https://github.com/XRPLF/rippled.git
synced 2026-09-28 15:58:07 +00:00
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.