10#ifndef MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
11#define MLIR_BINDINGS_PYTHON_PYBINDUTILS_H
27#if NB_VERSION_MAJOR >= 3
28template <
bool IsTuple>
29struct std::iterator_traits<
nanobind::detail::seq_iterator<IsTuple>> {
30 using value_type = nanobind::handle;
31 using reference =
const value_type;
33 using difference_type = std::ptrdiff_t;
34 using iterator_category = std::forward_iterator_tag;
38struct std::iterator_traits<
nanobind::detail::fast_iterator> {
54 typedef std::unique_ptr<T> (*
F)();
59 if (T *
result = output.load()) {
67 std::unique_ptr<T> m = initFn();
69 nanobind::ft_lock_guard lock(mu);
70 if (T *
result = output.load()) {
80 nanobind::ft_mutex mu;
81 std::atomic<T *> output{
nullptr};
112template <
typename DerivedTy,
typename T>
135template <
typename... Ts>
136inline std::string
join(
const Ts &...args) {
137 std::ostringstream oss;
138 (oss << ... << args);
142template <
typename DefaultingTy>
144 NB_TYPE_CASTER(DefaultingTy, const_name(DefaultingTy::kTypeDescription))
150 value = DefaultingTy{DefaultingTy::resolve()};
160 value = DefaultingTy{
161 nanobind::cast<typename DefaultingTy::ReferrentTy &>(src)};
163 }
catch (std::exception &) {
168 static handle
from_cpp(DefaultingTy src, rv_policy policy,
169 cleanup_list *cleanup)
noexcept {
170 return nanobind::cast(src, policy);
193 nanobind::str pyPart(part.
data,
195 printAccum->
parts.append(std::move(pyPart));
200 nanobind::str delim(
"", 0);
201 return nanobind::cast<nanobind::str>(delim.attr(
"join")(
parts));
222 std::string filePath;
223 if (nanobind::try_cast<std::string>(fileOrStringObject, filePath)) {
224 std::string errorMessage;
225 auto errorCallback = +[](
MlirStringRef message,
void *userData) {
226 auto *storage =
static_cast<std::string *
>(userData);
227 storage->assign(message.
data, message.
length);
230 filePath.c_str(), binary, errorCallback, &errorMessage);
232 throw nanobind::value_error(
233 (std::string(
"Unable to open file for writing: ") + errorMessage)
238 writeTarget.emplace<nanobind::object>(fileOrStringObject.attr(
"write"));
243 return writeTarget.index() == 0 ? getPyWriteCallback()
244 : getOStreamCallback();
252 nanobind::gil_scoped_acquire acquire;
256 nanobind::bytes pyBytes(part.
data, part.
length);
257 std::get<nanobind::object>(accum->writeTarget)(pyBytes);
259 nanobind::str pyStr(part.
data,
261 std::get<nanobind::object>(accum->writeTarget)(pyStr);
270 std::get<RAIIMlirLlvmRawFdOStream>(accum->writeTarget), part);
274 std::variant<nanobind::object, RAIIMlirLlvmRawFdOStream> writeTarget;
288 assert(!accum->invoked &&
289 "PySinglePartStringAccumulator called back multiple times");
290 accum->invoked =
true;
291 accum->value = nanobind::str(part.
data, part.
length);
296 assert(invoked &&
"PySinglePartStringAccumulator not called back");
297 return std::move(value);
302 bool invoked =
false;
335template <
typename Derived,
typename ElementTy>
342 static constexpr std::array<const char *, 0>
typeParams = {};
349 if (index < 0 || index >=
length)
357 assert(linearIndex >= 0 &&
358 linearIndex <
static_cast<Derived *
>(
this)->getRawNumElements() &&
359 "linear index out of bounds, the slice is ill-formed");
365 template <
typename T,
typename =
void>
368 template <
typename T>
379 PyErr_SetString(PyExc_IndexError,
"index out of range");
383 if constexpr (has_maybe_downcast<ElementTy>::value)
384 return static_cast<Derived *
>(
this)
388 return nanobind::cast(
395 Py_ssize_t start, stop, extraStep, sliceLength;
396 if (PySlice_GetIndicesEx(slice,
length, &start, &stop, &extraStep,
397 &sliceLength) != 0) {
398 PyErr_SetString(PyExc_IndexError,
"index out of range");
401 return nanobind::cast(
static_cast<Derived *
>(
this)->slice(
408 assert(
length >= 0 &&
"expected non-negative slice length");
417 throw nanobind::index_error(
"index out of range");
430 std::vector<ElementTy> elements;
431 elements.reserve(
length + other.length);
433 elements.push_back(
static_cast<Derived *
>(
this)->
getElement(i));
435 for (
intptr_t i = 0; i < other.length; ++i) {
436 elements.push_back(
static_cast<Derived *
>(&other)->
getElement(i));
452 static void bind(nanobind::module_ &m) {
456 static PyType_Slot sequenceSlots[] = {
457 {Py_sq_length, (
void *)(+[](PyObject *rawSelf) -> Py_ssize_t {
458 auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
464 (
void *)(+[](PyObject *rawSelf, Py_ssize_t
index) -> PyObject * {
465 auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
466 return self->getItem(
index).release().ptr();
470 (
void *)(+[](PyObject *rawSelf, PyObject *rawSubscript) -> PyObject * {
471 auto self = nanobind::cast<Derived *>(nanobind::handle(rawSelf));
473 PyNumber_AsSsize_t(rawSubscript, PyExc_IndexError);
474 if (!PyErr_Occurred()) {
476 return self->getItem(
index).release().ptr();
481 if (PySlice_Check(rawSubscript)) {
482 return self->getItemSlice(rawSubscript).release().ptr();
485 PyErr_SetString(PyExc_ValueError,
"expected integer or slice");
489 nanobind::handle elemTyInfo = nanobind::type<ElementTy>();
490 assert(elemTyInfo.is_valid() &&
491 "expected nanobind::type to succeed for Sliceable elemTy");
492 nanobind::str elemTyName = nanobind::type_name(elemTyInfo);
493 std::string sig = std::string(
"class ") + Derived::pyClassName +
494 "(collections.abc.Sequence[" + elemTyName.c_str() +
"]";
495 if constexpr (!Derived::typeParams.empty()) {
496 sig +=
", typing.Generic[";
497 for (
size_t i = 0; i < Derived::typeParams.size(); ++i) {
500 const char *tp = Derived::typeParams[i];
502 if (!nanobind::hasattr(m, tp))
503 m.attr(tp) = nanobind::type_var(tp);
509 if constexpr (!Derived::typeParams.empty()) {
511 ClassTy(m, Derived::pyClassName, nanobind::type_slots(sequenceSlots),
512 nanobind::is_generic(), nanobind::sig(sig.c_str()));
515 ClassTy(m, Derived::pyClassName, nanobind::type_slots(sequenceSlots),
516 nanobind::sig(sig.c_str()));
519 Derived::bindDerived(clazz);
Accumulates into a file, either writing text (default) or binary.
PyFileAccumulator(const nanobind::object &fileOrStringObject, bool binary)
MlirStringCallback getCallback()
nanobind::typed< nanobind::object, ElementTy > getItem(intptr_t index)
Returns the element at the given slice index.
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)
intptr_t wrapIndex(intptr_t index)
Transforms index into a legal value to access the underlying sequence.
static constexpr std::array< const char *, 0 > typeParams
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.
std::unique_ptr< T >(* F)()
MLIR_CAPI_EXPORTED bool mlirLlvmRawFdOStreamIsNull(MlirLlvmRawFdOStream stream)
Checks if a raw_fd_ostream is null.
MLIR_CAPI_EXPORTED void mlirLlvmRawFdOStreamWrite(MlirLlvmRawFdOStream stream, MlirStringRef string)
Write a string to a raw_fd_ostream created with mlirLlvmRawFdOStreamCreate.
MLIR_CAPI_EXPORTED size_t mlirTypeIDHashValue(MlirTypeID typeID)
Returns the hash value of the type id.
MLIR_CAPI_EXPORTED void mlirLlvmRawFdOStreamDestroy(MlirLlvmRawFdOStream stream)
Destroy a raw_fd_ostream created with mlirLlvmRawFdOStreamCreate.
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.
MLIR_CAPI_EXPORTED MlirLlvmRawFdOStream mlirLlvmRawFdOStreamCreate(const char *path, bool binary, MlirStringCallback errorCallback, void *userData)
Create a raw_fd_ostream for the given path.
Include the generated interface declarations.
std::string join(const Ts &...args)
Helper function to concatenate arguments into a std::string.
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.
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()
RAII wrapper for MlirLlvmRawFdOStream that ensures destruction on scope exit.
RAIIMlirLlvmRawFdOStream & operator=(const RAIIMlirLlvmRawFdOStream &)=delete
RAIIMlirLlvmRawFdOStream(MlirLlvmRawFdOStream stream)
~RAIIMlirLlvmRawFdOStream()
RAIIMlirLlvmRawFdOStream(const RAIIMlirLlvmRawFdOStream &)=delete
Trait to check if T provides a maybeDownCast method.
bool operator()(MlirTypeID lhs, MlirTypeID rhs) const
size_t operator()(MlirTypeID typeID) const
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