//===----------------------------------------------------------------------===// // // The LLVM Compiler Infrastructure // // This file is dual licensed under the MIT and the University of Illinois Open // Source Licenses. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #ifndef TEST_ALLOCATOR_H #define TEST_ALLOCATOR_H #include #include #include #include #include #include #include "test_macros.h" class test_alloc_base { protected: static int time_to_throw; public: static int throw_after; static int count; static int alloc_count; }; int test_alloc_base::count = 0; int test_alloc_base::time_to_throw = 0; int test_alloc_base::alloc_count = 0; int test_alloc_base::throw_after = INT_MAX; template class test_allocator : public test_alloc_base { int data_; template friend class test_allocator; public: typedef unsigned size_type; typedef int difference_type; typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef typename std::add_lvalue_reference::type reference; typedef typename std::add_lvalue_reference::type const_reference; template struct rebind {typedef test_allocator other;}; test_allocator() throw() : data_(0) {++count;} explicit test_allocator(int i) throw() : data_(i) {++count;} test_allocator(const test_allocator& a) throw() : data_(a.data_) {++count;} template test_allocator(const test_allocator& a) throw() : data_(a.data_) {++count;} ~test_allocator() throw() {assert(data_ >= 0); --count; data_ = -1;} pointer address(reference x) const {return &x;} const_pointer address(const_reference x) const {return &x;} pointer allocate(size_type n, const void* = 0) { assert(data_ >= 0); if (time_to_throw >= throw_after) { #ifndef _LIBCPP_NO_EXCEPTIONS throw std::bad_alloc(); #else std::terminate(); #endif } ++time_to_throw; ++alloc_count; return (pointer)::operator new(n * sizeof(T)); } void deallocate(pointer p, size_type) {assert(data_ >= 0); --alloc_count; ::operator delete((void*)p);} size_type max_size() const throw() {return UINT_MAX / sizeof(T);} #if TEST_STD_VER < 11 void construct(pointer p, const T& val) {::new(static_cast(p)) T(val);} #else template void construct(pointer p, U&& val) {::new(static_cast(p)) T(std::forward(val));} #endif void destroy(pointer p) { p->~T(); ((void)p); // Prevent MSVC's spurious unused warning } friend bool operator==(const test_allocator& x, const test_allocator& y) {return x.data_ == y.data_;} friend bool operator!=(const test_allocator& x, const test_allocator& y) {return !(x == y);} }; template class non_default_test_allocator : public test_alloc_base { int data_; template friend class non_default_test_allocator; public: typedef unsigned size_type; typedef int difference_type; typedef T value_type; typedef value_type* pointer; typedef const value_type* const_pointer; typedef typename std::add_lvalue_reference::type reference; typedef typename std::add_lvalue_reference::type const_reference; template struct rebind {typedef non_default_test_allocator other;}; // non_default_test_allocator() throw() : data_(0) {++count;} explicit non_default_test_allocator(int i) throw() : data_(i) {++count;} non_default_test_allocator(const non_default_test_allocator& a) throw() : data_(a.data_) {++count;} template non_default_test_allocator(const non_default_test_allocator& a) throw() : data_(a.data_) {++count;} ~non_default_test_allocator() throw() {assert(data_ >= 0); --count; data_ = -1;} pointer address(reference x) const {return &x;} const_pointer address(const_reference x) const {return &x;} pointer allocate(size_type n, const void* = 0) { assert(data_ >= 0); if (time_to_throw >= throw_after) { #ifndef _LIBCPP_NO_EXCEPTIONS throw std::bad_alloc(); #else std::terminate(); #endif } ++time_to_throw; ++alloc_count; return (pointer)::operator new (n * sizeof(T)); } void deallocate(pointer p, size_type) {assert(data_ >= 0); --alloc_count; ::operator delete((void*)p); } size_type max_size() const throw() {return UINT_MAX / sizeof(T);} #if TEST_STD_VER < 11 void construct(pointer p, const T& val) {::new(static_cast(p)) T(val);} #else template void construct(pointer p, U&& val) {::new(static_cast(p)) T(std::forward(val));} #endif void destroy(pointer p) {p->~T();} friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y) {return x.data_ == y.data_;} friend bool operator!=(const non_default_test_allocator& x, const non_default_test_allocator& y) {return !(x == y);} }; template <> class test_allocator : public test_alloc_base { int data_; template friend class test_allocator; public: typedef unsigned size_type; typedef int difference_type; typedef void value_type; typedef value_type* pointer; typedef const value_type* const_pointer; template struct rebind {typedef test_allocator other;}; test_allocator() throw() : data_(0) {} explicit test_allocator(int i) throw() : data_(i) {} test_allocator(const test_allocator& a) throw() : data_(a.data_) {} template test_allocator(const test_allocator& a) throw() : data_(a.data_) {} ~test_allocator() throw() {data_ = -1;} friend bool operator==(const test_allocator& x, const test_allocator& y) {return x.data_ == y.data_;} friend bool operator!=(const test_allocator& x, const test_allocator& y) {return !(x == y);} }; template class other_allocator { int data_; template friend class other_allocator; public: typedef T value_type; other_allocator() : data_(-1) {} explicit other_allocator(int i) : data_(i) {} template other_allocator(const other_allocator& a) : data_(a.data_) {} T* allocate(std::size_t n) {return (T*)::operator new(n * sizeof(T));} void deallocate(T* p, std::size_t) {::operator delete((void*)p);} other_allocator select_on_container_copy_construction() const {return other_allocator(-2);} friend bool operator==(const other_allocator& x, const other_allocator& y) {return x.data_ == y.data_;} friend bool operator!=(const other_allocator& x, const other_allocator& y) {return !(x == y);} typedef std::true_type propagate_on_container_copy_assignment; typedef std::true_type propagate_on_container_move_assignment; typedef std::true_type propagate_on_container_swap; #ifdef _LIBCPP_HAS_NO_ADVANCED_SFINAE std::size_t max_size() const {return UINT_MAX / sizeof(T);} #endif // _LIBCPP_HAS_NO_ADVANCED_SFINAE }; #if TEST_STD_VER >= 11 struct Ctor_Tag {}; template class TaggingAllocator; struct Tag_X { // All constructors must be passed the Tag type. // DefaultInsertable into vector>, Tag_X(Ctor_Tag) {} // CopyInsertable into vector>, Tag_X(Ctor_Tag, const Tag_X&) {} // MoveInsertable into vector>, and Tag_X(Ctor_Tag, Tag_X&&) {} // EmplaceConstructible into vector> from args. template Tag_X(Ctor_Tag, Args&&...) { } // not DefaultConstructible, CopyConstructible or MoveConstructible. Tag_X() = delete; Tag_X(const Tag_X&) = delete; Tag_X(Tag_X&&) = delete; // CopyAssignable. Tag_X& operator=(const Tag_X&) { return *this; } // MoveAssignable. Tag_X& operator=(Tag_X&&) { return *this; } private: // Not Destructible. ~Tag_X() { } // Erasable from vector>. friend class TaggingAllocator; }; template class TaggingAllocator { public: using value_type = T; TaggingAllocator() = default; template TaggingAllocator(const TaggingAllocator&) { } T* allocate(std::size_t n) { return std::allocator{}.allocate(n); } void deallocate(T* p, std::size_t n) { std::allocator{}.deallocate(p, n); } template void construct(Tag_X* p, Args&&... args) { ::new((void*)p) Tag_X(Ctor_Tag{}, std::forward(args)...); } template void construct(U* p, Args&&... args) { ::new((void*)p) U(std::forward(args)...); } template void destroy(U* p) { p->~U(); } }; template bool operator==(const TaggingAllocator&, const TaggingAllocator&) { return true; } template bool operator!=(const TaggingAllocator&, const TaggingAllocator&) { return false; } #endif #endif // TEST_ALLOCATOR_H