18 auto &&
getId(
const T &e)
const {
return e.getId(); }
39template <
typename T,
typename Adapter = PassthroughAdapter<T>>
47 typename std::remove_reference<decltype(std::declval<Adapter &>().getId(
48 std::declval<T &>()))>::type;
55 std::atomic<RadixElement>
root;
82 root.load().decrementRefCount();
101 rhs.root =
root.load();
130 if (leaf ==
nullptr ||
getId(*leaf) != key) {
140 T
const *ptr =
const_cast<RadixTree *
>(
this)->
get(key).release();
144 template <
typename Callable>
bool forEachLeaf(Callable &&func)
const {
149#define SEEK_LEAF_LOOP() \
150 RadixElement e = eptr->load(); \
154 while (e.isNode()) { \
156 auto nptr = e.getNode(); \
157 if (!nptr->isShared()) { \
158 eptr = nptr->get(level--, key); \
163 auto copy = std::make_unique<RadixNode>(*nptr); \
164 if (!eptr->compare_exchange_strong(e, RadixElement(copy.get()))) { \
170 e.decrementRefCount(); \
171 eptr = copy->get(level--, key); \
185 std::atomic<RadixElement> *eptr = &
root;
189 T *leaf = e.getLeaf();
190 if (leaf ==
nullptr ||
getId(*leaf) != key) {
216 std::atomic<RadixElement> *eptr = &
root;
222 if (e.getLeaf() ==
nullptr) {
223 if (eptr->compare_exchange_strong(e,
237 if (key == leafKey) {
243 auto newChild = std::make_unique<RadixNode>(level, leafKey, e);
244 if (eptr->compare_exchange_strong(e,
257 template <
typename Callable>
261 if (leaf !=
nullptr) {
269 [&](
const std::atomic<RadixElement> *pElement) {
336 return reinterpret_cast<T *
>(
raw & ~DISCRIMINANT);
351 std::array<RadixElement, CHILD_PER_LEVEL>
358 get(level, key)->store(e);
363 e.decrementRefCount();
370 e.incrementRefCount();
377 std::atomic<RadixElement> *
get(uint32_t level,
const KeyType &key) {
383 template <
typename Callable>
bool forEachChild(Callable &&func)
const {
394 static_assert(
alignof(T) > 1,
"T's alignment must be 2 or more.");
395 static_assert(
alignof(RadixNode) > 1,
396 "RadixNode alignment must be 2 or more.");
static void synchronize()
T * get()
Get allows to access the undelying pointer.
static RCUPtr acquire(T *&ptrIn)
Acquire ownership of some pointer.
T * release()
Release transfers ownership of the pointer from RCUPtr to the caller.
static RCUPtr copy(T *ptr)
Construct a new RCUPtr without transferring owership.
auto && getId(const T &e) const
bool getDiscriminant() const
bool isNode() const
Node features.
static const uintptr_t DISCRIMINANT
const T * getLeaf() const
bool isLeaf() const
Leaf features.
RadixElement(RadixNode *nodeIn) noexcept
void incrementRefCount()
RadixElement is designed to be a dumb wrapper.
const RadixNode * getNode() const
RadixElement(T *leafIn) noexcept
bool forEachChild(Callable &&func) const
RadixNode & operator=(const RadixNode &)=delete
std::atomic< RadixElement > * get(uint32_t level, const KeyType &key)
RadixNode(uint32_t level, const KeyType &key, RadixElement e)
std::array< RadixElement, CHILD_PER_LEVEL > non_atomic_children_DO_NOT_USE
RadixNode(const RadixNode &rhs)
std::array< std::atomic< RadixElement >, CHILD_PER_LEVEL > children
IMPLEMENT_RCU_REFCOUNT(uint64_t)
This is a radix tree storing values identified by a unique key.
static const uint32_t TOP_LEVEL
RCUPtr< T > remove(const KeyType &key)
Remove an element from the tree.
KeyType getId(const T &value) const
static const size_t CHILD_PER_LEVEL
RadixTree(RadixTree &&src)
Move semantic.
typename std::remove_reference< decltype(std::declval< Adapter & >().getId(std::declval< T & >()))>::type KeyType
bool forEachLeaf(RadixElement e, Callable &&func) const
RadixTree & operator=(const RadixTree &rhs)
static const size_t KEY_BITS
std::atomic< RadixElement > root
RadixTree(const RadixTree &src)
Copy semantic.
RCUPtr< const T > get(const KeyType &key) const
bool insert(const KeyType &key, RCUPtr< T > value)
RCUPtr< T > get(const KeyType &key)
Get the value corresponding to a key.
RadixTree & operator=(RadixTree &&rhs)
bool forEachLeaf(Callable &&func) const
bool insert(const RCUPtr< T > &value)
Insert a value into the tree.