diff --git a/libcxx/include/memory b/libcxx/include/memory --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -3353,6 +3353,170 @@ #endif } +// __libcpp_relocate_at + +template +inline _LIBCPP_INLINE_VISIBILITY +_Dt *__relocate_at2_impl(_St *__source, _Dt *__dest, false_type) { + __dest = ::new (static_cast(__dest)) _Dt(_VSTD::move(*__source)); + __source->~_St(); + return __dest; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_Dt *__relocate_at2_impl(_St *__source, _Dt *__dest, true_type) { + _VSTD::memmove(__dest, __source, sizeof (_St)); + return _VSTD::__launder(__dest); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_Dt *__relocate_at2(_St *__source, _Dt *__dest) { + using _ViaMemcpy = integral_constant::value && + __libcpp_is_trivially_relocatable::type>::value && + !is_volatile<_St>::value && !is_volatile<_Dt>::value + >; + return _VSTD::__relocate_at2_impl(__source, __dest, _ViaMemcpy()); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_Tp *__libcpp_relocate_at(_Tp *__source, _Tp *__dest) { + return _VSTD::__relocate_at2(__source, __dest); +} + +// __libcpp_uninitialized_relocate + +template +inline _LIBCPP_INLINE_VISIBILITY +_ForwardIt2 +__uninitialized_relocate_impl(_ForwardIt1 __first, _ForwardIt1 __last, + _ForwardIt2 __result, false_type, false_type) +{ + __result = _VSTD::uninitialized_move(__first, __last, __result); + _VSTD::destroy(__first, __last); + return __result; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_ForwardIt2 +__uninitialized_relocate_impl(_ForwardIt1 __first, _ForwardIt1 __last, + _ForwardIt2 __result, false_type, true_type) +{ + for (; __first != __last; ++__result, void(), ++__first) { + _VSTD::__relocate_at2(_VSTD::addressof(*__first), _VSTD::addressof(*__result)); + } + return __result; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_ForwardIt2 +__uninitialized_relocate_impl(_ForwardIt1 __first, _ForwardIt1 __last, + _ForwardIt2 __result, true_type, _RelocateInALoop) +{ + using _Dt = typename iterator_traits<_ForwardIt2>::value_type; + auto __count = __last - __first; + if (__count != 0) { + _VSTD::memmove(_VSTD::addressof(*__result), _VSTD::addressof(*__first), __count * sizeof (_Dt)); + __result += __count; + } + return __result; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +_ForwardIt2 +__libcpp_uninitialized_relocate(_ForwardIt1 __first, _ForwardIt1 __last, + _ForwardIt2 __result) +{ + using _St = typename remove_reference::type; + using _Dt = typename remove_reference::value_type>::type; + using _ElementTypeIsMemcpyable = integral_constant::value && + __libcpp_is_trivially_relocatable::type>::value && + !is_volatile<_St>::value && !is_volatile<_Dt>::value + >; + using _SingleMemcpy = integral_constant::value && + is_pointer<_ForwardIt2>::value + >; + using _RelocateInALoop = integral_constant::value + >; + return _VSTD::__uninitialized_relocate_impl(__first, __last, __result, + _SingleMemcpy(), _RelocateInALoop()); +} + +// __libcpp_uninitialized_relocate_n + +template +inline _LIBCPP_INLINE_VISIBILITY +pair<_ForwardIt1, _ForwardIt2> +__uninitialized_relocate_n_impl(_ForwardIt1 __first, _Size __n, + _ForwardIt2 __result, false_type, false_type) +{ + pair<_ForwardIt1, _ForwardIt2> __pair = _VSTD::uninitialized_move_n(__first, __n, __result); + _VSTD::destroy_n(__first, __n); + return __pair; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +pair<_ForwardIt1, _ForwardIt2> +__uninitialized_relocate_n_impl(_ForwardIt1 __first, _Size __n, + _ForwardIt2 __result, false_type, true_type) +{ + for (; __n > 0; ++__result, ++__first, void(), --__n) { + _VSTD::__relocate_at2(_VSTD::addressof(*__first), _VSTD::addressof(*__result)); + } + return {__first, __result}; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +pair<_ForwardIt1, _ForwardIt2> +__uninitialized_relocate_n_impl(_ForwardIt1 __first, _Size __n, + _ForwardIt2 __result, true_type, _RelocateInALoop) +{ + using _Dt = typename iterator_traits<_ForwardIt2>::value_type; + if (__n != 0) { + _VSTD::memmove(_VSTD::addressof(*__result), _VSTD::addressof(*__first), __n * sizeof (_Dt)); + __first += __n; + __result += __n; + } + return {__first, __result}; +} + +template +inline _LIBCPP_INLINE_VISIBILITY +pair<_ForwardIt1, _ForwardIt2> +__libcpp_uninitialized_relocate_n(_ForwardIt1 __first, _Size __n, _ForwardIt2 __result) +{ + using _St = typename remove_reference::type; + using _Dt = typename remove_reference::value_type>::type; + using _ElementTypeIsMemcpyable = integral_constant::value && + __libcpp_is_trivially_relocatable::type>::value && + !is_volatile<_St>::value && !is_volatile<_Dt>::value + >; + using _SingleMemcpy = integral_constant::value && + is_pointer<_ForwardIt2>::value + >; + using _RelocateInALoop = integral_constant::value + >; + return _VSTD::__uninitialized_relocate_n_impl(__first, __n, __result, + _SingleMemcpy(), _RelocateInALoop()); +} #endif // _LIBCPP_STD_VER > 14 diff --git a/libcxx/include/type_traits b/libcxx/include/type_traits --- a/libcxx/include/type_traits +++ b/libcxx/include/type_traits @@ -124,6 +124,7 @@ template struct is_trivially_copy_assignable; template struct is_trivially_move_assignable; template struct is_trivially_destructible; + template struct __libcpp_is_trivially_relocatable; // extension template struct is_nothrow_constructible; template struct is_nothrow_default_constructible; @@ -350,6 +351,8 @@ = is_trivially_move_assignable::value; // C++17 template inline constexpr bool is_trivially_destructible_v = is_trivially_destructible::value; // C++17 + template inline constexpr bool __libcpp_is_trivially_relocatable_v + = __libcpp_is_trivially_relocatable::value; // extension template inline constexpr bool is_nothrow_constructible_v = is_nothrow_constructible::value; // C++17 template inline constexpr bool is_nothrow_default_constructible_v @@ -3059,6 +3062,25 @@ = is_trivially_destructible<_Tp>::value; #endif +// __libcpp_is_trivially_relocatable + +template +struct _LIBCPP_TEMPLATE_VIS __libcpp_is_trivially_relocatable + : public integral_constant::type>::value && + is_trivially_destructible::type>::value +#endif + > {}; + +#if _LIBCPP_STD_VER > 14 && !defined(_LIBCPP_HAS_NO_VARIABLE_TEMPLATES) +template +_LIBCPP_INLINE_VAR _LIBCPP_CONSTEXPR bool __libcpp_is_trivially_relocatable_v + = __libcpp_is_trivially_relocatable<_Tp>::value; +#endif + // is_nothrow_constructible #if __has_keyword(__is_nothrow_constructible) diff --git a/libcxx/test/libcxx/type_traits/is_trivially_relocatable.pass.cpp b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/type_traits/is_trivially_relocatable.pass.cpp @@ -0,0 +1,223 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// UNSUPPORTED: c++98, c++03, c++11, c++14 +// +// +// +// Test that many standard types are trivially relocatable. + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +//#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +struct T { T(); T(const T&); ~T(); }; +struct R { }; +struct SM { void lock_shared(); void unlock_shared(); ~SM(); }; + +struct K { + T t; + bool operator==(const K&) const; + bool operator< (const K&) const; +}; +template<> struct std::hash { size_t operator()(const K&) const; }; + +static const bool NotDebug = +#if _LIBCPP_DEBUG_LEVEL >= 2 + false; +#else + true; +#endif + +// Define this name for convenience. +#define is_trivially_relocatable __libcpp_is_trivially_relocatable + +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +//static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(std::is_trivially_relocatable>::value, ""); +//static_assert(std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(!std::is_trivially_relocatable>::value, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::local_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::local_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::local_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::local_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::const_iterator>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable::iterator>::value, ""); +static_assert(std::is_trivially_relocatable::const_iterator>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>>::value, ""); +static_assert(std::is_trivially_relocatable>>::value, ""); +static_assert(std::is_trivially_relocatable>>::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable>>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); // because it uses vector internally +static_assert(!std::is_trivially_relocatable::value, ""); // because it uses vector internally +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); // because it uses vector internally +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); // because it uses vector internally +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +//static_assert(std::is_trivially_relocatable::value == NotDebug, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); // contains pointer into self +static_assert(!std::is_trivially_relocatable>::value, ""); // contains pointer into self +static_assert(!std::is_trivially_relocatable>::value, ""); // contains pointer into self +static_assert(!std::is_trivially_relocatable>::value, ""); // contains pointer into self + +// The following types are not move-constructible at all. +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable>::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); +static_assert(!std::is_trivially_relocatable::value, ""); + +int main(int, char**) +{ + return 0; +} diff --git a/libcxx/test/libcxx/utilities/memory/specialized.algorithms/specialized.relocate/relocate_at.pass.cpp b/libcxx/test/libcxx/utilities/memory/specialized.algorithms/specialized.relocate/relocate_at.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/memory/specialized.algorithms/specialized.relocate/relocate_at.pass.cpp @@ -0,0 +1,79 @@ +//===----------------------------------------------------------------------===// +// +// 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++98, c++03 + +// + +// template +// void __libcpp_relocate_at(_Tp *source, _Tp *dest); + +#include +#include +#include + +struct Counted { + static int count; + int m_data; + Counted(int i) : m_data(i) { ++count; } + Counted(Counted&& rhs) : m_data(rhs.m_data) { rhs.m_data = 0; ++count; } + ~Counted() { --count; } + friend void operator&(Counted) = delete; +}; +int Counted::count = 0; + +#ifdef _LIBCPP_TRIVIALLY_RELOCATABLE +struct _LIBCPP_TRIVIALLY_RELOCATABLE RCounted { +#else +struct RCounted { +#endif + static int count; + int m_data; + RCounted(int i) : m_data(i) { ++count; } + RCounted(RCounted const& rhs) : m_data(rhs.m_data) { ++count; } + ~RCounted() { --count; } + friend void operator&(RCounted) = delete; +}; +int RCounted::count = 0; + +int main(int, char**) +{ + { + void *mem1 = std::malloc(sizeof(Counted)); + void *mem2 = std::malloc(sizeof(Counted)); + assert(mem1 && mem2); + assert(Counted::count == 0); + Counted *ptr1 = ::new (mem1) Counted(1234); + Counted *ptr2 = static_cast(mem2); + assert(Counted::count == 1); + std::__libcpp_relocate_at(ptr1, ptr2); + assert(Counted::count == 1); + assert(ptr2->m_data == 1234); + ptr2->~Counted(); + std::free(mem1); + std::free(mem2); + } + + { + void *mem1 = std::malloc(sizeof(RCounted)); + void *mem2 = std::malloc(sizeof(RCounted)); + assert(mem1 && mem2); + assert(RCounted::count == 0); + RCounted *ptr1 = ::new (mem1) RCounted(5678); + RCounted *ptr2 = static_cast(mem2); + assert(RCounted::count == 1); + std::__libcpp_relocate_at(ptr1, ptr2); + assert(RCounted::count == 1); + assert(ptr2->m_data == 5678); + ptr2->~RCounted(); + std::free(mem1); + std::free(mem2); + } + + return 0; +} diff --git a/libcxx/test/libcxx/utilities/memory/specialized.algorithms/uninitialized.relocate/uninitialized_relocate.pass.cpp b/libcxx/test/libcxx/utilities/memory/specialized.algorithms/uninitialized.relocate/uninitialized_relocate.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/memory/specialized.algorithms/uninitialized.relocate/uninitialized_relocate.pass.cpp @@ -0,0 +1,165 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template +// ForwardIt __libcpp_uninitialized_relocate(InputIt, InputIt, ForwardIt); + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +struct Counted { + static int count; + static int constructed; + static void reset() { count = constructed = 0; } + explicit Counted(int&& x) : value(x) { x = 0; ++count; ++constructed; } + Counted(Counted const&) { assert(false); } + ~Counted() { assert(count > 0); --count; } + friend void operator&(Counted) = delete; + int value; +}; +int Counted::count = 0; +int Counted::constructed = 0; + +struct ThrowsCounted { + static int count; + static int constructed; + static int throw_after; + static void reset() { throw_after = count = constructed = 0; } + explicit ThrowsCounted(int&& x) { + ++constructed; + if (throw_after > 0 && --throw_after == 0) { + TEST_THROW(1); + } + ++count; + x = 0; + } + ThrowsCounted(ThrowsCounted const&) { assert(false); } + ~ThrowsCounted() { assert(count > 0); --count; } + friend void operator&(ThrowsCounted) = delete; +}; +int ThrowsCounted::count = 0; +int ThrowsCounted::constructed = 0; +int ThrowsCounted::throw_after = 0; + +void test_ctor_throws() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using It = forward_iterator; + const int N = 5; + int values[N] = {1, 2, 3, 4, 5}; + alignas(ThrowsCounted) char pool[sizeof(ThrowsCounted)*N] = {}; + ThrowsCounted* p = (ThrowsCounted*)pool; + try { + ThrowsCounted::throw_after = 4; + std::__libcpp_uninitialized_relocate(values, values + N, It(p)); + assert(false); + } catch (...) {} + assert(ThrowsCounted::count == 0); // the ones constructed have been destroyed automatically + assert(ThrowsCounted::constructed == 4); // fourth construction throws + assert(values[0] == 0); + assert(values[1] == 0); + assert(values[2] == 0); + assert(values[3] == 4); + assert(values[4] == 5); +#endif +} + +void test_counted() +{ + using It = input_iterator; + using FIt = forward_iterator; + const int N = 5; + int values[N] = {1, 2, 3, 4, 5}; + alignas(Counted) char pool[sizeof(Counted)*N] = {}; + Counted* p = (Counted*)pool; + auto ret = std::__libcpp_uninitialized_relocate(It(values), It(values + 1), FIt(p)); + assert(ret == FIt(p +1)); + assert(Counted::constructed == 1); + assert(Counted::count == 1); + assert(p[0].value == 1); + assert(values[0] == 0); + ret = std::__libcpp_uninitialized_relocate(It(values+1), It(values+N), FIt(p+1)); + assert(ret == FIt(p + N)); + assert(Counted::count == 5); + assert(Counted::constructed == 5); + assert(p[1].value == 2); + assert(p[2].value == 3); + assert(p[3].value == 4); + assert(p[4].value == 5); + assert(values[1] == 0); + assert(values[2] == 0); + assert(values[3] == 0); + assert(values[4] == 0); + std::destroy(p, p+N); + assert(Counted::count == 0); +} + +void test_unique_ptr_forward() +{ + using T = std::unique_ptr; + const int N = 5; + alignas(T) char sourcepool[sizeof(T) * N]; + alignas(T) char destpool[sizeof(T) * N]; + T *source = (T*)sourcepool; + T *dest = (T*)destpool; + for (int i=0; i < N; ++i) { + ::new ((void*)&source[i]) T(std::make_unique(i)); + } + auto result = std::__libcpp_uninitialized_relocate(source, source + 3, dest); + assert(result == dest + 3); + assert(*dest[0] == 0); + assert(*dest[1] == 1); + assert(*dest[2] == 2); + assert(*source[3] == 3); + assert(*source[4] == 4); + std::destroy(dest, dest + 3); + std::destroy(source + 3, source + N); +} + +void test_unique_ptr_backward() +{ + using T = std::unique_ptr; + const int N = 5; + alignas(T) char sourcepool[sizeof(T) * N]; + alignas(T) char destpool[sizeof(T) * N]; + T *source = (T*)sourcepool; + T *dest = (T*)destpool; + for (int i=0; i < N; ++i) { + ::new ((void*)&source[i]) T(std::make_unique(i)); + } + auto result = std::__libcpp_uninitialized_relocate( + std::make_reverse_iterator(source + 3), + std::make_reverse_iterator(source), dest); + assert(result == dest + 3); + assert(*dest[0] == 2); + assert(*dest[1] == 1); + assert(*dest[2] == 0); + assert(*source[3] == 3); + assert(*source[4] == 4); + std::destroy(dest, dest + 3); + std::destroy(source + 3, source + N); +} + +int main(int, char**) +{ + test_counted(); + test_ctor_throws(); + test_unique_ptr_forward(); + test_unique_ptr_backward(); + return 0; +} diff --git a/libcxx/test/libcxx/utilities/memory/specialized.algorithms/uninitialized.relocate/uninitialized_relocate_n.pass.cpp b/libcxx/test/libcxx/utilities/memory/specialized.algorithms/uninitialized.relocate/uninitialized_relocate_n.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/memory/specialized.algorithms/uninitialized.relocate/uninitialized_relocate_n.pass.cpp @@ -0,0 +1,168 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03, c++11, c++14 + +// + +// template +// pair __libcpp_uninitialized_relocate_n(InputIt, Size, ForwardIt); + +#include +#include +#include + +#include "test_macros.h" +#include "test_iterators.h" + +struct Counted { + static int count; + static int constructed; + static void reset() { count = constructed = 0; } + explicit Counted(int&& x) : value(x) { x = 0; ++count; ++constructed; } + Counted(Counted const&) { assert(false); } + ~Counted() { assert(count > 0); --count; } + friend void operator&(Counted) = delete; + int value; +}; +int Counted::count = 0; +int Counted::constructed = 0; + +struct ThrowsCounted { + static int count; + static int constructed; + static int throw_after; + static void reset() { throw_after = count = constructed = 0; } + explicit ThrowsCounted(int&& x) { + ++constructed; + if (throw_after > 0 && --throw_after == 0) { + TEST_THROW(1); + } + ++count; + x = 0; + } + ThrowsCounted(ThrowsCounted const&) { assert(false); } + ~ThrowsCounted() { assert(count > 0); --count; } + friend void operator&(ThrowsCounted) = delete; +}; +int ThrowsCounted::count = 0; +int ThrowsCounted::constructed = 0; +int ThrowsCounted::throw_after = 0; + +void test_ctor_throws() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + using It = forward_iterator; + const int N = 5; + int values[N] = {1, 2, 3, 4, 5}; + alignas(ThrowsCounted) char pool[sizeof(ThrowsCounted)*N] = {}; + ThrowsCounted* p = (ThrowsCounted*)pool; + try { + ThrowsCounted::throw_after = 4; + std::__libcpp_uninitialized_relocate_n(values, N, It(p)); + assert(false); + } catch (...) {} + assert(ThrowsCounted::count == 0); // the ones constructed have been destroyed automatically + assert(ThrowsCounted::constructed == 4); // fourth construction throws + assert(values[0] == 0); + assert(values[1] == 0); + assert(values[2] == 0); + assert(values[3] == 4); + assert(values[4] == 5); +#endif +} + +void test_counted() +{ + using It = input_iterator; + using FIt = forward_iterator; + const int N = 5; + int values[N] = {1, 2, 3, 4, 5}; + alignas(Counted) char pool[sizeof(Counted)*N] = {}; + Counted* p = (Counted*)pool; + auto ret = std::__libcpp_uninitialized_relocate_n(It(values), 1, FIt(p)); + assert(ret.first == It(values+1)); + assert(ret.second == FIt(p + 1)); + assert(Counted::constructed == 1); + assert(Counted::count == 1); + assert(p[0].value == 1); + assert(values[0] == 0); + ret = std::__libcpp_uninitialized_relocate_n(It(values+1), N-1, FIt(p+1)); + assert(ret.first == It(values+N)); + assert(ret.second == FIt(p + N)); + assert(Counted::count == 5); + assert(Counted::constructed == 5); + assert(p[1].value == 2); + assert(p[2].value == 3); + assert(p[3].value == 4); + assert(p[4].value == 5); + assert(values[1] == 0); + assert(values[2] == 0); + assert(values[3] == 0); + assert(values[4] == 0); + std::destroy(p, p+N); + assert(Counted::count == 0); +} + +void test_unique_ptr_forward() +{ + using T = std::unique_ptr; + const int N = 5; + alignas(T) char sourcepool[sizeof(T) * N]; + alignas(T) char destpool[sizeof(T) * N]; + T *source = (T*)sourcepool; + T *dest = (T*)destpool; + for (int i=0; i < N; ++i) { + ::new ((void*)&source[i]) T(std::make_unique(i)); + } + auto result = std::__libcpp_uninitialized_relocate_n(source, 3, dest); + assert(result.first == source + 3); + assert(result.second == dest + 3); + assert(*dest[0] == 0); + assert(*dest[1] == 1); + assert(*dest[2] == 2); + assert(*source[3] == 3); + assert(*source[4] == 4); + std::destroy(dest, dest + 3); + std::destroy(source + 3, source + N); +} + +void test_unique_ptr_backward() +{ + using T = std::unique_ptr; + const int N = 5; + alignas(T) char sourcepool[sizeof(T) * N]; + alignas(T) char destpool[sizeof(T) * N]; + T *source = (T*)sourcepool; + T *dest = (T*)destpool; + for (int i=0; i < N; ++i) { + ::new ((void*)&source[i]) T(std::make_unique(i)); + } + auto result = std::__libcpp_uninitialized_relocate_n( + std::make_reverse_iterator(source + 3), + 3, dest); + assert(result.first == std::make_reverse_iterator(source)); + assert(result.second == dest + 3); + assert(*dest[0] == 2); + assert(*dest[1] == 1); + assert(*dest[2] == 0); + assert(*source[3] == 3); + assert(*source[4] == 4); + std::destroy(dest, dest + 3); + std::destroy(source + 3, source + N); +} + +int main(int, char**) +{ + test_counted(); + test_ctor_throws(); + test_unique_ptr_forward(); + test_unique_ptr_backward(); + return 0; +} diff --git a/libcxx/test/libcxx/utilities/meta/meta.unary/meta.unary.prop/is_trivially_relocatable.pass.cpp b/libcxx/test/libcxx/utilities/meta/meta.unary/meta.unary.prop/is_trivially_relocatable.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/utilities/meta/meta.unary/meta.unary.prop/is_trivially_relocatable.pass.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// type_traits + +// __libcpp_is_trivially_relocatable +// __libcpp_is_trivially_relocatable_v + +// UNSUPPORTED: c++98, c++03 +// XFAIL: gcc-4.9 + +#include +#include +#include "test_macros.h" + + +template +void test_is_trivially_relocatable() +{ + static_assert( std::__libcpp_is_trivially_relocatable::value, ""); +#if TEST_STD_VER > 14 + static_assert( std::__libcpp_is_trivially_relocatable_v, ""); +#endif +} + +template +void test_is_not_trivially_relocatable() +{ + static_assert(!std::__libcpp_is_trivially_relocatable::value, ""); +#if TEST_STD_VER > 14 + static_assert(!std::__libcpp_is_trivially_relocatable_v, ""); +#endif +} + +class Empty +{ +}; + +class NotEmpty +{ +public: + virtual ~NotEmpty(); +}; + +union Union {}; + +struct bit_zero +{ + int : 0; +}; + +class Abstract +{ +public: + virtual ~Abstract() = 0; +}; + +struct A +{ + A(const A&); +}; + +#if TEST_STD_VER >= 11 + +struct MoveOnly1 +{ + MoveOnly1(MoveOnly1&&); +}; + +struct MoveOnly2 +{ + MoveOnly2(MoveOnly2&&) = default; +}; +#endif + +int main(int, char**) +{ + test_is_not_trivially_relocatable(); + test_is_not_trivially_relocatable(); + test_is_not_trivially_relocatable(); + test_is_not_trivially_relocatable(); + test_is_not_trivially_relocatable(); + + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); + +#if TEST_STD_VER >= 11 + test_is_not_trivially_relocatable(); + test_is_not_trivially_relocatable(); + test_is_trivially_relocatable(); + test_is_trivially_relocatable(); +#endif + + return 0; +}