forked from OSchip/llvm-project
[libc++] Implement structured binding for std::ranges::subrange.
The `get` half of this machinery was already implemented, but the `tuple_size` and `tuple_element` parts were hiding in [ranges.syn] and therefore missed. Differential Revision: https://reviews.llvm.org/D108054
This commit is contained in:
parent
38812f4ac1
commit
0fb189952c
|
@ -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 <concepts>
|
||||
#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)
|
||||
|
||||
// clang-format off
|
||||
namespace ranges {
|
||||
template<class _From, class _To>
|
||||
concept __convertible_to_non_slicing =
|
||||
|
@ -256,14 +256,37 @@ namespace ranges {
|
|||
using borrowed_subrange_t = _If<borrowed_range<_Rp>, subrange<iterator_t<_Rp>>, dangling>;
|
||||
} // namespace ranges
|
||||
|
||||
// [range.subrange.general]
|
||||
|
||||
using ranges::get;
|
||||
|
||||
// clang-format off
|
||||
// [ranges.syn]
|
||||
|
||||
template<class _Ip, class _Sp, ranges::subrange_kind _Kp>
|
||||
struct tuple_size<ranges::subrange<_Ip, _Sp, _Kp>> : integral_constant<size_t, 2> {};
|
||||
|
||||
template<class _Ip, class _Sp, ranges::subrange_kind _Kp>
|
||||
struct tuple_element<0, ranges::subrange<_Ip, _Sp, _Kp>> {
|
||||
using type = _Ip;
|
||||
};
|
||||
|
||||
template<class _Ip, class _Sp, ranges::subrange_kind _Kp>
|
||||
struct tuple_element<1, ranges::subrange<_Ip, _Sp, _Kp>> {
|
||||
using type = _Sp;
|
||||
};
|
||||
|
||||
template<class _Ip, class _Sp, ranges::subrange_kind _Kp>
|
||||
struct tuple_element<0, const ranges::subrange<_Ip, _Sp, _Kp>> {
|
||||
using type = _Ip;
|
||||
};
|
||||
|
||||
template<class _Ip, class _Sp, ranges::subrange_kind _Kp>
|
||||
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
|
||||
|
|
|
@ -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 <ranges>
|
||||
|
||||
#include <cassert>
|
||||
#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<decltype(r)>);
|
||||
{
|
||||
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<decltype(r)>);
|
||||
{
|
||||
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;
|
||||
}
|
Loading…
Reference in New Issue