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 #include "chre/util/container_support.h"
26 
27 namespace chre {
28 
29 template<typename ElementType>
destroy(ElementType * first,size_t count)30 inline void destroy(ElementType *first, size_t count) {
31   for (size_t i = 0; i < count; i++) {
32     first[i].~ElementType();
33   }
34 }
35 
36 //! Overload used when the type is move assignable
37 template<typename ElementType>
moveOrCopyAssign(ElementType & dest,ElementType & source,std::true_type)38 inline void moveOrCopyAssign(ElementType& dest, ElementType& source,
39                              std::true_type) {
40   dest = std::move(source);
41 }
42 
43 //! Overload used when the type is not move assignable
44 template<typename ElementType>
moveOrCopyAssign(ElementType & dest,ElementType & source,std::false_type)45 inline void moveOrCopyAssign(ElementType& dest, ElementType& source,
46                              std::false_type) {
47   dest = source;
48 }
49 
50 template<typename ElementType>
moveOrCopyAssign(ElementType & dest,ElementType & source)51 inline void moveOrCopyAssign(ElementType& dest, ElementType& source) {
52   moveOrCopyAssign(dest, source,
53                    typename std::is_move_assignable<ElementType>::type());
54 }
55 
56 //! Overload used when type is trivially copy constructible
57 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest,std::true_type)58 inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
59                                     ElementType *dest, std::true_type) {
60   std::memcpy(dest, source, count * sizeof(ElementType));
61 }
62 
63 //! Overload used when type is not trivially copy constructible, but is move
64 //! constructible
65 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest,std::false_type,std::true_type)66 inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
67                                     ElementType *dest, std::false_type,
68                                     std::true_type) {
69   for (size_t i = 0; i < count; i++) {
70     new (&dest[i]) ElementType(std::move(source[i]));
71   }
72 }
73 
74 //! Overload used when type is not trivially copy constructible or move
75 //! constructible
76 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest,std::false_type,std::false_type)77 inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
78                                     ElementType *dest, std::false_type,
79                                     std::false_type) {
80   for (size_t i = 0; i < count; i++) {
81     new (&dest[i]) ElementType(source[i]);
82   }
83 }
84 
85 //! Overload used when type is not trivially copy constructible
86 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest,std::false_type)87 inline void uninitializedMoveOrCopy(
88     ElementType *source, size_t count, ElementType *dest, std::false_type) {
89   // Check the assumption that if is_move_constructible is false, then
90   // is_copy_constructible is true
91   static_assert(std::is_move_constructible<ElementType>()
92                 || std::is_copy_constructible<ElementType>(),
93                 "Object must be copy- or move- constructible to use "
94                 "unintializedMoveOrCopy");
95   uninitializedMoveOrCopy(
96       source, count, dest, std::false_type(),
97       typename std::is_move_constructible<ElementType>::type());
98 }
99 
100 template<typename ElementType>
uninitializedMoveOrCopy(ElementType * source,size_t count,ElementType * dest)101 inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
102                                     ElementType *dest) {
103   // TODO: we should be able to use std::is_trivially_copy_constructible here,
104   // but it's not found in the linux x86 build, because our build uses GCC 4.8's
105   // C++ standard library, which doesn't support it. Works in the SLPI build,
106   // though...
107   uninitializedMoveOrCopy(
108       source, count, dest, typename std::is_trivial<ElementType>::type());
109       //typename std::is_trivially_copy_constructible<ElementType>::type());
110 }
111 
112 template<typename T, typename... Args>
memoryAlloc(Args &&...args)113 inline T *memoryAlloc(Args&&... args) {
114   auto *storage = static_cast<T *>(memoryAlloc(sizeof(T)));
115   if (storage != nullptr) {
116     new(storage) T(std::forward<Args>(args)...);
117   }
118 
119   return storage;
120 }
121 
122 }  // namespace chre
123 
124 #endif  // CHRE_UTIL_MEMORY_IMPL_H_
125