xref: /freebsd-src/contrib/llvm-project/libcxx/include/__algorithm/copy_move_common.h (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
1bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
2bdd1243dSDimitry Andric //
3bdd1243dSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4bdd1243dSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5bdd1243dSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6bdd1243dSDimitry Andric //
7bdd1243dSDimitry Andric //===----------------------------------------------------------------------===//
8bdd1243dSDimitry Andric 
9bdd1243dSDimitry Andric #ifndef _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H
10bdd1243dSDimitry Andric #define _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H
11bdd1243dSDimitry Andric 
12bdd1243dSDimitry Andric #include <__algorithm/iterator_operations.h>
13bdd1243dSDimitry Andric #include <__algorithm/unwrap_iter.h>
14bdd1243dSDimitry Andric #include <__algorithm/unwrap_range.h>
15bdd1243dSDimitry Andric #include <__config>
16bdd1243dSDimitry Andric #include <__iterator/iterator_traits.h>
17bdd1243dSDimitry Andric #include <__memory/pointer_traits.h>
1806c3fb27SDimitry Andric #include <__string/constexpr_c_functions.h>
19bdd1243dSDimitry Andric #include <__type_traits/enable_if.h>
20bdd1243dSDimitry Andric #include <__type_traits/is_always_bitcastable.h>
21bdd1243dSDimitry Andric #include <__type_traits/is_constant_evaluated.h>
22*0fca6ea1SDimitry Andric #include <__type_traits/is_constructible.h>
23bdd1243dSDimitry Andric #include <__type_traits/is_trivially_assignable.h>
24bdd1243dSDimitry Andric #include <__type_traits/is_volatile.h>
25bdd1243dSDimitry Andric #include <__utility/move.h>
26bdd1243dSDimitry Andric #include <__utility/pair.h>
27bdd1243dSDimitry Andric #include <cstddef>
28bdd1243dSDimitry Andric 
29bdd1243dSDimitry Andric #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
30bdd1243dSDimitry Andric #  pragma GCC system_header
31bdd1243dSDimitry Andric #endif
32bdd1243dSDimitry Andric 
33b3edf446SDimitry Andric _LIBCPP_PUSH_MACROS
34b3edf446SDimitry Andric #include <__undef_macros>
35b3edf446SDimitry Andric 
36bdd1243dSDimitry Andric _LIBCPP_BEGIN_NAMESPACE_STD
37bdd1243dSDimitry Andric 
38bdd1243dSDimitry Andric // Type traits.
39bdd1243dSDimitry Andric 
40bdd1243dSDimitry Andric template <class _From, class _To>
41bdd1243dSDimitry Andric struct __can_lower_copy_assignment_to_memmove {
42bdd1243dSDimitry Andric   static const bool value =
43bdd1243dSDimitry Andric       // If the types are always bitcastable, it's valid to do a bitwise copy between them.
44bdd1243dSDimitry Andric       __is_always_bitcastable<_From, _To>::value &&
45bdd1243dSDimitry Andric       // Reject conversions that wouldn't be performed by the regular built-in assignment (e.g. between arrays).
46bdd1243dSDimitry Andric       is_trivially_assignable<_To&, const _From&>::value &&
47bdd1243dSDimitry Andric       // `memmove` doesn't accept `volatile` pointers, make sure the optimization SFINAEs away in that case.
48cb14a3feSDimitry Andric       !is_volatile<_From>::value && !is_volatile<_To>::value;
49bdd1243dSDimitry Andric };
50bdd1243dSDimitry Andric 
51bdd1243dSDimitry Andric template <class _From, class _To>
52bdd1243dSDimitry Andric struct __can_lower_move_assignment_to_memmove {
53bdd1243dSDimitry Andric   static const bool value =
54cb14a3feSDimitry Andric       __is_always_bitcastable<_From, _To>::value && is_trivially_assignable<_To&, _From&&>::value &&
55cb14a3feSDimitry Andric       !is_volatile<_From>::value && !is_volatile<_To>::value;
56bdd1243dSDimitry Andric };
57bdd1243dSDimitry Andric 
58bdd1243dSDimitry Andric // `memmove` algorithms implementation.
59bdd1243dSDimitry Andric 
60bdd1243dSDimitry Andric template <class _In, class _Out>
61bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
62bdd1243dSDimitry Andric __copy_trivial_impl(_In* __first, _In* __last, _Out* __result) {
63bdd1243dSDimitry Andric   const size_t __n = static_cast<size_t>(__last - __first);
6406c3fb27SDimitry Andric 
6506c3fb27SDimitry Andric   std::__constexpr_memmove(__result, __first, __element_count(__n));
66bdd1243dSDimitry Andric 
67bdd1243dSDimitry Andric   return std::make_pair(__last, __result + __n);
68bdd1243dSDimitry Andric }
69bdd1243dSDimitry Andric 
70bdd1243dSDimitry Andric template <class _In, class _Out>
71bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 pair<_In*, _Out*>
72bdd1243dSDimitry Andric __copy_backward_trivial_impl(_In* __first, _In* __last, _Out* __result) {
73bdd1243dSDimitry Andric   const size_t __n = static_cast<size_t>(__last - __first);
74bdd1243dSDimitry Andric   __result -= __n;
75bdd1243dSDimitry Andric 
7606c3fb27SDimitry Andric   std::__constexpr_memmove(__result, __first, __element_count(__n));
77bdd1243dSDimitry Andric 
78bdd1243dSDimitry Andric   return std::make_pair(__last, __result);
79bdd1243dSDimitry Andric }
80bdd1243dSDimitry Andric 
81bdd1243dSDimitry Andric // Iterator unwrapping and dispatching to the correct overload.
82bdd1243dSDimitry Andric 
83*0fca6ea1SDimitry Andric template <class _InIter, class _OutIter>
84*0fca6ea1SDimitry Andric struct __can_rewrap
85*0fca6ea1SDimitry Andric     : integral_constant<bool, is_copy_constructible<_InIter>::value && is_copy_constructible<_OutIter>::value> {};
86bdd1243dSDimitry Andric 
87bdd1243dSDimitry Andric template <class _Algorithm,
88bdd1243dSDimitry Andric           class _InIter,
89bdd1243dSDimitry Andric           class _Sent,
90bdd1243dSDimitry Andric           class _OutIter,
91*0fca6ea1SDimitry Andric           __enable_if_t<__can_rewrap<_InIter, _OutIter>::value, int> = 0>
92bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter>
93*0fca6ea1SDimitry Andric __copy_move_unwrap_iters(_InIter __first, _Sent __last, _OutIter __out_first) {
94bdd1243dSDimitry Andric   auto __range  = std::__unwrap_range(__first, std::move(__last));
95bdd1243dSDimitry Andric   auto __result = _Algorithm()(std::move(__range.first), std::move(__range.second), std::__unwrap_iter(__out_first));
96bdd1243dSDimitry Andric   return std::make_pair(std::__rewrap_range<_Sent>(std::move(__first), std::move(__result.first)),
97bdd1243dSDimitry Andric                         std::__rewrap_iter(std::move(__out_first), std::move(__result.second)));
98bdd1243dSDimitry Andric }
99bdd1243dSDimitry Andric 
100bdd1243dSDimitry Andric template <class _Algorithm,
101bdd1243dSDimitry Andric           class _InIter,
102bdd1243dSDimitry Andric           class _Sent,
103bdd1243dSDimitry Andric           class _OutIter,
104*0fca6ea1SDimitry Andric           __enable_if_t<!__can_rewrap<_InIter, _OutIter>::value, int> = 0>
105bdd1243dSDimitry Andric _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 pair<_InIter, _OutIter>
106*0fca6ea1SDimitry Andric __copy_move_unwrap_iters(_InIter __first, _Sent __last, _OutIter __out_first) {
107bdd1243dSDimitry Andric   return _Algorithm()(std::move(__first), std::move(__last), std::move(__out_first));
108bdd1243dSDimitry Andric }
109bdd1243dSDimitry Andric 
110bdd1243dSDimitry Andric _LIBCPP_END_NAMESPACE_STD
111bdd1243dSDimitry Andric 
112b3edf446SDimitry Andric _LIBCPP_POP_MACROS
113b3edf446SDimitry Andric 
114bdd1243dSDimitry Andric #endif // _LIBCPP___ALGORITHM_COPY_MOVE_COMMON_H
115