Просмотр исходного кода

[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

git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@283631 91177308-0d34-0410-b5e6-96231b3b80d8
Eric Fiselier 9 лет назад
Родитель
Сommit
124ed406e5
32 измененных файлов с 142 добавлено и 135 удалено
  1. 2 2
      test/std/containers/container.adaptors/priority.queue/priqueue.cons/ctor_comp.pass.cpp
  2. 2 2
      test/std/containers/container.adaptors/priority.queue/priqueue.cons/ctor_default.pass.cpp
  3. 2 2
      test/std/containers/container.adaptors/queue/queue.cons/ctor_default.pass.cpp
  4. 2 2
      test/std/containers/container.adaptors/stack/stack.cons/ctor_default.pass.cpp
  5. 2 2
      test/std/containers/sequences/deque/deque.cons/default.pass.cpp
  6. 2 2
      test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp
  7. 2 2
      test/std/containers/sequences/deque/deque.cons/size.pass.cpp
  8. 2 2
      test/std/containers/sequences/deque/deque.cons/size_value.pass.cpp
  9. 2 2
      test/std/containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp
  10. 2 2
      test/std/containers/sequences/list/list.cons/default_stack_alloc.pass.cpp
  11. 2 2
      test/std/containers/sequences/list/list.cons/input_iterator.pass.cpp
  12. 2 2
      test/std/containers/sequences/list/list.cons/size_type.pass.cpp
  13. 2 2
      test/std/containers/sequences/list/list.cons/size_value_alloc.pass.cpp
  14. 2 2
      test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp
  15. 3 3
      test/std/containers/sequences/vector/vector.capacity/resize_size.pass.cpp
  16. 2 2
      test/std/containers/sequences/vector/vector.capacity/resize_size_value.pass.cpp
  17. 3 3
      test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp
  18. 2 2
      test/std/containers/sequences/vector/vector.cons/construct_default.pass.cpp
  19. 6 6
      test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp
  20. 1 1
      test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp
  21. 2 2
      test/std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp
  22. 3 3
      test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp
  23. 2 2
      test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp
  24. 3 3
      test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.pass.cpp
  25. 3 3
      test/std/containers/sequences/vector/vector.modifiers/insert_iter_rvalue.pass.cpp
  26. 3 3
      test/std/containers/sequences/vector/vector.modifiers/insert_iter_size_value.pass.cpp
  27. 3 3
      test/std/containers/sequences/vector/vector.modifiers/insert_iter_value.pass.cpp
  28. 1 1
      test/std/containers/sequences/vector/vector.modifiers/pop_back.pass.cpp
  29. 2 2
      test/std/containers/sequences/vector/vector.modifiers/push_back.pass.cpp
  30. 2 2
      test/std/containers/sequences/vector/vector.modifiers/push_back_rvalue.pass.cpp
  31. 0 66
      test/std/containers/stack_allocator.h
  32. 73 0
      test/support/test_allocator.h

+ 2 - 2
test/std/containers/container.adaptors/priority.queue/priqueue.cons/ctor_comp.pass.cpp

@@ -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);

+ 2 - 2
test/std/containers/container.adaptors/priority.queue/priqueue.cons/ctor_default.pass.cpp

@@ -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);

+ 2 - 2
test/std/containers/container.adaptors/queue/queue.cons/ctor_default.pass.cpp

@@ -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);

+ 2 - 2
test/std/containers/container.adaptors/stack/stack.cons/ctor_default.pass.cpp

@@ -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);

+ 2 - 2
test/std/containers/sequences/deque/deque.cons/default.pass.cpp

@@ -14,7 +14,7 @@
 #include <deque>
 #include <cassert>
 
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "../../../NotConstructible.h"
 #include "min_allocator.h"
 
@@ -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> >();

+ 2 - 2
test/std/containers/sequences/deque/deque.cons/iter_iter.pass.cpp

@@ -14,7 +14,7 @@
 #include <deque>
 #include <cassert>
 
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "test_iterators.h"
 #include "min_allocator.h"
 
@@ -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

+ 2 - 2
test/std/containers/sequences/deque/deque.cons/size.pass.cpp

@@ -14,7 +14,7 @@
 #include <deque>
 #include <cassert>
 
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "DefaultOnly.h"
 #include "min_allocator.h"
 
@@ -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);

+ 2 - 2
test/std/containers/sequences/deque/deque.cons/size_value.pass.cpp

@@ -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>
@@ -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

+ 2 - 2
test/std/containers/sequences/deque/deque.modifiers/insert_iter_iter.pass.cpp

@@ -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>
@@ -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

+ 2 - 2
test/std/containers/sequences/list/list.cons/default_stack_alloc.pass.cpp

@@ -13,7 +13,7 @@
 
 #include <list>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 
 int main()
@@ -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);
     }

+ 2 - 2
test/std/containers/sequences/list/list.cons/input_iterator.pass.cpp

@@ -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()
@@ -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]));

+ 2 - 2
test/std/containers/sequences/list/list.cons/size_type.pass.cpp

@@ -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>
@@ -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();

+ 2 - 2
test/std/containers/sequences/list/list.cons/size_value_alloc.pass.cpp

@@ -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()
@@ -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();

+ 2 - 2
test/std/containers/sequences/vector/vector.capacity/reserve.pass.cpp

@@ -13,7 +13,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
 
@@ -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);

+ 3 - 3
test/std/containers/sequences/vector/vector.capacity/resize_size.pass.cpp

@@ -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"
@@ -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);
@@ -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);

+ 2 - 2
test/std/containers/sequences/vector/vector.capacity/resize_size_value.pass.cpp

@@ -13,7 +13,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
 
@@ -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);

+ 3 - 3
test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp

@@ -13,7 +13,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
 
@@ -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();
@@ -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();

+ 2 - 2
test/std/containers/sequences/vector/vector.cons/construct_default.pass.cpp

@@ -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"
 
@@ -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

+ 6 - 6
test/std/containers/sequences/vector/vector.cons/construct_iter_iter.pass.cpp

@@ -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"
 
@@ -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));

+ 1 - 1
test/std/containers/sequences/vector/vector.cons/construct_iter_iter_alloc.pass.cpp

@@ -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"
 

+ 2 - 2
test/std/containers/sequences/vector/vector.cons/construct_size_value.pass.cpp

@@ -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"
 
@@ -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

+ 3 - 3
test/std/containers/sequences/vector/vector.modifiers/emplace.pass.cpp

@@ -17,7 +17,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
 
@@ -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);

+ 2 - 2
test/std/containers/sequences/vector/vector.modifiers/emplace_back.pass.cpp

@@ -15,7 +15,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "test_allocator.h"
 #include "asan_testing.h"
@@ -72,7 +72,7 @@ int main()
         assert(is_contiguous_container_asan_correct(c));
     }
     {
-        std::vector<A, stack_allocator<A, 4> > c;
+        std::vector<A, limited_allocator<A, 4> > c;
         A& r1 = c.emplace_back(2, 3.5);
         assert(c.size() == 1);
         assert(&r1 == &c.back());

+ 3 - 3
test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.pass.cpp

@@ -18,7 +18,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "test_iterators.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
@@ -96,7 +96,7 @@ int main()
             assert(v[j] == 0);
     }
     {
-        std::vector<int, stack_allocator<int, 308> > v(100);
+        std::vector<int, limited_allocator<int, 308> > v(100);
         int a[] = {1, 2, 3, 4, 5};
         const int N = sizeof(a)/sizeof(a[0]);
         std::vector<int>::iterator i = v.insert(v.cbegin() + 10, input_iterator<const int*>(a),
@@ -113,7 +113,7 @@ int main()
             assert(v[j] == 0);
     }
     {
-        std::vector<int, stack_allocator<int, 300> > v(100);
+        std::vector<int, limited_allocator<int, 300> > v(100);
         int a[] = {1, 2, 3, 4, 5};
         const int N = sizeof(a)/sizeof(a[0]);
         std::vector<int>::iterator i = v.insert(v.cbegin() + 10, forward_iterator<const int*>(a),

+ 3 - 3
test/std/containers/sequences/vector/vector.modifiers/insert_iter_rvalue.pass.cpp

@@ -17,7 +17,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "MoveOnly.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
@@ -39,8 +39,8 @@ int main()
             assert(v[j] == MoveOnly());
     }
     {
-        std::vector<MoveOnly, stack_allocator<MoveOnly, 300> > v(100);
-        std::vector<MoveOnly, stack_allocator<MoveOnly, 300> >::iterator i = v.insert(v.cbegin() + 10, MoveOnly(3));
+        std::vector<MoveOnly, limited_allocator<MoveOnly, 300> > v(100);
+        std::vector<MoveOnly, limited_allocator<MoveOnly, 300> >::iterator i = v.insert(v.cbegin() + 10, MoveOnly(3));
         assert(v.size() == 101);
         assert(is_contiguous_container_asan_correct(v));
         assert(i == v.begin() + 10);

+ 3 - 3
test/std/containers/sequences/vector/vector.modifiers/insert_iter_size_value.pass.cpp

@@ -17,7 +17,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
 
@@ -70,8 +70,8 @@ int main()
             assert(v[j] == 0);
     }
     {
-        std::vector<int, stack_allocator<int, 300> > v(100);
-        std::vector<int, stack_allocator<int, 300> >::iterator i = v.insert(v.cbegin() + 10, 5, 1);
+        std::vector<int, limited_allocator<int, 300> > v(100);
+        std::vector<int, limited_allocator<int, 300> >::iterator i = v.insert(v.cbegin() + 10, 5, 1);
         assert(v.size() == 105);
         assert(is_contiguous_container_asan_correct(v));
         assert(i == v.begin() + 10);

+ 3 - 3
test/std/containers/sequences/vector/vector.modifiers/insert_iter_value.pass.cpp

@@ -17,7 +17,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
 
@@ -68,8 +68,8 @@ int main()
             assert(v[j] == 0);
     }
     {
-        std::vector<int, stack_allocator<int, 300> > v(100);
-        std::vector<int, stack_allocator<int, 300> >::iterator i = v.insert(v.cbegin() + 10, 1);
+        std::vector<int, limited_allocator<int, 300> > v(100);
+        std::vector<int, limited_allocator<int, 300> >::iterator i = v.insert(v.cbegin() + 10, 1);
         assert(v.size() == 101);
         assert(is_contiguous_container_asan_correct(v));
         assert(i == v.begin() + 10);

+ 1 - 1
test/std/containers/sequences/vector/vector.modifiers/pop_back.pass.cpp

@@ -17,7 +17,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 
 #if _LIBCPP_DEBUG >= 1

+ 2 - 2
test/std/containers/sequences/vector/vector.modifiers/push_back.pass.cpp

@@ -13,7 +13,7 @@
 
 #include <vector>
 #include <cassert>
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
 
@@ -48,7 +48,7 @@ int main()
             assert(c[j] == j);
     }
     {
-        std::vector<int, stack_allocator<int, 15> > c;
+        std::vector<int, limited_allocator<int, 15> > c;
         c.push_back(0);
         assert(c.size() == 1);
         assert(is_contiguous_container_asan_correct(c));

+ 2 - 2
test/std/containers/sequences/vector/vector.modifiers/push_back_rvalue.pass.cpp

@@ -14,7 +14,7 @@
 #include <vector>
 #include <cassert>
 #include "MoveOnly.h"
-#include "../../../stack_allocator.h"
+#include "test_allocator.h"
 #include "min_allocator.h"
 #include "asan_testing.h"
 
@@ -50,7 +50,7 @@ int main()
             assert(c[j] == MoveOnly(j));
     }
     {
-        std::vector<MoveOnly, stack_allocator<MoveOnly, 15> > c;
+        std::vector<MoveOnly, limited_allocator<MoveOnly, 15> > c;
         c.push_back(MoveOnly(0));
         assert(c.size() == 1);
         assert(is_contiguous_container_asan_correct(c));

+ 0 - 66
test/std/containers/stack_allocator.h

@@ -1,66 +0,0 @@
-//===----------------------------------------------------------------------===//
-//
-//                     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 STACK_ALLOCATOR_H
-#define STACK_ALLOCATOR_H
-
-#include <cstddef>
-#include <new>
-
-template <class T, std::size_t N>
-class stack_allocator
-{
-    char buf_[sizeof(T)*N];
-    char* ptr_;
-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 stack_allocator<U, N> other;};
-
-    stack_allocator() : ptr_(buf_) {}
-
-private:
-    stack_allocator(const stack_allocator&);// = delete;
-    stack_allocator& operator=(const stack_allocator&);// = delete;
-
-public:
-    pointer allocate(size_type n, const void* = 0)
-    {
-        if (n > N - (ptr_ - buf_) / sizeof(value_type)) {
-#ifndef _LIBCPP_NO_EXCEPTIONS
-            throw std::bad_alloc();
-#else
-            std::terminate();
-#endif
-        }
-        pointer r = (T*)ptr_;
-        ptr_ += n * sizeof(T);
-        return r;
-    }
-    void deallocate(pointer p, size_type n)
-    {
-        if ((char*)(p + n) == ptr_)
-            ptr_ = (char*)p;
-    }
-
-    size_type max_size() const {return N;}
-};
-
-template <class T, std::size_t N>
-inline
-void
-swap(stack_allocator<T, N>& x, stack_allocator<T, N>& y) {}
-
-#endif  // STACK_ALLOCATOR_H

+ 73 - 0
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