2016-05-07 04:26:19 +00:00
|
|
|
/*
|
2016-08-12 11:50:00 +00:00
|
|
|
tests/test_stl_binders.cpp -- Usage of stl_binders functions
|
2016-05-07 04:26:19 +00:00
|
|
|
|
2016-05-15 18:50:38 +00:00
|
|
|
Copyright (c) 2016 Sergey Lyskov
|
2016-05-07 04:26:19 +00:00
|
|
|
|
|
|
|
All rights reserved. Use of this source code is governed by a
|
|
|
|
BSD-style license that can be found in the LICENSE file.
|
|
|
|
*/
|
|
|
|
|
2016-08-12 11:50:00 +00:00
|
|
|
#include "pybind11_tests.h"
|
2016-05-07 04:26:19 +00:00
|
|
|
|
2016-05-15 18:50:38 +00:00
|
|
|
#include <pybind11/stl_bind.h>
|
2016-11-08 13:03:34 +00:00
|
|
|
#include <pybind11/numpy.h>
|
2016-09-06 04:02:29 +00:00
|
|
|
#include <map>
|
Fix stl_bind to support movable, non-copyable value types (#490)
This commit includes the following changes:
* Don't provide make_copy_constructor for non-copyable container
make_copy_constructor currently fails for various stl containers (e.g.
std::vector, std::unordered_map, std::deque, etc.) when the container's
value type (e.g. the "T" or the std::pair<K,T> for a map) is
non-copyable. This adds an override that, for types that look like
containers, also requires that the value_type be copyable.
* stl_bind.h: make bind_{vector,map} work for non-copy-constructible types
Most stl_bind modifiers require copying, so if the type isn't copy
constructible, we provide a read-only interface instead.
In practice, this means that if the type is non-copyable, it will be,
for all intents and purposes, read-only from the Python side (but
currently it simply fails to compile with such a container).
It is still possible for the caller to provide an interface manually
(by defining methods on the returned class_ object), but this isn't
something stl_bind can handle because the C++ code to construct values
is going to be highly dependent on the container value_type.
* stl_bind: copy only for arithmetic value types
For non-primitive types, we may well be copying some complex type, when
returning by reference is more appropriate. This commit returns by
internal reference for all but basic arithmetic types.
* Return by reference whenever possible
Only if we definitely can't--i.e. std::vector<bool>--because v[i]
returns something that isn't a T& do we copy; for everything else, we
return by reference.
For the map case, we can always return by reference (at least for the
default stl map/unordered_map).
2016-11-15 11:30:38 +00:00
|
|
|
#include <deque>
|
2016-09-06 04:02:29 +00:00
|
|
|
#include <unordered_map>
|
2016-05-07 04:26:19 +00:00
|
|
|
|
Change all_of_t/any_of_t to all_of/any_of, add none_of
This replaces the current `all_of_t<Pred, Ts...>` with `all_of<Ts...>`,
with previous use of `all_of_t<Pred, Ts...>` becoming
`all_of<Pred<Ts>...>` (and similarly for `any_of_t`). It also adds a
`none_of<Ts...>`, a shortcut for `negation<any_of<Ts...>>`.
This allows `all_of` and `any_of` to be used a bit more flexible, e.g.
in cases where several predicates need to be tested for the same type
instead of the same predicate for multiple types.
This commit replaces the implementation with a more efficient version
for non-MSVC. For MSVC, this changes the workaround to use the
built-in, recursive std::conjunction/std::disjunction instead.
This also removes the `count_t` since `any_of_t` and `all_of_t` were the
only things using it.
This commit also rearranges some of the future std imports to use actual
`std` implementations for C++14/17 features when under the appropriate
compiler mode, as we were already doing for a few things (like
index_sequence). Most of these aren't saving much (the implementation
for enable_if_t, for example, is trivial), but I think it makes the
intention of the code instantly clear. It also enables MSVC's native
std::index_sequence support.
2016-12-12 23:11:49 +00:00
|
|
|
#ifdef _MSC_VER
|
|
|
|
// We get some really long type names here which causes MSVC to emit warnings
|
|
|
|
# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated
|
|
|
|
#endif
|
|
|
|
|
2016-05-15 18:50:38 +00:00
|
|
|
class El {
|
2016-05-07 04:26:19 +00:00
|
|
|
public:
|
2016-08-28 17:46:25 +00:00
|
|
|
El() = delete;
|
|
|
|
El(int v) : a(v) { }
|
2016-05-08 23:31:55 +00:00
|
|
|
|
2016-08-28 17:46:25 +00:00
|
|
|
int a;
|
2016-05-07 04:26:19 +00:00
|
|
|
};
|
|
|
|
|
2016-05-15 18:50:38 +00:00
|
|
|
std::ostream & operator<<(std::ostream &s, El const&v) {
|
2016-08-28 17:46:25 +00:00
|
|
|
s << "El{" << v.a << '}';
|
|
|
|
return s;
|
2016-05-08 23:31:55 +00:00
|
|
|
}
|
|
|
|
|
Fix stl_bind to support movable, non-copyable value types (#490)
This commit includes the following changes:
* Don't provide make_copy_constructor for non-copyable container
make_copy_constructor currently fails for various stl containers (e.g.
std::vector, std::unordered_map, std::deque, etc.) when the container's
value type (e.g. the "T" or the std::pair<K,T> for a map) is
non-copyable. This adds an override that, for types that look like
containers, also requires that the value_type be copyable.
* stl_bind.h: make bind_{vector,map} work for non-copy-constructible types
Most stl_bind modifiers require copying, so if the type isn't copy
constructible, we provide a read-only interface instead.
In practice, this means that if the type is non-copyable, it will be,
for all intents and purposes, read-only from the Python side (but
currently it simply fails to compile with such a container).
It is still possible for the caller to provide an interface manually
(by defining methods on the returned class_ object), but this isn't
something stl_bind can handle because the C++ code to construct values
is going to be highly dependent on the container value_type.
* stl_bind: copy only for arithmetic value types
For non-primitive types, we may well be copying some complex type, when
returning by reference is more appropriate. This commit returns by
internal reference for all but basic arithmetic types.
* Return by reference whenever possible
Only if we definitely can't--i.e. std::vector<bool>--because v[i]
returns something that isn't a T& do we copy; for everything else, we
return by reference.
For the map case, we can always return by reference (at least for the
default stl map/unordered_map).
2016-11-15 11:30:38 +00:00
|
|
|
/// Issue #487: binding std::vector<E> with E non-copyable
|
|
|
|
class E_nc {
|
|
|
|
public:
|
|
|
|
explicit E_nc(int i) : value{i} {}
|
|
|
|
E_nc(const E_nc &) = delete;
|
|
|
|
E_nc &operator=(const E_nc &) = delete;
|
|
|
|
E_nc(E_nc &&) = default;
|
|
|
|
E_nc &operator=(E_nc &&) = default;
|
|
|
|
|
|
|
|
int value;
|
|
|
|
};
|
|
|
|
|
|
|
|
template <class Container> Container *one_to_n(int n) {
|
|
|
|
auto v = new Container();
|
|
|
|
for (int i = 1; i <= n; i++)
|
|
|
|
v->emplace_back(i);
|
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
template <class Map> Map *times_ten(int n) {
|
|
|
|
auto m = new Map();
|
|
|
|
for (int i = 1; i <= n; i++)
|
|
|
|
m->emplace(int(i), E_nc(10*i));
|
|
|
|
return m;
|
|
|
|
}
|
|
|
|
|
2016-11-08 13:03:34 +00:00
|
|
|
struct VStruct {
|
|
|
|
bool w;
|
|
|
|
uint32_t x;
|
|
|
|
double y;
|
|
|
|
bool z;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct VUndeclStruct { //dtype not declared for this version
|
|
|
|
bool w;
|
|
|
|
uint32_t x;
|
|
|
|
double y;
|
|
|
|
bool z;
|
|
|
|
};
|
|
|
|
|
2016-09-03 18:54:22 +00:00
|
|
|
test_initializer stl_binder_vector([](py::module &m) {
|
2016-08-28 17:46:25 +00:00
|
|
|
py::class_<El>(m, "El")
|
|
|
|
.def(py::init<int>());
|
2016-05-08 23:31:55 +00:00
|
|
|
|
2016-11-08 13:03:34 +00:00
|
|
|
py::bind_vector<std::vector<unsigned char>>(m, "VectorUChar", py::buffer_protocol());
|
|
|
|
py::bind_vector<std::vector<unsigned int>>(m, "VectorInt", py::buffer_protocol());
|
2016-09-06 04:02:29 +00:00
|
|
|
py::bind_vector<std::vector<bool>>(m, "VectorBool");
|
2016-05-15 18:50:38 +00:00
|
|
|
|
2016-09-06 04:02:29 +00:00
|
|
|
py::bind_vector<std::vector<El>>(m, "VectorEl");
|
2016-05-07 04:26:19 +00:00
|
|
|
|
2016-09-06 04:02:29 +00:00
|
|
|
py::bind_vector<std::vector<std::vector<El>>>(m, "VectorVectorEl");
|
Fix stl_bind to support movable, non-copyable value types (#490)
This commit includes the following changes:
* Don't provide make_copy_constructor for non-copyable container
make_copy_constructor currently fails for various stl containers (e.g.
std::vector, std::unordered_map, std::deque, etc.) when the container's
value type (e.g. the "T" or the std::pair<K,T> for a map) is
non-copyable. This adds an override that, for types that look like
containers, also requires that the value_type be copyable.
* stl_bind.h: make bind_{vector,map} work for non-copy-constructible types
Most stl_bind modifiers require copying, so if the type isn't copy
constructible, we provide a read-only interface instead.
In practice, this means that if the type is non-copyable, it will be,
for all intents and purposes, read-only from the Python side (but
currently it simply fails to compile with such a container).
It is still possible for the caller to provide an interface manually
(by defining methods on the returned class_ object), but this isn't
something stl_bind can handle because the C++ code to construct values
is going to be highly dependent on the container value_type.
* stl_bind: copy only for arithmetic value types
For non-primitive types, we may well be copying some complex type, when
returning by reference is more appropriate. This commit returns by
internal reference for all but basic arithmetic types.
* Return by reference whenever possible
Only if we definitely can't--i.e. std::vector<bool>--because v[i]
returns something that isn't a T& do we copy; for everything else, we
return by reference.
For the map case, we can always return by reference (at least for the
default stl map/unordered_map).
2016-11-15 11:30:38 +00:00
|
|
|
|
2016-11-08 13:03:34 +00:00
|
|
|
m.def("create_undeclstruct", [m] () mutable {
|
|
|
|
py::bind_vector<std::vector<VUndeclStruct>>(m, "VectorUndeclStruct", py::buffer_protocol());
|
|
|
|
});
|
|
|
|
|
|
|
|
try {
|
|
|
|
py::module::import("numpy");
|
|
|
|
} catch (...) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
PYBIND11_NUMPY_DTYPE(VStruct, w, x, y, z);
|
|
|
|
py::class_<VStruct>(m, "VStruct").def_readwrite("x", &VStruct::x);
|
|
|
|
py::bind_vector<std::vector<VStruct>>(m, "VectorStruct", py::buffer_protocol());
|
|
|
|
m.def("get_vectorstruct", [] {return std::vector<VStruct> {{0, 5, 3.0, 1}, {1, 30, -1e4, 0}};});
|
2016-08-30 02:50:38 +00:00
|
|
|
});
|
|
|
|
|
|
|
|
test_initializer stl_binder_map([](py::module &m) {
|
2016-09-06 04:02:29 +00:00
|
|
|
py::bind_map<std::map<std::string, double>>(m, "MapStringDouble");
|
|
|
|
py::bind_map<std::unordered_map<std::string, double>>(m, "UnorderedMapStringDouble");
|
2016-08-30 02:50:38 +00:00
|
|
|
|
2016-09-06 04:02:29 +00:00
|
|
|
py::bind_map<std::map<std::string, double const>>(m, "MapStringDoubleConst");
|
|
|
|
py::bind_map<std::unordered_map<std::string, double const>>(m, "UnorderedMapStringDoubleConst");
|
Fix stl_bind to support movable, non-copyable value types (#490)
This commit includes the following changes:
* Don't provide make_copy_constructor for non-copyable container
make_copy_constructor currently fails for various stl containers (e.g.
std::vector, std::unordered_map, std::deque, etc.) when the container's
value type (e.g. the "T" or the std::pair<K,T> for a map) is
non-copyable. This adds an override that, for types that look like
containers, also requires that the value_type be copyable.
* stl_bind.h: make bind_{vector,map} work for non-copy-constructible types
Most stl_bind modifiers require copying, so if the type isn't copy
constructible, we provide a read-only interface instead.
In practice, this means that if the type is non-copyable, it will be,
for all intents and purposes, read-only from the Python side (but
currently it simply fails to compile with such a container).
It is still possible for the caller to provide an interface manually
(by defining methods on the returned class_ object), but this isn't
something stl_bind can handle because the C++ code to construct values
is going to be highly dependent on the container value_type.
* stl_bind: copy only for arithmetic value types
For non-primitive types, we may well be copying some complex type, when
returning by reference is more appropriate. This commit returns by
internal reference for all but basic arithmetic types.
* Return by reference whenever possible
Only if we definitely can't--i.e. std::vector<bool>--because v[i]
returns something that isn't a T& do we copy; for everything else, we
return by reference.
For the map case, we can always return by reference (at least for the
default stl map/unordered_map).
2016-11-15 11:30:38 +00:00
|
|
|
|
|
|
|
});
|
|
|
|
|
|
|
|
test_initializer stl_binder_noncopyable([](py::module &m) {
|
|
|
|
py::class_<E_nc>(m, "ENC")
|
|
|
|
.def(py::init<int>())
|
|
|
|
.def_readwrite("value", &E_nc::value);
|
|
|
|
|
|
|
|
py::bind_vector<std::vector<E_nc>>(m, "VectorENC");
|
|
|
|
m.def("get_vnc", &one_to_n<std::vector<E_nc>>, py::return_value_policy::reference);
|
|
|
|
|
|
|
|
py::bind_vector<std::deque<E_nc>>(m, "DequeENC");
|
|
|
|
m.def("get_dnc", &one_to_n<std::deque<E_nc>>, py::return_value_policy::reference);
|
|
|
|
|
|
|
|
py::bind_map<std::map<int, E_nc>>(m, "MapENC");
|
|
|
|
m.def("get_mnc", ×_ten<std::map<int, E_nc>>, py::return_value_policy::reference);
|
|
|
|
|
|
|
|
py::bind_map<std::unordered_map<int, E_nc>>(m, "UmapENC");
|
|
|
|
m.def("get_umnc", ×_ten<std::unordered_map<int, E_nc>>, py::return_value_policy::reference);
|
2016-09-03 18:54:22 +00:00
|
|
|
});
|