[libcxx-commits] [libcxx] 754ea6f - [libc++][ranges] Implement `uninitialized_value_construct{, _n}` and `uninitialized_fill{, _n}`.
Konstantin Varlamov via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Dec 20 00:24:44 PST 2021
Author: Konstantin Varlamov
Date: 2021-12-20T00:24:27-08:00
New Revision: 754ea6fd4d52f4699644a3c6dfc854a231c881c4
URL: https://github.com/llvm/llvm-project/commit/754ea6fd4d52f4699644a3c6dfc854a231c881c4
DIFF: https://github.com/llvm/llvm-project/commit/754ea6fd4d52f4699644a3c6dfc854a231c881c4.diff
LOG: [libc++][ranges] Implement `uninitialized_value_construct{,_n}` and `uninitialized_fill{,_n}`.
Also:
- refactor out `__voidify`;
- use the `destroy` algorithm internally;
- refactor out helper classes used in tests for `uninitialized_*`
algorithms.
Differential Revision: https://reviews.llvm.org/D115626
Added:
libcxx/include/__memory/voidify.h
libcxx/test/libcxx/diagnostics/detail.headers/memory/voidify.module.verify.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/buffer.h
libcxx/test/std/utilities/memory/specialized.algorithms/counted.h
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp
Modified:
libcxx/docs/Status/RangesAlgorithms.csv
libcxx/docs/Status/RangesPaper.csv
libcxx/include/CMakeLists.txt
libcxx/include/__memory/construct_at.h
libcxx/include/__memory/ranges_uninitialized_algorithms.h
libcxx/include/__memory/uninitialized_algorithms.h
libcxx/include/memory
libcxx/include/module.modulemap
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp
libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp
Removed:
################################################################################
diff --git a/libcxx/docs/Status/RangesAlgorithms.csv b/libcxx/docs/Status/RangesAlgorithms.csv
index 5e8cad6b96400..0d8beb37984c1 100644
--- a/libcxx/docs/Status/RangesAlgorithms.csv
+++ b/libcxx/docs/Status/RangesAlgorithms.csv
@@ -84,17 +84,17 @@ Permutation,pop_heap,Not assigned,n/a,Not started
Permutation,sort_heap,Not assigned,n/a,Not started
Permutation,prev_permutation,Not assigned,n/a,Not started
Permutation,next_permutation,Not assigned,n/a,Not started
-Uninitialised memory,uninitialized_copy,var-const,n/a,Not started
-Uninitialised memory,uninitialized_copy_n,var-const,n/a,Not started
-Uninitialised memory,uninitialized_fill,var-const,n/a,Not started
-Uninitialised memory,uninitialized_fill_n,var-const,n/a,Not started
-Uninitialised memory,uninitialized_move,var-const,n/a,Not started
-Uninitialised memory,uninitialized_move_n,var-const,n/a,Not started
-Uninitialised memory,uninitialized_default_construct,var-const,n/a,Not started
-Uninitialised memory,uninitialized_default_construct_n,var-const,n/a,Not started
-Uninitialised memory,uninitialized_value_construct,var-const,n/a,Not started
-Uninitialised memory,uninitialized_value_construct_n,var-const,n/a,Not started
-Uninitialised memory,destroy,var-const,n/a,Not started
-Uninitialised memory,destroy_n,var-const,n/a,Not started
-Uninitialised memory,destroy_at,var-const,n/a,Not started
-Uninitialised memory,construct_at,var-const,n/a,Not started
+Uninitialised memory,uninitialized_copy,Konstantin Varlamov,n/a,Not started
+Uninitialised memory,uninitialized_copy_n,Konstantin Varlamov,n/a,Not started
+Uninitialised memory,uninitialized_fill,Konstantin Varlamov,`D115626 <https://llvm.org/D115626>`_,✅
+Uninitialised memory,uninitialized_fill_n,Konstantin Varlamov,`D115626 <https://llvm.org/D115626>`_,✅
+Uninitialised memory,uninitialized_move,Konstantin Varlamov,n/a,Not started
+Uninitialised memory,uninitialized_move_n,Konstantin Varlamov,n/a,Not started
+Uninitialised memory,uninitialized_default_construct,Konstantin Varlamov,`D115315 <https://llvm.org/D115315>`_,✅
+Uninitialised memory,uninitialized_default_construct_n,Konstantin Varlamov,`D115315 <https://llvm.org/D115315>`_,✅
+Uninitialised memory,uninitialized_value_construct,Konstantin Varlamov,`D115626 <https://llvm.org/D115626>`_,✅
+Uninitialised memory,uninitialized_value_construct_n,Konstantin Varlamov,`D115626 <https://llvm.org/D115626>`_,✅
+Uninitialised memory,destroy,Konstantin Varlamov,n/a,Not started
+Uninitialised memory,destroy_n,Konstantin Varlamov,n/a,Not started
+Uninitialised memory,destroy_at,Konstantin Varlamov,n/a,Not started
+Uninitialised memory,construct_at,Konstantin Varlamov,n/a,Not started
diff --git a/libcxx/docs/Status/RangesPaper.csv b/libcxx/docs/Status/RangesPaper.csv
index 2cf510d6dcc23..ed1900bd12441 100644
--- a/libcxx/docs/Status/RangesPaper.csv
+++ b/libcxx/docs/Status/RangesPaper.csv
@@ -18,16 +18,16 @@ Section,Description,Dependencies,Assignee,Complete
| *nothrow-forward-iterator*
| *nothrow-forward-range*","| [iterator.concepts]
| [range.refinements]",Konstantin Varlamov,✅
-`[specialized.algorithms] <http://wg21.link/specialized.algorithms>`_,"| `ranges::uninitialized_default_construct <https://llvm.org/D115315>`
-| `ranges::uninitialized_default_construct_n <https://llvm.org/D115315>`
-| ranges::uninitialized_value_construct
-| ranges::uninitialized_value_construct_n
+`[specialized.algorithms] <http://wg21.link/specialized.algorithms>`_,"| `ranges::uninitialized_default_construct <https://llvm.org/D115315>`_
+| `ranges::uninitialized_default_construct_n <https://llvm.org/D115315>`_
+| `ranges::uninitialized_value_construct <https://llvm.org/D115626>`_
+| `ranges::uninitialized_value_construct_n <https://llvm.org/D115626>`_
| ranges::uninitialized_copy
| ranges::uninitialized_copy_n
| ranges::uninitialized_move
| ranges::uninitialized_move_n
-| ranges::uninitialized_fill
-| ranges::uninitialized_fill_n
+| `ranges::uninitialized_fill <https://llvm.org/D115626>`_
+| `ranges::uninitialized_fill_n <https://llvm.org/D115626>`_
| ranges::construct_at
| ranges::destroy
| ranges::destroy_at
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 0d4ddbf0a4777..e0801c7ee5226 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -238,6 +238,7 @@ set(files
__memory/uninitialized_algorithms.h
__memory/unique_ptr.h
__memory/uses_allocator.h
+ __memory/voidify.h
__mutex_base
__numeric/accumulate.h
__numeric/adjacent_
diff erence.h
diff --git a/libcxx/include/__memory/construct_at.h b/libcxx/include/__memory/construct_at.h
index 789677d7a6139..3b58451c5009f 100644
--- a/libcxx/include/__memory/construct_at.h
+++ b/libcxx/include/__memory/construct_at.h
@@ -41,44 +41,67 @@ constexpr _Tp* construct_at(_Tp* __location, _Args&& ...__args) {
// destroy_at
-#if _LIBCPP_STD_VER > 14
+// The internal functions are available regardless of the language version (with the exception of the `__destroy_at`
+// taking an array).
template <class _ForwardIterator>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
-void destroy(_ForwardIterator, _ForwardIterator);
+void __destroy(_ForwardIterator, _ForwardIterator);
-template <class _Tp, enable_if_t<!is_array_v<_Tp>, int> = 0>
+template <class _Tp, typename enable_if<!is_array<_Tp>::value, int>::type = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
-void destroy_at(_Tp* __loc) {
+void __destroy_at(_Tp* __loc) {
_LIBCPP_ASSERT(__loc, "null pointer given to destroy_at");
__loc->~_Tp();
}
+#if _LIBCPP_STD_VER > 17
+template <class _Tp, typename enable_if<is_array<_Tp>::value, int>::type = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
+void __destroy_at(_Tp* __loc) {
+ _LIBCPP_ASSERT(__loc, "null pointer given to destroy_at");
+ _VSTD::__destroy(_VSTD::begin(*__loc), _VSTD::end(*__loc));
+}
+#endif
+
+template <class _ForwardIterator>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
+void __destroy(_ForwardIterator __first, _ForwardIterator __last) {
+ for (; __first != __last; ++__first)
+ _VSTD::__destroy_at(_VSTD::addressof(*__first));
+}
+
+#if _LIBCPP_STD_VER > 14
+
+template <class _Tp, enable_if_t<!is_array_v<_Tp>, int> = 0>
+_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
+void destroy_at(_Tp* __loc) {
+ _VSTD::__destroy_at(__loc);
+}
+
#if _LIBCPP_STD_VER > 17
template <class _Tp, enable_if_t<is_array_v<_Tp>, int> = 0>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void destroy_at(_Tp* __loc) {
- _LIBCPP_ASSERT(__loc, "null pointer given to destroy_at");
- _VSTD::destroy(_VSTD::begin(*__loc), _VSTD::end(*__loc));
+ _VSTD::__destroy_at(__loc);
}
#endif
template <class _ForwardIterator>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
void destroy(_ForwardIterator __first, _ForwardIterator __last) {
- for (; __first != __last; ++__first)
- _VSTD::destroy_at(_VSTD::addressof(*__first));
+ _VSTD::__destroy(_VSTD::move(__first), _VSTD::move(__last));
}
template <class _ForwardIterator, class _Size>
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17
_ForwardIterator destroy_n(_ForwardIterator __first, _Size __n) {
for (; __n > 0; (void)++__first, --__n)
- _VSTD::destroy_at(_VSTD::addressof(*__first));
+ _VSTD::__destroy_at(_VSTD::addressof(*__first));
return __first;
}
-#endif
+#endif // _LIBCPP_STD_VER > 14
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/include/__memory/ranges_uninitialized_algorithms.h b/libcxx/include/__memory/ranges_uninitialized_algorithms.h
index 3b09a8cfaec67..6ec803806c05a 100644
--- a/libcxx/include/__memory/ranges_uninitialized_algorithms.h
+++ b/libcxx/include/__memory/ranges_uninitialized_algorithms.h
@@ -21,6 +21,7 @@
#include <__ranges/access.h>
#include <__ranges/concepts.h>
#include <__ranges/dangling.h>
+#include <__utility/move.h>
#include <type_traits>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
@@ -45,7 +46,8 @@ struct __fn final : private __function_like {
requires default_initializable<iter_value_t<_ForwardIterator>>
_ForwardIterator operator()(_ForwardIterator __first, _Sentinel __last) const {
using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
- return _VSTD::__uninitialized_default_construct<_ValueType>(__first, __last);
+ return _VSTD::__uninitialized_default_construct<_ValueType>(
+ _VSTD::move(__first), _VSTD::move(__last));
}
template <__nothrow_forward_range _ForwardRange>
@@ -56,7 +58,7 @@ struct __fn final : private __function_like {
};
-} // namespace __uninitialized_default_construct_ns
+} // namespace __uninitialized_default_construct
inline namespace __cpo {
inline constexpr auto uninitialized_default_construct =
@@ -77,18 +79,131 @@ struct __fn final : private __function_like {
_ForwardIterator operator()(_ForwardIterator __first,
iter_
diff erence_t<_ForwardIterator> __n) const {
using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
- return _VSTD::__uninitialized_default_construct_n<_ValueType>(__first, __n);
+ return _VSTD::__uninitialized_default_construct_n<_ValueType>(_VSTD::move(__first), __n);
}
};
-} // namespace __uninitialized_default_construct_n_ns
+} // namespace __uninitialized_default_construct_n
inline namespace __cpo {
inline constexpr auto uninitialized_default_construct_n =
__uninitialized_default_construct_n::__fn(__function_like::__tag());
} // namespace __cpo
+// uninitialized_value_construct
+
+namespace __uninitialized_value_construct {
+
+struct __fn final : private __function_like {
+
+ constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {}
+
+ template <__nothrow_forward_iterator _ForwardIterator,
+ __nothrow_sentinel_for<_ForwardIterator> _Sentinel>
+ requires default_initializable<iter_value_t<_ForwardIterator>>
+ _ForwardIterator operator()(_ForwardIterator __first, _Sentinel __last) const {
+ using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
+ return _VSTD::__uninitialized_value_construct<_ValueType>(
+ _VSTD::move(__first), _VSTD::move(__last));
+ }
+
+ template <__nothrow_forward_range _ForwardRange>
+ requires default_initializable<range_value_t<_ForwardRange>>
+ borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range) const {
+ return (*this)(ranges::begin(__range), ranges::end(__range));
+ }
+
+};
+
+} // namespace __uninitialized_value_construct
+
+inline namespace __cpo {
+inline constexpr auto uninitialized_value_construct =
+ __uninitialized_value_construct::__fn(__function_like::__tag());
+} // namespace __cpo
+
+// uninitialized_value_construct_n
+
+namespace __uninitialized_value_construct_n {
+
+struct __fn final : private __function_like {
+
+ constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {}
+
+ template <__nothrow_forward_iterator _ForwardIterator>
+ requires default_initializable<iter_value_t<_ForwardIterator>>
+ _ForwardIterator operator()(_ForwardIterator __first,
+ iter_
diff erence_t<_ForwardIterator> __n) const {
+ using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
+ return _VSTD::__uninitialized_value_construct_n<_ValueType>(_VSTD::move(__first), __n);
+ }
+
+};
+
+} // namespace __uninitialized_value_construct_n
+
+inline namespace __cpo {
+inline constexpr auto uninitialized_value_construct_n =
+ __uninitialized_value_construct_n::__fn(__function_like::__tag());
+} // namespace __cpo
+
+// uninitialized_fill
+
+namespace __uninitialized_fill {
+
+struct __fn final : private __function_like {
+
+ constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {}
+
+ template <__nothrow_forward_iterator _ForwardIterator,
+ __nothrow_sentinel_for<_ForwardIterator> _Sentinel,
+ class _Tp>
+ requires constructible_from<iter_value_t<_ForwardIterator>, const _Tp&>
+ _ForwardIterator operator()(_ForwardIterator __first, _Sentinel __last, const _Tp& __x) const {
+ using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
+ return _VSTD::__uninitialized_fill<_ValueType>(_VSTD::move(__first), _VSTD::move(__last), __x);
+ }
+
+ template <__nothrow_forward_range _ForwardRange, class _Tp>
+ requires constructible_from<range_value_t<_ForwardRange>, const _Tp&>
+ borrowed_iterator_t<_ForwardRange> operator()(_ForwardRange&& __range, const _Tp& __x) const {
+ return (*this)(ranges::begin(__range), ranges::end(__range), __x);
+ }
+
+};
+
+} // namespace __uninitialized_fil
+
+inline namespace __cpo {
+inline constexpr auto uninitialized_fill = __uninitialized_fill::__fn(__function_like::__tag());
+} // namespace __cpo
+
+// uninitialized_fill_n
+
+namespace __uninitialized_fill_n {
+
+struct __fn final : private __function_like {
+
+ constexpr explicit __fn(__tag __x) noexcept : __function_like(__x) {}
+
+ template <__nothrow_forward_iterator _ForwardIterator, class _Tp>
+ requires constructible_from<iter_value_t<_ForwardIterator>, const _Tp&>
+ _ForwardIterator operator()(_ForwardIterator __first,
+ iter_
diff erence_t<_ForwardIterator> __n,
+ const _Tp& __x) const {
+ using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
+ return _VSTD::__uninitialized_fill_n<_ValueType>(_VSTD::move(__first), __n, __x);
+ }
+
+};
+
+} // namespace __uninitialized_fill_n
+
+inline namespace __cpo {
+inline constexpr auto uninitialized_fill_n = __uninitialized_fill_n::__fn(__function_like::__tag());
+} // namespace __cpo
+
} // namespace ranges
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
diff --git a/libcxx/include/__memory/uninitialized_algorithms.h b/libcxx/include/__memory/uninitialized_algorithms.h
index 6f2e7abb18364..69132633a48e3 100644
--- a/libcxx/include/__memory/uninitialized_algorithms.h
+++ b/libcxx/include/__memory/uninitialized_algorithms.h
@@ -13,6 +13,7 @@
#include <__config>
#include <__memory/addressof.h>
#include <__memory/construct_at.h>
+#include <__memory/voidify.h>
#include <iterator>
#include <utility>
@@ -70,51 +71,70 @@ uninitialized_copy_n(_InputIterator __f, _Size __n, _ForwardIterator __r)
return __r;
}
-template <class _ForwardIterator, class _Tp>
-void
-uninitialized_fill(_ForwardIterator __f, _ForwardIterator __l, const _Tp& __x)
+// uninitialized_fill
+
+template <class _ValueType, class _ForwardIterator, class _Sentinel, class _Tp>
+inline _LIBCPP_HIDE_FROM_ABI
+_ForwardIterator __uninitialized_fill(_ForwardIterator __first, _Sentinel __last, const _Tp& __x)
{
- typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
+ _ForwardIterator __idx = __first;
#ifndef _LIBCPP_NO_EXCEPTIONS
- _ForwardIterator __s = __f;
try
{
#endif
- for (; __f != __l; ++__f)
- ::new ((void*)_VSTD::addressof(*__f)) value_type(__x);
+ for (; __idx != __last; ++__idx)
+ ::new (_VSTD::__voidify(*__idx)) _ValueType(__x);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- for (; __s != __f; ++__s)
- __s->~value_type();
+ _VSTD::__destroy(__first, __idx);
throw;
}
#endif
+
+ return __idx;
}
-template <class _ForwardIterator, class _Size, class _Tp>
-_ForwardIterator
-uninitialized_fill_n(_ForwardIterator __f, _Size __n, const _Tp& __x)
+template <class _ForwardIterator, class _Tp>
+inline _LIBCPP_HIDE_FROM_ABI
+void uninitialized_fill(_ForwardIterator __first, _ForwardIterator __last, const _Tp& __x)
{
- typedef typename iterator_traits<_ForwardIterator>::value_type value_type;
+ typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
+ (void)_VSTD::__uninitialized_fill<_ValueType>(__first, __last, __x);
+}
+
+// uninitialized_fill_n
+
+template <class _ValueType, class _ForwardIterator, class _Size, class _Tp>
+inline _LIBCPP_HIDE_FROM_ABI
+_ForwardIterator __uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
+{
+ _ForwardIterator __idx = __first;
#ifndef _LIBCPP_NO_EXCEPTIONS
- _ForwardIterator __s = __f;
try
{
#endif
- for (; __n > 0; ++__f, (void) --__n)
- ::new ((void*)_VSTD::addressof(*__f)) value_type(__x);
+ for (; __n > 0; ++__idx, (void) --__n)
+ ::new (_VSTD::__voidify(*__idx)) _ValueType(__x);
#ifndef _LIBCPP_NO_EXCEPTIONS
}
catch (...)
{
- for (; __s != __f; ++__s)
- __s->~value_type();
+ _VSTD::__destroy(__first, __idx);
throw;
}
#endif
- return __f;
+
+ return __idx;
+}
+
+template <class _ForwardIterator, class _Size, class _Tp>
+inline _LIBCPP_HIDE_FROM_ABI
+_ForwardIterator uninitialized_fill_n(_ForwardIterator __first, _Size __n, const _Tp& __x)
+{
+ typedef typename iterator_traits<_ForwardIterator>::value_type _ValueType;
+ return _VSTD::__uninitialized_fill_n<_ValueType>(__first, __n, __x);
}
#if _LIBCPP_STD_VER > 14
@@ -129,10 +149,10 @@ _ForwardIterator __uninitialized_default_construct(_ForwardIterator __first, _Se
try {
#endif
for (; __idx != __last; ++__idx)
- ::new ((void*)_VSTD::addressof(*__idx)) _ValueType;
+ ::new (_VSTD::__voidify(*__idx)) _ValueType;
#ifndef _LIBCPP_NO_EXCEPTIONS
} catch (...) {
- _VSTD::destroy(__first, __idx);
+ _VSTD::__destroy(__first, __idx);
throw;
}
#endif
@@ -141,10 +161,11 @@ _ForwardIterator __uninitialized_default_construct(_ForwardIterator __first, _Se
}
template <class _ForwardIterator>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_HIDE_FROM_ABI
void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) {
using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
- (void)_VSTD::__uninitialized_default_construct<_ValueType>(__first, __last);
+ (void)_VSTD::__uninitialized_default_construct<_ValueType>(
+ _VSTD::move(__first), _VSTD::move(__last));
}
// uninitialized_default_construct_n
@@ -157,10 +178,10 @@ _ForwardIterator __uninitialized_default_construct_n(_ForwardIterator __first, _
try {
#endif
for (; __n > 0; ++__idx, (void) --__n)
- ::new ((void*)_VSTD::addressof(*__idx)) _ValueType;
+ ::new (_VSTD::__voidify(*__idx)) _ValueType;
#ifndef _LIBCPP_NO_EXCEPTIONS
} catch (...) {
- _VSTD::destroy(__first, __idx);
+ _VSTD::__destroy(__first, __idx);
throw;
}
#endif
@@ -169,49 +190,68 @@ _ForwardIterator __uninitialized_default_construct_n(_ForwardIterator __first, _
}
template <class _ForwardIterator, class _Size>
-inline _LIBCPP_INLINE_VISIBILITY
+inline _LIBCPP_HIDE_FROM_ABI
_ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
- return _VSTD::__uninitialized_default_construct_n<_ValueType>(__first, __n);
+ return _VSTD::__uninitialized_default_construct_n<_ValueType>(_VSTD::move(__first), __n);
}
-template <class _ForwardIterator>
-inline _LIBCPP_INLINE_VISIBILITY
-void uninitialized_value_construct(_ForwardIterator __first, _ForwardIterator __last) {
- using _Vt = typename iterator_traits<_ForwardIterator>::value_type;
+// uninitialized_value_construct
+
+template <class _ValueType, class _ForwardIterator, class _Sentinel>
+inline _LIBCPP_HIDE_FROM_ABI
+_ForwardIterator __uninitialized_value_construct(_ForwardIterator __first, _Sentinel __last) {
auto __idx = __first;
#ifndef _LIBCPP_NO_EXCEPTIONS
try {
#endif
for (; __idx != __last; ++__idx)
- ::new ((void*)_VSTD::addressof(*__idx)) _Vt();
+ ::new (_VSTD::__voidify(*__idx)) _ValueType();
#ifndef _LIBCPP_NO_EXCEPTIONS
} catch (...) {
- _VSTD::destroy(__first, __idx);
+ _VSTD::__destroy(__first, __idx);
throw;
}
#endif
+
+ return __idx;
}
-template <class _ForwardIterator, class _Size>
-inline _LIBCPP_INLINE_VISIBILITY
-_ForwardIterator uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) {
- using _Vt = typename iterator_traits<_ForwardIterator>::value_type;
+template <class _ForwardIterator>
+inline _LIBCPP_HIDE_FROM_ABI
+void uninitialized_value_construct(_ForwardIterator __first, _ForwardIterator __last) {
+ using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
+ (void)_VSTD::__uninitialized_value_construct<_ValueType>(
+ _VSTD::move(__first), _VSTD::move(__last));
+}
+
+// uninitialized_value_construct_n
+
+template <class _ValueType, class _ForwardIterator, class _Size>
+inline _LIBCPP_HIDE_FROM_ABI
+_ForwardIterator __uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) {
auto __idx = __first;
#ifndef _LIBCPP_NO_EXCEPTIONS
try {
#endif
for (; __n > 0; ++__idx, (void) --__n)
- ::new ((void*)_VSTD::addressof(*__idx)) _Vt();
- return __idx;
+ ::new (_VSTD::__voidify(*__idx)) _ValueType();
#ifndef _LIBCPP_NO_EXCEPTIONS
} catch (...) {
- _VSTD::destroy(__first, __idx);
+ _VSTD::__destroy(__first, __idx);
throw;
}
#endif
+
+ return __idx;
}
+template <class _ForwardIterator, class _Size>
+inline _LIBCPP_HIDE_FROM_ABI
+_ForwardIterator uninitialized_value_construct_n(_ForwardIterator __first, _Size __n) {
+ using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
+ return __uninitialized_value_construct_n<_ValueType>(_VSTD::move(__first), __n);
+}
template <class _InputIt, class _ForwardIt>
inline _LIBCPP_INLINE_VISIBILITY
diff --git a/libcxx/include/__memory/voidify.h b/libcxx/include/__memory/voidify.h
new file mode 100644
index 0000000000000..3a65c0e83fb7f
--- /dev/null
+++ b/libcxx/include/__memory/voidify.h
@@ -0,0 +1,30 @@
+// -*- 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_VOIDIFY_H
+#define _LIBCPP___MEMORY_VOIDIFY_H
+
+#include <__config>
+#include <__memory/addressof.h>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+template <typename _Tp>
+_LIBCPP_ALWAYS_INLINE _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_AFTER_CXX17 void* __voidify(_Tp& __from) {
+ // Cast away cv-qualifiers to allow modifying elements of a range through const iterators.
+ return const_cast<void*>(static_cast<const volatile void*>(_VSTD::addressof(__from)));
+}
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP___MEMORY_VOIDIFY_H
diff --git a/libcxx/include/memory b/libcxx/include/memory
index 3898bdc9a9e38..3ed1530f2a756 100644
--- a/libcxx/include/memory
+++ b/libcxx/include/memory
@@ -188,10 +188,22 @@ uninitialized_copy_n(InputIterator first, Size n, ForwardIterator result);
template <class ForwardIterator, class T>
void uninitialized_fill(ForwardIterator first, ForwardIterator last, const T& x);
+template <nothrow-forward-iterator ForwardIterator, nothrow-sentinel-for<ForwardIterator> Sentinel, class T>
+ requires constructible_from<iter_value_t<ForwardIterator>, const T&>
+ForwardIterator ranges::uninitialized_fill(ForwardIterator first, Sentinel last, const T& x); // since C++20
+
+template <nothrow-forward-range ForwardRange, class T>
+ requires constructible_from<range_value_t<ForwardRange>, const T&>
+borrowed_iterator_t<ForwardRange> ranges::uninitialized_fill(ForwardRange&& range, const T& x); // since C++20
+
template <class ForwardIterator, class Size, class T>
ForwardIterator
uninitialized_fill_n(ForwardIterator first, Size n, const T& x);
+template <nothrow-forward-iterator ForwardIterator, class T>
+ requires constructible_from<iter_value_t<ForwardIterator>, const T&>
+ForwardIterator ranges::uninitialized_fill_n(ForwardIterator first, iter_
diff erence_t<ForwardIterator> n); // since C++20
+
template <class T, class ...Args>
constexpr T* construct_at(T* location, Args&& ...args); // since C++20
@@ -213,9 +225,21 @@ template <class InputIterator, class Size, class ForwardIterator>
template <class ForwardIterator>
void uninitialized_value_construct(ForwardIterator first, ForwardIterator last);
+template <nothrow-forward-iterator ForwardIterator, nothrow-sentinel-for<ForwardIterator> Sentinel>
+ requires default_initializable<iter_value_t<ForwardIterator>>
+ ForwardIterator ranges::uninitialized_value_construct(ForwardIterator first, Sentinel last); // since C++20
+
+template <nothrow-forward-range ForwardRange>
+ requires default_initializable<range_value_t<ForwardRange>>
+ borrowed_iterator_t<ForwardRange> ranges::uninitialized_value_construct(ForwardRange&& r); // since C++20
+
template <class ForwardIterator, class Size>
ForwardIterator uninitialized_value_construct_n(ForwardIterator first, Size n);
+template <nothrow-forward-iterator ForwardIterator>
+ requires default_initializable<iter_value_t<ForwardIterator>>
+ ForwardIterator ranges::uninitialized_value_construct_n(ForwardIterator first, iter_
diff erence_t<ForwardIterator> n); // since C++20
+
template <class ForwardIterator>
void uninitialized_default_construct(ForwardIterator first, ForwardIterator last);
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index 1cd5c837e6299..12e0a15f52f58 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -650,6 +650,7 @@ module std [system] {
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 voidify { private header "__memory/voidify.h" }
}
}
module mutex {
diff --git a/libcxx/test/libcxx/diagnostics/detail.headers/memory/voidify.module.verify.cpp b/libcxx/test/libcxx/diagnostics/detail.headers/memory/voidify.module.verify.cpp
new file mode 100644
index 0000000000000..a8fa2dd399132
--- /dev/null
+++ b/libcxx/test/libcxx/diagnostics/detail.headers/memory/voidify.module.verify.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: modules-build
+
+// WARNING: This test was generated by 'generate_private_header_tests.py'
+// and should not be edited manually.
+
+// expected-error@*:* {{use of private header from outside its module: '__memory/voidify.h'}}
+#include <__memory/voidify.h>
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/buffer.h b/libcxx/test/std/utilities/memory/specialized.algorithms/buffer.h
new file mode 100644
index 0000000000000..1114fdc68e724
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/buffer.h
@@ -0,0 +1,25 @@
+// -*- 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_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_BUFFER_H
+#define LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_BUFFER_H
+
+template <typename T, int N>
+struct Buffer {
+ alignas(T) char buffer[sizeof(T) * N] = {};
+
+ T* begin() { return reinterpret_cast<T*>(buffer); }
+ T* end() { return begin() + N; }
+ const T* cbegin() const { return reinterpret_cast<const T*>(buffer); }
+ const T* cend() const { return cbegin() + N; }
+
+ constexpr int size() const { return N; }
+};
+
+#endif // LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_BUFFER_H
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/counted.h b/libcxx/test/std/utilities/memory/specialized.algorithms/counted.h
new file mode 100644
index 0000000000000..384fa7d78f4b9
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/counted.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_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_COUNTED_H
+#define LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_COUNTED_H
+
+#include "test_macros.h"
+
+struct Counted {
+ static int current_objects;
+ static int total_objects;
+ static int throw_on;
+
+ int value;
+
+ explicit Counted() {
+ check_throw();
+ increase_counters();
+ }
+
+ explicit Counted(int v) : value(v) {
+ check_throw();
+ increase_counters();
+ }
+
+ ~Counted() { --current_objects; }
+
+ static void reset() {
+ current_objects = total_objects = 0;
+ throw_on = -1;
+ }
+
+ Counted(const Counted& rhs) : value(rhs.value) {
+ check_throw();
+ increase_counters();
+ }
+
+ friend void operator&(Counted) = delete;
+
+private:
+ void check_throw() {
+ if (throw_on == total_objects) {
+ TEST_THROW(1);
+ }
+ }
+
+ void increase_counters() {
+ ++current_objects;
+ ++total_objects;
+ }
+};
+int Counted::current_objects = 0;
+int Counted::total_objects = 0;
+int Counted::throw_on = -1;
+
+#endif // LIBCPP_TEST_STD_UTILITIES_MEMORY_SPECIALIZED_ALGORITHMS_COUNTED_H
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp
index 8552850fa3d67..04ee5b8e4d6eb 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct.pass.cpp
@@ -25,47 +25,11 @@
#include <ranges>
#include <type_traits>
+#include "../buffer.h"
+#include "../counted.h"
#include "test_macros.h"
#include "test_iterators.h"
-struct Counted {
- static int current_objects;
- static int total_objects;
- static int throw_on;
-
- explicit Counted() {
- if (throw_on == total_objects) {
- TEST_THROW(1);
- }
-
- ++current_objects;
- ++total_objects;
- }
-
- ~Counted() { --current_objects; }
-
- static void reset() {
- current_objects = total_objects = 0;
- throw_on = -1;
- }
-
- Counted(Counted const&) = delete;
- friend void operator&(Counted) = delete;
-};
-int Counted::current_objects = 0;
-int Counted::total_objects = 0;
-int Counted::throw_on = -1;
-
-template <typename T, int N>
-struct Buffer {
- alignas(T) char buffer[sizeof(T) * N] = {};
-
- T* begin() { return reinterpret_cast<T*>(buffer); }
- T* end() { return begin() + N; }
- const T* cbegin() const { return reinterpret_cast<const T*>(buffer); }
- const T* cend() const { return cbegin() + N; }
-};
-
// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
// implementations are allowed to use a
diff erent mechanism to achieve this effect, so this check is
// libc++-specific.
@@ -145,8 +109,7 @@ int main(int, char**) {
constexpr int N = 3;
Buffer<Counted, 5> buf;
- auto counted_range = std::views::counted(buf.begin(), N);
- std::ranges::uninitialized_default_construct(counted_range);
+ std::ranges::uninitialized_default_construct(std::views::counted(buf.begin(), N));
assert(Counted::current_objects == N);
assert(Counted::total_objects == N);
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp
index 742b16e9cc030..904366fe315c4 100644
--- a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.default/ranges_uninitialized_default_construct_n.pass.cpp
@@ -20,47 +20,11 @@
#include <memory>
#include <ranges>
+#include "../buffer.h"
+#include "../counted.h"
#include "test_macros.h"
#include "test_iterators.h"
-struct Counted {
- static int current_objects;
- static int total_objects;
- static int throw_on;
-
- explicit Counted() {
- if (throw_on == total_objects) {
- TEST_THROW(1);
- }
-
- ++current_objects;
- ++total_objects;
- }
-
- ~Counted() { --current_objects; }
-
- static void reset() {
- current_objects = total_objects = 0;
- throw_on = -1;
- }
-
- Counted(Counted const&) = delete;
- friend void operator&(Counted) = delete;
-};
-int Counted::current_objects = 0;
-int Counted::total_objects = 0;
-int Counted::throw_on = -1;
-
-template <typename T, int N>
-struct Buffer {
- alignas(T) char buffer[sizeof(T) * N] = {};
-
- T* begin() { return reinterpret_cast<T*>(buffer); }
- T* end() { return begin() + N; }
- const T* cbegin() const { return reinterpret_cast<const T*>(buffer); }
- const T* cend() const { return cbegin() + N; }
-};
-
// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
// implementations are allowed to use a
diff erent mechanism to achieve this effect, so this check is
// libc++-specific.
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp
new file mode 100644
index 0000000000000..cc89c69514b93
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct.pass.cpp
@@ -0,0 +1,213 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, libcpp-has-no-incomplete-ranges
+
+// <memory>
+
+// template <nothrow-forward-iterator ForwardIterator, nothrow-sentinel-for<ForwardIterator> Sentinel>
+// requires default_initializable<iter_value_t<ForwardIterator>>
+// ForwardIterator ranges::uninitialized_value_construct(ForwardIterator first, Sentinel last);
+//
+// template <nothrow-forward-range ForwardRange>
+// requires default_initializable<range_value_t<ForwardRange>>
+// borrowed_iterator_t<ForwardRange> ranges::uninitialized_value_construct(ForwardRange&& range);
+
+#include <cassert>
+#include <iterator>
+#include <memory>
+#include <ranges>
+#include <type_traits>
+
+#include "../buffer.h"
+#include "../counted.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
+// implementations are allowed to use a
diff erent mechanism to achieve this effect, so this check is
+// libc++-specific.
+LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_value_construct)>);
+
+struct NotDefaultCtrable {
+ NotDefaultCtrable() = delete;
+};
+static_assert(
+ !std::is_invocable_v<decltype(std::ranges::uninitialized_value_construct), NotDefaultCtrable*, NotDefaultCtrable*>);
+
+int main(int, char**) {
+ // An empty range -- no default constructors should be invoked.
+ {
+ Buffer<Counted, 1> buf;
+
+ std::ranges::uninitialized_value_construct(buf.begin(), buf.begin());
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+
+ std::ranges::uninitialized_value_construct(std::ranges::empty_view<Counted>());
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+
+ forward_iterator<Counted*> it(buf.begin());
+ auto range = std::ranges::subrange(it, sentinel_wrapper<forward_iterator<Counted*>>(it));
+ std::ranges::uninitialized_value_construct(range.begin(), range.end());
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+
+ std::ranges::uninitialized_value_construct(range);
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+ }
+
+ // A range containing several objects, (iter, sentinel) overload.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ std::ranges::uninitialized_value_construct(buf.begin(), buf.end());
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ // A range containing several objects, (range) overload.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ auto range = std::ranges::subrange(buf.begin(), buf.end());
+ std::ranges::uninitialized_value_construct(range);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ // Using `counted_iterator`.
+ {
+ constexpr int N = 3;
+ Buffer<Counted, 5> buf;
+
+ std::ranges::uninitialized_value_construct(std::counted_iterator(buf.begin(), N), std::default_sentinel);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+
+ std::destroy(buf.begin(), buf.begin() + N);
+ Counted::reset();
+ }
+
+ // Using `views::counted`.
+ {
+ constexpr int N = 3;
+ Buffer<Counted, 5> buf;
+
+ std::ranges::uninitialized_value_construct(std::views::counted(buf.begin(), N));
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+
+ std::destroy(buf.begin(), buf.begin() + N);
+ Counted::reset();
+ }
+
+ // Using `reverse_view`.
+ {
+ constexpr int N = 3;
+ Buffer<Counted, 5> buf;
+
+ auto range = std::ranges::subrange(buf.begin(), buf.begin() + N);
+ std::ranges::uninitialized_value_construct(std::ranges::reverse_view(range));
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+
+ std::destroy(buf.begin(), buf.begin() + N);
+ Counted::reset();
+ }
+
+ // Any existing values should be overwritten by value constructors.
+ {
+ constexpr int N = 5;
+ int buffer[N] = {42, 42, 42, 42, 42};
+
+ std::ranges::uninitialized_value_construct(buffer, buffer + 1);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == 42);
+
+ std::ranges::uninitialized_value_construct(buffer, buffer + N);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == 0);
+ assert(buffer[2] == 0);
+ assert(buffer[3] == 0);
+ assert(buffer[4] == 0);
+ }
+
+ // An exception is thrown while objects are being created -- the existing objects should stay
+ // valid. (iterator, sentinel) overload.
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ {
+ Buffer<Counted, 5> buf;
+
+ Counted::throw_on = 3; // When constructing the fourth object (counting from one).
+ try {
+ std::ranges::uninitialized_value_construct(buf.begin(), buf.end());
+ } catch (...) {
+ }
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 3);
+ std::destroy(buf.begin(), buf.begin() + Counted::total_objects);
+ Counted::reset();
+ }
+
+ // An exception is thrown while objects are being created -- the existing objects should stay
+ // valid. (range) overload.
+ {
+ Buffer<Counted, 5> buf;
+
+ Counted::throw_on = 3; // When constructing the fourth object.
+ try {
+ auto range = std::ranges::subrange(buf.begin(), buf.end());
+ std::ranges::uninitialized_value_construct(range);
+ } catch (...) {
+ }
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 3);
+ std::destroy(buf.begin(), buf.begin() + Counted::total_objects);
+ Counted::reset();
+ }
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+ // Works with const iterators, (iter, sentinel) overload.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ std::ranges::uninitialized_value_construct(buf.cbegin(), buf.cend());
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ // Works with const iterators, (range) overload.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ auto range = std::ranges::subrange(buf.cbegin(), buf.cend());
+ std::ranges::uninitialized_value_construct(range);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp
new file mode 100644
index 0000000000000..3207f286d14b7
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.construct.value/ranges_uninitialized_value_construct_n.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, libcpp-has-no-incomplete-ranges
+
+// <memory>
+
+// template <nothrow-forward-iterator ForwardIterator>
+// requires default_initializable<iter_value_t<ForwardIterator>>
+// ForwardIterator ranges::uninitialized_value_construct_n(ForwardIterator first,
+// iter_
diff erence_t<ForwardIterator> n);
+
+#include <cassert>
+#include <memory>
+#include <ranges>
+
+#include "../buffer.h"
+#include "../counted.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
+// implementations are allowed to use a
diff erent mechanism to achieve this effect, so this check is
+// libc++-specific.
+LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_value_construct_n)>);
+
+struct NotDefaultCtrable {
+ NotDefaultCtrable() = delete;
+};
+static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_value_construct_n), NotDefaultCtrable*, int>);
+
+int main(int, char**) {
+ // An empty range -- no default constructors should be invoked.
+ {
+ Buffer<Counted, 1> buf;
+
+ std::ranges::uninitialized_value_construct_n(buf.begin(), 0);
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+ }
+
+ // A range containing several objects.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ std::ranges::uninitialized_value_construct_n(buf.begin(), N);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ // Any existing values should be overwritten by value constructors.
+ {
+ constexpr int N = 5;
+ int buffer[N] = {42, 42, 42, 42, 42};
+
+ std::ranges::uninitialized_value_construct_n(buffer, 1);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == 42);
+
+ std::ranges::uninitialized_value_construct_n(buffer, N);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == 0);
+ assert(buffer[2] == 0);
+ assert(buffer[3] == 0);
+ assert(buffer[4] == 0);
+ }
+
+ // An exception is thrown while objects are being created -- the existing objects should stay
+ // valid.
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ Counted::throw_on = 3; // When constructing the fourth object (counting from one).
+ try {
+ std::ranges::uninitialized_value_construct_n(buf.begin(), N);
+ } catch (...) {
+ }
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 3);
+ std::destroy(buf.begin(), buf.begin() + Counted::total_objects);
+ Counted::reset();
+ }
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+ // Works with const iterators.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ std::ranges::uninitialized_value_construct_n(buf.cbegin(), N);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp
new file mode 100644
index 0000000000000..a93ab532f2cea
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill.n/ranges_uninitialized_fill_n.pass.cpp
@@ -0,0 +1,120 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, libcpp-has-no-incomplete-ranges
+
+// <memory>
+
+// template <nothrow-forward-iterator ForwardIterator, class T>
+// requires constructible_from<iter_value_t<ForwardIterator>, const T&>
+// ForwardIterator ranges::uninitialized_fill_n(ForwardIterator first, iter_
diff erence_t<ForwardIterator> n);
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <memory>
+#include <ranges>
+#include <type_traits>
+
+#include "../buffer.h"
+#include "../counted.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
+// implementations are allowed to use a
diff erent mechanism to achieve this effect, so this check is
+// libc++-specific.
+LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_fill_n)>);
+
+struct NotConvertibleFromInt {};
+static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_fill_n), NotConvertibleFromInt*,
+ NotConvertibleFromInt*, int>);
+
+int main(int, char**) {
+ constexpr int value = 42;
+ Counted x(value);
+ Counted::reset();
+ auto pred = [](const Counted& e) { return e.value == value; };
+
+ // An empty range -- no default constructors should be invoked.
+ {
+ Buffer<Counted, 1> buf;
+
+ std::ranges::uninitialized_fill_n(buf.begin(), 0, x);
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+ }
+
+ // A range containing several objects.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ std::ranges::uninitialized_fill_n(buf.begin(), N, x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.end(), pred));
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ // Any existing values should be overwritten by value constructors.
+ {
+ constexpr int N = 5;
+ int buffer[N] = {value, value, value, value, value};
+
+ std::ranges::uninitialized_fill_n(buffer, 1, 0);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == value);
+
+ std::ranges::uninitialized_fill_n(buffer, N, 0);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == 0);
+ assert(buffer[2] == 0);
+ assert(buffer[3] == 0);
+ assert(buffer[4] == 0);
+ }
+
+ // An exception is thrown while objects are being created -- the existing objects should stay
+ // valid. (iterator, sentinel) overload.
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ Counted::throw_on = 3; // When constructing the fourth object.
+ try {
+ std::ranges::uninitialized_fill_n(buf.begin(), N, x);
+ } catch (...) {
+ }
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 3);
+
+ std::destroy(buf.begin(), buf.begin() + 3);
+ Counted::reset();
+ }
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+ // Works with const iterators.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ std::ranges::uninitialized_fill_n(buf.cbegin(), N, x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.end(), pred));
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp
new file mode 100644
index 0000000000000..d9135a036eebb
--- /dev/null
+++ b/libcxx/test/std/utilities/memory/specialized.algorithms/uninitialized.fill/ranges_uninitialized_fill.pass.cpp
@@ -0,0 +1,232 @@
+//===----------------------------------------------------------------------===//
+//
+// 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, libcpp-has-no-incomplete-ranges
+
+// <memory>
+
+// template <nothrow-forward-iterator ForwardIterator, nothrow-sentinel-for<ForwardIterator> Sentinel, class T>
+// requires constructible_from<iter_value_t<ForwardIterator>, const T&>
+// ForwardIterator ranges::uninitialized_fill(ForwardIterator first, Sentinel last, const T& x);
+//
+// template <nothrow-forward-range ForwardRange, class T>
+// requires constructible_from<range_value_t<ForwardRange>, const T&>
+// borrowed_iterator_t<ForwardRange> ranges::uninitialized_fill(ForwardRange&& range, const T& x);
+
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <memory>
+#include <ranges>
+#include <type_traits>
+
+#include "../buffer.h"
+#include "../counted.h"
+#include "test_macros.h"
+#include "test_iterators.h"
+
+// Because this is a variable and not a function, it's guaranteed that ADL won't be used. However,
+// implementations are allowed to use a
diff erent mechanism to achieve this effect, so this check is
+// libc++-specific.
+LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_fill)>);
+
+struct NotConvertibleFromInt {};
+static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_fill), NotConvertibleFromInt*,
+ NotConvertibleFromInt*, int>);
+
+int main(int, char**) {
+ constexpr int value = 42;
+ Counted x(value);
+ Counted::reset();
+ auto pred = [](const Counted& e) { return e.value == value; };
+
+ // An empty range -- no default constructors should be invoked.
+ {
+ Buffer<Counted, 1> buf;
+
+ std::ranges::uninitialized_fill(buf.begin(), buf.begin(), x);
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+
+ std::ranges::uninitialized_fill(std::ranges::empty_view<Counted>(), x);
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+
+ forward_iterator<Counted*> it(buf.begin());
+ auto range = std::ranges::subrange(it, sentinel_wrapper<forward_iterator<Counted*>>(it));
+ std::ranges::uninitialized_fill(range.begin(), range.end(), x);
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+ Counted::reset();
+
+ std::ranges::uninitialized_fill(range, x);
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == 0);
+ Counted::reset();
+ }
+
+ // A range containing several objects, (iter, sentinel) overload.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ std::ranges::uninitialized_fill(buf.begin(), buf.end(), x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.end(), pred));
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ // A range containing several objects, (range) overload.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ auto range = std::ranges::subrange(buf.begin(), buf.end());
+ std::ranges::uninitialized_fill(range, x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.end(), pred));
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ // Using `counted_iterator`.
+ {
+ constexpr int N = 3;
+ Buffer<Counted, 5> buf;
+
+ std::ranges::uninitialized_fill(std::counted_iterator(buf.begin(), N), std::default_sentinel, x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.begin() + N, pred));
+
+ std::destroy(buf.begin(), buf.begin() + N);
+ Counted::reset();
+ }
+
+ // Using `views::counted`.
+ {
+ constexpr int N = 3;
+ Buffer<Counted, 5> buf;
+
+ std::ranges::uninitialized_fill(std::views::counted(buf.begin(), N), x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.begin() + N, pred));
+
+ std::destroy(buf.begin(), buf.begin() + N);
+ Counted::reset();
+ }
+
+ // Using `reverse_view`.
+ {
+ constexpr int N = 3;
+ Buffer<Counted, 5> buf;
+
+ auto range = std::ranges::subrange(buf.begin(), buf.begin() + N);
+ std::ranges::uninitialized_fill(std::ranges::reverse_view(range), x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.begin() + N, pred));
+
+ std::destroy(buf.begin(), buf.begin() + N);
+ Counted::reset();
+ }
+
+ // Any existing values should be overwritten by value constructors.
+ {
+ constexpr int N = 5;
+ int buffer[N] = {value, value, value, value, value};
+
+ std::ranges::uninitialized_fill(buffer, buffer + 1, 0);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == value);
+
+ std::ranges::uninitialized_fill(buffer, buffer + N, 0);
+ assert(buffer[0] == 0);
+ assert(buffer[1] == 0);
+ assert(buffer[2] == 0);
+ assert(buffer[3] == 0);
+ assert(buffer[4] == 0);
+ }
+
+ // An exception is thrown while objects are being created -- the existing objects should stay
+ // valid. (iterator, sentinel) overload.
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ {
+ constexpr int N = 3;
+ Buffer<Counted, 5> buf;
+
+ Counted::throw_on = N; // When constructing the fourth object.
+ try {
+ std::ranges::uninitialized_fill(buf.begin(), buf.end(), x);
+ } catch (...) {
+ }
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == N);
+
+ std::destroy(buf.begin(), buf.begin() + N);
+ Counted::reset();
+ }
+
+ // An exception is thrown while objects are being created -- the existing objects should stay
+ // valid. (range) overload.
+ {
+ constexpr int N = 3;
+ Buffer<Counted, 5> buf;
+
+ Counted::throw_on = N; // When constructing the fourth object.
+ try {
+ auto range = std::ranges::subrange(buf.begin(), buf.end());
+ std::ranges::uninitialized_fill(range, x);
+ } catch (...) {
+ }
+ assert(Counted::current_objects == 0);
+ assert(Counted::total_objects == N);
+
+ std::destroy(buf.begin(), buf.begin() + N);
+ Counted::reset();
+ }
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+ // Works with const iterators, (iter, sentinel) overload.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ std::ranges::uninitialized_fill(buf.cbegin(), buf.cend(), x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.end(), pred));
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ // Works with const iterators, (range) overload.
+ {
+ constexpr int N = 5;
+ Buffer<Counted, N> buf;
+
+ auto range = std::ranges::subrange(buf.cbegin(), buf.cend());
+ std::ranges::uninitialized_fill(range, x);
+ assert(Counted::current_objects == N);
+ assert(Counted::total_objects == N);
+ assert(std::all_of(buf.begin(), buf.end(), pred));
+
+ std::destroy(buf.begin(), buf.end());
+ Counted::reset();
+ }
+
+ return 0;
+}
More information about the libcxx-commits
mailing list