[libcxx][ranges] Add `ranges::common_view`.

Differential Revision: https://reviews.llvm.org/D105753

NOKEYCHECK=True
GitOrigin-RevId: e5d8b93e5a25072ec27260e162f5a036a2c32dc2
diff --git a/include/CMakeLists.txt b/include/CMakeLists.txt
index fc095df..dd4b812 100644
--- a/include/CMakeLists.txt
+++ b/include/CMakeLists.txt
@@ -184,6 +184,7 @@
   __random/uniform_int_distribution.h
   __ranges/access.h
   __ranges/all.h
+  __ranges/common_view.h
   __ranges/concepts.h
   __ranges/copyable_box.h
   __ranges/dangling.h
diff --git a/include/__ranges/common_view.h b/include/__ranges/common_view.h
new file mode 100644
index 0000000..dab8260
--- /dev/null
+++ b/include/__ranges/common_view.h
@@ -0,0 +1,113 @@
+// -*- 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_COMMON_VIEW_H
+#define _LIBCPP___RANGES_COMMON_VIEW_H
+
+#include <__config>
+#include <__iterator/common_iterator.h>
+#include <__iterator/iterator_traits.h>
+#include <__ranges/access.h>
+#include <__ranges/all.h>
+#include <__ranges/concepts.h>
+#include <__ranges/enable_borrowed_range.h>
+#include <__ranges/size.h>
+#include <__ranges/view_interface.h>
+#include <concepts>
+#include <type_traits>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+#pragma GCC system_header
+#endif
+
+_LIBCPP_PUSH_MACROS
+#include <__undef_macros>
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+#if !defined(_LIBCPP_HAS_NO_RANGES)
+
+namespace ranges {
+
+template<view _View>
+  requires (!common_range<_View> && copyable<iterator_t<_View>>)
+class common_view : public view_interface<common_view<_View>> {
+  _View __base_ = _View();
+
+public:
+  _LIBCPP_HIDE_FROM_ABI
+  common_view() requires default_initializable<_View> = default;
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr explicit common_view(_View __v) : __base_(_VSTD::move(__v)) { }
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr _View base() const& requires copy_constructible<_View> { return __base_; }
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr _View base() && { return _VSTD::move(__base_); }
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr auto begin() {
+    if constexpr (random_access_range<_View> && sized_range<_View>)
+      return ranges::begin(__base_);
+    else
+      return common_iterator<iterator_t<_View>, sentinel_t<_View>>(ranges::begin(__base_));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr auto begin() const requires range<const _View> {
+    if constexpr (random_access_range<const _View> && sized_range<const _View>)
+      return ranges::begin(__base_);
+    else
+      return common_iterator<iterator_t<const _View>, sentinel_t<const _View>>(ranges::begin(__base_));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr auto end() {
+    if constexpr (random_access_range<_View> && sized_range<_View>)
+      return ranges::begin(__base_) + ranges::size(__base_);
+    else
+      return common_iterator<iterator_t<_View>, sentinel_t<_View>>(ranges::end(__base_));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr auto end() const requires range<const _View> {
+    if constexpr (random_access_range<const _View> && sized_range<const _View>)
+      return ranges::begin(__base_) + ranges::size(__base_);
+    else
+      return common_iterator<iterator_t<const _View>, sentinel_t<const _View>>(ranges::end(__base_));
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr auto size() requires sized_range<_View> {
+    return ranges::size(__base_);
+  }
+
+  _LIBCPP_HIDE_FROM_ABI
+  constexpr auto size() const requires sized_range<const _View> {
+    return ranges::size(__base_);
+  }
+};
+
+template<class _Range>
+common_view(_Range&&)
+  -> common_view<views::all_t<_Range>>;
+
+template<class _View>
+inline constexpr bool enable_borrowed_range<common_view<_View>> = enable_borrowed_range<_View>;
+
+} // namespace ranges
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_COMMON_VIEW_H
diff --git a/include/module.modulemap b/include/module.modulemap
index 982002e..11cabad 100644
--- a/include/module.modulemap
+++ b/include/module.modulemap
@@ -613,6 +613,7 @@
     module __ranges {
       module access                 { private header "__ranges/access.h"                }
       module all                    { private header "__ranges/all.h"                   }
+      module common_view            { private header "__ranges/common_view.h"           }
       module concepts               { private header "__ranges/concepts.h"              }
       module copyable_box           { private header "__ranges/copyable_box.h"          }
       module dangling               { private header "__ranges/dangling.h"              }
diff --git a/include/ranges b/include/ranges
index 45825fd..ff78973 100644
--- a/include/ranges
+++ b/include/ranges
@@ -146,6 +146,13 @@
              can-reference<invoke_result_t<F&, range_reference_t<V>>>
   class transform_view;
 
+  // [range.common], common view
+  template<view V>
+    requires (!common_range<V> && copyable<iterator_t<V>>)
+  class common_view;
+
+  template<class T>
+  inline constexpr bool enable_borrowed_range<common_view<T>> = enable_borrowed_range<T>;
 }
 
 */
@@ -153,6 +160,7 @@
 #include <__config>
 #include <__ranges/access.h>
 #include <__ranges/all.h>
+#include <__ranges/common_view.h>
 #include <__ranges/concepts.h>
 #include <__ranges/dangling.h>
 #include <__ranges/data.h>