Skip to content

Commit e712b18

Browse files
Add ability to add NumPy user-defined types
1 parent 1151a8a commit e712b18

16 files changed

+2144
-41
lines changed

include/pybind11/cast.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1826,13 +1826,20 @@ template <typename T> struct move_if_unreferenced<T, enable_if_t<all_of<
18261826
>::value>> : std::true_type {};
18271827
template <typename T> using move_never = negation<move_common<T>>;
18281828

1829+
template <typename type, typename SFINAE = void>
1830+
struct cast_is_known_safe : public std::false_type {};
1831+
1832+
template <typename type>
1833+
struct cast_is_known_safe<type,
1834+
enable_if_t<std::is_base_of<type_caster_generic, make_caster<type>>::value>> : public std::true_type {};
1835+
18291836
// Detect whether returning a `type` from a cast on type's type_caster is going to result in a
18301837
// reference or pointer to a local variable of the type_caster. Basically, only
18311838
// non-reference/pointer `type`s and reference/pointers from a type_caster_generic are safe;
18321839
// everything else returns a reference/pointer to a local variable.
18331840
template <typename type> using cast_is_temporary_value_reference = bool_constant<
18341841
(std::is_reference<type>::value || std::is_pointer<type>::value) &&
1835-
!std::is_base_of<type_caster_generic, make_caster<type>>::value
1842+
!cast_is_known_safe<type>::value
18361843
>;
18371844

18381845
// When a value returned from a C++ function is being cast back to Python, we almost always want to

include/pybind11/detail/inference.h

Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
/*
2+
pybind11/detail/inference.h -- Simple inference for generic functions
3+
4+
Copyright (c) 2018 Eric Cousineau <[email protected]>
5+
6+
All rights reserved. Use of this source code is governed by a
7+
BSD-style license that can be found in the LICENSE file.
8+
*/
9+
10+
#pragma once
11+
12+
#include "common.h"
13+
14+
NAMESPACE_BEGIN(PYBIND11_NAMESPACE)
15+
NAMESPACE_BEGIN(detail)
16+
17+
// SFINAE for functors.
18+
// N.B. This *only* distinguished between function / method pointers and
19+
// lambda objects. It does *not* distinguish among other types.
20+
template <typename Func, typename T = void>
21+
using enable_if_lambda_t = enable_if_t<!std::is_function<intrinsic_t<Func>>::value, T>;
22+
23+
template <size_t N, size_t K, typename T, typename ... Ts>
24+
struct type_at_impl {
25+
using type = typename type_at_impl<N, K + 1, Ts...>::type;
26+
};
27+
28+
template <size_t N, typename T, typename ... Ts>
29+
struct type_at_impl<N, N, T, Ts...> {
30+
using type = T;
31+
};
32+
33+
// Convenient mechanism for passing sets of arguments.
34+
template <typename ... Ts>
35+
struct type_pack {
36+
static constexpr int size = sizeof...(Ts);
37+
38+
template <template <typename...> class Tpl>
39+
using bind = Tpl<Ts...>;
40+
41+
template <size_t N>
42+
struct type_at_internal {
43+
static_assert(N < size, "Invalid type index");
44+
using type = typename type_at_impl<N, 0, Ts...>::type;
45+
};
46+
47+
template <size_t N>
48+
using type_at = typename type_at_internal<N>::type;
49+
};
50+
51+
52+
#if defined(PYBIND11_CPP14)
53+
54+
template <typename... A, typename... B>
55+
auto type_pack_concat(type_pack<A...> = {}, type_pack<B...> = {}) {
56+
return type_pack<A..., B...>{};
57+
}
58+
59+
template <template <typename> class Apply, typename... T>
60+
auto type_pack_apply(type_pack<T...> = {}) {
61+
return type_pack<Apply<T>...>{};
62+
}
63+
64+
struct function_inference {
65+
// Collects both a functor object and its signature for ease of inference.
66+
template <typename Func_, typename ReturnT, typename ... ArgsT>
67+
struct inferred_info {
68+
// TODO(eric.cousineau): Ensure that this permits copy elision when combined
69+
// with `std::forward<Func>(func)`, while still behaving well with primitive
70+
// types.
71+
using Func = std::decay_t<Func_>;
72+
Func func;
73+
74+
using Return = ReturnT;
75+
using Args = type_pack<ArgsT...>;
76+
};
77+
78+
// Factory method for `inferred_info<>`, to be used by `run`.
79+
template <typename Return, typename ... Args, typename Func>
80+
static auto make_inferred_info(Func&& func, Return (*infer)(Args...) = nullptr) {
81+
(void)infer;
82+
return inferred_info<Func, Return, Args...>{std::forward<Func>(func)};
83+
}
84+
85+
// Infers `inferred_info<>` from a function pointer.
86+
template <typename Return, typename ... Args>
87+
static auto run(Return (*func)(Args...)) {
88+
return make_inferred_info<Return, Args...>(func);
89+
}
90+
91+
// Infers `inferred_info<>` from a mutable method pointer.
92+
template <typename Return, typename Class, typename ... Args>
93+
static auto run(Return (Class::*method)(Args...)) {
94+
auto func = [method](Class& self, Args... args) {
95+
return (self.*method)(std::forward<Args>(args)...);
96+
};
97+
return make_inferred_info<Return, Class&, Args...>(func);
98+
}
99+
100+
// Infers `inferred_info<>` from a const method pointer.
101+
template <typename Return, typename Class, typename ... Args>
102+
static auto run(Return (Class::*method)(Args...) const) {
103+
auto func = [method](const Class& self, Args... args) {
104+
return (self.*method)(std::forward<Args>(args)...);
105+
};
106+
return make_inferred_info<Return, const Class&, Args...>(func);
107+
}
108+
109+
// Helpers for general functor objects.
110+
struct infer_helper {
111+
// Removes class from mutable method pointer for inferring signature
112+
// of functor.
113+
template <typename Class, typename Return, typename ... Args>
114+
static auto remove_class_from_ptr(Return (Class::*)(Args...)) {
115+
using Ptr = Return (*)(Args...);
116+
return Ptr{};
117+
}
118+
119+
// Removes class from const method pointer for inferring signature of functor.
120+
template <typename Class, typename Return, typename ... Args>
121+
static auto remove_class_from_ptr(Return (Class::*)(Args...) const) {
122+
using Ptr = Return (*)(Args...);
123+
return Ptr{};
124+
}
125+
126+
// Infers funtion pointer from functor.
127+
// @pre `Func` must have only *one* overload of `operator()`.
128+
template <typename Func>
129+
static auto infer_function_ptr() {
130+
return remove_class_from_ptr(&Func::operator());
131+
}
132+
};
133+
134+
// Infers `inferred_info<>` from a generic functor.
135+
template <typename Func, typename = detail::enable_if_lambda_t<Func>>
136+
static auto run(Func&& func) {
137+
return make_inferred_info(
138+
std::forward<Func>(func),
139+
infer_helper::infer_function_ptr<std::decay_t<Func>>());
140+
}
141+
};
142+
143+
#endif // defined(PYBIND_CPP14)
144+
145+
NAMESPACE_END(detail)
146+
147+
NAMESPACE_END(PYBIND11_NAMESPACE)

include/pybind11/detail/internals.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,13 +87,15 @@ struct internals {
8787
/// Additional type information which does not fit into the PyTypeObject.
8888
/// Changes to this struct also require bumping `PYBIND11_INTERNALS_VERSION`.
8989
struct type_info {
90+
using implicit_conversion_func = PyObject *(*)(PyObject *, PyTypeObject *);
91+
9092
PyTypeObject *type;
9193
const std::type_info *cpptype;
9294
size_t type_size, holder_size_in_ptrs;
9395
void *(*operator_new)(size_t);
9496
void (*init_instance)(instance *, holder_erased);
9597
void (*dealloc)(value_and_holder &v_h);
96-
std::vector<PyObject *(*)(PyObject *, PyTypeObject *)> implicit_conversions;
98+
std::vector<implicit_conversion_func> implicit_conversions;
9799
std::vector<std::pair<const std::type_info *, void *(*)(void *)>> implicit_casts;
98100
std::vector<bool (*)(PyObject *, void *&)> *direct_conversions;
99101
buffer_info *(*get_buffer)(PyObject *, void *) = nullptr;

include/pybind11/eigen.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ template <typename PlainObjectType, int Options, typename StrideType>
114114
struct eigen_extract_stride<Eigen::Ref<PlainObjectType, Options, StrideType>> { using type = StrideType; };
115115

116116
template <typename Scalar> bool is_pyobject_() {
117-
return static_cast<pybind11::detail::npy_api::constants>(npy_format_descriptor<Scalar>::value) == npy_api::NPY_OBJECT_;
117+
return static_cast<pybind11::detail::npy_api::constants>(npy_format_descriptor<Scalar>::dtype().num()) == npy_api::NPY_OBJECT_;
118118
}
119119

120120
// Helper struct for extracting information from an Eigen type
@@ -223,7 +223,7 @@ template <typename props> handle eigen_array_cast(typename props::Type const &sr
223223
constexpr ssize_t elem_size = sizeof(typename props::Scalar);
224224
array a;
225225
using Scalar = typename props::Type::Scalar;
226-
bool is_pyoject = static_cast<pybind11::detail::npy_api::constants>(npy_format_descriptor<Scalar>::value) == npy_api::NPY_OBJECT_;
226+
bool is_pyoject = static_cast<pybind11::detail::npy_api::constants>(npy_format_descriptor<Scalar>::dtype().num()) == npy_api::NPY_OBJECT_;
227227

228228
if (!is_pyoject) {
229229
if (props::vector)

0 commit comments

Comments
 (0)