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 .def(self == self)
85 .def(self != self)
86 .def(self < self)
87 .def(self <= self)
88 .def(self > self)
89 .def(self >= self)
90 .def(self == other<value_vector_type>())
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 ;
97 }
98
99 static std::string _GetName()
100 {
101 std::string name = "ListProxy_" +
102 ArchGetDemangled<TypePolicy>();
103 name = TfStringReplace(name, " ", "_");
104 name = TfStringReplace(name, ",", "_");
105 name = TfStringReplace(name, "::", "_");
106 name = TfStringReplace(name, "<", "_");
107 name = TfStringReplace(name, ">", "_");
108 return name;
109 }
110
111 static std::string _GetStr(const Type& x)
112 {
113 return TfPyRepr(static_cast<value_vector_type>(x));
114 }
115
116 static value_type _GetItemIndex(const Type& x, int index)
117 {
118 return x[TfPyNormalizeIndex(index, x._GetSize(), true)];
119 }
120
121 static boost::python::list _GetItemSlice(const Type& x,
122 const boost::python::slice& index)
123 {
124 using namespace boost::python;
125
126 list result;
127
128 if (x._Validate()) {
129 try {
130 slice::range<typename Type::const_iterator> range =
131 index.get_indicies(x.begin(), x.end());
132 for (; range.start != range.stop; range.start += range.step) {
133 result.append(*range.start);
134 }
135 result.append(*range.start);
136 }
137 catch (const std::invalid_argument&) {
138 // Ignore.
139 }
140 }
141
142 return result;
143 }
144
145 static void _SetItemIndex(Type& x, int index, const value_type& value)
146 {
147 x[TfPyNormalizeIndex(index, x._GetSize(), true)] = value;
148 }
149
150 static void _SetItemSlice(Type& x, const boost::python::slice& index,
151 const value_vector_type& values)
152 {
153 using namespace boost::python;
154
155 if (! x._Validate()) {
156 return;
157 }
158
159 // Get the range and the number of items in the slice.
160 size_t start, step, count;
161 try {
162 slice::range<typename Type::iterator> range =
163 index.get_indicies(x.begin(), x.end());
164 start = range.start - x.begin();
165 step = range.step;
166 count = 1 + (range.stop - range.start) / range.step;
167 }
168 catch (const std::invalid_argument&) {
169 // Empty range.
170 extract<int> e(index.start());
171 start = e.check() ? TfPyNormalizeIndex(e(), x._GetSize(), true) : 0;
172 step = 0;
173 count = 0;
174 }
175
176 if (TfPyIsNone(index.step())) {
177 // Replace contiguous sequence with values.
178 x._Edit(start, count, values);
179 }
180 else {
181 // Replace exactly the selected items.
182 if (count != values.size()) {
184 TfStringPrintf("attempt to assign sequence of size %zd "
185 "to extended slice of size %zd",
186 values.size(), count).c_str());
187 }
188 else if (step == 1) {
189 x._Edit(start, count, values);
190 }
191 else {
192 SdfChangeBlock block;
193 for (size_t i = 0, j = start; i != count; j += step, ++i) {
194 x._Edit(j, 1, value_vector_type(1, values[i]));
195 }
196 }
197 }
198 }
199
200 static void _DelItemIndex(Type& x, int i)
201 {
202 x._Edit(TfPyNormalizeIndex(i, x._GetSize(), true),
203 1, value_vector_type());
204 }
205
206 static void _DelItemSlice(Type& x, const boost::python::slice& index)
207 {
208 using namespace boost::python;
209
210 if (x._Validate()) {
211 try {
212 // Get the range and the number of items in the slice.
213 slice::range<typename Type::iterator> range =
214 index.get_indicies(x.begin(), x.end());
215 size_t start = range.start - x.begin();
216 size_t step = range.step;
217 size_t count = 1 + (range.stop - range.start) / range.step;
218
219 // Erase items.
220 if (step == 1) {
221 x._Edit(start, count, value_vector_type());
222 }
223 else {
224 SdfChangeBlock block;
225 value_vector_type empty;
226 for (size_t j = start; count > 0; j += step - 1, --count) {
227 x._Edit(j, 1, empty);
228 }
229 }
230 }
231 catch (const std::invalid_argument&) {
232 // Empty slice -- do nothing.
233 }
234 }
235 }
236
237 static int _FindIndex(const Type& x, const value_type& value)
238 {
239 if (x._Validate()) {
240 return static_cast<int>(x.Find(value));
241 }
242 else {
243 return -1;
244 }
245 }
246
247 static void _Insert(Type& x, int index, const value_type& value)
248 {
249 if (index < 0) {
250 index += x._GetSize();
251 }
252 if (index < 0 || index > static_cast<int>(x._GetSize())) {
253 TfPyThrowIndexError("list index out of range");
254 }
255 x._Edit(index, 0, value_vector_type(1, value));
256 }
257
258 static bool _IsExpired(const Type& x)
259 {
260 return x.IsExpired();
261 }
262
263 static value_vector_type _ApplyEditsToList(Type& x,
264 const value_vector_type& values)
265 {
266 value_vector_type newValues = values;
267 x.ApplyEditsToList(&newValues);
268 return newValues;
269 }
270};
271
272PXR_NAMESPACE_CLOSE_SCOPE
273
274#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.