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