// // 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_MAP_EDIT_PROXY_H #define PXR_USD_SDF_PY_MAP_EDIT_PROXY_H /// \file sdf/pyMapEditProxy.h #include "pxr/pxr.h" #include "pxr/usd/sdf/changeBlock.h" #include "pxr/base/arch/demangle.h" #include "pxr/base/tf/iterator.h" #include "pxr/base/tf/pyUtils.h" #include "pxr/base/tf/stringUtils.h" #include PXR_NAMESPACE_OPEN_SCOPE template class SdfPyWrapMapEditProxy { public: typedef T Type; typedef typename Type::key_type key_type; typedef typename Type::mapped_type mapped_type; typedef typename Type::value_type value_type; typedef typename Type::iterator iterator; typedef typename Type::const_iterator const_iterator; typedef SdfPyWrapMapEditProxy This; SdfPyWrapMapEditProxy() { TfPyWrapOnce(&This::_Wrap); } private: typedef std::pair pair_type; 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)), _cur(_owner.begin()), _end(_owner.end()) { // Do nothing } _Iterator GetCopy() const { return *this; } boost::python::object GetNext() { if (_cur == _end) { TfPyThrowStopIteration("End of MapEditProxy iteration"); } boost::python::object result = E::Get(_cur); ++_cur; return result; } private: boost::python::object _object; const Type& _owner; const_iterator _cur; const_iterator _end; }; static void _Wrap() { using namespace boost::python; std::string name = _GetName(); scope thisScope = class_(name.c_str()) .def("__repr__", &This::_GetRepr) .def("__str__", &This::_GetStr) .def("__len__", &Type::size) .def("__getitem__", &This::_GetItem) .def("__setitem__", &This::_SetItem) .def("__delitem__", &This::_DelItem) .def("__contains__", &This::_HasKey) .def("__iter__", &This::_GetKeyIterator) #if PY_MAJOR_VERSION < 3 .def("itervalues", &This::_GetValueIterator) .def("iterkeys", &This::_GetKeyIterator) .def("iteritems", &This::_GetItemIterator) .def("values", &This::_GetValues) .def("keys", &This::_GetKeys) .def("items", &This::_GetItems) .def("has_key", &This::_HasKey) #else .def("values", &This::_GetValueIterator) .def("keys", &This::_GetKeyIterator) .def("items", &This::_GetItemIterator) #endif .def("clear", &Type::clear) .def("get", &This::_PyGet) .def("get", &This::_PyGetDefault) .def("pop", &This::_Pop) .def("popitem", &This::_PopItem) .def("setdefault", &This::_SetDefault) .def("update", &This::_UpdateDict) .def("update", &This::_UpdateList) .def("copy", &This::_Copy) .add_property("expired", &Type::IsExpired) .def(TfPyBoolBuiltinFuncName, &This::_NonZero) .def(self == self) .def(self != self) ; 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 = "MapEditProxy_" + ArchGetDemangled(); name = TfStringReplace(name, " ", "_"); name = TfStringReplace(name, ",", "_"); name = TfStringReplace(name, "::", "_"); name = TfStringReplace(name, "<", "_"); name = TfStringReplace(name, ">", "_"); return name; } static std::string _GetRepr(const Type& x) { std::string arg; if (x) { arg = TfStringPrintf("<%s>", x._Location().c_str()); } else { arg = ""; } return TF_PY_REPR_PREFIX + _GetName() + "(" + arg + ")"; } static std::string _GetStr(const Type& x) { std::string result("{"); if (x && ! x.empty()) { const_iterator i = x.begin(), n = x.end(); result += TfPyRepr(i->first) + ": " + TfPyRepr(i->second); while (++i != n) { result +=", " + TfPyRepr(i->first) + ": " + TfPyRepr(i->second); } } result += "}"; return result; } static mapped_type _GetItem(const Type& x, const key_type& key) { const_iterator i = x.find(key); if (i == x.end()) { TfPyThrowKeyError(TfPyRepr(key)); return mapped_type(); } else { return i->second; } } static void _SetItem(Type& x, const key_type& key, const mapped_type& value) { std::pair i = x.insert(value_type(key, value)); if (! i.second && i.first != typename Type::iterator()) { i.first->second = value; } } static void _DelItem(Type& x, const key_type& key) { x.erase(key); } static bool _HasKey(const Type& x, const key_type& key) { return x.count(key) != 0; } 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); } static boost::python::object _PyGet(const Type& x, const key_type& key) { const_iterator i = x.find(key); return i == x.end() ? boost::python::object() : boost::python::object(i->second); } static mapped_type _PyGetDefault(const Type& x, const key_type& key, const mapped_type& def) { const_iterator i = x.find(key); return i == x.end() ? def : i->second; } template static boost::python::list _Get(const Type& x) { boost::python::list result; for (const_iterator i = x.begin(), n = x.end(); i != n; ++i) { result.append(E::Get(i)); } return result; } #if PY_MAJOR_VERSION < 3 static boost::python::list _GetItems(const Type& x) { return _Get<_ExtractItem>(x); } static boost::python::list _GetKeys(const Type& x) { return _Get<_ExtractKey>(x); } static boost::python::list _GetValues(const Type& x) { return _Get<_ExtractValue>(x); } #endif static mapped_type _Pop(Type& x, const key_type& key) { iterator i = x.find(key); if (i == x.end()) { TfPyThrowKeyError(TfPyRepr(key)); return mapped_type(); } else { mapped_type result = i->second; x.erase(i); return result; } } static boost::python::tuple _PopItem(Type& x) { if (x.empty()) { TfPyThrowKeyError("MapEditProxy is empty"); return boost::python::tuple(); } else { iterator i = x.begin(); value_type result = *i; x.erase(i); return boost::python::make_tuple(result.first, result.second); } } static mapped_type _SetDefault(Type& x, const key_type& key, const mapped_type& def) { const_iterator i = x.find(key); if (i != x.end()) { return i->second; } else { return x[key] = def; } } static void _Update(Type& x, const std::vector& values) { SdfChangeBlock block; TF_FOR_ALL(i, values) { x[i->first] = i->second; } } static void _UpdateDict(Type& x, const boost::python::dict& d) { _UpdateList(x, d.items()); } static void _UpdateList(Type& x, const boost::python::list& pairs) { using namespace boost::python; std::vector values; for (int i = 0, n = len(pairs); i != n; ++i) { values.push_back(pair_type( extract(pairs[i][0])(), extract(pairs[i][1])())); } _Update(x, values); } static void _Copy(Type& x, const typename Type::Type& other) { x = other; } static bool _NonZero(const Type& x) { return static_cast(x); } }; PXR_NAMESPACE_CLOSE_SCOPE #endif // PXR_USD_SDF_PY_MAP_EDIT_PROXY_H