mirror of
https://github.com/pybind/pybind11.git
synced 2026-05-13 09:46:10 +00:00
Add anyset & frozenset, enable copying (cast) to std::set (#3901)
* Add frozenset, and allow it cast to std::set For the reverse direction, std::set still casts to set. This is in concordance with the behavior for sequence containers, where e.g. tuple casts to std::vector but std::vector casts to list. Extracted from #3886. * Rename set_base to any_set to match Python C API since this will be part of pybind11 public API * PR: static_cast, anyset * Add tests for frozenset and rename anyset methods * Remove frozenset default ctor, add tests Making frozenset non-default constructible means that we need to adjust pyobject_caster to not require that its value is default constructible, by initializing value to a nil handle. This also allows writing C++ functions taking anyset, and is arguably a performance improvement, since there is no need to allocate an object that will just be replaced by load. Add some more tests, including anyset::empty, anyset::size, set::add and set::clear. * [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci * Add rationale to `pyobject_caster` default ctor * Remove ineffectual protected: access control Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
@@ -908,6 +908,14 @@ struct handle_type_name<kwargs> {
|
||||
|
||||
template <typename type>
|
||||
struct pyobject_caster {
|
||||
template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>
|
||||
pyobject_caster() : value() {}
|
||||
|
||||
// `type` may not be default constructible (e.g. frozenset, anyset). Initializing `value`
|
||||
// to a nil handle is safe since it will only be accessed if `load` succeeds.
|
||||
template <typename T = type, enable_if_t<std::is_base_of<object, T>::value, int> = 0>
|
||||
pyobject_caster() : value(reinterpret_steal<type>(handle())) {}
|
||||
|
||||
template <typename T = type, enable_if_t<std::is_same<T, handle>::value, int> = 0>
|
||||
bool load(handle src, bool /* convert */) {
|
||||
value = src;
|
||||
|
||||
@@ -1784,25 +1784,35 @@ class kwargs : public dict {
|
||||
PYBIND11_OBJECT_DEFAULT(kwargs, dict, PyDict_Check)
|
||||
};
|
||||
|
||||
class set : public object {
|
||||
class anyset : public object {
|
||||
public:
|
||||
PYBIND11_OBJECT_CVT(set, object, PySet_Check, PySet_New)
|
||||
set() : object(PySet_New(nullptr), stolen_t{}) {
|
||||
PYBIND11_OBJECT(anyset, object, PyAnySet_Check)
|
||||
size_t size() const { return static_cast<size_t>(PySet_Size(m_ptr)); }
|
||||
bool empty() const { return size() == 0; }
|
||||
template <typename T>
|
||||
bool contains(T &&val) const {
|
||||
return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
|
||||
}
|
||||
};
|
||||
|
||||
class set : public anyset {
|
||||
public:
|
||||
PYBIND11_OBJECT_CVT(set, anyset, PySet_Check, PySet_New)
|
||||
set() : anyset(PySet_New(nullptr), stolen_t{}) {
|
||||
if (!m_ptr) {
|
||||
pybind11_fail("Could not allocate set object!");
|
||||
}
|
||||
}
|
||||
size_t size() const { return (size_t) PySet_Size(m_ptr); }
|
||||
bool empty() const { return size() == 0; }
|
||||
template <typename T>
|
||||
bool add(T &&val) /* py-non-const */ {
|
||||
return PySet_Add(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 0;
|
||||
}
|
||||
void clear() /* py-non-const */ { PySet_Clear(m_ptr); }
|
||||
template <typename T>
|
||||
bool contains(T &&val) const {
|
||||
return PySet_Contains(m_ptr, detail::object_or_cast(std::forward<T>(val)).ptr()) == 1;
|
||||
}
|
||||
};
|
||||
|
||||
class frozenset : public anyset {
|
||||
public:
|
||||
PYBIND11_OBJECT_CVT(frozenset, anyset, PyFrozenSet_Check, PyFrozenSet_New)
|
||||
};
|
||||
|
||||
class function : public object {
|
||||
|
||||
@@ -55,10 +55,10 @@ struct set_caster {
|
||||
using key_conv = make_caster<Key>;
|
||||
|
||||
bool load(handle src, bool convert) {
|
||||
if (!isinstance<pybind11::set>(src)) {
|
||||
if (!isinstance<anyset>(src)) {
|
||||
return false;
|
||||
}
|
||||
auto s = reinterpret_borrow<pybind11::set>(src);
|
||||
auto s = reinterpret_borrow<anyset>(src);
|
||||
value.clear();
|
||||
for (auto entry : s) {
|
||||
key_conv conv;
|
||||
|
||||
Reference in New Issue
Block a user