From 01ace074fcb6a497fc16b1578fc10480dc7d563d Mon Sep 17 00:00:00 2001 From: Mark de Wever Date: Tue, 24 Nov 2020 18:08:02 +0100 Subject: [PATCH] [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 --- libcxx/docs/Cxx2aStatusIssuesStatus.csv | 2 +- libcxx/docs/Cxx2aStatusPaperStatus.csv | 2 +- libcxx/include/CMakeLists.txt | 2 + .../include/__ranges/enable_borrowed_range.h | 46 ++++++++++++ libcxx/include/module.modulemap | 4 + libcxx/include/ranges | 52 +++++++++++++ libcxx/include/span | 10 ++- libcxx/include/string_view | 8 ++ libcxx/test/libcxx/double_include.sh.cpp | 1 + .../ranges.inclusions.compile.pass.cpp | 34 +++++++++ .../libcxx/min_max_macros.compile.pass.cpp | 2 + .../libcxx/no_assert_include.compile.pass.cpp | 1 + .../libcxx/ranges/version.compile.pass.cpp | 20 +++++ .../enable_borrowed_range.compile.pass.cpp | 28 +++++++ .../ranges.version.pass.cpp | 75 +++++++++++++++++++ .../enable_borrowed_range.compile.pass.cpp | 67 +++++++++++++++++ .../enable_borrowed_range.compile.pass.cpp | 27 +++++++ .../utils/generate_header_inclusion_tests.py | 2 +- 18 files changed, 379 insertions(+), 4 deletions(-) create mode 100644 libcxx/include/__ranges/enable_borrowed_range.h create mode 100644 libcxx/include/ranges create mode 100644 libcxx/test/libcxx/inclusions/ranges.inclusions.compile.pass.cpp create mode 100644 libcxx/test/libcxx/ranges/version.compile.pass.cpp create mode 100644 libcxx/test/std/containers/views/enable_borrowed_range.compile.pass.cpp create mode 100644 libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.pass.cpp create mode 100644 libcxx/test/std/ranges/range.range/enable_borrowed_range.compile.pass.cpp create mode 100644 libcxx/test/std/strings/string.view/enable_borrowed_range.compile.pass.cpp diff --git a/libcxx/docs/Cxx2aStatusIssuesStatus.csv b/libcxx/docs/Cxx2aStatusIssuesStatus.csv index a471cd4f8b0a1d..7512630b24726e 100644 --- a/libcxx/docs/Cxx2aStatusIssuesStatus.csv +++ b/libcxx/docs/Cxx2aStatusIssuesStatus.csv @@ -281,7 +281,7 @@ "`3374 `__","P0653 + P1006 should have made the other ``std::to_address``\ overload ``constexpr``\ ","Prague","|Complete|","12.0" "`3375 `__","``decay``\ in ``viewable_range``\ should be ``remove_cvref``\ ","Prague","","" "`3377 `__","``elements_view::iterator``\ befriends a specialization of itself","Prague","","" -"`3379 `__","""``safe``\ "" in several library names is misleading","Prague","","" +"`3379 `__","""``safe``\ "" in several library names is misleading","Prague","|In Progress|","" "`3380 `__","``common_type``\ and comparison categories","Prague","","" "`3381 `__","``begin``\ and ``data``\ must agree for ``contiguous_range``\ ","Prague","","" "`3382 `__","NTTP for ``pair``\ and ``array``\ ","Prague","","" diff --git a/libcxx/docs/Cxx2aStatusPaperStatus.csv b/libcxx/docs/Cxx2aStatusPaperStatus.csv index f478f31d162b98..1c5a84c200397a 100644 --- a/libcxx/docs/Cxx2aStatusPaperStatus.csv +++ b/libcxx/docs/Cxx2aStatusPaperStatus.csv @@ -153,7 +153,7 @@ "`P1862 `__","LWG","Ranges adaptors for non-copyable iterators","Belfast","* *","" "`P1865 `__","LWG","Add max() to latch and barrier","Belfast","|Complete|","11.0" "`P1869 `__","LWG","Rename 'condition_variable_any' interruptible wait methods","Belfast","* *","" -"`P1870 `__","LWG","forwarding-range is too subtle","Belfast","* *","" +"`P1870 `__","LWG","forwarding-range is too subtle","Belfast","|In Progress|","" "`P1871 `__","LWG","Should concepts be enabled or disabled?","Belfast","* *","" "`P1872 `__","LWG","span should have size_type, not index_type","Belfast","|Complete|","10.0" "`P1878 `__","LWG","Constraining Readable Types","Belfast","* *","" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8050fd95a82a7a..683f790c9a473d 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -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 diff --git a/libcxx/include/__ranges/enable_borrowed_range.h b/libcxx/include/__ranges/enable_borrowed_range.h new file mode 100644 index 00000000000000..618b2223c71691 --- /dev/null +++ b/libcxx/include/__ranges/enable_borrowed_range.h @@ -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 and . The +// separate header is used to avoid including the entire header in +// and . + +#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 +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 diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap index 56b49c473070f8..c970082b560053 100644 --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -409,6 +409,10 @@ module std [system] { export initializer_list export * } + module ranges { + header "ranges" + export * + } module ratio { header "ratio" export * diff --git a/libcxx/include/ranges b/libcxx/include/ranges new file mode 100644 index 00000000000000..3bcb62be28d410 --- /dev/null +++ b/libcxx/include/ranges @@ -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 // see [compare.syn] +#include // see [initializer.list.syn] +#include // see [iterator.synopsis] + +namespace std::ranges { + // [range.range], ranges + template + inline constexpr bool enable_borrowed_range = false; +} + +*/ + +#include <__config> +#include <__ranges/enable_borrowed_range.h> +#include // Required by the standard. +#include // Required by the standard. +#include // Required by the standard. +#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 _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 diff --git a/libcxx/include/span b/libcxx/include/span index 4f63d0ac4e1f15..b47574084b2acc 100644 --- a/libcxx/include/span +++ b/libcxx/include/span @@ -22,6 +22,9 @@ inline constexpr size_t dynamic_extent = numeric_limits::max(); template class span; +template + inline constexpr bool ranges::enable_borrowed_range> = true; + // [span.objectrep], views of object representation template span (sizeof(ElementType) * Extent))> as_writable_bytes(span s) noexcept; -namespace std { template class span { public: @@ -123,6 +125,7 @@ template */ #include <__config> +#include <__ranges/enable_borrowed_range.h> #include // for array #include // for byte #include // for iterators @@ -516,6 +519,11 @@ private: size_type __size; }; +#if !defined(_LIBCPP_HAS_NO_RANGES) +template +inline constexpr bool ranges::enable_borrowed_range > = true; +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + // as_bytes & as_writable_bytes template _LIBCPP_INLINE_VISIBILITY diff --git a/libcxx/include/string_view b/libcxx/include/string_view index 3177fcd7783163..e957a649f62ddf 100644 --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -19,6 +19,9 @@ namespace std { template> class basic_string_view; + template + inline constexpr bool ranges::enable_borrowed_range> = true; // C++20 + // 7.9, basic_string_view non-member comparison functions template constexpr bool operator==(basic_string_view x, @@ -179,6 +182,7 @@ namespace std { */ #include <__config> +#include <__ranges/enable_borrowed_range.h> #include <__string> #include #include @@ -649,6 +653,10 @@ private: size_type __size; }; +#if _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES) +template +inline constexpr bool ranges::enable_borrowed_range > = true; +#endif // _LIBCPP_STD_VER > 17 && !defined(_LIBCPP_HAS_NO_RANGES) // [string.view.comparison] // operator == diff --git a/libcxx/test/libcxx/double_include.sh.cpp b/libcxx/test/libcxx/double_include.sh.cpp index 84486edb465506..eb9de0b64b1ab9 100644 --- a/libcxx/test/libcxx/double_include.sh.cpp +++ b/libcxx/test/libcxx/double_include.sh.cpp @@ -143,6 +143,7 @@ #endif #include #include +#include #include #ifndef _LIBCPP_HAS_NO_LOCALIZATION # include diff --git a/libcxx/test/libcxx/inclusions/ranges.inclusions.compile.pass.cpp b/libcxx/test/libcxx/inclusions/ranges.inclusions.compile.pass.cpp new file mode 100644 index 00000000000000..316d1410415898 --- /dev/null +++ b/libcxx/test/libcxx/inclusions/ranges.inclusions.compile.pass.cpp @@ -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 + +// + +// Test that includes all the other headers it's supposed to. + +#include +#include "test_macros.h" + +#if !defined(_LIBCPP_RANGES) + # error " was expected to define _LIBCPP_RANGES" +#endif +#if TEST_STD_VER > 17 && !defined(_LIBCPP_COMPARE) + # error " should include in C++20 and later" +#endif +#if TEST_STD_VER > 03 && !defined(_LIBCPP_INITIALIZER_LIST) + # error " should include in C++20 and later" +#endif +#if !defined(_LIBCPP_ITERATOR) + # error " should include in C++20 and later" +#endif diff --git a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp index 3e75de51a6ece7..520fd3cc15907c 100644 --- a/libcxx/test/libcxx/min_max_macros.compile.pass.cpp +++ b/libcxx/test/libcxx/min_max_macros.compile.pass.cpp @@ -218,6 +218,8 @@ TEST_MACROS(); TEST_MACROS(); #include TEST_MACROS(); +#include +TEST_MACROS(); #include TEST_MACROS(); #ifndef _LIBCPP_HAS_NO_LOCALIZATION diff --git a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp index 221c39a07b2b84..60839d52ea5feb 100644 --- a/libcxx/test/libcxx/no_assert_include.compile.pass.cpp +++ b/libcxx/test/libcxx/no_assert_include.compile.pass.cpp @@ -136,6 +136,7 @@ #endif #include #include +#include #include #ifndef _LIBCPP_HAS_NO_LOCALIZATION # include diff --git a/libcxx/test/libcxx/ranges/version.compile.pass.cpp b/libcxx/test/libcxx/ranges/version.compile.pass.cpp new file mode 100644 index 00000000000000..817b9eede4d259 --- /dev/null +++ b/libcxx/test/libcxx/ranges/version.compile.pass.cpp @@ -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 +// +//===----------------------------------------------------------------------===// + +// + +#include + +#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; } diff --git a/libcxx/test/std/containers/views/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/containers/views/enable_borrowed_range.compile.pass.cpp new file mode 100644 index 00000000000000..946cb5c1cd3342 --- /dev/null +++ b/libcxx/test/std/containers/views/enable_borrowed_range.compile.pass.cpp @@ -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 + +// + +// template +// inline constexpr bool ranges::enable_borrowed_range< +// span> = true; + +#include + +#include "test_macros.h" + +void test() { + static_assert(std::ranges::enable_borrowed_range >); + static_assert(std::ranges::enable_borrowed_range >); + static_assert(std::ranges::enable_borrowed_range >); + static_assert(!std::ranges::enable_borrowed_range&>); + static_assert(!std::ranges::enable_borrowed_range const>); +} diff --git a/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.pass.cpp b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.pass.cpp new file mode 100644 index 00000000000000..96496add7622f9 --- /dev/null +++ b/libcxx/test/std/language.support/support.limits/support.limits.general/ranges.version.pass.cpp @@ -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 + +// + +// Test the feature test macros defined by + +/* Constant Value + __cpp_lib_ranges 201811L [C++20] +*/ + +#include +#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; } diff --git a/libcxx/test/std/ranges/range.range/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/ranges/range.range/enable_borrowed_range.compile.pass.cpp new file mode 100644 index 00000000000000..46755e3129c051 --- /dev/null +++ b/libcxx/test/std/ranges/range.range/enable_borrowed_range.compile.pass.cpp @@ -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 + +// + +// template +// inline constexpr bool enable_borrowed_range = false; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +struct S {}; + +void test() { + using std::ranges::enable_borrowed_range; + static_assert(!enable_borrowed_range); + static_assert(!enable_borrowed_range); + static_assert(!enable_borrowed_range); + static_assert(!enable_borrowed_range); + + // Sequence containers + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + + // Associative containers + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + + // Unordered associative containers + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + + // Container adaptors + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + static_assert(!enable_borrowed_range >); + + // Both std::span and std::string_view have their own test. +} diff --git a/libcxx/test/std/strings/string.view/enable_borrowed_range.compile.pass.cpp b/libcxx/test/std/strings/string.view/enable_borrowed_range.compile.pass.cpp new file mode 100644 index 00000000000000..f19dd1a17e0b5b --- /dev/null +++ b/libcxx/test/std/strings/string.view/enable_borrowed_range.compile.pass.cpp @@ -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 + +// + +// template +// inline constexpr bool ranges::enable_borrowed_range< +// basic_string_view> = true; + +#include + +#include "test_macros.h" + +void test() { + using std::ranges::enable_borrowed_range; + static_assert(enable_borrowed_range >); + static_assert(enable_borrowed_range >); + static_assert(enable_borrowed_range >); +} diff --git a/libcxx/utils/generate_header_inclusion_tests.py b/libcxx/utils/generate_header_inclusion_tests.py index 0bf318ea440e8a..5596872c339b1e 100755 --- a/libcxx/utils/generate_header_inclusion_tests.py +++ b/libcxx/utils/generate_header_inclusion_tests.py @@ -42,7 +42,7 @@ def get_libcxx_paths(): "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"],