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