55 #ifndef __UT_ARTMAP_H__
56 #define __UT_ARTMAP_H__
75 #if defined(__i386__) || defined(__amd64__)
76 #include <emmintrin.h>
77 #include <immintrin.h>
78 #elif defined (_WIN32)
83 #if defined(USE_MEMORY_RESOURCE)
84 #include <memory_resource>
85 namespace UT_PMR = std::pmr;
88 #if defined(LINUX) || defined(MBSD)
89 #if defined(__i386) || defined(__amd64)
90 #define SUPPORT_FAST_STR
92 #elif !defined(__clang__) && defined(_M_AMD64)
93 #define SUPPORT_FAST_STR
96 #define UT_VERIFY_ROOT UT_ASSERT(myRoot && !myRoot->hasValue())
100 template <
typename T>
108 template <
typename T>
113 template <
typename T>
118 template <
typename T>
127 #
if defined(USE_MEMORY_RESOURCE)
135 #
if defined(USE_MEMORY_RESOURCE)
150 template <
typename... Args>
167 virtual bool isFull()
const = 0;
193 if (child !=
nullptr)
195 child->
debug(wbuf, indent + 1);
197 }
while (child !=
nullptr);
216 myKey = stolen->myKey;
218 stolen->myPrefix.begin() - prefix_length,
219 stolen->myPrefix.end());
221 myValue = std::move(stolen->myValue);
223 stolen->moveChildren(ref);
244 const char*
start = child->myPrefix.begin() - node_prefix_length;
245 UT_ASSERT(start >= child->myKey.buffer());
246 child->myPrefix =
UT_StringView(start, child->myPrefix.end());
248 (*ref)->insertChild(ref, std::move(child));
267 const char* k = key.
data();
268 const char* p = node_prefix.
data();
271 #if defined(SUPPORT_FAST_STR) && !defined(ASAN_ENABLED)
272 static constexpr
exint theMaxSIMDLen = 16;
273 const int mode = _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_EACH
274 | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY;
275 while (n > theMaxSIMDLen)
277 const __m128i
data = _mm_loadu_si128(
278 reinterpret_cast<const __m128i*>(k));
279 const __m128i
prefix = _mm_loadu_si128(
280 reinterpret_cast<const __m128i*>(p));
282 int check_len =
std::min(n, theMaxSIMDLen);
283 int res = _mm_cmpestri(data, check_len, prefix, check_len, mode);
288 if (n < 16 && res == 16)
327 #if defined(USE_MEMORY_RESOURCE)
328 UT_PMR::polymorphic_allocator<UT_ARTNode<T>> getAllocator()
334 template <
typename NodeT>
337 #if defined(USE_MEMORY_RESOURCE)
338 UT_PMR::polymorphic_allocator<NodeT> alloc(myAllocator);
339 NodeT* node = alloc.allocate(1);
357 #if defined(USE_MEMORY_RESOURCE)
358 UT_PMR::polymorphic_allocator<UT_ARTNode<T>> myAllocator;
370 template <
typename T>
374 #if defined(USE_MEMORY_RESOURCE)
375 auto alloc = ptr->getAllocator();
377 alloc.deallocate(ptr, 1);
384 template <
typename T>
400 return myCurrent == it.myCurrent;
404 return !(*
this == it);
428 bool hasValue()
const {
return myCurrent && myCurrent->hasValue(); }
430 const T&
value()
const {
return *myCurrent->value(); }
431 T&
value() {
return *myCurrent->value(); }
442 if (myCurrent && !myCurrent->hasValue())
446 void findNextValue_()
451 bool has_seen =
false;
459 myNodeStack.
emplace_back(std::make_pair(myCurrent, myIndex));
463 else if (!myNodeStack.
isEmpty())
465 auto&& [node,
index] = myNodeStack.
last();
479 }
while (myCurrent !=
nullptr && (has_seen || !myCurrent->hasValue()));
490 template <
typename T>
497 #if defined(USE_MEMORY_RESOURCE)
523 return theType.asHolder();
525 bool isFull()
const override;
543 template <
typename T>
550 #if defined(USE_MEMORY_RESOURCE)
566 for (
int i = 16; i-->0; )
573 return theType.asHolder();
575 bool isFull()
const override;
592 unsigned bitfield = 0;
593 #if defined(__i386) || defined(__amd64)
595 __m128i key_vec = _mm_set1_epi8(c);
596 __m128i results = _mm_cmpeq_epi8(
598 bitfield = _mm_movemask_epi8(results) &
mask;
600 for (
int i = 0; i < 16; ++i)
603 bitfield |= (1 << i);
612 return __builtin_ctz(bitfield);
614 return _tzcnt_u32(bitfield);
625 template <
typename T>
632 #if defined(USE_MEMORY_RESOURCE)
648 for (
int i = 48; i-->0; )
654 return theType.asHolder();
656 bool isFull()
const override;
675 template <
typename T>
682 #if defined(USE_MEMORY_RESOURCE)
697 for (
int i = 256; i-->0; )
704 return theType.asHolder();
706 bool isFull()
const override;
725 template <
typename T>
738 #if defined(USE_MEMORY_RESOURCE)
740 UT_ARTMap(UT_PMR::get_default_resource())
743 explicit UT_ARTMap(UT_PMR::memory_resource* resource) :
744 myAllocator(resource)
749 myRoot = createBaseNode(
756 #if defined(USE_MEMORY_RESOURCE)
757 UT_PMR::polymorphic_allocator<Node> alloc(myAllocator);
758 alloc.destroy(myRoot);
759 alloc.deallocate(myRoot, 1);
771 bool allow_partial =
false)
773 return insert_(name, allow_partial, data);
783 bool allow_partial =
false)
785 return insert_(name, allow_partial,
value);
791 template <
typename... Args>
797 name,
false, std::forward<Args>(
args)...);
803 typename std::enable_if_t<std::is_default_constructible_v<T>,
T&>
806 auto&& [it, inserted] = insert_(key,
false);
809 if (it.myCurrent && inserted)
811 it.myCurrent->emplace();
820 typename std::enable_if_t<std::is_default_constructible_v<T>,
T&>
823 auto&& [it, inserted] = insert_(key,
false);
826 if (it.myCurrent && inserted)
828 it.myCurrent->emplace();
840 Node* last_partial =
nullptr;
842 while (!prefix.
isEmpty() && child !=
nullptr)
849 prefix, found_prefix);
850 if (common_length == found_prefix.length())
857 && common_length != found_prefix.length())
867 last_partial = child;
889 else if (last_partial !=
nullptr && last_partial->
hasValue())
906 myRoot->
debug(wbuf, 0);
912 return doErase_(prefix);
918 #if defined(USE_MEMORY_RESOURCE)
919 UT_PMR::polymorphic_allocator<Node> alloc(myAllocator);
920 alloc.destroy(myRoot);
921 alloc.deallocate(myRoot, 1);
926 myRoot = createBaseNode(
933 return myRoot->childCount();
963 template <
typename... Args>
964 std::pair<iterator, bool> insert_(
970 return std::make_pair(
end(),
false);
972 bool inserted =
false;
973 Node* node = doInsert_(name, inserted);
975 UT_ASSERT((inserted && node !=
nullptr) || !inserted);
976 if (node && inserted)
978 node->emplace(std::forward<Args>(
args)...);
979 node->setAllowsPartial(allows_partial);
981 return std::make_pair(
iterator(node), inserted);
991 Node** current = &myRoot;
993 bool removed =
false;
995 while (!removed && current && prefix)
997 Node** node = (*current)->findPartialPrefixChild(prefix);
1000 if (node ==
nullptr)
1005 exint common_length = (*current)->getCommonPrefixLength(
1006 prefix, (*node)->myPrefix);
1008 if (common_length == prefix.length())
1012 if (!(*node)->hasValue())
1017 if ((*node)->isLeaf())
1019 auto stolen = (*current)->stealChild(current, *node);
1025 removed_node->moveChildren(current);
1028 if ((*current) != myRoot)
1029 (*current)->compress(current);
1033 prefix.removePrefix(common_length);
1046 #if defined(USE_MEMORY_RESOURCE)
1047 UT_PMR::polymorphic_allocator<UT_ARTNode4<T>> alloc(myAllocator);
1049 alloc.construct(node, key, prefix, alloc);
1068 Node** current = &myRoot;
1071 while (current !=
nullptr && prefix.
length() > 0)
1074 if (node ==
nullptr)
1078 Node** inserted_node = (*current)->insertChild(
1079 current, createBaseNode(key, prefix));
1081 return (*inserted_node);
1085 const exint prefix_length = (*current)->getCommonPrefixLength(
1086 prefix, (*node)->myPrefix);
1089 if (prefix.
length() == (*node)->myPrefix.length()
1090 && prefix.
length() == prefix_length)
1092 inserted = !(*node)->hasValue();
1097 else if (prefix_length == (*node)->myPrefix.length())
1104 else if (prefix_length == prefix.
length())
1106 auto new_child = createBaseNode(key, prefix);
1112 stolen->myPrefix.removePrefix(prefix_length);
1115 new_child->insertChild(&ptr, std::move(stolen));
1118 Node** inserted_node = (*current)->insertChild(
1119 current, std::move(new_child));
1122 return (*inserted_node);
1135 ->stealChild(current, *node);
1138 auto parent = createBaseNode(key, item_prefix);
1140 erased_child->myPrefix.removePrefix(prefix_length);
1142 Node* ptr = parent.get();
1143 parent->insertChild(
1144 &ptr, std::move(erased_child));
1148 Node** inserted_node = parent->insertChild(
1149 &ptr, createBaseNode(key, prefix));
1153 (*current)->insertChild(current, std::move(parent));
1156 return *inserted_node;
1164 Node* myRoot =
nullptr;
1165 #if defined(USE_MEMORY_RESOURCE)
1166 UT_PMR::polymorphic_allocator<std::byte> myAllocator;
1171 template <std::
size_t N,
class T, std::enable_if_t<N == 0,
int> = 0>
1178 template <std::
size_t N,
class T, std::enable_if_t<N == 1,
int> = 0>
1187 template <
typename T>
1188 struct tuple_size<UT_ARTIterator<
T>>
1189 :
public std::integral_constant<std::size_t, 2>
1193 template <std::
size_t N,
typename T>
1194 struct tuple_element<
N, UT_ARTIterator<
T>>
1196 using type = decltype(get<N>(
1203 #endif // __UT_ARTMAP_H__
bool erase(const UT_StringRef &prefix)
bool operator!=(const UT_ARTIterator &it) const
The middle sized node with 16 max children.
SYS_NO_DISCARD_RESULT bool isEmpty() const
Returns true if the map has no items currently inserted.
UT_StringHolder key() const
The largest node size in the art map. The 256 node has at most 256 children.
UT_ARTNodePtr< parent_t > parent_ptr_t
parent_t * nextChild(int &index) override
SYS_NO_DISCARD_RESULT iterator begin()
Returns the beginning of an iterator used to traverse the full tree.
parent_t * nextChild(int &index) override
SYS_FORCE_INLINE void removeLast()
virtual ~UT_ARTNode()=default
parent_ptr_t stealChild(parent_t **ref, parent_t *child) override
GLsizei const GLfloat * value
UT_ARTNodePtr< parent_t > parent_ptr_t
std::ptrdiff_t difference_type
SYS_NO_DISCARD_RESULT iterator end()
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
bool isEmpty() const
Same as !isstring()
void emplace(Args &&...args)
void moveHeader(UT_ARTNode< T > &move_to)
void debug(UT_WorkBuffer &wbuf, unsigned indent=0) const
UT_ARTNode16(const UT_StringHolder &key, UT_StringView prefix)
SYS_NO_DISCARD_RESULT bool contains(const UT_StringHolder &prefix) const
Check if the tree contains the provided string.
parent_t * myChildren[256]
GLuint GLsizei GLsizei * length
UT_NON_COPYABLE(UT_ARTNode)
UT_ARTNode4(const UT_StringHolder &key, UT_StringView prefix)
parent_ptr_t stealChild(parent_t **ref, parent_t *child) override
ImageBuf OIIO_API min(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
bool operator==(const UT_ARTIterator &it) const
const UT_StringHolder & type() const override
The second largest node size with 48 max children.
const UT_StringHolder & type() const override
void moveChildren(UT_ARTNode< T > **ref)
SYS_FORCE_INLINE const value_type * value() const
int prefixToIndex_(char c) const
parent_t ** findPartialPrefixChild(const UT_StringView &prefix) override
void removePrefix(exint n)
exint getCommonPrefixLength(const UT_StringView &key, const UT_StringView &node_prefix)
decltype(get< N >(std::declval< UT_ARTIterator< T >>())) type
std::optional< T > UT_Optional
virtual UT_ARTNode< T > * nextChild(int &idx)=0
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
parent_t * myChildren[16]
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE const char * data() const noexcept
Returns a pointer to the first character of a view.
void debug(UT_WorkBuffer &wbuf) const
Write out the tree into the work buffer. This is pretty printed.
A utility class to do read-only operations on a subset of an existing string.
size_t appendFormat(const char *fmt, const Args &...args)
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE bool isEmpty() const
Returns true if the string is empty.
UT_ARTNodePtr< parent_t > parent_ptr_t
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE exint length() const
Returns the length of the string in bytes.
std::forward_iterator_tag iterator_category
exint emplace_back(S &&...s)
std::pair< iterator, bool > insert(const UT_StringHolder &name, const T &data, bool allow_partial=false)
unsigned char myChildKeys[16]
bool isFull() const override
SYS_NO_DISCARD_RESULT const_iterator end() const
virtual const UT_StringHolder & type() const =0
static const UT_StringHolder theEmptyString
SYS_NO_DISCARD_RESULT const_iterator begin() const
const UT_StringHolder & type() const override
void clear()
Clear out the tree.
bool isFull() const override
Iterator for traversing the adaptive radix tree.
UT_ARTNode(const UT_StringHolder &key, const UT_StringView &prefix)
UT_ARTIterator< T > iterator
SYS_NO_DISCARD_RESULT iterator find(UT_StringView prefix) const
Find the node based on the provided prefix.
UT_ARTIterator & operator++()
The smallest (also known as base node) node with 4 max children.
UT_NON_COPYABLE(UT_ARTNode48)
SYS_FORCE_INLINE bool isLeaf() const
#define SYS_NO_DISCARD_RESULT
UT_Optional< value_type > myValue
parent_t ** insertChild(parent_t **ref, parent_ptr_t child) override
SYS_NO_DISCARD_RESULT const_iterator cend() const
GLuint const GLchar * name
bool isFull() const override
std::enable_if_t< std::is_default_constructible_v< T >, T & > operator[](UT_StringHolder &&key)
const UT_StringHolder & type() const override
parent_t ** findPartialPrefixChild(const UT_StringView &prefix) override
UT_ARTNodePtr< parent_t > parent_ptr_t
parent_t ** insertChild(parent_t **ref, parent_ptr_t child) override
parent_t ** findPartialPrefixChild(const UT_StringView &prefix) override
parent_t ** insertChild(parent_t **ref, parent_ptr_t child) override
parent_ptr_t stealChild(parent_t **ref, parent_t *child) override
~UT_ARTNode256() override
virtual UT_ARTNodePtr< UT_ARTNode< T > > stealChild(UT_ARTNode **ref, UT_ARTNode *child)=0
const_reference operator*() const
virtual UT_ARTNode< T > ** findPartialPrefixChild(const UT_StringView &prefix)=0
parent_t ** insertChild(parent_t **ref, parent_ptr_t child) override
UT_ARTIterator operator++(int)
unsigned char myChildKeys[256]
std::pair< iterator, bool > emplace(const UT_StringHolder &name, Args &&...args)
std::pair< iterator, bool > insert(const UT_StringHolder &name, T &&value, bool allow_partial=false)
unsigned char myChildKeys[4]
SYS_FORCE_INLINE bool hasValue() const
UT_ARTNodePtr< NodeT > newNode()
virtual bool isFull() const =0
parent_t * nextChild(int &index) override
SYS_FORCE_INLINE void append(char character)
SYS_NO_DISCARD_RESULT const_iterator cbegin() const
GA_API const UT_StringHolder N
parent_t * nextChild(int &index) override
**If you just want to fire and args
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE const_iterator begin() const
Returns a constant iterator pointing to the beginning of the string.
UT_ARTNode256(const UT_StringHolder &key, UT_StringView prefix)
SYS_FORCE_INLINE value_type * value()
static void destroy(UT_ARTNode< T > *node)
UT_NON_COPYABLE(UT_ARTMap)
SYS_FORCE_INLINE void clear()
parent_t ** findPartialPrefixChild(const UT_StringView &prefix) override
UT_NON_COPYABLE(UT_ARTNode16)
UT_ARTMap()
Initialize an empty map.
void setAllowsPartial(bool allow)
std::enable_if_t< std::is_default_constructible_v< T >, T & > operator[](const UT_StringHolder &key)
parent_ptr_t stealChild(parent_t **ref, parent_t *child) override
virtual UT_ARTNode< T > ** insertChild(UT_ARTNode **ref, UT_ARTNodePtr< UT_ARTNode< T >> node)=0
void compress(UT_ARTNode< T > **ref)
parent_t * myChildren[48]
UT_UniquePtr< T, UT_ARTNodeDelete > UT_ARTNodePtr
SYS_FORCE_INLINE const UT_StringView & prefix() const
UT_NON_COPYABLE(UT_ARTNode256)
UT_NON_COPYABLE(UT_ARTNode4)
bool isFull() const override
UT_StringHolder key() const
const_pointer operator->() const
UT_ARTNode48(const UT_StringHolder &key, UT_StringView prefix)
bool isEmpty() const
Returns true iff there are no occupied elements in the array.
SYS_FORCE_INLINE bool allowsPartial() const