Loading...
Searching...
No Matches
pyListProxy.h
Go to the documentation of this file.
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_PY_LIST_PROXY_H
25#define PXR_USD_SDF_PY_LIST_PROXY_H
26
28
29#include "pxr/pxr.h"
30#include "pxr/usd/sdf/changeBlock.h"
33#include "pxr/base/tf/pyLock.h"
34#include "pxr/base/tf/pyUtils.h"
35#include "pxr/base/tf/pyResultConversions.h"
37#include <stdexcept>
38#include <boost/python.hpp>
39#include <boost/python/slice.hpp>
40
41PXR_NAMESPACE_OPEN_SCOPE
42
43template <class T>
44class SdfPyWrapListProxy {
45public:
46 typedef T Type;
47 typedef typename Type::TypePolicy TypePolicy;
48 typedef typename Type::value_type value_type;
49 typedef typename Type::value_vector_type value_vector_type;
50 typedef SdfPyWrapListProxy<Type> This;
51
52 SdfPyWrapListProxy()
53 {
54 TfPyWrapOnce<Type>(&This::_Wrap);
55 }
56
57private:
58 static void _Wrap()
59 {
60 using namespace boost::python;
61
62 class_<Type>(_GetName().c_str(), no_init)
63 .def("__str__", &This::_GetStr)
64 .def("__len__", &Type::size)
65 .def("__getitem__", &This::_GetItemIndex)
66 .def("__getitem__", &This::_GetItemSlice)
67 .def("__setitem__", &This::_SetItemIndex)
68 .def("__setitem__", &This::_SetItemSlice)
69 .def("__delitem__", &This::_DelItemIndex)
70 .def("__delitem__", &This::_DelItemSlice)
71 .def("__delitem__", &Type::Remove)
72 .def("count", &Type::Count)
73 .def("copy", &Type::operator value_vector_type,
74 return_value_policy<TfPySequenceToList>())
75 .def("index", &This::_FindIndex)
76 .def("clear", &Type::clear)
77 .def("insert", &This::_Insert)
78 .def("append", &Type::push_back)
79 .def("remove", &Type::Remove)
80 .def("replace", &Type::Replace)
81 .def("ApplyList", &Type::ApplyList)
82 .def("ApplyEditsToList", &This::_ApplyEditsToList)
83 .add_property("expired", &This::_IsExpired)
84 .add_static_property("invalidIndex", &This::_GetInvalidIndex)
85 .def(self == self)
86 .def(self != self)
87 .def(self < self)
88 .def(self <= self)
89 .def(self > self)
90 .def(self >= self)
91 .def(self == other<value_vector_type>())
92 .def(self != other<value_vector_type>())
93 .def(self < other<value_vector_type>())
94 .def(self <= other<value_vector_type>())
95 .def(self > other<value_vector_type>())
96 .def(self >= other<value_vector_type>())
97 ;
98 }
99
100 static std::string _GetName()
101 {
102 std::string name = "ListProxy_" +
103 ArchGetDemangled<TypePolicy>();
104 name = TfStringReplace(name, " ", "_");
105 name = TfStringReplace(name, ",", "_");
106 name = TfStringReplace(name, "::", "_");
107 name = TfStringReplace(name, "<", "_");
108 name = TfStringReplace(name, ">", "_");
109 return name;
110 }
111
112 static std::string _GetStr(const Type& x)
113 {
114 return TfPyRepr(static_cast<value_vector_type>(x));
115 }
116
117 static value_type _GetItemIndex(const Type& x, int index)
118 {
119 return x[TfPyNormalizeIndex(index, x._GetSize(), true)];
120 }
121
122 static boost::python::list _GetItemSlice(const Type& x,
123 const boost::python::slice& index)
124 {
125 using namespace boost::python;
126
127 list result;
128
129 if (x._Validate()) {
130 try {
131 slice::range<typename Type::const_iterator> range =
132 index.get_indicies(x.begin(), x.end());
133 for (; range.start != range.stop; range.start += range.step) {
134 result.append(*range.start);
135 }
136 result.append(*range.start);
137 }
138 catch (const std::invalid_argument&) {
139 // Ignore.
140 }
141 }
142
143 return result;
144 }
145
146 static void _SetItemIndex(Type& x, int index, const value_type& value)
147 {
148 x[TfPyNormalizeIndex(index, x._GetSize(), true)] = value;
149 }
150
151 static void _SetItemSlice(Type& x, const boost::python::slice& index,
152 const value_vector_type& values)
153 {
154 using namespace boost::python;
155
156 if (! x._Validate()) {
157 return;
158 }
159
160 // Get the range and the number of items in the slice.
161 size_t start, step, count;
162 try {
163 slice::range<typename Type::iterator> range =
164 index.get_indicies(x.begin(), x.end());
165 start = range.start - x.begin();
166 step = range.step;
167 count = 1 + (range.stop - range.start) / range.step;
168 }
169 catch (const std::invalid_argument&) {
170 // Empty range.
171 extract<int> e(index.start());
172 start = e.check() ? TfPyNormalizeIndex(e(), x._GetSize(), true) : 0;
173 step = 0;
174 count = 0;
175 }
176
177 if (TfPyIsNone(index.step())) {
178 // Replace contiguous sequence with values.
179 x._Edit(start, count, values);
180 }
181 else {
182 // Replace exactly the selected items.
183 if (count != values.size()) {
185 TfStringPrintf("attempt to assign sequence of size %zd "
186 "to extended slice of size %zd",
187 values.size(), count).c_str());
188 }
189 else if (step == 1) {
190 x._Edit(start, count, values);
191 }
192 else {
193 SdfChangeBlock block;
194 for (size_t i = 0, j = start; i != count; j += step, ++i) {
195 x._Edit(j, 1, value_vector_type(1, values[i]));
196 }
197 }
198 }
199 }
200
201 static void _DelItemIndex(Type& x, int i)
202 {
203 x._Edit(TfPyNormalizeIndex(i, x._GetSize(), true),
204 1, value_vector_type());
205 }
206
207 static void _DelItemSlice(Type& x, const boost::python::slice& index)
208 {
209 using namespace boost::python;
210
211 if (x._Validate()) {
212 try {
213 // Get the range and the number of items in the slice.
214 slice::range<typename Type::iterator> range =
215 index.get_indicies(x.begin(), x.end());
216 size_t start = range.start - x.begin();
217 size_t step = range.step;
218 size_t count = 1 + (range.stop - range.start) / range.step;
219
220 // Erase items.
221 if (step == 1) {
222 x._Edit(start, count, value_vector_type());
223 }
224 else {
225 SdfChangeBlock block;
226 value_vector_type empty;
227 for (size_t j = start; count > 0; j += step - 1, --count) {
228 x._Edit(j, 1, empty);
229 }
230 }
231 }
232 catch (const std::invalid_argument&) {
233 // Empty slice -- do nothing.
234 }
235 }
236 }
237
238 static int _GetInvalidIndex()
239 {
240 // Note that SdfListProxy::Find returns an unsigned value, however the
241 // wrapped class returns -1 in the event that a value could not be found
242 // in the list of operations.
243 return -1;
244 }
245
246 static int _FindIndex(const Type& x, const value_type& value)
247 {
248 if (x._Validate()) {
249 const size_t index = x.Find(value);
250 return index == Type::invalidIndex
251 ? _GetInvalidIndex()
252 : static_cast<int>(index);
253 }
254 else {
255 return _GetInvalidIndex();
256 }
257 }
258
259 static void _Insert(Type& x, int index, const value_type& value)
260 {
261 if (index < 0) {
262 index += x._GetSize();
263 }
264 if (index < 0 || index > static_cast<int>(x._GetSize())) {
265 TfPyThrowIndexError("list index out of range");
266 }
267 x._Edit(index, 0, value_vector_type(1, value));
268 }
269
270 static bool _IsExpired(const Type& x)
271 {
272 return x.IsExpired();
273 }
274
275 static value_vector_type _ApplyEditsToList(Type& x,
276 const value_vector_type& values)
277 {
278 value_vector_type newValues = values;
279 x.ApplyEditsToList(&newValues);
280 return newValues;
281 }
282};
283
284PXR_NAMESPACE_CLOSE_SCOPE
285
286#endif // PXR_USD_SDF_PY_LIST_PROXY_H
Miscellaneous Utilities for dealing with script.
TF_API void TfPyThrowIndexError(const char *msg)
Raises a Python IndexError with the given error msg and throws a boost::python::error_already_set exc...
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
TF_API void TfPyThrowValueError(const char *msg)
Raises a Python ValueError with the given error msg and throws a boost::python::error_already_set exc...
TF_API int64_t TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError=false)
Return a positive index in the range [0,size).
std::string TfPyRepr(T const &t)
Return repr(t).
Definition: pyUtils.h:180
DANGER DANGER DANGER
Definition: changeBlock.h:73
Demangle C++ typenames generated by the typeid() facility.
TF_API std::string TfStringReplace(const std::string &source, const std::string &from, const std::string &to)
Replaces all occurrences of string from with to in source.
TF_API std::string TfStringPrintf(const char *fmt,...)
Returns a string formed by a printf()-like specification.
Definitions of basic string utilities in tf.