summaryrefslogtreecommitdiff
path: root/ext/pybind11/include/pybind11/stl_bind.h
diff options
context:
space:
mode:
Diffstat (limited to 'ext/pybind11/include/pybind11/stl_bind.h')
-rw-r--r--ext/pybind11/include/pybind11/stl_bind.h108
1 files changed, 77 insertions, 31 deletions
diff --git a/ext/pybind11/include/pybind11/stl_bind.h b/ext/pybind11/include/pybind11/stl_bind.h
index ef9950ebb..897188220 100644
--- a/ext/pybind11/include/pybind11/stl_bind.h
+++ b/ext/pybind11/include/pybind11/stl_bind.h
@@ -70,7 +70,7 @@ void vector_if_copy_constructible(enable_if_t<
std::is_copy_constructible<Vector>::value &&
std::is_copy_constructible<typename Vector::value_type>::value, Class_> &cl) {
- cl.def(pybind11::init<const Vector &>(), "Copy constructor");
+ cl.def(init<const Vector &>(), "Copy constructor");
}
template<typename Vector, typename Class_>
@@ -93,7 +93,7 @@ void vector_if_equal_operator(enable_if_t<is_comparable<Vector>::value, Class_>
if (p != v.end())
v.erase(p);
else
- throw pybind11::value_error();
+ throw value_error();
},
arg("x"),
"Remove the first item from the list whose value is x. "
@@ -155,7 +155,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
cl.def("pop",
[](Vector &v) {
if (v.empty())
- throw pybind11::index_error();
+ throw index_error();
T t = v.back();
v.pop_back();
return t;
@@ -166,7 +166,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
cl.def("pop",
[](Vector &v, SizeType i) {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
T t = v[i];
v.erase(v.begin() + (DiffType) i);
return t;
@@ -178,7 +178,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
cl.def("__setitem__",
[](Vector &v, SizeType i, const T &t) {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
v[i] = t;
}
);
@@ -189,7 +189,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
- throw pybind11::error_already_set();
+ throw error_already_set();
Vector *seq = new Vector();
seq->reserve((size_t) slicelength);
@@ -208,7 +208,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
[](Vector &v, slice slice, const Vector &value) {
size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
- throw pybind11::error_already_set();
+ throw error_already_set();
if (slicelength != value.size())
throw std::runtime_error("Left and right hand size of slice assignment have different sizes!");
@@ -224,7 +224,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
cl.def("__delitem__",
[](Vector &v, SizeType i) {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
v.erase(v.begin() + DiffType(i));
},
"Delete the list elements at index ``i``"
@@ -235,7 +235,7 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
size_t start, stop, step, slicelength;
if (!slice.compute(v.size(), &start, &stop, &step, &slicelength))
- throw pybind11::error_already_set();
+ throw error_already_set();
if (step == 1 && false) {
v.erase(v.begin() + (DiffType) start, v.begin() + DiffType(start + slicelength));
@@ -253,8 +253,8 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
// we have to access by copying; otherwise we return by reference.
-template <typename Vector> using vector_needs_copy = bool_constant<
- !std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>::value>;
+template <typename Vector> using vector_needs_copy = negation<
+ std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
// The usual case: access and iterate by reference
template <typename Vector, typename Class_>
@@ -266,7 +266,7 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl)
cl.def("__getitem__",
[](Vector &v, SizeType i) -> T & {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
return v[i];
},
return_value_policy::reference_internal // ref + keepalive
@@ -274,7 +274,7 @@ void vector_accessor(enable_if_t<!vector_needs_copy<Vector>::value, Class_> &cl)
cl.def("__iter__",
[](Vector &v) {
- return pybind11::make_iterator<
+ return make_iterator<
return_value_policy::reference_internal, ItType, ItType, T&>(
v.begin(), v.end());
},
@@ -291,14 +291,14 @@ void vector_accessor(enable_if_t<vector_needs_copy<Vector>::value, Class_> &cl)
cl.def("__getitem__",
[](const Vector &v, SizeType i) -> T {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
return v[i];
}
);
cl.def("__iter__",
[](Vector &v) {
- return pybind11::make_iterator<
+ return make_iterator<
return_value_policy::copy, ItType, ItType, T>(
v.begin(), v.end());
},
@@ -326,18 +326,64 @@ template <typename Vector, typename Class_> auto vector_if_insertion_operator(Cl
);
}
+// Provide the buffer interface for vectors if we have data() and we have a format for it
+// GCC seems to have "void std::vector<bool>::data()" - doing SFINAE on the existence of data() is insufficient, we need to check it returns an appropriate pointer
+template <typename Vector, typename = void>
+struct vector_has_data_and_format : std::false_type {};
+template <typename Vector>
+struct vector_has_data_and_format<Vector, enable_if_t<std::is_same<decltype(format_descriptor<typename Vector::value_type>::format(), std::declval<Vector>().data()), typename Vector::value_type*>::value>> : std::true_type {};
+
+// Add the buffer interface to a vector
+template <typename Vector, typename Class_, typename... Args>
+enable_if_t<detail::any_of<std::is_same<Args, buffer_protocol>...>::value>
+vector_buffer(Class_& cl) {
+ using T = typename Vector::value_type;
+
+ static_assert(vector_has_data_and_format<Vector>::value, "There is not an appropriate format descriptor for this vector");
+
+ // numpy.h declares this for arbitrary types, but it may raise an exception and crash hard at runtime if PYBIND11_NUMPY_DTYPE hasn't been called, so check here
+ format_descriptor<T>::format();
+
+ cl.def_buffer([](Vector& v) -> buffer_info {
+ return buffer_info(v.data(), sizeof(T), format_descriptor<T>::format(), 1, {v.size()}, {sizeof(T)});
+ });
+
+ cl.def("__init__", [](Vector& vec, buffer buf) {
+ auto info = buf.request();
+ if (info.ndim != 1 || info.strides[0] <= 0 || info.strides[0] % sizeof(T))
+ throw type_error("Only valid 1D buffers can be copied to a vector");
+ if (!detail::compare_buffer_info<T>::compare(info) || sizeof(T) != info.itemsize)
+ throw type_error("Format mismatch (Python: " + info.format + " C++: " + format_descriptor<T>::format() + ")");
+ new (&vec) Vector();
+ vec.reserve(info.shape[0]);
+ T *p = static_cast<T*>(info.ptr);
+ auto step = info.strides[0] / sizeof(T);
+ T *end = p + info.shape[0] * step;
+ for (; p < end; p += step)
+ vec.push_back(*p);
+ });
+
+ return;
+}
+
+template <typename Vector, typename Class_, typename... Args>
+enable_if_t<!detail::any_of<std::is_same<Args, buffer_protocol>...>::value> vector_buffer(Class_&) {}
+
NAMESPACE_END(detail)
//
// std::vector
//
template <typename Vector, typename holder_type = std::unique_ptr<Vector>, typename... Args>
-pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::string const &name, Args&&... args) {
- using Class_ = pybind11::class_<Vector, holder_type>;
+class_<Vector, holder_type> bind_vector(module &m, std::string const &name, Args&&... args) {
+ using Class_ = class_<Vector, holder_type>;
Class_ cl(m, name.c_str(), std::forward<Args>(args)...);
- cl.def(pybind11::init<>());
+ // Declare the buffer interface if a buffer_protocol() is passed in
+ detail::vector_buffer<Vector, Class_, Args...>(cl);
+
+ cl.def(init<>());
// Register copy constructor (if possible)
detail::vector_if_copy_constructible<Vector, Class_>(cl);
@@ -368,7 +414,7 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri
#if 0
// C++ style functions deprecated, leaving it here as an example
- cl.def(pybind11::init<size_type>());
+ cl.def(init<size_type>());
cl.def("resize",
(void (Vector::*) (size_type count)) & Vector::resize,
@@ -377,7 +423,7 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri
cl.def("erase",
[](Vector &v, SizeType i) {
if (i >= v.size())
- throw pybind11::index_error();
+ throw index_error();
v.erase(v.begin() + i);
}, "erases element at index ``i``");
@@ -396,12 +442,12 @@ pybind11::class_<Vector, holder_type> bind_vector(pybind11::module &m, std::stri
cl.def("front", [](Vector &v) {
if (v.size()) return v.front();
- else throw pybind11::index_error();
+ else throw index_error();
}, "access the first element");
cl.def("back", [](Vector &v) {
if (v.size()) return v.back();
- else throw pybind11::index_error();
+ else throw index_error();
}, "access the last element ");
#endif
@@ -484,14 +530,14 @@ template <typename Map, typename Class_> auto map_if_insertion_operator(Class_ &
NAMESPACE_END(detail)
template <typename Map, typename holder_type = std::unique_ptr<Map>, typename... Args>
-pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) {
+class_<Map, holder_type> bind_map(module &m, const std::string &name, Args&&... args) {
using KeyType = typename Map::key_type;
using MappedType = typename Map::mapped_type;
- using Class_ = pybind11::class_<Map, holder_type>;
+ using Class_ = class_<Map, holder_type>;
Class_ cl(m, name.c_str(), std::forward<Args>(args)...);
- cl.def(pybind11::init<>());
+ cl.def(init<>());
// Register stream insertion operator (if possible)
detail::map_if_insertion_operator<Map, Class_>(cl, name);
@@ -502,20 +548,20 @@ pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name,
);
cl.def("__iter__",
- [](Map &m) { return pybind11::make_key_iterator(m.begin(), m.end()); },
- pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
+ [](Map &m) { return make_key_iterator(m.begin(), m.end()); },
+ keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
);
cl.def("items",
- [](Map &m) { return pybind11::make_iterator(m.begin(), m.end()); },
- pybind11::keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
+ [](Map &m) { return make_iterator(m.begin(), m.end()); },
+ keep_alive<0, 1>() /* Essential: keep list alive while iterator exists */
);
cl.def("__getitem__",
[](Map &m, const KeyType &k) -> MappedType & {
auto it = m.find(k);
if (it == m.end())
- throw pybind11::key_error();
+ throw key_error();
return it->second;
},
return_value_policy::reference_internal // ref + keepalive
@@ -528,7 +574,7 @@ pybind11::class_<Map, holder_type> bind_map(module &m, const std::string &name,
[](Map &m, const KeyType &k) {
auto it = m.find(k);
if (it == m.end())
- throw pybind11::key_error();
+ throw key_error();
return m.erase(it);
}
);