Skip to content

Commit

Permalink
Merge pull request #4 from lsst-dm/tickets/DM-7115
Browse files Browse the repository at this point in the history
Accept any sequence type as std::vector
  • Loading branch information
Pim Schellart authored Oct 15, 2016
2 parents 26df852 + d2afe7f commit fcab621
Show file tree
Hide file tree
Showing 3 changed files with 40 additions and 6 deletions.
26 changes: 26 additions & 0 deletions include/pybind11/pytypes.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,14 @@ namespace accessor_policies {
struct obj_attr;
struct str_attr;
struct generic_item;
struct sequence_item;
struct list_item;
struct tuple_item;
}
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
using str_attr_accessor = accessor<accessor_policies::str_attr>;
using item_accessor = accessor<accessor_policies::generic_item>;
using sequence_accessor = accessor<accessor_policies::sequence_item>;
using list_accessor = accessor<accessor_policies::list_item>;
using tuple_accessor = accessor<accessor_policies::tuple_item>;

Expand Down Expand Up @@ -261,6 +263,23 @@ struct generic_item {
}
};

struct sequence_item {
using key_type = size_t;

static object get(handle obj, size_t index) {
PyObject *result = PySequence_GetItem(obj.ptr(), static_cast<ssize_t>(index));
if (!result) { throw error_already_set(); }
return {result, true};
}

static void set(handle obj, size_t index, handle val) {
// PySequence_SetItem does not steal a reference to 'val'
if (PySequence_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.ptr()) != 0) {
throw error_already_set();
}
}
};

struct list_item {
using key_type = size_t;

Expand Down Expand Up @@ -673,6 +692,13 @@ class dict : public object {
bool contains(const char *key) const { return PyDict_Contains(ptr(), pybind11::str(key).ptr()) == 1; }
};

class sequence : public object {
public:
PYBIND11_OBJECT(sequence, object, PySequence_Check)
size_t size() const { return (size_t) PySequence_Size(m_ptr); }
detail::sequence_accessor operator[](size_t index) const { return {*this, index}; }
};

class list : public object {
public:
PYBIND11_OBJECT(list, object, PyList_Check)
Expand Down
12 changes: 6 additions & 6 deletions include/pybind11/stl.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,13 @@ template <typename Type, typename Value> struct list_caster {
using value_conv = make_caster<Value>;

bool load(handle src, bool convert) {
list l(src, true);
if (!l.check())
sequence s(src, true);
if (!s.check())
return false;
value_conv conv;
value.clear();
reserve_maybe(l, &value);
for (auto it : l) {
reserve_maybe(s, &value);
for (auto it : s) {
if (!conv.load(it, convert))
return false;
value.push_back((Value) conv);
Expand All @@ -113,8 +113,8 @@ template <typename Type, typename Value> struct list_caster {

template <typename T = Type,
enable_if_t<std::is_same<decltype(std::declval<T>().reserve(0)), void>::value, int> = 0>
void reserve_maybe(list l, Type *) { value.reserve(l.size()); }
void reserve_maybe(list, void *) { }
void reserve_maybe(sequence s, Type *) { value.reserve(s.size()); }
void reserve_maybe(sequence, void *) { }

static handle cast(const Type &src, return_value_policy policy, handle parent) {
list l(src.size());
Expand Down
8 changes: 8 additions & 0 deletions tests/test_python_types.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,14 @@ def test_instance(capture):
list item 0: value
list item 1: value2
"""
with capture:
list_result = instance.get_list_2()
list_result.append('value2')
instance.print_list_2(tuple(list_result))
assert capture.unordered == """
list item 0: value
list item 1: value2
"""
array_result = instance.get_array()
assert array_result == ['array entry 1', 'array entry 2']
with capture:
Expand Down

0 comments on commit fcab621

Please sign in to comment.