fix: <ranges> support for py::tuple and py::list (#5314)

* feat: add `<ranges>` support for `py::tuple` and `py::list`

* fix: format the code

* fix: disable `ranges` in clang < 16

* refactor: move `<ranges>` test macro to `test_pytypes.h`

* refactor: seperate `ranges` test into 3 funcs

* style: compress the if statement

* style: pre-commit fixes

* style: better formatting

---------

Co-authored-by: Henry Schreiner <HenrySchreinerIII@gmail.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
This commit is contained in:
ObeliskGate
2024-08-22 03:33:06 +08:00
committed by GitHub
parent 7d85baa6a1
commit 2baf9d6833
3 changed files with 107 additions and 0 deletions

View File

@@ -13,6 +13,14 @@
#include <utility>
//__has_include has been part of C++17, no need to check it
#if defined(PYBIND11_CPP20) && __has_include(<ranges>)
# if !defined(PYBIND11_COMPILER_CLANG) || __clang_major__ >= 16 // llvm/llvm-project#52696
# define PYBIND11_TEST_PYTYPES_HAS_RANGES
# include <ranges>
# endif
#endif
namespace external {
namespace detail {
bool check(PyObject *o) { return PyFloat_Check(o) != 0; }
@@ -923,4 +931,59 @@ TEST_SUBMODULE(pytypes, m) {
#else
m.attr("defined_PYBIND11_TYPING_H_HAS_STRING_LITERAL") = false;
#endif
#if defined(PYBIND11_TEST_PYTYPES_HAS_RANGES)
// test_tuple_ranges
m.def("tuple_iterator_default_initialization", []() {
using TupleIterator = decltype(std::declval<py::tuple>().begin());
static_assert(std::random_access_iterator<TupleIterator>);
return TupleIterator{} == TupleIterator{};
});
m.def("transform_tuple_plus_one", [](py::tuple &tpl) {
py::list ret{};
for (auto it : tpl | std::views::transform([](auto &o) { return py::cast<int>(o) + 1; })) {
ret.append(py::int_(it));
}
return ret;
});
// test_list_ranges
m.def("list_iterator_default_initialization", []() {
using ListIterator = decltype(std::declval<py::list>().begin());
static_assert(std::random_access_iterator<ListIterator>);
return ListIterator{} == ListIterator{};
});
m.def("transform_list_plus_one", [](py::list &lst) {
py::list ret{};
for (auto it : lst | std::views::transform([](auto &o) { return py::cast<int>(o) + 1; })) {
ret.append(py::int_(it));
}
return ret;
});
// test_dict_ranges
m.def("dict_iterator_default_initialization", []() {
using DictIterator = decltype(std::declval<py::dict>().begin());
static_assert(std::forward_iterator<DictIterator>);
return DictIterator{} == DictIterator{};
});
m.def("transform_dict_plus_one", [](py::dict &dct) {
py::list ret{};
for (auto it : dct | std::views::transform([](auto &o) {
return std::pair{py::cast<int>(o.first) + 1,
py::cast<int>(o.second) + 1};
})) {
ret.append(py::make_tuple(py::int_(it.first), py::int_(it.second)));
}
return ret;
});
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = true;
#else
m.attr("defined_PYBIND11_TEST_PYTYPES_HAS_RANGES") = false;
#endif
}