All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
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 SDF_PYLISTPROXY_H
25 #define SDF_PYLISTPROXY_H
26 
28 
29 #include "pxr/pxr.h"
30 #include "pxr/usd/sdf/changeBlock.h"
31 #include "pxr/usd/sdf/listProxy.h"
32 #include "pxr/base/arch/demangle.h"
33 #include "pxr/base/tf/pyLock.h"
34 #include "pxr/base/tf/pyUtils.h"
35 #include "pxr/base/tf/pyResultConversions.h"
36 #include "pxr/base/tf/stringUtils.h"
37 #include <stdexcept>
38 #include <boost/python.hpp>
39 #include <boost/python/slice.hpp>
40 
41 PXR_NAMESPACE_OPEN_SCOPE
42 
43 template <class T>
44 class SdfPyWrapListProxy {
45 public:
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 
57 private:
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 
272 PXR_NAMESPACE_CLOSE_SCOPE
273 
274 #endif // SDF_PYLISTPROXY_H
TF_API std::string TfStringPrintf(const char *fmt,...)
Returns a string formed by a printf()-like specification.
void if(!TfPyIsInitialized())
Invokes wrapFunc to wrap type T if T is not already wrapped.
Definition: pyUtils.h:210
TF_API int64_t TfPyNormalizeIndex(int64_t index, uint64_t size, bool throwError=false)
Return a positive index in the range [0,size).
DANGER DANGER DANGER
Definition: changeBlock.h:72
TF_API bool TfPyIsNone(boost::python::object const &obj)
Return true iff obj is None.
TF_API void TfPyThrowIndexError(std::string const &msg)
Raises a python IndexError and throws a C++ exception.
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.
std::string TfPyRepr(T const &t)
Return repr(t).
Definition: pyUtils.h:136
TF_API void TfPyThrowValueError(std::string const &msg)
Raises a python ValueError and throws a C++ exception.