diff --git a/libcxx/docs/Status/ZipProjects.csv b/libcxx/docs/Status/ZipProjects.csv --- a/libcxx/docs/Status/ZipProjects.csv +++ b/libcxx/docs/Status/ZipProjects.csv @@ -8,9 +8,9 @@ | `[vector.bool] `_, "[vector::reference] add const operator= overload", None, Nikolas Klauser, |Not Started| | `[iterator.concept.winc] `_, "Update weakly_comparable", None, Unassigned, |Not Started| | `[range.zip] `_, "zip_view", "| `zip_view::iterator` -| `zip_view::sentinel`", Unassigned, |Not Started| -| `[range.zip.iterator] `_, "zip_view::iterator", None, Unassigned, |Not Started| -| `[range.zip.sentinel] `_, "zip_view::sentinel", None, Unassigned, |Not Started| +| `zip_view::sentinel`", Hui Xie, |In Progress| +| `[range.zip.iterator] `_, "zip_view::iterator", None, Hui Xie, |In Progress| +| `[range.zip.sentinel] `_, "zip_view::sentinel", None, Hui Xie, |In Progress| | `[range.zip.transform.view] `_, "zip_transform_view", "| `zip_transform_view::iterator` | `zip_transform_view::sentinel`", Unassigned, |Not Started| | `[range.zip.transform.iterator] `_, "zip_transform_view::iterator", None, Unassigned, |Not Started| diff --git a/libcxx/include/__ranges/zip_view.h b/libcxx/include/__ranges/zip_view.h --- a/libcxx/include/__ranges/zip_view.h +++ b/libcxx/include/__ranges/zip_view.h @@ -17,14 +17,15 @@ #include <__iterator/iter_swap.h> #include <__ranges/access.h> #include <__ranges/all.h> -#include <__ranges/empty_view.h> #include <__ranges/concepts.h> +#include <__ranges/empty_view.h> +#include <__ranges/enable_borrowed_range.h> #include <__ranges/view_interface.h> #include <__tuple> #include #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) -#pragma GCC system_header +# pragma GCC system_header #endif _LIBCPP_BEGIN_NAMESPACE_STD @@ -33,87 +34,88 @@ namespace ranges { -template -concept __zip_is_common = (sizeof...(_Rs) == 1 && (common_range<_Rs> && ...)) || - (!(bidirectional_range<_Rs> && ...) && (common_range<_Rs> && ...)) || - ((random_access_range<_Rs> && ...) && (sized_range<_Rs> && ...)); +template +concept __zip_is_common = (sizeof...(_Ranges) == 1 && (common_range<_Ranges> && ...)) || + (!(bidirectional_range<_Ranges> && ...) && (common_range<_Ranges> && ...)) || + ((random_access_range<_Ranges> && ...) && (sized_range<_Ranges> && ...)); -template -auto __tuple_or_pair_test() -> pair<_T, _U>; +template +auto __tuple_or_pair_test() -> pair<_Tp, _Up>; -template -requires(sizeof...(_Ts) != 2) auto __tuple_or_pair_test() -> tuple<_Ts...>; +template requires(sizeof...(_Ts) != 2) +auto __tuple_or_pair_test() -> tuple<_Ts...>; template using __tuple_or_pair = decltype(__tuple_or_pair_test<_Ts...>()); -template -_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_transform(_F&& __f, _Tuple&& __tuple) { +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_transform(_Fun&& __f, _Tuple&& __tuple) { return apply( [&](_Ts&&... __elements) { - return __tuple_or_pair...>( - invoke(__f, static_cast<_Ts&&>(__elements))...); + return __tuple_or_pair...>( + std::invoke(__f, std::forward<_Ts>(__elements))...); }, - static_cast<_Tuple&&>(__tuple)); + std::forward<_Tuple>(__tuple)); } -template -_LIBCPP_HIDE_FROM_ABI constexpr void __tuple_for_each(_F&& __f, _Tuple&& __tuple) { +template +_LIBCPP_HIDE_FROM_ABI constexpr void __tuple_for_each(_Fun&& __f, _Tuple&& __tuple) { apply([&]( - _Ts&&... __elements) { (invoke(__f, static_cast<_Ts&&>(__elements)), ...); }, - static_cast<_Tuple&&>(__tuple)); + _Ts&&... __elements) { (std::invoke(__f, std::forward<_Ts>(__elements)), ...); }, + std::forward<_Tuple>(__tuple)); } -template -_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_zip_transform(_F&& __f, +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_zip_transform(_Fun&& __f, _Tuple1&& __tuple1, _Tuple2&& __tuple2, index_sequence) { return __tuple_or_pair< - invoke_result_t<_F&, typename tuple_element>::type, + invoke_result_t<_Fun&, typename tuple_element>::type, typename tuple_element>::type>...>{ - invoke(__f, get(static_cast<_Tuple1&&>(__tuple1)), - get(static_cast<_Tuple2&&>(__tuple2)))...}; + std::invoke(__f, std::get(std::forward<_Tuple1>(__tuple1)), + std::get(std::forward<_Tuple2>(__tuple2)))...}; } -template -_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_zip_transform(_F&& __f, +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_zip_transform(_Fun&& __f, _Tuple1&& __tuple1, _Tuple2&& __tuple2) { - return __tuple_zip_transform(__f, static_cast<_Tuple1&&>(__tuple1), - static_cast<_Tuple2&&>(__tuple2), + return __tuple_zip_transform(__f, std::forward<_Tuple1>(__tuple1), + std::forward<_Tuple2>(__tuple2), make_index_sequence>::value>()); } -template -_LIBCPP_HIDE_FROM_ABI constexpr void __tuple_zip_for_each(_F&& __f, +template +_LIBCPP_HIDE_FROM_ABI constexpr void __tuple_zip_for_each(_Fun&& __f, _Tuple1&& __tuple1, _Tuple2&& __tuple2, index_sequence) { - (invoke(__f, get(static_cast<_Tuple1&&>(__tuple1)), - get(static_cast<_Tuple2&&>(__tuple2))), + (std::invoke(__f, std::get(std::forward<_Tuple1>(__tuple1)), + std::get(std::forward<_Tuple2>(__tuple2))), ...); } -template -_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_zip_for_each(_F&& __f, +template +_LIBCPP_HIDE_FROM_ABI constexpr auto __tuple_zip_for_each(_Fun&& __f, _Tuple1&& __tuple1, _Tuple2&& __tuple2) { - return __tuple_zip_for_each(__f, static_cast<_Tuple1&&>(__tuple1), - static_cast<_Tuple2&&>(__tuple2), + return __tuple_zip_for_each(__f, std::forward<_Tuple1>(__tuple1), + std::forward<_Tuple2>(__tuple2), make_index_sequence>::value>()); } // abs in cstdlib is not constexpr +// TODO : remove __abs once P0533R9 is implemented. template _LIBCPP_HIDE_FROM_ABI constexpr auto __abs(_T t) { return t < 0 ? -t : t; } template - requires(view<_Views>&&...) && (sizeof...(_Views) > 0) class zip_view - : public view_interface> { + requires(view<_Views>&&...) && (sizeof...(_Views) > 0) +class zip_view : public view_interface> { tuple<_Views...> __views_; @@ -168,7 +170,7 @@ return apply( [](auto... sizes) { using CT = make_unsigned_t>; - return min({CT(sizes)...}); + return std::min({CT(sizes)...}); }, __tuple_transform(ranges::size, __views_)); } @@ -178,7 +180,7 @@ return apply( [](auto... sizes) { using CT = make_unsigned_t>; - return min({CT(sizes)...}); + return std::min({CT(sizes)...}); }, __tuple_transform(ranges::size, __views_)); } @@ -220,8 +222,8 @@ template requires(view<_Views>&&...) && (sizeof...(_Views) > 0) // - template - class zip_view<_Views...>::__iterator +template +class zip_view<_Views...>::__iterator : public __zip_view_iterator_category_base<_Const, _Views...> { __tuple_or_pair>...> __current_; @@ -386,7 +388,7 @@ const auto __diffs = __tuple_zip_transform(std::minus<>(), __x.__current_, __y.__current_); return apply( [](auto... ds) { - return min({difference_type(ds)...}, + return std::min({difference_type(ds)...}, [](auto x, auto y) { return __abs(x) < __abs(y); }); }, __diffs); @@ -412,8 +414,8 @@ template requires(view<_Views>&&...) && (sizeof...(_Views) > 0) // - template - class zip_view<_Views...>::__sentinel { +template +class zip_view<_Views...>::__sentinel { __tuple_or_pair>...> __end_; @@ -459,7 +461,7 @@ return apply( [](auto... ds) { using D = common_type_t>...>; - return min({D(ds)...}, [](auto x, auto y) { return __abs(x) < __abs(y); }); + return std::min({D(ds)...}, [](auto x, auto y) { return __abs(x) < __abs(y); }); }, __diffs); } @@ -474,6 +476,11 @@ } }; + +template +inline constexpr bool enable_borrowed_range> = + (enable_borrowed_range<_Views> && ...); + namespace views { namespace __zip { @@ -482,11 +489,11 @@ return empty_view>{}; } - template - _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Rs&&... rs) const - noexcept(noexcept(zip_view(static_cast<_Rs&&>(rs)...))) - -> decltype(zip_view(static_cast<_Rs&&>(rs)...)) { - return zip_view(static_cast<_Rs&&>(rs)...); + template + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Ranges&&... rs) const + noexcept(noexcept(zip_view(std::forward<_Ranges>(rs)...))) + -> decltype(zip_view(std::forward<_Ranges>(rs)...)) { + return zip_view(std::forward<_Ranges>(rs)...); } }; diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -848,7 +848,7 @@ } module view_interface { private header "__ranges/view_interface.h" } module views { private header "__ranges/views.h" } - module zip { private header "__ranges/zip_view.h" } + module zip_view { private header "__ranges/zip_view.h" } } } module ratio { diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -196,6 +196,17 @@ template requires view && input_range> class join_view; + + // [range.zip], zip view + template + requires (view && ...) && (sizeof...(Views) > 0) + class zip_view; + + template + inline constexpr bool enable_borrowed_range> = + (enable_borrowed_range && ...); + + namespace views { inline constexpr unspecified zip = unspecified; } } namespace std { diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.zip/begin.pass.cpp @@ -50,4 +50,4 @@ int main(int, char**) { test(); static_assert(test()); -} \ No newline at end of file +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/borrowing.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/borrowing.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.adaptors/range.zip/borrowing.compile.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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, c++20 +// UNSUPPORTED: libcpp-has-no-incomplete-ranges + +// template +// inline constexpr bool enable_borrowed_range> = +// (enable_borrowed_range && ...); + +#include + +struct Borrowed : std::ranges::view_base { + int* begin() const; + int* end() const; +}; + +template <> +inline constexpr bool std::ranges::enable_borrowed_range = true; + +static_assert(std::ranges::borrowed_range); + +struct NonBorrowed : std::ranges::view_base { + int* begin() const; + int* end() const; +}; +static_assert(!std::ranges::borrowed_range); + +void testBorrowedRange() { + static_assert(std::ranges::borrowed_range>); + static_assert(std::ranges::borrowed_range>); + static_assert(!std::ranges::borrowed_range>); + static_assert(!std::ranges::borrowed_range>); + static_assert(!std::ranges::borrowed_range>); +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/ctad.compile.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/ctad.compile.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.zip/ctad.compile.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.zip/ctad.compile.pass.cpp @@ -9,8 +9,8 @@ // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 // UNSUPPORTED: libcpp-has-no-incomplete-ranges -// template -// zip_view(_Rs&&...) -> zip_view...>; +// template +// zip_view(Rs&&...) -> zip_view...>; #include #include @@ -38,4 +38,4 @@ static_assert( std::same_as, View, std::ranges::ref_view>>); -} \ No newline at end of file +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/general.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/general.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.zip/general.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.zip/general.pass.cpp @@ -35,7 +35,7 @@ { using namespace std::string_literals; std::vector v{1, 2, 3, 4}; - std::array a{"abc", "def", "gh"}; + std::array a{"abc"s, "def"s, "gh"s}; auto view = std::views::zip(v, a); auto it = view.begin(); assert(&(std::get<0>(*it)) == &(v[0])); @@ -52,4 +52,4 @@ ++it; assert(it == view.end()); } -} \ No newline at end of file +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/decrement.pass.cpp @@ -39,7 +39,9 @@ using Iter = decltype(it); ASSERT_SAME_TYPE(decltype(--it), Iter&); - --it; + auto& it_ref = --it; + assert(&it_ref == &it); + assert(&(std::get<0>(*it)) == &(a[2])); assert(&(std::get<1>(*it)) == &(b[2])); assert(std::get<2>(*it) == 2); diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp --- a/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp +++ b/libcxx/test/std/ranges/range.adaptors/range.zip/iterator/increment.pass.cpp @@ -42,7 +42,9 @@ ASSERT_SAME_TYPE(decltype(++it), Iter&); - ++it; + auto& it_ref = ++it; + assert(&it_ref == &it); + assert(&(std::get<0>(*it)) == &(a[1])); assert(&(std::get<1>(*it)) == &(b[1])); assert(std::get<2>(*it) == 1); @@ -80,4 +82,4 @@ static_assert(test()); return 0; -} \ No newline at end of file +} diff --git a/libcxx/test/std/ranges/range.adaptors/range.zip/types.h b/libcxx/test/std/ranges/range.adaptors/range.zip/types.h --- a/libcxx/test/std/ranges/range.adaptors/range.zip/types.h +++ b/libcxx/test/std/ranges/range.adaptors/range.zip/types.h @@ -1,3 +1,11 @@ +//===----------------------------------------------------------------------===// +// +// 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 TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H #define TEST_STD_RANGES_RANGE_ADAPTORS_RANGE_ZIP_TYPES_H