[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