33static_assert(
sizeof(::pybind11::ssize_t) ==
sizeof(Py_intptr_t),
"ssize_t != Py_intptr_t");
34static_assert(std::is_signed<Py_intptr_t>::value,
"Py_intptr_t must be signed");
50template <
typename type,
typename SFINAE =
void>
80 PyObject_VAR_HEAD
char *
obval;
99 if (throw_if_missing) {
100 pybind11_fail(std::string(
"NumPy type info missing for ") + tinfo.name());
105 template <
typename T>
107 return get_type_info(
typeid(
typename std::remove_cv<T>::type), throw_if_missing);
112 ptr = &get_or_create_shared_data<numpy_internals>(
"_numpy_internals");
125 template <
typename U>
129template <
typename Concrete>
135template <
typename Concrete,
typename T,
typename... Ts,
typename... Ints>
137 return sizeof(Concrete) ==
sizeof(T) ? I :
platform_lookup<Concrete, Ts...>(Is...);
180 NPY_UINT32_ = platform_lookup<std::uint32_t, unsigned long, unsigned int, unsigned short>(
185 = platform_lookup<std::uint64_t, unsigned long, unsigned long long, unsigned int>(
189 struct PyArray_Dims {
207 PyObject *(*PyArray_DescrFromType_)(int);
208 PyObject *(*PyArray_NewFromDescr_)(PyTypeObject *,
217 PyObject *(*PyArray_DescrNewFromType_)(int);
219 PyObject *(*PyArray_NewCopy_)(PyObject *, int);
223 PyObject *(*PyArray_DescrFromScalar_)(PyObject *);
224 PyObject *(*PyArray_FromAny_)(PyObject *, PyObject *, int, int, int, PyObject *);
235 PyObject *(*PyArray_Squeeze_)(PyObject *);
238 PyObject *(*PyArray_Resize_)(PyObject *, PyArray_Dims *, int, int);
239 PyObject *(*PyArray_Newshape_)(PyObject *, PyArray_Dims *, int);
240 PyObject *(*PyArray_View_)(PyObject *, PyObject *, PyObject *);
267 auto c = m.attr(
"_ARRAY_API");
268 void **api_ptr = (
void **) PyCapsule_GetPointer(c.ptr(),
nullptr);
270#define DECL_NPY_API(Func) api.Func##_ = (decltype(api.Func##_)) api_ptr[API_##Func];
272 if (api.PyArray_GetNDArrayCFeatureVersion_() < 0x7) {
273 pybind11_fail(
"pybind11 numpy support requires numpy >= 1.7.0");
319template <
typename T,
size_t N>
329 static constexpr bool is_array =
false;
330 static constexpr bool is_empty =
false;
339template <
typename T,
size_t N>
342 static constexpr bool is_array =
true;
344 static constexpr size_t extent = N;
352 static constexpr auto extents = const_name<array_info<T>::is_array>(
361template <
typename T,
size_t N>
370#if defined(__GLIBCXX__) \
371 && (__GLIBCXX__ < 20150422 || __GLIBCXX__ == 20150426 || __GLIBCXX__ == 20150623 \
372 || __GLIBCXX__ == 20150626 || __GLIBCXX__ == 20160803)
375 std::is_trivially_destructible<T>,
378 std::is_trivially_copyable<T>,
392template <s
size_t Dim = 0,
typename Str
ides>
396template <
ssize_t Dim = 0,
typename Strides,
typename... Ix>
398 return i * strides[Dim] + byte_offset_unsafe<Dim + 1>(strides, index...);
406template <
typename T, s
size_t Dims>
409 static constexpr bool Dynamic = Dims < 0;
410 const unsigned char *
data_;
418 template <
bool Dyn = Dynamic>
423 :
data_{reinterpret_cast<const unsigned char *>(
data)},
dims_{Dims} {
430 template <
bool Dyn = Dynamic>
444 template <
typename... Ix>
447 "Invalid number of indices for unchecked array reference");
448 return *
reinterpret_cast<const T *
>(
data_
455 template <s
size_t D = Dims,
typename = enable_if_t<D == 1 || Dynamic>>
461 template <
typename... Ix>
462 const T *
data(Ix... ix)
const {
477 template <
bool Dyn = Dynamic>
479 return std::accumulate(
482 template <
bool Dyn = Dynamic>
493template <
typename T, s
size_t Dims>
497 using ConstBase::ConstBase;
502 using ConstBase::operator();
503 using ConstBase::operator[];
506 template <
typename... Ix>
509 "Invalid number of indices for unchecked array reference");
517 template <s
size_t D = Dims,
typename = enable_if_t<D == 1 || Dynamic>>
523 template <
typename... Ix>
529template <
typename T, s
size_t Dim>
531 static_assert(Dim == 0 && Dim > 0 ,
532 "unchecked array proxy object is not castable");
534template <
typename T, s
size_t Dim>
547 m_ptr =
descr.strip_padding(info.itemsize != 0 ? info.itemsize :
descr.itemsize())
560 args[
"names"] = std::move(names);
561 args[
"formats"] = std::move(formats);
562 args[
"offsets"] = std::move(offsets);
569 if (
m_ptr ==
nullptr) {
576 PyObject *
ptr =
nullptr;
577 if ((detail::npy_api::get().PyArray_DescrConverter_(
args.
ptr(), &
ptr) == 0) || !
ptr) {
580 return reinterpret_steal<dtype>(
ptr);
584 template <
typename T>
586 return detail::npy_format_descriptor<typename std::remove_cv<T>::type>
::dtype();
593 bool has_fields()
const {
return detail::array_descriptor_proxy(
m_ptr)->names !=
nullptr; }
597 char kind()
const {
return detail::array_descriptor_proxy(
m_ptr)->kind; }
605 return detail::array_descriptor_proxy(
m_ptr)->type;
613 return detail::array_descriptor_proxy(
m_ptr)->type_num;
617 char byteorder()
const {
return detail::array_descriptor_proxy(
m_ptr)->byteorder; }
620 int alignment()
const {
return detail::array_descriptor_proxy(
m_ptr)->alignment; }
623 char flags()
const {
return detail::array_descriptor_proxy(
m_ptr)->flags; }
628 .attr(
"_dtype_from_pep3118")
632 return reinterpret_borrow<object>(obj);
645 pybind11::int_ offset;
646 field_descr(pybind11::str &&
name,
object &&format, pybind11::int_ &&offset)
647 :
name{std::move(
name)}, format{std::move(format)}, offset{std::move(offset)} {};
649 auto field_dict = attr(
"fields").
cast<
dict>();
650 std::vector<field_descr> field_descriptors;
651 field_descriptors.reserve(field_dict.size());
653 for (
auto field : field_dict.attr(
"items")()) {
655 auto name = spec[0].cast<pybind11::str>();
656 auto spec_fo = spec[1].cast<
tuple>();
658 auto offset = spec_fo[1].
cast<pybind11::int_>();
659 if ((
len(
name) == 0u) && format.kind() ==
'V') {
662 field_descriptors.emplace_back(
663 std::move(
name), format.strip_padding(format.itemsize()), std::move(offset));
666 std::sort(field_descriptors.begin(),
667 field_descriptors.end(),
668 [](
const field_descr &a,
const field_descr &b) {
669 return a.offset.cast<int>() < b.offset.cast<int>();
672 list names, formats, offsets;
673 for (
auto &
descr : field_descriptors) {
678 return dtype(std::move(names), std::move(formats), std::move(offsets),
itemsize);
687 c_style = detail::npy_api::NPY_ARRAY_C_CONTIGUOUS_,
688 f_style = detail::npy_api::NPY_ARRAY_F_CONTIGUOUS_,
689 forcecast = detail::npy_api::NPY_ARRAY_FORCECAST_
701 const void *
ptr =
nullptr,
710 pybind11_fail(
"NumPy: shape ndim doesn't match strides ndim");
716 if (isinstance<array>(
base)) {
718 flags = reinterpret_borrow<array>(
base).flags()
722 flags = detail::npy_api::NPY_ARRAY_WRITEABLE_;
726 auto &api = detail::npy_api::get();
727 auto tmp = reinterpret_steal<object>(api.PyArray_NewFromDescr_(
729 descr.release().ptr(),
732 reinterpret_cast<Py_intptr_t *
>(
shape->data()),
733 reinterpret_cast<Py_intptr_t *
>(
strides->data()),
734 const_cast<void *
>(
ptr),
742 api.PyArray_SetBaseObject_(tmp.ptr(),
base.inc_ref().ptr());
744 tmp = reinterpret_steal<object>(
745 api.PyArray_NewCopy_(tmp.ptr(), -1 ));
748 m_ptr = tmp.release().ptr();
753 const void *
ptr =
nullptr,
757 template <
typename T,
759 = detail::enable_if_t<std::is_integral<T>::value && !std::is_same<bool, T>::value>>
763 template <
typename T>
767 template <
typename T>
771 template <
typename T>
780 return reinterpret_borrow<pybind11::dtype>(detail::array_proxy(
m_ptr)->
descr);
790 return detail::array_descriptor_proxy(detail::array_proxy(
m_ptr)->
descr)->elsize;
800 object base()
const {
return reinterpret_borrow<object>(detail::array_proxy(
m_ptr)->
base); }
825 int flags()
const {
return detail::array_proxy(
m_ptr)->flags; }
829 return detail::check_flags(
m_ptr, detail::npy_api::NPY_ARRAY_WRITEABLE_);
834 return detail::check_flags(
m_ptr, detail::npy_api::NPY_ARRAY_OWNDATA_);
839 template <
typename... Ix>
840 const void *
data(Ix... index)
const {
841 return static_cast<const void *
>(detail::array_proxy(
m_ptr)->data +
offset_at(index...));
847 template <
typename... Ix>
850 return static_cast<void *
>(detail::array_proxy(
m_ptr)->data +
offset_at(index...));
855 template <
typename... Ix>
858 fail_dim_check(
sizeof...(index),
"too many indices for an array");
867 template <
typename... Ix>
878 template <
typename T,
ssize_t Dims = -1>
880 if (Dims >= 0 &&
ndim() != Dims) {
881 throw std::domain_error(
"array has incorrect number of dimensions: "
882 + std::to_string(
ndim()) +
"; expected "
883 + std::to_string(Dims));
885 return detail::unchecked_mutable_reference<T, Dims>(
896 template <
typename T,
ssize_t Dims = -1>
897 detail::unchecked_reference<T, Dims>
unchecked() const & {
898 if (Dims >= 0 &&
ndim() != Dims) {
899 throw std::domain_error(
"array has incorrect number of dimensions: "
900 + std::to_string(
ndim()) +
"; expected "
901 + std::to_string(Dims));
908 auto &api = detail::npy_api::get();
909 return reinterpret_steal<array>(api.PyArray_Squeeze_(
m_ptr));
916 detail::npy_api::PyArray_Dims d
918 reinterpret_cast<Py_intptr_t *
>(new_shape->data()),
919 int(new_shape->size())};
921 auto new_array = reinterpret_steal<object>(
922 detail::npy_api::get().PyArray_Resize_(
m_ptr, &d,
int(refcheck), -1));
926 if (isinstance<array>(new_array)) {
927 *
this = std::move(new_array);
933 detail::npy_api::PyArray_Dims d
934 = {
reinterpret_cast<Py_intptr_t *
>(new_shape->data()),
int(new_shape->size())};
936 = reinterpret_steal<array>(detail::npy_api::get().PyArray_Newshape_(
m_ptr, &d, 0));
949 auto &api = detail::npy_api::get();
950 auto new_view = reinterpret_steal<array>(api.PyArray_View_(
961 auto result = reinterpret_steal<array>(
raw_array(h.
ptr(), ExtraFlags));
969 template <
typename,
typename>
973 throw index_error(msg +
": " + std::to_string(dim) +
" (ndim = " + std::to_string(
ndim())
977 template <
typename... Ix>
985 throw std::domain_error(
"array is not writeable");
989 template <
typename... Ix>
996 template <
typename... Ix>
999 throw index_error(std::string(
"index ") + std::to_string(i)
1000 +
" is out of bounds for axis " + std::to_string(axis)
1001 +
" with size " + std::to_string(*
shape));
1008 if (
ptr ==
nullptr) {
1009 PyErr_SetString(PyExc_ValueError,
"cannot create a pybind11::array from a nullptr");
1012 return detail::npy_api::get().PyArray_FromAny_(
1013 ptr,
nullptr, 0, 0, detail::npy_api::NPY_ARRAY_ENSUREARRAY_ | ExtraFlags,
nullptr);
1017template <
typename T,
int ExtraFlags = array::forcecast>
1020 struct private_ctor {};
1030 static_assert(!detail::array_info<T>::is_array,
"Array types cannot be used with array_t");
1044 Py_XDECREF(h.ptr());
1059 const T *
ptr =
nullptr,
1076 template <
typename... Ix>
1081 template <
typename... Ix>
1083 return static_cast<const T *
>(
array::data(index...));
1086 template <
typename... Ix>
1092 template <
typename... Ix>
1093 const T &
at(Ix... index)
const {
1102 template <
typename... Ix>
1119 return array::mutable_unchecked<T, Dims>();
1131 return array::unchecked<T, Dims>();
1145 const auto &api = detail::npy_api::get();
1146 return api.PyArray_Check_(h.
ptr())
1147 && api.PyArray_EquivTypes_(detail::array_proxy(h.
ptr())->descr,
1148 dtype::of<T>().ptr())
1155 if (
ptr ==
nullptr) {
1156 PyErr_SetString(PyExc_ValueError,
"cannot create a pybind11::array_t from a nullptr");
1159 return detail::npy_api::get().PyArray_FromAny_(
ptr,
1163 detail::npy_api::NPY_ARRAY_ENSUREARRAY_
1169template <
typename T>
1172 return detail::npy_format_descriptor<typename std::remove_cv<T>::type>::format();
1178 static std::string
format() {
return std::to_string(N) +
's'; }
1182 static std::string
format() {
return std::to_string(N) +
's'; }
1185template <
typename T>
1189 typename std::remove_cv<typename std::underlying_type<T>::type>
::type>::format();
1193template <
typename T>
1196 using namespace detail;
1203template <
typename T,
int ExtraFlags>
1208 if (!convert && !type::check_(src)) {
1211 value = type::ensure(src);
1212 return static_cast<bool>(value);
1221template <
typename T>
1228template <
typename T,
typename =
void>
1231template <
typename T>
1233 static constexpr auto name = const_name<std::is_same<T, bool>::value>(
1235 const_name<std::is_signed<T>::value>(
"numpy.int",
"numpy.uint")
1236 + const_name<
sizeof(T) * 8>());
1239template <
typename T>
1241 static constexpr auto name = const_name < std::is_same<T, float>::value
1242 || std::is_same<T, const float>::value
1243 || std::is_same<T, double>::value
1244 || std::is_same<T, const double>::value
1245 > (
const_name(
"numpy.float") + const_name<sizeof(T) * 8>(),
1249template <
typename T>
1251 static constexpr auto name = const_name < std::is_same<typename T::value_type, float>::value
1252 || std::is_same<typename T::value_type, const float>::value
1253 || std::is_same<typename T::value_type, double>::value
1254 || std::is_same<typename T::value_type, const double>::value
1256 + const_name<sizeof(typename T::value_type) * 16>(),
1260template <
typename T>
1284 static constexpr int value = values[detail::is_fmt_numeric<T>::index];
1287 if (
auto *ptr =
npy_api::get().PyArray_DescrFromType_(value)) {
1288 return reinterpret_steal<pybind11::dtype>(ptr);
1294#define PYBIND11_DECL_CHAR_FMT \
1295 static constexpr auto name = const_name("S") + const_name<N>(); \
1296 static pybind11::dtype dtype() { \
1297 return pybind11::dtype(std::string("S") + std::to_string(N)); \
1307#undef PYBIND11_DECL_CHAR_FMT
1309template <
typename T>
1317 static constexpr auto name
1322 return pybind11::dtype::from_args(
1323 pybind11::make_tuple(base_descr::dtype(), std::move(shape)));
1327template <
typename T>
1333 static constexpr auto name = base_descr::name;
1334 static pybind11::dtype
dtype() {
return base_descr::dtype(); }
1346 const std::type_info &tinfo,
1348 bool (*direct_converter)(PyObject *,
void *&)) {
1357 std::vector<field_descriptor> ordered_fields(std::move(fields));
1359 ordered_fields.begin(),
1360 ordered_fields.end(),
1363 list names, formats, offsets;
1364 for (
auto &field : ordered_fields) {
1366 pybind11_fail(std::string(
"NumPy: unsupported field dtype: `") + field.name +
"` @ "
1369 names.
append(pybind11::str(field.name));
1370 formats.
append(field.descr);
1371 offsets.
append(pybind11::int_(field.offset));
1374 = pybind11::dtype(std::move(names), std::move(formats), std::move(offsets), itemsize)
1386 std::ostringstream oss;
1393 for (
auto &field : ordered_fields) {
1394 if (field.offset > offset) {
1395 oss << (field.offset - offset) <<
'x';
1397 oss << field.format <<
':' << field.name <<
':';
1398 offset = field.offset + field.size;
1400 if (itemsize > offset) {
1401 oss << (itemsize - offset) <<
'x';
1404 auto format_str = oss.str();
1409 if (!api.PyArray_EquivTypes_(dtype_ptr,
arr.dtype().ptr())) {
1413 auto tindex = std::type_index(tinfo);
1418template <
typename T,
typename SFINAE>
1421 "Attempt to use a non-POD or unimplemented POD type as a numpy dtype");
1425 static pybind11::dtype
dtype() {
return reinterpret_borrow<pybind11::dtype>(
dtype_ptr()); }
1434 typeid(
typename std::remove_cv<T>::type),
1447 if (!PyObject_TypeCheck(obj, api.PyVoidArrType_Type_)) {
1450 if (
auto descr = reinterpret_steal<object>(api.PyArray_DescrFromScalar_(obj))) {
1461# define PYBIND11_NUMPY_DTYPE(Type, ...) ((void) 0)
1462# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) ((void) 0)
1465# define PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, Name) \
1466 ::pybind11::detail::field_descriptor { \
1467 Name, offsetof(T, Field), sizeof(decltype(std::declval<T>().Field)), \
1468 ::pybind11::format_descriptor<decltype(std::declval<T>().Field)>::format(), \
1469 ::pybind11::detail::npy_format_descriptor< \
1470 decltype(std::declval<T>().Field)>::dtype() \
1474# define PYBIND11_FIELD_DESCRIPTOR(T, Field) PYBIND11_FIELD_DESCRIPTOR_EX(T, Field, #Field)
1478# define PYBIND11_EVAL0(...) __VA_ARGS__
1479# define PYBIND11_EVAL1(...) PYBIND11_EVAL0(PYBIND11_EVAL0(PYBIND11_EVAL0(__VA_ARGS__)))
1480# define PYBIND11_EVAL2(...) PYBIND11_EVAL1(PYBIND11_EVAL1(PYBIND11_EVAL1(__VA_ARGS__)))
1481# define PYBIND11_EVAL3(...) PYBIND11_EVAL2(PYBIND11_EVAL2(PYBIND11_EVAL2(__VA_ARGS__)))
1482# define PYBIND11_EVAL4(...) PYBIND11_EVAL3(PYBIND11_EVAL3(PYBIND11_EVAL3(__VA_ARGS__)))
1483# define PYBIND11_EVAL(...) PYBIND11_EVAL4(PYBIND11_EVAL4(PYBIND11_EVAL4(__VA_ARGS__)))
1484# define PYBIND11_MAP_END(...)
1485# define PYBIND11_MAP_OUT
1486# define PYBIND11_MAP_COMMA ,
1487# define PYBIND11_MAP_GET_END() 0, PYBIND11_MAP_END
1488# define PYBIND11_MAP_NEXT0(test, next, ...) next PYBIND11_MAP_OUT
1489# define PYBIND11_MAP_NEXT1(test, next) PYBIND11_MAP_NEXT0(test, next, 0)
1490# define PYBIND11_MAP_NEXT(test, next) PYBIND11_MAP_NEXT1(PYBIND11_MAP_GET_END test, next)
1491# if defined(_MSC_VER) \
1492 && !defined(__clang__)
1493# define PYBIND11_MAP_LIST_NEXT1(test, next) \
1494 PYBIND11_EVAL0(PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0))
1496# define PYBIND11_MAP_LIST_NEXT1(test, next) \
1497 PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0)
1499# define PYBIND11_MAP_LIST_NEXT(test, next) \
1500 PYBIND11_MAP_LIST_NEXT1(PYBIND11_MAP_GET_END test, next)
1501# define PYBIND11_MAP_LIST0(f, t, x, peek, ...) \
1502 f(t, x) PYBIND11_MAP_LIST_NEXT(peek, PYBIND11_MAP_LIST1)(f, t, peek, __VA_ARGS__)
1503# define PYBIND11_MAP_LIST1(f, t, x, peek, ...) \
1504 f(t, x) PYBIND11_MAP_LIST_NEXT(peek, PYBIND11_MAP_LIST0)(f, t, peek, __VA_ARGS__)
1506# define PYBIND11_MAP_LIST(f, t, ...) \
1507 PYBIND11_EVAL(PYBIND11_MAP_LIST1(f, t, __VA_ARGS__, (), 0))
1509# define PYBIND11_NUMPY_DTYPE(Type, ...) \
1510 ::pybind11::detail::npy_format_descriptor<Type>::register_dtype( \
1511 ::std::vector<::pybind11::detail::field_descriptor>{ \
1512 PYBIND11_MAP_LIST(PYBIND11_FIELD_DESCRIPTOR, Type, __VA_ARGS__)})
1514# if defined(_MSC_VER) && !defined(__clang__)
1515# define PYBIND11_MAP2_LIST_NEXT1(test, next) \
1516 PYBIND11_EVAL0(PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0))
1518# define PYBIND11_MAP2_LIST_NEXT1(test, next) \
1519 PYBIND11_MAP_NEXT0(test, PYBIND11_MAP_COMMA next, 0)
1521# define PYBIND11_MAP2_LIST_NEXT(test, next) \
1522 PYBIND11_MAP2_LIST_NEXT1(PYBIND11_MAP_GET_END test, next)
1523# define PYBIND11_MAP2_LIST0(f, t, x1, x2, peek, ...) \
1524 f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT(peek, PYBIND11_MAP2_LIST1)(f, t, peek, __VA_ARGS__)
1525# define PYBIND11_MAP2_LIST1(f, t, x1, x2, peek, ...) \
1526 f(t, x1, x2) PYBIND11_MAP2_LIST_NEXT(peek, PYBIND11_MAP2_LIST0)(f, t, peek, __VA_ARGS__)
1528# define PYBIND11_MAP2_LIST(f, t, ...) \
1529 PYBIND11_EVAL(PYBIND11_MAP2_LIST1(f, t, __VA_ARGS__, (), 0))
1531# define PYBIND11_NUMPY_DTYPE_EX(Type, ...) \
1532 ::pybind11::detail::npy_format_descriptor<Type>::register_dtype( \
1533 ::std::vector<::pybind11::detail::field_descriptor>{ \
1534 PYBIND11_MAP2_LIST(PYBIND11_FIELD_DESCRIPTOR_EX, Type, __VA_ARGS__)})
1547 :
p_ptr(reinterpret_cast<char *>(ptr)),
m_strides(strides.size()) {
1561 char *
p_ptr{
nullptr};
1574 for (
size_t i = 0; i < shape.size(); ++i) {
1579 for (
size_t i = 0; i < N; ++i) {
1585 for (
size_t j =
m_index.size(); j != 0; --j) {
1596 template <
size_t K,
class T =
void>
1608 auto buffer_shape_iter =
buffer.shape.rbegin();
1609 auto buffer_strides_iter =
buffer.strides.rbegin();
1610 auto shape_iter = shape.rbegin();
1611 auto strides_iter = strides.rbegin();
1613 while (buffer_shape_iter !=
buffer.shape.rend()) {
1614 if (*shape_iter == *buffer_shape_iter) {
1615 *strides_iter = *buffer_strides_iter;
1620 ++buffer_shape_iter;
1621 ++buffer_strides_iter;
1626 std::fill(strides_iter, strides.rend(), 0);
1632 iter.increment(dim);
1649broadcast(
const std::array<buffer_info, N> &buffers,
ssize_t &ndim, std::vector<ssize_t> &shape) {
1650 ndim = std::accumulate(
1652 return std::max(res, buf.
ndim);
1656 shape.resize((
size_t) ndim, 1);
1660 for (
size_t i = 0; i < N; ++i) {
1661 auto res_iter = shape.rbegin();
1662 auto end = buffers[i].shape.rend();
1663 for (
auto shape_iter = buffers[i].shape.rbegin(); shape_iter != end;
1664 ++shape_iter, ++res_iter) {
1665 const auto &dim_size_in = *shape_iter;
1666 auto &dim_size_out = *res_iter;
1670 if (dim_size_out == 1) {
1671 dim_size_out = dim_size_in;
1672 }
else if (dim_size_in != 1 && dim_size_in != dim_size_out) {
1673 pybind11_fail(
"pybind11::vectorize: incompatible size/dimension of inputs!");
1678 bool trivial_broadcast_c =
true;
1679 bool trivial_broadcast_f =
true;
1680 for (
size_t i = 0; i < N && (trivial_broadcast_c || trivial_broadcast_f); ++i) {
1681 if (buffers[i].size == 1) {
1686 if (buffers[i].ndim != ndim) {
1691 if (!std::equal(buffers[i].shape.cbegin(), buffers[i].shape.cend(), shape.cbegin())) {
1696 if (trivial_broadcast_c) {
1697 ssize_t expect_stride = buffers[i].itemsize;
1698 auto end = buffers[i].shape.crend();
1699 for (
auto shape_iter = buffers[i].shape.crbegin(),
1700 stride_iter = buffers[i].strides.crbegin();
1701 trivial_broadcast_c && shape_iter != end;
1702 ++shape_iter, ++stride_iter) {
1703 if (expect_stride == *stride_iter) {
1704 expect_stride *= *shape_iter;
1706 trivial_broadcast_c =
false;
1712 if (trivial_broadcast_f) {
1713 ssize_t expect_stride = buffers[i].itemsize;
1714 auto end = buffers[i].shape.cend();
1715 for (
auto shape_iter = buffers[i].shape.cbegin(),
1716 stride_iter = buffers[i].strides.cbegin();
1717 trivial_broadcast_f && shape_iter != end;
1718 ++shape_iter, ++stride_iter) {
1719 if (expect_stride == *stride_iter) {
1720 expect_stride *= *shape_iter;
1722 trivial_broadcast_f =
false;
1733template <
typename T>
1735 static_assert(!std::is_rvalue_reference<T>::value,
1736 "Functions with rvalue reference arguments cannot be vectorized");
1746 std::is_enum>::value
1747 && (!std::is_reference<T>::value
1748 || (std::is_lvalue_reference<T>::value && std::is_const<call_type>::value));
1754template <
typename Func,
typename Return,
typename... Args>
1759 if (trivial == broadcast_trivial::f_trivial) {
1769 static void call(Return *out,
size_t i, Func &f, Args &...
args) { out[i] = f(
args...); }
1773template <
typename Func,
typename... Args>
1781 static detail::void_type
call(Func &f, Args &...
args) {
1789template <
typename Func,
typename Return,
typename... Args>
1799 static constexpr size_t N =
sizeof...(Args);
1803 "pybind11::vectorize(...) requires a function with at least one vectorizable argument");
1806 template <
typename T,
1808 typename = detail::enable_if_t<
1809 !std::is_same<vectorize_helper, typename std::decay<T>::type>::value>>
1825 template <
size_t Index>
1826 using param_n_t =
typename std::tuple_element<Index, arg_call_types>::type;
1837 template <
size_t... Index,
size_t... VIndex,
size_t... BIndex>
1846 std::array<void *, N> params{{&
args...}};
1849 std::array<buffer_info, NVectorized> buffers{
1850 {
reinterpret_cast<array *
>(params[VIndex])->request()...}};
1854 std::vector<ssize_t> shape(0);
1855 auto trivial =
broadcast(buffers, nd, shape);
1859 = std::accumulate(shape.begin(), shape.end(), (
size_t) 1, std::multiplies<size_t>());
1863 if (size == 1 && ndim == 0) {
1871 PYBIND11_WARNING_PUSH
1872#ifdef PYBIND11_DETECTED_CLANG_WITH_MISLEADING_CALL_STD_MOVE_EXPLICITLY_WARNING
1882 if (trivial == broadcast_trivial::non_trivial) {
1883 apply_broadcast(buffers, params, mutable_data, size, shape, i_seq, vi_seq, bi_seq);
1885 apply_trivial(buffers, params, mutable_data, size, i_seq, vi_seq, bi_seq);
1892 template <
size_t... Index,
size_t... VIndex,
size_t... BIndex>
1894 std::array<void *, N> ¶ms,
1904 std::array<std::pair<unsigned char *&, const size_t>,
NVectorized> vecparams{
1905 {std::pair<unsigned char *&, const size_t>(
1906 reinterpret_cast<unsigned char *&
>(params[VIndex] = buffers[BIndex].ptr),
1909 for (
size_t i = 0; i < size; ++i) {
1912 for (
auto &x : vecparams) {
1913 x.first += x.second;
1918 template <
size_t... Index,
size_t... VIndex,
size_t... BIndex>
1920 std::array<void *, N> ¶ms,
1923 const std::vector<ssize_t> &output_shape,
1930 for (
size_t i = 0; i < size; ++i, ++input_iter) {
1938template <
typename Func,
typename Return,
typename... Args>
1940 return detail::vectorize_helper<Func, Return, Args...>(f);
1943template <
typename T,
int Flags>
1945 static constexpr auto name
1952template <
typename Return,
typename... Args>
1953detail::vectorize_helper<Return (*)(Args...), Return, Args...>
vectorize(Return (*f)(Args...)) {
1954 return detail::vectorize_helper<Return (*)(Args...), Return, Args...>(f);
1958template <typename Func, detail::enable_if_t<detail::is_lambda<Func>::value,
int> = 0>
1960 ->
decltype(detail::vectorize_extractor(std::forward<Func>(f),
1961 (detail::function_signature_t<Func> *)
nullptr)) {
1962 return detail::vectorize_extractor(std::forward<Func>(f),
1963 (detail::function_signature_t<Func> *)
nullptr);
1967template <
typename Return,
1970 typename Helper = detail::vectorize_helper<
1971 decltype(std::mem_fn(std::declval<Return (Class::*)(Args...)>())),
1976 return Helper(std::mem_fn(f));
1980template <
typename Return,
1983 typename Helper = detail::vectorize_helper<
1984 decltype(std::mem_fn(std::declval<Return (Class::*)(Args...)
const>())),
1988Helper
vectorize(Return (Class::*f)(Args...)
const) {
1989 return Helper(std::mem_fn(f));
array_t(handle h, borrowed_t)
const T * data(Ix... index) const
T * mutable_data(Ix... index)
ssize_t index_at(Ix... index) const
const T & at(Ix... index) const
array_t(ssize_t count, const T *ptr=nullptr, handle base=handle())
static PyObject * raw_array_t(PyObject *ptr)
Create array from any object – always returns a new reference.
T & mutable_at(Ix... index)
constexpr ssize_t itemsize() const
array_t(handle h, stolen_t)
array_t(ShapeContainer shape, const T *ptr=nullptr, handle base=handle())
static bool check_(handle h)
static array_t ensure(handle h)
Ensure that the argument is a NumPy array of the correct dtype (and if not, try to convert it).
array_t(ShapeContainer shape, StridesContainer strides, const T *ptr=nullptr, handle base=handle())
detail::unchecked_mutable_reference< T, Dims > mutable_unchecked() &
Returns a proxy object that provides access to the array's data without bounds or dimensionality chec...
detail::unchecked_reference< T, Dims > unchecked() const &
Returns a proxy object that provides const access to the array's data without bounds or dimensionalit...
array_t(private_ctor, ShapeContainer &&shape, StridesContainer &&strides, const T *ptr, handle base)
array_t(const buffer_info &info, handle base=handle())
ssize_t offset_at(Ix... index) const
Byte offset from beginning of the array to a given index (full or partial).
void fail_dim_check(ssize_t dim, const std::string &msg) const
array(const pybind11::dtype &dt, ShapeContainer shape, const void *ptr=nullptr, handle base=handle())
ssize_t nbytes() const
Total number of bytes.
static PyObject * raw_array(PyObject *ptr, int ExtraFlags=0)
Create array from any object – always returns a new reference.
void check_dimensions(Ix... index) const
array reshape(ShapeContainer new_shape)
Optional order parameter omitted, to be added as needed.
ssize_t ndim() const
Number of dimensions.
array(ShapeContainer shape, const T *ptr, handle base=handle())
const ssize_t * strides() const
Strides of the array.
friend struct detail::npy_format_descriptor
ssize_t byte_offset(Ix... index) const
detail::any_container< ssize_t > ShapeContainer
object base() const
Base object.
ssize_t size() const
Total number of elements.
void check_dimensions_impl(ssize_t axis, const ssize_t *shape, ssize_t i, Ix... index) const
int flags() const
Return the NumPy array flags.
detail::unchecked_reference< T, Dims > unchecked() const &
Returns a proxy object that provides const access to the array's data without bounds or dimensionalit...
void resize(ShapeContainer new_shape, bool refcheck=true)
Resize array to given shape If refcheck is true and more that one reference exist to this array then ...
array(ssize_t count, const T *ptr, handle base=handle())
ssize_t index_at(Ix... index) const
Item count from beginning of the array to a given index (full or partial).
pybind11::dtype dtype() const
Array descriptor (dtype)
static array ensure(handle h, int ExtraFlags=0)
Ensure that the argument is a NumPy array In case of an error, nullptr is returned and the Python err...
array(const buffer_info &info, handle base=handle())
array(const pybind11::dtype &dt, ShapeContainer shape, StridesContainer strides, const void *ptr=nullptr, handle base=handle())
const ssize_t * shape() const
Dimensions of the array.
void check_dimensions_impl(ssize_t, const ssize_t *) const
detail::any_container< ssize_t > StridesContainer
array view(const std::string &dtype)
Create a view of an array in a different data type.
void check_writeable() const
bool writeable() const
If set, the array is writeable (otherwise the buffer is read-only)
detail::unchecked_mutable_reference< T, Dims > mutable_unchecked() &
Returns a proxy object that provides access to the array's data without bounds or dimensionality chec...
bool owndata() const
If set, the array owns the data (will be freed when the array is deleted)
void * mutable_data(Ix... index)
Mutable pointer to the contained data.
array(const pybind11::dtype &dt, T count, const void *ptr=nullptr, handle base=handle())
ssize_t itemsize() const
Byte size of a single element.
ssize_t shape(ssize_t dim) const
Dimension along a given axis.
ssize_t offset_at() const
const void * data(Ix... index) const
Pointer to the contained data.
array squeeze()
Return a new view with all of the dimensions of length 1 removed.
array(ShapeContainer shape, StridesContainer strides, const T *ptr, handle base=handle())
ssize_t strides(ssize_t dim) const
Stride along a given axis.
container_type::size_type size_type
common_iterator(void *ptr, const container_type &strides, const container_type &shape)
std::vector< ssize_t > container_type
void increment(size_type dim)
container_type::value_type value_type
static dtype of()
Return dtype associated with a C++ type.
char flags() const
Flags for the array descriptor.
char kind() const
Single-character code for dtype's kind.
char byteorder() const
Single character for byteorder.
dtype strip_padding(ssize_t itemsize)
static dtype from_args(const object &args)
This is essentially the same as calling numpy.dtype(args) in Python.
ssize_t itemsize() const
Size of the data type in bytes.
static object _dtype_from_pep3118()
dtype(list names, list formats, list offsets, ssize_t itemsize)
dtype(const char *format)
int alignment() const
Alignment of the data type.
static dtype from_args(object args)
This is essentially the same as calling numpy.dtype(args) in Python.
char char_() const
Single-character for dtype's type.
bool has_fields() const
Returns true for structured data types.
dtype(const std::string &format)
int num() const
type number of dtype.
dtype(const pybind11::str &format)
Fetch and hold an error which was already set in Python.
\rst Holds a reference to a Python object (no reference counting)
const handle & inc_ref() const &
\rst Manually increase the reference count of the Python object.
handle()=default
The default constructor creates a handle with a nullptr-valued pointer.
PyObject * ptr() const
Return the underlying PyObject * pointer.
\rst Wraps a Python iterator so that it can also be used as a C++ input iterator
Wrapper for Python extension modules.
static module_ import(const char *name)
Import and return a module or throws error_already_set.
void increment_common_iterator(size_t dim)
common_iterator common_iter
multi_array_iterator & operator++()
multi_array_iterator(const std::array< buffer_info, N > &buffers, const container_type &shape)
void init_common_iterator(const buffer_info &buffer, const container_type &shape, common_iter &iterator, container_type &strides)
std::array< common_iter, N > m_common_iterator
std::vector< ssize_t > container_type
\rst Holds a reference to a Python object (with reference counting)
handle release()
\rst Resets the internal pointer to nullptr without decreasing the object's reference count.
T & operator[](ssize_t index)
Mutable, unchecked access data at the given index; this operator only participates if the reference i...
T * mutable_data(Ix... ix)
Mutable pointer access to the data at the given indices.
friend class pybind11::array
T & operator()(Ix... index)
Mutable, unchecked access to data at the given indices.
static constexpr bool Dynamic
Proxy class providing unsafe, unchecked const access to array data.
const T & operator()(Ix... index) const
Unchecked const reference access to data at the given indices.
conditional_t< Dynamic, const ssize_t *, std::array< ssize_t,(size_t) Dims > > strides_
const T * data(Ix... ix) const
Pointer access to the data at the given indices.
conditional_t< Dynamic, const ssize_t *, std::array< ssize_t,(size_t) Dims > > shape_
const T & operator[](ssize_t index) const
Unchecked const reference access to data; this operator only participates if the reference is to a 1-...
ssize_t shape(ssize_t dim) const
Returns the shape (i.e. size) of dimension dim
const unsigned char * data_
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t< Dyn, ssize_t > dims)
ssize_t ndim() const
Returns the number of dimensions of the array.
ssize_t nbytes() const
Returns the total number of bytes used by the referenced data.
friend class pybind11::array
enable_if_t<!Dyn, ssize_t > size() const
Returns the total number of elements in the referenced array, i.e.
enable_if_t< Dyn, ssize_t > size() const
unchecked_reference(const void *data, const ssize_t *shape, const ssize_t *strides, enable_if_t<!Dyn, ssize_t >)
static constexpr bool Dynamic
static constexpr ssize_t itemsize()
Returns the item size, i.e. sizeof(T)
iterator iter(handle obj)
size_t len(handle h)
Get the length of a Python object.
PYBIND11_WARNING_PUSH PYBIND11_WARNING_POP
std::vector< ssize_t > f_strides(const std::vector< ssize_t > &shape, ssize_t itemsize)
std::vector< ssize_t > c_strides(const std::vector< ssize_t > &shape, ssize_t itemsize)
T cast(const handle &handle)
typename std::enable_if< B, T >::type enable_if_t
from cpp_future import (convenient aliases from C++14/17)
std::integral_constant< bool, B > bool_constant
Backports of std::bool_constant and std::negation to accommodate older compilers.
PYBIND11_NOINLINE void pybind11_fail(const char *reason)
Thrown when pybind11::cast or.
#define PYBIND11_NOINLINE
typename std::remove_reference< T >::type remove_reference_t
#define PYBIND11_EXPAND_SIDE_EFFECTS(PATTERN)
constexpr size_t constexpr_sum()
Compile-time integer sum.
#define PYBIND11_NAMESPACE_END(name)
#define PYBIND11_NAMESPACE_BEGIN(name)
typename make_index_sequence_impl< N >::type make_index_sequence
std::is_same< bools< Ts::value..., true >, bools< true, Ts::value... > > all_of
typename std::conditional< B, T, F >::type conditional_t
return_value_policy
Approach used to cast a previously unknown C++ instance into a Python object.
@ move
Use std::move to move the return value contents into a new instance that will be owned by Python.
#define PYBIND11_DEPRECATED(reason)
typename select_indices_impl< index_sequence<>, 0, Bs... >::type select_indices
constexpr descr< N - 1 > const_name(char const (&text)[N])
constexpr descr< 0 > concat()
PYBIND11_NOINLINE internals & get_internals()
Return a reference to the current internals data.
PyArray_Proxy * array_proxy(void *ptr)
all_of< std::is_standard_layout< T >, std::is_trivial< T > > is_pod
detail::vectorize_helper< Return(*)(Args...), Return, Args... > vectorize(Return(*f)(Args...))
numpy_internals & get_numpy_internals()
vectorize_helper< Func, Return, Args... > vectorize_extractor(const Func &f, Return(*)(Args...))
ssize_t byte_offset_unsafe(const Strides &)
broadcast_trivial broadcast(const std::array< buffer_info, N > &buffers, ssize_t &ndim, std::vector< ssize_t > &shape)
PYBIND11_NOINLINE void register_structured_dtype(any_container< field_descriptor > fields, const std::type_info &tinfo, ssize_t itemsize, bool(*direct_converter)(PyObject *, void *&))
PYBIND11_NOINLINE void load_numpy_internals(numpy_internals *&ptr)
PyArrayDescr_Proxy * array_descriptor_proxy(PyObject *ptr)
bool check_flags(const void *ptr, int flag)
constexpr int platform_lookup()
typename array_info< T >::type remove_all_extents_t
all_of< std::is_standard_layout< T >, std::is_trivially_copyable< T >, satisfies_none_of< T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum > > is_pod_struct
#define PYBIND11_OBJECT_DEFAULT(Name, Parent, CheckFun)
#define PYBIND11_OBJECT_CVT(Name, Parent, CheckFun, ConvertFun)
#define PYBIND11_WARNING_DISABLE_MSVC(name)
#define PYBIND11_WARNING_DISABLE_CLANG(name)
#define PYBIND11_DECL_CHAR_FMT
numpy_internals & get_numpy_internals()
#define DECL_NPY_API(Func)
ssize_t byte_offset_unsafe(const Strides &)
broadcast_trivial broadcast(const std::array< buffer_info, N > &buffers, ssize_t &ndim, std::vector< ssize_t > &shape)
PYBIND11_NOINLINE void register_structured_dtype(any_container< field_descriptor > fields, const std::type_info &tinfo, ssize_t itemsize, bool(*direct_converter)(PyObject *, void *&))
all_of< std::is_standard_layout< T >, std::is_trivially_copyable< T >, satisfies_none_of< T, std::is_reference, std::is_array, is_std_array, std::is_arithmetic, is_complex, std::is_enum > > is_pod_struct
PyObject_HEAD char * data
PyObject_HEAD PyObject * typeobj
PyArrayDescr_Proxy * descr
PyObject_VAR_HEAD char * obval
static void append_extents(list &shape)
static constexpr bool is_empty
static constexpr auto extents
static constexpr bool is_array
static void append_extents(list &)
Annotation indicating that a class derives from another given type.
Information record describing a Python buffer object.
static bool compare(const buffer_info &b)
type_map< std::vector< bool(*)(PyObject *, void *&)> > direct_conversions
Annotation for function names.
int(* PyArray_DescrConverter_)(PyObject *, PyObject **)
int(* PyArray_SetBaseObject_)(PyObject *, PyObject *)
PyTypeObject * PyArray_Type_
PyTypeObject * PyArrayDescr_Type_
@ NPY_ARRAY_C_CONTIGUOUS_
@ NPY_ARRAY_F_CONTIGUOUS_
@ API_PyArray_SetBaseObject
@ API_PyArray_NewFromDescr
@ API_PyArray_DescrFromScalar
@ API_PyArray_DescrConverter
@ API_PyArray_DescrFromType
@ API_PyArray_GetNDArrayCFeatureVersion
@ API_PyArray_DescrNewFromType
@ API_PyArray_GetArrayParamsFromObject
unsigned int(* PyArray_GetNDArrayCFeatureVersion_)()
int(* PyArray_GetArrayParamsFromObject_)(PyObject *, PyObject *, unsigned char, PyObject **, int *, Py_intptr_t *, PyObject **, PyObject *)
bool(* PyArray_EquivTypes_)(PyObject *, PyObject *)
bool PyArrayDescr_Check_(PyObject *obj) const
int(* PyArray_CopyInto_)(PyObject *, PyObject *)
PyTypeObject * PyVoidArrType_Type_
bool PyArray_Check_(PyObject *obj) const
numpy_type_info * get_type_info(bool throw_if_missing=true)
numpy_type_info * get_type_info(const std::type_info &tinfo, bool throw_if_missing=true)
std::unordered_map< std::type_index, numpy_type_info > registered_dtypes
bool_constant< sizeof(T)==sizeof(U)> as
conditional_t< vectorize, array_t< remove_cv_t< call_type >, array::forcecast >, T > type
remove_reference_t< T > call_type
static constexpr bool vectorize
object operator()(typename vectorize_arg< Args >::type... args)
typename std::tuple_element< Index, arg_call_types >::type param_n_t
void apply_trivial(std::array< buffer_info, NVectorized > &buffers, std::array< void *, N > ¶ms, Return *out, size_t size, index_sequence< Index... >, index_sequence< VIndex... >, index_sequence< BIndex... >)
object run(typename vectorize_arg< Args >::type &...args, index_sequence< Index... > i_seq, index_sequence< VIndex... > vi_seq, index_sequence< BIndex... > bi_seq)
static constexpr size_t NVectorized
void apply_broadcast(std::array< buffer_info, NVectorized > &buffers, std::array< void *, N > ¶ms, Return *out, size_t size, const std::vector< ssize_t > &output_shape, index_sequence< Index... >, index_sequence< VIndex... >, index_sequence< BIndex... >)
static constexpr size_t N
remove_reference_t< Func > f
std::tuple< typename vectorize_arg< Args >::call_type... > arg_call_types
static detail::void_type call(Func &f, Args &...args)
static Type create(broadcast_trivial, const std::vector< ssize_t > &)
static void call(void *, size_t, Func &f, Args &...args)
static void * mutable_data(Type &)
static Return call(Func &f, Args &...args)
static void call(Return *out, size_t i, Func &f, Args &...args)
static Return * mutable_data(Type &array)
static Type create(broadcast_trivial trivial, const std::vector< ssize_t > &shape)