1 //===----------------------------------------------------------------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef MIN_ALLOCATOR_H 10 #define MIN_ALLOCATOR_H 11 12 #include <cassert> 13 #include <climits> 14 #include <cstddef> 15 #include <cstdlib> 16 #include <iterator> 17 #include <memory> 18 #include <new> 19 #include <type_traits> 20 #include <cstring> 21 22 #include "test_macros.h" 23 24 template <class T> 25 class bare_allocator 26 { 27 public: 28 typedef T value_type; 29 30 bare_allocator() TEST_NOEXCEPT {} 31 32 template <class U> 33 bare_allocator(bare_allocator<U>) TEST_NOEXCEPT {} 34 35 T* allocate(std::size_t n) 36 { 37 return static_cast<T*>(::operator new(n*sizeof(T))); 38 } 39 40 void deallocate(T* p, std::size_t) 41 { 42 return ::operator delete(static_cast<void*>(p)); 43 } 44 45 friend bool operator==(bare_allocator, bare_allocator) {return true;} 46 friend bool operator!=(bare_allocator x, bare_allocator y) {return !(x == y);} 47 }; 48 49 50 template <class T> 51 class no_default_allocator 52 { 53 #if TEST_STD_VER >= 11 54 no_default_allocator() = delete; 55 #else 56 no_default_allocator(); 57 #endif 58 struct construct_tag {}; 59 explicit no_default_allocator(construct_tag) {} 60 61 public: 62 static no_default_allocator create() { 63 construct_tag tag; 64 return no_default_allocator(tag); 65 } 66 67 public: 68 typedef T value_type; 69 70 template <class U> 71 no_default_allocator(no_default_allocator<U>) TEST_NOEXCEPT {} 72 73 T* allocate(std::size_t n) 74 { 75 return static_cast<T*>(::operator new(n*sizeof(T))); 76 } 77 78 void deallocate(T* p, std::size_t) 79 { 80 return ::operator delete(static_cast<void*>(p)); 81 } 82 83 friend bool operator==(no_default_allocator, no_default_allocator) {return true;} 84 friend bool operator!=(no_default_allocator x, no_default_allocator y) {return !(x == y);} 85 }; 86 87 struct malloc_allocator_base { 88 static std::size_t outstanding_bytes; 89 static std::size_t alloc_count; 90 static std::size_t dealloc_count; 91 static bool disable_default_constructor; 92 93 static std::size_t outstanding_alloc() { 94 assert(alloc_count >= dealloc_count); 95 return (alloc_count - dealloc_count); 96 } 97 98 static void reset() { 99 assert(outstanding_alloc() == 0); 100 disable_default_constructor = false; 101 outstanding_bytes = 0; 102 alloc_count = 0; 103 dealloc_count = 0; 104 } 105 }; 106 107 size_t malloc_allocator_base::outstanding_bytes = 0; 108 size_t malloc_allocator_base::alloc_count = 0; 109 size_t malloc_allocator_base::dealloc_count = 0; 110 bool malloc_allocator_base::disable_default_constructor = false; 111 112 113 template <class T> 114 class malloc_allocator : public malloc_allocator_base 115 { 116 public: 117 typedef T value_type; 118 119 malloc_allocator() TEST_NOEXCEPT { assert(!disable_default_constructor); } 120 121 template <class U> 122 malloc_allocator(malloc_allocator<U>) TEST_NOEXCEPT {} 123 124 T* allocate(std::size_t n) 125 { 126 const std::size_t nbytes = n*sizeof(T); 127 ++alloc_count; 128 outstanding_bytes += nbytes; 129 return static_cast<T*>(std::malloc(nbytes)); 130 } 131 132 void deallocate(T* p, std::size_t n) 133 { 134 const std::size_t nbytes = n*sizeof(T); 135 ++dealloc_count; 136 outstanding_bytes -= nbytes; 137 std::free(static_cast<void*>(p)); 138 } 139 140 friend bool operator==(malloc_allocator, malloc_allocator) {return true;} 141 friend bool operator!=(malloc_allocator x, malloc_allocator y) {return !(x == y);} 142 }; 143 144 template <class T> 145 struct cpp03_allocator : bare_allocator<T> 146 { 147 typedef T value_type; 148 typedef value_type* pointer; 149 150 static bool construct_called; 151 152 // Returned value is not used but it's not prohibited. 153 pointer construct(pointer p, const value_type& val) 154 { 155 ::new(p) value_type(val); 156 construct_called = true; 157 return p; 158 } 159 160 std::size_t max_size() const 161 { 162 return UINT_MAX / sizeof(T); 163 } 164 }; 165 template <class T> bool cpp03_allocator<T>::construct_called = false; 166 167 template <class T> 168 struct cpp03_overload_allocator : bare_allocator<T> 169 { 170 typedef T value_type; 171 typedef value_type* pointer; 172 173 static bool construct_called; 174 175 void construct(pointer p, const value_type& val) 176 { 177 construct(p, val, std::is_class<T>()); 178 } 179 void construct(pointer p, const value_type& val, std::true_type) 180 { 181 ::new(p) value_type(val); 182 construct_called = true; 183 } 184 void construct(pointer p, const value_type& val, std::false_type) 185 { 186 ::new(p) value_type(val); 187 construct_called = true; 188 } 189 190 std::size_t max_size() const 191 { 192 return UINT_MAX / sizeof(T); 193 } 194 }; 195 template <class T> bool cpp03_overload_allocator<T>::construct_called = false; 196 197 template <class T, class = std::integral_constant<std::size_t, 0> > class min_pointer; 198 template <class T, class ID> class min_pointer<const T, ID>; 199 template <class ID> class min_pointer<void, ID>; 200 template <class ID> class min_pointer<const void, ID>; 201 template <class T> class min_allocator; 202 203 template <class ID> 204 class min_pointer<const void, ID> 205 { 206 const void* ptr_; 207 public: 208 min_pointer() TEST_NOEXCEPT = default; 209 min_pointer(std::nullptr_t) TEST_NOEXCEPT : ptr_(nullptr) {} 210 template <class T> 211 min_pointer(min_pointer<T, ID> p) TEST_NOEXCEPT : ptr_(p.ptr_) {} 212 213 explicit operator bool() const {return ptr_ != nullptr;} 214 215 friend bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;} 216 friend bool operator!=(min_pointer x, min_pointer y) {return !(x == y);} 217 template <class U, class XID> friend class min_pointer; 218 }; 219 220 template <class ID> 221 class min_pointer<void, ID> 222 { 223 void* ptr_; 224 public: 225 min_pointer() TEST_NOEXCEPT = default; 226 TEST_CONSTEXPR_CXX14 min_pointer(std::nullptr_t) TEST_NOEXCEPT : ptr_(nullptr) {} 227 template <class T, 228 class = typename std::enable_if 229 < 230 !std::is_const<T>::value 231 >::type 232 > 233 TEST_CONSTEXPR_CXX14 min_pointer(min_pointer<T, ID> p) TEST_NOEXCEPT : ptr_(p.ptr_) {} 234 235 TEST_CONSTEXPR_CXX14 explicit operator bool() const {return ptr_ != nullptr;} 236 237 TEST_CONSTEXPR_CXX14 friend bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;} 238 TEST_CONSTEXPR_CXX14 friend bool operator!=(min_pointer x, min_pointer y) {return !(x == y);} 239 template <class U, class XID> friend class min_pointer; 240 }; 241 242 template <class T, class ID> 243 class min_pointer 244 { 245 T* ptr_; 246 247 TEST_CONSTEXPR_CXX14 explicit min_pointer(T* p) TEST_NOEXCEPT : ptr_(p) {} 248 public: 249 min_pointer() TEST_NOEXCEPT = default; 250 TEST_CONSTEXPR_CXX14 min_pointer(std::nullptr_t) TEST_NOEXCEPT : ptr_(nullptr) {} 251 TEST_CONSTEXPR_CXX14 explicit min_pointer(min_pointer<void, ID> p) TEST_NOEXCEPT : ptr_(static_cast<T*>(p.ptr_)) {} 252 253 TEST_CONSTEXPR_CXX14 explicit operator bool() const {return ptr_ != nullptr;} 254 255 typedef std::ptrdiff_t difference_type; 256 typedef T& reference; 257 typedef T* pointer; 258 typedef T value_type; 259 typedef std::random_access_iterator_tag iterator_category; 260 261 TEST_CONSTEXPR_CXX14 reference operator*() const {return *ptr_;} 262 TEST_CONSTEXPR_CXX14 pointer operator->() const {return ptr_;} 263 264 TEST_CONSTEXPR_CXX14 min_pointer& operator++() {++ptr_; return *this;} 265 TEST_CONSTEXPR_CXX14 min_pointer operator++(int) {min_pointer tmp(*this); ++ptr_; return tmp;} 266 267 TEST_CONSTEXPR_CXX14 min_pointer& operator--() {--ptr_; return *this;} 268 TEST_CONSTEXPR_CXX14 min_pointer operator--(int) {min_pointer tmp(*this); --ptr_; return tmp;} 269 270 TEST_CONSTEXPR_CXX14 min_pointer& operator+=(difference_type n) {ptr_ += n; return *this;} 271 TEST_CONSTEXPR_CXX14 min_pointer& operator-=(difference_type n) {ptr_ -= n; return *this;} 272 273 TEST_CONSTEXPR_CXX14 min_pointer operator+(difference_type n) const 274 { 275 min_pointer tmp(*this); 276 tmp += n; 277 return tmp; 278 } 279 280 friend TEST_CONSTEXPR_CXX14 min_pointer operator+(difference_type n, min_pointer x) 281 { 282 return x + n; 283 } 284 285 TEST_CONSTEXPR_CXX14 min_pointer operator-(difference_type n) const 286 { 287 min_pointer tmp(*this); 288 tmp -= n; 289 return tmp; 290 } 291 292 friend TEST_CONSTEXPR_CXX14 difference_type operator-(min_pointer x, min_pointer y) 293 { 294 return x.ptr_ - y.ptr_; 295 } 296 297 TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return ptr_[n];} 298 299 friend TEST_CONSTEXPR_CXX14 bool operator< (min_pointer x, min_pointer y) {return x.ptr_ < y.ptr_;} 300 friend TEST_CONSTEXPR_CXX14 bool operator> (min_pointer x, min_pointer y) {return y < x;} 301 friend TEST_CONSTEXPR_CXX14 bool operator<=(min_pointer x, min_pointer y) {return !(y < x);} 302 friend TEST_CONSTEXPR_CXX14 bool operator>=(min_pointer x, min_pointer y) {return !(x < y);} 303 304 static TEST_CONSTEXPR_CXX14 min_pointer pointer_to(T& t) {return min_pointer(std::addressof(t));} 305 306 friend TEST_CONSTEXPR_CXX14 bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;} 307 friend TEST_CONSTEXPR_CXX14 bool operator!=(min_pointer x, min_pointer y) {return !(x == y);} 308 template <class U, class XID> friend class min_pointer; 309 template <class U> friend class min_allocator; 310 }; 311 312 template <class T, class ID> 313 class min_pointer<const T, ID> 314 { 315 const T* ptr_; 316 317 TEST_CONSTEXPR_CXX14 explicit min_pointer(const T* p) : ptr_(p) {} 318 public: 319 min_pointer() TEST_NOEXCEPT = default; 320 TEST_CONSTEXPR_CXX14 min_pointer(std::nullptr_t) : ptr_(nullptr) {} 321 TEST_CONSTEXPR_CXX14 min_pointer(min_pointer<T, ID> p) : ptr_(p.ptr_) {} 322 TEST_CONSTEXPR_CXX14 explicit min_pointer(min_pointer<const void, ID> p) : ptr_(static_cast<const T*>(p.ptr_)) {} 323 324 TEST_CONSTEXPR_CXX14 explicit operator bool() const {return ptr_ != nullptr;} 325 326 typedef std::ptrdiff_t difference_type; 327 typedef const T& reference; 328 typedef const T* pointer; 329 typedef const T value_type; 330 typedef std::random_access_iterator_tag iterator_category; 331 332 TEST_CONSTEXPR_CXX14 reference operator*() const {return *ptr_;} 333 TEST_CONSTEXPR_CXX14 pointer operator->() const {return ptr_;} 334 335 TEST_CONSTEXPR_CXX14 min_pointer& operator++() {++ptr_; return *this;} 336 TEST_CONSTEXPR_CXX14 min_pointer operator++(int) {min_pointer tmp(*this); ++ptr_; return tmp;} 337 338 TEST_CONSTEXPR_CXX14 min_pointer& operator--() {--ptr_; return *this;} 339 TEST_CONSTEXPR_CXX14 min_pointer operator--(int) {min_pointer tmp(*this); --ptr_; return tmp;} 340 341 TEST_CONSTEXPR_CXX14 min_pointer& operator+=(difference_type n) {ptr_ += n; return *this;} 342 TEST_CONSTEXPR_CXX14 min_pointer& operator-=(difference_type n) {ptr_ -= n; return *this;} 343 344 TEST_CONSTEXPR_CXX14 min_pointer operator+(difference_type n) const 345 { 346 min_pointer tmp(*this); 347 tmp += n; 348 return tmp; 349 } 350 351 friend TEST_CONSTEXPR_CXX14 min_pointer operator+(difference_type n, min_pointer x) 352 { 353 return x + n; 354 } 355 356 TEST_CONSTEXPR_CXX14 min_pointer operator-(difference_type n) const 357 { 358 min_pointer tmp(*this); 359 tmp -= n; 360 return tmp; 361 } 362 363 friend TEST_CONSTEXPR_CXX14 difference_type operator-(min_pointer x, min_pointer y) 364 { 365 return x.ptr_ - y.ptr_; 366 } 367 368 TEST_CONSTEXPR_CXX14 reference operator[](difference_type n) const {return ptr_[n];} 369 370 friend TEST_CONSTEXPR_CXX14 bool operator< (min_pointer x, min_pointer y) {return x.ptr_ < y.ptr_;} 371 friend TEST_CONSTEXPR_CXX14 bool operator> (min_pointer x, min_pointer y) {return y < x;} 372 friend TEST_CONSTEXPR_CXX14 bool operator<=(min_pointer x, min_pointer y) {return !(y < x);} 373 friend TEST_CONSTEXPR_CXX14 bool operator>=(min_pointer x, min_pointer y) {return !(x < y);} 374 375 static TEST_CONSTEXPR_CXX14 min_pointer pointer_to(const T& t) {return min_pointer(std::addressof(t));} 376 377 friend TEST_CONSTEXPR_CXX14 bool operator==(min_pointer x, min_pointer y) {return x.ptr_ == y.ptr_;} 378 friend TEST_CONSTEXPR_CXX14 bool operator!=(min_pointer x, min_pointer y) {return x.ptr_ != y.ptr_;} 379 friend TEST_CONSTEXPR_CXX14 bool operator==(min_pointer x, std::nullptr_t) {return x.ptr_ == nullptr;} 380 friend TEST_CONSTEXPR_CXX14 bool operator!=(min_pointer x, std::nullptr_t) {return x.ptr_ != nullptr;} 381 friend TEST_CONSTEXPR_CXX14 bool operator==(std::nullptr_t, min_pointer x) {return x.ptr_ == nullptr;} 382 friend TEST_CONSTEXPR_CXX14 bool operator!=(std::nullptr_t, min_pointer x) {return x.ptr_ != nullptr;} 383 template <class U, class XID> friend class min_pointer; 384 }; 385 386 template <class T> 387 class min_allocator 388 { 389 public: 390 typedef T value_type; 391 typedef min_pointer<T> pointer; 392 393 min_allocator() = default; 394 template <class U> 395 TEST_CONSTEXPR_CXX20 min_allocator(min_allocator<U>) {} 396 397 TEST_CONSTEXPR_CXX20 pointer allocate(std::ptrdiff_t n) 398 { 399 return pointer(std::allocator<T>().allocate(n)); 400 } 401 402 TEST_CONSTEXPR_CXX20 void deallocate(pointer p, std::ptrdiff_t n) 403 { 404 std::allocator<T>().deallocate(p.ptr_, n); 405 } 406 407 TEST_CONSTEXPR_CXX20 friend bool operator==(min_allocator, min_allocator) {return true;} 408 TEST_CONSTEXPR_CXX20 friend bool operator!=(min_allocator x, min_allocator y) {return !(x == y);} 409 }; 410 411 template <class T> 412 class explicit_allocator 413 { 414 public: 415 typedef T value_type; 416 417 TEST_CONSTEXPR_CXX20 explicit_allocator() TEST_NOEXCEPT {} 418 419 template <class U> 420 TEST_CONSTEXPR_CXX20 explicit explicit_allocator(explicit_allocator<U>) TEST_NOEXCEPT {} 421 422 TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) 423 { 424 return static_cast<T*>(std::allocator<T>().allocate(n)); 425 } 426 427 TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) 428 { 429 std::allocator<T>().deallocate(p, n); 430 } 431 432 TEST_CONSTEXPR_CXX20 friend bool operator==(explicit_allocator, explicit_allocator) {return true;} 433 TEST_CONSTEXPR_CXX20 friend bool operator!=(explicit_allocator x, explicit_allocator y) {return !(x == y);} 434 }; 435 436 template <class T> 437 class unaligned_allocator { 438 public: 439 static_assert(TEST_ALIGNOF(T) == 1, "Type T cannot be created on unaligned address (UB)"); 440 typedef T value_type; 441 442 TEST_CONSTEXPR_CXX20 unaligned_allocator() TEST_NOEXCEPT {} 443 444 template <class U> 445 TEST_CONSTEXPR_CXX20 explicit unaligned_allocator(unaligned_allocator<U>) TEST_NOEXCEPT {} 446 447 TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return std::allocator<T>().allocate(n + 1) + 1; } 448 449 TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator<T>().deallocate(p - 1, n + 1); } 450 451 TEST_CONSTEXPR_CXX20 friend bool operator==(unaligned_allocator, unaligned_allocator) { return true; } 452 TEST_CONSTEXPR_CXX20 friend bool operator!=(unaligned_allocator x, unaligned_allocator y) { return !(x == y); } 453 }; 454 455 template <class T> 456 class safe_allocator { 457 public: 458 typedef T value_type; 459 460 TEST_CONSTEXPR_CXX20 safe_allocator() TEST_NOEXCEPT {} 461 462 template <class U> 463 TEST_CONSTEXPR_CXX20 safe_allocator(safe_allocator<U>) TEST_NOEXCEPT {} 464 465 TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { 466 T* memory = std::allocator<T>().allocate(n); 467 if (!TEST_IS_CONSTANT_EVALUATED) 468 std::memset(static_cast<void*>(memory), 0, sizeof(T) * n); 469 470 return memory; 471 } 472 473 TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { 474 if (!TEST_IS_CONSTANT_EVALUATED) 475 DoNotOptimize(std::memset(static_cast<void*>(p), 0, sizeof(T) * n)); 476 std::allocator<T>().deallocate(p, n); 477 } 478 479 TEST_CONSTEXPR_CXX20 friend bool operator==(safe_allocator, safe_allocator) { return true; } 480 TEST_CONSTEXPR_CXX20 friend bool operator!=(safe_allocator x, safe_allocator y) { return !(x == y); } 481 }; 482 483 #endif // MIN_ALLOCATOR_H 484