Loading...
Searching...
No Matches
mapEditProxy.h
Go to the documentation of this file.
1//
2// Copyright 2016 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7#ifndef PXR_USD_SDF_MAP_EDIT_PROXY_H
8#define PXR_USD_SDF_MAP_EDIT_PROXY_H
9
11
12#include "pxr/pxr.h"
13#include "pxr/usd/sdf/allowed.h"
14#include "pxr/usd/sdf/changeBlock.h"
16#include "pxr/usd/sdf/spec.h"
17
18#include "pxr/base/vt/value.h" // for Vt_DefaultValueFactory
19#include "pxr/base/vt/valueRef.h"
22#include "pxr/base/tf/token.h"
23#include <iterator>
24#include <string>
25#include <utility>
26
27PXR_NAMESPACE_OPEN_SCOPE
28
29SDF_DECLARE_HANDLES(SdfSpec);
30
37protected:
38 SdfMapEditProxyBase() = default;
39
40 SDF_API
41 SdfMapEditProxyBase(const SdfSpecHandle& owner, const TfToken& field);
42
43 SDF_API bool _IsExpired() const;
44 SDF_API std::string _Location() const;
45 SDF_API SdfAllowed _IsValidKey(const VtValueRef& key) const;
46 SDF_API SdfAllowed _IsValidValue(const VtValueRef& value) const;
47 SDF_API void _WriteToSpec(const VtValueRef& value);
48
49 SdfSpecHandle _owner;
50 TfToken _field;
51};
52
65template <class T>
67public:
68 typedef T Type;
69 typedef typename Type::key_type key_type;
70 typedef typename Type::mapped_type mapped_type;
71 typedef typename Type::value_type value_type;
72
76 static const Type& CanonicalizeType(const SdfSpecHandle&, const Type& x)
77 {
78 return x;
79 }
80
83 static const key_type& CanonicalizeKey(const SdfSpecHandle&,
84 const key_type& x)
85 {
86 return x;
87 }
88
91 static const mapped_type& CanonicalizeValue(const SdfSpecHandle&,
92 const mapped_type& x)
93 {
94 return x;
95 }
96
100 static const value_type& CanonicalizePair(const SdfSpecHandle&,
101 const value_type& x)
102 {
103 return x;
104 }
105};
106
121template <class T, class _ValuePolicy = SdfIdentityMapEditProxyValuePolicy<T> >
123public:
124 typedef T Type;
125 typedef _ValuePolicy ValuePolicy;
127 typedef typename Type::key_type key_type;
128 typedef typename Type::mapped_type mapped_type;
129 typedef typename Type::value_type value_type;
130
131private:
132 // Note: We're playing a dangerous game with copy-on-write and
133 // iterators. Our iterators wrap iterators on the proxied
134 // Type. When and if we copy-on-write then all of our
135 // existing iterators use the old proxied object's iterators
136 // and any new iterators will use the new proxied object's
137 // iterators. Therefore old and new iterators are no longer
138 // compatible and an old and new iterator that refer to the
139 // same key will not compare equal.
140 //
141 // It turns out that this is okay because we don't promise
142 // to keep iterators valid across an edit. However, we'd
143 // like dereferencing an old iterator to either report an
144 // error or yield the current state. We can do that by
145 // storing the Type* in use when the iterator was created
146 // and comparing it to the current Type*. If they're
147 // different we need to report an error or use the key from
148 // the old iterator and lookup that key in the new Type*.
149 // We currently choose to return the current state.
150
151 typedef typename Type::iterator inner_iterator;
152 typedef typename Type::const_iterator const_inner_iterator;
153
154 class _ValueProxy {
155 public:
156 _ValueProxy(This* owner, const Type* data, inner_iterator i) :
157 _owner(owner), _data(data), _pos(i)
158 {
159 // Do nothing
160 }
161
162 template <class U>
163 _ValueProxy& operator=(const U& other)
164 {
165 if (!_owner) {
166 TF_CODING_ERROR("Assignment to invalid map proxy");
167 } else {
168 _owner->_Set(_data, _pos, other);
169 }
170 return *this;
171 }
172
173 operator mapped_type() const
174 {
175 return Get();
176 }
177
178 // Required for _PairProxy::operator value_type().
179 mapped_type Get() const
180 {
181 if (!_owner) {
182 TF_CODING_ERROR("Read from invalid map proxy");
183 return mapped_type();
184 }
185 return _owner->_Get(_data, _pos);
186 }
187
188 private:
189 This* _owner;
190 const Type* _data;
191 inner_iterator _pos;
192 };
193
194 class _PairProxy {
195 public:
196 explicit _PairProxy(This* owner, const Type* data, inner_iterator i) :
197 first(i->first), second(_ValueProxy(owner, data, i)) { }
198
199 const key_type first;
200 _ValueProxy second;
201
202 operator value_type() const
203 {
204 // Note that we cannot simply use 'second' or we'll use the
205 // mapped_type c'tor instead of the _ValueProxy implicit
206 // conversion if one is available. If mapped_type is VtValue
207 // then we'll type erase _ValueProxy instead of just getting
208 // the VtValue out of the _ValueProxy.
209 return value_type(first, second.Get());
210 }
211 };
212
213 class Traits {
214 public:
215 static _PairProxy Dereference(This* owner,
216 const Type* data, inner_iterator i)
217 {
218 if (!owner) {
219 TF_FATAL_ERROR("Dereferenced an invalid map proxy iterator");
220 }
221 return _PairProxy(owner, data, i);
222 }
223
224 static const value_type& Dereference(const This* owner,
225 const Type* data,
226 const_inner_iterator i)
227 {
228 if (!owner) {
229 TF_FATAL_ERROR("Dereferenced an invalid map proxy iterator");
230 }
231 return owner->_Get(data, i);
232 }
233 };
234
235 template <class Owner, class I, class R>
236 class _Iterator {
237 class _PtrProxy {
238 public:
239 std::add_pointer_t<R> operator->() {
240 return std::addressof(_result);
241 }
242 private:
243 friend class _Iterator;
244 explicit _PtrProxy(const R& result) : _result(result) {}
245 R _result;
246 };
247 public:
248 using iterator_category = std::bidirectional_iterator_tag;
249 using value_type = R;
250 using reference = R;
251 using pointer = std::conditional_t<std::is_lvalue_reference<R>::value,
252 std::add_pointer_t<R>, _PtrProxy>;
253 using difference_type = std::ptrdiff_t;
254
255 _Iterator() = default;
256
257 _Iterator(Owner owner, const Type* data, I i) :
258 _owner(owner), _data(data), _pos(i)
259 {
260 // Do nothing
261 }
262
263 template <class Owner2, class I2, class R2>
264 _Iterator(const _Iterator<Owner2, I2, R2>& other) :
265 _owner(other._owner), _data(other._data), _pos(other._pos)
266 {
267 // Do nothing
268 }
269
270 reference operator*() const { return dereference(); }
271
272 // In C++20, when pointer can be `void` and `operator->` elided,
273 // this conditional behavior may be deprecated. The `operator->`
274 // implementation is keyed off of whether the underlying pointer
275 // requires a proxy type
276 template <typename PointerType=pointer,
277 typename std::enable_if_t<
278 std::is_pointer<PointerType>::value, int> = 0>
279 pointer operator->() const { return std::addressof(dereference()); }
280 template <typename PointerType=pointer,
281 typename std::enable_if_t<
282 !std::is_pointer<PointerType>::value, int> = 0>
283 pointer operator->() const { return pointer(dereference()); }
284
285
286 const I& base() const
287 {
288 return _pos;
289 }
290
291 _Iterator& operator++() {
292 increment();
293 return *this;
294 }
295
296 _Iterator& operator--() {
297 decrement();
298 return *this;
299 }
300
301 _Iterator operator++(int) {
302 _Iterator result(*this);
303 increment();
304 return result;
305 }
306
307 _Iterator operator--(int) {
308 _Iterator result(*this);
309 decrement();
310 return result;
311 }
312
313 template <class Owner2, class I2, class R2>
314 bool operator==(const _Iterator<Owner2, I2, R2>& other) const {
315 return equal(other);
316 }
317
318 template <class Owner2, class I2, class R2>
319 bool operator!=(const _Iterator<Owner2, I2, R2>& other) const {
320 return !equal(other);
321 }
322
323 private:
324 R dereference() const
325 {
326 return Traits::Dereference(_owner, _data, _pos);
327 }
328
329 template <class Owner2, class I2, class R2>
330 bool equal(const _Iterator<Owner2, I2, R2>& other) const
331 {
332 if (_owner == other._owner && _pos == other._pos) {
333 return true;
334 }
335 else {
336 // All iterators at the end compare equal.
337 return atEnd() && other.atEnd();
338 }
339 }
340
341 void increment() {
342 ++_pos;
343 }
344
345 void decrement() {
346 --_pos;
347 }
348
349 bool atEnd() const {
350 // We consider an iterator with no owner to be at the end.
351 return !_owner || _pos == _owner->_ConstData()->end();
352 }
353
354 private:
355 Owner _owner = nullptr;
356 const Type* _data = nullptr;
357 I _pos;
358
359 template <class Owner2, class I2, class R2> friend class _Iterator;
360 };
361
362public:
363 typedef _ValueProxy reference;
364 typedef const value_type& const_reference;
365 typedef size_t size_type;
366 typedef ptrdiff_t difference_type;
367 typedef _Iterator<This*, inner_iterator, _PairProxy> iterator;
368 typedef _Iterator<const This*, const_inner_iterator,
369 const value_type&> const_iterator;
370 typedef Tf_ProxyReferenceReverseIterator<iterator> reverse_iterator;
371 typedef Tf_ProxyReferenceReverseIterator<const_iterator> const_reverse_iterator;
372
373 explicit SdfMapEditProxy(const SdfSpecHandle& owner, const TfToken& field)
374 : SdfMapEditProxyBase(owner, field)
375 {
376 const VtValue& dataVal = _owner->GetField(_field);
377 if (dataVal.IsHolding<T>()) {
378 _data = dataVal.UncheckedGet<T>();
379 }
380 else if (!dataVal.IsEmpty()) {
381 TF_CODING_ERROR("%s does not hold value of expected type.",
382 _Location().c_str());
383 }
384 }
385
386 SdfMapEditProxy() = default;
387
388 This& operator=(const This& other)
389 {
390 if (other._Validate()) {
391 _Copy(*other._ConstData());
392 }
393 return *this;
394 }
395
396 template <class U, class UVP>
397 This& operator=(const SdfMapEditProxy<U, UVP>& other)
398 {
399 if (other._Validate()) {
400 _Copy(Type(other._ConstData()->begin(), other._ConstData()->end()));
401 }
402 return *this;
403 }
404
405 This& operator=(const Type& data)
406 {
407 _Copy(data);
408 return *this;
409 }
410
412 operator Type() const
413 {
414 return _Validate() ? *_ConstData() : Type();
415 }
416
417 iterator begin()
418 {
419 return _Validate() ? iterator(this, _Data(), _Data()->begin()) :
420 iterator();
421 }
422 iterator end()
423 {
424 return _Validate() ? iterator(this, _Data(), _Data()->end()) :
425 iterator();
426 }
427 const_iterator begin() const
428 {
429 return _Validate() ?
430 const_iterator(this, _ConstData(), _ConstData()->begin()) :
431 const_iterator();
432 }
433 const_iterator end() const
434 {
435 return _Validate() ?
436 const_iterator(this, _ConstData(), _ConstData()->end()) :
437 const_iterator();
438 }
439
440 reverse_iterator rbegin()
441 {
442 return reverse_iterator(end());
443 }
444 reverse_iterator rend()
445 {
446 return reverse_iterator(begin());
447 }
448 const_reverse_iterator rbegin() const
449 {
450 return const_reverse_iterator(end());
451 }
452 const_reverse_iterator rend() const
453 {
454 return const_reverse_iterator(begin());
455 }
456
457 size_type size() const
458 {
459 return _Validate() ? _ConstData()->size() : 0;
460 }
461
462 size_type max_size() const
463 {
464 return _Validate() ? _ConstData()->max_size() : 0;
465 }
466
467 bool empty() const
468 {
469 return _Validate() ? _ConstData()->empty() : true;
470 }
471
472 std::pair<iterator, bool> insert(const value_type& value)
473 {
474 return _Insert(value);
475 }
476
477 iterator insert(iterator pos, const value_type& value)
478 {
479 return _Insert(value).first;
480 }
481
482 template <class InputIterator>
483 void insert(InputIterator first, InputIterator last)
484 {
485 if (_Validate()) {
486 SdfChangeBlock block;
487 for (; first != last; ++first) {
488 const value_type& v =
489 ValuePolicy::CanonicalizePair(_Owner(), *first);
490
491 if (_ValidateInsert(v) && _data.insert(v).second) {
492 _UpdateDataInSpec();
493 }
494 }
495 }
496 }
497
498 void erase(iterator pos)
499 {
500 if (_Validate() && _ValidateErase(pos->first)) {
501 _Erase(pos->first);
502 }
503 }
504
505 size_type erase(const key_type& key)
506 {
507 if (_Validate()) {
508 const key_type& k = ValuePolicy::CanonicalizeKey(_Owner(), key);
509 if (_ValidateErase(k) && _data.erase(k) != 0) {
510 _UpdateDataInSpec();
511 return 1;
512 }
513 }
514 return 0;
515 }
516
517 void erase(iterator first, iterator last)
518 {
519 if (_Validate()) {
520 SdfChangeBlock block;
521 while (first != last) {
522 const key_type& key = first->first;
523 ++first;
524 if (_ValidateErase(key) && _data.erase(key) != 0) {
525 _UpdateDataInSpec();
526 }
527 }
528 }
529 }
530
531 void clear()
532 {
533 _Copy(Type());
534 }
535
536 iterator find(const key_type& key)
537 {
538 return
539 _Validate() ?
540 iterator(this, _Data(),
541 _Data()->find(ValuePolicy::CanonicalizeKey(_Owner(), key))) :
542 iterator();
543 }
544
545 const_iterator find(const key_type& key) const
546 {
547 return
548 _Validate() ?
549 const_iterator(this, _ConstData(),
550 _ConstData()->find(
551 ValuePolicy::CanonicalizeKey(_Owner(), key))) :
552 const_iterator();
553 }
554
555 size_type count(const key_type& key) const
556 {
557 return
558 _Validate() ?
559 _ConstData()->count(
560 ValuePolicy::CanonicalizeKey(_Owner(), key)) :
561 0;
562 }
563
564 iterator lower_bound(const key_type& key)
565 {
566 return
567 _Validate() ?
568 iterator(this, _Data(),
569 _Data()->lower_bound(
570 ValuePolicy::CanonicalizeKey(_Owner(), key))) :
571 iterator();
572 }
573
574 const_iterator lower_bound(const key_type& key) const
575 {
576 return
577 _Validate() ?
578 const_iterator(this, _ConstData(),
579 _ConstData()->lower_bound(
580 ValuePolicy::CanonicalizeKey(_Owner(), key))) :
581 const_iterator();
582 }
583
584 iterator upper_bound(const key_type& key)
585 {
586 return
587 _Validate() ?
588 iterator(this, _Data(),
589 _Data()->upper_bound(
590 ValuePolicy::CanonicalizeKey(_Owner(), key))) :
591 iterator();
592 }
593
594 const_iterator upper_bound(const key_type& key) const
595 {
596 return
597 _Validate() ?
598 const_iterator(this, _ConstData(),
599 _ConstData()->upper_bound(
600 ValuePolicy::CanonicalizeKey(_Owner(), key))) :
601 const_iterator();
602 }
603
604 std::pair<iterator, iterator> equal_range(const key_type& key)
605 {
606 if (_Validate()) {
607 std::pair<inner_iterator, inner_iterator> result =
608 _Data()->equal_range(
609 ValuePolicy::CanonicalizeKey(_Owner(), key));
610 return std::make_pair(iterator(this, _Data(), result.first),
611 iterator(this, _Data(), result.second));
612 }
613 else {
614 return std::make_pair(iterator(), iterator());
615 }
616 }
617
618 std::pair<const_iterator,const_iterator>
619 equal_range(const key_type& key) const
620 {
621 if (_Validate()) {
622 std::pair<const_inner_iterator, const_inner_iterator> result =
623 _ConstData()->equal_range(
624 ValuePolicy::CanonicalizeKey(_Owner(), key));
625 return std::make_pair(
626 const_iterator(this, _ConstData(), result.first),
627 const_iterator(this, _ConstData(), result.second));
628 }
629 else {
630 return std::make_pair(const_iterator(), const_iterator());
631 }
632 }
633
634 reference operator[](const key_type& key)
635 {
636 auto iter = _Insert(value_type(key, mapped_type())).first;
637 bool failed = iter == iterator();
638 return reference(failed ? nullptr : this,
639 failed ? nullptr : _Data(),
640 iter.base());
641 }
642
643 bool operator==(const Type& other) const
644 {
645 return _Validate() ? _CompareEqual(other) : false;
646 }
647
648 bool operator!=(const Type& other) const
649 {
650 return !(*this == other);
651 }
652
653 friend bool operator==(const Type& lhs, const SdfMapEditProxy& rhs)
654 {
655 return rhs == lhs;
656 }
657
658 friend bool operator!=(const Type& lhs, const SdfMapEditProxy& rhs)
659 {
660 return rhs != lhs;
661 }
662
665 bool operator<(const Type& other) const
666 {
667 return !_Validate() || _Compare(other) < 0;
668 }
669
670 bool operator>(const Type& other) const
671 {
672 return _Validate() ? _Compare(other) > 0 : false;
673 }
674
675 bool operator>=(const Type& other) const
676 {
677 return !(*this < other);
678 }
679
680 bool operator<=(const Type& other) const
681 {
682 return !(*this > other);
683 }
684
685 friend bool operator<(const Type& lhs, const SdfMapEditProxy& rhs)
686 {
687 return rhs > lhs;
688 }
689
690 friend bool operator>(const Type& lhs, const SdfMapEditProxy& rhs)
691 {
692 return rhs < lhs;
693 }
694
695 friend bool operator<=(const Type& lhs, const SdfMapEditProxy& rhs)
696 {
697 return rhs >= lhs;
698 }
699
700 friend bool operator>=(const Type& lhs, const SdfMapEditProxy& rhs)
701 {
702 return rhs <= lhs;
703 }
704
707 template <class U, class UVP>
708 bool operator==(const SdfMapEditProxy<U, UVP>& other) const
709 {
710 const bool isValid = _Validate();
711 const bool otherIsValid = other._Validate();
712
713 return isValid && otherIsValid ?
714 _CompareEqual(*other._ConstData()) : isValid == otherIsValid;
715 }
716
717 template <class U, class UVP>
718 bool operator!=(const SdfMapEditProxy<U, UVP>& other) const
719 {
720 return !(*this == other);
721 }
722
723 template <class U, class UVP>
724 bool operator<(const SdfMapEditProxy<U, UVP>& other) const
725 {
726 return _Validate() && other._Validate() ?
727 _Compare(*other._ConstData()) < 0 : false;
728 }
729
730 template <class U, class UVP>
731 bool operator<=(const SdfMapEditProxy<U, UVP>& other) const
732 {
733 return _Validate() && other._Validate() ?
734 _Compare(*other._ConstData()) <= 0 : false;
735 }
736
737 template <class U, class UVP>
738 bool operator>(const SdfMapEditProxy<U, UVP>& other) const
739 {
740 return !(*this <= other);
741 }
742
743 template <class U, class UVP>
744 bool operator>=(const SdfMapEditProxy<U, UVP>& other) const
745 {
746 return !(*this < other);
747 }
748
751 bool IsExpired() const
752 {
753 return _IsExpired();
754 }
755
758 explicit operator bool() const
759 {
760 return _ConstData() && !IsExpired();
761 }
762
763private:
764 bool _Validate()
765 {
766 if (_ConstData() && !IsExpired()) {
767 return true;
768 }
769 else {
770 TF_CODING_ERROR("Editing an invalid map proxy");
771 return false;
772 }
773 }
774
775 bool _Validate() const
776 {
777 if (_ConstData() && !IsExpired()) {
778 return true;
779 }
780 else {
781 TF_CODING_ERROR("Accessing an invalid map proxy");
782 return false;
783 }
784 }
785
786 Type* _Data()
787 {
788 return _owner ? &_data : nullptr;
789 }
790
791 const Type* _ConstData() const
792 {
793 return _owner ? &_data : nullptr;
794 }
795
796 SdfSpecHandle _Owner() const
797 {
798 return _owner;
799 }
800
801 bool _CompareEqual(const Type& other) const
802 {
803 if (_ConstData()->size() < other.size()) {
804 return false;
805 }
806 if (_ConstData()->size() > other.size()) {
807 return false;
808 }
809
810 // Same size -- find the first mismatch.
811 const Type& x = ValuePolicy::CanonicalizeType(_Owner(), other);
812 std::pair<const_inner_iterator, const_inner_iterator> result =
813 std::mismatch(_ConstData()->begin(), _ConstData()->end(),
814 x.begin());
815 return result.first == _ConstData()->end();
816 }
817
818 int _Compare(const Type& other) const
819 {
820 if (_ConstData()->size() < other.size()) {
821 return -1;
822 }
823 if (_ConstData()->size() > other.size()) {
824 return 1;
825 }
826
827 // Same size -- find the first mismatch.
828 const Type& x = ValuePolicy::CanonicalizeType(_Owner(), other);
829 std::pair<const_inner_iterator, const_inner_iterator> result =
830 std::mismatch(_ConstData()->begin(), _ConstData()->end(),
831 x.begin());
832 if (*result.first < *result.second) {
833 return -1;
834 }
835 else if (*result.first > *result.second) {
836 return 1;
837 }
838 else {
839 return 0;
840 }
841 }
842
843 template <class D>
844 bool _CompareEqual(const D& other) const
845 {
846 // This is expensive but yields reliable results.
847 return _CompareEqual(Type(other.begin(), other.end()));
848 }
849
850 template <class D>
851 int _Compare(const D& other) const
852 {
853 // This is expensive but yields reliable ordering.
854 return _Compare(Type(other.begin(), other.end()));
855 }
856
857 mapped_type _Get(const Type* data, const inner_iterator& i)
858 {
859 if (_Validate()) {
860 if (data == _ConstData()) {
861 return i->second;
862 }
863 else {
864 // Data has changed since we created the iterator.
865 // Look up same key in new data.
866 return _ConstData()->find(i->first)->second;
867 }
868 }
869 return mapped_type();
870 }
871
872 const value_type& _Get(const Type* data,
873 const const_inner_iterator& i) const
874 {
875 // If data has changed since we created the iterator then look up
876 // the same key in the new data.
877 return (data == _ConstData()) ? *i : *_ConstData()->find(i->first);
878 }
879
880 void _Copy(const Type& other)
881 {
882 if (_Validate()) {
883 // Canonicalize the given map before copying it into ourselves.
884 // If multiple keys in the given map would conflict with each
885 // other in the canonicalized map, we consider this an error.
886 // This is primarily to avoid confusing the consumer, who would
887 // otherwise observe a key/value pair to be missing entirely.
888 Type canonicalOther;
889 TF_FOR_ALL(it, other) {
890 const value_type canonicalValue =
891 ValuePolicy::CanonicalizePair(_Owner(), *it);
892 if (!canonicalOther.insert(canonicalValue).second) {
893 TF_CODING_ERROR("Can't copy to %s: Duplicate key '%s' "
894 "exists in map.",
895 _Location().c_str(),
896 TfStringify(canonicalValue.first).c_str());
897 return;
898 }
899 }
900
901 if (_ValidateCopy(canonicalOther)) {
902 _data = canonicalOther;
903 _UpdateDataInSpec();
904 }
905 }
906 }
907
908 bool _ValidateCopy(const Type& other)
909 {
910 SdfSpecHandle owner = _Owner();
911 if (owner && !owner->PermissionToEdit()) {
912 TF_CODING_ERROR("Can't copy to %s: Permission denied.",
913 _Location().c_str());
914 return false;
915 }
916
917 if (other.empty()) {
918 return true;
919 }
920
921 TF_FOR_ALL(it, other) {
922 if (!_ValidateInsert(*it)) {
923 return false;
924 }
925 }
926
927 return true;
928 }
929
930 template <class U>
931 void _Set(const Type* data, const inner_iterator& i, const U& value)
932 {
933 if (_Validate()) {
934 const mapped_type& x =
935 ValuePolicy::CanonicalizeValue(_Owner(), value);
936 if (_ValidateSet(i->first, x)) {
937 _data[i->first] = x;
938 _UpdateDataInSpec();
939 }
940 }
941 }
942
943 bool _ValidateSet(const key_type& key, const mapped_type& value)
944 {
945 SdfSpecHandle owner = _Owner();
946 if (owner && !owner->PermissionToEdit()) {
947 TF_CODING_ERROR("Can't set value in %s: Permission denied.",
948 _Location().c_str());
949 return false;
950 }
951
952 if (SdfAllowed allowed = _IsValidValue(VtValueRef(value))) {
953 // Do nothing
954 }
955 else {
956 TF_CODING_ERROR("Can't set value in %s: %s",
957 _Location().c_str(),
958 allowed.GetWhyNot().c_str());
959 return false;
960 }
961
962 return true;
963 }
964
965 std::pair<iterator, bool> _Insert(const value_type& value)
966 {
967 if (_Validate()) {
968 const value_type& v = ValuePolicy::CanonicalizePair(_Owner(), value);
969 if (_ValidateInsert(v)) {
970 std::pair<inner_iterator, bool> status = _data.insert(v);
971 if (status.second) {
972 _UpdateDataInSpec();
973 }
974 return std::make_pair(iterator(this, _Data(), status.first),
975 status.second);
976 }
977 else {
978 return std::make_pair(iterator(), false);
979 }
980 }
981 return std::make_pair(iterator(), false);
982 }
983
984 bool _ValidateInsert(const value_type& value)
985 {
986 SdfSpecHandle owner = _Owner();
987 if (owner && !owner->PermissionToEdit()) {
988 TF_CODING_ERROR("Can't insert value in %s: Permission denied.",
989 _Location().c_str());
990 return false;
991 }
992
993 if (SdfAllowed allowed = _IsValidKey(VtValueRef(value.first))) {
994 // Do nothing
995 }
996 else {
997 TF_CODING_ERROR("Can't insert key in %s: %s",
998 _Location().c_str(),
999 allowed.GetWhyNot().c_str());
1000 return false;
1001 }
1002
1003 if (SdfAllowed allowed = _IsValidValue(VtValueRef(value.second))) {
1004 // Do nothing
1005 }
1006 else {
1007 TF_CODING_ERROR("Can't insert value in %s: %s",
1008 _Location().c_str(),
1009 allowed.GetWhyNot().c_str());
1010 return false;
1011 }
1012
1013 return true;
1014 }
1015
1016 void _Erase(const key_type& key)
1017 {
1018 if (_Validate() && _ValidateErase(key) && _data.erase(key) != 0) {
1019 _UpdateDataInSpec();
1020 }
1021 }
1022
1023 bool _ValidateErase(const key_type& key)
1024 {
1025 SdfSpecHandle owner = _Owner();
1026 if (owner && !owner->PermissionToEdit()) {
1027 TF_CODING_ERROR("Can't erase value from %s: Permission denied.",
1028 _Location().c_str());
1029 return false;
1030 }
1031
1032 return true;
1033 }
1034
1035 void _UpdateDataInSpec()
1036 {
1037 _WriteToSpec(_data.empty() ? VtValueRef() : VtValueRef(_data));
1038 }
1039
1040private:
1041 template <class ProxyT> friend class SdfPyWrapMapEditProxy;
1042
1043 Type _data;
1044};
1045
1046// Cannot get from a VtValue except as the correct type.
1047template <class T, class _ValuePolicy>
1048struct Vt_DefaultValueFactory<SdfMapEditProxy<T, _ValuePolicy> > {
1049 static Vt_DefaultValueHolder Invoke() = delete;
1050};
1051
1052PXR_NAMESPACE_CLOSE_SCOPE
1053
1054#endif // PXR_USD_SDF_MAP_EDIT_PROXY_H
Low-level utilities for informing users of various internal and external diagnostic conditions.
A simple iterator adapter for STL containers.
Indicates if an operation is allowed and, if not, why not.
Definition allowed.h:29
DANGER DANGER DANGER
Definition changeBlock.h:56
A value policy for SdfMapEditProxy that does nothing.
static const value_type & CanonicalizePair(const SdfSpecHandle &, const value_type &x)
Canonicalize a key/value pair.
static const mapped_type & CanonicalizeValue(const SdfSpecHandle &, const mapped_type &x)
Canonicalize a value.
static const key_type & CanonicalizeKey(const SdfSpecHandle &, const key_type &x)
Canonicalize a key.
static const Type & CanonicalizeType(const SdfSpecHandle &, const Type &x)
Canonicalize an entire Type object.
Non-template base for SdfMapEditProxy<T> holding the type-independent owner/field state and operation...
A proxy for editing map-like values.
bool IsExpired() const
Returns true if the value is expired.
bool operator<(const Type &other) const
Invalid SdfMapEditProxy objects will compare less to an object of their map type.
bool operator==(const SdfMapEditProxy< U, UVP > &other) const
Comparison operator with another proxy Two invalid proxy objects will compare equal.
Base class for all Sdf spec classes.
Definition spec.h:33
Token for efficient comparison, assignment, and hashing of known strings.
Definition token.h:81
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition value.h:90
bool IsEmpty() const
Returns true iff this value is empty.
Definition value.h:1286
bool IsHolding() const
Return true if this value is holding an object of type T, false otherwise.
Definition value.h:1061
T const & UncheckedGet() const &
Returns a const reference to the held object if the held object is of type T.
Definition value.h:1105
A non-owning type-erased view of a value, interoperating with VtValue.
Definition valueRef.h:65
#define TF_FOR_ALL(iter, c)
Macro for iterating over a container.
Definition iterator.h:373
#define TF_FATAL_ERROR(fmt, args)
Issue a fatal error and end the program.
Definition diagnostic.h:92
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition diagnostic.h:69
std::string TfStringify(const T &v)
Convert an arbitrary type into a string.
TfToken class for efficient string referencing and hashing, plus conversions to and from stl string c...