Loading...
Searching...
No Matches
pyOperators.h
1//
2// Copyright 2017 Pixar
3//
4// Licensed under the terms set forth in the LICENSE.txt file available at
5// https://openusd.org/license.
6//
7
8#ifndef PXR_BASE_VT_PY_OPERATORS_H
9#define PXR_BASE_VT_PY_OPERATORS_H
10
11#include "pxr/pxr.h"
12#include "pxr/base/vt/api.h"
13
14PXR_NAMESPACE_OPEN_SCOPE
15
16namespace {
17// Per-op helpers with auto return so the result type is deduced from the
18// element operation. This enables heterogeneous results for list/tuple
19// operands (e.g. __sub__ on a TimeCode array produces a Duration array).
20// The bool specialization preserves existing Hyrum's-Law behavior.
21template <class T>
22struct _ArrayPyOpHelp {
23 static auto __add__(T l, T r) { return l + r; }
24 static auto __sub__(T l, T r) { return l - r; }
25 static auto __mul__(T l, T r) { return l * r; }
26 static auto __div__(T l, T r) { return l / r; }
27 static auto __mod__(T l, T r) { return l % r; }
28};
29
30// These operations on bool-arrays are highly questionable, but this preserves
31// existing behavior in the name of Hyrum's Law.
32template <>
33struct _ArrayPyOpHelp<bool> {
34 static bool __add__(bool l, bool r) { return l | r; }
35 static bool __sub__(bool l, bool r) { return l ^ r; }
36 static bool __mul__(bool l, bool r) { return l & r; }
37 static bool __div__(bool l, bool r) { return l; }
38 static bool __mod__(bool l, bool r) { return false; }
39};
40
41} // anon
42
43// -------------------------------------------------------------------------
44// Python operator definitions
45// -------------------------------------------------------------------------
46// These will define the operator to work with tuples and lists from Python.
47
48// base macro called by wrapping layers below for various operators, python
49// types (lists and tuples), and special methods.
50// The return type is deduced from _ArrayPyOpHelp<T>::op so that heterogeneous
51// results work correctly (e.g. __sub__ on a TimeCode array returns a Duration
52// array). Elements are extracted as T and the op result is stored in
53// VtArray<RetElem>.
54#define VTOPERATOR_WRAP_PYTYPE_BASE(op, method, pytype, isRightVer) \
55 template <typename T> static \
56 auto method##pytype(VtArray<T> vec, pytype obj) \
57 { \
58 using RetElem = decltype( \
59 _ArrayPyOpHelp<T>:: op (std::declval<T>(), std::declval<T>())); \
60 size_t length = len(obj); \
61 if (length != vec.size()) { \
62 TfPyThrowValueError("Non-conforming inputs for operator " \
63 #method); \
64 return VtArray<RetElem>(); \
65 } \
66 VtArray<RetElem> ret(vec.size()); \
67 for (size_t i = 0; i < length; ++i) { \
68 if (!extract<T>(obj[i]).check()) \
69 TfPyThrowValueError("Element is of incorrect type."); \
70 if (isRightVer) { \
71 ret[i] = _ArrayPyOpHelp<T>:: op ( \
72 (T)extract<T>(obj[i]), vec[i]); \
73 } \
74 else { \
75 ret[i] = _ArrayPyOpHelp<T>:: op ( \
76 vec[i], (T)extract<T>(obj[i])); \
77 } \
78 } \
79 return ret; \
80 }
81
82// wrap Array op pytype
83#define VTOPERATOR_WRAP_PYTYPE(op, method, pytype) \
84 VTOPERATOR_WRAP_PYTYPE_BASE(op, method, pytype, false)
85
86// wrap pytype op Array (for noncommutative ops like subtraction)
87#define VTOPERATOR_WRAP_PYTYPE_R(op, method, pytype) \
88 VTOPERATOR_WRAP_PYTYPE_BASE(op, method, pytype, true)
89
90
91// operator that needs a special method plus a reflected special method,
92// each defined on tuples and lists
93#define VTOPERATOR_WRAP(lmethod,rmethod) \
94 VTOPERATOR_WRAP_PYTYPE(lmethod,lmethod,tuple) \
95 VTOPERATOR_WRAP_PYTYPE(lmethod,lmethod,list) \
96 VTOPERATOR_WRAP_PYTYPE(lmethod,rmethod,tuple) \
97 VTOPERATOR_WRAP_PYTYPE(lmethod,rmethod,list)
98
99// like above, but for non-commutative ops like subtraction
100#define VTOPERATOR_WRAP_NONCOMM(lmethod,rmethod) \
101 VTOPERATOR_WRAP_PYTYPE(lmethod,lmethod,tuple) \
102 VTOPERATOR_WRAP_PYTYPE(lmethod,lmethod,list) \
103 VTOPERATOR_WRAP_PYTYPE_R(lmethod,rmethod,tuple) \
104 VTOPERATOR_WRAP_PYTYPE_R(lmethod,rmethod,list)
105
106// to be used to actually declare the wrapping with def() on the class
107#define VTOPERATOR_WRAPDECLARE_BASE(op,method,rettype) \
108 .def(self op self) \
109 .def(self op Type()) \
110 .def(Type() op self) \
111 .def(#method,method##tuple<rettype>) \
112 .def(#method,method##list<rettype>)
113
114#define VTOPERATOR_WRAPDECLARE(op,lmethod,rmethod) \
115 VTOPERATOR_WRAPDECLARE_BASE(op,lmethod,Type) \
116 .def(#rmethod,rmethod##tuple<Type>) \
117 .def(#rmethod,rmethod##list<Type>)
118
119// array OP pytype
120// pytype OP array
121#define VTOPERATOR_WRAP_PYTYPE_BOOL(func,pytype,op) \
122 VTOPERATOR_WRAP_PYTYPE_BOOL_BASE(func, \
123 VtArray<T> const &vec, pytype const &obj, \
124 (vec[i] op (T)extract<T>(obj[i])) ) \
125 VTOPERATOR_WRAP_PYTYPE_BOOL_BASE(func, \
126 pytype const &obj,VtArray<T> const &vec, \
127 ((T)extract<T>(obj[i]) op vec[i]) )
128
129#define VTOPERATOR_WRAP_BOOL(func,op) \
130 VTOPERATOR_WRAP_PYTYPE_BOOL(func,list,op) \
131 VTOPERATOR_WRAP_PYTYPE_BOOL(func,tuple,op)
132
133
134PXR_NAMESPACE_CLOSE_SCOPE
135
136#endif // PXR_BASE_VT_PY_OPERATORS_H