HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
pathTable.h
Go to the documentation of this file.
1 //
2 // Copyright 2016 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 #ifndef PXR_USD_SDF_PATH_TABLE_H
25 #define PXR_USD_SDF_PATH_TABLE_H
26 
27 #include "pxr/pxr.h"
28 #include "pxr/usd/sdf/api.h"
29 #include "pxr/usd/sdf/path.h"
32 
33 #include <algorithm>
34 #include <utility>
35 #include <vector>
36 
38 
39 // Parallel visitation helper function.
40 SDF_API
41 void Sdf_VisitPathTableInParallel(void **, size_t, TfFunctionRef<void(void*&)>);
42 
43 /// \class SdfPathTable
44 ///
45 /// A mapping from SdfPath to \a MappedType, somewhat similar to map<SdfPath,
46 /// MappedType> and TfHashMap<SdfPath, MappedType>, but with key
47 /// differences. Notably:
48 ///
49 /// Works exclusively with absolute paths.
50 ///
51 /// Inserting a path \a p also implicitly inserts all of \a p's ancestors.
52 ///
53 /// Erasing a path \a p also implicitly erases all of \a p's descendants.
54 ///
55 /// The table has an order: it's a preordering of the paths in the table, but
56 /// with arbitrary sibling order. Given a path \a p in the table, all other
57 /// paths in the table with \a p as a prefix appear contiguously, immediately
58 /// following \a p. For example, suppose a table contains the paths:
59 ///
60 /// {'/a/b/c', '/a', '/a/d', '/', '/a/b'}
61 ///
62 /// Then there are two possible valid orderings:
63 ///
64 /// ['/', '/a', '/a/d', '/a/b', '/a/b/c']
65 /// ['/', '/a', '/a/b', '/a/b/c', '/a/d']
66 ///
67 /// In addition to the ordinary map and TfHashMap methods, this class
68 /// provides a method \a FindSubtreeRange, which, given a path \a p, returns
69 /// a pair of iterators [\a b, \a e) defining a range such that for every
70 /// iterator \a i in [\a b, \a e), i->first is either equal to \a p or is
71 /// prefixed by \a p.
72 ///
73 /// Iterator Invalidation
74 ///
75 /// Like most other node-based containers, iterators are only invalidated when
76 /// the element they refer to is removed from the table. Note however, that
77 /// since removing the element with path \a p also implicitly removes all
78 /// elements with paths prefixed by \a p, a call to erase(\a i) may invalidate
79 /// many iterators.
80 ///
81 template <class MappedType>
83 {
84 public:
85 
86  typedef SdfPath key_type;
87  typedef MappedType mapped_type;
88  typedef std::pair<key_type, mapped_type> value_type;
89 
90 private:
91 
92  // An _Entry represents an item in the table. It holds the item's value, a
93  // pointer (\a next) to the next item in the hash bucket's linked list, and
94  // two pointers (\a firstChild and \a nextSibling) that describe the tree
95  // structure.
96  struct _Entry {
97  _Entry(const _Entry&) = delete;
98  _Entry& operator=(const _Entry&) = delete;
99  _Entry(value_type const &value, _Entry *n)
100  : value(value)
101  , next(n)
102  , firstChild(nullptr)
103  , nextSiblingOrParent(nullptr, false) {}
104 
105  _Entry(value_type &&value, _Entry *n)
106  : value(std::move(value))
107  , next(n)
108  , firstChild(nullptr)
109  , nextSiblingOrParent(nullptr, false) {}
110 
111  // If this entry's nextSiblingOrParent field points to a sibling, return
112  // a pointer to it, otherwise return null.
113  _Entry *GetNextSibling() {
114  return nextSiblingOrParent.template BitsAs<bool>() ?
115  nextSiblingOrParent.Get() : 0;
116  }
117  // If this entry's nextSiblingOrParent field points to a sibling, return
118  // a pointer to it, otherwise return null.
119  _Entry const *GetNextSibling() const {
120  return nextSiblingOrParent.template BitsAs<bool>() ?
121  nextSiblingOrParent.Get() : 0;
122  }
123 
124  // If this entry's nextSiblingOrParent field points to a parent, return
125  // a pointer to it, otherwise return null.
126  _Entry *GetParentLink() {
127  return nextSiblingOrParent.template BitsAs<bool>() ? 0 :
128  nextSiblingOrParent.Get();
129  }
130  // If this entry's nextSiblingOrParent field points to a parent, return
131  // a pointer to it, otherwise return null.
132  _Entry const *GetParentLink() const {
133  return nextSiblingOrParent.template BitsAs<bool>() ? 0 :
134  nextSiblingOrParent.Get();
135  }
136 
137  // Set this entry's nextSiblingOrParent field to point to the passed
138  // sibling.
139  void SetSibling(_Entry *sibling) {
140  nextSiblingOrParent.Set(sibling, /* isSibling */ true);
141  }
142 
143  // Set this entry's nextSiblingOrParent field to point to the passed
144  // parent.
145  void SetParentLink(_Entry *parent) {
146  nextSiblingOrParent.Set(parent, /* isSibling */ false);
147  }
148 
149  // Add \a child as a child of this entry.
150  void AddChild(_Entry *child) {
151  // If there are already one or more children, make \a child be our
152  // new first child. Otherwise, add \a child as the first child.
153  if (firstChild)
154  child->SetSibling(firstChild);
155  else
156  child->SetParentLink(this);
157  firstChild = child;
158  }
159 
160  void RemoveChild(_Entry *child) {
161  // Remove child from this _Entry's children.
162  if (child == firstChild) {
163  firstChild = child->GetNextSibling();
164  } else {
165  // Search the list to find the preceding child, then unlink the
166  // child to remove.
167  _Entry *prev, *cur = firstChild;
168  do {
169  prev = cur;
170  cur = prev->GetNextSibling();
171  } while (cur != child);
172  prev->nextSiblingOrParent = cur->nextSiblingOrParent;
173  }
174  }
175 
176  // The value object mapped by this entry.
178 
179  // The next field links together entries in chained hash table buckets.
180  _Entry *next;
181 
182  // The firstChild and nextSiblingOrParent fields describe the tree
183  // structure of paths. An entry has one or more children when
184  // firstChild is non null. Its chlidren are stored in a singly linked
185  // list, where nextSiblingOrParent points to the next entry in the list.
186  //
187  // The end of the list is reached when the bit stored in
188  // nextSiblingOrParent is set false, indicating a pointer to the parent
189  // rather than another sibling.
190  _Entry *firstChild;
191  TfPointerAndBits<_Entry> nextSiblingOrParent;
192  };
193 
194  // Hash table's list of buckets is a vector of _Entry ptrs.
195  typedef std::vector<_Entry *> _BucketVec;
196 
197 public:
198 
199  // The iterator class, used to make both const and non-const
200  // iterators. Currently only forward traversal is supported.
201  template <class, class> friend class Iterator;
202  template <class ValType, class EntryPtr>
203  class Iterator
204  {
205  public:
206  using iterator_category = std::forward_iterator_tag;
207  using value_type = ValType;
208  using reference = ValType&;
209  using pointer = ValType*;
210  using difference_type = std::ptrdiff_t;
211 
212  /// The standard requires default construction but places practically no
213  /// requirements on the semantics of default-constructed iterators.
214  Iterator() = default;
215 
216  /// Copy constructor (also allows for converting non-const to const).
217  template <class OtherVal, class OtherEntryPtr>
219  : _entry(other._entry)
220  {}
221 
222  reference operator*() const { return dereference(); }
223  pointer operator->() const { return &(dereference()); }
224 
226  increment();
227  return *this;
228  }
229 
231  Iterator result(*this);
232  increment();
233  return result;
234  }
235 
236  template <class OtherVal, class OtherEntryPtr>
238  return equal(other);
239  }
240 
241  template <class OtherVal, class OtherEntryPtr>
243  return !equal(other);
244  }
245 
246  /// Return an iterator \a e, defining a maximal range [\a *this, \a e)
247  /// such that for all \a i in the range, \a i->first is \a
248  /// (*this)->first or is prefixed by \a (*this)->first.
250  Iterator result(0);
251  if (_entry) {
252  if (EntryPtr sibling = _entry->GetNextSibling()) {
253  // Next subtree is next sibling, if present.
254  result._entry = sibling;
255  } else {
256  // Otherwise, walk up parents until we either find one with
257  // a next sibling or run out.
258  for (EntryPtr p = _entry->GetParentLink(); p;
259  p = p->GetParentLink()) {
260  if (EntryPtr sibling = p->GetNextSibling()) {
261  result._entry = sibling;
262  break;
263  }
264  }
265  }
266  }
267  return result;
268  }
269 
270  /// Returns true if incrementing this iterator would move to a child
271  /// entry, false otherwise.
272  bool HasChild() const {
273  return bool(_entry->firstChild);
274  }
275 
276  protected:
277  friend class SdfPathTable;
278  template <class, class> friend class Iterator;
279 
280  explicit Iterator(EntryPtr entry)
281  : _entry(entry) {}
282 
283  // Fundamental functionality to implement the iterator.
284 
285  // Iterator increment.
286  inline void increment() {
287  // Move to first child, if present. Otherwise move to next subtree.
288  _entry = _entry->firstChild ? _entry->firstChild :
290  }
291 
292  // Equality comparison. A template, to allow comparison between const
293  // and non-const iterators.
294  template <class OtherVal, class OtherEntryPtr>
295  bool equal(Iterator<OtherVal, OtherEntryPtr> const &other) const {
296  return _entry == other._entry;
297  }
298 
299  // Dereference.
300  ValType &dereference() const {
301  return _entry->value;
302  }
303 
304  // Store pointer to current entry.
305  EntryPtr _entry;
306  };
307 
308  typedef Iterator<value_type, _Entry *> iterator;
309  typedef Iterator<const value_type, const _Entry *> const_iterator;
310 
311  /// Result type for insert().
312  typedef std::pair<iterator, bool> _IterBoolPair;
313 
314  /// A handle owning a path table node that may be used to "reserve" a stable
315  /// memory location for key & mapped object. A node handle may be inserted
316  /// into a table later, and if that insertion is successful, the underlying
317  /// key & mapped object remain at the same memory location.
318  struct NodeHandle
319  {
320  friend class SdfPathTable;
321 
322  /// Create a new NodeHandle for a table entry. This NodeHandle can
323  /// later be inserted into an SdfPathTable. If inserted successfully,
324  /// the key and value addresses remain valid. NodeHandles may be
325  /// created concurrently without additional synchronization.
326  static NodeHandle
327  New(value_type const &value) {
328  NodeHandle ret;
329  ret._unlinkedEntry.reset(new _Entry(value, nullptr));
330  return ret;
331  }
332 
333  /// \overload
334  static NodeHandle
336  NodeHandle ret;
337  ret._unlinkedEntry.reset(new _Entry(std::move(value), nullptr));
338  return ret;
339  }
340 
341  /// \overload
342  static NodeHandle
343  New(key_type const &key, mapped_type const &mapped) {
344  return New({ key, mapped });
345  }
346 
347  /// Return a const reference to this NodeHandle's key. This NodeHandle
348  /// must be valid to call this member function (see
349  /// NodeHandle::IsValid).
350  key_type const &GetKey() const {
351  return _unlinkedEntry->value.first;
352  }
353 
354  /// Return a mutable reference to this NodeHandle's key. This
355  /// NodeHandle must be valid to call this member function (see
356  /// NodeHandle::IsValid).
358  return _unlinkedEntry->value.first;
359  }
360 
361  /// Return a const reference to this NodeHandle's mapped object. This
362  /// NodeHandle must be valid to call this member function (see
363  /// NodeHandle::IsValid).
364  mapped_type const &GetMapped() const {
365  return _unlinkedEntry->value.second;
366  }
367 
368  /// Return a mutable reference to this NodeHandle's mapped object. This
369  /// NodeHandle must be valid to call this member function (see
370  /// NodeHandle::IsValid).
372  return _unlinkedEntry->value.second;
373  }
374 
375  /// Return true if this NodeHandle owns a path table entry, false
376  /// otherwise.
377  bool IsValid() const {
378  return static_cast<bool>(_unlinkedEntry);
379  }
380 
381  /// Return true if this NodeHandle owns a path table entry, false
382  /// otherwise.
383  explicit operator bool() const {
384  return IsValid();
385  }
386 
387  /// Delete any owned path table entry. After calling this function,
388  /// IsValid() returns false.
389  void reset() {
390  _unlinkedEntry.reset();
391  }
392 
393  private:
394  std::unique_ptr<_Entry> _unlinkedEntry;
395  };
396 
397  /// Default constructor.
398  SdfPathTable() : _size(0), _mask(0) {}
399 
400  /// Copy constructor.
402  : _buckets(other._buckets.size())
403  , _size(0) // size starts at 0, since we insert elements.
404  , _mask(other._mask)
405  {
406  // Walk all elements in the other container, inserting into this one,
407  // and creating the right child/sibling links along the way.
408  for (const_iterator i = other.begin(), end = other.end();
409  i != end; ++i) {
410  iterator j = _InsertInTable(*i).first;
411  // Ensure first child and next sibling links are created.
412  if (i._entry->firstChild && !j._entry->firstChild) {
413  j._entry->firstChild =
414  _InsertInTable(i._entry->firstChild->value).first._entry;
415  }
416  // Ensure the nextSibling/parentLink is created.
417  if (i._entry->nextSiblingOrParent.Get() &&
418  !j._entry->nextSiblingOrParent.Get()) {
419  j._entry->nextSiblingOrParent.Set(
420  _InsertInTable(i._entry->nextSiblingOrParent.
421  Get()->value).first._entry,
422  i._entry->nextSiblingOrParent.template BitsAs<bool>());
423  }
424  }
425  }
426 
427  /// Move constructor.
429  : _buckets(std::move(other._buckets))
430  , _size(other._size)
431  , _mask(other._mask)
432  {
433  other._size = 0;
434  other._mask = 0;
435  }
436 
437  /// Destructor.
439  // Call clear to free all nodes.
440  clear();
441  }
442 
443  /// Copy assignment.
445  if (this != &other)
446  SdfPathTable(other).swap(*this);
447  return *this;
448  }
449 
450  /// Move assignment.
452  if (this != &other)
453  SdfPathTable(std::move(other)).swap(*this);
454  return *this;
455  }
456 
457  /// Return an iterator to the start of the table.
459  // Return an iterator pointing to the root if this table isn't empty.
460  if (empty())
461  return end();
463  }
464 
465  /// Return a const_iterator to the start of the table.
467  // Return an iterator pointing to the root if this table isn't empty.
468  if (empty())
469  return end();
471  }
472 
473  /// Return an iterator denoting the end of the table.
475  return iterator(0);
476  }
477 
478  /// Return a const_iterator denoting the end of the table.
479  const_iterator end() const {
480  return const_iterator(0);
481  }
482 
483  /// Remove the element with path \a path from the table as well as all
484  /// elements whose paths are prefixed by \a path. Return true if any
485  /// elements were removed, false otherwise.
486  ///
487  /// Note that since descendant paths are also erased, size() may be
488  /// decreased by more than one after calling this function.
489  bool erase(SdfPath const &path) {
490  iterator i = find(path);
491  if (i == end())
492  return false;
493  erase(i);
494  return true;
495  }
496 
497  /// Remove the element pointed to by \p i from the table as well as all
498  /// elements whose paths are prefixed by \a i->first. \a i must be a valid
499  /// iterator for this table.
500  ///
501  /// Note that since descendant paths are also erased, size() may be
502  /// decreased by more than one after calling this function.
503  void erase(iterator const &i) {
504  // Delete descendant nodes, if any. Then remove from parent, finally
505  // erase from hash table.
506  _Entry * const entry = i._entry;
507  _EraseSubtree(entry);
508  _RemoveFromParent(entry);
509  _EraseFromTable(entry);
510  }
511 
512  /// Return an iterator to the element corresponding to \a path, or \a end()
513  /// if there is none.
515  if (!empty()) {
516  // Find the item in the list.
517  for (_Entry *e = _buckets[_Hash(path)]; e; e = e->next) {
518  if (e->value.first == path)
519  return iterator(e);
520  }
521  }
522  return end();
523  }
524 
525  /// Return a const_iterator to the element corresponding to \a path, or
526  /// \a end() if there is none.
527  const_iterator find(SdfPath const &path) const {
528  if (!empty()) {
529  // Find the item in the list.
530  for (_Entry const *e = _buckets[_Hash(path)]; e; e = e->next) {
531  if (e->value.first == path)
532  return const_iterator(e);
533  }
534  }
535  return end();
536  }
537 
538  /// Return a pair of iterators [\a b, \a e), describing the maximal range
539  /// such that for all \a i in the range, \a i->first is \a b->first or
540  /// is prefixed by \a b->first.
541  std::pair<iterator, iterator>
543  std::pair<iterator, iterator> result;
544  result.first = find(path);
545  result.second = result.first.GetNextSubtree();
546  return result;
547  }
548 
549  /// Return a pair of const_iterators [\a b, \a e), describing the maximal
550  /// range such that for all \a i in the range, \a i->first is \a b->first or
551  /// is prefixed by \a b->first.
552  std::pair<const_iterator, const_iterator>
553  FindSubtreeRange(SdfPath const &path) const {
554  std::pair<const_iterator, const_iterator> result;
555  result.first = find(path);
556  result.second = result.first.GetNextSubtree();
557  return result;
558  }
559 
560  /// Return 1 if there is an element for \a path in the table, otherwise 0.
561  size_t count(SdfPath const &path) const {
562  return find(path) != end();
563  }
564 
565  /// Return the number of elements in the table.
566  inline size_t size() const { return _size; }
567 
568  /// Return true if this table is empty.
569  inline bool empty() const { return !size(); }
570 
571  /// Insert \a value into the table, and additionally insert default entries
572  /// for all ancestral paths of \a value.first that do not already exist in
573  /// the table.
574  ///
575  /// Return a pair of iterator and bool. The iterator points to the inserted
576  /// element, the bool indicates whether insertion was successful. The bool
577  /// is true if \a value was successfully inserted and false if an element
578  /// with path \a value.first was already present in the map.
579  ///
580  /// Note that since ancestral paths are also inserted, size() may be
581  /// increased by more than one after calling this function.
583  // Insert in table.
584  _IterBoolPair result = _InsertInTable(value);
585  if (result.second) {
586  // New element -- make sure the parent is inserted.
587  _UpdateTreeForNewEntry(result);
588  }
589  return result;
590  }
591 
592  /// \overload
593  ///
594  /// Insert the entry held by \p node into this table. If the insertion is
595  /// successful, the contents of \p node are moved-from and indeterminate.
596  /// Otherwise if the insertion is unsuccessful, the contents of \p node are
597  /// unmodified.
598  _IterBoolPair insert(NodeHandle &&node) {
599  // Insert in table.
600  _IterBoolPair result = _InsertInTable(std::move(node));
601  if (result.second) {
602  // New element -- make sure the parent is inserted.
603  _UpdateTreeForNewEntry(result);
604  }
605  return result;
606  }
607 
608  /// Shorthand for the following, where \a t is an SdfPathTable<T>.
609  /// \code
610  /// t.insert(value_type(path, mapped_type())).first->second
611  /// \endcode
613  return insert(value_type(path, mapped_type())).first->second;
614  }
615 
616  /// Remove all elements from the table, leaving size() == 0. Note that this
617  /// function will not shrink the number of buckets used for the hash table.
618  /// To do that, swap this instance with a default constructed instance.
619  /// See also \a TfReset.
620  void clear() {
621  // Note this leaves the size of _buckets unchanged.
622  for (size_t i = 0, n = _buckets.size(); i != n; ++i) {
623  _Entry *entry = _buckets[i];
624  while (entry) {
625  _Entry *next = entry->next;
626  delete entry;
627  entry = next;
628  }
629  _buckets[i] = 0;
630  }
631  _size = 0;
632  }
633 
634  /// Equivalent to clear(), but destroy contained objects in parallel. This
635  /// requires that running the contained objects' destructors is thread-safe.
637  auto visitFn =
638  [](void*& voidEntry) {
639  _Entry *entry = static_cast<_Entry *>(voidEntry);
640  while (entry) {
641  _Entry *next = entry->next;
642  delete entry;
643  entry = next;
644  }
645  voidEntry = nullptr;
646  };
647  Sdf_VisitPathTableInParallel(reinterpret_cast<void **>(_buckets.data()),
648  _buckets.size(), visitFn);
649  _size = 0;
650  }
651 
652  /// Swap this table's contents with \a other.
653  void swap(SdfPathTable &other) {
654  _buckets.swap(other._buckets);
655  std::swap(_size, other._size);
656  std::swap(_mask, other._mask);
657  }
658 
659  /// Return a vector of the count of elements in each bucket.
660  std::vector<size_t> GetBucketSizes() const {
661  std::vector<size_t> sizes(_buckets.size(), 0u);;
662  for (size_t i = 0, n = _buckets.size(); i != n; ++i) {
663  for (_Entry *entry = _buckets[i]; entry; entry = entry->next) {
664  sizes[i]++;
665  }
666  }
667  return sizes;
668  }
669 
670  /// Replaces all prefixes from \p oldName to \p newName.
671  /// Note that \p oldName and \p newName need to be silbing paths (ie.
672  /// their parent paths must be the same).
673  void UpdateForRename(const SdfPath &oldName, const SdfPath &newName) {
674 
675  if (oldName.GetParentPath() != newName.GetParentPath()) {
676  TF_CODING_ERROR("Unexpected arguments.");
677  return;
678  }
679 
680  std::pair<iterator, iterator> range = FindSubtreeRange(oldName);
681  for (iterator i=range.first; i!=range.second; ++i) {
683  i->first.ReplacePrefix(oldName, newName),
684  i->second));
685  }
686 
687  if (range.first != range.second)
688  erase(oldName);
689  }
690 
691  /// ParallelForEach: parallel iteration over all of the key-value pairs
692  /// in the path table. The type of \p visitFn should be a callable,
693  /// taking a (const SdfPath&, mapped_type&), representing the loop
694  /// body. Note: since this function is run in parallel, visitFn is
695  /// responsible for synchronizing access to any non-pathtable state.
696  template <typename Callback>
697  void ParallelForEach(Callback const& visitFn) {
698  auto lambda =
699  [&visitFn](void*& voidEntry) {
700  _Entry *entry = static_cast<_Entry *>(voidEntry);
701  while (entry) {
702  visitFn(std::cref(entry->value.first),
703  std::ref(entry->value.second));
704  entry = entry->next;
705  }
706  };
707  Sdf_VisitPathTableInParallel(reinterpret_cast<void **>(_buckets.data()),
708  _buckets.size(), lambda);
709  }
710 
711  /// ParallelForEach: const version, runnable on a const path table and
712  /// taking a (const SdfPath&, const mapped_type&) input.
713  template <typename Callback>
714  void ParallelForEach(Callback const& visitFn) const {
715  auto lambda =
716  [&visitFn](void*& voidEntry) {
717  const _Entry *entry = static_cast<const _Entry *>(voidEntry);
718  while (entry) {
719  visitFn(std::cref(entry->value.first),
720  std::cref(entry->value.second));
721  entry = entry->next;
722  }
723  };
725  // Note: the const cast here is undone by the static cast above...
726  reinterpret_cast<void **>(const_cast<_Entry**>(_buckets.data())),
727  _buckets.size(), lambda);
728  }
729 
730  /// @}
731 
732 private:
733 
734  // Helper to get parent paths.
735  static SdfPath _GetParentPath(SdfPath const &path) {
736  return path.GetParentPath();
737  }
738 
739  void _UpdateTreeForNewEntry(_IterBoolPair const &iresult) {
740  // New element -- make sure the parent is inserted.
741  _Entry * const newEntry = iresult.first._entry;
742  SdfPath const &parentPath = _GetParentPath(newEntry->value.first);
743  if (!parentPath.IsEmpty()) {
744  iterator parIter =
745  insert(value_type(parentPath, mapped_type())).first;
746  // Add the new entry to the parent's children.
747  parIter._entry->AddChild(newEntry);
748  }
749  }
750 
751  // Helper to insert \a value in the hash table. Is responsible for growing
752  // storage space when necessary. Does not consider the tree structure.
753  template <class MakeEntryFn>
754  _IterBoolPair _InsertInTableImpl(key_type const &key,
755  MakeEntryFn &&makeEntry) {
756  // If we have no storage at all so far, grow.
757  if (_mask == 0)
758  _Grow();
759 
760  // Find the item, if present.
761  _Entry **bucketHead = &(_buckets[_Hash(key)]);
762  for (_Entry *e = *bucketHead; e; e = e->next) {
763  if (e->value.first == key) {
764  return _IterBoolPair(iterator(e), false);
765  }
766  }
767 
768  // Not present. If the table is getting full then grow and re-find the
769  // bucket.
770  if (_IsTooFull()) {
771  _Grow();
772  bucketHead = &(_buckets[_Hash(key)]);
773  }
774 
775  // Make an entry and insert it in the list.
776  *bucketHead = std::forward<MakeEntryFn>(makeEntry)(*bucketHead);
777 
778  // One more element
779  ++_size;
780 
781  // Return the new item
782  return _IterBoolPair(iterator(*bucketHead), true);
783  }
784 
785  _IterBoolPair _InsertInTable(value_type const &value) {
786  return _InsertInTableImpl(
787  value.first, [&value](_Entry *next) {
788  return new _Entry(value, next);
789  });
790  }
791 
792  _IterBoolPair _InsertInTable(NodeHandle &&node) {
793  return _InsertInTableImpl(
794  node.GetKey(), [&node](_Entry *next) mutable {
795  node._unlinkedEntry->next = next;
796  return node._unlinkedEntry.release();
797  });
798  }
799 
800  // Erase \a entry from the hash table. Does not consider tree structure.
801  void _EraseFromTable(_Entry *entry) {
802  // Remove from table.
803  _Entry **cur = &_buckets[_Hash(entry->value.first)];
804  while (*cur != entry)
805  cur = &((*cur)->next);
806 
807  // Unlink item and destroy it
808  --_size;
809  _Entry *tmp = *cur;
810  *cur = tmp->next;
811  delete tmp;
812  }
813 
814  // Erase all the tree structure descendants of \a entry from the table.
815  void _EraseSubtree(_Entry *entry) {
816  // Delete descendant nodes, if any.
817  if (_Entry * const firstChild = entry->firstChild) {
818  _EraseSubtreeAndSiblings(firstChild);
819  _EraseFromTable(firstChild);
820  }
821  }
822 
823  // Erase all the tree structure descendants and siblings of \a entry from
824  // the table.
825  void _EraseSubtreeAndSiblings(_Entry *entry) {
826  // Remove subtree.
827  _EraseSubtree(entry);
828 
829  // And siblings.
830  _Entry *sibling = entry->GetNextSibling();
831  _Entry *nextSibling = sibling ? sibling->GetNextSibling() : nullptr;
832  while (sibling) {
833  _EraseSubtree(sibling);
834  _EraseFromTable(sibling);
835  sibling = nextSibling;
836  nextSibling = sibling ? sibling->GetNextSibling() : nullptr;
837  }
838  }
839 
840  // Remove \a entry from its parent's list of children in the tree structure
841  // alone. Does not consider the table.
842  void _RemoveFromParent(_Entry *entry) {
843  if (entry->value.first == SdfPath::AbsoluteRootPath())
844  return;
845 
846  // Find parent in table.
847  iterator parIter = find(_GetParentPath(entry->value.first));
848 
849  // Remove this entry from the parent's children.
850  parIter._entry->RemoveChild(entry);
851  }
852 
853  // Grow the table's number of buckets to the next larger size. Rehashes the
854  // elements into the new table, but leaves tree structure untouched. (The
855  // tree structure need not be modified).
856  void _Grow() {
857  TfAutoMallocTag2 tag2("Sdf", "SdfPathTable::_Grow");
858  TfAutoMallocTag tag(__ARCH_PRETTY_FUNCTION__);
859 
860  // Allocate a new bucket list of twice the size. Minimum nonzero number
861  // of buckets is 8.
862  _mask = std::max(size_t(7), (_mask << 1) + 1);
863  _BucketVec newBuckets(_mask + 1);
864 
865  // Move items to a new bucket list
866  for (size_t i = 0, n = _buckets.size(); i != n; ++i) {
867  _Entry *elem = _buckets[i];
868  while (elem) {
869  // Save pointer to next item
870  _Entry *next = elem->next;
871 
872  // Get the bucket in the new list
873  _Entry *&m = newBuckets[_Hash(elem->value.first)];
874 
875  // Insert the item at the head
876  elem->next = m;
877  m = elem;
878 
879  // Next item
880  elem = next;
881  }
882  }
883 
884  // Use the new buckets
885  _buckets.swap(newBuckets);
886  }
887 
888  // Return true if the table should be made bigger.
889  bool _IsTooFull() const {
890  return _size > _buckets.size();
891  }
892 
893  // Return the bucket index for \a path.
894  inline size_t _Hash(SdfPath const &path) const {
895  return path.GetHash() & _mask;
896  }
897 
898 private:
899  _BucketVec _buckets;
900  size_t _size;
901  size_t _mask;
902 
903 };
904 
906 
907 #endif // PXR_USD_SDF_PATH_TABLE_H
void ParallelForEach(Callback const &visitFn) const
Definition: pathTable.h:714
GLuint GLsizei const GLuint const GLintptr const GLsizeiptr * sizes
Definition: glcorearb.h:2621
GLint first
Definition: glcorearb.h:405
pointer operator->() const
Definition: pathTable.h:223
const_iterator begin() const
Return a const_iterator to the start of the table.
Definition: pathTable.h:466
_IterBoolPair insert(NodeHandle &&node)
Definition: pathTable.h:598
static SDF_API const SdfPath & AbsoluteRootPath()
~SdfPathTable()
Destructor.
Definition: pathTable.h:438
GLenum GLint * range
Definition: glcorearb.h:1925
key_type & GetMutableKey()
Definition: pathTable.h:357
SdfPathTable()
Default constructor.
Definition: pathTable.h:398
SdfPathTable & operator=(SdfPathTable const &other)
Copy assignment.
Definition: pathTable.h:444
const_iterator end() const
Return a const_iterator denoting the end of the table.
Definition: pathTable.h:479
bool operator!=(Iterator< OtherVal, OtherEntryPtr > const &other) const
Definition: pathTable.h:242
void swap(UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &a, UT::ArraySet< Key, MULTI, MAX_LOAD_FACTOR_256, Clearer, Hash, KeyEqual > &b)
Definition: UT_ArraySet.h:1639
const_iterator find(SdfPath const &path) const
Definition: pathTable.h:527
SdfPathTable & operator=(SdfPathTable &&other)
Move assignment.
Definition: pathTable.h:451
GLsizei const GLfloat * value
Definition: glcorearb.h:824
GLsizei const GLchar *const * path
Definition: glcorearb.h:3341
mapped_type const & GetMapped() const
Definition: pathTable.h:364
#define TF_CODING_ERROR
void ClearInParallel()
Definition: pathTable.h:636
Iterator GetNextSubtree() const
Definition: pathTable.h:249
SdfPath key_type
Definition: pathTable.h:86
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:415
void ParallelForEach(Callback const &visitFn)
Definition: pathTable.h:697
void UpdateForRename(const SdfPath &oldName, const SdfPath &newName)
Definition: pathTable.h:673
**But if you need a result
Definition: thread.h:613
static NodeHandle New(value_type &&value)
Definition: pathTable.h:335
Iterator(Iterator< OtherVal, OtherEntryPtr > const &other)
Copy constructor (also allows for converting non-const to const).
Definition: pathTable.h:218
static NodeHandle New(key_type const &key, mapped_type const &mapped)
Definition: pathTable.h:343
size_t GetHash() const
Equality operator.
Definition: path.h:960
Iterator(EntryPtr entry)
Definition: pathTable.h:280
iterator find(SdfPath const &path)
Definition: pathTable.h:514
mapped_type & GetMutableMapped()
Definition: pathTable.h:371
GLdouble n
Definition: glcorearb.h:2008
GLint ref
Definition: glcorearb.h:124
#define __ARCH_PRETTY_FUNCTION__
Definition: functionLite.h:46
std::forward_iterator_tag iterator_category
Definition: pathTable.h:206
std::ptrdiff_t difference_type
Definition: pathTable.h:210
void erase(iterator const &i)
Definition: pathTable.h:503
GLuint GLuint end
Definition: glcorearb.h:475
bool operator==(Iterator< OtherVal, OtherEntryPtr > const &other) const
Definition: pathTable.h:237
static NodeHandle New(value_type const &value)
Definition: pathTable.h:327
MappedType mapped_type
Definition: pathTable.h:87
SdfPathTable(SdfPathTable const &other)
Copy constructor.
Definition: pathTable.h:401
std::pair< iterator, iterator > FindSubtreeRange(SdfPath const &path)
Definition: pathTable.h:542
key_type const & GetKey() const
Definition: pathTable.h:350
Definition: path.h:290
friend class Iterator
Definition: pathTable.h:201
void clear()
Definition: pathTable.h:620
Iterator< const value_type, const _Entry * > const_iterator
Definition: pathTable.h:309
GLint j
Definition: glad.h:2733
iterator begin()
Return an iterator to the start of the table.
Definition: pathTable.h:458
#define SDF_API
Definition: api.h:40
GLsizeiptr size
Definition: glcorearb.h:664
reference operator*() const
Definition: pathTable.h:222
Iterator & operator++()
Definition: pathTable.h:225
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1432
size_t size() const
Return the number of elements in the table.
Definition: pathTable.h:566
bool equal(Iterator< OtherVal, OtherEntryPtr > const &other) const
Definition: pathTable.h:295
bool HasChild() const
Definition: pathTable.h:272
size_t count(SdfPath const &path) const
Return 1 if there is an element for path in the table, otherwise 0.
Definition: pathTable.h:561
Iterator operator++(int)
Definition: pathTable.h:230
SdfPathTable(SdfPathTable &&other)
Move constructor.
Definition: pathTable.h:428
ImageBuf OIIO_API max(Image_or_Const A, Image_or_Const B, ROI roi={}, int nthreads=0)
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
std::pair< const_iterator, const_iterator > FindSubtreeRange(SdfPath const &path) const
Definition: pathTable.h:553
if(num_boxed_items<=0)
Definition: UT_RTreeImpl.h:697
SDF_API SdfPath GetParentPath() const
bool erase(SdfPath const &path)
Definition: pathTable.h:489
mapped_type & operator[](SdfPath const &path)
Definition: pathTable.h:612
Definition: core.h:1131
PXR_NAMESPACE_OPEN_SCOPE SDF_API void Sdf_VisitPathTableInParallel(void **, size_t, TfFunctionRef< void(void *&)>)
bool empty() const
Return true if this table is empty.
Definition: pathTable.h:569
std::pair< iterator, bool > _IterBoolPair
Result type for insert().
Definition: pathTable.h:312
std::pair< key_type, mapped_type > value_type
Definition: pathTable.h:88
Iterator< value_type, _Entry * > iterator
Definition: pathTable.h:308
_IterBoolPair insert(value_type const &value)
Definition: pathTable.h:582
std::vector< size_t > GetBucketSizes() const
Return a vector of the count of elements in each bucket.
Definition: pathTable.h:660
ValType & dereference() const
Definition: pathTable.h:300
FMT_CONSTEXPR auto find(Ptr first, Ptr last, T value, Ptr &out) -> bool
Definition: core.h:2089
bool IsValid() const
Definition: pathTable.h:377
void swap(SdfPathTable &other)
Swap this table's contents with other.
Definition: pathTable.h:653
iterator end()
Return an iterator denoting the end of the table.
Definition: pathTable.h:474