7#ifndef PXR_BASE_TF_PY_SPAN_H
8#define PXR_BASE_TF_PY_SPAN_H
41#include "pxr/base/tf/api.h"
45#include "pxr/external/boost/python/converter/arg_from_python.hpp"
46#include "pxr/external/boost/python/converter/registered.hpp"
47#include "pxr/external/boost/python/extract.hpp"
50#include <initializer_list>
56PXR_NAMESPACE_OPEN_SCOPE
61using Tf_PySpanSourceFn =
62 bool (*)(PyObject *obj,
bool wantMutable,
void **data,
size_t *size);
65Tf_PyRegisterSpanSource(std::type_info
const &elemType, Tf_PySpanSourceFn fn);
68Tf_PyRegisterSpanBufferLayout(std::type_info
const &elemType,
size_t elemSize,
70 Py_ssize_t
const *elemShape,
int elemNdim);
73Tf_PyGetSpanFromSources(PyObject *obj, std::type_info
const &elemType,
74 bool wantMutable,
void **data,
size_t *size);
78Tf_PyGetSpanFromBuffer(PyObject *obj, std::type_info
const &elemType,
79 bool wantMutable, Py_buffer *view,
80 void **data,
size_t *size);
82template <
class Source,
class T>
84Tf_PySpanSourceFromLValue(PyObject *obj,
bool wantMutable,
85 void **data,
size_t *size)
87 using namespace PXR_BOOST_NAMESPACE::python::converter;
88 using Value = std::remove_cv_t<T>;
89 if (std::is_const_v<T> && wantMutable) {
92 void *p = get_lvalue_from_python(obj, registered<Source>::converters);
96 Source &src = *
static_cast<Source *
>(p);
97 if constexpr (!std::is_const_v<T>) {
107 *data =
const_cast<Value *
>(span.data());
118template <
class Source,
class T>
122 using Value = std::remove_cv_t<T>;
123 static_assert(std::is_constructible_v<TfSpan<const Value>, Source
const &>,
124 "Source must convert to TfSpan<const T>");
125 static_assert(std::is_const_v<T> ||
126 std::is_constructible_v<TfSpan<Value>, Source &>,
127 "Source must convert to TfSpan<T>; for read-only sources, "
128 "register with const T");
129 Tf_PyRegisterSpanSource(
typeid(Value),
130 Tf_PySpanSourceFromLValue<Source, T>);
143 std::initializer_list<Py_ssize_t> elemShape = {})
145 Tf_PyRegisterSpanBufferLayout(
146 typeid(T),
sizeof(T), scalarFormat,
147 elemShape.begin(),
static_cast<int>(elemShape.size()));
153class Tf_PySpanArgConverter
155 using Value = std::remove_cv_t<T>;
156 static constexpr bool _isMutable = !std::is_const_v<T>;
159 explicit Tf_PySpanArgConverter(PyObject *obj) {
162 if (Tf_PyGetSpanFromSources(
163 obj,
typeid(Value), _isMutable, &data, &size) ||
164 (_hasView = Tf_PyGetSpanFromBuffer(
165 obj,
typeid(Value), _isMutable, &_view, &data, &size))) {
166 _span =
TfSpan<T>(
static_cast<T *
>(data), size);
169 else if constexpr (!_isMutable) {
170 _convertible = _CopyFromSequence(obj);
174 ~Tf_PySpanArgConverter() {
176 PyBuffer_Release(&_view);
180 Tf_PySpanArgConverter(Tf_PySpanArgConverter
const &) =
delete;
181 Tf_PySpanArgConverter &operator=(Tf_PySpanArgConverter
const &) =
delete;
183 bool convertible()
const {
return _convertible; }
185 TfSpan<T> &operator()() {
return _span; }
188 bool _CopyFromSequence(PyObject *obj) {
189 if (!PySequence_Check(obj) ||
190 PyUnicode_Check(obj) || PyBytes_Check(obj)) {
193 Py_ssize_t len = PySequence_Size(obj);
198 std::unique_ptr<Value []> storage(
new Value[len]);
199 for (Py_ssize_t i = 0; i != len; ++i) {
200 PyObject *item = PySequence_GetItem(obj, i);
205 PXR_BOOST_NAMESPACE::python::extract<Value> get(item);
206 bool ok = get.check();
216 _storage = std::move(storage);
221 std::unique_ptr<Value []> _storage;
223 bool _hasView =
false;
224 bool _convertible =
false;
227PXR_NAMESPACE_CLOSE_SCOPE
229namespace PXR_BOOST_NAMESPACE::python::converter {
232struct arg_rvalue_from_python<PXR_NS::
TfSpan<T>>
233 : PXR_NS::Tf_PySpanArgConverter<T>
235 using result_type = PXR_NS::TfSpan<T> &;
236 using PXR_NS::Tf_PySpanArgConverter<T>::Tf_PySpanArgConverter;
240struct arg_rvalue_from_python<PXR_NS::
TfSpan<T> const &>
241 : PXR_NS::Tf_PySpanArgConverter<T>
243 using result_type = PXR_NS::TfSpan<T> &;
244 using PXR_NS::Tf_PySpanArgConverter<T>::Tf_PySpanArgConverter;
Represents a range of contiguous elements.
Intended to replace a direct include of Python.h, which causes several build problems with certain co...
void TfPyRegisterSpanBufferLayout(char scalarFormat, std::initializer_list< Py_ssize_t > elemShape={})
Register the buffer layout of T: a C-contiguous array of elemShape-shaped blocks of scalars described...
void TfPyRegisterSpanSource()
Register the wrapped C++ type Source as a span source for TfSpan<T>.