mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-26 07:02:11 +00:00
Extend tuple and list accessor interface
This commit is contained in:
parent
242b146a51
commit
ea763a57a8
@ -1338,7 +1338,7 @@ NAMESPACE_BEGIN(detail)
|
||||
PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) {
|
||||
auto strings = tuple(args.size());
|
||||
for (size_t i = 0; i < args.size(); ++i) {
|
||||
strings[i] = args[i].cast<object>().str();
|
||||
strings[i] = args[i].str();
|
||||
}
|
||||
auto sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" ");
|
||||
auto line = sep.attr("join")(strings);
|
||||
|
@ -29,10 +29,14 @@ namespace accessor_policies {
|
||||
struct obj_attr;
|
||||
struct str_attr;
|
||||
struct generic_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 list_accessor = accessor<accessor_policies::list_item>;
|
||||
using tuple_accessor = accessor<accessor_policies::tuple_item>;
|
||||
|
||||
/// Tag and check to identify a class which implements the Python object API
|
||||
class pyobject_tag { };
|
||||
@ -241,58 +245,42 @@ struct generic_item {
|
||||
if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); }
|
||||
}
|
||||
};
|
||||
|
||||
struct list_item {
|
||||
using key_type = size_t;
|
||||
|
||||
static object get(handle obj, size_t index) {
|
||||
PyObject *result = PyList_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) {
|
||||
// PyList_SetItem steals a reference to 'val'
|
||||
if (PyList_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) {
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct tuple_item {
|
||||
using key_type = size_t;
|
||||
|
||||
static object get(handle obj, size_t index) {
|
||||
PyObject *result = PyTuple_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) {
|
||||
// PyTuple_SetItem steals a reference to 'val'
|
||||
if (PyTuple_SetItem(obj.ptr(), static_cast<ssize_t>(index), val.inc_ref().ptr()) != 0) {
|
||||
throw error_already_set();
|
||||
}
|
||||
}
|
||||
};
|
||||
NAMESPACE_END(accessor_policies)
|
||||
|
||||
struct list_accessor {
|
||||
public:
|
||||
list_accessor(handle list, size_t index) : list(list), index(index) { }
|
||||
|
||||
void operator=(list_accessor o) { return operator=(object(o)); }
|
||||
|
||||
void operator=(const handle &o) {
|
||||
// PyList_SetItem steals a reference to 'o'
|
||||
if (PyList_SetItem(list.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
|
||||
pybind11_fail("Unable to assign value in Python list!");
|
||||
}
|
||||
|
||||
operator object() const {
|
||||
PyObject *result = PyList_GetItem(list.ptr(), (ssize_t) index);
|
||||
if (!result)
|
||||
pybind11_fail("Unable to retrieve value from Python list!");
|
||||
return object(result, true);
|
||||
}
|
||||
|
||||
template <typename T> T cast() const { return operator object().cast<T>(); }
|
||||
private:
|
||||
handle list;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
struct tuple_accessor {
|
||||
public:
|
||||
tuple_accessor(handle tuple, size_t index) : tuple(tuple), index(index) { }
|
||||
|
||||
void operator=(tuple_accessor o) { return operator=(object(o)); }
|
||||
|
||||
void operator=(const handle &o) {
|
||||
// PyTuple_SetItem steals a referenceto 'o'
|
||||
if (PyTuple_SetItem(tuple.ptr(), (ssize_t) index, o.inc_ref().ptr()) < 0)
|
||||
pybind11_fail("Unable to assign value in Python tuple!");
|
||||
}
|
||||
|
||||
operator object() const {
|
||||
PyObject *result = PyTuple_GetItem(tuple.ptr(), (ssize_t) index);
|
||||
if (!result)
|
||||
pybind11_fail("Unable to retrieve value from Python tuple!");
|
||||
return object(result, true);
|
||||
}
|
||||
|
||||
template <typename T> T cast() const { return operator object().cast<T>(); }
|
||||
private:
|
||||
handle tuple;
|
||||
size_t index;
|
||||
};
|
||||
|
||||
struct dict_iterator {
|
||||
public:
|
||||
dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { }
|
||||
@ -647,7 +635,7 @@ public:
|
||||
if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
|
||||
}
|
||||
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
||||
detail::tuple_accessor operator[](size_t index) const { return detail::tuple_accessor(*this, index); }
|
||||
detail::tuple_accessor operator[](size_t index) const { return {*this, index}; }
|
||||
};
|
||||
|
||||
class dict : public object {
|
||||
@ -677,7 +665,7 @@ public:
|
||||
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
||||
}
|
||||
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
||||
detail::list_accessor operator[](size_t index) const { return detail::list_accessor(*this, index); }
|
||||
detail::list_accessor operator[](size_t index) const { return {*this, index}; }
|
||||
void append(handle h) const { PyList_Append(m_ptr, h.ptr()); }
|
||||
};
|
||||
|
||||
|
@ -60,7 +60,7 @@ public:
|
||||
py::list get_list() {
|
||||
py::list list;
|
||||
list.append(py::str("value"));
|
||||
py::print("Entry at position 0:", py::object(list[0]));
|
||||
py::print("Entry at position 0:", list[0]);
|
||||
list[0] = py::str("overwritten");
|
||||
return list;
|
||||
}
|
||||
@ -257,4 +257,19 @@ test_initializer python_types([](py::module &m) {
|
||||
|
||||
return d;
|
||||
});
|
||||
|
||||
m.def("test_tuple_accessor", [](py::tuple existing_t) {
|
||||
try {
|
||||
existing_t[0] = py::cast(1);
|
||||
} catch (const py::error_already_set &) {
|
||||
// --> Python system error
|
||||
// Only new tuples (refcount == 1) are mutable
|
||||
auto new_t = py::tuple(3);
|
||||
for (size_t i = 0; i < new_t.size(); ++i) {
|
||||
new_t[i] = py::cast(i);
|
||||
}
|
||||
return new_t;
|
||||
}
|
||||
return py::tuple();
|
||||
});
|
||||
});
|
||||
|
@ -251,7 +251,7 @@ def test_dict_api():
|
||||
|
||||
|
||||
def test_accessors():
|
||||
from pybind11_tests import test_accessor_api
|
||||
from pybind11_tests import test_accessor_api, test_tuple_accessor
|
||||
|
||||
class SubTestObject:
|
||||
attr_obj = 1
|
||||
@ -278,3 +278,5 @@ def test_accessors():
|
||||
assert d["is_none"] is False
|
||||
assert d["operator()"] == 2
|
||||
assert d["operator*"] == 7
|
||||
|
||||
assert test_tuple_accessor(tuple()) == (0, 1, 2)
|
||||
|
Loading…
Reference in New Issue
Block a user