EricWF created this revision.
EricWF added a reviewer: mclow.lists.
EricWF added a subscriber: cfe-commits.
Implemented from the LFTS v2 spec here:
https://rawgit.com/cplusplus/fundamentals-ts/v2/main.html#memory.resource.monotonic.buffer.
This patch could use some finishing touches, but for the most part it is a
complete implementation and tests.
https://reviews.llvm.org/D27402
Files:
include/experimental/__memory
include/experimental/memory_resource
src/experimental/memory_resource.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/buffer.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/buffer_resource.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/copy_move.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/default.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/dtor.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/initial_size.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/resource.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/do_allocate.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/do_deallocate.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/release.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/upstream_resource.pass.cpp
test/std/experimental/memory/memory.resource.pool/pool_options.pass.cpp
test/support/count_new.hpp
test/support/test_memory_resource.hpp
Index: test/support/test_memory_resource.hpp
===================================================================
--- test/support/test_memory_resource.hpp
+++ test/support/test_memory_resource.hpp
@@ -483,7 +483,8 @@
assert(false);
#endif
}
-
+ next = static_cast<char*>(next) + s;
+ space -= s;
return ret;
}
Index: test/support/count_new.hpp
===================================================================
--- test/support/count_new.hpp
+++ test/support/count_new.hpp
@@ -184,6 +184,10 @@
return disable_checking || n != last_new_size;
}
+ bool checkLastNewSizeGreaterEq(int n) const {
+ return disable_checking || last_new_size >= n;
+ }
+
bool checkOutstandingArrayNewEq(int n) const
{
return disable_checking || n == outstanding_array_new;
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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// struct pool_options
+
+#include <cassert>
+#include <experimental/memory_resource>
+
+int main() {
+ using std::experimental::pmr::pool_options;
+ {
+ const pool_options p;
+ assert(p.max_blocks_per_chunk == 0);
+ assert(p.largest_required_pool_block == 0);
+ }
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/upstream_resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/upstream_resource.pass.cpp
@@ -0,0 +1,46 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class monotonic_buffer_resource
+
+// memory_resource *upstream_resource() const;
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ Res R1;
+ {
+ ex::monotonic_buffer_resource res;
+ assert(res.upstream_resource() == ex::get_default_resource());
+ assert(ex::get_default_resource() == ex::new_delete_resource());
+
+ Res R;
+ ex::set_default_resource(&R);
+ ex::monotonic_buffer_resource res2;
+ assert(res2.upstream_resource() == &R);
+
+ ex::set_default_resource(ex::new_delete_resource());
+ }
+ {
+ Res R;
+ const ex::monotonic_buffer_resource res(&R);
+ assert(res.upstream_resource() == &R);
+ }
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/release.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/release.pass.cpp
@@ -0,0 +1,84 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class monotonic_buffer_resource
+
+// void release()
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+#include "count_new.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ Res R1;
+ AllocController &P = R1.getController();
+ {
+ DisableAllocationGuard g;
+ ex::monotonic_buffer_resource res;
+ res.release();
+ }
+ {
+ ex::monotonic_buffer_resource res(&R1);
+ assert(res.allocate(1));
+ assert(P.alive == 1);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 0);
+ assert(P.last_alloc_size > 1);
+ int count = 0;
+ while (P.alive == 1) {
+ ++count;
+ assert(res.allocate(1));
+ }
+ assert(count > 1);
+ assert(P.alive == 2);
+ assert(P.alloc_count == 2);
+ assert(P.dealloc_count == 0);
+ res.release();
+ assert(P.alive == 0);
+ assert(P.alloc_count == 2);
+ assert(P.dealloc_count == 2);
+ }
+ assert(P.alive == 0);
+ assert(P.alloc_count == 2);
+ assert(P.dealloc_count == 2);
+ P.reset();
+ {
+ const size_t S = 1024;
+ alignas(std::max_align_t) char Buff[S];
+ ex::monotonic_buffer_resource res(Buff, S, &R1);
+ res.allocate(1024, alignof(std::max_align_t));
+ assert(P.alloc_count == 0);
+ assert(P.dealloc_count == 0);
+
+ res.allocate(1);
+ assert(P.alive == 1);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 0);
+
+ res.release();
+ assert(P.alive == 0);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 1);
+ assert(P.checkDeallocMatchesAlloc());
+ }
+ assert(P.alive == 0);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 1);
+ P.reset();
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/do_deallocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/do_deallocate.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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class monotonic_buffer_resource
+
+// void do_deallocate(void *p, size_t size, size_t align)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+#include "count_new.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ Res R1;
+ AllocController &P = R1.getController();
+ {
+ ex::monotonic_buffer_resource res(&R1);
+ const size_t size = 2056;
+ void *mem = res.allocate(size);
+ assert(mem);
+ assert(P.alive == 1);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 0);
+ assert(P.last_alloc_size > size);
+
+ res.deallocate(mem, size);
+ assert(P.alive == 1);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 0);
+ }
+ assert(P.alive == 0);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 1);
+ assert(P.checkDeallocMatchesAlloc());
+ P.reset();
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/do_allocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/do_allocate.pass.cpp
@@ -0,0 +1,105 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class monotonic_buffer_resource
+
+// void *do_allocate(size_t size, size_t align)
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+#include "count_new.hpp"
+
+namespace ex = std::experimental::pmr;
+
+void test_contiguous_allocation() {
+ using Res = TestResource;
+ Res R1;
+ AllocController &P = R1.getController();
+
+ {
+ const int initial_size = 2056;
+ ex::monotonic_buffer_resource res(initial_size, &R1);
+ void *last_ptr = res.allocate(1, 1);
+ int last_size = 1;
+ int rem_size = initial_size - 1;
+ for (int i = 0; rem_size - i >= 0; ++i) {
+ void *new_ptr = res.allocate(i, 1);
+ assert(new_ptr == (static_cast<char *>(last_ptr) + last_size));
+ last_ptr = new_ptr;
+ last_size = i;
+ rem_size -= i;
+ if (i == 64)
+ i = 0;
+ }
+ assert(P.alive == 1);
+ void *new_ptr = res.allocate(65, 1);
+ assert(P.alive >= 2);
+ assert(new_ptr != (static_cast<char *>(last_ptr) + 1));
+ }
+ assert(P.alive == 0);
+ P.reset();
+}
+
+void test_correct_alignment() {
+ using AllocT = MinAlignedAllocator<char>;
+ using Res = ex::resource_adaptor<AllocT>;
+
+ { // Test default alignment
+ AllocController P;
+ Res R((AllocT(P)));
+ ex::monotonic_buffer_resource res(&R);
+ for (int i = 0; i < 3; ++i) {
+ for (size_t size = 0; size < 1024; ++size) {
+ void *ptr = res.allocate(size);
+ assert(ptr);
+ assert((reinterpret_cast<uintptr_t>(ptr) % alignof(std::max_align_t)) ==
+ 0);
+ }
+ }
+ }
+ {
+ AllocController P;
+ Res R((AllocT(P)));
+ ex::monotonic_buffer_resource res(&R);
+ for (int i = 0; i < 3; ++i) {
+ for (size_t align = 1; align <= alignof(std::max_align_t); align *= 2) {
+ void *ptr = res.allocate(1, align);
+ assert(ptr);
+ assert(reinterpret_cast<uintptr_t>(ptr) % align == 0);
+ }
+ }
+ }
+}
+
+void test_alloc_zero_size() {
+ using AllocT = MinAlignedAllocator<char>;
+ using Res = ex::resource_adaptor<AllocT>;
+ AllocController P;
+ Res R((AllocT(P)));
+ {
+ ex::monotonic_buffer_resource res(&R);
+ assert(res.allocate(0));
+ assert(P.alive == 1);
+ }
+ assert(P.alive == 0);
+ P.reset();
+}
+
+int main() {
+ test_contiguous_allocation();
+ test_correct_alignment();
+ test_alloc_zero_size();
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/resource.pass.cpp
@@ -0,0 +1,65 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// explicit monotonic_buffer_resource(monotonic_buffer_resource*);
+// monotonic_buffer_resource(size_t initial_size, monotonic_buffer_resource*);
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ Res R1, R2;
+ AllocController &P1 = R1.getController();
+ AllocController &P2 = R2.getController();
+ {
+ static_assert(!std::is_convertible<ex::memory_resource *,
+ ex::monotonic_buffer_resource>::value,
+ "");
+ static_assert(std::is_constructible<ex::monotonic_buffer_resource,
+ ex::monotonic_buffer_resource *>::value,
+ "");
+ }
+ {
+ ex::monotonic_buffer_resource res(&R1);
+ ex::monotonic_buffer_resource res2(&R2);
+ assert(res.upstream_resource() == &R1);
+ assert(res2.upstream_resource() == &R2);
+ assert(P1.alive == 0);
+ assert(P2.alive == 0);
+ }
+ {
+ ex::monotonic_buffer_resource res(42, &R1);
+
+ assert(res.upstream_resource() == &R1);
+
+ assert(P1.alive == 0);
+ assert(P2.alive == 0);
+ void *mem1 = res.allocate(1, 1);
+ assert(P1.last_alloc_size >= 42);
+ const size_t default_alloc_size = P1.last_alloc_size;
+ assert(P1.alive == 1);
+
+ const size_t init_size = default_alloc_size + 42;
+ ex::monotonic_buffer_resource res2(init_size, &R2);
+ assert(res2.upstream_resource() == &R2);
+ void *mem2 = res2.allocate(1, 1);
+ assert(P2.last_alloc_size >= init_size);
+ assert(P2.alive == 1);
+ }
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/initial_size.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/initial_size.pass.cpp
@@ -0,0 +1,59 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// explicit monotonic_buffer_resource(size_t initial_size);
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+#include "count_new.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ {
+ static_assert(
+ !std::is_convertible<size_t, ex::monotonic_buffer_resource>::value, "");
+ static_assert(
+ std::is_constructible<ex::monotonic_buffer_resource, size_t>::value,
+ "");
+ }
+ {
+ Res R1;
+ auto &C = R1.getController();
+ auto *default_res = ex::get_default_resource();
+ assert(default_res == ex::new_delete_resource());
+
+ ex::monotonic_buffer_resource res(42);
+ assert(res.upstream_resource() == default_res);
+ void *mem = res.allocate(1, 1);
+ assert(globalMemCounter.checkOutstandingNewEq(1));
+ assert(globalMemCounter.checkLastNewSizeGreaterEq(42));
+ const size_t default_init_size = globalMemCounter.last_new_size;
+
+ const size_t custom_init_size = default_init_size + 42;
+ ex::set_default_resource(&R1);
+ ex::monotonic_buffer_resource res1(custom_init_size);
+ assert(res1.upstream_resource() == &R1);
+ assert(res1.upstream_resource() != default_res);
+ {
+ DisableAllocationGuard g;
+ mem = res1.allocate(1, 0);
+ assert(C.last_alloc_size >= default_init_size);
+ assert(C.alive == 1);
+ }
+ }
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/dtor.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/dtor.pass.cpp
@@ -0,0 +1,60 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// ~monotonic_buffer_resource();
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ Res R1;
+ AllocController &P = R1.getController();
+
+ {
+ ex::monotonic_buffer_resource res(&R1);
+ res.allocate(1, 1);
+ assert(P.alive == 1);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 0);
+ assert(P.last_alloc_size > 1);
+ while (P.alive == 1)
+ res.allocate(1);
+ }
+ assert(P.alive == 0);
+ assert(P.alloc_count == 2);
+ assert(P.dealloc_count == 2);
+ P.reset();
+ {
+ const size_t S = 1024;
+ alignas(std::max_align_t) char Buff[S];
+ ex::monotonic_buffer_resource res(Buff, S, &R1);
+ res.allocate(1024, alignof(std::max_align_t));
+ assert(P.alloc_count == 0);
+ assert(P.dealloc_count == 0);
+
+ res.allocate(1);
+ assert(P.alive == 1);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 0);
+ }
+ assert(P.alive == 0);
+ assert(P.alloc_count == 1);
+ assert(P.dealloc_count == 1);
+ P.reset();
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/default.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/default.pass.cpp
@@ -0,0 +1,39 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// monotonic_buffer_resource();
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ {
+ Res R1;
+ auto *default_res = ex::get_default_resource();
+ assert(default_res == ex::new_delete_resource());
+
+ ex::monotonic_buffer_resource res;
+ assert(res.upstream_resource() == default_res);
+
+ ex::set_default_resource(&R1);
+ ex::monotonic_buffer_resource res1;
+ assert(res1.upstream_resource() == &R1);
+ assert(res1.upstream_resource() != default_res);
+ assert(res.upstream_resource() != &R1);
+ }
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/copy_move.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/copy_move.pass.cpp
@@ -0,0 +1,31 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// monotonic_buffer_resource(monotonic_buffer_resource const&) = delete;
+// monotonic_buffer_resource& operator=(monotonic_buffer_resource const&) = delete;
+
+#include <experimental/memory_resource>
+#include <type_traits>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using MBR = ex::monotonic_buffer_resource;
+ static_assert(!std::is_copy_constructible<MBR>::value, "");
+ static_assert(!std::is_move_constructible<MBR>::value, "");
+ static_assert(!std::is_copy_assignable<MBR>::value, "");
+ static_assert(!std::is_move_assignable<MBR>::value, "");
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/buffer_resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/buffer_resource.pass.cpp
@@ -0,0 +1,79 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// monotonic_buffer_resource(void *buffer, size_t buffer_size, monotonic_buffer_resource*);
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ auto in_range = [](void *p, char *b, char *e) {
+ uintptr_t pint = reinterpret_cast<uintptr_t>(p);
+ uintptr_t bint = reinterpret_cast<uintptr_t>(b);
+ uintptr_t eint = reinterpret_cast<uintptr_t>(e);
+ return pint >= bint && pint < eint;
+ };
+ {
+ Res R1, R2;
+ AllocController &P1 = R1.getController();
+ AllocController &P2 = R2.getController();
+ char Buff1[42];
+ char Buff2[512];
+
+ ex::monotonic_buffer_resource res(Buff1, 42, &R1);
+ ex::monotonic_buffer_resource res2(Buff2, 512, &R2);
+ assert(res.upstream_resource() == &R1);
+ assert(res2.upstream_resource() == &R2);
+ assert(P1.alive == 0);
+ assert(P2.alive == 0);
+ }
+ {
+ const size_t Size = 64;
+ alignas(std::max_align_t) char Buff[Size];
+ char *End = Buff + Size;
+ Res R;
+ auto &P = R.getController();
+ ex::monotonic_buffer_resource res(Buff, Size, &R);
+ assert(res.upstream_resource() == &R);
+ assert(P.alive == 0);
+ void *mem1 = res.allocate(Size - 4, 1);
+ assert(in_range(mem1, Buff, End));
+ assert(P.alive == 0);
+ mem1 = res.allocate(4, 1);
+ assert(in_range(mem1, Buff, End));
+ assert(P.alive == 0);
+ mem1 = res.allocate(1, 1);
+ assert(P.alive == 1);
+ assert(!in_range(mem1, Buff, End));
+ }
+ {
+ const size_t Size = 512;
+ alignas(std::max_align_t) char Buff[Size];
+ char *End = Buff + Size;
+ Res R;
+ auto &P = R.getController();
+ ex::monotonic_buffer_resource res(Buff, Size, &R);
+ assert(res.upstream_resource() == &R);
+ assert(P.alive == 0);
+ void *mem1 = res.allocate(Size + 1, 8);
+ assert(!in_range(mem1, Buff, End));
+ assert(P.alive == 1);
+ assert(P.last_alloc_size >= Size + 1);
+ assert(P.last_alloc_align >= 8);
+ }
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/buffer.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/buffer.pass.cpp
@@ -0,0 +1,80 @@
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// monotonic_buffer_resource(void *buffer, size_t buffer_size, monotonic_buffer_resource*);
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "test_memory_resource.hpp"
+#include "count_new.hpp"
+
+namespace ex = std::experimental::pmr;
+
+int main() {
+ using Res = TestResource;
+ auto in_range = [](void *p, char *b, char *e) {
+ uintptr_t pint = reinterpret_cast<uintptr_t>(p);
+ uintptr_t bint = reinterpret_cast<uintptr_t>(b);
+ uintptr_t eint = reinterpret_cast<uintptr_t>(e);
+ return pint >= bint && pint < eint;
+ };
+ {
+ DisableAllocationGuard g;
+ Res R1;
+ AllocController &P1 = R1.getController();
+ char Buff1[42];
+ char Buff2[512];
+
+ ex::monotonic_buffer_resource res(Buff1, 42);
+ ex::set_default_resource(&R1);
+ ex::monotonic_buffer_resource res2(Buff2, 512);
+ assert(res.upstream_resource() == ex::new_delete_resource());
+ assert(res2.upstream_resource() == &R1);
+ assert(P1.alive == 0);
+ }
+ ex::set_default_resource(ex::new_delete_resource());
+ {
+ const size_t Size = 64;
+ alignas(std::max_align_t) char Buff[Size];
+ char *End = Buff + Size;
+ globalMemCounter.disableAllocations();
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+ ex::monotonic_buffer_resource res(Buff, Size);
+ assert(res.upstream_resource() == ex::new_delete_resource());
+ void *mem1 = res.allocate(Size - 4, 1);
+ assert(in_range(mem1, Buff, End));
+ mem1 = res.allocate(4, 1);
+ assert(in_range(mem1, Buff, End));
+ globalMemCounter.enableAllocations();
+ mem1 = res.allocate(1, 1);
+ assert(globalMemCounter.checkOutstandingNewEq(1));
+ assert(!in_range(mem1, Buff, End));
+ }
+ {
+ const size_t Size = 512;
+ alignas(std::max_align_t) char Buff[Size];
+ char *End = Buff + Size;
+ Res R;
+ ex::set_default_resource(&R);
+ auto &P = R.getController();
+ ex::monotonic_buffer_resource res(Buff, Size);
+ assert(res.upstream_resource() == &R);
+ assert(P.alive == 0);
+ void *mem1 = res.allocate(Size + 1, 8);
+ assert(!in_range(mem1, Buff, End));
+ assert(P.alive == 1);
+ assert(P.last_alloc_size >= Size + 1);
+ assert(P.last_alloc_align >= 8);
+ }
+}
Index: src/experimental/memory_resource.cpp
===================================================================
--- src/experimental/memory_resource.cpp
+++ src/experimental/memory_resource.cpp
@@ -140,4 +140,8 @@
return __default_memory_resource(true, __new_res);
}
-_LIBCPP_END_NAMESPACE_LFTS_PMR
\ No newline at end of file
+monotonic_buffer_resource::~monotonic_buffer_resource() {
+ __alloc_.__release(__res_);
+}
+
+_LIBCPP_END_NAMESPACE_LFTS_PMR
Index: include/experimental/memory_resource
===================================================================
--- include/experimental/memory_resource
+++ include/experimental/memory_resource
@@ -78,35 +78,28 @@
#include <cstdlib>
#include <__debug>
+#include <cassert> // FIXME remove all usages of assert
+
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
#pragma GCC system_header
#endif
_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
-// Round __s up to next multiple of __a.
-inline _LIBCPP_INLINE_VISIBILITY
-size_t __aligned_allocation_size(size_t __s, size_t __a) _NOEXCEPT
-{
- _LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows");
- return (__s + __a - 1) & ~(__a - 1);
-}
-
// 8.5, memory.resource
class _LIBCPP_TYPE_VIS_ONLY memory_resource
{
- static const size_t __max_align = alignof(max_align_t);
// 8.5.2, memory.resource.public
public:
virtual ~memory_resource() = default;
_LIBCPP_INLINE_VISIBILITY
- void* allocate(size_t __bytes, size_t __align = __max_align)
+ void* allocate(size_t __bytes, size_t __align = __max_align())
{ return do_allocate(__bytes, __align); }
_LIBCPP_INLINE_VISIBILITY
- void deallocate(void * __p, size_t __bytes, size_t __align = __max_align)
+ void deallocate(void * __p, size_t __bytes, size_t __align = __max_align())
{ do_deallocate(__p, __bytes, __align); }
_LIBCPP_INLINE_VISIBILITY
@@ -342,10 +335,8 @@
&& is_same<typename _CTraits::pointer, char*>::value
&& is_same<typename _CTraits::void_pointer, void*>::value, "");
- static const size_t _MaxAlign = alignof(max_align_t);
-
using _Alloc = typename _CTraits::template rebind_alloc<
- typename aligned_storage<_MaxAlign, _MaxAlign>::type
+ typename aligned_storage<__max_align(), __max_align()>::type
>;
using _ValueType = typename _Alloc::value_type;
@@ -387,15 +378,15 @@
"std::experimental::pmr::resource_adaptor<T>::do_allocate(size_t bytes, size_t align)"
" 'bytes' exceeds maximum supported size");
}
- size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
+ size_t __s = __aligned_allocation_size(__bytes) / __max_align();
return __alloc_.allocate(__s);
}
virtual void do_deallocate(void * __p, size_t __bytes, size_t)
{
_LIBCPP_ASSERT(__bytes <= __max_size(),
"do_deallocate called for size which exceeds the maximum allocation size");
- size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign;
+ size_t __s = __aligned_allocation_size(__bytes) / __max_align();
__alloc_.deallocate((_ValueType*)__p, __s);
}
@@ -408,15 +399,269 @@
private:
_LIBCPP_INLINE_VISIBILITY
size_t __max_size() const _NOEXCEPT {
- return numeric_limits<size_t>::max() - _MaxAlign;
+ return numeric_limits<size_t>::max() - __max_align();
}
};
template <class _Alloc>
using resource_adaptor = __resource_adaptor_imp<
typename allocator_traits<_Alloc>::template rebind_alloc<char>
>;
+struct _LIBCPP_TYPE_VIS_ONLY pool_options {
+ size_t max_blocks_per_chunk = 0;
+ size_t largest_required_pool_block = 0;
+
+ // Implementation limits
+ static constexpr size_t __impl_max_blocks_per_chunk = 32;
+ static constexpr size_t __impl_smallest_block = 8;
+ static constexpr size_t __impl_largest_block = 4096;
+};
+
+inline _LIBCPP_INLINE_VISIBILITY size_t
+ __adjust_max_blocks_per_chunk(size_t __mbpc) _NOEXCEPT {
+ if (__mbpc == 0 || __mbpc > pool_options::__impl_max_blocks_per_chunk) {
+ return pool_options::__impl_max_blocks_per_chunk;
+ } else {
+ return __mbpc;
+ }
+}
+
+inline _LIBCPP_INLINE_VISIBILITY size_t
+ __adjust_largest_required_pool_block(size_t __lpb) _NOEXCEPT {
+ if (__lpb == 0 || __lpb > pool_options::__impl_largest_block) {
+ return pool_options::__impl_largest_block;
+ } else if (__lpb < pool_options::__impl_smallest_block) {
+ return pool_options::__impl_smallest_block;
+ } else {
+ return __lpb;
+ }
+}
+
+inline _LIBCPP_INLINE_VISIBILITY pool_options
+ __adjust_pool_options(pool_options __opts) _NOEXCEPT {
+ __opts.max_blocks_per_chunk =
+ __adjust_max_blocks_per_chunk(__opts.max_blocks_per_chunk);
+
+ __opts.largest_required_pool_block =
+ __adjust_largest_required_pool_block(__opts.largest_required_pool_block);
+
+ return __opts;
+}
+
+
+struct __single_linked_chunk_node {
+ __single_linked_chunk_node *__next_;
+ size_t __size_;
+ alignas(std::max_align_t) char __memory_[0];
+
+ static inline _LIBCPP_INLINE_VISIBILITY
+ void __push(__single_linked_chunk_node **__head_ptr,
+ __single_linked_chunk_node *__n) {
+ __n->__next_ = *__head_ptr;
+ *__head_ptr = __n;
+ }
+
+ static inline _LIBCPP_INLINE_VISIBILITY
+ void __remove(__single_linked_chunk_node **__head_ptr,
+ __single_linked_chunk_node *__n)
+ {
+ auto **__prev = __head_ptr;
+ auto *__idx = *__head_ptr;
+ while (__idx != __n) {
+ __prev = &__idx->__next_;
+ __idx = *__prev;
+ }
+ *__prev = __n->__next_;
+ __n->__next_ = nullptr;
+ }
+};
+
+
+struct __double_linked_chunk_node {
+ __double_linked_chunk_node *__next_;
+ __double_linked_chunk_node **__prev_next_addr_;
+ size_t __size_;
+ alignas(std::max_align_t) char __memory_[0];
+
+ static inline _LIBCPP_INLINE_VISIBILITY
+ void __push(__double_linked_chunk_node **__head_ptr,
+ __double_linked_chunk_node *__n) {
+ __n->__next_ = *__head_ptr;
+ __n->__prev_next_addr_ = __head_ptr;
+ if (*__head_ptr)
+ (*__head_ptr)->__prev_next_addr_ = &__n->__next_;
+ *__head_ptr = __n;
+ }
+
+ static inline _LIBCPP_INLINE_VISIBILITY
+ void __remove(__double_linked_chunk_node **,
+ __double_linked_chunk_node *__n) {
+ *(__n->__prev_next_addr_) = __n->__next_;
+ if (__n->__next_)
+ __n->__next_->__prev_next_addr_ = __n->__prev_next_addr_;
+ }
+};
+
+template <class _ChunkNode>
+class _LIBCPP_TYPE_VIS_ONLY __basic_chunk_allocator {
+ static_assert(is_standard_layout<_ChunkNode>::value,
+ "_ChunkNode must be standard layout");
+ static_assert(is_trivially_destructible<_ChunkNode>::value,
+ "_ChunkNode must be trivially destructible");
+
+ static inline _LIBCPP_INLINE_VISIBILITY
+ _ChunkNode *__memory_to_chunk(void *__p) _NOEXCEPT {
+ return static_cast<_ChunkNode *>(static_cast<void *>(
+ static_cast<char *>(__p) - offsetof(_ChunkNode, __memory_)));
+ }
+public:
+ _LIBCPP_INLINE_VISIBILITY
+ __basic_chunk_allocator() : __head_(nullptr) {}
+ __basic_chunk_allocator(__basic_chunk_allocator const &) = delete;
+ __basic_chunk_allocator &operator=(__basic_chunk_allocator const &) = delete;
+
+ _LIBCPP_INLINE_VISIBILITY
+ void *__allocate(memory_resource *__res, size_t __s) {
+ if (__s == 0)
+ __s = 1;
+ const size_t __alloc_size =
+ __aligned_allocation_size(sizeof(_ChunkNode) + __s);
+ return __insert_new_chunk(__res->allocate(__alloc_size, __max_align()),
+ __alloc_size);
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ void __deallocate(memory_resource *__res, void *__p) _NOEXCEPT {
+ if (!__p)
+ return;
+ _ChunkNode *const __n = __memory_to_chunk(__p);
+ _ChunkNode::__remove(&__head_, __n);
+ __res->deallocate(__n, __n->__size_, __max_align());
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ void __release(memory_resource *__res) _NOEXCEPT {
+ while (__head_) {
+ auto *__p = __head_;
+ __head_ = __head_->__next_;
+ __res->deallocate(__p, __p->__size_, __max_align());
+ }
+ }
+
+private:
+ _LIBCPP_INLINE_VISIBILITY
+ void *__insert_new_chunk(void *__p, size_t __s) _NOEXCEPT {
+ _ChunkNode *__n = ::new (__p) _ChunkNode;
+ __n->__size_ = __s;
+ _ChunkNode::__push(&__head_, __n);
+ return static_cast<void *>(&__n->__memory_);
+ }
+
+private:
+ _ChunkNode *__head_;
+};
+
+typedef __basic_chunk_allocator<__double_linked_chunk_node> __chunk_allocator;
+typedef __basic_chunk_allocator<__single_linked_chunk_node>
+ __single_linked_chunk_allocator;
+
+
+class _LIBCPP_TYPE_VIS_ONLY monotonic_buffer_resource : public memory_resource {
+ static constexpr size_t __min_buf_size = 512;
+
+public:
+ explicit monotonic_buffer_resource(memory_resource *__res)
+ : __buf_(nullptr), __left_(0), __next_buf_size_(__min_buf_size),
+ __res_(__res) { }
+
+ monotonic_buffer_resource(size_t __init_size, memory_resource *__res)
+ : __buf_(nullptr), __left_(0),
+ __next_buf_size_(__init_size), __res_(__res) {}
+
+ monotonic_buffer_resource(void *__buf, size_t __buf_size,
+ memory_resource *__res)
+ : __buf_(__buf), __left_(__buf_size), __next_buf_size_(__min_buf_size),
+ __res_(__res) {}
+
+ monotonic_buffer_resource()
+ : monotonic_buffer_resource(get_default_resource()) {}
+
+ explicit monotonic_buffer_resource(size_t __init_size)
+ : monotonic_buffer_resource(__init_size, get_default_resource()) {}
+
+ monotonic_buffer_resource(void *__buf, size_t __buf_size)
+ : monotonic_buffer_resource(__buf, __buf_size, get_default_resource()) {}
+
+ monotonic_buffer_resource(monotonic_buffer_resource const &) = delete;
+
+ _LIBCPP_FUNC_VIS
+ virtual ~monotonic_buffer_resource(); // KEY FUNCTION
+
+ monotonic_buffer_resource &
+ operator=(monotonic_buffer_resource const &) = delete;
+
+ _LIBCPP_INLINE_VISIBILITY
+ void release() {
+ __alloc_.__release(__res_);
+ __buf_ = nullptr;
+ __left_ = 0;
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ memory_resource *upstream_resource() const _NOEXCEPT { return __res_; }
+
+protected:
+ virtual void *do_allocate(size_t __bytes, size_t __align) {
+ if (void *__p = __take_from_buf(__bytes, __align))
+ return __p;
+ return __alloc_from_upstream(__bytes, __align);
+ }
+
+ virtual void do_deallocate(void *, size_t, size_t) { }
+
+ virtual bool do_is_equal(memory_resource const &__other) const _NOEXCEPT {
+ return this ==
+ dynamic_cast<monotonic_buffer_resource const *>(&__other);
+ }
+
+private:
+ _LIBCPP_INLINE_VISIBILITY
+ void *__take_from_buf(size_t __s, size_t __a) _NOEXCEPT {
+ void* __p = nullptr;
+ if (__buf_ && (__p = _VSTD::align(__a, __s, __buf_, __left_))) {
+ __buf_ = static_cast<void*>(static_cast<char*>(__p) + __s);
+ __left_ -= __s;
+ }
+ return __p;
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ void *__alloc_from_upstream(size_t __s, size_t __a) {
+ size_t __alloc_size = std::max<size_t>(
+ __aligned_allocation_size(__s, __a),
+ __next_buf_size_);
+ __increment_buf_size(__alloc_size);
+ __buf_ = __alloc_.__allocate(__res_, __alloc_size);
+ __left_ = __alloc_size;
+ return __take_from_buf(__s, __a);
+ }
+
+ _LIBCPP_INLINE_VISIBILITY
+ void __increment_buf_size(size_t __s) _NOEXCEPT {
+ size_t const __possible_next =
+ _VSTD::max(__round_up_pow_2(__s), __next_buf_size_ << 1);
+ __next_buf_size_ = _VSTD::max(__possible_next, __next_buf_size_);
+ }
+
+private:
+ void *__buf_;
+ size_t __left_;
+ size_t __next_buf_size_;
+ memory_resource *__res_;
+ __single_linked_chunk_allocator __alloc_;
+};
+
_LIBCPP_END_NAMESPACE_LFTS_PMR
#endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */
Index: include/experimental/__memory
===================================================================
--- include/experimental/__memory
+++ include/experimental/__memory
@@ -13,6 +13,7 @@
#include <experimental/__config>
#include <experimental/utility> // for erased_type
+#include <algorithm>
#include <__functional_base>
#include <type_traits>
@@ -85,6 +86,48 @@
);
}
+inline _LIBCPP_INLINE_VISIBILITY
+size_t __is_power2(size_t __bc)
+{
+ return __bc == 1 || __bc == 2 || (__bc && !(__bc & (__bc - 1)));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+size_t __next_pow2(size_t __n)
+{
+ return (__n < 2) ? __n + 1
+ : (size_t(1) << (std::numeric_limits<size_t>::digits - __clz(__n-1)));
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+size_t __round_up_pow_2(size_t __s) _NOEXCEPT
+{
+ return __is_power2(__s) ? __s : __next_pow2(__s);
+}
+
+inline _LIBCPP_INLINE_VISIBILITY
+constexpr size_t __max_align() _NOEXCEPT
+{
+ return alignment_of<max_align_t>::value;
+}
+
+// The alignment is 2 ^ (index of lowest set bit)
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+size_t __fundamental_alignment(size_t __s) _NOEXCEPT
+{
+ return (__s | __max_align())
+ & ~((__s | __max_align()) - 1);
+}
+
+// Round __s up to next multiple of __a.
+inline _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR
+size_t __aligned_allocation_size(size_t __s, size_t __a = __max_align()) _NOEXCEPT
+{
+ _LIBCPP_ASSERT(__s + __a > __s, "aligned allocation size overflows");
+ return (__s + __a - 1) & ~(__a - 1);
+}
+
+
_LIBCPP_END_NAMESPACE_LFTS
#endif /* _LIBCPP_EXPERIMENTAL___MEMORY */
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits