1 // -*- C++ -*- 2 //===----------------------------------------------------------------------===// 3 // 4 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 5 // See https://llvm.org/LICENSE.txt for license information. 6 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 7 // 8 //===----------------------------------------------------------------------===// 9 10 #ifndef _LIBCPP___MEMORY_ALLOCATOR_H 11 #define _LIBCPP___MEMORY_ALLOCATOR_H 12 13 #include <__config> 14 #include <__memory/allocate_at_least.h> 15 #include <__memory/allocator_traits.h> 16 #include <__utility/forward.h> 17 #include <cstddef> 18 #include <new> 19 #include <stdexcept> 20 #include <type_traits> 21 22 #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) 23 # pragma GCC system_header 24 #endif 25 26 _LIBCPP_BEGIN_NAMESPACE_STD 27 28 template <class _Tp> class allocator; 29 30 #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_VOID_SPECIALIZATION) 31 template <> 32 class _LIBCPP_TEMPLATE_VIS allocator<void> 33 { 34 #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS) 35 public: 36 _LIBCPP_DEPRECATED_IN_CXX17 typedef void* pointer; 37 _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer; 38 _LIBCPP_DEPRECATED_IN_CXX17 typedef void value_type; 39 40 template <class _Up> struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {typedef allocator<_Up> other;}; 41 #endif 42 }; 43 44 template <> 45 class _LIBCPP_TEMPLATE_VIS allocator<const void> 46 { 47 #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS) 48 public: 49 _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* pointer; 50 _LIBCPP_DEPRECATED_IN_CXX17 typedef const void* const_pointer; 51 _LIBCPP_DEPRECATED_IN_CXX17 typedef const void value_type; 52 53 template <class _Up> struct _LIBCPP_DEPRECATED_IN_CXX17 rebind {typedef allocator<_Up> other;}; 54 #endif 55 }; 56 #endif 57 58 // This class provides a non-trivial default constructor to the class that derives from it 59 // if the condition is satisfied. 60 // 61 // The second template parameter exists to allow giving a unique type to __non_trivial_if, 62 // which makes it possible to avoid breaking the ABI when making this a base class of an 63 // existing class. Without that, imagine we have classes D1 and D2, both of which used to 64 // have no base classes, but which now derive from __non_trivial_if. The layout of a class 65 // that inherits from both D1 and D2 will change because the two __non_trivial_if base 66 // classes are not allowed to share the same address. 67 // 68 // By making those __non_trivial_if base classes unique, we work around this problem and 69 // it is safe to start deriving from __non_trivial_if in existing classes. 70 template <bool _Cond, class _Unique> 71 struct __non_trivial_if { }; 72 73 template <class _Unique> 74 struct __non_trivial_if<true, _Unique> { 75 _LIBCPP_INLINE_VISIBILITY 76 _LIBCPP_CONSTEXPR __non_trivial_if() _NOEXCEPT { } 77 }; 78 79 // allocator 80 // 81 // Note: For ABI compatibility between C++20 and previous standards, we make 82 // allocator<void> trivial in C++20. 83 84 template <class _Tp> 85 class _LIBCPP_TEMPLATE_VIS allocator 86 : private __non_trivial_if<!is_void<_Tp>::value, allocator<_Tp> > 87 { 88 static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types"); 89 public: 90 typedef size_t size_type; 91 typedef ptrdiff_t difference_type; 92 typedef _Tp value_type; 93 typedef true_type propagate_on_container_move_assignment; 94 typedef true_type is_always_equal; 95 96 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 97 allocator() _NOEXCEPT = default; 98 99 template <class _Up> 100 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 101 allocator(const allocator<_Up>&) _NOEXCEPT { } 102 103 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 104 _Tp* allocate(size_t __n) { 105 if (__n > allocator_traits<allocator>::max_size(*this)) 106 __throw_bad_array_new_length(); 107 if (__libcpp_is_constant_evaluated()) { 108 return static_cast<_Tp*>(::operator new(__n * sizeof(_Tp))); 109 } else { 110 return static_cast<_Tp*>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp))); 111 } 112 } 113 114 #if _LIBCPP_STD_VER > 20 115 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr 116 allocation_result<_Tp*> allocate_at_least(size_t __n) { 117 return {allocate(__n), __n}; 118 } 119 #endif 120 121 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 122 void deallocate(_Tp* __p, size_t __n) _NOEXCEPT { 123 if (__libcpp_is_constant_evaluated()) { 124 ::operator delete(__p); 125 } else { 126 _VSTD::__libcpp_deallocate((void*)__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)); 127 } 128 } 129 130 // C++20 Removed members 131 #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS) 132 _LIBCPP_DEPRECATED_IN_CXX17 typedef _Tp* pointer; 133 _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* const_pointer; 134 _LIBCPP_DEPRECATED_IN_CXX17 typedef _Tp& reference; 135 _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& const_reference; 136 137 template <class _Up> 138 struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { 139 typedef allocator<_Up> other; 140 }; 141 142 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY 143 pointer address(reference __x) const _NOEXCEPT { 144 return _VSTD::addressof(__x); 145 } 146 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY 147 const_pointer address(const_reference __x) const _NOEXCEPT { 148 return _VSTD::addressof(__x); 149 } 150 151 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_IN_CXX17 152 _Tp* allocate(size_t __n, const void*) { 153 return allocate(__n); 154 } 155 156 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT { 157 return size_type(~0) / sizeof(_Tp); 158 } 159 160 template <class _Up, class... _Args> 161 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY 162 void construct(_Up* __p, _Args&&... __args) { 163 ::new ((void*)__p) _Up(_VSTD::forward<_Args>(__args)...); 164 } 165 166 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY 167 void destroy(pointer __p) { 168 __p->~_Tp(); 169 } 170 #endif 171 }; 172 173 template <class _Tp> 174 class _LIBCPP_TEMPLATE_VIS allocator<const _Tp> 175 : private __non_trivial_if<!is_void<_Tp>::value, allocator<const _Tp> > 176 { 177 static_assert(!is_volatile<_Tp>::value, "std::allocator does not support volatile types"); 178 public: 179 typedef size_t size_type; 180 typedef ptrdiff_t difference_type; 181 typedef const _Tp value_type; 182 typedef true_type propagate_on_container_move_assignment; 183 typedef true_type is_always_equal; 184 185 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 186 allocator() _NOEXCEPT = default; 187 188 template <class _Up> 189 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 190 allocator(const allocator<_Up>&) _NOEXCEPT { } 191 192 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 193 const _Tp* allocate(size_t __n) { 194 if (__n > allocator_traits<allocator>::max_size(*this)) 195 __throw_bad_array_new_length(); 196 if (__libcpp_is_constant_evaluated()) { 197 return static_cast<const _Tp*>(::operator new(__n * sizeof(_Tp))); 198 } else { 199 return static_cast<const _Tp*>(_VSTD::__libcpp_allocate(__n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp))); 200 } 201 } 202 203 #if _LIBCPP_STD_VER > 20 204 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr 205 allocation_result<const _Tp*> allocate_at_least(size_t __n) { 206 return {allocate(__n), __n}; 207 } 208 #endif 209 210 _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 211 void deallocate(const _Tp* __p, size_t __n) { 212 if (__libcpp_is_constant_evaluated()) { 213 ::operator delete(const_cast<_Tp*>(__p)); 214 } else { 215 _VSTD::__libcpp_deallocate((void*) const_cast<_Tp *>(__p), __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)); 216 } 217 } 218 219 // C++20 Removed members 220 #if _LIBCPP_STD_VER <= 17 || defined(_LIBCPP_ENABLE_CXX20_REMOVED_ALLOCATOR_MEMBERS) 221 _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* pointer; 222 _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp* const_pointer; 223 _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& reference; 224 _LIBCPP_DEPRECATED_IN_CXX17 typedef const _Tp& const_reference; 225 226 template <class _Up> 227 struct _LIBCPP_DEPRECATED_IN_CXX17 rebind { 228 typedef allocator<_Up> other; 229 }; 230 231 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY 232 const_pointer address(const_reference __x) const _NOEXCEPT { 233 return _VSTD::addressof(__x); 234 } 235 236 _LIBCPP_NODISCARD_AFTER_CXX17 _LIBCPP_INLINE_VISIBILITY _LIBCPP_DEPRECATED_IN_CXX17 237 const _Tp* allocate(size_t __n, const void*) { 238 return allocate(__n); 239 } 240 241 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT { 242 return size_type(~0) / sizeof(_Tp); 243 } 244 245 template <class _Up, class... _Args> 246 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY 247 void construct(_Up* __p, _Args&&... __args) { 248 ::new ((void*)__p) _Up(_VSTD::forward<_Args>(__args)...); 249 } 250 251 _LIBCPP_DEPRECATED_IN_CXX17 _LIBCPP_INLINE_VISIBILITY 252 void destroy(pointer __p) { 253 __p->~_Tp(); 254 } 255 #endif 256 }; 257 258 template <class _Tp, class _Up> 259 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 260 bool operator==(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return true;} 261 262 template <class _Tp, class _Up> 263 inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX17 264 bool operator!=(const allocator<_Tp>&, const allocator<_Up>&) _NOEXCEPT {return false;} 265 266 _LIBCPP_END_NAMESPACE_STD 267 268 #endif // _LIBCPP___MEMORY_ALLOCATOR_H 269