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 @@ -17,7 +17,7 @@ | *no-throw-input-range* | *no-throw-forward-iterator* | *no-throw-forward-range*","| [iterator.concepts] -| [range.refinements]",Konstantin Varlamov,Not started +| [range.refinements]",Konstantin Varlamov,✅ `[specialized.algorithms] `_,"| ranges::uninitialized_default_construct | ranges::uninitialized_default_construct_n | ranges::uninitialized_value_construct diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -230,6 +230,7 @@ __memory/compressed_pair.h __memory/construct_at.h __memory/pointer_traits.h + __memory/ranges_uninitialized_algorithms.h __memory/raw_storage_iterator.h __memory/shared_ptr.h __memory/temporary_buffer.h diff --git a/libcxx/include/__memory/ranges_uninitialized_algorithms.h b/libcxx/include/__memory/ranges_uninitialized_algorithms.h new file mode 100644 --- /dev/null +++ b/libcxx/include/__memory/ranges_uninitialized_algorithms.h @@ -0,0 +1,62 @@ +// -*- 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___MEMORY_RANGES_UNINITIALIZED_ALGORITHMS_H +#define _LIBCPP___MEMORY_RANGES_UNINITIALIZED_ALGORITHMS_H + +#include <__config> +#include <__iterator/concepts.h> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +#if !defined(_LIBCPP_HAS_NO_RANGES) +namespace ranges { + +// [special.mem.concepts] + +template +concept __nothrow_input_iterator = + input_iterator<_Ip> && + // Not a proxy iterator. + is_lvalue_reference_v> && + same_as>, iter_value_t<_Ip>>; + +template +concept __nothrow_sentinel_for = sentinel_for<_Sp, _Ip>; + +template +concept __nothrow_input_range = + range<_Rp> && + __nothrow_input_iterator> && + __nothrow_sentinel_for, iterator_t<_Rp>>; + +template +concept __nothrow_forward_iterator = + __nothrow_input_iterator<_Ip> && + forward_iterator<_Ip> && + __nothrow_sentinel_for<_Ip, _Ip>; + +template +concept __nothrow_forward_range = + __nothrow_input_range<_Rp> && + __nothrow_forward_iterator>; + +} // namespace ranges +#endif // !defined(_LIBCPP_HAS_NO_RANGES) + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___MEMORY_RANGES_UNINITIALIZED_ALGORITHMS_H diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -671,6 +671,7 @@ #include <__memory/compressed_pair.h> #include <__memory/construct_at.h> #include <__memory/pointer_traits.h> +#include <__memory/ranges_uninitialized_algorithms.h> #include <__memory/raw_storage_iterator.h> #include <__memory/shared_ptr.h> #include <__memory/temporary_buffer.h> diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap --- a/libcxx/include/module.modulemap +++ b/libcxx/include/module.modulemap @@ -630,21 +630,22 @@ export * module __memory { - module addressof { private header "__memory/addressof.h" } - module allocation_guard { private header "__memory/allocation_guard.h" } - module allocator { private header "__memory/allocator.h" } - module allocator_arg_t { private header "__memory/allocator_arg_t.h" } - module allocator_traits { private header "__memory/allocator_traits.h" } - module auto_ptr { private header "__memory/auto_ptr.h" } - module compressed_pair { private header "__memory/compressed_pair.h" } - module construct_at { private header "__memory/construct_at.h" } - module pointer_traits { private header "__memory/pointer_traits.h" } - module raw_storage_iterator { private header "__memory/raw_storage_iterator.h" } - module shared_ptr { private header "__memory/shared_ptr.h" } - module temporary_buffer { private header "__memory/temporary_buffer.h" } - module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" } - module unique_ptr { private header "__memory/unique_ptr.h" } - module uses_allocator { private header "__memory/uses_allocator.h" } + module addressof { private header "__memory/addressof.h" } + module allocation_guard { private header "__memory/allocation_guard.h" } + module allocator { private header "__memory/allocator.h" } + module allocator_arg_t { private header "__memory/allocator_arg_t.h" } + module allocator_traits { private header "__memory/allocator_traits.h" } + module auto_ptr { private header "__memory/auto_ptr.h" } + module compressed_pair { private header "__memory/compressed_pair.h" } + module construct_at { private header "__memory/construct_at.h" } + module pointer_traits { private header "__memory/pointer_traits.h" } + module ranges_uninitialized_algorithms { private header "__memory/ranges_uninitialized_algorithms.h" } + module raw_storage_iterator { private header "__memory/raw_storage_iterator.h" } + module shared_ptr { private header "__memory/shared_ptr.h" } + module temporary_buffer { private header "__memory/temporary_buffer.h" } + module uninitialized_algorithms { private header "__memory/uninitialized_algorithms.h" } + module unique_ptr { private header "__memory/unique_ptr.h" } + module uses_allocator { private header "__memory/uses_allocator.h" } } } module mutex { diff --git a/libcxx/test/std/algorithms/specialized.algorithms/special.mem.concepts/special.mem.concepts.compile.pass.cpp b/libcxx/test/std/algorithms/specialized.algorithms/special.mem.concepts/special.mem.concepts.compile.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/std/algorithms/specialized.algorithms/special.mem.concepts/special.mem.concepts.compile.pass.cpp @@ -0,0 +1,78 @@ +//===----------------------------------------------------------------------===// +// +// 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 +// concept __nothrow_input_iterator; +// template +// concept __nothrow_sentinel_for; +// template +// concept __nothrow_input_range; +// template +// concept __nothrow_forward_iterator; +// template +// concept __nothrow_forward_range; + +#include +#include +#include + +#include "test_iterators.h" +#include "test_range.h" +#include "MoveOnly.h" + +using namespace iterator_mixins; + +using InputIterator = cpp20_input_iterator; +using OutputIterator = output_iterator; + +// __nothrow_input_iterator + +template +struct InputIterator_Proxy : MoveOnly, Incrementable>, HasIteratorConcept<> { + using value_type = T; + value_type operator*() const; +}; + +static_assert(std::ranges::__nothrow_input_iterator); +static_assert(!std::ranges::__nothrow_input_iterator); +static_assert(std::input_iterator>); +static_assert(!std::ranges::__nothrow_input_iterator>); + +// __nothrow_sentinel_for + +static_assert(std::ranges::__nothrow_sentinel_for); +static_assert(!std::ranges::__nothrow_sentinel_for); + +// __nothrow_input_range + +static_assert(std::ranges::__nothrow_input_range>); +static_assert(std::ranges::input_range>); +static_assert(!std::ranges::__nothrow_input_range>); + +// __nothrow_forward_iterator + +template +struct ForwardIterator_Proxy : Incrementable>, + EqualityComparable, HasIteratorConcept { + using value_type = T; + value_type operator*() const; +}; + +static_assert(std::ranges::__nothrow_forward_iterator>); +static_assert(std::forward_iterator>); +static_assert(!std::ranges::__nothrow_forward_iterator>); + +// __nothrow_forward_range + +static_assert(std::ranges::__nothrow_forward_range>); +static_assert(!std::ranges::__nothrow_forward_range>); +static_assert(std::ranges::forward_range>); +static_assert(!std::ranges::__nothrow_forward_range>); diff --git a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp --- a/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp +++ b/libcxx/test/std/iterators/iterator.requirements/iterator.concepts/iterator.concept.input/input_iterator.compile.pass.cpp @@ -15,109 +15,58 @@ #include #include "test_iterators.h" +#include "MoveOnly.h" -static_assert(std::input_iterator >); -static_assert(std::input_iterator >); - -struct no_explicit_iter_concept { - using value_type = int; - using difference_type = std::ptrdiff_t; - - no_explicit_iter_concept() = default; - - no_explicit_iter_concept(no_explicit_iter_concept&&) = default; - no_explicit_iter_concept& operator=(no_explicit_iter_concept&&) = default; - - no_explicit_iter_concept(no_explicit_iter_concept const&) = delete; - no_explicit_iter_concept& operator=(no_explicit_iter_concept const&) = delete; - - value_type operator*() const; - - no_explicit_iter_concept& operator++(); - void operator++(int); -}; -// ITER-CONCEPT is `random_access_iterator_tag` >:( -static_assert(std::input_iterator); +using namespace iterator_mixins; static_assert(std::input_iterator); static_assert(std::input_iterator); static_assert(std::input_iterator); static_assert(std::input_iterator); -struct not_weakly_incrementable { - using difference_type = std::ptrdiff_t; - using iterator_concept = std::input_iterator_tag; - - not_weakly_incrementable() = default; - - not_weakly_incrementable(not_weakly_incrementable&&) = default; - not_weakly_incrementable& operator=(not_weakly_incrementable&&) = default; - - not_weakly_incrementable(not_weakly_incrementable const&) = delete; - not_weakly_incrementable& operator=(not_weakly_incrementable const&) = delete; +static_assert(std::input_iterator >); +static_assert(std::input_iterator >); - int operator*() const; +// NoExplicitIterConcept - not_weakly_incrementable& operator++(); +struct NoExplicitIterConcept : MoveOnly, Incrementable, Readable<> { + using value_type = int; + using difference_type = std::ptrdiff_t; }; -static_assert(!std::input_or_output_iterator && - !std::input_iterator); -struct not_indirectly_readable { - using difference_type = std::ptrdiff_t; - using iterator_concept = std::input_iterator_tag; +// ITER-CONCEPT is `random_access_iterator_tag` >:( +static_assert(std::input_iterator); - not_indirectly_readable() = default; +// NotWeaklyIncrementable - not_indirectly_readable(not_indirectly_readable&&) = default; - not_indirectly_readable& operator=(not_indirectly_readable&&) = default; +struct NotWeaklyIncrementable : MoveOnly, PreIncrementableOnly, Readable<>, HasIteratorConcept<> { +}; - not_indirectly_readable(not_indirectly_readable const&) = delete; - not_indirectly_readable& operator=(not_indirectly_readable const&) = delete; +static_assert(!std::input_or_output_iterator && + !std::input_iterator); - int operator*() const; +// NotIndirectlyReadable - not_indirectly_readable& operator++(); +struct NotIndirectlyReadable : MoveOnly, Readable<>, HasIteratorConcept<> { + NotIndirectlyReadable& operator++(); void operator++(int); }; -static_assert(!std::indirectly_readable && !std::input_iterator); +static_assert(!std::indirectly_readable && !std::input_iterator); + +// BadIteratorCategory -struct bad_iterator_category { +struct BadIteratorCategory : MoveOnly, Incrementable, Readable<> { using value_type = int; using difference_type = std::ptrdiff_t; using iterator_category = void; - - bad_iterator_category() = default; - - bad_iterator_category(bad_iterator_category&&) = default; - bad_iterator_category& operator=(bad_iterator_category&&) = default; - - bad_iterator_category(bad_iterator_category const&) = delete; - bad_iterator_category& operator=(bad_iterator_category const&) = delete; - - value_type operator*() const; - - bad_iterator_category& operator++(); - void operator++(int); }; -static_assert(!std::input_iterator); +static_assert(!std::input_iterator); -struct bad_iterator_concept { - using value_type = int; +// BadIteratorConcept + +struct BadIteratorConcept : MoveOnly, Incrementable, Readable<> { using difference_type = std::ptrdiff_t; + using value_type = int; using iterator_concept = void*; - - bad_iterator_concept() = default; - - bad_iterator_concept(bad_iterator_concept&&) = default; - bad_iterator_concept& operator=(bad_iterator_concept&&) = default; - - bad_iterator_concept(bad_iterator_concept const&) = delete; - bad_iterator_concept& operator=(bad_iterator_concept const&) = delete; - - value_type operator*() const; - - bad_iterator_concept& operator++(); - void operator++(int); }; -static_assert(!std::input_iterator); +static_assert(!std::input_iterator); diff --git a/libcxx/test/support/test_iterators.h b/libcxx/test/support/test_iterators.h --- a/libcxx/test/support/test_iterators.h +++ b/libcxx/test/support/test_iterators.h @@ -626,6 +626,40 @@ const T *current_; }; +namespace iterator_mixins { + +template +struct PreIncrementableOnly { + T& operator++(); +}; + +template +struct PostIncrementableOnly { + T operator++(int); +}; + +template +struct Incrementable : PreIncrementableOnly, PostIncrementableOnly { +}; + +template +struct Readable { + T x = {}; + const T& operator*() const { return x; } +}; + +template +struct HasIteratorConcept { + using difference_type = std::ptrdiff_t; + using iterator_concept = Tag; +}; + +struct EqualityComparable { + bool operator==(const EqualityComparable&) const { return true; } +}; + +} // namespace iterator_mixins + #ifdef TEST_SUPPORTS_RANGES template