diff options
author | Hui Xie <hui.xie1990@gmail.com> | 2022-09-05 16:45:47 +0100 |
---|---|---|
committer | Hui Xie <hui.xie1990@gmail.com> | 2022-10-06 22:57:37 +0100 |
commit | 96a509bca28b8668c3c2c68aae4116cc0d8c2952 (patch) | |
tree | cdf67a9fa314ab866cb5427864e649b6f4c2a9a1 | |
parent | 6e7df70e5acb482b118b8d9a8957c0980a172e16 (diff) | |
download | llvm-96a509bca28b8668c3c2c68aae4116cc0d8c2952.zip llvm-96a509bca28b8668c3c2c68aae4116cc0d8c2952.tar.gz llvm-96a509bca28b8668c3c2c68aae4116cc0d8c2952.tar.bz2 |
implement `std::views::istream`
implement `std::ranges::basic_istream_view` and `std::views::istream`. Although the view itself is constexpr,
the constructor argument is a base class std::istream where its ctor/dtor are not constexpr. So no tests are performed in
constexpr
Differential Revision: https://reviews.llvm.org/D133317
22 files changed, 885 insertions, 5 deletions
diff --git a/libcxx/docs/Status/Cxx20Issues.csv b/libcxx/docs/Status/Cxx20Issues.csv index bd93c95..b151424 100644 --- a/libcxx/docs/Status/Cxx20Issues.csv +++ b/libcxx/docs/Status/Cxx20Issues.csv @@ -296,6 +296,6 @@ "`3393 <https://wg21.link/LWG3393>`__","Missing/incorrect feature test macro for coroutines","Prague","|Complete|","14.0" "`3395 <https://wg21.link/LWG3395>`__","Definition for three-way comparison needs to be updated (US 152)","Prague","","","|spaceship|" "`3396 <https://wg21.link/LWG3396>`__","Clarify point of reference for ``source_location::current()``\ (DE 169)","Prague","","" -"`3397 <https://wg21.link/LWG3397>`__","``ranges::basic_istream_view::iterator``\ should not provide ``iterator_category``\ ","Prague","","","|ranges|" +"`3397 <https://wg21.link/LWG3397>`__","``ranges::basic_istream_view::iterator``\ should not provide ``iterator_category``\ ","Prague","|Complete|","16.0","|ranges|" "`3398 <https://wg21.link/LWG3398>`__","``tuple_element_t``\ is also wrong for ``const subrange``\ ","Prague","|Complete|","14.0","|ranges|" "`3446 <https://wg21.link/LWG3446>`__","``indirectly_readable_traits``\ ambiguity for types with both ``value_type``\ and ``element_type``\ ","November virtual meeting","|Complete|","13.0" diff --git a/libcxx/docs/Status/Cxx20Papers.csv b/libcxx/docs/Status/Cxx20Papers.csv index ab7a84b..90215d3 100644 --- a/libcxx/docs/Status/Cxx20Papers.csv +++ b/libcxx/docs/Status/Cxx20Papers.csv @@ -108,7 +108,7 @@ "`P0784R7 <https://wg21.link/P0784R7>`__","CWG","More constexpr containers","Cologne","|Complete|","12.0" "`P0980R1 <https://wg21.link/P0980R1>`__","LWG","Making std::string constexpr","Cologne","|Complete|","15.0" "`P1004R2 <https://wg21.link/P1004R2>`__","LWG","Making std::vector constexpr","Cologne","|Complete|","15.0" -"`P1035R7 <https://wg21.link/P1035R7>`__","LWG","Input Range Adaptors","Cologne","","" +"`P1035R7 <https://wg21.link/P1035R7>`__","LWG","Input Range Adaptors","Cologne","|In Progress|","" "`P1065R2 <https://wg21.link/P1065R2>`__","LWG","Constexpr INVOKE","Cologne","|Complete|","12.0" "`P1135R6 <https://wg21.link/P1135R6>`__","LWG","The C++20 Synchronization Library","Cologne","|Complete|","11.0" "`P1207R4 <https://wg21.link/P1207R4>`__","LWG","Movability of Single-pass Iterators","Cologne","|Complete|","15.0" @@ -124,7 +124,7 @@ "`P1523R1 <https://wg21.link/P1523R1>`__","LWG","Views and Size Types","Cologne","|Complete|","15.0" "`P1612R1 <https://wg21.link/P1612R1>`__","LWG","Relocate Endian's Specification","Cologne","|Complete|","10.0" "`P1614R2 <https://wg21.link/P1614R2>`__","LWG","The Mothership has Landed","Cologne","|In Progress|","" -"`P1638R1 <https://wg21.link/P1638R1>`__","LWG","basic_istream_view::iterator should not be copyable","Cologne","","" +"`P1638R1 <https://wg21.link/P1638R1>`__","LWG","basic_istream_view::iterator should not be copyable","Cologne","|Complete|","16.0" "`P1643R1 <https://wg21.link/P1643R1>`__","LWG","Add wait/notify to atomic_ref","Cologne","","" "`P1644R0 <https://wg21.link/P1644R0>`__","LWG","Add wait/notify to atomic<shared_ptr>","Cologne","","" "`P1650R0 <https://wg21.link/P1650R0>`__","LWG","Output std::chrono::days with 'd' suffix","Cologne","","" @@ -204,4 +204,4 @@ "`P2372R3 <https://wg21.link/P2372R3>`__","LWG","Fixing locale handling in chrono formatters","October 2021","","" "`P2415R2 <https://wg21.link/P2415R2>`__","LWG","What is a ``view``","October 2021","|Complete|","14.0" "`P2418R2 <https://wg21.link/P2418R2>`__","LWG","Add support for ``std::generator``-like types to ``std::format``","October 2021","|Complete|","15.0" -"`P2432R1 <https://wg21.link/P2432R1>`__","LWG","Fix ``istream_view``","October 2021","","" +"`P2432R1 <https://wg21.link/P2432R1>`__","LWG","Fix ``istream_view``","October 2021","|Complete|","16.0" diff --git a/libcxx/docs/Status/Cxx2bIssues.csv b/libcxx/docs/Status/Cxx2bIssues.csv index 534bd7e..b3516766 100644 --- a/libcxx/docs/Status/Cxx2bIssues.csv +++ b/libcxx/docs/Status/Cxx2bIssues.csv @@ -121,7 +121,7 @@ `3563 <https://wg21.link/LWG3563>`__,"``keys_view`` example is broken","October 2021","","","|ranges|" `3566 <https://wg21.link/LWG3566>`__,"Constraint recursion for ``operator<=>(optional<T>, U)``","October 2021","","","|spaceship|" `3567 <https://wg21.link/LWG3567>`__,"Formatting move-only iterators take two","October 2021","","","|format|" -`3568 <https://wg21.link/LWG3568>`__,"``basic_istream_view`` needs to initialize ``value_``","October 2021","","","|ranges|" +`3568 <https://wg21.link/LWG3568>`__,"``basic_istream_view`` needs to initialize ``value_``","October 2021","|Complete|","16.0","|ranges|" `3570 <https://wg21.link/LWG3570>`__,"``basic_osyncstream::emit`` should be an unformatted output function","October 2021","","" `3571 <https://wg21.link/LWG3571>`__,"``flush_emit`` should set ``badbit`` if the ``emit`` call fails","October 2021","","" `3572 <https://wg21.link/LWG3572>`__,"``copyable-box`` should be fully ``constexpr``","October 2021","|Complete|","14.0","|ranges|" diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt index 8e79e10..b9b657b 100644 --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -481,6 +481,7 @@ set(files __ranges/enable_view.h __ranges/filter_view.h __ranges/iota_view.h + __ranges/istream_view.h __ranges/join_view.h __ranges/lazy_split_view.h __ranges/non_propagating_cache.h diff --git a/libcxx/include/__ranges/istream_view.h b/libcxx/include/__ranges/istream_view.h new file mode 100644 index 0000000..caa29aa --- /dev/null +++ b/libcxx/include/__ranges/istream_view.h @@ -0,0 +1,139 @@ +// -*- 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_ISTREAM_VIEW_H +#define _LIBCPP___RANGES_ISTREAM_VIEW_H + +#include <__concepts/constructible.h> +#include <__concepts/derived_from.h> +#include <__concepts/movable.h> +#include <__config> +#include <__iterator/default_sentinel.h> +#include <__iterator/iterator_traits.h> +#include <__memory/addressof.h> +#include <__ranges/view_interface.h> +#include <__type_traits/remove_cvref.h> +#include <__utility/forward.h> +#include <cstddef> +#include <iosfwd> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +#if _LIBCPP_STD_VER >= 20 + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace ranges { + +template <class _Val, class _CharT, class _Traits> +concept __stream_extractable = requires(basic_istream<_CharT, _Traits>& __is, _Val& __t) { __is >> __t; }; + +template <movable _Val, class _CharT, class _Traits = char_traits<_CharT>> + requires default_initializable<_Val> && __stream_extractable<_Val, _CharT, _Traits> +class basic_istream_view : public view_interface<basic_istream_view<_Val, _CharT, _Traits>> { +public: + _LIBCPP_HIDE_FROM_ABI constexpr explicit basic_istream_view(basic_istream<_CharT, _Traits>& __stream) + : __stream_(std::addressof(__stream)) {} + + _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { + *__stream_ >> __value_; + return __iterator{*this}; + } + + _LIBCPP_HIDE_FROM_ABI constexpr default_sentinel_t end() const noexcept { return default_sentinel; } + +private: + class __iterator; + + basic_istream<_CharT, _Traits>* __stream_; + _LIBCPP_NO_UNIQUE_ADDRESS _Val __value_ = _Val(); +}; + +template <movable _Val, class _CharT, class _Traits> + requires default_initializable<_Val> && __stream_extractable<_Val, _CharT, _Traits> +class basic_istream_view<_Val, _CharT, _Traits>::__iterator { +public: + using iterator_concept = input_iterator_tag; + using difference_type = ptrdiff_t; + using value_type = _Val; + + _LIBCPP_HIDE_FROM_ABI constexpr explicit __iterator(basic_istream_view& __parent) noexcept + : __parent_(std::addressof(__parent)) {} + + __iterator(const __iterator&) = delete; + _LIBCPP_HIDE_FROM_ABI __iterator(__iterator&&) = default; + + __iterator& operator=(const __iterator&) = delete; + _LIBCPP_HIDE_FROM_ABI __iterator& operator=(__iterator&&) = default; + + _LIBCPP_HIDE_FROM_ABI __iterator& operator++() { + *__parent_->__stream_ >> __parent_->__value_; + return *this; + } + + _LIBCPP_HIDE_FROM_ABI void operator++(int) { ++*this; } + + _LIBCPP_HIDE_FROM_ABI _Val& operator*() const { return __parent_->__value_; } + + _LIBCPP_HIDE_FROM_ABI friend bool operator==(const __iterator& __x, default_sentinel_t) { + return !*__x.__get_parent_stream(); + } + +private: + basic_istream_view* __parent_; + + _LIBCPP_HIDE_FROM_ABI constexpr basic_istream<_CharT, _Traits>* __get_parent_stream() const { + return __parent_->__stream_; + } +}; + +template <class _Val> +using istream_view = basic_istream_view<_Val, char>; + +#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS +template <class _Val> +using wistream_view = basic_istream_view<_Val, wchar_t>; +#endif + +namespace views { +namespace __istream { + +// clang-format off +template <class _Tp> +struct __fn { + template <class _Up, class _UnCVRef = remove_cvref_t<_Up>> + requires derived_from<_UnCVRef, basic_istream<typename _UnCVRef::char_type, + typename _UnCVRef::traits_type>> + _LIBCPP_HIDE_FROM_ABI constexpr auto operator()(_Up&& __u) const + noexcept(noexcept(basic_istream_view<_Tp, typename _UnCVRef::char_type, + typename _UnCVRef::traits_type>(std::forward<_Up>(__u)))) + -> decltype( basic_istream_view<_Tp, typename _UnCVRef::char_type, + typename _UnCVRef::traits_type>(std::forward<_Up>(__u))) + { return basic_istream_view<_Tp, typename _UnCVRef::char_type, + typename _UnCVRef::traits_type>(std::forward<_Up>(__u)); + } +}; +// clang-format on + +} // namespace __istream + +inline namespace __cpo { +template <class _Tp> + inline constexpr auto istream = __istream::__fn<_Tp>{}; +} // namespace __cpo +} // namespace views + +} // namespace ranges + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP_STD_VER >= 20 + +#endif // _LIBCPP___RANGES_ISTREAM_VIEW_H diff --git a/libcxx/include/module.modulemap.in b/libcxx/include/module.modulemap.in index dd7fd08..73e366f 100644 --- a/libcxx/include/module.modulemap.in +++ b/libcxx/include/module.modulemap.in @@ -1014,6 +1014,10 @@ module std [system] { module enable_view { private header "__ranges/enable_view.h" } module filter_view { private header "__ranges/filter_view.h" } module iota_view { private header "__ranges/iota_view.h" } + module istream_view { + @requires_LIBCXX_ENABLE_LOCALIZATION@ + private header "__ranges/istream_view.h" + } module join_view { private header "__ranges/join_view.h" } module lazy_split_view { private header "__ranges/lazy_split_view.h" } module non_propagating_cache { private header "__ranges/non_propagating_cache.h" } diff --git a/libcxx/include/ranges b/libcxx/include/ranges index b2e14cd..0565b2f 100644 --- a/libcxx/include/ranges +++ b/libcxx/include/ranges @@ -228,6 +228,19 @@ namespace std::ranges { inline constexpr unspecified lazy_split = unspecified; } + // [range.istream], istream view + template<movable Val, class CharT, class Traits = char_traits<CharT>> + requires see below + class basic_istream_view; + + template<class Val> + using istream_view = basic_istream_view<Val, char>; + + template<class Val> + using wistream_view = basic_istream_view<Val, wchar_t>; + + namespace views { template<class T> inline constexpr unspecified istream = unspecified; } + // [range.zip], zip view template<input_range... Views> requires (view<Views> && ...) && (sizeof...(Views) > 0) @@ -305,6 +318,10 @@ namespace std { #include <type_traits> #include <version> +#if !defined(_LIBCPP_HAS_NO_LOCALIZATION) +#include <__ranges/istream_view.h> +#endif + // standard-mandated includes // [ranges.syn] diff --git a/libcxx/test/libcxx/private_headers.verify.cpp b/libcxx/test/libcxx/private_headers.verify.cpp index 693dd1d..90e06bd 100644 --- a/libcxx/test/libcxx/private_headers.verify.cpp +++ b/libcxx/test/libcxx/private_headers.verify.cpp @@ -512,6 +512,7 @@ END-SCRIPT #include <__ranges/enable_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/enable_view.h'}} #include <__ranges/filter_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/filter_view.h'}} #include <__ranges/iota_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/iota_view.h'}} +#include <__ranges/istream_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/istream_view.h'}} #include <__ranges/join_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/join_view.h'}} #include <__ranges/lazy_split_view.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/lazy_split_view.h'}} #include <__ranges/non_propagating_cache.h> // expected-error@*:* {{use of private header from outside its module: '__ranges/non_propagating_cache.h'}} diff --git a/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp b/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp new file mode 100644 index 0000000..f2fd2d6 --- /dev/null +++ b/libcxx/test/libcxx/ranges/range.factories/range.istream.view/no_unique_address.compile.pass.cpp @@ -0,0 +1,26 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// clang-cl and cl currently don't support [[no_unique_address]] +// XFAIL: msvc + +// Test the libc++ extension that the value stored in `std::ranges::istream_view` has been marked +// as _LIBCPP_NO_UNIQUE_ADDRESS + +#include <istream> +#include <ranges> + +struct Empty { + friend std::istream& operator>>(std::istream& i, Empty const&) { return i; } +}; + +static_assert(sizeof(std::ranges::istream_view<Empty>) == sizeof(void*)); + diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/begin.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/begin.pass.cpp new file mode 100644 index 0000000..99891bc --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/begin.pass.cpp @@ -0,0 +1,58 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// constexpr auto begin(); + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "utils.h" + +template <class T> +concept HasBegin = requires(T t) { t.begin(); }; + +static_assert(HasBegin<std::ranges::istream_view<int>>); +static_assert(!HasBegin<const std::ranges::istream_view<int>>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(HasBegin<std::ranges::wistream_view<int>>); +static_assert(!HasBegin<const std::ranges::wistream_view<int>>); +#endif + +template <class CharT> +void test() { + // begin should read the first element + { + auto iss = make_string_stream<CharT>("12 3"); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + assert(*it == 12); + } + + // empty stream + { + auto iss = make_string_stream<CharT>(""); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + assert(it == isv.end()); + } +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/cpo.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/cpo.pass.cpp new file mode 100644 index 0000000..1cbbccf --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/cpo.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// std::views::istream<T> + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "utils.h" + +static_assert(!std::is_invocable_v<decltype((std::views::istream<int>))>); +static_assert(std::is_invocable_v<decltype((std::views::istream<int>)), std::istream&>); +static_assert(!std::is_invocable_v<decltype((std::views::istream<int>)), const std::istream&>); +static_assert(!std::is_invocable_v<decltype((std::views::istream<int>)), int>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(std::is_invocable_v<decltype((std::views::istream<int>)), std::wistream&>); +static_assert(!std::is_invocable_v<decltype((std::views::istream<int>)), const std::wistream&>); +#endif + +template <class CharT> +void test() { + auto iss = make_string_stream<CharT>("12 3"); + auto isv = std::views::istream<int>(iss); + auto it = isv.begin(); + assert(*it == 12); +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/ctor.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/ctor.pass.cpp new file mode 100644 index 0000000..ff60fbf --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/ctor.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// constexpr explicit basic_istream_view(basic_istream<CharT, Traits>& stream); + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "utils.h" + +// test that the constructor is explicit +static_assert(std::constructible_from<std::ranges::istream_view<int>, std::istream&>); +static_assert(!std::convertible_to<std::istream&, std::ranges::istream_view<int>>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(std::constructible_from<std::ranges::wistream_view<int>, std::wistream&>); +static_assert(!std::convertible_to<std::wistream&, std::ranges::wistream_view<int>>); +#endif + +template <class CharT> +void test() { + // test constructor init the stream pointer to the passed one + { + auto iss = make_string_stream<CharT>("123"); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + assert(*it == 123); + } + + // LWG 3568. basic_istream_view needs to initialize value_ + { + auto iss = make_string_stream<CharT>("123"); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + using Iter = std::ranges::iterator_t<decltype(isv)>; + Iter iter{isv}; + assert(*iter == 0); + } +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/end.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/end.pass.cpp new file mode 100644 index 0000000..80b1dfe --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/end.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// constexpr default_sentinel_t end() const noexcept; + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "utils.h" + +template <class T> +concept NoexceptEnd = + requires(T t) { + { t.end() } noexcept; + }; + +static_assert(NoexceptEnd<std::ranges::istream_view<int>>); +static_assert(NoexceptEnd<const std::ranges::istream_view<int>>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(NoexceptEnd<std::ranges::wistream_view<int>>); +static_assert(NoexceptEnd<const std::ranges::wistream_view<int>>); +#endif + +template <class CharT> +void test() { + auto iss = make_string_stream<CharT>("12"); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + [[maybe_unused]] std::same_as<std::default_sentinel_t> auto sent = isv.end(); +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/general.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/general.pass.cpp new file mode 100644 index 0000000..c65f10c --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/general.pass.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// Some basic examples of how istream_view might be used in the wild. This is a general +// collection of sample algorithms and functions that try to mock general usage of +// this view. + +#include <algorithm> +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "utils.h" + +template <class CharT> +void test() { + auto ints = make_string_stream<CharT>("0 1 2 3 4"); + auto oss = std::basic_ostringstream<CharT>{}; + auto delimiter = make_string<CharT>("-"); + std::ranges::copy( + std::ranges::basic_istream_view<int, CharT>(ints), std::ostream_iterator<int, CharT>{oss, delimiter.c_str()}); + auto expected = make_string<CharT>("0-1-2-3-4-"); + assert(oss.str() == expected); +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/compare.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/compare.pass.cpp new file mode 100644 index 0000000..81ae088 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/compare.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// friend bool operator==(const iterator& x, default_sentinel_t); + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "../utils.h" + +template <class CharT> +void test() { + // fail to read + { + auto iss = make_string_stream<CharT>("a123 4"); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + assert(it == std::default_sentinel); + } + + // iterate through the end + { + auto iss = make_string_stream<CharT>("123 "); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + assert(it != std::default_sentinel); + ++it; + assert(it == std::default_sentinel); + } + + // empty stream + { + auto iss = make_string_stream<CharT>(""); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + assert(it == std::default_sentinel); + } +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.pass.cpp new file mode 100644 index 0000000..017d11c --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/ctor.pass.cpp @@ -0,0 +1,57 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// constexpr explicit iterator(basic_istream_view& parent) noexcept; + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "../utils.h" + +// test that the constructor is explicit +template <class CharT> +using IstreamView = std::ranges::basic_istream_view<int, CharT>; +template <class CharT> +using Iter = std::ranges::iterator_t<IstreamView<CharT>>; + +static_assert(std::constructible_from<Iter<char>, IstreamView<char>&>); +static_assert(!std::convertible_to<IstreamView<char>&, Iter<char>>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(std::constructible_from<Iter<wchar_t>, IstreamView<wchar_t>&>); +static_assert(!std::convertible_to<IstreamView<wchar_t>&, Iter<wchar_t>>); +#endif + +// test that the constructor is noexcept +static_assert(std::is_nothrow_constructible_v<Iter<char>, IstreamView<char>&>); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(std::is_nothrow_constructible_v<Iter<wchar_t>, IstreamView<wchar_t>&>); +#endif + +template <class CharT> +void test() { + auto iss = make_string_stream<CharT>("123"); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + Iter<CharT> it{isv}; + ++it; + assert(*it == 123); +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp new file mode 100644 index 0000000..1cf05f0 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/deref.pass.cpp @@ -0,0 +1,51 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// Val& operator*() const; + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "../utils.h" + +template <class CharT> +void test() { + // operator* should return correct value + { + auto iss = make_string_stream<CharT>("1 2 345 "); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + std::same_as<int&> decltype(auto) v1 = *it; + assert(v1 == 1); + } + + // operator* should return the same reference to the value stored in the view + { + auto iss = make_string_stream<CharT>("1 2 345 "); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + using Iter = std::ranges::iterator_t<decltype(isv)>; + + Iter it1{isv}; + Iter it2{isv}; + assert(&*it1 == &*it2); + } +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/increment.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/increment.pass.cpp new file mode 100644 index 0000000..6675478 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/increment.pass.cpp @@ -0,0 +1,62 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// iterator& operator++(); +// void operator++(int); + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "../utils.h" + +template <class CharT> +void test() { + // operator ++() + { + auto iss = make_string_stream<CharT>("1 2 345 "); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + assert(*it == 1); + + std::same_as<decltype(it)&> decltype(auto) it2 = ++it; + assert(&it2 == &it); + assert(*it2 == 2); + + ++it2; + assert(*it2 == 345); + + ++it2; + assert(it2 == isv.end()); + } + + // operator ++(int) + { + auto iss = make_string_stream<CharT>("1 2 345 "); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + assert(*it == 1); + + static_assert(std::same_as<decltype(it++), void>); + it++; + assert(*it == 2); + } +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/member_types.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/member_types.compile.pass.cpp new file mode 100644 index 0000000..1e9924f --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/member_types.compile.pass.cpp @@ -0,0 +1,49 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// Member typedefs in istream_view<T>::<iterator>. + +#include <istream> +#include <ranges> + +#include "test_macros.h" + +template <class T> +concept HasIterCategory = requires { typename T::iterator_category; }; + +struct MemberIteratorCategory { + using iterator_category = std::input_iterator_tag; +}; +static_assert(HasIterCategory<MemberIteratorCategory>); + +template <class Val, class CharT> +void test() { + using Iter = std::ranges::iterator_t<std::ranges::basic_istream_view<Val, CharT>>; + static_assert(std::is_same_v<typename Iter::iterator_concept, std::input_iterator_tag>); + static_assert(std::is_same_v<typename Iter::difference_type, std::ptrdiff_t>); + static_assert(std::is_same_v<typename Iter::value_type, Val>); + static_assert(!HasIterCategory<Iter>); +} + +template <class CharT> +void testOne() { + test<int, CharT>(); + test<long, CharT>(); + test<double, CharT>(); + test<CharT, CharT>(); +} + +void test() { + testOne<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + testOne<wchar_t>(); +#endif +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/special_op.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/special_op.pass.cpp new file mode 100644 index 0000000..edcf6eb --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/iterator/special_op.pass.cpp @@ -0,0 +1,70 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// iterator(const iterator&) = delete; +// iterator(iterator&&) = default; +// iterator& operator=(const iterator&) = delete; +// iterator& operator=(iterator&&) = default; + +#include <cassert> +#include <ranges> +#include <sstream> + +#include "test_macros.h" +#include "../utils.h" + +template <class CharT> +using Iter = std::ranges::iterator_t<std::ranges::basic_istream_view<int, CharT>>; +static_assert(!std::copy_constructible<Iter<char>>); +static_assert(!std::is_copy_assignable_v<Iter<char>>); +static_assert(std::move_constructible<Iter<char>>); +static_assert(std::is_move_assignable_v<Iter<char>>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(!std::copy_constructible<Iter<wchar_t>>); +static_assert(!std::is_copy_assignable_v<Iter<wchar_t>>); +static_assert(std::move_constructible<Iter<wchar_t>>); +static_assert(std::is_move_assignable_v<Iter<wchar_t>>); +#endif + +template <class CharT> +void test() { + // test move constructor + { + auto iss = make_string_stream<CharT>("12 3"); + std::ranges::basic_istream_view<int, CharT> isv{iss}; + auto it = isv.begin(); + auto it2 = std::move(it); + assert(*it2 == 12); + } + + // test move assignment + { + auto iss1 = make_string_stream<CharT>("12 3"); + std::ranges::basic_istream_view<int, CharT> isv1{iss1}; + auto iss2 = make_string_stream<CharT>("45 6"); + std::ranges::basic_istream_view<int, CharT> isv2{iss2}; + + auto it1 = isv1.begin(); + assert(*it1 == 12); + it1 = isv2.begin(); + assert(*it1 == 45); + } +} + +int main(int, char**) { + test<char>(); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + test<wchar_t>(); +#endif + + return 0; +} diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/range.concept.compile.pass.cpp b/libcxx/test/std/ranges/range.factories/range.istream.view/range.concept.compile.pass.cpp new file mode 100644 index 0000000..9141632 --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/range.concept.compile.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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: no-localization +// UNSUPPORTED: c++03, c++11, c++14, c++17 + +// concept checking istream_view + +#include <istream> +#include <ranges> + +#include "test_macros.h" + +template <class Val, class CharT, class Traits = std::char_traits<CharT>> +concept HasIstreamView = requires { typename std::ranges::basic_istream_view<Val, CharT, Traits>; }; + +static_assert(HasIstreamView<int, char>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(HasIstreamView<int, wchar_t>); +#endif + +// Unmovable Val +struct Unmovable { + Unmovable() = default; + Unmovable(Unmovable&&) = delete; + template <class CharT> + friend std::basic_istream<CharT>& operator>>(std::basic_istream<CharT>& x, const Unmovable&) { + return x; + } +}; +static_assert(!HasIstreamView<Unmovable, char>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(!HasIstreamView<Unmovable, wchar_t>); +#endif + +// !default_initializable<Val> +struct NoDefaultCtor { + NoDefaultCtor(int) {} + friend std::istream& operator>>(std::istream& x, const NoDefaultCtor&) { return x; } +}; +static_assert(!HasIstreamView<NoDefaultCtor, char>); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(!HasIstreamView<NoDefaultCtor, wchar_t>); +#endif + +// !stream-extractable<Val, CharT, Traits> +struct Foo {}; +static_assert(!HasIstreamView<Foo, char>); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(!HasIstreamView<Foo, wchar_t>); +#endif + +template <class T> +concept OnlyInputRange = std::ranges::input_range<T> && !std::ranges::forward_range<T>; + +static_assert(OnlyInputRange<std::ranges::istream_view<int>>); +static_assert(OnlyInputRange<std::ranges::istream_view<long>>); +static_assert(OnlyInputRange<std::ranges::istream_view<double>>); +static_assert(OnlyInputRange<std::ranges::istream_view<char>>); + +#ifndef TEST_HAS_NO_WIDE_CHARACTERS +static_assert(OnlyInputRange<std::ranges::wistream_view<int>>); +static_assert(OnlyInputRange<std::ranges::wistream_view<long>>); +static_assert(OnlyInputRange<std::ranges::wistream_view<double>>); +static_assert(OnlyInputRange<std::ranges::wistream_view<wchar_t>>); +#endif diff --git a/libcxx/test/std/ranges/range.factories/range.istream.view/utils.h b/libcxx/test/std/ranges/range.factories/range.istream.view/utils.h new file mode 100644 index 0000000..ec6ed4da --- /dev/null +++ b/libcxx/test/std/ranges/range.factories/range.istream.view/utils.h @@ -0,0 +1,21 @@ +#ifndef TEST_STD_RANGES_RANGE_FACTORIES_RANGE_ISTREAM_UTILS_H +#define TEST_STD_RANGES_RANGE_FACTORIES_RANGE_ISTREAM_UTILS_H + +#include <sstream> +#include <string> + +template <class CharT, std::size_t N> +auto make_string(const char (&in)[N]) { + std::basic_string<CharT> r(N - 1, static_cast<CharT>(0)); + for (std::size_t i = 0; i < N - 1; ++i) { + r[i] = static_cast<CharT>(in[i]); + } + return r; +} + +template <class CharT, std::size_t N> +auto make_string_stream(const char (&in)[N]) { + return std::basic_istringstream<CharT>(make_string<CharT>(in)); +} + +#endif //TEST_STD_RANGES_RANGE_FACTORIES_RANGE_ISTREAM_UTILS_H |