10#ifndef MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
11#define MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
15#include "llvm/ADT/STLExtras.h"
16#include "llvm/ADT/StringRef.h"
17#include "llvm/ADT/Twine.h"
18#include "llvm/Support/DataTypes.h"
19#include "llvm/Support/raw_ostream.h"
26struct std::iterator_traits<
nanobind::detail::fast_iterator> {
52template <
typename DerivedTy,
typename T>
74template <
typename DefaultingTy>
76 NB_TYPE_CASTER(DefaultingTy, const_name(DefaultingTy::kTypeDescription))
82 value = DefaultingTy{DefaultingTy::resolve()};
93 nanobind::cast<typename DefaultingTy::ReferrentTy &>(src)};
95 }
catch (std::exception &) {
100 static handle
from_cpp(DefaultingTy src, rv_policy policy,
101 cleanup_list *cleanup)
noexcept {
102 return nanobind::cast(src, policy);
125 nanobind::str pyPart(part.
data,
127 printAccum->
parts.append(std::move(pyPart));
132 nanobind::str delim(
"", 0);
133 return nanobind::cast<nanobind::str>(delim.attr(
"join")(
parts));
143 std::string filePath;
144 if (nanobind::try_cast<std::string>(fileOrStringObject, filePath)) {
146 writeTarget.emplace<llvm::raw_fd_ostream>(filePath, ec);
148 throw nanobind::value_error(
149 (std::string(
"Unable to open file for writing: ") + ec.message())
153 writeTarget.emplace<nanobind::object>(fileOrStringObject.attr(
"write"));
158 return writeTarget.index() == 0 ? getPyWriteCallback()
159 : getOstreamCallback();
167 nanobind::gil_scoped_acquire acquire;
171 nanobind::bytes pyBytes(part.
data, part.
length);
172 std::get<nanobind::object>(accum->writeTarget)(pyBytes);
174 nanobind::str pyStr(part.
data,
176 std::get<nanobind::object>(accum->writeTarget)(pyStr);
184 std::get<llvm::raw_fd_ostream>(accum->writeTarget)
189 std::variant<nanobind::object, llvm::raw_fd_ostream> writeTarget;
203 assert(!accum->invoked &&
204 "PySinglePartStringAccumulator called back multiple times");
205 accum->invoked =
true;
206 accum->value = nanobind::str(part.
data, part.
length);
211 assert(invoked &&
"PySinglePartStringAccumulator not called back");
212 return std::move(value);
217 bool invoked =
false;
248template <
typename Derived,
typename ElementTy>
258 if (index < 0 || index >=
length)
266 assert(linearIndex >= 0 &&
267 linearIndex <
static_cast<Derived *
>(
this)->getRawNumElements() &&
268 "linear index out of bounds, the slice is ill-formed");
274 template <
typename T,
typename... Args>
284 PyErr_SetString(PyExc_IndexError,
"index out of range");
288 if constexpr (llvm::is_detected<has_maybe_downcast, ElementTy>::value)
289 return static_cast<Derived *
>(
this)
293 return nanobind::cast(
300 ssize_t start, stop, extraStep, sliceLength;
301 if (PySlice_GetIndicesEx(slice,
length, &start, &stop, &extraStep,
302 &sliceLength) != 0) {
303 PyErr_SetString(PyExc_IndexError,
"index out of range");
306 return nanobind::cast(
static_cast<Derived *
>(
this)->slice(
313 assert(
length >= 0 &&
"expected non-negative slice length");
322 throw nanobind::index_error(
"index out of range");
335 std::vector<ElementTy> elements;
336 elements.reserve(
length + other.length);
337 for (intptr_t i = 0; i <
length; ++i) {
338 elements.push_back(
static_cast<Derived *
>(
this)->
getElement(i));
340 for (intptr_t i = 0; i < other.length; ++i) {
341 elements.push_back(
static_cast<Derived *
>(&other)->
getElement(i));
347 static void bind(nanobind::module_ &m) {
348 const std::type_info &elemTy =
typeid(ElementTy);
349 PyObject *elemTyInfo = nanobind::detail::nb_type_lookup(&elemTy);
351 "expected nb_type_lookup to succeed for Sliceable elemTy");
352 nanobind::handle elemTyName = nanobind::detail::nb_type_name(elemTyInfo);
353 std::string sig = std::string(
"class ") + Derived::pyClassName +
354 "(collections.abc.Sequence[" +
355 nanobind::cast<std::string>(elemTyName) +
"])";
356 auto clazz = nanobind::class_<Derived>(m, Derived::pyClassName,
357 nanobind::sig(sig.c_str()))
359 Derived::bindDerived(clazz);
370 auto heap_type =
reinterpret_cast<PyHeapTypeObject *
>(clazz.ptr());
371 assert(heap_type->ht_type.tp_flags & Py_TPFLAGS_HEAPTYPE &&
372 "must be heap type");
373 heap_type->as_sequence.sq_length = +[](PyObject *rawSelf) -> Py_ssize_t {
374 auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
379 heap_type->as_sequence.sq_item =
380 +[](PyObject *rawSelf, Py_ssize_t
index) -> PyObject * {
381 auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
382 return self->getItem(
index).release().ptr();
385 heap_type->as_mapping.mp_subscript =
386 +[](PyObject *rawSelf, PyObject *rawSubscript) -> PyObject * {
387 auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
388 Py_ssize_t
index = PyNumber_AsSsize_t(rawSubscript, PyExc_IndexError);
389 if (!PyErr_Occurred()) {
391 return self->getItem(
index).release().ptr();
396 if (PySlice_Check(rawSubscript)) {
397 return self->getItemSlice(rawSubscript).release().ptr();
400 PyErr_SetString(PyExc_ValueError,
"expected integer or slice");
Accumulates into a file, either writing text (default) or binary.
PyFileAccumulator(const nanobind::object &fileOrStringObject, bool binary)
MlirStringCallback getCallback()
intptr_t linearizeIndex(intptr_t index)
Computes the linear index given the current slice properties.
static void bind(nanobind::module_ &m)
Binds the indexing and length methods in the Python class.
std::vector< ElementTy > dunderAdd(Derived &other)
Returns a new vector (mapped to Python list) containing elements from two slices.
ElementTy getElement(intptr_t index)
Returns the index-th element in the slice, supports negative indices.
nanobind::object getItemSlice(PyObject *slice)
Returns a new instance of the pseudo-container restricted to the given slice.
nanobind::class_< PyOpResultList > ClassTy
static void bindDerived(ClassTy &)
Hook for derived classes willing to bind more methods.
Sliceable(intptr_t startIndex, intptr_t length, intptr_t step)
decltype(&T::maybeDownCast) has_maybe_downcast
intptr_t wrapIndex(intptr_t index)
Transforms index into a legal value to access the underlying sequence.
nanobind::object getItem(intptr_t index)
Returns the element at the given slice index.
intptr_t size()
Returns the size of slice.
ReferrentTy * operator->()
Defaulting(ReferrentTy &referrent)
ReferrentTy * get() const
Defaulting()=default
Type casters require the type to be default constructible, but using such an instance is illegal.
MLIR_CAPI_EXPORTED MlirTypeID mlirTypeIDCreate(const void *ptr)
ptr must be 8 byte aligned and unique to a type valid for the duration of the returned type id's usag...
MLIR_CAPI_EXPORTED size_t mlirTypeIDHashValue(MlirTypeID typeID)
Returns the hash value of the type id.
struct MlirStringRef MlirStringRef
MLIR_CAPI_EXPORTED bool mlirTypeIDEqual(MlirTypeID typeID1, MlirTypeID typeID2)
Checks if two type ids are equal.
void(* MlirStringCallback)(MlirStringRef, void *)
A callback for returning string references.
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Include the generated interface declarations.
A pointer to a sized fragment of a string, not necessarily null-terminated.
const char * data
Pointer to the first symbol.
size_t length
Length of the fragment.
static MlirTypeID getTombstoneKey()
static MlirTypeID getEmptyKey()
static bool isEqual(const MlirTypeID &lhs, const MlirTypeID &rhs)
static unsigned getHashValue(const MlirTypeID &val)
Accumulates into a python string from a method that accepts an MlirStringCallback.
MlirStringCallback getCallback()
Accumulates into a python string from a method that is expected to make one (no more,...
nanobind::str takeValue()
MlirStringCallback getCallback()
bool from_python(handle src, uint8_t flags, cleanup_list *cleanup)
static handle from_cpp(DefaultingTy src, rv_policy policy, cleanup_list *cleanup) noexcept
const value_type reference
std::ptrdiff_t difference_type
std::forward_iterator_tag iterator_category
nanobind::handle value_type