1 /** 2 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. 3 * SPDX-License-Identifier: Apache-2.0. 4 */ 5 6 #pragma once 7 8 #include <aws/core/Core_EXPORTS.h> 9 #include <aws/core/utils/UnreferencedParam.h> 10 #include <aws/core/utils/memory/MemorySystemInterface.h> 11 12 #include <memory> 13 #include <cstdlib> 14 #include <algorithm> 15 #include <type_traits> 16 17 struct aws_allocator; 18 19 namespace Aws 20 { 21 namespace Utils 22 { 23 namespace Memory 24 { 25 /** 26 *InitializeAWSMemory should be called at the very start of your program 27 */ 28 AWS_CORE_API void InitializeAWSMemorySystem(MemorySystemInterface& memorySystem); 29 30 /** 31 * ShutdownAWSMemory should be called the very end of your program 32 */ 33 AWS_CORE_API void ShutdownAWSMemorySystem(void); 34 35 /** 36 * Get the globally install memory system, if it has been installed. 37 */ 38 AWS_CORE_API MemorySystemInterface* GetMemorySystem(); 39 40 } // namespace Memory 41 } // namespace Utils 42 43 /** 44 * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code 45 * use these functions instead or Aws::MakeShared 46 */ 47 AWS_CORE_API void* Malloc(const char* allocationTag, size_t allocationSize); 48 49 /** 50 * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code 51 * use these functions instead or Aws::MakeShared 52 */ 53 AWS_CORE_API void Free(void* memoryPtr); 54 55 AWS_CORE_API aws_allocator* get_aws_allocator(); 56 57 /** 58 * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code 59 * use these functions instead or Aws::MakeShared 60 */ 61 template<typename T, typename ...ArgTypes> New(const char * allocationTag,ArgTypes &&...args)62 T* New(const char* allocationTag, ArgTypes&&... args) 63 { 64 void *rawMemory = Malloc(allocationTag, sizeof(T)); 65 // http://stackoverflow.com/questions/6783993/placement-new-and-delete 66 T *constructedMemory = new (rawMemory) T(std::forward<ArgTypes>(args)...); 67 return constructedMemory; 68 } 69 /* 70 * dynamic_cast of all sorts do not work on MSVC if RTTI is turned off. 71 * This means that deleting an object via a pointer to one of its polymorphic base types that do not point to the 72 * address of their concrete class will result in undefined behavior. 73 * Example: 74 * struct Foo : InterfaceA, InterfaceB {}; 75 * Aws::Delete(pointerToInterfaceB); 76 */ 77 #if defined(_MSC_VER) && !defined(_CPPRTTI) 78 template<typename T> Delete(T * pointerToT)79 void Delete(T* pointerToT) 80 { 81 if (pointerToT == nullptr) 82 { 83 return; 84 } 85 pointerToT->~T(); 86 Free(pointerToT); 87 } 88 #else 89 /** 90 * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code 91 * use these functions instead or Aws::MakeShared 92 */ 93 template<typename T> Delete(T * pointerToT)94 typename std::enable_if<!std::is_polymorphic<T>::value>::type Delete(T* pointerToT) 95 { 96 if (pointerToT == nullptr) 97 { 98 return; 99 } 100 //http://stackoverflow.com/questions/6783993/placement-new-and-delete 101 pointerToT->~T(); 102 Free(pointerToT); 103 } 104 105 template<typename T> Delete(T * pointerToT)106 typename std::enable_if<std::is_polymorphic<T>::value>::type Delete(T* pointerToT) 107 { 108 if (pointerToT == nullptr) 109 { 110 return; 111 } 112 // deal with deleting objects that implement multiple interfaces 113 // see casting to pointer to void in http://en.cppreference.com/w/cpp/language/dynamic_cast 114 // https://stackoverflow.com/questions/8123776/are-there-practical-uses-for-dynamic-casting-to-void-pointer 115 // NOTE: on some compilers, calling the destructor before doing the dynamic_cast affects how calculation of 116 // the address of the most derived class. 117 void* mostDerivedT = dynamic_cast<void*>(pointerToT); 118 pointerToT->~T(); 119 Free(mostDerivedT); 120 } 121 #endif // _CPPRTTI 122 123 template<typename T> ShouldConstructArrayMembers()124 bool ShouldConstructArrayMembers() 125 { 126 return std::is_class<T>::value; 127 } 128 129 template<typename T> ShouldDestroyArrayMembers()130 bool ShouldDestroyArrayMembers() 131 { 132 return !std::is_trivially_destructible<T>::value; 133 } 134 135 /** 136 * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code 137 * use these functions instead or Aws::MakeShared 138 */ 139 template<typename T> NewArray(std::size_t amount,const char * allocationTag)140 T* NewArray(std::size_t amount, const char* allocationTag) 141 { 142 if (amount > 0) 143 { 144 bool constructMembers = ShouldConstructArrayMembers<T>(); 145 bool trackMemberCount = ShouldDestroyArrayMembers<T>(); 146 147 // if we need to remember the # of items in the array (because we need to call their destructors) then allocate extra memory and keep the # of items in the extra slot 148 std::size_t allocationSize = amount * sizeof(T); 149 #if defined(_MSC_VER) && _MSC_VER < 1900 150 std::size_t headerSize = (std::max)(sizeof(std::size_t), __alignof(T)); 151 #else 152 std::size_t headerSize = (std::max)(sizeof(std::size_t), alignof(T)); 153 #endif 154 155 if (trackMemberCount) 156 { 157 allocationSize += headerSize; 158 } 159 160 void* rawMemory = Malloc(allocationTag, allocationSize); 161 T* pointerToT = nullptr; 162 163 if (trackMemberCount) 164 { 165 std::size_t* pointerToAmount = reinterpret_cast<std::size_t*>(rawMemory); 166 *pointerToAmount = amount; 167 pointerToT = reinterpret_cast<T*>(reinterpret_cast<char*>(pointerToAmount) + headerSize); 168 169 } 170 else 171 { 172 pointerToT = reinterpret_cast<T*>(rawMemory); 173 } 174 175 if (constructMembers) 176 { 177 for (std::size_t i = 0; i < amount; ++i) 178 { 179 new (pointerToT + i) T; 180 } 181 } 182 183 return pointerToT; 184 } 185 186 return nullptr; 187 } 188 189 /** 190 * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code 191 * use these functions instead or Aws::MakeShared 192 */ 193 template<typename T> DeleteArray(T * pointerToTArray)194 void DeleteArray(T* pointerToTArray) 195 { 196 if (pointerToTArray == nullptr) 197 { 198 return; 199 } 200 201 bool destroyMembers = ShouldDestroyArrayMembers<T>(); 202 void* rawMemory = nullptr; 203 204 if (destroyMembers) 205 { 206 #if defined(_MSC_VER) && _MSC_VER < 1900 207 std::size_t headerSize = (std::max)(sizeof(std::size_t), __alignof(T)); 208 #else 209 std::size_t headerSize = (std::max)(sizeof(std::size_t), alignof(T)); 210 #endif 211 212 std::size_t *pointerToAmount = reinterpret_cast<std::size_t*>(reinterpret_cast<char*>(pointerToTArray) - headerSize); 213 std::size_t amount = *pointerToAmount; 214 215 for (std::size_t i = amount; i > 0; --i) 216 { 217 (pointerToTArray + i - 1)->~T(); 218 } 219 rawMemory = reinterpret_cast<void *>(pointerToAmount); 220 } 221 else 222 { 223 rawMemory = reinterpret_cast<void *>(pointerToTArray); 224 } 225 226 Free(rawMemory); 227 } 228 229 /** 230 * modeled from std::default_delete 231 */ 232 template<typename T> 233 struct Deleter 234 { DeleterDeleter235 Deleter() {} 236 237 template<class U, class = typename std::enable_if<std::is_convertible<U *, T *>::value, void>::type> DeleterDeleter238 Deleter(const Deleter<U>&) 239 { 240 } 241 operatorDeleter242 void operator()(T *pointerToT) const 243 { 244 static_assert(0 < sizeof(T), "can't delete an incomplete type"); 245 Aws::Delete(pointerToT); 246 } 247 }; 248 249 template< typename T > using UniquePtr = std::unique_ptr< T, Deleter< T > >; 250 251 /** 252 * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code 253 * use these functions instead or Aws::MakeShared 254 */ 255 template<typename T, typename ...ArgTypes> MakeUnique(const char * allocationTag,ArgTypes &&...args)256 UniquePtr<T> MakeUnique(const char* allocationTag, ArgTypes&&... args) 257 { 258 return UniquePtr<T>(Aws::New<T>(allocationTag, std::forward<ArgTypes>(args)...)); 259 } 260 261 template<typename T> 262 struct ArrayDeleter 263 { ArrayDeleterArrayDeleter264 ArrayDeleter() {} 265 266 template<class U, class = typename std::enable_if<std::is_convertible<U *, T *>::value, void>::type> ArrayDeleterArrayDeleter267 ArrayDeleter(const ArrayDeleter<U>&) 268 { 269 } 270 operatorArrayDeleter271 void operator()(T *pointerToTArray) const 272 { 273 static_assert(0 < sizeof(T), "can't delete an incomplete type"); 274 Aws::DeleteArray(pointerToTArray); 275 } 276 }; 277 278 template< typename T > using UniqueArrayPtr = std::unique_ptr< T, ArrayDeleter< T > >; 279 280 /** 281 * ::new, ::delete, ::malloc, ::free, std::make_shared, and std::make_unique should not be used in SDK code 282 * use these functions instead or Aws::MakeShared 283 */ 284 template<typename T, typename ...ArgTypes> MakeUniqueArray(std::size_t amount,const char * allocationTag,ArgTypes &&...args)285 UniqueArrayPtr<T> MakeUniqueArray(std::size_t amount, const char* allocationTag, ArgTypes&&... args) 286 { 287 return UniqueArrayPtr<T>(Aws::NewArray<T>(amount, allocationTag, std::forward<ArgTypes>(args)...)); 288 } 289 290 } // namespace Aws 291 292