Files
rippled/include/xrpl/shamap/SHAMapInnerNode.h
2026-07-13 10:40:40 +00:00

217 lines
4.9 KiB
C++

#pragma once
#include <xrpl/basics/CountedObject.h>
#include <xrpl/basics/SHAMapHash.h>
#include <xrpl/basics/Slice.h>
#include <xrpl/protocol/Serializer.h>
#include <xrpl/shamap/SHAMapNodeID.h>
#include <xrpl/shamap/SHAMapTreeNode.h>
#include <xrpl/shamap/detail/TaggedPointer.h>
#include <atomic>
#include <cstdint>
#include <optional>
#include <string>
namespace xrpl {
class SHAMapInnerNode final : public SHAMapTreeNode, public CountedObject<SHAMapInnerNode>
{
public:
/**
* Each inner node has 16 children (the 'radix tree' part of the map)
*/
static constexpr unsigned int kBranchFactor = 16;
private:
/**
* Opaque type that contains the `hashes` array (array of type
* `SHAMapHash`) and the `children` array (array of type
* `intr_ptr::SharedPtr<SHAMapInnerNode>`).
*/
TaggedPointer hashesAndChildren_;
std::uint32_t fullBelowGen_ = 0;
std::uint16_t isBranch_ = 0;
/**
* A bitlock for the children of this node, with one bit per child
*/
mutable std::atomic<std::uint16_t> lock_ = 0;
/**
* Convert arrays stored in `hashesAndChildren_` so they can store the
* requested number of children.
*
* @param toAllocate allocate space for at least this number of children
* (must be <= branchFactor)
*
* @note the arrays may allocate more than the requested value in
* `toAllocate`. This is due to the implementation of TagPointer, which
* only supports allocating arrays of 4 different sizes.
*/
void
resizeChildArrays(std::uint8_t toAllocate);
/**
* Get the child's index inside the `hashes` or `children` array (stored in
* `hashesAndChildren_`.
*
* These arrays may or may not be sparse). The optional will be empty is an
* empty branch is requested and the arrays are sparse.
*
* @param i index of the requested child
*/
std::optional<int>
getChildIndex(int i) const;
/**
* Call the `f` callback for all 16 (branchFactor) branches - even if
* the branch is empty.
*
* @param f a one parameter callback function. The parameter is the
* child's hash.
*/
template <class F>
void
iterChildren(F&& f) const;
/**
* Call the `f` callback for all non-empty branches.
*
* @param f a two parameter callback function. The first parameter is
* the branch number, the second parameter is the index into the array.
* For dense formats these are the same, for sparse they may be
* different.
*/
template <class F>
void
iterNonEmptyChildIndexes(F&& f) const;
public:
explicit SHAMapInnerNode(std::uint32_t cowid, std::uint8_t numAllocatedChildren = 2);
SHAMapInnerNode(SHAMapInnerNode const&) = delete;
SHAMapInnerNode&
operator=(SHAMapInnerNode const&) = delete;
~SHAMapInnerNode() override;
// Needed to support intrusive weak pointers
void
partialDestructor() override;
SHAMapTreeNodePtr
clone(std::uint32_t cowid) const override;
SHAMapNodeType
getType() const override
{
return SHAMapNodeType::TnInner;
}
bool
isLeaf() const override
{
return false;
}
bool
isInner() const override
{
return true;
}
bool
isEmpty() const;
bool
isEmptyBranch(int m) const;
int
getBranchCount() const;
SHAMapHash const&
getChildHash(int m) const;
void
setChild(int m, SHAMapTreeNodePtr child);
void
shareChild(int m, SHAMapTreeNodePtr const& child);
SHAMapTreeNode*
getChildPointer(int branch);
SHAMapTreeNodePtr
getChild(int branch);
SHAMapTreeNodePtr
canonicalizeChild(int branch, SHAMapTreeNodePtr node);
// sync functions
bool
isFullBelow(std::uint32_t generation) const;
void
setFullBelowGen(std::uint32_t gen);
void
updateHash() override;
/**
* Recalculate the hash of all children and this node.
*/
void
updateHashDeep();
void
serializeForWire(Serializer&) const override;
void
serializeWithPrefix(Serializer&) const override;
std::string
getString(SHAMapNodeID const&) const override;
void
invariants(bool isRoot = false) const override;
static SHAMapTreeNodePtr
makeFullInner(Slice data, SHAMapHash const& hash, bool hashValid);
static SHAMapTreeNodePtr
makeCompressedInner(Slice data);
};
inline bool
SHAMapInnerNode::isEmpty() const
{
return isBranch_ == 0;
}
inline bool
SHAMapInnerNode::isEmptyBranch(int m) const
{
return (isBranch_ & (1 << m)) == 0;
}
inline int
SHAMapInnerNode::getBranchCount() const
{
return popcnt16(isBranch_);
}
inline bool
SHAMapInnerNode::isFullBelow(std::uint32_t generation) const
{
return fullBelowGen_ == generation;
}
inline void
SHAMapInnerNode::setFullBelowGen(std::uint32_t gen)
{
fullBelowGen_ = gen;
}
} // namespace xrpl