Quuxplusone updated this revision to Diff 175011.
Quuxplusone added a comment.
Change `1 <<` to `size_t(1) <<` in one last place. @EricWF ping.
Repository:
rCXX libc++
https://reviews.llvm.org/D47358
Files:
include/experimental/memory_resource
src/experimental/memory_resource.cpp
test/libcxx/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsynchronized_buffer.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/ctor_does_not_allocate.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/sync_with_default_resource.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/unsync_with_default_resource.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/equality.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate_overaligned_request.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate_reuse_blocks.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_deallocate_matches_allocate.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate_overaligned_request.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate_reuse_blocks.pass.cpp
test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_deallocate_matches_allocate.pass.cpp
test/std/experimental/memory/memory.resource.pool/pool_options.pass.cpp
test/support/count_new.hpp
Index: test/support/count_new.hpp
===================================================================
--- test/support/count_new.hpp
+++ test/support/count_new.hpp
@@ -211,6 +211,11 @@
return disable_checking || n != delete_called;
}
+ bool checkDeleteCalledGreaterThan(int n) const
+ {
+ return disable_checking || delete_called > n;
+ }
+
bool checkAlignedNewCalledEq(int n) const
{
return disable_checking || n == aligned_new_called;
Index: test/std/experimental/memory/memory.resource.pool/pool_options.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/pool_options.pass.cpp
@@ -0,0 +1,26 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03, c++11, c++14
+// UNSUPPORTED: apple-clang-7
+
+// <experimental/memory_resource>
+
+// struct pool_options
+
+#include <cassert>
+#include <experimental/memory_resource>
+
+int main()
+{
+ const std::experimental::pmr::pool_options p;
+ assert(p.max_blocks_per_chunk == 0);
+ assert(p.largest_required_pool_block == 0);
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_deallocate_matches_allocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_deallocate_matches_allocate.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class unsynchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+#include <vector>
+
+struct allocation_record {
+ size_t bytes;
+ size_t align;
+ explicit allocation_record(size_t b, size_t a) : bytes(b), align(a) {}
+ bool operator==(const allocation_record& rhs) const {
+ return (bytes == rhs.bytes) && (align == rhs.align);
+ }
+ bool operator<(const allocation_record& rhs) const {
+ if (bytes != rhs.bytes) return (bytes < rhs.bytes);
+ return (align < rhs.align);
+ }
+};
+
+class test_resource : public std::experimental::pmr::memory_resource {
+ void *do_allocate(size_t bytes, size_t align) override {
+ void *result = std::experimental::pmr::new_delete_resource()->allocate(bytes, align);
+ successful_allocations.emplace_back(bytes, align);
+ return result;
+ }
+ void do_deallocate(void *p, size_t bytes, size_t align) override {
+ deallocations.emplace_back(bytes, align);
+ return std::experimental::pmr::new_delete_resource()->deallocate(p, bytes, align);
+ }
+ bool do_is_equal(const std::experimental::pmr::memory_resource&) const noexcept override {
+ return false;
+ }
+public:
+ std::vector<allocation_record> successful_allocations;
+ std::vector<allocation_record> deallocations;
+};
+
+template<class F>
+void test_allocation_pattern(F do_pattern)
+{
+ test_resource tr;
+ std::experimental::pmr::pool_options opts { 0, 256 };
+ std::experimental::pmr::unsynchronized_pool_resource uspr(opts, &tr);
+
+ try {
+ do_pattern(uspr);
+ } catch (const std::bad_alloc&) {}
+ uspr.release();
+
+ assert(tr.successful_allocations.size() == tr.deallocations.size());
+ std::sort(tr.successful_allocations.begin(), tr.successful_allocations.end());
+ std::sort(tr.deallocations.begin(), tr.deallocations.end());
+ assert(tr.successful_allocations == tr.deallocations);
+}
+
+template<size_t Bytes, size_t Align>
+auto foo() {
+ return [=](auto& mr) {
+ void *p = mr.allocate(Bytes, Align);
+ mr.deallocate(p, Bytes, Align);
+ };
+}
+
+int main()
+{
+ test_allocation_pattern(foo<2, 1>());
+ test_allocation_pattern(foo<2, 8>());
+ test_allocation_pattern(foo<2, 64>());
+ test_allocation_pattern(foo<128, 1>());
+ test_allocation_pattern(foo<128, 8>());
+ test_allocation_pattern(foo<128, 64>());
+ test_allocation_pattern(foo<1024, 1>());
+ test_allocation_pattern(foo<1024, 8>());
+ test_allocation_pattern(foo<1024, 64>());
+
+ test_allocation_pattern([](auto& mr) {
+ void *p1 = mr.allocate(2, 1);
+ void *p2 = mr.allocate(2, 8);
+ void *p3 = mr.allocate(2, 64);
+ void *p4 = mr.allocate(128, 1);
+ void *p5 = mr.allocate(128, 8);
+ void *p6 = mr.allocate(128, 64);
+ void *p7 = mr.allocate(1024, 1);
+ void *p8 = mr.allocate(1024, 8);
+ void *p9 = mr.allocate(1024, 64);
+ mr.deallocate(p1, 2, 1);
+ mr.deallocate(p2, 2, 8);
+ mr.deallocate(p3, 2, 64);
+ mr.deallocate(p4, 128, 1);
+ mr.deallocate(p5, 128, 8);
+ mr.deallocate(p6, 128, 64);
+ mr.deallocate(p7, 1024, 1);
+ mr.deallocate(p8, 1024, 8);
+ mr.deallocate(p9, 1024, 64);
+ });
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate_reuse_blocks.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate_reuse_blocks.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class unsynchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+static bool is_aligned_to(void *p, size_t alignment)
+{
+ void *p2 = p;
+ size_t space = 1;
+ void *result = std::align(alignment, 1, p2, space);
+ return (result == p);
+}
+
+int main()
+{
+ globalMemCounter.reset();
+ std::experimental::pmr::pool_options opts { 1, 256 };
+ std::experimental::pmr::unsynchronized_pool_resource unsync1(opts, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = unsync1;
+
+ void *ret = r1.allocate(8);
+ assert(ret != nullptr);
+ assert(is_aligned_to(ret, 8));
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+ int new_called = globalMemCounter.new_called;
+
+ // After deallocation, the pool for 8-byte blocks should have at least one vacancy.
+ r1.deallocate(ret, 8);
+ assert(globalMemCounter.new_called == new_called);
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ // This should return an existing block from the pool: no new allocations.
+ ret = r1.allocate(8);
+ assert(ret != nullptr);
+ assert(is_aligned_to(ret, 8));
+ assert(globalMemCounter.new_called == new_called);
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate_overaligned_request.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate_overaligned_request.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class unsynchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+static bool is_aligned_to(void *p, size_t alignment)
+{
+ void *p2 = p;
+ size_t space = 1;
+ void *result = std::align(alignment, 1, p2, space);
+ return (result == p);
+}
+
+int main()
+{
+ globalMemCounter.reset();
+ std::experimental::pmr::pool_options opts { 1, 1024 };
+ std::experimental::pmr::unsynchronized_pool_resource unsync1(opts, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = unsync1;
+
+ constexpr size_t big_alignment = 8 * alignof(std::max_align_t);
+ static_assert(big_alignment > 4);
+
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ void *ret = r1.allocate(2048, big_alignment);
+ assert(ret != nullptr);
+ assert(is_aligned_to(ret, big_alignment));
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+
+ ret = r1.allocate(16, 4);
+ assert(ret != nullptr);
+ assert(is_aligned_to(ret, 4));
+ assert(globalMemCounter.checkNewCalledGreaterThan(1));
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsync_allocate.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class unsynchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ {
+ globalMemCounter.reset();
+
+ std::experimental::pmr::unsynchronized_pool_resource unsync1(std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = unsync1;
+
+ void *ret = r1.allocate(50);
+ assert(ret);
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ r1.deallocate(ret, 50);
+ unsync1.release();
+ assert(globalMemCounter.checkDeleteCalledGreaterThan(0));
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+
+ globalMemCounter.reset();
+
+ ret = r1.allocate(500);
+ assert(ret);
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ // Check that the destructor calls release()
+ }
+ assert(globalMemCounter.checkDeleteCalledGreaterThan(0));
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_deallocate_matches_allocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_deallocate_matches_allocate.pass.cpp
@@ -0,0 +1,110 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class synchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+#include <vector>
+
+struct allocation_record {
+ size_t bytes;
+ size_t align;
+ explicit allocation_record(size_t b, size_t a) : bytes(b), align(a) {}
+ bool operator==(const allocation_record& rhs) const {
+ return (bytes == rhs.bytes) && (align == rhs.align);
+ }
+ bool operator<(const allocation_record& rhs) const {
+ if (bytes != rhs.bytes) return (bytes < rhs.bytes);
+ return (align < rhs.align);
+ }
+};
+
+class test_resource : public std::experimental::pmr::memory_resource {
+ void *do_allocate(size_t bytes, size_t align) override {
+ void *result = std::experimental::pmr::new_delete_resource()->allocate(bytes, align);
+ successful_allocations.emplace_back(bytes, align);
+ return result;
+ }
+ void do_deallocate(void *p, size_t bytes, size_t align) override {
+ deallocations.emplace_back(bytes, align);
+ return std::experimental::pmr::new_delete_resource()->deallocate(p, bytes, align);
+ }
+ bool do_is_equal(const std::experimental::pmr::memory_resource&) const noexcept override {
+ return false;
+ }
+public:
+ std::vector<allocation_record> successful_allocations;
+ std::vector<allocation_record> deallocations;
+};
+
+template<class F>
+void test_allocation_pattern(F do_pattern)
+{
+ test_resource tr;
+ std::experimental::pmr::pool_options opts { 0, 256 };
+ std::experimental::pmr::synchronized_pool_resource spr(opts, &tr);
+
+ try {
+ do_pattern(spr);
+ } catch (const std::bad_alloc&) {}
+ spr.release();
+
+ assert(tr.successful_allocations.size() == tr.deallocations.size());
+ std::sort(tr.successful_allocations.begin(), tr.successful_allocations.end());
+ std::sort(tr.deallocations.begin(), tr.deallocations.end());
+ assert(tr.successful_allocations == tr.deallocations);
+}
+
+template<size_t Bytes, size_t Align>
+auto foo() {
+ return [=](auto& mr) {
+ void *p = mr.allocate(Bytes, Align);
+ mr.deallocate(p, Bytes, Align);
+ };
+}
+
+int main()
+{
+ test_allocation_pattern(foo<2, 1>());
+ test_allocation_pattern(foo<2, 8>());
+ test_allocation_pattern(foo<2, 64>());
+ test_allocation_pattern(foo<128, 1>());
+ test_allocation_pattern(foo<128, 8>());
+ test_allocation_pattern(foo<128, 64>());
+ test_allocation_pattern(foo<1024, 1>());
+ test_allocation_pattern(foo<1024, 8>());
+ test_allocation_pattern(foo<1024, 64>());
+
+ test_allocation_pattern([](auto& mr) {
+ void *p1 = mr.allocate(2, 1);
+ void *p2 = mr.allocate(2, 8);
+ void *p3 = mr.allocate(2, 64);
+ void *p4 = mr.allocate(128, 1);
+ void *p5 = mr.allocate(128, 8);
+ void *p6 = mr.allocate(128, 64);
+ void *p7 = mr.allocate(1024, 1);
+ void *p8 = mr.allocate(1024, 8);
+ void *p9 = mr.allocate(1024, 64);
+ mr.deallocate(p1, 2, 1);
+ mr.deallocate(p2, 2, 8);
+ mr.deallocate(p3, 2, 64);
+ mr.deallocate(p4, 128, 1);
+ mr.deallocate(p5, 128, 8);
+ mr.deallocate(p6, 128, 64);
+ mr.deallocate(p7, 1024, 1);
+ mr.deallocate(p8, 1024, 8);
+ mr.deallocate(p9, 1024, 64);
+ });
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate_reuse_blocks.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate_reuse_blocks.pass.cpp
@@ -0,0 +1,54 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class synchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+static bool is_aligned_to(void *p, size_t alignment)
+{
+ void *p2 = p;
+ size_t space = 1;
+ void *result = std::align(alignment, 1, p2, space);
+ return (result == p);
+}
+
+int main()
+{
+ globalMemCounter.reset();
+ std::experimental::pmr::pool_options opts { 1, 256 };
+ std::experimental::pmr::synchronized_pool_resource sync1(opts, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = sync1;
+
+ void *ret = r1.allocate(8);
+ assert(ret != nullptr);
+ assert(is_aligned_to(ret, 8));
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+ int new_called = globalMemCounter.new_called;
+
+ // After deallocation, the pool for 8-byte blocks should have at least one vacancy.
+ r1.deallocate(ret, 8);
+ assert(globalMemCounter.new_called == new_called);
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ // This should return an existing block from the pool: no new allocations.
+ ret = r1.allocate(8);
+ assert(ret != nullptr);
+ assert(is_aligned_to(ret, 8));
+ assert(globalMemCounter.new_called == new_called);
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate_overaligned_request.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate_overaligned_request.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class synchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+static bool is_aligned_to(void *p, size_t alignment)
+{
+ void *p2 = p;
+ size_t space = 1;
+ void *result = std::align(alignment, 1, p2, space);
+ return (result == p);
+}
+
+int main()
+{
+ globalMemCounter.reset();
+ std::experimental::pmr::pool_options opts { 1, 1024 };
+ std::experimental::pmr::synchronized_pool_resource sync1(opts, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = sync1;
+
+ constexpr size_t big_alignment = 8 * alignof(std::max_align_t);
+ static_assert(big_alignment > 4);
+
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ void *ret = r1.allocate(2048, big_alignment);
+ assert(ret != nullptr);
+ assert(is_aligned_to(ret, big_alignment));
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+
+ ret = r1.allocate(16, 4);
+ assert(ret != nullptr);
+ assert(is_aligned_to(ret, 4));
+ assert(globalMemCounter.checkNewCalledGreaterThan(1));
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/sync_allocate.pass.cpp
@@ -0,0 +1,51 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class synchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ {
+ globalMemCounter.reset();
+
+ std::experimental::pmr::synchronized_pool_resource sync1(std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = sync1;
+
+ void *ret = r1.allocate(50);
+ assert(ret);
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ r1.deallocate(ret, 50);
+ sync1.release();
+ assert(globalMemCounter.checkDeleteCalledGreaterThan(0));
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+
+ globalMemCounter.reset();
+
+ ret = r1.allocate(500);
+ assert(ret);
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ // Check that the destructor calls release()
+ }
+ assert(globalMemCounter.checkDeleteCalledGreaterThan(0));
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/equality.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.mem/equality.pass.cpp
@@ -0,0 +1,71 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class synchronized_pool_resource
+// class unsynchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <new>
+#include <type_traits>
+#include <cassert>
+
+#include "count_new.hpp"
+
+class assert_on_compare : public std::experimental::pmr::memory_resource
+{
+ void * do_allocate(size_t, size_t) override
+ { assert(false); }
+
+ void do_deallocate(void *, size_t, size_t) override
+ { assert(false); }
+
+ bool do_is_equal(std::experimental::pmr::memory_resource const &) const noexcept override
+ { assert(false); }
+};
+
+template<class PoolResource>
+void test()
+{
+ // Same type
+ {
+ PoolResource pr1;
+ PoolResource pr2;
+ assert(pr1 == pr1);
+ assert(pr1 != pr2);
+
+ std::experimental::pmr::memory_resource & mr1 = pr1;
+ std::experimental::pmr::memory_resource & mr2 = pr2;
+ assert(mr1 == mr1);
+ assert(mr1 != mr2);
+ assert(mr1 == pr1);
+ assert(pr1 == mr1);
+ assert(mr1 != pr2);
+ assert(pr2 != mr1);
+ }
+ // Different types
+ {
+ PoolResource pr1;
+ std::experimental::pmr::memory_resource & mr1 = pr1;
+ assert_on_compare c;
+ std::experimental::pmr::memory_resource & mr2 = c;
+ assert(mr1 != mr2);
+ assert(!(mr1 == mr2));
+ }
+}
+
+int main()
+{
+ test<std::experimental::pmr::synchronized_pool_resource>();
+ test<std::experimental::pmr::unsynchronized_pool_resource>();
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/unsync_with_default_resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/unsync_with_default_resource.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class unsynchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+int main()
+{
+ std::experimental::pmr::memory_resource *expected = std::experimental::pmr::null_memory_resource();
+ std::experimental::pmr::set_default_resource(expected);
+ {
+ std::experimental::pmr::pool_options opts { 0, 0 };
+ std::experimental::pmr::unsynchronized_pool_resource r1;
+ std::experimental::pmr::unsynchronized_pool_resource r2(opts);
+ assert(r1.upstream_resource() == expected);
+ assert(r2.upstream_resource() == expected);
+ }
+
+ expected = std::experimental::pmr::new_delete_resource();
+ std::experimental::pmr::set_default_resource(expected);
+ {
+ std::experimental::pmr::pool_options opts { 1024, 2048 };
+ std::experimental::pmr::unsynchronized_pool_resource r1;
+ std::experimental::pmr::unsynchronized_pool_resource r2(opts);
+ assert(r1.upstream_resource() == expected);
+ assert(r2.upstream_resource() == expected);
+ }
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/sync_with_default_resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/sync_with_default_resource.pass.cpp
@@ -0,0 +1,41 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class synchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+int main()
+{
+ std::experimental::pmr::memory_resource *expected = std::experimental::pmr::null_memory_resource();
+ std::experimental::pmr::set_default_resource(expected);
+ {
+ std::experimental::pmr::pool_options opts { 0, 0 };
+ std::experimental::pmr::synchronized_pool_resource r1;
+ std::experimental::pmr::synchronized_pool_resource r2(opts);
+ assert(r1.upstream_resource() == expected);
+ assert(r2.upstream_resource() == expected);
+ }
+
+ expected = std::experimental::pmr::new_delete_resource();
+ std::experimental::pmr::set_default_resource(expected);
+ {
+ std::experimental::pmr::pool_options opts { 1024, 2048 };
+ std::experimental::pmr::synchronized_pool_resource r1;
+ std::experimental::pmr::synchronized_pool_resource r2(opts);
+ assert(r1.upstream_resource() == expected);
+ assert(r2.upstream_resource() == expected);
+ }
+}
Index: test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/ctor_does_not_allocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.pool/memory.resource.pool.ctor/ctor_does_not_allocate.pass.cpp
@@ -0,0 +1,47 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class synchronized_pool_resource
+// class unsynchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+template<class PoolResource>
+void test()
+{
+ // Constructing a pool resource should not cause allocations
+ // by itself; the resource should wait to allocate until an
+ // allocation is requested.
+
+ globalMemCounter.reset();
+ std::experimental::pmr::set_default_resource(std::experimental::pmr::new_delete_resource());
+
+ PoolResource r1;
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ PoolResource r2(std::experimental::pmr::pool_options{ 1024, 2048 });
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ PoolResource r3(std::experimental::pmr::pool_options{ 1024, 2048 }, std::experimental::pmr::new_delete_resource());
+ assert(globalMemCounter.checkNewCalledEq(0));
+}
+
+int main()
+{
+ test<std::experimental::pmr::unsynchronized_pool_resource>();
+ test<std::experimental::pmr::synchronized_pool_resource>();
+}
Index: test/libcxx/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsynchronized_buffer.pass.cpp
===================================================================
--- /dev/null
+++ test/libcxx/experimental/memory/memory.resource.pool/memory.resource.pool.mem/unsynchronized_buffer.pass.cpp
@@ -0,0 +1,208 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// struct pool_options
+// class unsynchronized_pool_resource
+// class synchronized_pool_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+static void assert_options(const std::experimental::pmr::pool_options& actual, const std::experimental::pmr::pool_options& expected)
+{
+ assert(actual.max_blocks_per_chunk == expected.max_blocks_per_chunk);
+ assert(actual.largest_required_pool_block == expected.largest_required_pool_block);
+}
+
+void test_pool_options(std::experimental::pmr::pool_options initial, std::experimental::pmr::pool_options expected)
+{
+ std::experimental::pmr::unsynchronized_pool_resource mr(initial, std::experimental::pmr::null_memory_resource());
+ assert_options(mr.options(), expected);
+
+ std::experimental::pmr::synchronized_pool_resource mr2(initial, std::experimental::pmr::null_memory_resource());
+ assert_options(mr2.options(), expected);
+}
+
+int main()
+{
+ test_pool_options({0, 0}, {1048576, 1048576});
+ test_pool_options({0, 1}, {1048576, 8});
+ test_pool_options({0, 2}, {1048576, 8});
+ test_pool_options({0, 4}, {1048576, 8});
+ test_pool_options({0, 8}, {1048576, 8});
+ test_pool_options({0, 16}, {1048576, 16});
+ test_pool_options({0, 32}, {1048576, 32});
+ test_pool_options({0, 1024}, {1048576, 1024});
+ test_pool_options({0, 1048576}, {1048576, 1048576});
+ test_pool_options({0, 2097152}, {1048576, 2097152});
+ test_pool_options({0, 1073741824}, {1048576, 1073741824});
+ test_pool_options({0, 2147483648}, {1048576, 1073741824});
+ test_pool_options({0, 8589934592}, {1048576, 1073741824});
+ test_pool_options({1, 0}, {16, 1048576});
+ test_pool_options({1, 1}, {16, 8});
+ test_pool_options({1, 2}, {16, 8});
+ test_pool_options({1, 4}, {16, 8});
+ test_pool_options({1, 8}, {16, 8});
+ test_pool_options({1, 16}, {16, 16});
+ test_pool_options({1, 32}, {16, 32});
+ test_pool_options({1, 1024}, {16, 1024});
+ test_pool_options({1, 1048576}, {16, 1048576});
+ test_pool_options({1, 2097152}, {16, 2097152});
+ test_pool_options({1, 1073741824}, {16, 1073741824});
+ test_pool_options({1, 2147483648}, {16, 1073741824});
+ test_pool_options({1, 8589934592}, {16, 1073741824});
+ test_pool_options({2, 0}, {16, 1048576});
+ test_pool_options({2, 1}, {16, 8});
+ test_pool_options({2, 2}, {16, 8});
+ test_pool_options({2, 4}, {16, 8});
+ test_pool_options({2, 8}, {16, 8});
+ test_pool_options({2, 16}, {16, 16});
+ test_pool_options({2, 32}, {16, 32});
+ test_pool_options({2, 1024}, {16, 1024});
+ test_pool_options({2, 1048576}, {16, 1048576});
+ test_pool_options({2, 2097152}, {16, 2097152});
+ test_pool_options({2, 1073741824}, {16, 1073741824});
+ test_pool_options({2, 2147483648}, {16, 1073741824});
+ test_pool_options({2, 8589934592}, {16, 1073741824});
+ test_pool_options({4, 0}, {16, 1048576});
+ test_pool_options({4, 1}, {16, 8});
+ test_pool_options({4, 2}, {16, 8});
+ test_pool_options({4, 4}, {16, 8});
+ test_pool_options({4, 8}, {16, 8});
+ test_pool_options({4, 16}, {16, 16});
+ test_pool_options({4, 32}, {16, 32});
+ test_pool_options({4, 1024}, {16, 1024});
+ test_pool_options({4, 1048576}, {16, 1048576});
+ test_pool_options({4, 2097152}, {16, 2097152});
+ test_pool_options({4, 1073741824}, {16, 1073741824});
+ test_pool_options({4, 2147483648}, {16, 1073741824});
+ test_pool_options({4, 8589934592}, {16, 1073741824});
+ test_pool_options({8, 0}, {16, 1048576});
+ test_pool_options({8, 1}, {16, 8});
+ test_pool_options({8, 2}, {16, 8});
+ test_pool_options({8, 4}, {16, 8});
+ test_pool_options({8, 8}, {16, 8});
+ test_pool_options({8, 16}, {16, 16});
+ test_pool_options({8, 32}, {16, 32});
+ test_pool_options({8, 1024}, {16, 1024});
+ test_pool_options({8, 1048576}, {16, 1048576});
+ test_pool_options({8, 2097152}, {16, 2097152});
+ test_pool_options({8, 1073741824}, {16, 1073741824});
+ test_pool_options({8, 2147483648}, {16, 1073741824});
+ test_pool_options({8, 8589934592}, {16, 1073741824});
+ test_pool_options({16, 0}, {16, 1048576});
+ test_pool_options({16, 1}, {16, 8});
+ test_pool_options({16, 2}, {16, 8});
+ test_pool_options({16, 4}, {16, 8});
+ test_pool_options({16, 8}, {16, 8});
+ test_pool_options({16, 16}, {16, 16});
+ test_pool_options({16, 32}, {16, 32});
+ test_pool_options({16, 1024}, {16, 1024});
+ test_pool_options({16, 1048576}, {16, 1048576});
+ test_pool_options({16, 2097152}, {16, 2097152});
+ test_pool_options({16, 1073741824}, {16, 1073741824});
+ test_pool_options({16, 2147483648}, {16, 1073741824});
+ test_pool_options({16, 8589934592}, {16, 1073741824});
+ test_pool_options({32, 0}, {32, 1048576});
+ test_pool_options({32, 1}, {32, 8});
+ test_pool_options({32, 2}, {32, 8});
+ test_pool_options({32, 4}, {32, 8});
+ test_pool_options({32, 8}, {32, 8});
+ test_pool_options({32, 16}, {32, 16});
+ test_pool_options({32, 32}, {32, 32});
+ test_pool_options({32, 1024}, {32, 1024});
+ test_pool_options({32, 1048576}, {32, 1048576});
+ test_pool_options({32, 2097152}, {32, 2097152});
+ test_pool_options({32, 1073741824}, {32, 1073741824});
+ test_pool_options({32, 2147483648}, {32, 1073741824});
+ test_pool_options({32, 8589934592}, {32, 1073741824});
+ test_pool_options({1024, 0}, {1024, 1048576});
+ test_pool_options({1024, 1}, {1024, 8});
+ test_pool_options({1024, 2}, {1024, 8});
+ test_pool_options({1024, 4}, {1024, 8});
+ test_pool_options({1024, 8}, {1024, 8});
+ test_pool_options({1024, 16}, {1024, 16});
+ test_pool_options({1024, 32}, {1024, 32});
+ test_pool_options({1024, 1024}, {1024, 1024});
+ test_pool_options({1024, 1048576}, {1024, 1048576});
+ test_pool_options({1024, 2097152}, {1024, 2097152});
+ test_pool_options({1024, 1073741824}, {1024, 1073741824});
+ test_pool_options({1024, 2147483648}, {1024, 1073741824});
+ test_pool_options({1024, 8589934592}, {1024, 1073741824});
+ test_pool_options({1048576, 0}, {1048576, 1048576});
+ test_pool_options({1048576, 1}, {1048576, 8});
+ test_pool_options({1048576, 2}, {1048576, 8});
+ test_pool_options({1048576, 4}, {1048576, 8});
+ test_pool_options({1048576, 8}, {1048576, 8});
+ test_pool_options({1048576, 16}, {1048576, 16});
+ test_pool_options({1048576, 32}, {1048576, 32});
+ test_pool_options({1048576, 1024}, {1048576, 1024});
+ test_pool_options({1048576, 1048576}, {1048576, 1048576});
+ test_pool_options({1048576, 2097152}, {1048576, 2097152});
+ test_pool_options({1048576, 1073741824}, {1048576, 1073741824});
+ test_pool_options({1048576, 2147483648}, {1048576, 1073741824});
+ test_pool_options({1048576, 8589934592}, {1048576, 1073741824});
+ test_pool_options({2097152, 0}, {1048576, 1048576});
+ test_pool_options({2097152, 1}, {1048576, 8});
+ test_pool_options({2097152, 2}, {1048576, 8});
+ test_pool_options({2097152, 4}, {1048576, 8});
+ test_pool_options({2097152, 8}, {1048576, 8});
+ test_pool_options({2097152, 16}, {1048576, 16});
+ test_pool_options({2097152, 32}, {1048576, 32});
+ test_pool_options({2097152, 1024}, {1048576, 1024});
+ test_pool_options({2097152, 1048576}, {1048576, 1048576});
+ test_pool_options({2097152, 2097152}, {1048576, 2097152});
+ test_pool_options({2097152, 1073741824}, {1048576, 1073741824});
+ test_pool_options({2097152, 2147483648}, {1048576, 1073741824});
+ test_pool_options({2097152, 8589934592}, {1048576, 1073741824});
+ test_pool_options({1073741824, 0}, {1048576, 1048576});
+ test_pool_options({1073741824, 1}, {1048576, 8});
+ test_pool_options({1073741824, 2}, {1048576, 8});
+ test_pool_options({1073741824, 4}, {1048576, 8});
+ test_pool_options({1073741824, 8}, {1048576, 8});
+ test_pool_options({1073741824, 16}, {1048576, 16});
+ test_pool_options({1073741824, 32}, {1048576, 32});
+ test_pool_options({1073741824, 1024}, {1048576, 1024});
+ test_pool_options({1073741824, 1048576}, {1048576, 1048576});
+ test_pool_options({1073741824, 2097152}, {1048576, 2097152});
+ test_pool_options({1073741824, 1073741824}, {1048576, 1073741824});
+ test_pool_options({1073741824, 2147483648}, {1048576, 1073741824});
+ test_pool_options({1073741824, 8589934592}, {1048576, 1073741824});
+ test_pool_options({2147483648, 0}, {1048576, 1048576});
+ test_pool_options({2147483648, 1}, {1048576, 8});
+ test_pool_options({2147483648, 2}, {1048576, 8});
+ test_pool_options({2147483648, 4}, {1048576, 8});
+ test_pool_options({2147483648, 8}, {1048576, 8});
+ test_pool_options({2147483648, 16}, {1048576, 16});
+ test_pool_options({2147483648, 32}, {1048576, 32});
+ test_pool_options({2147483648, 1024}, {1048576, 1024});
+ test_pool_options({2147483648, 1048576}, {1048576, 1048576});
+ test_pool_options({2147483648, 2097152}, {1048576, 2097152});
+ test_pool_options({2147483648, 1073741824}, {1048576, 1073741824});
+ test_pool_options({2147483648, 2147483648}, {1048576, 1073741824});
+ test_pool_options({2147483648, 8589934592}, {1048576, 1073741824});
+ test_pool_options({8589934592, 0}, {1048576, 1048576});
+ test_pool_options({8589934592, 1}, {1048576, 8});
+ test_pool_options({8589934592, 2}, {1048576, 8});
+ test_pool_options({8589934592, 4}, {1048576, 8});
+ test_pool_options({8589934592, 8}, {1048576, 8});
+ test_pool_options({8589934592, 16}, {1048576, 16});
+ test_pool_options({8589934592, 32}, {1048576, 32});
+ test_pool_options({8589934592, 1024}, {1048576, 1024});
+ test_pool_options({8589934592, 1048576}, {1048576, 1048576});
+ test_pool_options({8589934592, 2097152}, {1048576, 2097152});
+ test_pool_options({8589934592, 1073741824}, {1048576, 1073741824});
+ test_pool_options({8589934592, 2147483648}, {1048576, 1073741824});
+ test_pool_options({8589934592, 8589934592}, {1048576, 1073741824});
+}
Index: src/experimental/memory_resource.cpp
===================================================================
--- src/experimental/memory_resource.cpp
+++ src/experimental/memory_resource.cpp
@@ -165,14 +165,340 @@
return __default_memory_resource(true, __new_res);
}
-// 23.12.6, mem.res.monotonic.buffer
+// 23.12.5, mem.res.pool
static size_t roundup(size_t count, size_t alignment)
{
size_t mask = alignment - 1;
return (count + mask) & ~mask;
}
+struct unsynchronized_pool_resource::__adhoc_pool::__chunk_header {
+ __chunk_header *__next_;
+ char *__start_;
+ size_t __align_;
+ size_t __allocation_size() {
+ return (reinterpret_cast<char*>(this) - __start_) + sizeof(*this);
+ }
+};
+
+void unsynchronized_pool_resource::__adhoc_pool::__release(
+ memory_resource *upstream)
+{
+ while (__first_ != nullptr) {
+ __chunk_header *next = __first_->__next_;
+ upstream->deallocate(__first_->__start_, __first_->__allocation_size(),
+ __first_->__align_);
+ __first_ = next;
+ }
+}
+
+void *unsynchronized_pool_resource::__adhoc_pool::__do_allocate(
+ memory_resource *upstream, size_t bytes, size_t align)
+{
+ const size_t header_size = sizeof(__chunk_header);
+ const size_t header_align = alignof(__chunk_header);
+
+ if (align < header_align)
+ align = header_align;
+
+ size_t aligned_capacity = roundup(bytes, header_align) + header_size;
+
+ void *result = upstream->allocate(aligned_capacity, align);
+
+ __chunk_header *h =
+ (__chunk_header *)((char *)result + aligned_capacity - header_size);
+ h->__next_ = __first_;
+ h->__start_ = (char *)result;
+ h->__align_ = align;
+ __first_ = h;
+ return result;
+}
+
+void unsynchronized_pool_resource::__adhoc_pool::__do_deallocate(
+ memory_resource *upstream, void *p, size_t bytes, size_t align)
+{
+ _LIBCPP_ASSERT(__first_ != nullptr, "deallocating a block that was not allocated with this allocator");
+ if (__first_->__start_ == p) {
+ __chunk_header *next = __first_->__next_;
+ upstream->deallocate(p, __first_->__allocation_size(), __first_->__align_);
+ __first_ = next;
+ } else {
+ for (__chunk_header *h = __first_; h->__next_ != nullptr; h = h->__next_) {
+ if (h->__next_->__start_ == p) {
+ __chunk_header *next = h->__next_->__next_;
+ upstream->deallocate(p, h->__next_->__allocation_size(),
+ h->__next_->__align_);
+ h->__next_ = next;
+ return;
+ }
+ }
+ _LIBCPP_ASSERT(false, "deallocating a block that was not allocated with this allocator");
+ }
+}
+
+class unsynchronized_pool_resource::__fixed_pool {
+ struct __chunk_header {
+ __chunk_header *__next_;
+ char *__start_;
+ size_t __align_;
+ size_t __allocation_size() {
+ return (reinterpret_cast<char*>(this) - __start_) + sizeof(*this);
+ }
+ };
+
+ struct __vacancy_header {
+ __vacancy_header *__next_vacancy_;
+ };
+
+ __chunk_header *__first_chunk_ = nullptr;
+ __vacancy_header *__first_vacancy_ = nullptr;
+
+public:
+ explicit __fixed_pool() = default;
+
+ void __release(memory_resource *upstream)
+ {
+ __first_vacancy_ = nullptr;
+ while (__first_chunk_ != nullptr) {
+ __chunk_header *next = __first_chunk_->__next_;
+ upstream->deallocate(__first_chunk_->__start_,
+ __first_chunk_->__allocation_size(), __first_chunk_->__align_);
+ __first_chunk_ = next;
+ }
+ }
+
+ void *__try_allocate_from_vacancies()
+ {
+ if (__first_vacancy_ != nullptr) {
+ void *result = __first_vacancy_;
+ __first_vacancy_ = __first_vacancy_->__next_vacancy_;
+ return result;
+ }
+ return nullptr;
+ }
+
+ void *__allocate_in_new_chunk(
+ memory_resource *upstream, size_t block_size, size_t chunk_size)
+ {
+ _LIBCPP_ASSERT(chunk_size % block_size == 0, "");
+ static_assert(__default_alignment >= alignof(std::max_align_t), "");
+ static_assert(__default_alignment >= alignof(__chunk_header), "");
+ static_assert(__default_alignment >= alignof(__vacancy_header), "");
+
+ const size_t header_size = sizeof(__chunk_header);
+ const size_t header_align = alignof(__chunk_header);
+
+ size_t aligned_capacity = roundup(chunk_size, header_align) + header_size;
+
+ void *result = upstream->allocate(aligned_capacity, __default_alignment);
+
+ __chunk_header *h =
+ (__chunk_header *)((char *)result + aligned_capacity - header_size);
+ h->__next_ = __first_chunk_;
+ h->__start_ = (char *)result;
+ h->__align_ = __default_alignment;
+ __first_chunk_ = h;
+
+ if (chunk_size > block_size) {
+ __vacancy_header *last_vh = this->__first_vacancy_;
+ for (size_t i = block_size; i != chunk_size; i += block_size) {
+ __vacancy_header *vh = (__vacancy_header *)((char *)result + i);
+ vh->__next_vacancy_ = last_vh;
+ last_vh = vh;
+ }
+ this->__first_vacancy_ = last_vh;
+ }
+ return result;
+ }
+
+ void __evacuate(void *p)
+ {
+ __vacancy_header *vh = (__vacancy_header *)(p);
+ vh->__next_vacancy_ = __first_vacancy_;
+ __first_vacancy_ = vh;
+ }
+
+ size_t __previous_chunk_size_in_bytes() const
+ {
+ return __first_chunk_ ? __first_chunk_->__allocation_size() : 0;
+ }
+
+ static const size_t __default_alignment = alignof(max_align_t);
+};
+
+size_t unsynchronized_pool_resource::__pool_block_size(int i) const
+{
+ return size_t(1) << __log2_pool_block_size(i);
+}
+
+int unsynchronized_pool_resource::__log2_pool_block_size(int i) const
+{
+ return (i + __log2_smallest_block_size);
+}
+
+int unsynchronized_pool_resource::__pool_index(size_t bytes, size_t align) const
+{
+ if (align > alignof(std::max_align_t) || bytes > (size_t(1) << __num_fixed_pools_))
+ return __num_fixed_pools_;
+ else {
+ int i = 0;
+ bytes = (bytes > align) ? bytes : align;
+ bytes -= 1;
+ bytes >>= __log2_smallest_block_size;
+ while (bytes != 0) {
+ bytes >>= 1;
+ i += 1;
+ }
+ return i;
+ }
+}
+
+unsynchronized_pool_resource::unsynchronized_pool_resource(
+ const pool_options& opts, memory_resource* upstream)
+ : __res_(upstream), __fixed_pools_(nullptr)
+{
+ size_t largest_block_size;
+ if (opts.largest_required_pool_block == 0)
+ largest_block_size = __default_largest_block_size;
+ else if (opts.largest_required_pool_block < __smallest_block_size)
+ largest_block_size = __smallest_block_size;
+ else if (opts.largest_required_pool_block > __max_largest_block_size)
+ largest_block_size = __max_largest_block_size;
+ else
+ largest_block_size = opts.largest_required_pool_block;
+
+ if (opts.max_blocks_per_chunk == 0)
+ __options_max_blocks_per_chunk_ = __max_blocks_per_chunk;
+ else if (opts.max_blocks_per_chunk < __min_blocks_per_chunk)
+ __options_max_blocks_per_chunk_ = __min_blocks_per_chunk;
+ else if (opts.max_blocks_per_chunk > __max_blocks_per_chunk)
+ __options_max_blocks_per_chunk_ = __max_blocks_per_chunk;
+ else
+ __options_max_blocks_per_chunk_ = opts.max_blocks_per_chunk;
+
+ __num_fixed_pools_ = 1;
+ size_t capacity = __smallest_block_size;
+ while (capacity < largest_block_size) {
+ capacity <<= 1;
+ __num_fixed_pools_ += 1;
+ }
+}
+
+pool_options unsynchronized_pool_resource::options() const
+{
+ return {
+ __options_max_blocks_per_chunk_,
+ __pool_block_size(__num_fixed_pools_ - 1)
+ };
+}
+
+void unsynchronized_pool_resource::release()
+{
+ __adhoc_pool_.__release(__res_);
+ if (__fixed_pools_ != nullptr) {
+ const int n = __num_fixed_pools_;
+ for (int i=0; i < n; ++i)
+ __fixed_pools_[i].__release(__res_);
+ __res_->deallocate(__fixed_pools_,
+ __num_fixed_pools_ * sizeof(__fixed_pool), alignof(__fixed_pool));
+ __fixed_pools_ = nullptr;
+ }
+}
+
+void *unsynchronized_pool_resource::do_allocate(size_t bytes, size_t align)
+{
+ // A pointer to allocated storage (6.6.4.4.1) with a size of at least bytes.
+ // The size and alignment of the allocated memory shall meet the requirements for
+ // a class derived from memory_resource (23.12).
+ // If the pool selected for a block of size bytes is unable to satisfy the memory request
+ // from its own internal data structures, it will call upstream_resource()->allocate()
+ // to obtain more memory. If bytes is larger than that which the largest pool can handle,
+ // then memory will be allocated using upstream_resource()->allocate().
+
+ int i = __pool_index(bytes, align);
+ if (i == __num_fixed_pools_)
+ return __adhoc_pool_.__do_allocate(__res_, bytes, align);
+ else {
+ if (__fixed_pools_ == nullptr) {
+ __fixed_pools_ = (__fixed_pool*)__res_->allocate(
+ __num_fixed_pools_ * sizeof(__fixed_pool),
+ alignof(__fixed_pool)
+ );
+ __fixed_pool *first = __fixed_pools_;
+ __fixed_pool *last = __fixed_pools_ + __num_fixed_pools_;
+ for (__fixed_pool *pool = first; pool != last; ++pool)
+ ::new((void*)pool) __fixed_pool;
+ }
+ void *result = __fixed_pools_[i].__try_allocate_from_vacancies();
+ if (result == nullptr) {
+ static_assert(
+ (__max_bytes_per_chunk*5)/4 > __max_bytes_per_chunk,
+ "unsigned overflow is possible"
+ );
+ auto min = [](size_t a, size_t b) { return a < b ? a : b; };
+ auto max = [](size_t a, size_t b) { return a < b ? b : a; };
+
+ size_t prev_chunk_size_in_bytes = __fixed_pools_[i].__previous_chunk_size_in_bytes();
+ size_t prev_chunk_size_in_blocks = prev_chunk_size_in_bytes >> __log2_pool_block_size(i);
+
+ size_t chunk_size_in_blocks;
+
+ if (prev_chunk_size_in_blocks == 0) {
+ size_t min_blocks_per_chunk = max(
+ __min_bytes_per_chunk >> __log2_pool_block_size(i),
+ __min_blocks_per_chunk
+ );
+ chunk_size_in_blocks = min_blocks_per_chunk;
+ } else
+ chunk_size_in_blocks = (prev_chunk_size_in_blocks*5)/4;
+
+ size_t max_blocks_per_chunk = min(
+ (__max_bytes_per_chunk >> __log2_pool_block_size(i)),
+ min(
+ __max_blocks_per_chunk,
+ __options_max_blocks_per_chunk_
+ )
+ );
+ if (chunk_size_in_blocks > max_blocks_per_chunk)
+ chunk_size_in_blocks = max_blocks_per_chunk;
+
+ size_t block_size = __pool_block_size(i);
+
+ size_t chunk_size_in_bytes =
+ (chunk_size_in_blocks << __log2_pool_block_size(i));
+ result = __fixed_pools_[i].__allocate_in_new_chunk(
+ __res_, block_size, chunk_size_in_bytes
+ );
+ }
+ return result;
+ }
+}
+
+void unsynchronized_pool_resource::do_deallocate(
+ void* p, size_t bytes, size_t align)
+{
+ // Returns the memory at p to the pool. It is unspecified if,
+ // or under what circumstances, this operation will result in
+ // a call to upstream_resource()->deallocate().
+
+ int i = __pool_index(bytes, align);
+ if (i == __num_fixed_pools_)
+ return __adhoc_pool_.__do_deallocate(__res_, p, bytes, align);
+ else {
+ _LIBCPP_ASSERT(__fixed_pools_ != nullptr, "deallocating a block that was not allocated with this allocator");
+ __fixed_pools_[i].__evacuate(p);
+ }
+}
+
+bool synchronized_pool_resource::do_is_equal(
+ const memory_resource& other) const _NOEXCEPT
+{
+ return &other == this;
+}
+
+// 23.12.6, mem.res.monotonic.buffer
+
void *monotonic_buffer_resource::__initial_header::__try_allocate_from_chunk(
size_t bytes, size_t align)
{
Index: include/experimental/memory_resource
===================================================================
--- include/experimental/memory_resource
+++ include/experimental/memory_resource
@@ -69,12 +69,16 @@
#include <experimental/__memory>
#include <limits>
#include <memory>
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+#include <mutex>
+#endif
#include <new>
#include <stdexcept>
#include <__tuple>
#include <type_traits>
#include <utility>
#include <cstddef>
+#include <cstdint>
#include <cstdlib>
#include <__debug>
@@ -420,6 +424,167 @@
typename allocator_traits<_Alloc>::template rebind_alloc<char>
>;
+// 23.12.5, mem.res.pool
+
+// 23.12.5.2, mem.res.pool.options
+
+struct _LIBCPP_TYPE_VIS pool_options {
+ size_t max_blocks_per_chunk = 0;
+ size_t largest_required_pool_block = 0;
+};
+
+// 23.12.5.1, mem.res.pool.overview
+
+
+class _LIBCPP_TYPE_VIS unsynchronized_pool_resource : public memory_resource
+{
+ class __fixed_pool;
+
+ class __adhoc_pool {
+ struct __chunk_header;
+ __chunk_header *__first_;
+
+ public:
+ _LIBCPP_INLINE_VISIBILITY
+ explicit __adhoc_pool() : __first_(nullptr) {}
+
+ void __release(memory_resource *__upstream);
+ void *__do_allocate(memory_resource *__upstream,
+ size_t __bytes, size_t __align);
+ void __do_deallocate(memory_resource *__upstream,
+ void *__p, size_t __bytes, size_t __align);
+ };
+
+ static const size_t __min_blocks_per_chunk = 16;
+ static const size_t __min_bytes_per_chunk = 1024;
+ static const size_t __max_blocks_per_chunk = (size_t(1) << 20);
+ static const size_t __max_bytes_per_chunk = (size_t(1) << 30);
+
+ static const int __log2_smallest_block_size = 3;
+ static const size_t __smallest_block_size = 8;
+ static const size_t __default_largest_block_size = (size_t(1) << 20);
+ static const size_t __max_largest_block_size = (size_t(1) << 30);
+
+ size_t __pool_block_size(int __i) const;
+ int __log2_pool_block_size(int __i) const;
+ int __pool_index(size_t __bytes, size_t __align) const;
+
+public:
+ unsynchronized_pool_resource(const pool_options& __opts,
+ memory_resource* __upstream);
+
+ _LIBCPP_INLINE_VISIBILITY
+ unsynchronized_pool_resource()
+ : unsynchronized_pool_resource(pool_options(), get_default_resource()) {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ explicit unsynchronized_pool_resource(memory_resource* __upstream)
+ : unsynchronized_pool_resource(pool_options(), __upstream) {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ explicit unsynchronized_pool_resource(const pool_options& __opts)
+ : unsynchronized_pool_resource(__opts, get_default_resource()) {}
+
+ unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete;
+
+ _LIBCPP_INLINE_VISIBILITY
+ ~unsynchronized_pool_resource() override
+ { release(); }
+
+ unsynchronized_pool_resource& operator=(const unsynchronized_pool_resource&) = delete;
+
+ void release();
+
+ _LIBCPP_INLINE_VISIBILITY
+ memory_resource* upstream_resource() const
+ { return __res_; }
+
+ pool_options options() const;
+
+protected:
+ void *do_allocate(size_t __bytes, size_t __align) override; // key function
+
+ void do_deallocate(void *__p, size_t __bytes, size_t __align) override;
+
+ _LIBCPP_INLINE_VISIBILITY
+ bool do_is_equal(const memory_resource& __other) const _NOEXCEPT override
+ { return &__other == this; }
+
+private:
+ memory_resource *__res_;
+ __adhoc_pool __adhoc_pool_;
+ __fixed_pool *__fixed_pools_;
+ int __num_fixed_pools_;
+ uint32_t __options_max_blocks_per_chunk_;
+};
+
+class _LIBCPP_TYPE_VIS synchronized_pool_resource : public memory_resource
+{
+public:
+ _LIBCPP_INLINE_VISIBILITY
+ synchronized_pool_resource(const pool_options& __opts, memory_resource *__upstream)
+ : __unsync_(__opts, __upstream) {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ synchronized_pool_resource()
+ : synchronized_pool_resource(pool_options(), get_default_resource()) {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ explicit synchronized_pool_resource(memory_resource *__upstream)
+ : synchronized_pool_resource(pool_options(), __upstream) {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ explicit synchronized_pool_resource(const pool_options& __opts)
+ : synchronized_pool_resource(__opts, get_default_resource()) {}
+
+ synchronized_pool_resource(const synchronized_pool_resource&) = delete;
+
+ ~synchronized_pool_resource() override = default;
+
+ synchronized_pool_resource& operator=(const synchronized_pool_resource&) = delete;
+
+ _LIBCPP_INLINE_VISIBILITY
+ void release() {
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+ unique_lock<mutex> __lk(__mut_);
+#endif
+ __unsync_.release();
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ memory_resource* upstream_resource() const
+ { return __unsync_.upstream_resource(); }
+
+ _LIBCPP_INLINE_VISIBILITY
+ pool_options options() const
+ { return __unsync_.options(); }
+
+protected:
+ _LIBCPP_INLINE_VISIBILITY
+ void* do_allocate(size_t __bytes, size_t __align) override {
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+ unique_lock<mutex> __lk(__mut_);
+#endif
+ return __unsync_.allocate(__bytes, __align);
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ void do_deallocate(void *__p, size_t __bytes, size_t __align) override {
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+ unique_lock<mutex> __lk(__mut_);
+#endif
+ return __unsync_.deallocate(__p, __bytes, __align);
+ }
+
+ bool do_is_equal(const memory_resource& __other) const _NOEXCEPT override; // key function
+
+private:
+#if !defined(_LIBCPP_HAS_NO_THREADS)
+ mutex __mut_;
+#endif
+ unsynchronized_pool_resource __unsync_;
+};
+
// 23.12.6, mem.res.monotonic.buffer
class _LIBCPP_TYPE_VIS monotonic_buffer_resource : public memory_resource
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits