From 6784a7aff75e32f68468d0f8f503abcf5b5a2830 Mon Sep 17 00:00:00 2001 From: Volker Hilsheimer Date: Sat, 30 Aug 2025 11:52:04 +0200 Subject: [PATCH] QRM: make size() work for ranges that don't have begin/end(const R&) Use const_cast to call the mutable overload if we cannot call the const overload. This allows us to directly support e.g. std::views::filter. As a drive by, use using-statements to reduce code duplication. Use std::views::filter directly in the tests, now that it works. Change-Id: I47f06ee8fe921d5854f676a35a750e64f4356fc0 Reviewed-by: Artem Dyomin --- src/corelib/itemmodels/qrangemodel_impl.h | 26 ++++++++++++++----- .../qrangemodel/tst_qrangemodel.cpp | 2 +- .../corelib/itemmodels/qrangemodel/main.cpp | 3 +-- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/src/corelib/itemmodels/qrangemodel_impl.h b/src/corelib/itemmodels/qrangemodel_impl.h index 52ea58be32a..20e64bdc295 100644 --- a/src/corelib/itemmodels/qrangemodel_impl.h +++ b/src/corelib/itemmodels/qrangemodel_impl.h @@ -480,6 +480,13 @@ namespace QRangeModelDetails template struct test_size()))>> : std::true_type {}; + template + struct test_cbegin : std::false_type {}; + template + struct test_cbegin()))>> + : std::true_type + {}; + template struct range_traits : std::false_type { static constexpr bool is_mutable = !std::is_const_v; @@ -488,6 +495,7 @@ namespace QRangeModelDetails static constexpr bool has_erase = false; static constexpr bool has_resize = false; static constexpr bool has_rotate = false; + static constexpr bool has_cbegin = false; }; template struct range_traits())), @@ -503,6 +511,7 @@ namespace QRangeModelDetails static constexpr bool has_erase = test_erase(); static constexpr bool has_resize = test_resize(); static constexpr bool has_rotate = test_rotate(); + static constexpr bool has_cbegin = test_cbegin::value; }; // Specializations for types that look like ranges, but should be @@ -515,6 +524,7 @@ namespace QRangeModelDetails static constexpr bool has_erase = false; static constexpr bool has_resize = false; static constexpr bool has_rotate = false; + static constexpr bool has_cbegin = true; }; template <> struct range_traits : iterable_value {}; template <> struct range_traits : iterable_value {}; @@ -1042,19 +1052,23 @@ protected: template static constexpr int size(const C &c) { - if (!QRangeModelDetails::isValid(c)) + using namespace QRangeModelDetails; + if (!isValid(c)) return 0; - if constexpr (QRangeModelDetails::test_size()) { + if constexpr (test_size()) { return int(std::size(c)); } else { #if defined(__cpp_lib_ranges) - return int(std::ranges::distance(QRangeModelDetails::begin(c), - QRangeModelDetails::end(c))); + using std::ranges::distance; #else - return int(std::distance(QRangeModelDetails::begin(c), - QRangeModelDetails::end(c))); + using std::distance; #endif + using container_type = std::conditional_t::has_cbegin, + const wrapped_t, + wrapped_t>; + container_type& container = const_cast(refTo(c)); + return int(distance(std::begin(container), std::end(container))); } } diff --git a/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp b/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp index 00d7ec86932..4f4841b2ed1 100644 --- a/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp +++ b/tests/auto/corelib/itemmodels/qrangemodel/tst_qrangemodel.cpp @@ -1219,7 +1219,7 @@ void tst_QRangeModel::filterAsRange() | std::views::filter([](int i){ return 0 == i % 2; }) | std::views::transform([](int i){ return i * i; }); - QRangeModel model(std::ranges::subrange(view.begin(), view.end())); + QRangeModel model(view); QCOMPARE(model.rowCount(), 50); #else QSKIP("Test of std::ranges requires C++ 20"); diff --git a/tests/manual/corelib/itemmodels/qrangemodel/main.cpp b/tests/manual/corelib/itemmodels/qrangemodel/main.cpp index 70a776f5211..f03c68f14b8 100644 --- a/tests/manual/corelib/itemmodels/qrangemodel/main.cpp +++ b/tests/manual/corelib/itemmodels/qrangemodel/main.cpp @@ -294,8 +294,7 @@ public slots: | std::views::filter([](int i){ return 0 == i % 2; }) | std::views::transform([](int i){ return i * i; }); - // suboptimal: eager evaluation of view.begin() - return new QRangeModel(std::ranges::subrange(view.begin(), view.end())); + return new QRangeModel(view); } QRangeModel *makeMultiRoleMap()