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