-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Add shortcut dict::get and optimize item access for dict
#2779
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from 3 commits
8a9b35d
e0aa141
5f0aead
6b2d1ba
fcecfae
68684d6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -35,13 +35,15 @@ namespace accessor_policies { | |
| struct sequence_item; | ||
| struct list_item; | ||
| struct tuple_item; | ||
| struct dict_item; | ||
| } // namespace accessor_policies | ||
| 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>; | ||
| using dict_accessor = accessor<accessor_policies::dict_item>; | ||
|
|
||
| /// Tag and check to identify a class which implements the Python object API | ||
| class pyobject_tag { }; | ||
|
|
@@ -613,6 +615,31 @@ struct tuple_item { | |
| } | ||
| } | ||
| }; | ||
|
|
||
| struct dict_item { | ||
| using key_type = object; | ||
|
|
||
| static object get(handle obj, handle key) { | ||
| #if PY_MAJOR_VERSION >= 3 | ||
| if (PyObject *result = PyDict_GetItemWithError(obj.ptr(), key.ptr())) { | ||
| return reinterpret_borrow<object>(result); | ||
| } else { | ||
| if (!PyErr_Occurred()) | ||
YannickJadoul marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| if (PyObject* key_repr = PyObject_Repr(key.ptr())) | ||
lqf96 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| PyErr_SetObject(PyExc_KeyError, key_repr); | ||
| throw error_already_set(); | ||
| } | ||
| #else | ||
| return generic_item::get(obj, key); | ||
| #endif | ||
| } | ||
|
|
||
| static void set(handle obj, handle key, handle val) { | ||
| if (PyDict_SetItem(obj.ptr(), key.ptr(), val.ptr()) != 0) { | ||
| throw error_already_set(); | ||
| } | ||
| } | ||
| }; | ||
| PYBIND11_NAMESPACE_END(accessor_policies) | ||
|
|
||
| /// STL iterator template used for tuple, list, sequence and dict | ||
|
|
@@ -1285,13 +1312,42 @@ class dict : public object { | |
|
|
||
| size_t size() const { return (size_t) PyDict_Size(m_ptr); } | ||
| bool empty() const { return size() == 0; } | ||
| detail::dict_accessor operator[](const char *key) const { return {*this, pybind11::str(key)}; } | ||
lqf96 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| detail::dict_accessor operator[](handle h) const { return {*this, reinterpret_borrow<object>(h)}; } | ||
| detail::dict_iterator begin() const { return {*this, 0}; } | ||
| detail::dict_iterator end() const { return {}; } | ||
| void clear() const { PyDict_Clear(ptr()); } | ||
| template <typename T> bool contains(T &&key) const { | ||
| return PyDict_Contains(m_ptr, detail::object_or_cast(std::forward<T>(key)).ptr()) == 1; | ||
| } | ||
|
|
||
| object get(handle key, handle default_ = none()) const { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Other reviewers: should this be moved out of the class definition? I think it's on the edge of being too long, but good enough and maybe nicer to keep it just as-is than to split it up into two parts. |
||
| #if PY_MAJOR_VERSION >= 3 | ||
| if (PyObject *result = PyDict_GetItemWithError(m_ptr, key.ptr())) { | ||
lqf96 marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| return reinterpret_borrow<object>(result); | ||
| } else { | ||
| if (PyErr_Occurred()) | ||
lqf96 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| throw error_already_set(); | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Throw or return default?
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #2779 (comment) |
||
| else | ||
| return reinterpret_borrow<object>(default_); | ||
| } | ||
| #else | ||
| try { | ||
| return object::operator[](key); | ||
| } catch (const error_already_set& e) { | ||
| if (e.type().ptr() == PyExc_KeyError) { | ||
| return reinterpret_borrow<object>(default_); | ||
| } else { | ||
| throw; | ||
| } | ||
| } | ||
| #endif | ||
| } | ||
|
|
||
| object get(const char *key, handle default_ = none()) const { | ||
lqf96 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| return get(pybind11::str(key), default_); | ||
| } | ||
|
|
||
| private: | ||
| /// Call the `dict` Python type -- always returns a new reference | ||
| static PyObject *raw_dict(PyObject *op) { | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.