// // 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 PXR_USD_SDF_PY_CHILDREN_PROXY_H #define PXR_USD_SDF_PY_CHILDREN_PROXY_H /// \file sdf/pyChildrenProxy.h #include "pxr/pxr.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 #include PXR_NAMESPACE_OPEN_SCOPE template class SdfPyChildrenProxy { public: typedef _View View; typedef SdfChildrenProxy 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 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 _Iterator { public: _Iterator(const boost::python::object& object) : _object(object), _owner(boost::python::extract(object)()._proxy) { _cur = _owner.begin(); } _Iterator 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::_Wrap); } static void _Wrap() { using namespace boost::python; std::string name = _GetName(); scope thisScope = class_(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("clear", &This::_Clear, TfPyRaiseOnError<>()) .def("append", &This::_AppendItem, TfPyRaiseOnError<>()) .def("insert", &This::_InsertItemByIndex, TfPyRaiseOnError<>()) .def("get", &This::_PyGet, TfPyRaiseOnError<>()) .def("get", &This::_PyGetDefault, TfPyRaiseOnError<>()) #if PY_MAJOR_VERSION < 3 .def("has_key", &This::_HasKey, TfPyRaiseOnError<>()) .def("itervalues", &This::_GetValueIterator, TfPyRaiseOnError<>()) .def("iterkeys", &This::_GetKeyIterator, TfPyRaiseOnError<>()) .def("iteritems", &This::_GetItemIterator, TfPyRaiseOnError<>()) .def("items", &This::_GetItems, TfPyRaiseOnError<>()) .def("keys", &This::_GetKeys, TfPyRaiseOnError<>()) .def("values", &This::_GetValues, TfPyRaiseOnError<>()) #else .def("items", &This::_GetItemIterator, TfPyRaiseOnError<>()) .def("keys", &This::_GetKeyIterator, TfPyRaiseOnError<>()) .def("values", &This::_GetValueIterator, TfPyRaiseOnError<>()) #endif .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(TfPyIteratorNextMethodName, &This::template _Iterator<_ExtractItem>::GetNext) ; class_<_Iterator<_ExtractKey> > ((name + "_KeyIterator").c_str(), no_init) .def("__iter__", &This::template _Iterator<_ExtractKey>::GetCopy) .def(TfPyIteratorNextMethodName, &This::template _Iterator<_ExtractKey>::GetNext) ; class_<_Iterator<_ExtractValue> > ((name + "_ValueIterator").c_str(), no_init) .def("__iter__", &This::template _Iterator<_ExtractValue>::GetCopy) .def(TfPyIteratorNextMethodName, &This::template _Iterator<_ExtractValue>::GetNext) ; } static std::string _GetName() { std::string name = "ChildrenProxy_" + ArchGetDemangled(); 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 (! _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 { index = TfPyNormalizeIndex(index, _proxy.size(), true /*throwError*/); 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 (! TfPyIsNone(slice.start()) || ! TfPyIsNone(slice.stop()) || ! 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) { // Note that -1 below means to insert at end for the _proxy._Insert API. index = index < (int)_proxy.size() ? TfPyNormalizeIndex(index, _proxy.size(), false /*throwError*/) : -1; _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 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; } #if PY_MAJOR_VERSION < 3 boost::python::list _GetItems() const { return _Get<_ExtractItem>(); } boost::python::list _GetKeys() const { return _Get<_ExtractKey>(); } boost::python::list _GetValues() const { return _Get<_ExtractValue>(); } #endif 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 friend class _Iterator; }; PXR_NAMESPACE_CLOSE_SCOPE #endif // PXR_USD_SDF_PY_CHILDREN_PROXY_H