diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -188,6 +188,7 @@ __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 --- /dev/null +++ b/libcxx/include/__ranges/counted.h @@ -0,0 +1,87 @@ +// -*- 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/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 +#include + +#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 { + struct __fn { + template + requires contiguous_iterator> + _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t, iter_difference_t<_Tp> __c) const + noexcept(noexcept( + span(_VSTD::to_address(_VSTD::forward<_Tp>(__t)), static_cast>(__c)) + )) + { + return span(_VSTD::to_address(_VSTD::forward<_Tp>(__t)), static_cast>(__c)); + } + + template + requires random_access_iterator> + _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t, iter_difference_t<_Tp> __c) const + noexcept( + noexcept(__t + static_cast>(__c)) && + noexcept(ranges::subrange(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Tp>(__t))) + ) + { + auto __sent = __t + static_cast>(__c); + return ranges::subrange(_VSTD::forward<_Tp>(__t), _VSTD::forward<_Tp>(__sent)); + } + + template + _LIBCPP_HIDE_FROM_ABI + constexpr auto operator()(_Tp&& __t, iter_difference_t<_Tp> __c) const + noexcept(noexcept( + ranges::subrange(counted_iterator(_VSTD::forward<_Tp>(__t), __c), default_sentinel) + )) + { + return ranges::subrange(counted_iterator(_VSTD::forward<_Tp>(__t), __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/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -164,6 +164,7 @@ #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/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 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.counted/counted.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// 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 +#include + +#include +#include "test_macros.h" +#include "test_iterators.h" + +constexpr bool test() { + int buffer[8] = {1, 2, 3, 4, 5, 6, 7, 8}; + + { + { + contiguous_iterator iter(buffer); + std::span s = std::views::counted(iter, 8); + assert(s.size() == 8); + assert(s.data() == buffer); + } + { + const contiguous_iterator iter(buffer); + std::span s = std::views::counted(iter, 8); + assert(s.size() == 8); + assert(s.data() == buffer); + } + } + + { + { + random_access_iterator iter(buffer); + std::ranges::subrange> s = std::views::counted(iter, 8); + assert(s.size() == 8); + assert(s.begin() == iter); + } + { + const random_access_iterator iter(buffer); + std::ranges::subrange> s = std::views::counted(iter, 8); + assert(s.size() == 8); + assert(s.begin() == iter); + } + } + + { + { + bidirectional_iterator iter(buffer); + std::ranges::subrange< + std::counted_iterator>, + std::default_sentinel_t> s = std::views::counted(iter, 8); + assert(s.size() == 8); + assert(s.begin() == std::counted_iterator(iter, 8)); + } + { + const bidirectional_iterator iter(buffer); + std::ranges::subrange< + std::counted_iterator>, + std::default_sentinel_t> s = std::views::counted(iter, 8); + assert(s.size() == 8); + assert(s.begin() == std::counted_iterator(iter, 8)); + } + } + + return true; +} + +int main(int, char**) { + test(); + static_assert(test()); + + return 0; +}