diff --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h --- a/libcxx/include/__ranges/subrange.h +++ b/libcxx/include/__ranges/subrange.h @@ -9,6 +9,11 @@ #ifndef _LIBCPP___RANGES_SUBRANGE_H #define _LIBCPP___RANGES_SUBRANGE_H +#include <__concepts/constructible.h> +#include <__concepts/convertible_to.h> +#include <__concepts/copyable.h> +#include <__concepts/derived_from.h> +#include <__concepts/different_from.h> #include <__config> #include <__iterator/concepts.h> #include <__iterator/incrementable_traits.h> @@ -22,21 +27,16 @@ #include <__ranges/view_interface.h> #include <__tuple> #include <__utility/move.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) -// clang-format off namespace ranges { template concept __convertible_to_non_slicing = @@ -253,17 +253,40 @@ inline constexpr bool enable_borrowed_range> = true; template - using borrowed_subrange_t = _If, subrange >, dangling>; + using borrowed_subrange_t = _If, subrange>, dangling>; } // namespace ranges +// [range.subrange.general] + using ranges::get; -// clang-format off +// [ranges.syn] + +template +struct tuple_size> : integral_constant {}; + +template +struct tuple_element<0, ranges::subrange<_Ip, _Sp, _Kp>> { + using type = _Ip; +}; + +template +struct tuple_element<1, ranges::subrange<_Ip, _Sp, _Kp>> { + using type = _Sp; +}; + +template +struct tuple_element<0, const ranges::subrange<_Ip, _Sp, _Kp>> { + using type = _Ip; +}; + +template +struct tuple_element<1, const ranges::subrange<_Ip, _Sp, _Kp>> { + using type = _Sp; +}; #endif // !defined(_LIBCPP_HAS_NO_RANGES) _LIBCPP_END_NAMESPACE_STD -_LIBCPP_POP_MACROS - #endif // _LIBCPP___RANGES_SUBRANGE_H diff --git a/libcxx/test/std/ranges/range.utility/range.subrange/access/structured_binding.pass.cpp b/libcxx/test/std/ranges/range.utility/range.subrange/access/structured_binding.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.subrange/access/structured_binding.pass.cpp @@ -0,0 +1,113 @@ +//===----------------------------------------------------------------------===// +// +// 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: libcpp-has-no-incomplete-ranges + +// class std::ranges::subrange; + +#include + +#include +#include "test_macros.h" + +constexpr void test_sized_subrange() +{ + int a[4] = {1,2,3,4}; + auto r = std::ranges::subrange(a, a+4); + assert(std::ranges::sized_range); + { + auto [first, last] = r; + assert(first == a); + assert(last == a+4); + } + { + auto [first, last] = std::move(r); + assert(first == a); + assert(last == a+4); + } + { + auto [first, last] = std::as_const(r); + assert(first == a); + assert(last == a+4); + } + { + auto [first, last] = std::move(std::as_const(r)); + assert(first == a); + assert(last == a+4); + } +} + +constexpr void test_unsized_subrange() +{ + int a[4] = {1,2,3,4}; + auto r = std::ranges::subrange(a, std::unreachable_sentinel); + assert(!std::ranges::sized_range); + { + auto [first, last] = r; + assert(first == a); + ASSERT_SAME_TYPE(decltype(last), std::unreachable_sentinel_t); + } + { + auto [first, last] = std::move(r); + assert(first == a); + ASSERT_SAME_TYPE(decltype(last), std::unreachable_sentinel_t); + } + { + auto [first, last] = std::as_const(r); + assert(first == a); + ASSERT_SAME_TYPE(decltype(last), std::unreachable_sentinel_t); + } + { + auto [first, last] = std::move(std::as_const(r)); + assert(first == a); + ASSERT_SAME_TYPE(decltype(last), std::unreachable_sentinel_t); + } +} + +constexpr void test_copies_not_originals() +{ + int a[4] = {1,2,3,4}; + { + auto r = std::ranges::subrange(a, a+4); + auto&& [first, last] = r; + ASSERT_SAME_TYPE(decltype(first), int*); + ASSERT_SAME_TYPE(decltype(last), int*); + first = a+2; + last = a+2; + assert(r.begin() == a); + assert(r.end() == a+4); + } + { + const auto r = std::ranges::subrange(a, a+4); + auto&& [first, last] = r; + ASSERT_SAME_TYPE(decltype(first), int*); + ASSERT_SAME_TYPE(decltype(last), int*); + first = a+2; + last = a+2; + assert(r.begin() == a); + assert(r.end() == a+4); + } +} + +constexpr bool test() +{ + test_sized_subrange(); + test_unsized_subrange(); + test_copies_not_originals(); + return true; +} + +int main(int, char**) +{ + test(); + static_assert(test()); + + return 0; +}