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