Skip to content

Commit

Permalink
[libc++] Fix stack_allocator
Browse files Browse the repository at this point in the history
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
  • Loading branch information
EricWF committed Oct 8, 2016
1 parent ddb7a59 commit 69a4f66
Show file tree
Hide file tree
Showing 32 changed files with 142 additions and 135 deletions.
Expand Up @@ -14,11 +14,11 @@
#include <queue>
#include <cassert>

#include "../../../stack_allocator.h"
#include "test_allocator.h"

int main()
{
std::priority_queue<int, std::vector<int, stack_allocator<int, 10> > > q((std::less<int>()));
std::priority_queue<int, std::vector<int, limited_allocator<int, 10> > > q((std::less<int>()));
assert(q.size() == 0);
q.push(1);
q.push(2);
Expand Down
Expand Up @@ -14,11 +14,11 @@
#include <queue>
#include <cassert>

#include "../../../stack_allocator.h"
#include "test_allocator.h"

int main()
{
std::priority_queue<int, std::vector<int, stack_allocator<int, 10> > > q;
std::priority_queue<int, std::vector<int, limited_allocator<int, 10> > > q;
assert(q.size() == 0);
q.push(1);
q.push(2);
Expand Down
Expand Up @@ -14,11 +14,11 @@
#include <queue>
#include <cassert>

#include "../../../stack_allocator.h"
#include "test_allocator.h"

int main()
{
std::queue<int, std::vector<int, stack_allocator<int, 10> > > q;
std::queue<int, std::vector<int, limited_allocator<int, 10> > > q;
assert(q.size() == 0);
q.push(1);
q.push(2);
Expand Down
Expand Up @@ -15,11 +15,11 @@
#include <vector>
#include <cassert>

#include "../../../stack_allocator.h"
#include "test_allocator.h"

int main()
{
std::stack<int, std::vector<int, stack_allocator<int, 10> > > q;
std::stack<int, std::vector<int, limited_allocator<int, 10> > > q;
assert(q.size() == 0);
q.push(1);
q.push(2);
Expand Down
Expand Up @@ -14,7 +14,7 @@
#include <deque>
#include <cassert>

#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "../../../NotConstructible.h"
#include "min_allocator.h"

Expand All @@ -33,7 +33,7 @@ test()
int main()
{
test<int, std::allocator<int> >();
test<NotConstructible, stack_allocator<NotConstructible, 1> >();
test<NotConstructible, limited_allocator<NotConstructible, 1> >();
#if TEST_STD_VER >= 11
test<int, min_allocator<int> >();
test<NotConstructible, min_allocator<NotConstructible> >();
Expand Down
Expand Up @@ -14,7 +14,7 @@
#include <deque>
#include <cassert>

#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "test_iterators.h"
#include "min_allocator.h"

Expand Down Expand Up @@ -55,7 +55,7 @@ int main()
test(forward_iterator<const int*>(ab), forward_iterator<const int*>(an));
test(bidirectional_iterator<const int*>(ab), bidirectional_iterator<const int*>(an));
test(random_access_iterator<const int*>(ab), random_access_iterator<const int*>(an));
test<stack_allocator<int, 4096> >(ab, an);
test<limited_allocator<int, 4096> >(ab, an);
#if TEST_STD_VER >= 11
test<min_allocator<int> >(ab, an);
#endif
Expand Down
Expand Up @@ -14,7 +14,7 @@
#include <deque>
#include <cassert>

#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "DefaultOnly.h"
#include "min_allocator.h"

Expand Down Expand Up @@ -98,7 +98,7 @@ int main()
test<DefaultOnly, std::allocator<DefaultOnly> >(4096);
test<DefaultOnly, std::allocator<DefaultOnly> >(4097);

test1<DefaultOnly, stack_allocator<DefaultOnly, 4096> >(4095);
test1<DefaultOnly, limited_allocator<DefaultOnly, 4096> >(4095);

#if TEST_STD_VER >= 11
test<DefaultOnly, min_allocator<DefaultOnly> >(4095);
Expand Down
Expand Up @@ -14,7 +14,7 @@
#include <deque>
#include <cassert>

#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"

template <class T, class Allocator>
Expand Down Expand Up @@ -44,7 +44,7 @@ int main()
test<int, std::allocator<int> >(4095, 78);
test<int, std::allocator<int> >(4096, 1165);
test<int, std::allocator<int> >(4097, 157);
test<int, stack_allocator<int, 4096> >(4095, 90);
test<int, limited_allocator<int, 4096> >(4095, 90);
#if TEST_STD_VER >= 11
test<int, min_allocator<int> >(4095, 90);
#endif
Expand Down
Expand Up @@ -20,7 +20,7 @@
#include "test_macros.h"
#include "test_iterators.h"
#include "MoveOnly.h"
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"

template <class C>
Expand Down Expand Up @@ -270,7 +270,7 @@ int main()
testN<std::deque<int> >(rng[i], rng[j], rng[k]);
testNI<std::deque<int> >(1500, 2000, 1000);
#if TEST_STD_VER >= 11
test_move<std::deque<MoveOnly, stack_allocator<MoveOnly, 2000> > >();
test_move<std::deque<MoveOnly, limited_allocator<MoveOnly, 2000> > >();
#endif
}
#if TEST_STD_VER >= 11
Expand Down
Expand Up @@ -13,7 +13,7 @@

#include <list>
#include <cassert>
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"

int main()
Expand All @@ -29,7 +29,7 @@ int main()
assert(std::distance(l.begin(), l.end()) == 0);
}
{
std::list<int, stack_allocator<int, 4> > l;
std::list<int, limited_allocator<int, 4> > l;
assert(l.size() == 0);
assert(std::distance(l.begin(), l.end()) == 0);
}
Expand Down
Expand Up @@ -15,7 +15,7 @@
#include <list>
#include <cassert>
#include "test_iterators.h"
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"

int main()
Expand Down Expand Up @@ -43,7 +43,7 @@ int main()
}
{
int a[] = {0, 1, 2, 3};
std::list<int, stack_allocator<int, sizeof(a)/sizeof(a[0])> > l(input_iterator<const int*>(a),
std::list<int, limited_allocator<int, sizeof(a)/sizeof(a[0])> > l(input_iterator<const int*>(a),
input_iterator<const int*>(a + sizeof(a)/sizeof(a[0])));
assert(l.size() == sizeof(a)/sizeof(a[0]));
assert(std::distance(l.begin(), l.end()) == sizeof(a)/sizeof(a[0]));
Expand Down
Expand Up @@ -14,7 +14,7 @@
#include <list>
#include <cassert>
#include "DefaultOnly.h"
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"

template <class T, class Allocator>
Expand Down Expand Up @@ -48,7 +48,7 @@ int main()
assert(*i == 0);
}
{
std::list<int, stack_allocator<int, 3> > l(3);
std::list<int, limited_allocator<int, 3> > l(3);
assert(l.size() == 3);
assert(std::distance(l.begin(), l.end()) == 3);
std::list<int>::const_iterator i = l.begin();
Expand Down
Expand Up @@ -14,7 +14,7 @@
#include <list>
#include <cassert>
#include "DefaultOnly.h"
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"

int main()
Expand Down Expand Up @@ -42,7 +42,7 @@ int main()
assert(*i == 2);
}
{
std::list<int, stack_allocator<int, 3> > l(3, 2);
std::list<int, limited_allocator<int, 3> > l(3, 2);
assert(l.size() == 3);
assert(std::distance(l.begin(), l.end()) == 3);
std::list<int>::const_iterator i = l.begin();
Expand Down
Expand Up @@ -13,7 +13,7 @@

#include <vector>
#include <cassert>
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"

Expand All @@ -37,7 +37,7 @@ int main()
assert(is_contiguous_container_asan_correct(v));
}
{
std::vector<int, stack_allocator<int, 250> > v(100);
std::vector<int, limited_allocator<int, 250> > v(100);
assert(v.capacity() == 100);
v.reserve(50);
assert(v.size() == 100);
Expand Down
Expand Up @@ -13,7 +13,7 @@

#include <vector>
#include <cassert>
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "MoveOnly.h"
#include "min_allocator.h"
#include "asan_testing.h"
Expand All @@ -33,7 +33,7 @@ int main()
assert(is_contiguous_container_asan_correct(v));
}
{
std::vector<MoveOnly, stack_allocator<MoveOnly, 300> > v(100);
std::vector<MoveOnly, limited_allocator<MoveOnly, 300> > v(100);
v.resize(50);
assert(v.size() == 50);
assert(v.capacity() == 100);
Expand All @@ -56,7 +56,7 @@ int main()
assert(is_contiguous_container_asan_correct(v));
}
{
std::vector<int, stack_allocator<int, 300> > v(100);
std::vector<int, limited_allocator<int, 300> > v(100);
v.resize(50);
assert(v.size() == 50);
assert(v.capacity() == 100);
Expand Down
Expand Up @@ -13,7 +13,7 @@

#include <vector>
#include <cassert>
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"

Expand All @@ -35,7 +35,7 @@ int main()
assert(v[i] == 1);
}
{
std::vector<int, stack_allocator<int, 300> > v(100);
std::vector<int, limited_allocator<int, 300> > v(100);
v.resize(50, 1);
assert(v.size() == 50);
assert(v.capacity() == 100);
Expand Down
Expand Up @@ -13,7 +13,7 @@

#include <vector>
#include <cassert>
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"

Expand All @@ -29,7 +29,7 @@ int main()
assert(is_contiguous_container_asan_correct(v));
}
{
std::vector<int, stack_allocator<int, 401> > v(100);
std::vector<int, limited_allocator<int, 401> > v(100);
v.push_back(1);
assert(is_contiguous_container_asan_correct(v));
v.shrink_to_fit();
Expand All @@ -39,7 +39,7 @@ int main()
}
#ifndef _LIBCPP_NO_EXCEPTIONS
{
std::vector<int, stack_allocator<int, 400> > v(100);
std::vector<int, limited_allocator<int, 400> > v(100);
v.push_back(1);
assert(is_contiguous_container_asan_correct(v));
v.shrink_to_fit();
Expand Down
Expand Up @@ -18,7 +18,7 @@
#include "test_macros.h"
#include "test_allocator.h"
#include "../../../NotConstructible.h"
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"

Expand Down Expand Up @@ -71,7 +71,7 @@ int main()
(test_allocator<NotConstructible>(5));
}
{
std::vector<int, stack_allocator<int, 10> > v;
std::vector<int, limited_allocator<int, 10> > v;
assert(v.empty());
}
#if TEST_STD_VER >= 11
Expand Down
Expand Up @@ -16,7 +16,7 @@

#include "test_macros.h"
#include "test_iterators.h"
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"

Expand All @@ -42,11 +42,11 @@ int main()
test<std::vector<int> >(random_access_iterator<const int*>(a), random_access_iterator<const int*>(an));
test<std::vector<int> >(a, an);

test<std::vector<int, stack_allocator<int, 63> > >(input_iterator<const int*>(a), input_iterator<const int*>(an));
test<std::vector<int, stack_allocator<int, 18> > >(forward_iterator<const int*>(a), forward_iterator<const int*>(an));
test<std::vector<int, stack_allocator<int, 18> > >(bidirectional_iterator<const int*>(a), bidirectional_iterator<const int*>(an));
test<std::vector<int, stack_allocator<int, 18> > >(random_access_iterator<const int*>(a), random_access_iterator<const int*>(an));
test<std::vector<int, stack_allocator<int, 18> > >(a, an);
test<std::vector<int, limited_allocator<int, 63> > >(input_iterator<const int*>(a), input_iterator<const int*>(an));
test<std::vector<int, limited_allocator<int, 18> > >(forward_iterator<const int*>(a), forward_iterator<const int*>(an));
test<std::vector<int, limited_allocator<int, 18> > >(bidirectional_iterator<const int*>(a), bidirectional_iterator<const int*>(an));
test<std::vector<int, limited_allocator<int, 18> > >(random_access_iterator<const int*>(a), random_access_iterator<const int*>(an));
test<std::vector<int, limited_allocator<int, 18> > >(a, an);
#if TEST_STD_VER >= 11
test<std::vector<int, min_allocator<int>> >(input_iterator<const int*>(a), input_iterator<const int*>(an));
test<std::vector<int, min_allocator<int>> >(forward_iterator<const int*>(a), forward_iterator<const int*>(an));
Expand Down
Expand Up @@ -17,7 +17,7 @@

#include "test_macros.h"
#include "test_iterators.h"
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"

Expand Down
Expand Up @@ -15,7 +15,7 @@
#include <cassert>

#include "test_macros.h"
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"

Expand All @@ -34,7 +34,7 @@ test(typename C::size_type n, const typename C::value_type& x)
int main()
{
test<std::vector<int> >(50, 3);
test<std::vector<int, stack_allocator<int, 50> > >(50, 5);
test<std::vector<int, limited_allocator<int, 50> > >(50, 5);
#if TEST_STD_VER >= 11
test<std::vector<int, min_allocator<int>> >(50, 3);
#endif
Expand Down
Expand Up @@ -17,7 +17,7 @@

#include <vector>
#include <cassert>
#include "../../../stack_allocator.h"
#include "test_allocator.h"
#include "min_allocator.h"
#include "asan_testing.h"

Expand Down Expand Up @@ -88,8 +88,8 @@ int main()
assert(is_contiguous_container_asan_correct(c));
}
{
std::vector<A, stack_allocator<A, 7> > c;
std::vector<A, stack_allocator<A, 7> >::iterator i = c.emplace(c.cbegin(), 2, 3.5);
std::vector<A, limited_allocator<A, 7> > c;
std::vector<A, limited_allocator<A, 7> >::iterator i = c.emplace(c.cbegin(), 2, 3.5);
assert(i == c.begin());
assert(c.size() == 1);
assert(c.front().geti() == 2);
Expand Down

0 comments on commit 69a4f66

Please sign in to comment.