mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-12-27 10:18:36 +00:00
[libc++][ranges] Implement ranges::uninitialized_default_construct{,_n}.
Defined in [`specialized.algorithms`](wg21.link/specialized.algorithms). Also: - refactor the existing non-range implementation so that most of it can be shared between the range-based and non-range-based algorithms; - remove an existing test for the non-range version of `uninitialized_default_construct{,_n}` that likely triggered undefined behavior (it read the values of built-ins after default-initializing them, essentially reading uninitialized memory). Reviewed By: #libc, Quuxplusone, ldionne Differential Revision: https://reviews.llvm.org/D115315
This commit is contained in:
parent
624f12d34f
commit
3f630cff65
@ -12,14 +12,14 @@ Section,Description,Dependencies,Assignee,Complete
|
||||
| `iter_difference_t <https://llvm.org/D99863>`_",,Christopher Di Bella,✅
|
||||
`[iterator.traits] <http://wg21.link/iterator.traits>`_,`Updates to iterator_traits <https://llvm.org/D99855>`_,"| indirectly_readable_traits
|
||||
| incrementable_traits",Christopher Di Bella,✅
|
||||
`[special.mem.concepts] <http://wg21.link/special.mem.concepts>`_,"| *no-throw-input-iterator*
|
||||
| *no-throw-sentinel-for*
|
||||
| *no-throw-input-range*
|
||||
| *no-throw-forward-iterator*
|
||||
| *no-throw-forward-range*","| [iterator.concepts]
|
||||
`[special.mem.concepts] <http://wg21.link/special.mem.concepts>`_,"| *nothrow-input-iterator*
|
||||
| *nothrow-sentinel-for*
|
||||
| *nothrow-input-range*
|
||||
| *nothrow-forward-iterator*
|
||||
| *nothrow-forward-range*","| [iterator.concepts]
|
||||
| [range.refinements]",Konstantin Varlamov,✅
|
||||
`[specialized.algorithms] <http://wg21.link/specialized.algorithms>`_,"| ranges::uninitialized_default_construct
|
||||
| ranges::uninitialized_default_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
|
||||
| ranges::uninitialized_value_construct_n
|
||||
| ranges::uninitialized_copy
|
||||
@ -31,7 +31,7 @@ Section,Description,Dependencies,Assignee,Complete
|
||||
| ranges::construct_at
|
||||
| ranges::destroy
|
||||
| ranges::destroy_at
|
||||
| ranges::destroy_n",[special.mem.concepts],Konstantin Varlamov,Not started
|
||||
| ranges::destroy_n",[special.mem.concepts],Konstantin Varlamov,In progress
|
||||
[strings],Adds begin/end and updates const_iterator.,[iterator.concepts],Unassigned,Not started
|
||||
[views.span],Same as [strings],[iterator.concepts],Unassigned,Not started
|
||||
`[iterator.cust.move] <http://wg21.link/iterator.cust.move>`_,`ranges::iter_move <https://llvm.org/D99873>`_,,Zoe Carver,✅
|
||||
|
|
@ -231,6 +231,7 @@ set(files
|
||||
__memory/concepts.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
|
||||
|
@ -69,6 +69,7 @@ void advance(_InputIter& __i, _Distance __orig_n) {
|
||||
|
||||
namespace ranges {
|
||||
// [range.iter.op.advance]
|
||||
// TODO(varconst): rename `__advance_fn` to `__fn`.
|
||||
struct __advance_fn final : private __function_like {
|
||||
private:
|
||||
template <class _Tp>
|
||||
|
@ -39,6 +39,7 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
#if !defined(_LIBCPP_HAS_NO_RANGES)
|
||||
|
||||
namespace ranges {
|
||||
// TODO(varconst): rename `__next_fn` to `__fn`.
|
||||
struct __next_fn final : private __function_like {
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr explicit __next_fn(__tag __x) noexcept : __function_like(__x) {}
|
||||
|
@ -38,6 +38,7 @@ inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX14
|
||||
#if !defined(_LIBCPP_HAS_NO_RANGES)
|
||||
|
||||
namespace ranges {
|
||||
// TODO(varconst): rename `__prev_fn` to `__fn`.
|
||||
struct __prev_fn final : private __function_like {
|
||||
_LIBCPP_HIDE_FROM_ABI
|
||||
constexpr explicit __prev_fn(__tag __x) noexcept : __function_like(__x) {}
|
||||
|
97
libcxx/include/__memory/ranges_uninitialized_algorithms.h
Normal file
97
libcxx/include/__memory/ranges_uninitialized_algorithms.h
Normal file
@ -0,0 +1,97 @@
|
||||
// -*- 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 <__concepts/constructible.h>
|
||||
#include <__config>
|
||||
#include <__function_like.h>
|
||||
#include <__iterator/incrementable_traits.h>
|
||||
#include <__iterator/iterator_traits.h>
|
||||
#include <__iterator/readable_traits.h>
|
||||
#include <__memory/concepts.h>
|
||||
#include <__memory/uninitialized_algorithms.h>
|
||||
#include <__ranges/access.h>
|
||||
#include <__ranges/concepts.h>
|
||||
#include <__ranges/dangling.h>
|
||||
#include <type_traits>
|
||||
|
||||
#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 {
|
||||
|
||||
// uninitialized_default_construct
|
||||
|
||||
namespace __uninitialized_default_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_default_construct<_ValueType>(__first, __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_default_construct_ns
|
||||
|
||||
inline namespace __cpo {
|
||||
inline constexpr auto uninitialized_default_construct =
|
||||
__uninitialized_default_construct::__fn(__function_like::__tag());
|
||||
} // namespace __cpo
|
||||
|
||||
// uninitialized_default_construct_n
|
||||
|
||||
namespace __uninitialized_default_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_difference_t<_ForwardIterator> __n) const {
|
||||
using _ValueType = remove_reference_t<iter_reference_t<_ForwardIterator>>;
|
||||
return _VSTD::__uninitialized_default_construct_n<_ValueType>(__first, __n);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
} // namespace __uninitialized_default_construct_n_ns
|
||||
|
||||
inline namespace __cpo {
|
||||
inline constexpr auto uninitialized_default_construct_n =
|
||||
__uninitialized_default_construct_n::__fn(__function_like::__tag());
|
||||
} // namespace __cpo
|
||||
|
||||
} // namespace ranges
|
||||
#endif // !defined(_LIBCPP_HAS_NO_RANGES)
|
||||
|
||||
_LIBCPP_END_NAMESPACE_STD
|
||||
|
||||
#endif // _LIBCPP___MEMORY_RANGES_UNINITIALIZED_ALGORITHMS_H
|
@ -119,43 +119,61 @@ uninitialized_fill_n(_ForwardIterator __f, _Size __n, const _Tp& __x)
|
||||
|
||||
#if _LIBCPP_STD_VER > 14
|
||||
|
||||
template <class _ForwardIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) {
|
||||
using _Vt = typename iterator_traits<_ForwardIterator>::value_type;
|
||||
// uninitialized_default_construct
|
||||
|
||||
template <class _ValueType, class _ForwardIterator, class _Sentinel>
|
||||
inline _LIBCPP_HIDE_FROM_ABI
|
||||
_ForwardIterator __uninitialized_default_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 ((void*)_VSTD::addressof(*__idx)) _ValueType;
|
||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
} catch (...) {
|
||||
_VSTD::destroy(__first, __idx);
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
|
||||
return __idx;
|
||||
}
|
||||
|
||||
template <class _ForwardIterator, class _Size>
|
||||
template <class _ForwardIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_ForwardIterator uninitialized_default_construct_n(_ForwardIterator __first, _Size __n) {
|
||||
using _Vt = typename iterator_traits<_ForwardIterator>::value_type;
|
||||
void uninitialized_default_construct(_ForwardIterator __first, _ForwardIterator __last) {
|
||||
using _ValueType = typename iterator_traits<_ForwardIterator>::value_type;
|
||||
(void)_VSTD::__uninitialized_default_construct<_ValueType>(__first, __last);
|
||||
}
|
||||
|
||||
// uninitialized_default_construct_n
|
||||
|
||||
template <class _ValueType, class _ForwardIterator, class _Size>
|
||||
inline _LIBCPP_HIDE_FROM_ABI
|
||||
_ForwardIterator __uninitialized_default_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 ((void*)_VSTD::addressof(*__idx)) _ValueType;
|
||||
#ifndef _LIBCPP_NO_EXCEPTIONS
|
||||
} catch (...) {
|
||||
_VSTD::destroy(__first, __idx);
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
|
||||
return __idx;
|
||||
}
|
||||
|
||||
template <class _ForwardIterator, class _Size>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
_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);
|
||||
}
|
||||
|
||||
template <class _ForwardIterator>
|
||||
inline _LIBCPP_INLINE_VISIBILITY
|
||||
|
@ -219,9 +219,21 @@ template <class ForwardIterator, class Size>
|
||||
template <class ForwardIterator>
|
||||
void uninitialized_default_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_default_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_default_construct(ForwardRange&& r); // since C++20
|
||||
|
||||
template <class ForwardIterator, class Size>
|
||||
ForwardIterator uninitialized_default_construct_n(ForwardIterator first, Size n);
|
||||
|
||||
template <nothrow-forward-iterator ForwardIterator>
|
||||
requires default_initializable<iter_value_t<ForwardIterator>>
|
||||
ForwardIterator ranges::uninitialized_default_construct_n(ForwardIterator first, iter_difference_t<ForwardIterator> n); // since C++20
|
||||
|
||||
template <class Y> struct auto_ptr_ref {}; // deprecated in C++11, removed in C++17
|
||||
|
||||
template<class X>
|
||||
@ -672,6 +684,7 @@ void* align(size_t alignment, size_t size, void*& ptr, size_t& space);
|
||||
#include <__memory/concepts.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>
|
||||
|
@ -630,22 +630,26 @@ module std [system] {
|
||||
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 concepts { private header "__memory/concepts.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 concepts { private header "__memory/concepts.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"
|
||||
export __function_like
|
||||
}
|
||||
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 {
|
||||
@ -755,7 +759,10 @@ module std [system] {
|
||||
module common_view { private header "__ranges/common_view.h" }
|
||||
module concepts { private header "__ranges/concepts.h" }
|
||||
module copyable_box { private header "__ranges/copyable_box.h" }
|
||||
module counted { private header "__ranges/counted.h" }
|
||||
module counted {
|
||||
private header "__ranges/counted.h"
|
||||
export span
|
||||
}
|
||||
module dangling { private header "__ranges/dangling.h" }
|
||||
module data { private header "__ranges/data.h" }
|
||||
module drop_view { private header "__ranges/drop_view.h" }
|
||||
|
@ -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/ranges_uninitialized_algorithms.h'}}
|
||||
#include <__memory/ranges_uninitialized_algorithms.h>
|
@ -81,6 +81,7 @@ void advance(forward_iterator<I>&, std::ptrdiff_t, forward_iterator<I>) {
|
||||
}
|
||||
} // namespace test
|
||||
|
||||
// TODO(varconst): simply check that `advance` is a variable and not a function.
|
||||
// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a
|
||||
// function call ([expr.call]), they inhibit argument-dependent name lookup.
|
||||
void adl_inhibition() {
|
||||
|
@ -88,6 +88,7 @@ void next(forward_iterator<I>, std::ptrdiff_t, forward_iterator<I>) {
|
||||
}
|
||||
} // namespace test
|
||||
|
||||
// TODO(varconst): simply check that `next` is a variable and not a function.
|
||||
// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a
|
||||
// function call ([expr.call]), they inhibit argument-dependent name lookup.
|
||||
void adl_inhibition() {
|
||||
|
@ -83,6 +83,7 @@ void prev(bidirectional_iterator<I>, std::ptrdiff_t, bidirectional_iterator<I>)
|
||||
}
|
||||
} // namespace test
|
||||
|
||||
// TODO(varconst): simply check that `prev` is a variable and not a function.
|
||||
// When found by unqualified ([basic.lookup.unqual]) name lookup for the postfix-expression in a
|
||||
// function call ([expr.call]), they inhibit argument-dependent name lookup.
|
||||
void adl_inhibition() {
|
||||
|
@ -0,0 +1,234 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_default_construct(ForwardIterator first, Sentinel last);
|
||||
//
|
||||
// template <nothrow-forward-range ForwardRange>
|
||||
// requires default_initializable<range_value_t<ForwardRange>>
|
||||
// borrowed_iterator_t<ForwardRange> ranges::uninitialized_default_construct(ForwardRange&& range);
|
||||
|
||||
#include <cassert>
|
||||
#include <iterator>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
#include <type_traits>
|
||||
|
||||
#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 different mechanism to achieve this effect, so this check is
|
||||
// libc++-specific.
|
||||
LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_default_construct)>);
|
||||
|
||||
struct NotDefaultCtrable { NotDefaultCtrable() = delete; };
|
||||
static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_default_construct),
|
||||
NotDefaultCtrable*, NotDefaultCtrable*>);
|
||||
|
||||
int main(int, char**) {
|
||||
// An empty range -- no default constructors should be invoked.
|
||||
{
|
||||
Buffer<Counted, 1> buf;
|
||||
|
||||
std::ranges::uninitialized_default_construct(buf.begin(), buf.begin());
|
||||
assert(Counted::current_objects == 0);
|
||||
assert(Counted::total_objects == 0);
|
||||
|
||||
std::ranges::uninitialized_default_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_default_construct(range.begin(), range.end());
|
||||
assert(Counted::current_objects == 0);
|
||||
assert(Counted::total_objects == 0);
|
||||
|
||||
std::ranges::uninitialized_default_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, 5> buf;
|
||||
|
||||
std::ranges::uninitialized_default_construct(buf.begin(), buf.end());
|
||||
assert(Counted::current_objects == N);
|
||||
assert(Counted::total_objects == N);
|
||||
|
||||
std::destroy(buf.begin(), buf.end());
|
||||
assert(Counted::current_objects == 0);
|
||||
assert(Counted::total_objects == N);
|
||||
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_default_construct(range);
|
||||
assert(Counted::current_objects == N);
|
||||
assert(Counted::total_objects == N);
|
||||
|
||||
std::destroy(buf.begin(), buf.end());
|
||||
assert(Counted::current_objects == 0);
|
||||
assert(Counted::total_objects == N);
|
||||
Counted::reset();
|
||||
}
|
||||
|
||||
// Using `counted_iterator`.
|
||||
{
|
||||
constexpr int N = 3;
|
||||
Buffer<Counted, 5> buf;
|
||||
|
||||
std::ranges::uninitialized_default_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;
|
||||
|
||||
auto counted_range = std::views::counted(buf.begin(), N);
|
||||
std::ranges::uninitialized_default_construct(counted_range);
|
||||
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_default_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();
|
||||
}
|
||||
|
||||
// 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_default_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_default_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_default_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_default_construct(range);
|
||||
assert(Counted::current_objects == N);
|
||||
assert(Counted::total_objects == N);
|
||||
std::destroy(buf.begin(), buf.end());
|
||||
Counted::reset();
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -0,0 +1,129 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// 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_default_construct_n(ForwardIterator first,
|
||||
// iter_difference_t<ForwardIterator> n);
|
||||
|
||||
#include <cassert>
|
||||
#include <memory>
|
||||
#include <ranges>
|
||||
|
||||
#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 different mechanism to achieve this effect, so this check is
|
||||
// libc++-specific.
|
||||
LIBCPP_STATIC_ASSERT(std::is_class_v<decltype(std::ranges::uninitialized_default_construct_n)>);
|
||||
|
||||
struct NotDefaultCtrable { NotDefaultCtrable() = delete; };
|
||||
static_assert(!std::is_invocable_v<decltype(std::ranges::uninitialized_default_construct_n),
|
||||
NotDefaultCtrable*, int>);
|
||||
|
||||
int main(int, char**) {
|
||||
// An empty range -- no default constructors should be invoked.
|
||||
{
|
||||
Buffer<Counted, 1> buf;
|
||||
|
||||
std::ranges::uninitialized_default_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_default_construct_n(buf.begin(), N);
|
||||
assert(Counted::current_objects == N);
|
||||
assert(Counted::total_objects == N);
|
||||
|
||||
std::destroy(buf.begin(), buf.end());
|
||||
assert(Counted::current_objects == 0);
|
||||
assert(Counted::total_objects == N);
|
||||
Counted::reset();
|
||||
}
|
||||
|
||||
// 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_default_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_default_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;
|
||||
}
|
@ -23,7 +23,6 @@
|
||||
struct Counted {
|
||||
static int count;
|
||||
static int constructed;
|
||||
static void reset() { count = constructed = 0; }
|
||||
explicit Counted() { ++count; ++constructed; }
|
||||
Counted(Counted const&) { assert(false); }
|
||||
~Counted() { --count; }
|
||||
@ -37,7 +36,6 @@ struct ThrowsCounted {
|
||||
static int count;
|
||||
static int constructed;
|
||||
static int throw_after;
|
||||
static void reset() { throw_after = count = constructed = 0; }
|
||||
explicit ThrowsCounted() {
|
||||
++constructed;
|
||||
if (throw_after > 0 && --throw_after == 0) {
|
||||
@ -67,7 +65,7 @@ void test_ctor_throws()
|
||||
assert(false);
|
||||
} catch (...) {}
|
||||
assert(ThrowsCounted::count == 0);
|
||||
assert(ThrowsCounted::constructed == 4); // forth construction throws
|
||||
assert(ThrowsCounted::constructed == 4); // Fourth construction throws
|
||||
#endif
|
||||
}
|
||||
|
||||
@ -87,26 +85,9 @@ void test_counted()
|
||||
assert(Counted::count == 0);
|
||||
}
|
||||
|
||||
void test_value_initialized()
|
||||
{
|
||||
using It = forward_iterator<int*>;
|
||||
const int N = 5;
|
||||
int pool[N] = {-1, -1, -1, -1, -1};
|
||||
int* p = pool;
|
||||
std::uninitialized_default_construct(It(p), It(p+1));
|
||||
assert(pool[0] == -1);
|
||||
assert(pool[1] == -1);
|
||||
std::uninitialized_default_construct(It(p+1), It(p+N));
|
||||
assert(pool[1] == -1);
|
||||
assert(pool[2] == -1);
|
||||
assert(pool[3] == -1);
|
||||
assert(pool[4] == -1);
|
||||
}
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test_counted();
|
||||
test_value_initialized();
|
||||
test_ctor_throws();
|
||||
|
||||
return 0;
|
||||
|
@ -88,29 +88,9 @@ void test_counted()
|
||||
assert(Counted::count == 0);
|
||||
}
|
||||
|
||||
void test_value_initialized()
|
||||
{
|
||||
using It = forward_iterator<int*>;
|
||||
const int N = 5;
|
||||
int pool[N] = {-1, -1, -1, -1, -1};
|
||||
int* p = pool;
|
||||
auto e = std::uninitialized_default_construct_n(It(p), 1);
|
||||
assert(e == It(p+1));
|
||||
assert(pool[0] == -1);
|
||||
assert(pool[1] == -1);
|
||||
e = std::uninitialized_default_construct_n(It(p+1), 4);
|
||||
assert(e == It(p+N));
|
||||
assert(pool[1] == -1);
|
||||
assert(pool[2] == -1);
|
||||
assert(pool[3] == -1);
|
||||
assert(pool[4] == -1);
|
||||
}
|
||||
|
||||
|
||||
int main(int, char**)
|
||||
{
|
||||
test_counted();
|
||||
test_value_initialized();
|
||||
test_ctor_throws();
|
||||
|
||||
return 0;
|
||||
|
Loading…
Reference in New Issue
Block a user