[libcxx-commits] [libcxx] f9e58f3 - [libcxx][ranges] Add `views::counted` CPO.

via libcxx-commits libcxx-commits at lists.llvm.org
Tue Aug 10 16:42:36 PDT 2021


Author: zoecarver
Date: 2021-08-10T16:42:28-07:00
New Revision: f9e58f35e905c457ac81e951f22e3b2de3a7dc45

URL: https://github.com/llvm/llvm-project/commit/f9e58f35e905c457ac81e951f22e3b2de3a7dc45
DIFF: https://github.com/llvm/llvm-project/commit/f9e58f35e905c457ac81e951f22e3b2de3a7dc45.diff

LOG: [libcxx][ranges] Add `views::counted` CPO.

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

Added: 
    libcxx/include/__ranges/counted.h
    libcxx/test/libcxx/diagnostics/detail.headers/ranges/counted.module.verify.cpp
    libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp

Modified: 
    libcxx/docs/Status/RangesPaper.csv
    libcxx/include/CMakeLists.txt
    libcxx/include/module.modulemap
    libcxx/include/ranges

Removed: 
    


################################################################################
diff  --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index daa7668166096..e174cda1a7ca2 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -144,6 +144,6 @@ Section,Description,Dependencies,Assignee,Complete
 `[range.empty] <http://wg21.link/range.empty>`_,`empty_view <https://llvm.org/D103208>`_,[view.interface],Zoe Carver,✅
 `[range.single] <http://wg21.link/range.single>`_,single_view,[view.interface],Zoe Carver,✅
 `[range.split] <http://wg21.link/range.split>`_,split_view,[range.all],Zoe Carver,In Progress
-`[range.counted] <http://wg21.link/range.counted>`_,view::counted,[range.subrange],Zoe Carver,Not started
+`[range.counted] <http://wg21.link/range.counted>`_,view::counted,[range.subrange],Zoe Carver,✅
 `[range.common] <http://wg21.link/range.common>`_,common_view,[range.all],Zoe Carver,✅
 `[range.reverse] <http://wg21.link/range.reverse>`_,reverse_view,[range.all],Zoe Carver,✅

diff  --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 765c193339127..b063272c44212 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -190,6 +190,7 @@ set(files
   __ranges/common_view.h
   __ranges/concepts.h
   __ranges/copyable_box.h
+  __ranges/counted.h
   __ranges/dangling.h
   __ranges/data.h
   __ranges/drop_view.h

diff  --git a/libcxx/include/__ranges/counted.h b/libcxx/include/__ranges/counted.h
new file mode 100644
index 0000000000000..d891c1f4efac4
--- /dev/null
+++ b/libcxx/include/__ranges/counted.h
@@ -0,0 +1,99 @@
+// -*- 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_COUNTED_H
+#define _LIBCPP___RANGES_COUNTED_H
+
+#include <__config>
+#include <__iterator/concepts.h>
+#include <__iterator/counted_iterator.h>
+#include <__iterator/default_sentinel.h>
+#include <__iterator/incrementable_traits.h>
+#include <__iterator/iterator_traits.h>
+#include <__memory/pointer_traits.h>
+#include <__ranges/concepts.h>
+#include <__ranges/subrange.h>
+#include <__utility/__decay_copy.h>
+#include <__utility/declval.h>
+#include <__utility/forward.h>
+#include <__utility/move.h>
+#include <span>
+#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 views {
+
+namespace __counted {
+  template<class _From, class _To>
+  concept __explicitly_convertible = requires {
+    _To(_From{});
+  };
+
+  struct __fn {
+    template<class _Iter, class _Diff>
+      requires contiguous_iterator<decay_t<_Iter>> &&
+               __explicitly_convertible<_Diff, iter_
diff erence_t<_Iter>>
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr auto operator()(_Iter&& __it, _Diff __c) const
+      noexcept(noexcept(
+        span(_VSTD::to_address(__it), static_cast<iter_
diff erence_t<_Iter>>(__c))
+      ))
+    {
+      return span(_VSTD::to_address(__it), static_cast<iter_
diff erence_t<_Iter>>(__c));
+    }
+
+    template<class _Iter, class _Diff>
+      requires random_access_iterator<decay_t<_Iter>> &&
+               __explicitly_convertible<_Diff, iter_
diff erence_t<_Iter>>
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr auto operator()(_Iter&& __it, _Diff __c) const
+      noexcept(
+        noexcept(__it + static_cast<iter_
diff erence_t<_Iter>>(__c)) &&
+        noexcept(ranges::subrange(_VSTD::forward<_Iter>(__it), _VSTD::__decay_copy(__it)))
+      )
+    {
+      auto __last = __it + static_cast<iter_
diff erence_t<_Iter>>(__c);
+      return ranges::subrange(_VSTD::forward<_Iter>(__it), _VSTD::move(__last));
+    }
+
+    template<class _Iter, class _Diff>
+      requires __explicitly_convertible<_Diff, iter_
diff erence_t<_Iter>>
+    _LIBCPP_HIDE_FROM_ABI
+    constexpr auto operator()(_Iter&& __it, _Diff __c) const
+      noexcept(noexcept(
+        ranges::subrange(counted_iterator(_VSTD::forward<_Iter>(__it), __c), default_sentinel)
+      ))
+    {
+      return ranges::subrange(counted_iterator(_VSTD::forward<_Iter>(__it), __c), default_sentinel);
+    }
+  };
+}
+
+inline namespace __cpo {
+  inline constexpr auto counted = __counted::__fn{};
+} // namespace __cpo
+
+} // namespace views
+
+#endif // !defined(_LIBCPP_HAS_NO_RANGES)
+
+_LIBCPP_END_NAMESPACE_STD
+
+_LIBCPP_POP_MACROS
+
+#endif // _LIBCPP___RANGES_COUNTED_H

diff  --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 7f8c3bcc9d707..e07709d6e794e 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -622,6 +622,7 @@ module std [system] {
       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 counted                { private header "__ranges/counted.h"               }
       module dangling               { private header "__ranges/dangling.h"              }
       module data                   { private header "__ranges/data.h"                  }
       module drop_view              { private header "__ranges/drop_view.h"             }

diff  --git a/libcxx/include/ranges b/libcxx/include/ranges
index a2243138531cc..1ca3ea537c4cc 100644
--- a/libcxx/include/ranges
+++ b/libcxx/include/ranges
@@ -149,6 +149,9 @@ namespace std::ranges {
              can-reference<invoke_result_t<F&, range_reference_t<V>>>
   class transform_view;
 
+  // [range.counted], counted view
+  namespace views { inline constexpr unspecified counted = unspecified; }
+
   // [range.common], common view
   template<view V>
     requires (!common_range<V> && copyable<iterator_t<V>>)
@@ -187,6 +190,7 @@ namespace std::ranges {
 #include <__ranges/access.h>
 #include <__ranges/all.h>
 #include <__ranges/common_view.h>
+#include <__ranges/counted.h>
 #include <__ranges/concepts.h>
 #include <__ranges/dangling.h>
 #include <__ranges/data.h>

diff  --git a/libcxx/test/libcxx/diagnostics/detail.headers/ranges/counted.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/counted.module.verify.cpp
new file mode 100644
index 0000000000000..748706b818204
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/ranges/counted.module.verify.cpp
@@ -0,0 +1,16 @@
+// -*- 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__ranges/counted.h'}}
+#include <__ranges/counted.h>

diff  --git a/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp
new file mode 100644
index 0000000000000..9664620ac9f89
--- /dev/null
+++ b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp
@@ -0,0 +1,207 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+// UNSUPPORTED: libcpp-no-concepts
+// UNSUPPORTED: gcc-10
+// UNSUPPORTED: libcpp-has-no-incomplete-ranges
+
+// std::views::counted;
+
+#include <concepts>
+#include <ranges>
+#include <span>
+
+#include <cassert>
+#include "test_macros.h"
+#include "test_iterators.h"
+
+struct Unrelated {};
+
+struct ConvertibleToSize {
+  constexpr operator std::ptr
diff _t() const { return 8; }
+};
+
+struct ImplicitlyConvertible {
+    operator short();
+    explicit operator std::ptr
diff _t() = delete;
+};
+
+template<class Iter, class T>
+concept CountedInvocable = requires(Iter& i, T t) { std::views::counted(i, t); };
+
+constexpr bool test() {
+  int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8};
+
+  {
+    static_assert( CountedInvocable<contiguous_iterator<int*>, ConvertibleToSize>);
+    static_assert(!CountedInvocable<contiguous_iterator<int*>, ImplicitlyConvertible>);
+    static_assert(!CountedInvocable<contiguous_iterator<int*>, Unrelated>);
+
+    static_assert(std::semiregular<std::remove_const_t<decltype(std::views::counted)>>);
+  }
+
+  {
+    {
+      contiguous_iterator<int*> iter(buffer);
+      std::span<int> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.data() == buffer);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::span<int>);
+    }
+    {
+      const contiguous_iterator<int*> iter(buffer);
+      std::span<int> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.data() == buffer);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::span<int>);
+    }
+    {
+      contiguous_iterator<const int*> iter(buffer);
+      std::span<const int> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.data() == buffer);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::span<const int>);
+    }
+    {
+      const contiguous_iterator<const int*> iter(buffer);
+      std::span<const int> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.data() == buffer);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::span<const int>);
+    }
+  }
+
+  {
+    {
+      random_access_iterator<int*> iter(buffer);
+      std::ranges::subrange<random_access_iterator<int*>> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.begin() == iter);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::ranges::subrange<random_access_iterator<int*>>);
+    }
+    {
+      const random_access_iterator<int*> iter(buffer);
+      std::ranges::subrange<random_access_iterator<int*>> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.begin() == iter);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::ranges::subrange<random_access_iterator<int*>>);
+    }
+    {
+      random_access_iterator<const int*> iter(buffer);
+      std::ranges::subrange<random_access_iterator<const int*>> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.begin() == iter);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::ranges::subrange<random_access_iterator<const int*>>);
+    }
+    {
+      const random_access_iterator<const int*> iter(buffer);
+      std::ranges::subrange<random_access_iterator<const int*>> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.begin() == iter);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)), std::ranges::subrange<random_access_iterator<const int*>>);
+    }
+  }
+
+  {
+    {
+      bidirectional_iterator<int*> iter(buffer);
+      std::ranges::subrange<
+        std::counted_iterator<bidirectional_iterator<int*>>,
+        std::default_sentinel_t> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.begin() == std::counted_iterator(iter, 8));
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)),
+                       std::ranges::subrange<
+                         std::counted_iterator<bidirectional_iterator<int*>>,
+                         std::default_sentinel_t>);
+    }
+    {
+      const bidirectional_iterator<int*> iter(buffer);
+      std::ranges::subrange<
+        std::counted_iterator<bidirectional_iterator<int*>>,
+        std::default_sentinel_t> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.begin() == std::counted_iterator(iter, 8));
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)),
+                       std::ranges::subrange<
+                         std::counted_iterator<bidirectional_iterator<int*>>,
+                         std::default_sentinel_t>);
+    }
+    {
+      output_iterator<const int*> iter(buffer);
+      std::ranges::subrange<
+        std::counted_iterator<output_iterator<const int*>>,
+        std::default_sentinel_t> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.begin() == std::counted_iterator(iter, 8));
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)),
+                       std::ranges::subrange<
+                         std::counted_iterator<output_iterator<const int*>>,
+                         std::default_sentinel_t>);
+    }
+    {
+      const output_iterator<const int*> iter(buffer);
+      std::ranges::subrange<
+        std::counted_iterator<output_iterator<const int*>>,
+        std::default_sentinel_t> s = std::views::counted(iter, 8);
+      assert(s.size() == 8);
+      assert(s.begin() == std::counted_iterator(iter, 8));
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(iter, 8)),
+                       std::ranges::subrange<
+                         std::counted_iterator<output_iterator<const int*>>,
+                         std::default_sentinel_t>);
+    }
+    {
+      cpp20_input_iterator<int*> iter(buffer);
+      std::ranges::subrange<
+        std::counted_iterator<cpp20_input_iterator<int*>>,
+        std::default_sentinel_t> s = std::views::counted(std::move(iter), 8);
+      assert(s.size() == 8);
+      assert(s.begin().base().base() == buffer);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(std::move(iter), 8)),
+                       std::ranges::subrange<
+                         std::counted_iterator<cpp20_input_iterator<int*>>,
+                         std::default_sentinel_t>);
+    }
+    {
+      std::ranges::subrange<
+        std::counted_iterator<cpp20_input_iterator<int*>>,
+        std::default_sentinel_t> s = std::views::counted(cpp20_input_iterator<int*>(buffer), 8);
+      assert(s.size() == 8);
+      assert(s.begin().base().base() == buffer);
+
+      ASSERT_SAME_TYPE(decltype(std::views::counted(cpp20_input_iterator<int*>(buffer), 8)),
+                       std::ranges::subrange<
+                         std::counted_iterator<cpp20_input_iterator<int*>>,
+                         std::default_sentinel_t>);
+    }
+  }
+
+  return true;
+}
+
+int main(int, char**) {
+  test();
+  static_assert(test());
+
+  return 0;
+}


        


More information about the libcxx-commits mailing list