pathTable.h
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"
30 #include "pxr/base/tf/pointerAndBits.h"
31 #include "pxr/base/tf/functionRef.h"
32 
33 #include <boost/iterator/iterator_facade.hpp>
34 #include <boost/noncopyable.hpp>
35 
36 #include <algorithm>
37 #include <utility>
38 #include <vector>
39 
40 PXR_NAMESPACE_OPEN_SCOPE
41 
42 // Parallel visitation helper function.
43 SDF_API
44 void Sdf_VisitPathTableInParallel(void **, size_t, TfFunctionRef<void(void*&)>);
45 
84 template <class MappedType>
86 {
87 public:
88 
89  typedef SdfPath key_type;
90  typedef MappedType mapped_type;
91  typedef std::pair<key_type, mapped_type> value_type;
92 
93 private:
94 
95  // An _Entry represents an item in the table. It holds the item's value, a
96  // pointer (\a next) to the next item in the hash bucket's linked list, and
97  // two pointers (\a firstChild and \a nextSibling) that describe the tree
98  // structure.
99  struct _Entry : boost::noncopyable {
100  _Entry(value_type const &value, _Entry *n)
101  : value(value)
102  , next(n)
103  , firstChild(0)
104  , nextSiblingOrParent(0, false) {}
105 
106  // If this entry's nextSiblingOrParent field points to a sibling, return
107  // a pointer to it, otherwise return null.
108  _Entry *GetNextSibling() {
109  return nextSiblingOrParent.template BitsAs<bool>() ?
110  nextSiblingOrParent.Get() : 0;
111  }
112  // If this entry's nextSiblingOrParent field points to a sibling, return
113  // a pointer to it, otherwise return null.
114  _Entry const *GetNextSibling() const {
115  return nextSiblingOrParent.template BitsAs<bool>() ?
116  nextSiblingOrParent.Get() : 0;
117  }
118 
119  // If this entry's nextSiblingOrParent field points to a parent, return
120  // a pointer to it, otherwise return null.
121  _Entry *GetParentLink() {
122  return nextSiblingOrParent.template BitsAs<bool>() ? 0 :
123  nextSiblingOrParent.Get();
124  }
125  // If this entry's nextSiblingOrParent field points to a parent, return
126  // a pointer to it, otherwise return null.
127  _Entry const *GetParentLink() const {
128  return nextSiblingOrParent.template BitsAs<bool>() ? 0 :
129  nextSiblingOrParent.Get();
130  }
131 
132  // Set this entry's nextSiblingOrParent field to point to the passed
133  // sibling.
134  void SetSibling(_Entry *sibling) {
135  nextSiblingOrParent.Set(sibling, /* isSibling */ true);
136  }
137 
138  // Set this entry's nextSiblingOrParent field to point to the passed
139  // parent.
140  void SetParentLink(_Entry *parent) {
141  nextSiblingOrParent.Set(parent, /* isSibling */ false);
142  }
143 
144  // Add \a child as a child of this entry.
145  void AddChild(_Entry *child) {
146  // If there are already one or more children, make \a child be our
147  // new first child. Otherwise, add \a child as the first child.
148  if (firstChild)
149  child->SetSibling(firstChild);
150  else
151  child->SetParentLink(this);
152  firstChild = child;
153  }
154 
155  void RemoveChild(_Entry *child) {
156  // Remove child from this _Entry's children.
157  if (child == firstChild) {
158  firstChild = child->GetNextSibling();
159  } else {
160  // Search the list to find the preceding child, then unlink the
161  // child to remove.
162  _Entry *prev, *cur = firstChild;
163  do {
164  prev = cur;
165  cur = prev->GetNextSibling();
166  } while (cur != child);
167  prev->nextSiblingOrParent = cur->nextSiblingOrParent;
168  }
169  }
170 
171  // The value object mapped by this entry.
172  value_type value;
173 
174  // The next field links together entries in chained hash table buckets.
175  _Entry *next;
176 
177  // The firstChild and nextSiblingOrParent fields describe the tree
178  // structure of paths. An entry has one or more children when
179  // firstChild is non null. Its chlidren are stored in a singly linked
180  // list, where nextSiblingOrParent points to the next entry in the list.
181  //
182  // The end of the list is reached when the bit stored in
183  // nextSiblingOrParent is set false, indicating a pointer to the parent
184  // rather than another sibling.
185  _Entry *firstChild;
186  TfPointerAndBits<_Entry> nextSiblingOrParent;
187  };
188 
189  // Hash table's list of buckets is a vector of _Entry ptrs.
190  typedef std::vector<_Entry *> _BucketVec;
191 
192 public:
193 
194  // The iterator class, used to make both const and non-const
195  // iterators. Currently only forward traversal is supported.
196  template <class, class> friend class Iterator;
197  template <class ValType, class EntryPtr>
198  class Iterator :
199  public boost::iterator_facade<Iterator<ValType, EntryPtr>,
200  ValType, boost::forward_traversal_tag>
201  {
202  public:
205  Iterator() {}
206 
208  template <class OtherVal, class OtherEntryPtr>
209  Iterator(Iterator<OtherVal, OtherEntryPtr> const &other)
210  : _entry(other._entry)
211  {}
212 
216  Iterator GetNextSubtree() const {
217  Iterator result(0);
218  if (_entry) {
219  if (EntryPtr sibling = _entry->GetNextSibling()) {
220  // Next subtree is next sibling, if present.
221  result._entry = sibling;
222  } else {
223  // Otherwise, walk up parents until we either find one with
224  // a next sibling or run out.
225  for (EntryPtr p = _entry->GetParentLink(); p;
226  p = p->GetParentLink()) {
227  if (EntryPtr sibling = p->GetNextSibling()) {
228  result._entry = sibling;
229  break;
230  }
231  }
232  }
233  }
234  return result;
235  }
236 
239  bool HasChild() const {
240  return bool(_entry->firstChild);
241  }
242 
243  protected:
244  friend class boost::iterator_core_access;
245  friend class SdfPathTable;
246  template <class, class> friend class Iterator;
247 
248  explicit Iterator(EntryPtr entry)
249  : _entry(entry) {}
250 
251  // Fundamental functionality to implement the iterator.
252  // boost::iterator_facade will invoke these as necessary to implement
253  // the full iterator public interface.
254 
255  // Iterator increment.
256  inline void increment() {
257  // Move to first child, if present. Otherwise move to next subtree.
258  _entry = _entry->firstChild ? _entry->firstChild :
259  GetNextSubtree()._entry;
260  }
261 
262  // Equality comparison. A template, to allow comparison between const
263  // and non-const iterators.
264  template <class OtherVal, class OtherEntryPtr>
265  bool equal(Iterator<OtherVal, OtherEntryPtr> const &other) const {
266  return _entry == other._entry;
267  }
268 
269  // Dereference.
270  ValType &dereference() const {
271  return _entry->value;
272  }
273 
274  // Store pointer to current entry.
275  EntryPtr _entry;
276  };
277 
278  typedef Iterator<value_type, _Entry *> iterator;
279  typedef Iterator<const value_type, const _Entry *> const_iterator;
280 
282  typedef std::pair<iterator, bool> _IterBoolPair;
283 
285  SdfPathTable() : _size(0), _mask(0) {}
286 
289  : _buckets(other._buckets.size())
290  , _size(0) // size starts at 0, since we insert elements.
291  , _mask(other._mask)
292  {
293  // Walk all elements in the other container, inserting into this one,
294  // and creating the right child/sibling links along the way.
295  for (const_iterator i = other.begin(), end = other.end();
296  i != end; ++i) {
297  iterator j = _InsertInTable(*i).first;
298  // Ensure first child and next sibling links are created.
299  if (i._entry->firstChild && !j._entry->firstChild) {
300  j._entry->firstChild =
301  _InsertInTable(i._entry->firstChild->value).first._entry;
302  }
303  // Ensure the nextSibling/parentLink is created.
304  if (i._entry->nextSiblingOrParent.Get() &&
305  !j._entry->nextSiblingOrParent.Get()) {
306  j._entry->nextSiblingOrParent.Set(
307  _InsertInTable(i._entry->nextSiblingOrParent.
308  Get()->value).first._entry,
309  i._entry->nextSiblingOrParent.template BitsAs<bool>());
310  }
311  }
312  }
313 
316  : _buckets(std::move(other._buckets))
317  , _size(other._size)
318  , _mask(other._mask)
319  {
320  other._size = 0;
321  other._mask = 0;
322  }
323 
326  // Call clear to free all nodes.
327  clear();
328  }
329 
332  if (this != &other)
333  SdfPathTable(other).swap(*this);
334  return *this;
335  }
336 
339  if (this != &other)
340  SdfPathTable(std::move(other)).swap(*this);
341  return *this;
342  }
343 
345  iterator begin() {
346  // Return an iterator pointing to the root if this table isn't empty.
347  if (empty())
348  return end();
350  }
351 
353  const_iterator begin() const {
354  // Return an iterator pointing to the root if this table isn't empty.
355  if (empty())
356  return end();
358  }
359 
361  iterator end() {
362  return iterator(0);
363  }
364 
366  const_iterator end() const {
367  return const_iterator(0);
368  }
369 
376  bool erase(SdfPath const &path) {
377  iterator i = find(path);
378  if (i == end())
379  return false;
380  erase(i);
381  return true;
382  }
383 
390  void erase(iterator const &i) {
391  // Delete descendant nodes, if any. Then remove from parent, finally
392  // erase from hash table.
393  _Entry * const entry = i._entry;
394  _EraseSubtree(entry);
395  _RemoveFromParent(entry);
396  _EraseFromTable(entry);
397  }
398 
401  iterator find(SdfPath const &path) {
402  if (!empty()) {
403  // Find the item in the list.
404  for (_Entry *e = _buckets[_Hash(path)]; e; e = e->next) {
405  if (e->value.first == path)
406  return iterator(e);
407  }
408  }
409  return end();
410  }
411 
414  const_iterator find(SdfPath const &path) const {
415  if (!empty()) {
416  // Find the item in the list.
417  for (_Entry const *e = _buckets[_Hash(path)]; e; e = e->next) {
418  if (e->value.first == path)
419  return const_iterator(e);
420  }
421  }
422  return end();
423  }
424 
428  std::pair<iterator, iterator>
429  FindSubtreeRange(SdfPath const &path) {
430  std::pair<iterator, iterator> result;
431  result.first = find(path);
432  result.second = result.first.GetNextSubtree();
433  return result;
434  }
435 
439  std::pair<const_iterator, const_iterator>
440  FindSubtreeRange(SdfPath const &path) const {
441  std::pair<const_iterator, const_iterator> result;
442  result.first = find(path);
443  result.second = result.first.GetNextSubtree();
444  return result;
445  }
446 
448  size_t count(SdfPath const &path) const {
449  return find(path) != end();
450  }
451 
453  inline size_t size() const { return _size; }
454 
456  inline bool empty() const { return !size(); }
457 
469  _IterBoolPair insert(value_type const &value) {
470  // Insert in table.
471  _IterBoolPair result = _InsertInTable(value);
472  if (result.second) {
473  // New element -- make sure the parent is inserted.
474  _Entry * const newEntry = result.first._entry;
475  SdfPath const &parentPath = _GetParentPath(value.first);
476  if (!parentPath.IsEmpty()) {
477  iterator parIter =
478  insert(value_type(parentPath, mapped_type())).first;
479  // Add the new entry to the parent's children.
480  parIter._entry->AddChild(newEntry);
481  }
482  }
483  return result;
484  }
485 
490  mapped_type &operator[](SdfPath const &path) {
491  return insert(value_type(path, mapped_type())).first->second;
492  }
493 
498  void clear() {
499  // Note this leaves the size of _buckets unchanged.
500  for (size_t i = 0, n = _buckets.size(); i != n; ++i) {
501  _Entry *entry = _buckets[i];
502  while (entry) {
503  _Entry *next = entry->next;
504  delete entry;
505  entry = next;
506  }
507  _buckets[i] = 0;
508  }
509  _size = 0;
510  }
511 
515  auto visitFn =
516  [](void*& voidEntry) {
517  _Entry *entry = static_cast<_Entry *>(voidEntry);
518  while (entry) {
519  _Entry *next = entry->next;
520  delete entry;
521  entry = next;
522  }
523  voidEntry = nullptr;
524  };
525  Sdf_VisitPathTableInParallel(reinterpret_cast<void **>(_buckets.data()),
526  _buckets.size(), visitFn);
527  _size = 0;
528  }
529 
531  void swap(SdfPathTable &other) {
532  _buckets.swap(other._buckets);
533  std::swap(_size, other._size);
534  std::swap(_mask, other._mask);
535  }
536 
538  std::vector<size_t> GetBucketSizes() const {
539  std::vector<size_t> sizes(_buckets.size(), 0u);;
540  for (size_t i = 0, n = _buckets.size(); i != n; ++i) {
541  for (_Entry *entry = _buckets[i]; entry; entry = entry->next) {
542  sizes[i]++;
543  }
544  }
545  return sizes;
546  }
547 
551  void UpdateForRename(const SdfPath &oldName, const SdfPath &newName) {
552 
553  if (oldName.GetParentPath() != newName.GetParentPath()) {
554  TF_CODING_ERROR("Unexpected arguments.");
555  return;
556  }
557 
558  std::pair<iterator, iterator> range = FindSubtreeRange(oldName);
559  for (iterator i=range.first; i!=range.second; ++i) {
560  insert(value_type(
561  i->first.ReplacePrefix(oldName, newName),
562  i->second));
563  }
564 
565  if (range.first != range.second)
566  erase(oldName);
567  }
568 
574  template <typename Callback>
575  void ParallelForEach(Callback const& visitFn) {
576  auto lambda =
577  [&visitFn](void*& voidEntry) {
578  _Entry *entry = static_cast<_Entry *>(voidEntry);
579  while (entry) {
580  visitFn(std::cref(entry->value.first),
581  std::ref(entry->value.second));
582  entry = entry->next;
583  }
584  };
585  Sdf_VisitPathTableInParallel(reinterpret_cast<void **>(_buckets.data()),
586  _buckets.size(), lambda);
587  }
588 
591  template <typename Callback>
592  void ParallelForEach(Callback const& visitFn) const {
593  auto lambda =
594  [&visitFn](void*& voidEntry) {
595  const _Entry *entry = static_cast<const _Entry *>(voidEntry);
596  while (entry) {
597  visitFn(std::cref(entry->value.first),
598  std::cref(entry->value.second));
599  entry = entry->next;
600  }
601  };
602  Sdf_VisitPathTableInParallel(
603  // Note: the const cast here is undone by the static cast above...
604  reinterpret_cast<void **>(const_cast<_Entry**>(_buckets.data())),
605  _buckets.size(), lambda);
606  }
607 
609 
610 private:
611 
612  // Helper to get parent paths.
613  static SdfPath _GetParentPath(SdfPath const &path) {
614  return path.GetParentPath();
615  }
616 
617  // Helper to insert \a value in the hash table. Is responsible for growing
618  // storage space when necessary. Does not consider the tree structure.
619  _IterBoolPair _InsertInTable(value_type const &value) {
620  // If we have no storage at all so far, grow.
621  if (_mask == 0)
622  _Grow();
623 
624  // Find the item, if present.
625  _Entry **bucketHead = &(_buckets[_Hash(value.first)]);
626  for (_Entry *e = *bucketHead; e; e = e->next)
627  if (e->value.first == value.first)
628  return _IterBoolPair(iterator(e), false);
629 
630  // Not present. If the table is getting full then grow and re-find the
631  // bucket.
632  if (_IsTooFull()) {
633  _Grow();
634  bucketHead = &(_buckets[_Hash(value.first)]);
635  }
636 
637  TfAutoMallocTag2 tag2("Sdf", "SdfPathTable::_FindOrCreate");
638  TfAutoMallocTag tag(__ARCH_PRETTY_FUNCTION__);
639 
640  // Create a new item and insert it in the list
641  *bucketHead = new _Entry(value, *bucketHead);
642 
643  // One more element
644  ++_size;
645 
646  // Return the new item
647  return _IterBoolPair(iterator(*bucketHead), true);
648  }
649 
650  // Erase \a entry from the hash table. Does not consider tree structure.
651  void _EraseFromTable(_Entry *entry) {
652  // Remove from table.
653  _Entry **cur = &_buckets[_Hash(entry->value.first)];
654  while (*cur != entry)
655  cur = &((*cur)->next);
656 
657  // Unlink item and destroy it
658  --_size;
659  _Entry *tmp = *cur;
660  *cur = tmp->next;
661  delete tmp;
662  }
663 
664  // Erase all the tree structure descendants of \a entry from the table.
665  void _EraseSubtree(_Entry *entry) {
666  // Delete descendant nodes, if any.
667  if (_Entry * const firstChild = entry->firstChild) {
668  _EraseSubtreeAndSiblings(firstChild);
669  _EraseFromTable(firstChild);
670  }
671  }
672 
673  // Erase all the tree structure descendants and siblings of \a entry from
674  // the table.
675  void _EraseSubtreeAndSiblings(_Entry *entry) {
676  // Remove subtree.
677  _EraseSubtree(entry);
678 
679  // And siblings.
680  _Entry *sibling = entry->GetNextSibling();
681  _Entry *nextSibling = sibling ? sibling->GetNextSibling() : nullptr;
682  while (sibling) {
683  _EraseSubtree(sibling);
684  _EraseFromTable(sibling);
685  sibling = nextSibling;
686  nextSibling = sibling ? sibling->GetNextSibling() : nullptr;
687  }
688  }
689 
690  // Remove \a entry from its parent's list of children in the tree structure
691  // alone. Does not consider the table.
692  void _RemoveFromParent(_Entry *entry) {
693  if (entry->value.first == SdfPath::AbsoluteRootPath())
694  return;
695 
696  // Find parent in table.
697  iterator parIter = find(_GetParentPath(entry->value.first));
698 
699  // Remove this entry from the parent's children.
700  parIter._entry->RemoveChild(entry);
701  }
702 
703  // Grow the table's number of buckets to the next larger size. Rehashes the
704  // elements into the new table, but leaves tree structure untouched. (The
705  // tree structure need not be modified).
706  void _Grow() {
707  TfAutoMallocTag2 tag2("Sdf", "SdfPathTable::_Grow");
708  TfAutoMallocTag tag(__ARCH_PRETTY_FUNCTION__);
709 
710  // Allocate a new bucket list of twice the size. Minimum nonzero number
711  // of buckets is 8.
712  _mask = std::max(size_t(7), (_mask << 1) + 1);
713  _BucketVec newBuckets(_mask + 1);
714 
715  // Move items to a new bucket list
716  for (size_t i = 0, n = _buckets.size(); i != n; ++i) {
717  _Entry *elem = _buckets[i];
718  while (elem) {
719  // Save pointer to next item
720  _Entry *next = elem->next;
721 
722  // Get the bucket in the new list
723  _Entry *&m = newBuckets[_Hash(elem->value.first)];
724 
725  // Insert the item at the head
726  elem->next = m;
727  m = elem;
728 
729  // Next item
730  elem = next;
731  }
732  }
733 
734  // Use the new buckets
735  _buckets.swap(newBuckets);
736  }
737 
738  // Return true if the table should be made bigger.
739  bool _IsTooFull() const {
740  return _size > _buckets.size();
741  }
742 
743  // Return the bucket index for \a path.
744  inline size_t _Hash(SdfPath const &path) const {
745  return path.GetHash() & _mask;
746  }
747 
748 private:
749  _BucketVec _buckets;
750  size_t _size;
751  size_t _mask;
752 
753 };
754 
755 PXR_NAMESPACE_CLOSE_SCOPE
756 
757 #endif // PXR_USD_SDF_PATH_TABLE_H
const_iterator end() const
Return a const_iterator denoting the end of the table.
Definition: pathTable.h:366
size_t size() const
Return the number of elements in the table.
Definition: pathTable.h:453
void UpdateForRename(const SdfPath &oldName, const SdfPath &newName)
Replaces all prefixes from oldName to newName.
Definition: pathTable.h:551
SdfPathTable & operator=(SdfPathTable &&other)
Move assignment.
Definition: pathTable.h:338
size_t count(SdfPath const &path) const
Return 1 if there is an element for path in the table, otherwise 0.
Definition: pathTable.h:448
~SdfPathTable()
Destructor.
Definition: pathTable.h:325
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition: diagnostic.h:85
SdfPathTable & operator=(SdfPathTable const &other)
Copy assignment.
Definition: pathTable.h:331
mapped_type & operator[](SdfPath const &path)
Shorthand for the following, where t is an SdfPathTable<T>.
Definition: pathTable.h:490
const_iterator find(SdfPath const &path) const
Return a const_iterator to the element corresponding to path, or end() if there is none.
Definition: pathTable.h:414
std::pair< iterator, bool > _IterBoolPair
Result type for insert().
Definition: pathTable.h:282
Scoped (i.e.
Definition: mallocTag.h:349
SDF_API SdfPath GetParentPath() const
Return the path that identifies this path's namespace parent.
This class provides a non-owning reference to a type-erased callable object with a specified signatur...
Definition: functionRef.h:36
SdfPathTable(SdfPathTable const &other)
Copy constructor.
Definition: pathTable.h:288
void ParallelForEach(Callback const &visitFn) const
ParallelForEach: const version, runnable on a const path table and taking a (const SdfPath&,...
Definition: pathTable.h:592
SdfPathTable(SdfPathTable &&other)
Move constructor.
Definition: pathTable.h:315
std::pair< const_iterator, const_iterator > FindSubtreeRange(SdfPath const &path) const
Return a pair of const_iterators [b, e), describing the maximal range such that for all i in the rang...
Definition: pathTable.h:440
void swap(UsdStageLoadRules &l, UsdStageLoadRules &r)
Swap the contents of rules l and r.
bool empty() const
Return true if this table is empty.
Definition: pathTable.h:456
iterator end()
Return an iterator denoting the end of the table.
Definition: pathTable.h:361
bool erase(SdfPath const &path)
Remove the element with path path from the table as well as all elements whose paths are prefixed by ...
Definition: pathTable.h:376
Scoped (i.e.
Definition: mallocTag.h:262
void ParallelForEach(Callback const &visitFn)
ParallelForEach: parallel iteration over all of the key-value pairs in the path table.
Definition: pathTable.h:575
const_iterator begin() const
Return a const_iterator to the start of the table.
Definition: pathTable.h:353
A path value used to locate objects in layers or scenegraphs.
Definition: path.h:290
iterator begin()
Return an iterator to the start of the table.
Definition: pathTable.h:345
_IterBoolPair insert(value_type const &value)
Insert value into the table, and additionally insert default entries for all ancestral paths of value...
Definition: pathTable.h:469
void clear()
Remove all elements from the table, leaving size() == 0.
Definition: pathTable.h:498
SdfPathTable()
Default constructor.
Definition: pathTable.h:285
std::vector< size_t > GetBucketSizes() const
Return a vector of the count of elements in each bucket.
Definition: pathTable.h:538
static SDF_API const SdfPath & AbsoluteRootPath()
The absolute path representing the top of the namespace hierarchy.
void swap(SdfPathTable &other)
Swap this table's contents with other.
Definition: pathTable.h:531
iterator find(SdfPath const &path)
Return an iterator to the element corresponding to path, or end() if there is none.
Definition: pathTable.h:401
A mapping from SdfPath to MappedType, somewhat similar to map<SdfPath, MappedType> and TfHashMap<SdfP...
Definition: pathTable.h:85
std::pair< iterator, iterator > FindSubtreeRange(SdfPath const &path)
Return a pair of iterators [b, e), describing the maximal range such that for all i in the range,...
Definition: pathTable.h:429
void erase(iterator const &i)
Remove the element pointed to by i from the table as well as all elements whose paths are prefixed by...
Definition: pathTable.h:390
bool IsEmpty() const noexcept
Returns true if this is the empty path (SdfPath::EmptyPath()).
Definition: path.h:419
void ClearInParallel()
Equivalent to clear(), but destroy contained objects in parallel.
Definition: pathTable.h:514