Skip to content

Commit 20fd6fc

Browse files
committed
[libc++][WIP] Implement relocation primitives
1 parent 14c47bd commit 20fd6fc

File tree

7 files changed

+373
-20
lines changed

7 files changed

+373
-20
lines changed

libcxx/include/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -552,18 +552,21 @@ set(files
552552
__memory/destroy.h
553553
__memory/destruct_n.h
554554
__memory/inout_ptr.h
555+
__memory/is_trivially_allocator_relocatable.h
555556
__memory/noexcept_move_assign_container.h
556557
__memory/out_ptr.h
557558
__memory/pointer_traits.h
558559
__memory/ranges_construct_at.h
559560
__memory/ranges_uninitialized_algorithms.h
560561
__memory/raw_storage_iterator.h
562+
__memory/relocate_at.h
561563
__memory/shared_count.h
562564
__memory/shared_ptr.h
563565
__memory/swap_allocator.h
564566
__memory/temp_value.h
565567
__memory/temporary_buffer.h
566568
__memory/uninitialized_algorithms.h
569+
__memory/uninitialized_relocate.h
567570
__memory/unique_ptr.h
568571
__memory/unique_temporary_buffer.h
569572
__memory/uses_allocator.h
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___MEMORY_IS_TRIVIALLY_ALLOCATOR_RELOCATABLE_H
10+
#define _LIBCPP___MEMORY_IS_TRIVIALLY_ALLOCATOR_RELOCATABLE_H
11+
12+
#include <__config>
13+
#include <__memory/allocator_traits.h>
14+
#include <__type_traits/conjunction.h>
15+
#include <__type_traits/disjunction.h>
16+
#include <__type_traits/integral_constant.h>
17+
#include <__type_traits/is_nothrow_constructible.h>
18+
#include <__type_traits/is_trivially_relocatable.h>
19+
#include <__type_traits/negation.h>
20+
21+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22+
# pragma GCC system_header
23+
#endif
24+
25+
_LIBCPP_BEGIN_NAMESPACE_STD
26+
27+
// A type is trivially allocator relocatable if the allocator's move construction and destruction
28+
// don't do anything beyond calling the type's move constructor and destructor, and if the type
29+
// itself is trivially relocatable.
30+
31+
template <class _Alloc, class _Type>
32+
struct __allocator_has_trivial_move_construct : _Not<__has_construct<_Alloc, _Type*, _Type&&> > {};
33+
34+
template <class _Type>
35+
struct __allocator_has_trivial_move_construct<allocator<_Type>, _Type> : true_type {};
36+
37+
template <class _Alloc, class _Tp>
38+
struct __allocator_has_trivial_destroy : _Not<__has_destroy<_Alloc, _Tp*> > {};
39+
40+
template <class _Tp, class _Up>
41+
struct __allocator_has_trivial_destroy<allocator<_Tp>, _Up> : true_type {};
42+
43+
template <class _Alloc, class _Tp>
44+
struct __is_trivially_allocator_relocatable
45+
: integral_constant<bool,
46+
__allocator_has_trivial_move_construct<_Alloc, _Tp>::value &&
47+
__allocator_has_trivial_destroy<_Alloc, _Tp>::value &&
48+
__libcpp_is_trivially_relocatable<_Tp>::value> {};
49+
50+
template <class _Alloc, class _Tp>
51+
struct __is_nothrow_allocator_relocatable
52+
: _Or<_And<__allocator_has_trivial_move_construct<_Alloc, _Tp>, is_nothrow_move_constructible<_Tp>>,
53+
__is_trivially_allocator_relocatable<_Alloc, _Tp>> {};
54+
55+
_LIBCPP_END_NAMESPACE_STD
56+
57+
#endif // _LIBCPP___MEMORY_IS_TRIVIALLY_ALLOCATOR_RELOCATABLE_H
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
//===----------------------------------------------------------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef _LIBCPP___MEMORY_RELOCATE_AT_H
10+
#define _LIBCPP___MEMORY_RELOCATE_AT_H
11+
12+
#include <__memory/allocator_traits.h>
13+
#include <__memory/construct_at.h>
14+
#include <__memory/is_trivially_allocator_relocatable.h>
15+
#include <__type_traits/enable_if.h>
16+
#include <__type_traits/is_constant_evaluated.h>
17+
#include <__type_traits/is_trivially_relocatable.h>
18+
#include <__utility/move.h>
19+
#include <__utility/scope_guard.h>
20+
21+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
22+
# pragma GCC system_header
23+
#endif
24+
25+
_LIBCPP_PUSH_MACROS
26+
#include <__undef_macros>
27+
28+
_LIBCPP_BEGIN_NAMESPACE_STD
29+
30+
template <class _Tp>
31+
struct __destroy_object {
32+
_LIBCPP_CONSTEXPR_SINCE_CXX20 void operator()() const { std::__destroy_at(__obj_); }
33+
_Tp* __obj_;
34+
};
35+
36+
template <class _Alloc, class _Tp>
37+
struct __allocator_destroy_object {
38+
_LIBCPP_CONSTEXPR_SINCE_CXX20 void operator()() const { allocator_traits<_Alloc>::destroy(__alloc_, __obj_); }
39+
_Alloc& __alloc_;
40+
_Tp* __obj_;
41+
};
42+
43+
template <class _Tp>
44+
_LIBCPP_HIDE_FROM_ABI _Tp* __libcpp_builtin_trivially_relocate_at(_Tp* __source, _Tp* __dest) _NOEXCEPT {
45+
static_assert(__libcpp_is_trivially_relocatable<_Tp>::value, "");
46+
// Casting to void* to suppress clang complaining that this is technically UB.
47+
__builtin_memcpy(static_cast<void*>(__dest), __source, sizeof(_Tp));
48+
return __dest;
49+
}
50+
51+
template <class _Tp>
52+
_LIBCPP_HIDE_FROM_ABI _Tp* __libcpp_builtin_trivially_relocate_at(_Tp* __first, Tp* __last, _Tp* __dest) _NOEXCEPT {
53+
static_assert(__libcpp_is_trivially_relocatable<_Tp>::value, "");
54+
// Casting to void* to suppress clang complaining that this is technically UB.
55+
__builtin_memmove(static_cast<void*>(__dest), __first, (__last - __first) * sizeof(_Tp));
56+
return __dest;
57+
}
58+
59+
template <class _Tp>
60+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp* __relocate_at(_Tp* __source, _Tp* __dest) {
61+
if constexpr (__libcpp_is_trivially_relocatable<_Tp>::value) {
62+
if (!__libcpp_is_constant_evaluated()) {
63+
return std::__libcpp_builtin_trivially_relocate_at(__source, __dest);
64+
}
65+
}
66+
auto __guard = std::__make_scope_guard(__destroy_object<_Tp>{__source});
67+
return std::__construct_at(__dest, std::move(*__source));
68+
}
69+
70+
template <class _Alloc, class _Tp>
71+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _Tp*
72+
__allocator_relocate_at(_Alloc& __alloc, _Tp* __source, _Tp* __dest) {
73+
if constexpr (__allocator_has_trivial_move_construct<_Alloc, _Tp>::value &&
74+
__allocator_has_trivial_destroy<_Alloc, _Tp>::value) {
75+
(void)__alloc; // ignore the allocator
76+
return std::__relocate_at(__source, __dest);
77+
} else {
78+
auto __guard = std::__make_scope_guard(__allocator_destroy_object<_Alloc, _Tp>{__alloc, __source});
79+
allocator_traits<_Alloc>::construct(__alloc, __dest, std::move(*__source));
80+
return __dest;
81+
}
82+
}
83+
84+
_LIBCPP_END_NAMESPACE_STD
85+
86+
_LIBCPP_POP_MACROS
87+
88+
#endif // _LIBCPP___MEMORY_RELOCATE_AT_H

libcxx/include/__memory/uninitialized_algorithms.h

Lines changed: 4 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include <__memory/destroy.h>
2222
#include <__memory/allocator_traits.h>
2323
#include <__memory/construct_at.h>
24+
#include <__memory/is_trivially_allocator_relocatable.h>
2425
#include <__memory/pointer_traits.h>
2526
#include <__type_traits/enable_if.h>
2627
#include <__type_traits/extent.h>
@@ -584,19 +585,7 @@ __uninitialized_allocator_copy(_Alloc& __alloc, _Iter1 __first1, _Sent1 __last1,
584585
return std::__rewrap_iter(__first2, __result);
585586
}
586587

587-
template <class _Alloc, class _Type>
588-
struct __allocator_has_trivial_move_construct : _Not<__has_construct<_Alloc, _Type*, _Type&&> > {};
589-
590-
template <class _Type>
591-
struct __allocator_has_trivial_move_construct<allocator<_Type>, _Type> : true_type {};
592-
593-
template <class _Alloc, class _Tp>
594-
struct __allocator_has_trivial_destroy : _Not<__has_destroy<_Alloc, _Tp*> > {};
595-
596-
template <class _Tp, class _Up>
597-
struct __allocator_has_trivial_destroy<allocator<_Tp>, _Up> : true_type {};
598-
599-
// __uninitialized_allocator_relocate relocates the objects in [__first, __last) into __result.
588+
// __uninitialized_allocator_relocate_for_vector relocates the objects in [__first, __last) into __result.
600589
// Relocation means that the objects in [__first, __last) are placed into __result as-if by move-construct and destroy,
601590
// except that the move constructor and destructor may never be called if they are known to be equivalent to a memcpy.
602591
//
@@ -609,15 +598,13 @@ struct __allocator_has_trivial_destroy<allocator<_Tp>, _Up> : true_type {};
609598
// - is_copy_constructible<_ValueType>
610599
// - __libcpp_is_trivially_relocatable<_ValueType>
611600
template <class _Alloc, class _ContiguousIterator>
612-
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __uninitialized_allocator_relocate(
601+
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __uninitialized_allocator_relocate_for_vector(
613602
_Alloc& __alloc, _ContiguousIterator __first, _ContiguousIterator __last, _ContiguousIterator __result) {
614603
static_assert(__libcpp_is_contiguous_iterator<_ContiguousIterator>::value, "");
615604
using _ValueType = typename iterator_traits<_ContiguousIterator>::value_type;
616605
static_assert(__is_cpp17_move_insertable<_Alloc>::value,
617606
"The specified type does not meet the requirements of Cpp17MoveInsertable");
618-
if (__libcpp_is_constant_evaluated() || !__libcpp_is_trivially_relocatable<_ValueType>::value ||
619-
!__allocator_has_trivial_move_construct<_Alloc, _ValueType>::value ||
620-
!__allocator_has_trivial_destroy<_Alloc, _ValueType>::value) {
607+
if (__libcpp_is_constant_evaluated() || !__is_trivially_allocator_relocatable<_Alloc, _ValueType>::value) {
621608
auto __destruct_first = __result;
622609
auto __guard = std::__make_exception_guard(
623610
_AllocatorDestroyRangeReverse<_Alloc, _ContiguousIterator>(__alloc, __destruct_first, __result));

0 commit comments

Comments
 (0)