diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv --- a/libcxx/docs/Status/RangesPaper.csv +++ b/libcxx/docs/Status/RangesPaper.csv @@ -133,7 +133,7 @@ `[range.dangling] `_,"| ranges::dangling | ranges::borrowed_iterator_t | ranges::borrowed_subrange_t","| [range.range] -| [range.subrange]",Unassigned,Not started +| [range.subrange]",Christopher Di Bella,✅ `[range.all] `_,`view::all `_,"[range.subrange], [range.view.ref]",Zoe Carver,✅ `[range.view.ref] `_,`ref-view `_,[view.interface],Zoe Carver,✅ `[range.filter] `_,filter_view,[range.all],Louis Dionne,Not started diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -185,6 +185,7 @@ __ranges/all.h __ranges/concepts.h __ranges/copyable_box.h + __ranges/dangling.h __ranges/data.h __ranges/drop_view.h __ranges/empty_view.h diff --git a/libcxx/include/__ranges/dangling.h b/libcxx/include/__ranges/dangling.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__ranges/dangling.h @@ -0,0 +1,47 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// 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_DANGLING_H +#define _LIBCPP___RANGES_DANGLING_H + +#include <__config> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#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) + +namespace ranges { +struct dangling { + dangling() = default; + _LIBCPP_HIDE_FROM_ABI constexpr dangling(auto&&...) noexcept {} +}; + +template +using borrowed_iterator_t = _If, iterator_t<_Rp>, dangling>; + +// borrowed_subrange_t defined in <__ranges/subrange.h> +} // namespace ranges + +#endif // !_LIBCPP_HAS_NO_RANGES + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif // _LIBCPP___RANGES_DANGLING_H 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 @@ -16,6 +16,7 @@ #include <__iterator/advance.h> #include <__ranges/access.h> #include <__ranges/concepts.h> +#include <__ranges/dangling.h> #include <__ranges/enable_borrowed_range.h> #include <__ranges/size.h> #include <__ranges/view_interface.h> @@ -226,6 +227,9 @@ else return __subrange.end(); } + + template + using borrowed_subrange_t = _If, subrange >, dangling>; } // namespace ranges using ranges::get; diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -601,6 +601,7 @@ module all { header "__ranges/all.h" } module concepts { header "__ranges/concepts.h" } module copyable_box { header "__ranges/copyable_box.h" } + module dangling { header "__ranges/dangling.h" } module data { header "__ranges/data.h" } module empty { header "__ranges/empty.h" } module empty_view { header "__ranges/empty_view.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -90,6 +90,25 @@ requires is_class_v && same_as> class view_interface; + // [range.subrange], sub-ranges + enum class subrange_kind : bool { unsized, sized }; + + template S = I, subrange_kind K = see below> + requires (K == subrange_kind::sized || !sized_sentinel_for) + class subrange; + + template + inline constexpr bool enable_borrowed_range> = true; + + // [range.dangling], dangling iterator handling + struct dangling; + + template + using borrowed_iterator_t = see below; + + template + using borrowed_subrange_t = see below; + // [range.empty], empty view template requires is_object_v @@ -117,6 +136,7 @@ #include <__ranges/access.h> #include <__ranges/all.h> #include <__ranges/concepts.h> +#include <__ranges/dangling.h> #include <__ranges/data.h> #include <__ranges/drop_view.h> #include <__ranges/empty.h> diff --git a/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_iterator.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_iterator.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_iterator.compile.pass.cpp @@ -0,0 +1,36 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// class std::ranges::borrowed_iterator_t; + +#include + +#include +#include +#include +#include +#include + +static_assert(std::same_as, std::ranges::dangling>); +static_assert(std::same_as, std::ranges::dangling>); +static_assert(std::same_as >, std::ranges::dangling>); + +static_assert(std::same_as, std::string::iterator>); +static_assert(std::same_as, std::string_view::iterator>); +static_assert(std::same_as >, std::span::iterator>); + +template +constexpr bool has_borrowed_iterator = requires { + typename std::ranges::borrowed_iterator_t; +}; + +static_assert(!has_borrowed_iterator); diff --git a/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_subrange.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_subrange.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.dangling/borrowed_subrange.compile.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// class std::ranges::borrowed_subrange_t; + +#include + +#include +#include +#include +#include +#include + +static_assert(std::same_as, std::ranges::dangling>); +static_assert(std::same_as, std::ranges::dangling>); +static_assert(std::same_as >, std::ranges::dangling>); + +static_assert( + std::same_as, std::ranges::subrange >); + +static_assert( + std::same_as >, std::ranges::subrange::iterator> >); + +static_assert(std::same_as, + std::ranges::subrange >); + +template +constexpr bool has_type = requires { + typename std::ranges::borrowed_subrange_t; +}; + +static_assert(!has_type); + +struct S {}; +static_assert(!has_type); diff --git a/libcxx/test/std/ranges/range.utility/range.dangling/dangling.compile.pass.cpp b/libcxx/test/std/ranges/range.utility/range.dangling/dangling.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/ranges/range.utility/range.dangling/dangling.compile.pass.cpp @@ -0,0 +1,31 @@ +//===----------------------------------------------------------------------===// +// +// 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: gcc-10 + +// class std::ranges::dangling; + +#include + +#include +#include + +static_assert(std::is_empty_v); + +template struct S { }; +static_assert(std::is_nothrow_constructible_v); +static_assert(std::is_nothrow_constructible_v>); +static_assert(std::is_nothrow_constructible_v, S<1>>); +static_assert(std::is_nothrow_constructible_v, S<1>, S<2>>); + +[[maybe_unused]] constexpr auto a = std::ranges::dangling(); +[[maybe_unused]] constexpr auto b = std::ranges::dangling(S<0>()); +[[maybe_unused]] constexpr auto c = std::ranges::dangling(S<0>(), S<1>()); +[[maybe_unused]] constexpr auto d = std::ranges::dangling(S<0>(), S<1>(), S<2>());