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) {
|
PYBIND11_NOINLINE inline void print(tuple args, dict kwargs) {
|
||||||
auto strings = tuple(args.size());
|
auto strings = tuple(args.size());
|
||||||
for (size_t i = 0; i < args.size(); ++i) {
|
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 sep = kwargs.contains("sep") ? kwargs["sep"] : cast(" ");
|
||||||
auto line = sep.attr("join")(strings);
|
auto line = sep.attr("join")(strings);
|
||||||
|
@ -29,10 +29,14 @@ namespace accessor_policies {
|
|||||||
struct obj_attr;
|
struct obj_attr;
|
||||||
struct str_attr;
|
struct str_attr;
|
||||||
struct generic_item;
|
struct generic_item;
|
||||||
|
struct list_item;
|
||||||
|
struct tuple_item;
|
||||||
}
|
}
|
||||||
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
|
using obj_attr_accessor = accessor<accessor_policies::obj_attr>;
|
||||||
using str_attr_accessor = accessor<accessor_policies::str_attr>;
|
using str_attr_accessor = accessor<accessor_policies::str_attr>;
|
||||||
using item_accessor = accessor<accessor_policies::generic_item>;
|
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
|
/// Tag and check to identify a class which implements the Python object API
|
||||||
class pyobject_tag { };
|
class pyobject_tag { };
|
||||||
@ -241,58 +245,42 @@ struct generic_item {
|
|||||||
if (PyObject_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { throw error_already_set(); }
|
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)
|
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 {
|
struct dict_iterator {
|
||||||
public:
|
public:
|
||||||
dict_iterator(handle dict = handle(), ssize_t pos = -1) : dict(dict), pos(pos) { }
|
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!");
|
if (!m_ptr) pybind11_fail("Could not allocate tuple object!");
|
||||||
}
|
}
|
||||||
size_t size() const { return (size_t) PyTuple_Size(m_ptr); }
|
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 {
|
class dict : public object {
|
||||||
@ -677,7 +665,7 @@ public:
|
|||||||
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
if (!m_ptr) pybind11_fail("Could not allocate list object!");
|
||||||
}
|
}
|
||||||
size_t size() const { return (size_t) PyList_Size(m_ptr); }
|
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()); }
|
void append(handle h) const { PyList_Append(m_ptr, h.ptr()); }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -60,7 +60,7 @@ public:
|
|||||||
py::list get_list() {
|
py::list get_list() {
|
||||||
py::list list;
|
py::list list;
|
||||||
list.append(py::str("value"));
|
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");
|
list[0] = py::str("overwritten");
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
@ -257,4 +257,19 @@ test_initializer python_types([](py::module &m) {
|
|||||||
|
|
||||||
return d;
|
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():
|
def test_accessors():
|
||||||
from pybind11_tests import test_accessor_api
|
from pybind11_tests import test_accessor_api, test_tuple_accessor
|
||||||
|
|
||||||
class SubTestObject:
|
class SubTestObject:
|
||||||
attr_obj = 1
|
attr_obj = 1
|
||||||
@ -278,3 +278,5 @@ def test_accessors():
|
|||||||
assert d["is_none"] is False
|
assert d["is_none"] is False
|
||||||
assert d["operator()"] == 2
|
assert d["operator()"] == 2
|
||||||
assert d["operator*"] == 7
|
assert d["operator*"] == 7
|
||||||
|
|
||||||
|
assert test_tuple_accessor(tuple()) == (0, 1, 2)
|
||||||
|
Loading…
Reference in New Issue
Block a user