diff options
author | Eric Fiselier <eric@efcs.ca> | 2016-10-08 00:56:22 +0000 |
---|---|---|
committer | Eric Fiselier <eric@efcs.ca> | 2016-10-08 00:56:22 +0000 |
commit | 69a4f66114eed30c06d403bf3cb1e2e9360a20d4 (patch) | |
tree | 4346c82c28e057ed970e3edf060213ec04268d9d /libcxx/test/support/test_allocator.h | |
parent | ddb7a59fe92533e92006f7bdde2d3a4e4abb2c3a (diff) | |
download | bcm5719-llvm-69a4f66114eed30c06d403bf3cb1e2e9360a20d4.tar.gz bcm5719-llvm-69a4f66114eed30c06d403bf3cb1e2e9360a20d4.zip |
[libc++] Fix stack_allocator
Summary:
To quote STL the problems with stack allocator are"
>"stack_allocator<T, N> is seriously nonconformant to N4582 17.6.3.5 [allocator.requirements].
> First, it lacks a rebinding constructor. (The nested "struct rebind" isn't sufficient.)
> Second, it lacks templated equality/inequality.
> Third, it completely ignores alignment.
> Finally, and most severely, the Standard forbids its existence. Allocators are forbidden from returning memory "inside themselves". This requirement is implied by the Standard's requirements for rebinding and equality. It's permitted to return memory from a separate buffer object on the stack, though."
This patch attempts to address all of those issues.
First, instead of storing the buffer inside the allocator I've change `stack_allocator` to accept the buffer as an argument.
Second, in order to fix rebinding I changed the parameter list from `<class T, size_t NumElements>` to `<class T, size_t NumBytes>`. This allows allocator rebinding
between types that have different sizes.
Third, I added copy and rebinding constructors and assignment operators.
And finally I fixed the allocation logic to always return properly aligned storage.
Reviewers: mclow.lists, howard.hinnant, STL_MSFT
Subscribers: cfe-commits
Differential Revision: https://reviews.llvm.org/D25154
llvm-svn: 283631
Diffstat (limited to 'libcxx/test/support/test_allocator.h')
-rw-r--r-- | libcxx/test/support/test_allocator.h | 73 |
1 files changed, 73 insertions, 0 deletions
diff --git a/libcxx/test/support/test_allocator.h b/libcxx/test/support/test_allocator.h index 394d1ccd450..41473371500 100644 --- a/libcxx/test/support/test_allocator.h +++ b/libcxx/test/support/test_allocator.h @@ -302,5 +302,78 @@ operator!=(const TaggingAllocator<T>&, const TaggingAllocator<U>&) { return false; } #endif +template <std::size_t MaxAllocs> +struct limited_alloc_handle { + std::size_t outstanding_; + void* last_alloc_; + + limited_alloc_handle() : outstanding_(0), last_alloc_(nullptr) {} + + template <class T> + T *allocate(std::size_t N) { + if (N + outstanding_ > MaxAllocs) + TEST_THROW(std::bad_alloc()); + last_alloc_ = ::operator new(N*sizeof(T)); + outstanding_ += N; + return static_cast<T*>(last_alloc_); + } + + void deallocate(void* ptr, std::size_t N) { + if (ptr == last_alloc_) { + last_alloc_ = nullptr; + assert(outstanding_ >= N); + outstanding_ -= N; + } + ::operator delete(ptr); + } +}; + +template <class T, std::size_t N> +class limited_allocator +{ + typedef limited_alloc_handle<N> BuffT; + std::shared_ptr<BuffT> handle_; +public: + typedef T value_type; + typedef value_type* pointer; + typedef const value_type* const_pointer; + typedef value_type& reference; + typedef const value_type& const_reference; + typedef std::size_t size_type; + typedef std::ptrdiff_t difference_type; + + template <class U> struct rebind { typedef limited_allocator<U, N> other; }; + + limited_allocator() : handle_(new BuffT) {} + + limited_allocator(limited_allocator const& other) : handle_(other.handle_) {} + + template <class U> + explicit limited_allocator(limited_allocator<U, N> const& other) + : handle_(other.handle_) {} + +private: + limited_allocator& operator=(const limited_allocator&);// = delete; + +public: + pointer allocate(size_type n) { return handle_->template allocate<T>(n); } + void deallocate(pointer p, size_type n) { handle_->deallocate(p, n); } + size_type max_size() const {return N;} + + BuffT* getHandle() const { return handle_.get(); } +}; + +template <class T, class U, std::size_t N> +inline bool operator==(limited_allocator<T, N> const& LHS, + limited_allocator<U, N> const& RHS) { + return LHS.getHandle() == RHS.getHandle(); +} + +template <class T, class U, std::size_t N> +inline bool operator!=(limited_allocator<T, N> const& LHS, + limited_allocator<U, N> const& RHS) { + return !(LHS == RHS); +} + #endif // TEST_ALLOCATOR_H |