text: //
  // Copyright 2016 Pixar
  //
  // Licensed under the Apache License, Version 2.0 (the "Apache License")
  // with the following modification; you may not use this file except in
  // compliance with the Apache License and the following modification to it:
  // Section 6. Trademarks. is deleted and replaced with:
  //
  // 6. Trademarks. This License does not grant permission to use the trade
  //    names, trademarks, service marks, or product names of the Licensor
  //    and its affiliates, except as required to comply with Section 4(c) of
  //    the License and to reproduce the content of the NOTICE file.
  //
  // You may obtain a copy of the Apache License at
  //
  //     http://www.apache.org/licenses/LICENSE-2.0
  //
  // Unless required by applicable law or agreed to in writing, software
  // distributed under the Apache License with the above modification is
  // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
  // KIND, either express or implied. See the Apache License for the specific
  // language governing permissions and limitations under the Apache License.
  //
  #ifndef SDF_PYCHILDRENPROXY_H
  #define SDF_PYCHILDRENPROXY_H
  
  /// \file sdf/pyChildrenProxy.h
  
  #include "pxr/usd/sdf/childrenProxy.h"
  #include "pxr/base/arch/demangle.h"
  #include "pxr/base/tf/pyError.h"
  #include "pxr/base/tf/pyUtils.h"
  #include "pxr/base/tf/stringUtils.h"
  #include <boost/python.hpp>
  #include <boost/python/slice.hpp>
  
  template <class _View>
  class SdfPyChildrenProxy {
  public:
      typedef _View View;
      typedef SdfChildrenProxy<View> Proxy;
      typedef typename Proxy::key_type key_type;
      typedef typename Proxy::mapped_type mapped_type;
      typedef typename Proxy::mapped_vector_type mapped_vector_type;
      typedef typename Proxy::size_type size_type;
      typedef SdfPyChildrenProxy<View> This;
  
      SdfPyChildrenProxy(const Proxy& proxy) : _proxy(proxy)
      {
          _Init();
      }
  
      SdfPyChildrenProxy(const View& view, const std::string& type,
                         int permission = Proxy::CanSet |
                                          Proxy::CanInsert |
                                          Proxy::CanErase) :
          _proxy(view, type, permission)
      {
          _Init();
      }
  
      bool operator==(const This& other) const
      {
          return _proxy == other._proxy;
      }
  
      bool operator!=(const This& other) const
      {
          return _proxy != other._proxy;
      }
  
  private:
      typedef typename Proxy::const_iterator _const_iterator;
      typedef typename View::const_iterator _view_const_iterator;
  
      struct _ExtractItem {
          static boost::python::object Get(const _const_iterator& i)
          {
              return boost::python::make_tuple(i->first, i->second);
          }
      };
  
      struct _ExtractKey {
          static boost::python::object Get(const _const_iterator& i)
          {
              return boost::python::object(i->first);
          }
      };
  
      struct _ExtractValue {
          static boost::python::object Get(const _const_iterator& i)
          {
              return boost::python::object(i->second);
          }
      };
  
      template <class E>
      class _Iterator {
      public:
          _Iterator(const boost::python::object& object) :
              _object(object),
              _owner(boost::python::extract<const This&>(object)()._proxy)
          {
              _cur = _owner.begin();
          }
  
          _Iterator<E> GetCopy() const
          {
              return *this;
          }
  
          boost::python::object GetNext()
          {
              if (_cur == _owner.end()) {
                  TfPyThrowStopIteration("End of ChildrenProxy iteration");
              }
              boost::python::object result = E::Get(_cur);
              ++_cur;
              return result;
          }
  
      private:
          boost::python::object _object;
          const Proxy& _owner;
          _const_iterator _cur;
      };
  
      void _Init()
      {
          TfPyWrapOnce<This>(&This::_Wrap);
      }
  
      static void _Wrap()
      {
          using namespace boost::python;
  
          std::string name = _GetName();
  
          scope thisScope =
          class_<This>(name.c_str(), no_init)
              .def("__repr__", &This::_GetRepr, TfPyRaiseOnError<>())
              .def("__len__", &This::_GetSize, TfPyRaiseOnError<>())
              .def("__getitem__", &This::_GetItemByKey, TfPyRaiseOnError<>())
              .def("__getitem__", &This::_GetItemByIndex, TfPyRaiseOnError<>())
              .def("__setitem__", &This::_SetItemByKey, TfPyRaiseOnError<>())
              .def("__setitem__", &This::_SetItemBySlice, TfPyRaiseOnError<>())
              .def("__delitem__", &This::_DelItemByKey, TfPyRaiseOnError<>())
              .def("__delitem__", &This::_DelItemByIndex, TfPyRaiseOnError<>())
              .def("__contains__", &This::_HasKey, TfPyRaiseOnError<>())
              .def("__contains__", &This::_HasValue, TfPyRaiseOnError<>())
              .def("__iter__",   &This::_GetValueIterator, TfPyRaiseOnError<>())
              .def("itervalues", &This::_GetValueIterator, TfPyRaiseOnError<>())
              .def("iterkeys",   &This::_GetKeyIterator, TfPyRaiseOnError<>())
              .def("iteritems",  &This::_GetItemIterator, TfPyRaiseOnError<>())
              .def("clear", &This::_Clear, TfPyRaiseOnError<>())
              .def("append", &This::_AppendItem, TfPyRaiseOnError<>())
              .def("insert", &This::_InsertItemByIndex, TfPyRaiseOnError<>())
              .def("get", &This::_PyGet, TfPyRaiseOnError<>())
              .def("get", &This::_PyGetDefault, TfPyRaiseOnError<>())
              .def("has_key", &This::_HasKey, TfPyRaiseOnError<>())
              .def("items", &This::_GetItems, TfPyRaiseOnError<>())
              .def("keys", &This::_GetKeys, TfPyRaiseOnError<>())
              .def("values", &This::_GetValues, TfPyRaiseOnError<>())
              .def("index", &This::_FindIndexByKey, TfPyRaiseOnError<>())
              .def("index", &This::_FindIndexByValue, TfPyRaiseOnError<>())
              .def("__eq__", &This::operator==, TfPyRaiseOnError<>())
              .def("__ne__", &This::operator!=, TfPyRaiseOnError<>())
              ;
  
          class_<_Iterator<_ExtractItem> >
              ((name + "_Iterator").c_str(), no_init)
              .def("__iter__", &This::template _Iterator<_ExtractItem>::GetCopy)
              .def("next", &This::template _Iterator<_ExtractItem>::GetNext)
              ;
  
          class_<_Iterator<_ExtractKey> >
              ((name + "_KeyIterator").c_str(), no_init)
              .def("__iter__", &This::template _Iterator<_ExtractKey>::GetCopy)
              .def("next", &This::template _Iterator<_ExtractKey>::GetNext)
              ;
  
          class_<_Iterator<_ExtractValue> >
              ((name + "_ValueIterator").c_str(), no_init)
              .def("__iter__", &This::template _Iterator<_ExtractValue>::GetCopy)
              .def("next", &This::template _Iterator<_ExtractValue>::GetNext)
              ;
      }
  
      static std::string _GetName()
      {
          std::string name = "ChildrenProxy_" +
                             ArchGetDemangled<View>();
          name = TfStringReplace(name, " ", "_");
          name = TfStringReplace(name, ",", "_");
          name = TfStringReplace(name, "::", "_");
          name = TfStringReplace(name, "<", "_");
          name = TfStringReplace(name, ">", "_");
          return name;
      }
  
      const View& _GetView() const
      {
          return _proxy._view;
      }
  
      View& _GetView()
      {
          return _proxy._view;
      }
  
      std::string _GetRepr() const
      {
          std::string result("{");
          if (not _proxy.empty()) {
              _const_iterator i = _proxy.begin(), n = _proxy.end();
              result += TfPyRepr(i->first) + ": " + TfPyRepr(i->second);
              while (++i != n) {
                  result += ", " + TfPyRepr(i->first) +
                            ": " + TfPyRepr(i->second);
              }
          }
          result += "}";
          return result;
      }
  
      size_type _GetSize() const
      {
          return _proxy.size();
      }
  
      mapped_type _GetItemByKey(const key_type& key) const
      {
          _view_const_iterator i = _GetView().find(key);
          if (i == _GetView().end()) {
              TfPyThrowIndexError(TfPyRepr(key));
              return mapped_type();
          }
          else {
              return *i;
          }
      }
  
      mapped_type _GetItemByIndex(int index) const
      {
          if (index >= _proxy.size()) {
              TfPyThrowIndexError("list index out of range");
          }
          return _GetView()[index];
      }
  
      void _SetItemByKey(const key_type& key, const mapped_type& value)
      {
          TF_CODING_ERROR("can't directly reparent a %s",
                          _proxy._GetType().c_str());
      }
  
      void _SetItemBySlice(const boost::python::slice& slice,
                           const mapped_vector_type& values)
      {
          if (not TfPyIsNone(slice.start()) or
              not TfPyIsNone(slice.stop()) or
              not TfPyIsNone(slice.step())) {
              TfPyThrowIndexError("can only assign to full slice [:]");
          }
          else {
              _proxy._Copy(values);
          }
      }
  
      void _DelItemByKey(const key_type& key)
      {
          if (_GetView().find(key) == _GetView().end()) {
              TfPyThrowIndexError(TfPyRepr(key));
          }
          _proxy._Erase(key);
      }
  
      void _DelItemByIndex(int index)
      {
          _proxy._Erase(_GetView().key(_GetItemByIndex(index)));
      }
  
      void _Clear()
      {
          _proxy._Copy(mapped_vector_type());
      }
  
      void _AppendItem(const mapped_type& value)
      {
          _proxy._Insert(value, _proxy.size());
      }
  
      void _InsertItemByIndex(int index, const mapped_type& value)
      {
          if (index < -1 or index > static_cast<int>(_proxy.size())) {
              TfPyThrowIndexError("list index out of range");
          }
          _proxy._Insert(value, index);
      }
  
      boost::python::object _PyGet(const key_type& key) const
      {
          _view_const_iterator i = _GetView().find(key);
          return i == _GetView().end() ? boost::python::object() :
                                         boost::python::object(*i);
      }
  
      boost::python::object _PyGetDefault(const key_type& key,
                                          const mapped_type& def) const
      {
          _view_const_iterator i = _GetView().find(key);
          return i == _GetView().end() ? boost::python::object(def) :
                                         boost::python::object(*i);
      }
  
      bool _HasKey(const key_type& key) const
      {
          return _GetView().find(key) != _GetView().end();
      }
  
      bool _HasValue(const mapped_type& value) const
      {
          return _GetView().find(value) != _GetView().end();
      }
  
      static
      _Iterator<_ExtractItem> _GetItemIterator(const boost::python::object &x)
      {
          return _Iterator<_ExtractItem>(x);
      }
  
      static
      _Iterator<_ExtractKey> _GetKeyIterator(const boost::python::object &x)
      {
          return _Iterator<_ExtractKey>(x);
      }
  
      static
      _Iterator<_ExtractValue> _GetValueIterator(const boost::python::object &x)
      {
          return _Iterator<_ExtractValue>(x);
      }
  
      template <class E>
      boost::python::list _Get() const
      {
          boost::python::list result;
          for (_const_iterator i = _proxy.begin(), n = _proxy.end(); i != n; ++i){
              result.append(E::Get(i));
          }
          return result;
      }
  
      boost::python::list _GetItems() const
      {
          return _Get<_ExtractItem>();
      }
  
      boost::python::list _GetKeys() const
      {
          return _Get<_ExtractKey>();
      }
  
      boost::python::list _GetValues() const
      {
          return _Get<_ExtractValue>();
      }
  
      int _FindIndexByKey(const key_type& key) const
      {
          size_t i = std::distance(_GetView().begin(), _GetView().find(key));
          return i == _GetView().size() ? -1 : i;
      }
  
      int _FindIndexByValue(const mapped_type& value) const
      {
          size_t i = std::distance(_GetView().begin(), _GetView().find(value));
          return i == _GetView().size() ? -1 : i;
      }
  
  private:
      Proxy _proxy;
  
      template <class E> friend class _Iterator;
  };
  
  #endif
  