HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
UT_ARTMap.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * NAME: UT_ARTMap.h
7  *
8  * COMMENTS:
9  *
10  */
11 
12 #ifndef __UT_ARTMAP_H__
13 #define __UT_ARTMAP_H__
14 
15 #include "UT_API.h"
16 
17 #include "UT_Array.h"
18 #include "UT_Assert.h"
19 #include "UT_Debug.h"
20 #include "UT_Optional.h"
21 #include "UT_StringHolder.h"
22 #include "UT_UniquePtr.h"
23 #include "UT_WorkBuffer.h"
24 
25 #include <SYS/SYS_Compiler.h>
26 #include <SYS/SYS_Platform.h>
28 
29 #include <cctype>
30 #include <variant>
31 
32 #if defined(__i386__) || defined(__amd64__)
33 #include <emmintrin.h>
34 #include <immintrin.h>
35 #elif defined (_WIN32)
36 #include <intrin.h>
37 #endif
38 
39 
40 #if defined(USE_MEMORY_RESOURCE)
41 #include <memory_resource>
42 namespace UT_PMR = std::pmr;
43 #endif
44 
45 #if defined(LINUX) || defined(MBSD)
46  #if defined(__i386) || defined(__amd64)
47  #define SUPPORT_FAST_STR
48  #endif
49 #elif !defined(__clang__) && defined(_M_AMD64)
50  #define SUPPORT_FAST_STR
51 #endif
52 
53 template <typename T>
54 class UT_ARTMap;
55 template <typename T>
56 class UT_ARTNode;
57 
59 {
60 public:
61  template <typename T>
62  void operator()(T* ptr);
63 
64 private:
65 };
66 template <typename T>
68 
69 template <typename T>
70 class UT_ARTNode
71 {
72 public:
73  using value_type = T;
74 
75  explicit UT_ARTNode(
76  const UT_StringHolder& key,
77  const UT_StringView& prefix
78 #if defined(USE_MEMORY_RESOURCE)
79  , UT_PMR::polymorphic_allocator<UT_ARTNode<T>> alloc
80 #endif
81  )
82  : myKey(key)
83  , myPrefix(prefix)
84  , myValue()
85  , myAllowsPartial(false)
86 #if defined(USE_MEMORY_RESOURCE)
87  , myAllocator(alloc)
88 #endif
89  {
90  }
91  virtual ~UT_ARTNode() = default;
93 
94  UT_StringHolder key() const { return myKey; }
96  {
97  if (myValue.has_value())
98  return &myValue.value();
99  return nullptr;
100  }
101  template <typename... Args>
102  void emplace(Args&&... args)
103  {
104  myValue.emplace(std::forward<Args>(args)...);
105  }
107  {
108  if (myValue.has_value())
109  return &myValue.value();
110  return nullptr;
111  }
112  SYS_FORCE_INLINE bool hasValue() const { return myValue.has_value(); }
113  SYS_FORCE_INLINE const UT_StringView& prefix() const { return myPrefix; }
115  {
116  return myNumChildren == 0;
117  }
118  virtual bool isFull() const = 0;
120  void setAllowsPartial(bool allow) { myAllowsPartial = allow; }
121 
122  virtual const UT_StringHolder& type() const = 0;
123 
124  void debug(UT_WorkBuffer& wbuf, unsigned indent = 0) const
125  {
126  wbuf.append(indent, ' ');
127  if (myPrefix)
128  wbuf.append(myPrefix);
129  else
130  wbuf.append("<empty>");
131  wbuf.append(' ');
132  if (hasValue())
133  wbuf.appendFormat("{}", *value());
134  else
135  wbuf.append("<None>");
136  wbuf.append('\n');
137 
138  int idx = 0;
139  const UT_ARTNode<T>* child = nullptr;
140  do
141  {
142  child = nextChild(idx);
143  idx++;
144  if (child != nullptr)
145  {
146  child->debug(wbuf, indent + 1);
147  }
148  } while (child != nullptr);
149  }
150 
151  /// Compress the current node and its child. Compression happens when
152  /// this node has no value (edge) and its only child has a value. When
153  /// this occurs we can move the child up to this node.
155  {
156  if (myNumChildren == 1)
157  {
158  // If this node is not a root and has no value move the child
159  // up.
160  if (!hasValue())
161  {
163  = stealChild(ref, 0);
164  if (stolen)
165  {
166  exint prefix_length = myPrefix.length();
167  myKey = stolen->myKey;
169  stolen->myPrefix.begin() - prefix_length,
170  stolen->myPrefix.end());
171  myAllowsPartial = stolen->myAllowsPartial;
172  myValue = std::move(stolen->myValue);
173 
174  stolen->moveChildren(ref);
175  }
176  }
177  }
178  }
179 
180  virtual UT_ARTNode<T>** insertChild(
181  UT_ARTNode** ref,
183  = 0;
185  UT_ARTNode** ref,
186  UT_ARTNode* child)
187  = 0;
189  {
190  exint node_prefix_length = this->myPrefix.length();
191 
192  for (int i = this->myNumChildren; i-- > 0;)
193  {
194  UT_ARTNodePtr<UT_ARTNode<T>> child = stealChild(ref, i);
195  const char* start = child->myPrefix.begin() - node_prefix_length;
196  UT_ASSERT(start >= child->myKey.buffer());
197  child->myPrefix = UT_StringView(start, child->myPrefix.end());
198 
199  (*ref)->insertChild(ref, std::move(child));
200  }
201  }
202  virtual UT_ARTNode<T>* nextChild(int& idx) = 0;
203  virtual const UT_ARTNode<T>* nextChild(int& idx) const = 0;
205  UT_ARTNode<T>** ref,
206  int idx)
207  = 0;
208 
209  // Find the max length that both key and node prefix share
211  const UT_StringView& key,
212  const UT_StringView& node_prefix)
213  {
214  if (key.isEmpty() || node_prefix.isEmpty())
215  return 0;
216 
217  exint length = 0;
218  const char* k = key.data();
219  const char* p = node_prefix.data();
220  exint n = std::min(key.length(), node_prefix.length());
221 
222 #if defined(SUPPORT_FAST_STR) && !defined(ASAN_ENABLED)
223  static constexpr exint theMaxSIMDLen = 16;
224  const int mode = _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_EACH
225  | _SIDD_LEAST_SIGNIFICANT | _SIDD_NEGATIVE_POLARITY;
226  while (n > theMaxSIMDLen)
227  {
228  const __m128i data = _mm_loadu_si128(
229  reinterpret_cast<const __m128i*>(k));
230  const __m128i prefix = _mm_loadu_si128(
231  reinterpret_cast<const __m128i*>(p));
232 
233  int check_len = std::min(n, theMaxSIMDLen);
234  int res = _mm_cmpestri(data, check_len, prefix, check_len, mode);
235 
236  // For some reason if the length of the string is less then the
237  // max and the entire string matches it returns 16 instead of
238  // the length of the string so we cover that case here
239  if (n < 16 && res == 16)
240  res = n;
241 
242  length += res;
243 
244  n -= check_len;
245 
246  k += check_len;
247  p += check_len;
248  }
249 #endif
250 
251  while (n > 0)
252  {
253  if (*k != *p)
254  break;
255 
256  length++;
257  k++;
258  p++;
259  n--;
260  }
261  return length;
262  }
263 
264  // Find a child that is a partial match to the prefix.
266  const UT_StringView& prefix)
267  = 0;
268 
269  void moveHeader(UT_ARTNode<T>& move_to)
270  {
271  move_to.myKey = myKey;
272  move_to.myPrefix = myPrefix;
273  move_to.myValue = std::move(myValue);
275  move_to.myNumChildren = myNumChildren;
276  }
277 
278 #if defined(USE_MEMORY_RESOURCE)
279  UT_PMR::polymorphic_allocator<UT_ARTNode<T>> getAllocator()
280  {
281  return myAllocator;
282  }
283 #endif
284 
285  template <typename NodeT>
287  {
288 #if defined(USE_MEMORY_RESOURCE)
289  UT_PMR::polymorphic_allocator<NodeT> alloc(myAllocator);
290  NodeT* node = alloc.allocate(1);
291  alloc.construct(node, myKey, myPrefix, alloc);
293  return ptr;
294 #else
295  UT_ARTNodePtr<NodeT> ptr(new NodeT(myKey, myPrefix));
296  return ptr;
297 #endif
298  }
299  static void destroy(UT_ARTNode<T>* node)
300  {
301  if (node)
302  {
303  UT_ARTNodeDelete del;
304  del(node);
305  }
306  }
307 
308 #if defined(USE_MEMORY_RESOURCE)
309  UT_PMR::polymorphic_allocator<UT_ARTNode<T>> myAllocator;
310 #endif
314 
315  // If the node allows for partial matches
316  bool myAllowsPartial = false;
317 
318  uint8_t myNumChildren = 0;
319 };
320 
321 template <typename T>
322 inline void
324 {
325 #if defined(USE_MEMORY_RESOURCE)
326  auto alloc = ptr->getAllocator();
327  alloc.destroy(ptr);
328  alloc.deallocate(ptr, 1);
329 #else
330  delete ptr;
331 #endif
332 }
333 
334 template <typename T>
336 {
337 public:
338  using difference_type = std::ptrdiff_t;
340  using pointer = value_type*;
341  using const_pointer = const value_type*;
344  using iterator_category = std::forward_iterator_tag;
345 
346  UT_ARTIterator() = default;
347 
348  bool operator==(const UT_ARTIterator& it) const
349  {
350  return myCurrent == it.myCurrent;
351  }
352  bool operator!=(const UT_ARTIterator& it) const
353  {
354  return !(*this == it);
355  }
356  const_reference operator*() const { return *this; }
357  reference operator*() { return *this; }
358  const_pointer operator->() const { return this; }
359  pointer operator->() { return this; }
360 
362  {
363  if (!myCurrent)
364  return *this;
365 
366  findNextValue_();
367 
368  return *this;
369  }
370 
372  {
373  UT_ARTIterator tmp = *this;
374  ++(*this);
375  return tmp;
376  }
377 
378  bool hasValue() const { return myCurrent && myCurrent->hasValue(); }
379 
380  const T& value() const { return *myCurrent->value(); }
381  T& value() { return *myCurrent->value(); }
382 
383  UT_StringHolder key() const { return myCurrent->key(); }
384 
385 private:
386  friend class UT_ARTMap<T>;
387 
388  explicit UT_ARTIterator(UT_ARTNode<T>* node) : myCurrent(node)
389  {
390  // If the given value is not a value node skip to the next value node.
391  // Note that this should only be the case when the node is a root node.
392  if (myCurrent && !myCurrent->hasValue())
393  findNextValue_();
394  }
395 
396  void findNextValue_()
397  {
398  if (!myCurrent)
399  return;
400 
401  do
402  {
403  UT_ARTNode<T>* child = myCurrent->nextChild(myIndex);
404  if (child)
405  {
406  myIndex++;
407  myNodeStack.emplace_back(std::make_pair(myCurrent, myIndex));
408  myCurrent = child;
409  myIndex = 0;
410  }
411  else if (!myNodeStack.isEmpty())
412  {
413  auto&& [node, index] = myNodeStack.last();
414  myNodeStack.removeLast();
415 
416  myCurrent = node;
417  myIndex = index;
418  }
419  else
420  {
421  myCurrent = nullptr;
422  myIndex = 0;
423  }
424  } while (myCurrent != nullptr && !myCurrent->hasValue());
425 
426  return;
427  }
428 
429  UT_Array<std::pair<UT_ARTNode<T>*, int>> myNodeStack;
430  UT_ARTNode<T>* myCurrent = nullptr;
431  int myIndex = 0;
432 };
433 
434 template <typename T>
435 class UT_ARTNode4 final : public UT_ARTNode<T>
436 {
437 public:
440 
441 #if defined(USE_MEMORY_RESOURCE)
442  UT_ARTNode4(
443  const UT_StringHolder& key,
445  , UT_PMR::polymorphic_allocator<UT_ARTNode4<T>> alloc)
446  : UT_ARTNode<T>(key, prefix, alloc)
447  {
448  }
449 #else
452  UT_ARTNode<T>(key, prefix)
453  {}
454 #endif
456  ~UT_ARTNode4() override
457  {
462  }
463 
464  const UT_StringHolder& type() const override
465  {
466  static constexpr UT_StringLit theType("node4");
467  return theType.asHolder();
468  }
469  bool isFull() const override;
471  parent_t** ref,
472  parent_ptr_t child) override;
474  parent_t** ref,
475  parent_t* child) override;
477  const UT_StringView& prefix) override;
478  parent_t* nextChild(int& index) override;
479  const parent_t* nextChild(int& index) const override;
480  parent_ptr_t stealChild(parent_t** ref, int idx) override;
481 
482  unsigned char myChildKeys[4] = {0,0,0,0};
483  parent_t* myChildren[4] = {nullptr, nullptr, nullptr, nullptr};
484 };
485 
486 template <typename T>
487 class UT_ARTNode16 final : public UT_ARTNode<T>
488 {
489 public:
492 
493 #if defined(USE_MEMORY_RESOURCE)
494  UT_ARTNode16(
495  const UT_StringHolder& key,
497  UT_PMR::polymorphic_allocator<UT_ARTNode4<T>> alloc)
498  : UT_ARTNode<T>(key, prefix, alloc)
499 #else
501  : UT_ARTNode<T>(key, prefix)
502 #endif
503  {
504  memset(myChildKeys, 0, 16);
505  }
507  ~UT_ARTNode16() override
508  {
509  for (int i = 16; i-->0; )
511  }
512 
513  const UT_StringHolder& type() const override
514  {
515  static constexpr UT_StringLit theType("node16");
516  return theType.asHolder();
517  }
518  bool isFull() const override;
520  parent_t** ref,
521  parent_ptr_t child) override;
523  parent_t** ref,
524  parent_t* child) override;
526  const UT_StringView& prefix) override;
527  parent_t* nextChild(int& index) override;
528  const parent_t* nextChild(int& index) const override;
529  parent_ptr_t stealChild(parent_t** ref, int idx)
530  override;
531 
532  int prefixToIndex_(char c) const
533  {
534  unsigned mask = (1 << this->myNumChildren) - 1;
535  unsigned bitfield = 0;
536 #if defined(__i386) || defined(__amd64)
537  // SSE2 instructions so shouldnt need to check processor...
538  __m128i key_vec = _mm_set1_epi8(c);
539  __m128i results = _mm_cmpeq_epi8(
540  key_vec, _mm_loadu_si128((__m128i*)myChildKeys));
541  bitfield = _mm_movemask_epi8(results) & mask;
542 #else
543  for (int i = 0; i < 16; ++i)
544  {
545  if (myChildKeys[i] == c)
546  bitfield |= (1 << i);
547  }
548 
549  bitfield &= mask;
550 #endif
551 
552  if (bitfield)
553  {
554 #if !defined(_WIN32)
555  return __builtin_ctz(bitfield);
556 #else
557  return _tzcnt_u32(bitfield);
558 #endif
559  }
560  return -1;
561  }
562 
563  unsigned char myChildKeys[16];
564  parent_t* myChildren[16] = {};
565 };
566 
567 template <typename T>
568 class UT_ARTNode48 final : public UT_ARTNode<T>
569 {
570 public:
573 
574 #if defined(USE_MEMORY_RESOURCE)
575  UT_ARTNode48(
576  const UT_StringHolder& key,
578  UT_PMR::polymorphic_allocator<UT_ARTNode4<T>> alloc)
579  : UT_ARTNode<T>(key, prefix, alloc)
580 #else
582  : UT_ARTNode<T>(key, prefix)
583 #endif
584  {
585  memset(myChildKeys, 0, 256);
586  }
588  ~UT_ARTNode48() override
589  {
590  for (int i = 48; i-->0; )
592  }
593  const UT_StringHolder& type() const override
594  {
595  static constexpr UT_StringLit theType("node48");
596  return theType.asHolder();
597  }
598  bool isFull() const override;
600  parent_t** ref,
601  parent_ptr_t child) override;
603  parent_t** ref,
604  parent_t* child) override;
606  const UT_StringView& prefix) override;
607  parent_t* nextChild(int& index) override;
608  const parent_t* nextChild(int& index) const override;
609  parent_ptr_t stealChild(parent_t** ref, int idx)
610  override;
611 
612  unsigned char myChildKeys[256];
613  parent_t* myChildren[48] = {};
614 };
615 
616 template <typename T>
617 class UT_ARTNode256 final : public UT_ARTNode<T>
618 {
619 public:
622 
623 #if defined(USE_MEMORY_RESOURCE)
625  const UT_StringHolder& key,
627  UT_PMR::polymorphic_allocator<UT_ARTNode4<T>> alloc)
628  : UT_ARTNode<T>(key, prefix, alloc)
629 #else
631  : UT_ARTNode<T>(key, prefix)
632 #endif
633  {
634  }
636  ~UT_ARTNode256() override
637  {
638  for (int i = 256; i-->0; )
640  }
641 
642  const UT_StringHolder& type() const override
643  {
644  static constexpr UT_StringLit theType("node256");
645  return theType.asHolder();
646  }
647  bool isFull() const override;
649  parent_t** ref,
650  parent_ptr_t child) override;
652  parent_t** ref,
653  parent_t* child) override;
655  const UT_StringView& prefix) override;
656  parent_t* nextChild(int& index) override;
657  const parent_t* nextChild(int& index) const override;
658  parent_ptr_t stealChild(parent_t** ref, int idx)
659  override;
660 
661  parent_t* myChildren[256] = {};
662 };
663 
664 /// A simple radix tree implementation
665 template <typename T>
666 class UT_ARTMap
667 {
668 private:
669  using Node = UT_ARTNode<T>;
670  using StartNode = UT_ARTNode4<T>;
671 
672 public:
675  using mapped_type = T;
676 
677 #if defined(USE_MEMORY_RESOURCE)
678  UT_ARTMap() :
679  UT_ARTMap(UT_PMR::get_default_resource())
680  {
681  }
682  explicit UT_ARTMap(UT_PMR::memory_resource* resource) :
683  myAllocator(resource)
684 #else
686 #endif
687  {
688  myRoot = createBaseNode(
690  .release();
691  }
694  {
695 #if defined(USE_MEMORY_RESOURCE)
696  UT_PMR::polymorphic_allocator<Node> alloc(myAllocator);
697  alloc.destroy(myRoot);
698  alloc.deallocate(myRoot, 1);
699 #else
700  delete myRoot;
701 #endif
702  }
703 
704  /// Insert a node
705  std::pair<iterator, bool> insert(
706  const UT_StringHolder& name,
707  const T& data,
708  bool allow_partial = false)
709  {
710  return insert_(name, allow_partial, data);
711  }
712 
713  std::pair<iterator, bool> insert(
714  const UT_StringHolder& name,
715  T&& value,
716  bool allow_partial = false)
717  {
718  return insert_(name, allow_partial, value);
719  }
720 
721  template <typename... Args>
722  std::pair<iterator, bool> emplace(
723  const UT_StringHolder& name,
724  Args&&... args)
725  {
726  return insert_(
727  name, /*allows_partial=*/false, std::forward<Args>(args)...);
728  }
729 
730  typename std::enable_if_t<std::is_default_constructible_v<T>, T&>
732  {
733  auto&& [it, inserted] = insert_(key, /*allows_partial=*/false);
734 
735  UT_ASSERT(it.myCurrent != nullptr);
736  if (it.myCurrent && inserted)
737  {
738  it.myCurrent->emplace();
739  }
740 
741  return it.value();
742  }
743 
744  typename std::enable_if_t<std::is_default_constructible_v<T>, T&>
746  {
747  auto&& [it, inserted] = insert_(key, /*allows_partial=*/false);
748 
749  UT_ASSERT(it.myCurrent != nullptr);
750  if (it.myCurrent && inserted)
751  {
752  it.myCurrent->emplace();
753  }
754 
755  return it.value();
756  }
757 
758  /// Find the node based on the provided prefix.
760  find(UT_StringView prefix) const
761  {
762  Node* child = SYSconst_cast(this)->myRoot;
763  Node* last_partial = nullptr;
764 
765  while (!prefix.isEmpty() && child != nullptr)
766  {
767  Node** found = child->findPartialPrefixChild(prefix);
768  if (found && *found)
769  {
770  UT_StringView found_prefix((*found)->prefix());
771  exint common_length = child->getCommonPrefixLength(
772  prefix, found_prefix);
773  if (common_length == found_prefix.length())
774  {
775  prefix.removePrefix(common_length);
776 
777  // If we have found the last node but the common length is
778  // not an exact match then we have not found a node.
779  if (prefix.isEmpty()
780  && common_length != found_prefix.length())
781  {
782  child = nullptr;
783  break;
784  }
785 
786  child = *found;
787  // If this child allows for partial matches then update the
788  // last partial node we found.
789  if (child->allowsPartial())
790  last_partial = child;
791 
792  continue;
793  }
794  else
795  {
796  child = nullptr;
797  break;
798  }
799  }
800  else
801  {
802  child = nullptr;
803  break;
804  }
805  }
806 
807  if (child && child->hasValue())
808  return iterator(child);
809  // If we didnt find a child that matches check if our traversal came
810  // across a node that allows for partial matches. If we found one
811  // then return this node instead of reporting nothing found.
812  else if (last_partial != nullptr && last_partial->hasValue())
813  return iterator(last_partial);
814  return end();
815  }
816 
817  /// Check if the tree contains the provided string
819  {
820  return find(prefix) != end();
821  }
822 
823  /// Write out the tree into the work buffer. This is pretty printed.
824  void debug(UT_WorkBuffer& wbuf) const
825  {
826  wbuf.clear();
827 
828  myRoot->debug(wbuf, 0);
829  }
830  bool erase(const UT_StringRef& prefix)
831  {
832  return doErase_(prefix);
833  }
834 
835  /// Clear out the tree
836  void clear()
837  {
838 #if defined(USE_MEMORY_RESOURCE)
839  UT_PMR::polymorphic_allocator<Node> alloc(myAllocator);
840  alloc.destroy(myRoot);
841  alloc.deallocate(myRoot, 1);
842 
843 #else
844  delete myRoot;
845 #endif
846  myRoot = createBaseNode(
848  }
849 
851  {
852  return myRoot->childCount();
853  }
854 
855  using const_iterator = const iterator;
857  {
858  auto me = SYSconst_cast(this);
859  return iterator(me->myRoot);
860  }
862  {
863  return iterator(myRoot);
864  }
869 
870 private:
871  template <typename... Args>
872  std::pair<iterator, bool> insert_(
873  const UT_StringHolder& name,
874  bool allows_partial,
875  Args&&... args)
876  {
877  if (name.isEmpty())
878  return std::make_pair(end(), false);
879 
880  bool inserted = false;
881  Node* node = doInsert_(name, inserted);
882 
883  UT_ASSERT((inserted && node != nullptr) || !inserted);
884  if (node && inserted)
885  {
886  node->emplace(std::forward<Args>(args)...);
887  node->setAllowsPartial(allows_partial);
888  }
889  return std::make_pair(iterator(node), inserted);
890  }
891 
892  bool doErase_(const UT_StringRef& str)
893  {
894  if (str.isEmpty())
895  return false;
896 
897  Node** current = &myRoot;
898 
899  bool removed = false;
900  UT_StringView prefix(str);
901  while (!removed && current && prefix)
902  {
903  Node** node = (*current)->findPartialPrefixChild(prefix);
904 
905  // If no child matches the prefix then theres nothing to do.
906  if (node == nullptr)
907  {
908  return false;
909  }
910 
911  exint common_length = (*current)->getCommonPrefixLength(
912  prefix, (*node)->myPrefix);
913 
914  if (common_length == prefix.length())
915  {
916  // If we found the node but the found node does not have a value
917  // it means its an edge so we dont delete it.
918  if (!(*node)->hasValue())
919  return false;
920 
921  removed = true;
922 
923  if ((*node)->isLeaf())
924  {
925  auto stolen = (*current)->stealChild(current, *node);
926  }
927  else
928  {
929  UT_ARTNodePtr<Node> removed_node = (*current)->stealChild(
930  current, *node);
931  removed_node->moveChildren(current);
932  }
933 
934  (*current)->compress(current);
935  }
936  else
937  {
938  prefix.removePrefix(common_length);
939  current = node;
940  }
941  }
942 
943  return removed;
944  }
945 
946  UT_ARTNodePtr<Node> createBaseNode(
947  const UT_StringHolder& key,
948  const UT_StringView& prefix)
949  {
950 #if defined(USE_MEMORY_RESOURCE)
951  UT_PMR::polymorphic_allocator<UT_ARTNode4<T>> alloc(myAllocator);
952  UT_ARTNode4<T>* node = alloc.allocate(1);
953  alloc.construct(node, key, prefix, alloc);
955  return ptr;
956 #else
958  return ptr;
959 #endif
960  }
961 
962  Node* doInsert_(const UT_StringHolder& key, bool& inserted)
963  {
964  UT_StringView prefix(key);
965  UT_ASSERT(key.length() > 0);
966  UT_ASSERT(myRoot != nullptr);
967 
968  Node** current = &myRoot;
969  inserted = false;
970 
971  while (current != nullptr && prefix.length() > 0)
972  {
973  Node** node = (*current)->findPartialPrefixChild(prefix);
974  if (node == nullptr)
975  {
976  // No child partially matched the prefix so we will create
977  // one
978  Node** inserted_node = (*current)->insertChild(
979  current, createBaseNode(key, prefix));
980  inserted = true;
981  return (*inserted_node);
982  }
983  else
984  {
985  const exint prefix_length = (*current)->getCommonPrefixLength(
986  prefix, (*node)->myPrefix);
987 
988  // Check if this is a duplicate key
989  if (prefix.length() == (*node)->myPrefix.length()
990  && prefix.length() == prefix_length)
991  {
992  inserted = !(*node)->hasValue();
993  return *node;
994  }
995  // The childs key is the prefix of the insert item
996  // abc -> abc - d [ after inserting "abcd" ]
997  else if (prefix_length == (*node)->myPrefix.length())
998  {
999  prefix.removePrefix(prefix_length);
1000  current = node;
1001  }
1002  // The insert item is the prefix of the childs prefix
1003  // abc -> ab - c [after inserting "abc"]
1004  else if (prefix_length == prefix.length())
1005  {
1006  auto new_child = createBaseNode(key, prefix);
1007 
1008  // Remove the current child
1009  UT_ARTNodePtr<Node> stolen = (*current)->stealChild(
1010  current, *node);
1011  // Update the child prefix
1012  stolen->myPrefix.removePrefix(prefix_length);
1013  // Add old child to the new child
1014  Node* ptr = new_child.get();
1015  new_child->insertChild(&ptr, std::move(stolen));
1016 
1017  // Attach the new child to the current children
1018  Node** inserted_node = (*current)->insertChild(
1019  current, std::move(new_child));
1020 
1021  inserted = true;
1022  return (*inserted_node);
1023  }
1024  // Inserting item and childs key have the same common prefix
1025  else
1026  {
1027  // We need to split the current child and the suffix
1028  // into
1029  // two children whos parent is the prefix of the two
1030  // children
1031 
1032  // remove the existing child as this will be move to the
1033  // parent of the two children.
1034  UT_ARTNodePtr<Node> erased_child = (*current)
1035  ->stealChild(current, *node);
1036 
1037  UT_StringView item_prefix(prefix.begin(), prefix_length);
1038  auto parent = createBaseNode(key, item_prefix);
1039  // update the new prefix
1040  erased_child->myPrefix.removePrefix(prefix_length);
1041  // Add the suffix of the old key into the new branch
1042  Node* ptr = parent.get();
1043  parent->insertChild(
1044  &ptr, std::move(erased_child));
1045 
1046  // Add the suffix of the key into the new split branch
1047  prefix.removePrefix(prefix_length);
1048  Node** inserted_node = parent->insertChild(
1049  &ptr, createBaseNode(key, prefix));
1050 
1051  // Add the prefix of the old child and the new key into
1052  // this children set.
1053  (*current)->insertChild(current, std::move(parent));
1054 
1055  inserted = true;
1056  return *inserted_node;
1057  }
1058  }
1059  }
1060 
1061  return nullptr;
1062  }
1063 
1064  Node* myRoot = nullptr;
1065 #if defined(USE_MEMORY_RESOURCE)
1066  UT_PMR::polymorphic_allocator<std::byte> myAllocator;
1067 #endif
1068 };
1069 
1070 // Structured binding support
1071 template <std::size_t N, class T, std::enable_if_t<N == 0, int> = 0>
1072 auto
1073 get(const UT_ARTIterator<T>& it) -> decltype(it.key())
1074 {
1075  return it.key();
1076 }
1077 
1078 template <std::size_t N, class T, std::enable_if_t<N == 1, int> = 0>
1079 auto
1080 get(const UT_ARTIterator<T>& it) -> decltype(it.value())
1081 {
1082  return it.value();
1083 }
1084 
1085 namespace std
1086 {
1087 template <typename T>
1088 struct tuple_size<UT_ARTIterator<T>>
1089  : public std::integral_constant<std::size_t, 2>
1090 {
1091 };
1092 
1093 template <std::size_t N, typename T>
1094 struct tuple_element<N, UT_ARTIterator<T>>
1095 {
1096  using type = decltype(get<N>(
1097  std::declval<UT_ARTIterator<T>>()));
1098 };
1099 } // namespace std
1100 
1101 #include "UT_ARTMapImpl.h"
1102 
1103 #endif // __UT_ARTMAP_H__
bool erase(const UT_StringRef &prefix)
Definition: UT_ARTMap.h:830
bool operator!=(const UT_ARTIterator &it) const
Definition: UT_ARTMap.h:352
T & last()
Definition: UT_Array.h:816
UT_StringView myPrefix
Definition: UT_ARTMap.h:312
const T & value() const
Definition: UT_ARTMap.h:380
SYS_NO_DISCARD_RESULT bool isEmpty() const
Definition: UT_ARTMap.h:850
UT_StringHolder key() const
Definition: UT_ARTMap.h:383
UT_ARTNodePtr< parent_t > parent_ptr_t
Definition: UT_ARTMap.h:621
parent_t * nextChild(int &index) override
SYS_NO_DISCARD_RESULT iterator begin()
Definition: UT_ARTMap.h:861
UT_ARTNode< T > parent_t
Definition: UT_ARTMap.h:438
Definition: Node.h:52
UT_ARTNode< T > parent_t
Definition: UT_ARTMap.h:490
parent_t * nextChild(int &index) override
SYS_FORCE_INLINE void removeLast()
Definition: UT_Array.h:379
virtual ~UT_ARTNode()=default
GLuint start
Definition: glcorearb.h:475
parent_ptr_t stealChild(parent_t **ref, parent_t *child) override
UT_ARTNodePtr< parent_t > parent_ptr_t
Definition: UT_ARTMap.h:439
std::ptrdiff_t difference_type
Definition: UT_ARTMap.h:338
SYS_NO_DISCARD_RESULT iterator end()
Definition: UT_ARTMap.h:866
UT_ARTIterator()=default
SYS_FORCE_INLINE T * SYSconst_cast(const T *foo)
Definition: SYS_Types.h:136
bool isEmpty() const
Same as !isstring()
void emplace(Args &&...args)
Definition: UT_ARTMap.h:102
void moveHeader(UT_ARTNode< T > &move_to)
Definition: UT_ARTMap.h:269
void debug(UT_WorkBuffer &wbuf, unsigned indent=0) const
Definition: UT_ARTMap.h:124
int64 exint
Definition: SYS_Types.h:125
UT_ARTNode16(const UT_StringHolder &key, UT_StringView prefix)
Definition: UT_ARTMap.h:500
bool hasValue() const
Definition: UT_ARTMap.h:378
SYS_NO_DISCARD_RESULT bool contains(const UT_StringHolder &prefix) const
Check if the tree contains the provided string.
Definition: UT_ARTMap.h:818
parent_t * myChildren[256]
Definition: UT_ARTMap.h:661
UT_StringHolder myKey
Definition: UT_ARTMap.h:311
GLuint GLsizei GLsizei * length
Definition: glcorearb.h:795
UT_NON_COPYABLE(UT_ARTNode)
UT_ARTNode4(const UT_StringHolder &key, UT_StringView prefix)
Definition: UT_ARTMap.h:450
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
Definition: UT_ARTMap.h:348
const UT_StringHolder & type() const override
Definition: UT_ARTMap.h:642
const UT_StringHolder & type() const override
Definition: UT_ARTMap.h:464
void moveChildren(UT_ARTNode< T > **ref)
Definition: UT_ARTMap.h:188
~UT_ARTNode4() override
Definition: UT_ARTMap.h:456
SYS_FORCE_INLINE const value_type * value() const
Definition: UT_ARTMap.h:95
int prefixToIndex_(char c) const
Definition: UT_ARTMap.h:532
parent_t ** findPartialPrefixChild(const UT_StringView &prefix) override
void removePrefix(exint n)
exint getCommonPrefixLength(const UT_StringView &key, const UT_StringView &node_prefix)
Definition: UT_ARTMap.h:210
~UT_ARTNode16() override
Definition: UT_ARTMap.h:507
decltype(get< N >(std::declval< UT_ARTIterator< T >>())) type
Definition: UT_ARTMap.h:1097
std::optional< T > UT_Optional
Definition: UT_Optional.h:26
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.
Definition: UT_UniquePtr.h:39
parent_t * myChildren[16]
Definition: UT_ARTMap.h:564
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.
Definition: UT_ARTMap.h:824
uint8_t myNumChildren
Definition: UT_ARTMap.h:318
A utility class to do read-only operations on a subset of an existing string.
Definition: UT_StringView.h:39
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.
A simple radix tree implementation.
Definition: UT_ARTMap.h:54
GLdouble n
Definition: glcorearb.h:2008
UT_ARTNodePtr< parent_t > parent_ptr_t
Definition: UT_ARTMap.h:491
void operator()(T *ptr)
Definition: UT_ARTMap.h:323
bool myAllowsPartial
Definition: UT_ARTMap.h:316
SYS_NO_DISCARD_RESULT SYS_FORCE_INLINE exint length() const
Returns the length of the string in bytes.
std::forward_iterator_tag iterator_category
Definition: UT_ARTMap.h:344
UT_ARTNode< T > parent_t
Definition: UT_ARTMap.h:620
exint emplace_back(S &&...s)
Definition: UT_ArrayImpl.h:769
std::pair< iterator, bool > insert(const UT_StringHolder &name, const T &data, bool allow_partial=false)
Insert a node.
Definition: UT_ARTMap.h:705
unsigned char myChildKeys[16]
Definition: UT_ARTMap.h:563
exint length() const
bool isFull() const override
GLint ref
Definition: glcorearb.h:124
SYS_NO_DISCARD_RESULT const_iterator end() const
Definition: UT_ARTMap.h:865
virtual const UT_StringHolder & type() const =0
static const UT_StringHolder theEmptyString
SYS_NO_DISCARD_RESULT const_iterator begin() const
Definition: UT_ARTMap.h:856
const UT_StringHolder & type() const override
Definition: UT_ARTMap.h:513
void clear()
Clear out the tree.
Definition: UT_ARTMap.h:836
#define SYS_FORCE_INLINE
Definition: SYS_Inline.h:45
bool isFull() const override
UT_ARTNode(const UT_StringHolder &key, const UT_StringView &prefix)
Definition: UT_ARTMap.h:75
UT_ARTIterator< T > iterator
Definition: UT_ARTMap.h:673
SYS_NO_DISCARD_RESULT iterator find(UT_StringView prefix) const
Find the node based on the provided prefix.
Definition: UT_ARTMap.h:760
UT_ARTIterator & operator++()
Definition: UT_ARTMap.h:361
pointer operator->()
Definition: UT_ARTMap.h:359
GLint GLuint mask
Definition: glcorearb.h:124
T value_type
Definition: UT_ARTMap.h:73
UT_NON_COPYABLE(UT_ARTNode48)
SYS_FORCE_INLINE bool isLeaf() const
Definition: UT_ARTMap.h:114
#define SYS_NO_DISCARD_RESULT
Definition: SYS_Compiler.h:93
UT_Optional< value_type > myValue
Definition: UT_ARTMap.h:313
parent_t ** insertChild(parent_t **ref, parent_ptr_t child) override
SYS_NO_DISCARD_RESULT const_iterator cend() const
Definition: UT_ARTMap.h:868
UT_ARTNode< T > parent_t
Definition: UT_ARTMap.h:571
GLuint const GLchar * name
Definition: glcorearb.h:786
bool isFull() const override
std::enable_if_t< std::is_default_constructible_v< T >, T & > operator[](UT_StringHolder &&key)
Definition: UT_ARTMap.h:745
~UT_ARTNode48() override
Definition: UT_ARTMap.h:588
const UT_StringHolder & type() const override
Definition: UT_ARTMap.h:593
parent_t ** findPartialPrefixChild(const UT_StringView &prefix) override
UT_ARTNodePtr< parent_t > parent_ptr_t
Definition: UT_ARTMap.h:572
~UT_ARTMap()
Definition: UT_ARTMap.h:693
parent_t ** insertChild(parent_t **ref, parent_ptr_t child) override
parent_t ** findPartialPrefixChild(const UT_StringView &prefix) override
Definition: UT_ARTMapImpl.h:87
GLenum mode
Definition: glcorearb.h:99
parent_t ** insertChild(parent_t **ref, parent_ptr_t child) override
parent_ptr_t stealChild(parent_t **ref, parent_t *child) override
Definition: UT_ARTMapImpl.h:67
~UT_ARTNode256() override
Definition: UT_ARTMap.h:636
virtual UT_ARTNodePtr< UT_ARTNode< T > > stealChild(UT_ARTNode **ref, UT_ARTNode *child)=0
const_reference operator*() const
Definition: UT_ARTMap.h:356
virtual UT_ARTNode< T > ** findPartialPrefixChild(const UT_StringView &prefix)=0
parent_t ** insertChild(parent_t **ref, parent_ptr_t child) override
Definition: UT_ARTMapImpl.h:29
UT_ARTIterator operator++(int)
Definition: UT_ARTMap.h:371
unsigned char myChildKeys[256]
Definition: UT_ARTMap.h:612
std::pair< iterator, bool > emplace(const UT_StringHolder &name, Args &&...args)
Definition: UT_ARTMap.h:722
std::pair< iterator, bool > insert(const UT_StringHolder &name, T &&value, bool allow_partial=false)
Definition: UT_ARTMap.h:713
unsigned char myChildKeys[4]
Definition: UT_ARTMap.h:482
SYS_FORCE_INLINE bool hasValue() const
Definition: UT_ARTMap.h:112
UT_ARTNodePtr< NodeT > newNode()
Definition: UT_ARTMap.h:286
reference operator*()
Definition: UT_ARTMap.h:357
GLuint index
Definition: glcorearb.h:786
T mapped_type
Definition: UT_ARTMap.h:675
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
Definition: UT_ARTMap.h:867
auto ptr(T p) -> const void *
Definition: format.h:2448
GA_API const UT_StringHolder N
if(num_boxed_items<=0)
Definition: UT_RTreeImpl.h:697
parent_t * nextChild(int &index) override
**If you just want to fire and args
Definition: thread.h:609
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)
Definition: UT_ARTMap.h:630
SYS_FORCE_INLINE value_type * value()
Definition: UT_ARTMap.h:106
static void destroy(UT_ARTNode< T > *node)
Definition: UT_ARTMap.h:299
UT_NON_COPYABLE(UT_ARTMap)
#define UT_ASSERT(ZZ)
Definition: UT_Assert.h:156
SYS_FORCE_INLINE void clear()
Definition: core.h:1131
parent_t ** findPartialPrefixChild(const UT_StringView &prefix) override
UT_NON_COPYABLE(UT_ARTNode16)
void setAllowsPartial(bool allow)
Definition: UT_ARTMap.h:120
std::enable_if_t< std::is_default_constructible_v< T >, T & > operator[](const UT_StringHolder &key)
Definition: UT_ARTMap.h:731
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)
Definition: UT_ARTMap.h:154
parent_t * myChildren[48]
Definition: UT_ARTMap.h:613
UT_UniquePtr< T, UT_ARTNodeDelete > UT_ARTNodePtr
Definition: UT_ARTMap.h:67
SYS_FORCE_INLINE const UT_StringView & prefix() const
Definition: UT_ARTMap.h:113
UT_NON_COPYABLE(UT_ARTNode256)
UT_NON_COPYABLE(UT_ARTNode4)
Definition: format.h:895
bool isFull() const override
Definition: UT_ARTMapImpl.h:22
UT_StringHolder key() const
Definition: UT_ARTMap.h:94
const_pointer operator->() const
Definition: UT_ARTMap.h:358
UT_ARTNode48(const UT_StringHolder &key, UT_StringView prefix)
Definition: UT_ARTMap.h:581
parent_t * myChildren[4]
Definition: UT_ARTMap.h:483
bool isEmpty() const
Returns true iff there are no occupied elements in the array.
Definition: UT_Array.h:650
SYS_FORCE_INLINE bool allowsPartial() const
Definition: UT_ARTMap.h:119