1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #ifndef CHRE_UTIL_MEMORY_IMPL_H_
18 #define CHRE_UTIL_MEMORY_IMPL_H_
19 
20 #include <cstring>
21 #include <new>
22 #include <type_traits>
23 #include <utility>
24 
25 namespace chre {
26 
27 template<typename ElementType>
destroy(ElementType * first,size_t count)28 inline void destroy(ElementType *first, size_t count) {
29   for (size_t i = 0; i < count; i++) {
30     first[i].~ElementType();
31   }
32 }
33 
34 //! Overload used when the type is move assignable
35 template<typename ElementType>
moveOrCopyAssign(ElementType & dest,ElementType & source,std::true_type)36 inline void moveOrCopyAssign(ElementType& dest, ElementType& source,
37                              std::true_type) {
38   dest = std::move(source);
39 }
40 
41 //! Overload used when the type is not move assignable
42 template<typename ElementType>
moveOrCopyAssign(ElementType & dest,ElementType & source,std::false_type)43 inline void moveOrCopyAssign(ElementType& dest, ElementType& source,
44                              std::false_type) {
45   dest = source;
46 }
47 
48 template<typename ElementType>
moveOrCopyAssign(ElementType & dest,ElementType & source)49 inline void moveOrCopyAssign(ElementType& dest, ElementType& source) {
50   moveOrCopyAssign(dest, source,
51                    typename std::is_move_assignable<ElementType>::type());
52 }
53 
54 //! Overload used when type is trivially copy constructible
55 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest,std::true_type)56 inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
57                                     ElementType *dest, std::true_type) {
58   std::memcpy(dest, source, count * sizeof(ElementType));
59 }
60 
61 //! Overload used when type is not trivially copy constructible, but is move
62 //! constructible
63 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest,std::false_type,std::true_type)64 inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
65                                     ElementType *dest, std::false_type,
66                                     std::true_type) {
67   for (size_t i = 0; i < count; i++) {
68     new (&dest[i]) ElementType(std::move(source[i]));
69   }
70 }
71 
72 //! Overload used when type is not trivially copy constructible or move
73 //! constructible
74 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest,std::false_type,std::false_type)75 inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
76                                     ElementType *dest, std::false_type,
77                                     std::false_type) {
78   for (size_t i = 0; i < count; i++) {
79     new (&dest[i]) ElementType(source[i]);
80   }
81 }
82 
83 //! Overload used when type is not trivially copy constructible
84 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest,std::false_type)85 inline void uninitializedMoveOrCopy(
86     ElementType *source, size_t count, ElementType *dest, std::false_type) {
87   // Check the assumption that if is_move_constructible is false, then
88   // is_copy_constructible is true
89   static_assert(std::is_move_constructible<ElementType>()
90                 || std::is_copy_constructible<ElementType>(),
91                 "Object must be copy- or move- constructible to use "
92                 "unintializedMoveOrCopy");
93   uninitializedMoveOrCopy(
94       source, count, dest, std::false_type(),
95       typename std::is_move_constructible<ElementType>::type());
96 }
97 
98 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest)99 inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
100                                     ElementType *dest) {
101   // TODO: we should be able to use std::is_trivially_copy_constructible here,
102   // but it's not found in the linux x86 build, because our build uses GCC 4.8's
103   // C++ standard library, which doesn't support it. Works in the SLPI build,
104   // though...
105   uninitializedMoveOrCopy(
106       source, count, dest, typename std::is_trivial<ElementType>::type());
107       //typename std::is_trivially_copy_constructible<ElementType>::type());
108 }
109 
110 }  // namespace chre
111 
112 #endif  // CHRE_UTIL_MEMORY_IMPL_H_
113