[libcxx-commits] [libcxx] [libc++] Implement adjacent_view (PR #165089)
Louis Dionne via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Dec 5 12:03:55 PST 2025
================
@@ -0,0 +1,136 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
+
+// constexpr auto begin() requires (!(simple-view<Views> && ...));
+// constexpr auto begin() const requires (range<const Views> && ...);
+
+#include <ranges>
+
+#include <array>
+#include <cassert>
+#include <concepts>
+#include <utility>
+
+#include "../range_adaptor_types.h"
+
+template <class T>
+concept HasConstBegin = requires(const T& ct) { ct.begin(); };
+
+template <class T>
+concept HasBegin = requires(T& t) { t.begin(); };
+
+template <class T>
+concept HasConstAndNonConstBegin = HasConstBegin<T> && requires(T& t, const T& ct) {
+ requires !std::same_as<decltype(t.begin()), decltype(ct.begin())>;
+};
+
+template <class T>
+concept HasOnlyNonConstBegin = HasBegin<T> && !HasConstBegin<T>;
+
+template <class T>
+concept HasOnlyConstBegin = HasConstBegin<T> && !HasConstAndNonConstBegin<T>;
+
+struct NoConstBeginView : std::ranges::view_base {
+ int* begin();
+ int* end();
+};
+
+template <class Range, std::size_t N>
+constexpr void test_one() {
+ using View = std::ranges::adjacent_view<Range, N>;
+ {
+ int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+ View v(Range{buffer});
+
+ auto it = v.begin();
+ auto tuple = *it;
+ assert(std::get<0>(tuple) == buffer[0]);
+ if constexpr (N >= 2)
+ assert(std::get<1>(tuple) == buffer[1]);
+ if constexpr (N >= 3)
+ assert(std::get<2>(tuple) == buffer[2]);
+
+ auto cit = std::as_const(v).begin();
+ auto ctuple = *cit;
+ assert(std::get<0>(ctuple) == buffer[0]);
+ if constexpr (N >= 2)
+ assert(std::get<1>(ctuple) == buffer[1]);
+ if constexpr (N >= 3)
+ assert(std::get<2>(ctuple) == buffer[2]);
+ if constexpr (N >= 4)
+ assert(std::get<3>(ctuple) == buffer[3]);
+ if constexpr (N >= 5)
+ assert(std::get<4>(ctuple) == buffer[4]);
+ }
+
+ {
+ // empty range
+ std::array<int, 0> buffer = {};
+ View v(Range{buffer.data(), 0});
+ auto it = v.begin();
+ auto cit = std::as_const(v).begin();
+ assert(it == v.end());
+ assert(cit == std::as_const(v).end());
+ }
+
+ if constexpr (N > 2) {
+ // N greater than range size
+ int buffer[2] = {1, 2};
+ View v(Range{buffer});
+ auto it = v.begin();
+ auto cit = std::as_const(v).begin();
+ assert(it == v.end());
+ assert(cit == std::as_const(v).end());
+ }
+}
+
+template <std::size_t N>
+constexpr void test_simple() {
+ test_one<SimpleCommon, N>();
+
+ using View = std::ranges::adjacent_view<SimpleCommon, N>;
+ static_assert(std::is_same_v<std::ranges::iterator_t<View>, std::ranges::iterator_t<const View>>);
+}
+
+template <std::size_t N>
+constexpr void test_non_simple() {
+ test_one<NonSimpleCommon, N>();
+
+ using View = std::ranges::adjacent_view<NonSimpleCommon, N>;
+ static_assert(!std::is_same_v<std::ranges::iterator_t<View>, std::ranges::iterator_t<const View>>);
+}
+
+template <std::size_t N>
+constexpr void test() {
+ test_simple<N>();
+ test_non_simple<N>();
----------------
ldionne wrote:
I find these 3 layers of function calls to be somewhat complicated. I'd suggest:
```c++
template <std::size_t N>
constexpr void test() {
// non-simple range
{
test_one<NonSimpleCommon, N>();
using View = std::ranges::adjacent_view<NonSimpleCommon, N>;
static_assert(!std::is_same_v<std::ranges::iterator_t<View>, std::ranges::iterator_t<const View>>);
}
// simple range
{
...
}
}
```
https://github.com/llvm/llvm-project/pull/165089
More information about the libcxx-commits
mailing list