Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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