[libc++] Implements ranges::enable_borrowed_range

This is the initial patch to implement ranges in libc++.

Implements parts of:
- P0896R4 One Ranges Proposal
- P1870 forwarding-range is too subtle
- LWG3379 in several library names is misleading

Reviewed By: ldionne, #libc, cjdb, zoecarver, Quuxplusone

Differential Revision: https://reviews.llvm.org/D90999
This commit is contained in:
Mark de Wever 2020-11-24 18:08:02 +01:00
parent aa80ea8a61
commit 01ace074fc
18 changed files with 379 additions and 4 deletions

View File

@ -281,7 +281,7 @@
"`3374 <https://wg21.link/LWG3374>`__","P0653 + P1006 should have made the other ``std::to_address``\ overload ``constexpr``\ ","Prague","|Complete|","12.0"
"`3375 <https://wg21.link/LWG3375>`__","``decay``\ in ``viewable_range``\ should be ``remove_cvref``\ ","Prague","",""
"`3377 <https://wg21.link/LWG3377>`__","``elements_view::iterator``\ befriends a specialization of itself","Prague","",""
"`3379 <https://wg21.link/LWG3379>`__","""``safe``\ "" in several library names is misleading","Prague","",""
"`3379 <https://wg21.link/LWG3379>`__","""``safe``\ "" in several library names is misleading","Prague","|In Progress|",""
"`3380 <https://wg21.link/LWG3380>`__","``common_type``\ and comparison categories","Prague","",""
"`3381 <https://wg21.link/LWG3381>`__","``begin``\ and ``data``\ must agree for ``contiguous_range``\ ","Prague","",""
"`3382 <https://wg21.link/LWG3382>`__","NTTP for ``pair``\ and ``array``\ ","Prague","",""

1 Issue # Issue Name Meeting Status First released version
281 `3374 <https://wg21.link/LWG3374>`__ P0653 + P1006 should have made the other ``std::to_address``\ overload ``constexpr``\ Prague |Complete| 12.0
282 `3375 <https://wg21.link/LWG3375>`__ ``decay``\ in ``viewable_range``\ should be ``remove_cvref``\ Prague
283 `3377 <https://wg21.link/LWG3377>`__ ``elements_view::iterator``\ befriends a specialization of itself Prague
284 `3379 <https://wg21.link/LWG3379>`__ "``safe``\ " in several library names is misleading Prague |In Progress|
285 `3380 <https://wg21.link/LWG3380>`__ ``common_type``\ and comparison categories Prague
286 `3381 <https://wg21.link/LWG3381>`__ ``begin``\ and ``data``\ must agree for ``contiguous_range``\ Prague
287 `3382 <https://wg21.link/LWG3382>`__ NTTP for ``pair``\ and ``array``\ Prague

View File

@ -153,7 +153,7 @@
"`P1862 <https://wg21.link/P1862>`__","LWG","Ranges adaptors for non-copyable iterators","Belfast","* *",""
"`P1865 <https://wg21.link/P1865>`__","LWG","Add max() to latch and barrier","Belfast","|Complete|","11.0"
"`P1869 <https://wg21.link/P1869>`__","LWG","Rename 'condition_variable_any' interruptible wait methods","Belfast","* *",""
"`P1870 <https://wg21.link/P1870>`__","LWG","forwarding-range is too subtle","Belfast","* *",""
"`P1870 <https://wg21.link/P1870>`__","LWG","forwarding-range is too subtle","Belfast","|In Progress|",""
"`P1871 <https://wg21.link/P1871>`__","LWG","Should concepts be enabled or disabled?","Belfast","* *",""
"`P1872 <https://wg21.link/P1872>`__","LWG","span should have size_type, not index_type","Belfast","|Complete|","10.0"
"`P1878 <https://wg21.link/P1878>`__","LWG","Constraining Readable Types","Belfast","* *",""

1 Paper # Group Paper Name Meeting Status First released version
153 `P1862 <https://wg21.link/P1862>`__ LWG Ranges adaptors for non-copyable iterators Belfast * *
154 `P1865 <https://wg21.link/P1865>`__ LWG Add max() to latch and barrier Belfast |Complete| 11.0
155 `P1869 <https://wg21.link/P1869>`__ LWG Rename 'condition_variable_any' interruptible wait methods Belfast * *
156 `P1870 <https://wg21.link/P1870>`__ LWG forwarding-range is too subtle Belfast * * |In Progress|
157 `P1871 <https://wg21.link/P1871>`__ LWG Should concepts be enabled or disabled? Belfast * *
158 `P1872 <https://wg21.link/P1872>`__ LWG span should have size_type, not index_type Belfast |Complete| 10.0
159 `P1878 <https://wg21.link/P1878>`__ LWG Constraining Readable Types Belfast * *

View File

@ -30,6 +30,7 @@ set(files
__mutex_base
__node_handle
__nullptr
__ranges/enable_borrowed_range.h
__split_buffer
__sso_allocator
__std_stream
@ -141,6 +142,7 @@ set(files
ostream
queue
random
ranges
ratio
regex
scoped_allocator

View File

@ -0,0 +1,46 @@
// -*- C++ -*-
//===------------------ __ranges/enable_borrowed_range.h ------------------===//
//
// 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_ENABLE_BORROWED_RANGE_H
#define _LIBCPP___RANGES_ENABLE_BORROWED_RANGE_H
// These customization variables are used in <span> and <string_view>. The
// separate header is used to avoid including the entire <ranges> header in
// <span> and <string_view>.
#include <__config>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
namespace ranges
{
// [range.range], ranges
template <class>
inline constexpr bool enable_borrowed_range = false;
} // namespace ranges
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP___RANGES_ENABLE_BORROWED_RANGE_H

View File

@ -409,6 +409,10 @@ module std [system] {
export initializer_list
export *
}
module ranges {
header "ranges"
export *
}
module ratio {
header "ratio"
export *

52
libcxx/include/ranges Normal file
View File

@ -0,0 +1,52 @@
// -*- C++ -*-
//===--------------------------- ranges -----------------------------------===//
//
// 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
#define _LIBCPP_RANGES
/*
#include <compare> // see [compare.syn]
#include <initializer_list> // see [initializer.list.syn]
#include <iterator> // see [iterator.synopsis]
namespace std::ranges {
// [range.range], ranges
template<class T>
inline constexpr bool enable_borrowed_range = false;
}
*/
#include <__config>
#include <__ranges/enable_borrowed_range.h>
#include <compare> // Required by the standard.
#include <initializer_list> // Required by the standard.
#include <iterator> // Required by the standard.
#include <type_traits>
#include <version>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_PUSH_MACROS
#include <__undef_macros>
_LIBCPP_BEGIN_NAMESPACE_STD
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
_LIBCPP_END_NAMESPACE_STD
_LIBCPP_POP_MACROS
#endif // _LIBCPP_RANGES

View File

@ -22,6 +22,9 @@ inline constexpr size_t dynamic_extent = numeric_limits<size_t>::max();
template <class ElementType, size_t Extent = dynamic_extent>
class span;
template<class ElementType, size_t Extent>
inline constexpr bool ranges::enable_borrowed_range<span<ElementType, Extent>> = true;
// [span.objectrep], views of object representation
template <class ElementType, size_t Extent>
span<const byte, ((Extent == dynamic_extent) ? dynamic_extent :
@ -32,7 +35,6 @@ template <class ElementType, size_t Extent>
(sizeof(ElementType) * Extent))> as_writable_bytes(span<ElementType, Extent> s) noexcept;
namespace std {
template <class ElementType, size_t Extent = dynamic_extent>
class span {
public:
@ -123,6 +125,7 @@ template<class Container>
*/
#include <__config>
#include <__ranges/enable_borrowed_range.h>
#include <array> // for array
#include <cstddef> // for byte
#include <iterator> // for iterators
@ -516,6 +519,11 @@ private:
size_type __size;
};
#if !defined(_LIBCPP_HAS_NO_RANGES)
template <class _Tp, size_t _Extent>
inline constexpr bool ranges::enable_borrowed_range<span<_Tp, _Extent> > = true;
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
// as_bytes & as_writable_bytes
template <class _Tp, size_t _Extent>
_LIBCPP_INLINE_VISIBILITY

View File

@ -19,6 +19,9 @@ namespace std {
template<class charT, class traits = char_traits<charT>>
class basic_string_view;
template<class charT, class traits>
inline constexpr bool ranges::enable_borrowed_range<basic_string_view<charT, traits>> = true; // C++20
// 7.9, basic_string_view non-member comparison functions
template<class charT, class traits>
constexpr bool operator==(basic_string_view<charT, traits> x,
@ -179,6 +182,7 @@ namespace std {
*/
#include <__config>
#include <__ranges/enable_borrowed_range.h>
#include <__string>
#include <iosfwd>
#include <algorithm>
@ -649,6 +653,10 @@ private:
size_type __size;
};
#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
template <class _CharT, class _Traits>
inline constexpr bool ranges::enable_borrowed_range<basic_string_view<_CharT, _Traits> > = true;
#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES)
// [string.view.comparison]
// operator ==

View File

@ -143,6 +143,7 @@
#endif
#include <queue>
#include <random>
#include <ranges>
#include <ratio>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
# include <regex>

View File

@ -0,0 +1,34 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// WARNING: This test was generated by generate_header_inclusion_tests.py
// and should not be edited manually.
//
// clang-format off
// UNSUPPORTED: c++03, c++11, c++14, c++17
// <ranges>
// Test that <ranges> includes all the other headers it's supposed to.
#include <ranges>
#include "test_macros.h"
#if !defined(_LIBCPP_RANGES)
# error "<ranges> was expected to define _LIBCPP_RANGES"
#endif
#if TEST_STD_VER > 17 && !defined(_LIBCPP_COMPARE)
# error "<ranges> should include <compare> in C++20 and later"
#endif
#if TEST_STD_VER > 03 && !defined(_LIBCPP_INITIALIZER_LIST)
# error "<ranges> should include <initializer_list> in C++20 and later"
#endif
#if !defined(_LIBCPP_ITERATOR)
# error "<ranges> should include <iterator> in C++20 and later"
#endif

View File

@ -218,6 +218,8 @@ TEST_MACROS();
TEST_MACROS();
#include <random>
TEST_MACROS();
#include <ranges>
TEST_MACROS();
#include <ratio>
TEST_MACROS();
#ifndef _LIBCPP_HAS_NO_LOCALIZATION

View File

@ -136,6 +136,7 @@
#endif
#include <queue>
#include <random>
#include <ranges>
#include <ratio>
#ifndef _LIBCPP_HAS_NO_LOCALIZATION
# include <regex>

View File

@ -0,0 +1,20 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
// <ranges>
#include <ranges>
#include "test_macros.h"
#ifndef _LIBCPP_VERSION
#error _LIBCPP_VERSION not defined
#endif
// Required for MSVC internal test runner compatibility.
int main(int, char**) { return 0; }

View File

@ -0,0 +1,28 @@
//===----------------------------------------------------------------------===//
//
// 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
// <span>
// template<class ElementType, size_t Extent>
// inline constexpr bool ranges::enable_borrowed_range<
// span<ElementType, Extent>> = true;
#include <span>
#include "test_macros.h"
void test() {
static_assert(std::ranges::enable_borrowed_range<std::span<int, 0> >);
static_assert(std::ranges::enable_borrowed_range<std::span<int, 42> >);
static_assert(std::ranges::enable_borrowed_range<std::span<int, std::dynamic_extent> >);
static_assert(!std::ranges::enable_borrowed_range<std::span<int, 42>&>);
static_assert(!std::ranges::enable_borrowed_range<std::span<int, 42> const>);
}

View File

@ -0,0 +1,75 @@
//===----------------------------------------------------------------------===//
//
// 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
//
//===----------------------------------------------------------------------===//
//
// WARNING: This test was generated by generate_feature_test_macro_components.py
// and should not be edited manually.
//
// clang-format off
// <ranges>
// Test the feature test macros defined by <ranges>
/* Constant Value
__cpp_lib_ranges 201811L [C++20]
*/
#include <ranges>
#include "test_macros.h"
#if TEST_STD_VER < 14
# ifdef __cpp_lib_ranges
# error "__cpp_lib_ranges should not be defined before c++20"
# endif
#elif TEST_STD_VER == 14
# ifdef __cpp_lib_ranges
# error "__cpp_lib_ranges should not be defined before c++20"
# endif
#elif TEST_STD_VER == 17
# ifdef __cpp_lib_ranges
# error "__cpp_lib_ranges should not be defined before c++20"
# endif
#elif TEST_STD_VER == 20
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges
# error "__cpp_lib_ranges should be defined in c++20"
# endif
# if __cpp_lib_ranges != 201811L
# error "__cpp_lib_ranges should have the value 201811L in c++20"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_ranges
# error "__cpp_lib_ranges should not be defined because it is unimplemented in libc++!"
# endif
# endif
#elif TEST_STD_VER > 20
# if !defined(_LIBCPP_VERSION)
# ifndef __cpp_lib_ranges
# error "__cpp_lib_ranges should be defined in c++2b"
# endif
# if __cpp_lib_ranges != 201811L
# error "__cpp_lib_ranges should have the value 201811L in c++2b"
# endif
# else // _LIBCPP_VERSION
# ifdef __cpp_lib_ranges
# error "__cpp_lib_ranges should not be defined because it is unimplemented in libc++!"
# endif
# endif
#endif // TEST_STD_VER > 20
int main(int, char**) { return 0; }

View File

@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
//
// 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
// <ranges>
// template<class>
// inline constexpr bool enable_borrowed_range = false;
#include <ranges>
#include <array>
#include <deque>
#include <forward_list>
#include <list>
#include <map>
#include <queue>
#include <set>
#include <stack>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "test_macros.h"
struct S {};
void test() {
using std::ranges::enable_borrowed_range;
static_assert(!enable_borrowed_range<char>);
static_assert(!enable_borrowed_range<int>);
static_assert(!enable_borrowed_range<double>);
static_assert(!enable_borrowed_range<S>);
// Sequence containers
static_assert(!enable_borrowed_range<std::array<int, 0> >);
static_assert(!enable_borrowed_range<std::array<int, 42> >);
static_assert(!enable_borrowed_range<std::deque<int> >);
static_assert(!enable_borrowed_range<std::forward_list<int> >);
static_assert(!enable_borrowed_range<std::list<int> >);
static_assert(!enable_borrowed_range<std::vector<int> >);
// Associative containers
static_assert(!enable_borrowed_range<std::set<int> >);
static_assert(!enable_borrowed_range<std::map<int, int> >);
static_assert(!enable_borrowed_range<std::multiset<int> >);
static_assert(!enable_borrowed_range<std::multimap<int, int> >);
// Unordered associative containers
static_assert(!enable_borrowed_range<std::unordered_set<int> >);
static_assert(!enable_borrowed_range<std::unordered_map<int, int> >);
static_assert(!enable_borrowed_range<std::unordered_multiset<int> >);
static_assert(!enable_borrowed_range<std::unordered_multimap<int, int> >);
// Container adaptors
static_assert(!enable_borrowed_range<std::stack<int> >);
static_assert(!enable_borrowed_range<std::queue<int> >);
static_assert(!enable_borrowed_range<std::priority_queue<int> >);
// Both std::span and std::string_view have their own test.
}

View File

@ -0,0 +1,27 @@
//===----------------------------------------------------------------------===//
//
// 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
// <string_view>
// template<class charT, class traits>
// inline constexpr bool ranges::enable_borrowed_range<
// basic_string_view<charT, traits>> = true;
#include <string_view>
#include "test_macros.h"
void test() {
using std::ranges::enable_borrowed_range;
static_assert(enable_borrowed_range<std::basic_string_view<char> >);
static_assert(enable_borrowed_range<std::basic_string_view<wchar_t> >);
static_assert(enable_borrowed_range<std::basic_string_view<char8_t> >);
}

View File

@ -42,7 +42,7 @@ mandatory_inclusions = {
"optional": ["compare"],
"queue": ["compare", "initializer_list"],
"random": ["initializer_list"],
# TODO "ranges": ["compare", "initializer_list", "iterator"],
"ranges": ["compare", "initializer_list", "iterator"],
"regex": ["compare", "initializer_list"],
"set": ["compare", "initializer_list"],
"stack": ["compare", "initializer_list"],