[libcxx-commits] [libcxx] 0fb1899 - [libc++] Implement structured binding for std::ranges::subrange.

Arthur O'Dwyer via libcxx-commits libcxx-commits at lists.llvm.org
Wed Aug 18 07:02:32 PDT 2021


Author: Arthur O'Dwyer
Date: 2021-08-18T10:01:45-04:00
New Revision: 0fb189952c7b326eda3edeab640d5ada644ead8b

URL: https://github.com/llvm/llvm-project/commit/0fb189952c7b326eda3edeab640d5ada644ead8b
DIFF: https://github.com/llvm/llvm-project/commit/0fb189952c7b326eda3edeab640d5ada644ead8b.diff

LOG: [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

Added: 
    libcxx/test/std/ranges/range.utility/range.subrange/access/structured_binding.pass.cpp

Modified: 
    libcxx/include/__ranges/subrange.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__ranges/subrange.h b/libcxx/include/__ranges/subrange.h
index acae70cf3cc88..e162d6b316952 100644
--- 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/
diff erent_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 =
@@ -253,17 +253,40 @@ namespace ranges {
   inline constexpr bool enable_borrowed_range<subrange<_Ip, _Sp, _Kp>> = true;
 
   template<range _Rp>
-  using borrowed_subrange_t = _If<borrowed_range<_Rp>, subrange<iterator_t<_Rp> >, dangling>;
+  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

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
index 0000000000000..ed2a166b93eca
--- /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 <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;
+}


        


More information about the libcxx-commits mailing list