[libcxx-commits] [libcxx] [libc++] Implement adjacent_view (PR #165089)
via libcxx-commits
libcxx-commits at lists.llvm.org
Fri Dec 5 11:20:28 PST 2025
================
@@ -0,0 +1,408 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP___RANGES_ADJACENT_VIEW_H
+#define _LIBCPP___RANGES_ADJACENT_VIEW_H
+
+#include <__config>
+
+#include <__algorithm/min.h>
+#include <__compare/three_way_comparable.h>
+#include <__concepts/constructible.h>
+#include <__concepts/convertible_to.h>
+#include <__concepts/equality_comparable.h>
+#include <__cstddef/size_t.h>
+#include <__functional/invoke.h>
+#include <__functional/operations.h>
+#include <__iterator/concepts.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/iter_move.h>
+#include <__iterator/iter_swap.h>
+#include <__iterator/iterator_traits.h>
+#include <__iterator/next.h>
+#include <__iterator/prev.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/empty_view.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/range_adaptor.h>
+#include <__ranges/size.h>
+#include <__ranges/view_interface.h>
+#include <__ranges/zip_utils.h>
+#include <__type_traits/common_type.h>
+#include <__type_traits/is_nothrow_constructible.h>
+#include <__type_traits/make_unsigned.h>
+#include <__type_traits/maybe_const.h>
+#include <__utility/declval.h>
+#include <__utility/forward.h>
+#include <__utility/integer_sequence.h>
+#include <__utility/move.h>
+#include <array>
+#include <tuple>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if _LIBCPP_STD_VER >= 23
+
+namespace ranges {
+
+template <forward_range _View, size_t _Np>
+ requires view<_View> && (_Np > 0)
+class adjacent_view : public view_interface<adjacent_view<_View, _Np>> {
+private:
+ _LIBCPP_NO_UNIQUE_ADDRESS _View __base_ = _View();
+
+ template <bool>
+ class __iterator;
+
+ template <bool>
+ class __sentinel;
+
+ struct __as_sentinel {};
+
+public:
+ _LIBCPP_HIDE_FROM_ABI adjacent_view()
+ requires default_initializable<_View>
+ = default;
+
+ _LIBCPP_HIDE_FROM_ABI constexpr explicit adjacent_view(_View __base) : __base_(std::move(__base)) {}
+
+ _LIBCPP_HIDE_FROM_ABI constexpr _View base() const&
+ requires copy_constructible<_View>
+ {
+ return __base_;
+ }
+ _LIBCPP_HIDE_FROM_ABI constexpr _View base() && { return std::move(__base_); }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto begin()
+ requires(!__simple_view<_View>)
+ {
+ return __iterator<false>(ranges::begin(__base_), ranges::end(__base_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto begin() const
+ requires range<const _View> // todo: this seems under-constrained. lwg issue?
+ {
+ return __iterator<true>(ranges::begin(__base_), ranges::end(__base_));
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto end()
+ requires(!__simple_view<_View>)
+ {
+ if constexpr (common_range<_View>) {
+ return __iterator<false>(__as_sentinel{}, ranges::begin(__base_), ranges::end(__base_));
+ } else {
+ return __sentinel<false>(ranges::end(__base_));
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto end() const
+ requires range<const _View>
+ {
+ if constexpr (common_range<const _View>) {
+ return __iterator<true>(__as_sentinel{}, ranges::begin(__base_), ranges::end(__base_));
+ } else {
+ return __sentinel<true>(ranges::end(__base_));
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size()
+ requires sized_range<_View>
+ {
+ using _ST = decltype(ranges::size(__base_));
+ using _CT = common_type_t<_ST, size_t>;
+ auto __sz = static_cast<_CT>(ranges::size(__base_));
+ __sz -= std::min<_CT>(__sz, _Np - 1);
+ return static_cast<_ST>(__sz);
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr auto size() const
+ requires sized_range<const _View>
+ {
+ using _ST = decltype(ranges::size(__base_));
+ using _CT = common_type_t<_ST, size_t>;
+ auto __sz = static_cast<_CT>(ranges::size(__base_));
+ __sz -= std::min<_CT>(__sz, _Np - 1);
+ return static_cast<_ST>(__sz);
+ }
+};
+
+template <forward_range _View, size_t _Np>
+ requires view<_View> && (_Np > 0)
+template <bool _Const>
+class adjacent_view<_View, _Np>::__iterator {
+ friend adjacent_view;
+ using _Base _LIBCPP_NODEBUG = __maybe_const<_Const, _View>;
+ array<iterator_t<_Base>, _Np> __current_ = array<iterator_t<_Base>, _Np>();
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator(iterator_t<_Base> __first, sentinel_t<_Base> __last) {
+ __current_[0] = __first;
+ for (int __i = 1; __i < static_cast<int>(_Np); ++__i) {
+ __current_[__i] = ranges::next(__current_[__i - 1], 1, __last);
+ }
+ }
+
+ _LIBCPP_HIDE_FROM_ABI constexpr __iterator(__as_sentinel, iterator_t<_Base> __first, iterator_t<_Base> __last) {
+ if constexpr (!bidirectional_range<_Base>) {
+ __current_.fill(__last);
----------------
huixie90 wrote:
I did try to just setting the last element and at least all my tests are still passing. Is it worth asking LWG why we need to fill the whole array?
https://github.com/llvm/llvm-project/pull/165089
More information about the libcxx-commits
mailing list