Quuxplusone updated this revision to Diff 151983.
Quuxplusone added a comment.
Minor cosmetic changes.
Repository:
rCXX libc++
https://reviews.llvm.org/D47111
Files:
include/experimental/memory_resource
src/experimental/memory_resource.cpp
test/libcxx/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_in_geometric_progression.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/with_default_resource.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/without_buffer.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_deallocate.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_exception_safety.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_initial_buffer.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_underaligned_buffer.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_zero_sized_buffer.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_in_geometric_progression.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_overaligned_request.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_with_initial_size.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/equality.pass.cpp
test/std/experimental/memory/memory.resource.monotonic.buffer/nothing_to_do.pass.cpp
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/nothing_to_do.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/nothing_to_do.pass.cpp
@@ -0,0 +1,13 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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.
+//
+//===----------------------------------------------------------------------===//
+
+int main()
+{
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/equality.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/equality.pass.cpp
@@ -0,0 +1,62 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <new>
+#include <type_traits>
+#include <cassert>
+
+struct assert_on_compare : public std::experimental::pmr::memory_resource
+{
+protected:
+ virtual void * do_allocate(size_t, size_t)
+ { assert(false); }
+
+ virtual void do_deallocate(void *, size_t, size_t)
+ { assert(false); }
+
+ virtual bool do_is_equal(std::experimental::pmr::memory_resource const &) const noexcept
+ { assert(false); }
+};
+
+int main()
+{
+ // Same object
+ {
+ std::experimental::pmr::monotonic_buffer_resource r1;
+ std::experimental::pmr::monotonic_buffer_resource r2;
+ assert(r1 == r1);
+ assert(r1 != r2);
+
+ std::experimental::pmr::memory_resource & p1 = r1;
+ std::experimental::pmr::memory_resource & p2 = r2;
+ assert(p1 == p1);
+ assert(p1 != p2);
+ assert(p1 == r1);
+ assert(r1 == p1);
+ assert(p1 != r2);
+ assert(r2 != p1);
+ }
+ // Different types
+ {
+ std::experimental::pmr::monotonic_buffer_resource mono1;
+ std::experimental::pmr::memory_resource & r1 = mono1;
+ assert_on_compare c;
+ std::experimental::pmr::memory_resource & r2 = c;
+ assert(r1 != r2);
+ assert(!(r1 == r2));
+ }
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_with_initial_size.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_with_initial_size.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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+void test(size_t initial_buffer_size)
+{
+ globalMemCounter.reset();
+
+ std::experimental::pmr::monotonic_buffer_resource mono1(
+ initial_buffer_size,
+ std::experimental::pmr::new_delete_resource()
+ );
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ mono1.allocate(1, 1);
+ assert(globalMemCounter.checkNewCalledEq(1));
+ assert(globalMemCounter.last_new_size >= initial_buffer_size);
+
+ mono1.allocate(initial_buffer_size - 1, 1);
+ assert(globalMemCounter.checkNewCalledEq(1));
+}
+
+int main()
+{
+ test(1);
+ test(8);
+ test(10);
+ test(100);
+ test(256);
+ test(1000);
+ test(1024);
+ test(1000000);
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_overaligned_request.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_overaligned_request.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ globalMemCounter.reset();
+ std::experimental::pmr::monotonic_buffer_resource mono1(1024, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = mono1;
+
+ constexpr size_t big_alignment = 8 * alignof(std::max_align_t);
+ static_assert(big_alignment > 4);
+
+ void *ret = r1.allocate(2048, big_alignment);
+ assert(ret != nullptr);
+ assert(globalMemCounter.checkNewCalledEq(1));
+ assert(globalMemCounter.last_new_size >= 2048);
+ // assert(globalMemCounter.last_new_align >= big_alignment);
+
+ // Check that a single highly aligned allocation request doesn't
+ // permanently "poison" the resource to allocate only super-aligned
+ // blocks of memory.
+ ret = r1.allocate(globalMemCounter.last_new_size, 4);
+ assert(ret != nullptr);
+ assert(globalMemCounter.checkNewCalledEq(2));
+ // assert(globalMemCounter.last_new_align >= 4);
+ // assert(globalMemCounter.last_new_align < big_alignment);
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_in_geometric_progression.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_in_geometric_progression.pass.cpp
@@ -0,0 +1,55 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+void test_geometric_progression()
+{
+ // mem.res.monotonic.buffer 1.3
+ // Each additional buffer is larger than the previous one, following a
+ // geometric progression.
+
+ globalMemCounter.reset();
+ std::experimental::pmr::monotonic_buffer_resource mono1(100, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = mono1;
+
+ assert(globalMemCounter.checkNewCalledEq(0));
+ size_t next_buffer_size = 100;
+ void *ret = r1.allocate(10, 1);
+ assert(ret != nullptr);
+ assert(globalMemCounter.checkNewCalledEq(1));
+ assert(globalMemCounter.last_new_size >= next_buffer_size);
+ next_buffer_size = globalMemCounter.last_new_size + 1;
+
+ int new_called = 1;
+ while (new_called < 5) {
+ ret = r1.allocate(10, 1);
+ if (globalMemCounter.new_called > new_called) {
+ assert(globalMemCounter.new_called == new_called + 1);
+ assert(globalMemCounter.last_new_size >= next_buffer_size);
+ next_buffer_size = globalMemCounter.last_new_size + 1;
+ new_called += 1;
+ }
+ }
+}
+
+int main()
+{
+ test_geometric_progression();
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_zero_sized_buffer.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_zero_sized_buffer.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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ globalMemCounter.reset();
+ {
+ char buffer[100];
+ std::experimental::pmr::monotonic_buffer_resource mono1((void *)buffer, 0, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = mono1;
+
+ void *ret = r1.allocate(1, 1);
+ assert(ret != nullptr);
+ assert(globalMemCounter.checkNewCalledEq(1));
+ }
+ assert(globalMemCounter.checkDeleteCalledEq(1));
+
+ globalMemCounter.reset();
+ {
+ std::experimental::pmr::monotonic_buffer_resource mono1(nullptr, 0, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = mono1;
+
+ void *ret = r1.allocate(1, 1);
+ assert(ret != nullptr);
+ assert(globalMemCounter.checkNewCalledEq(1));
+ }
+ assert(globalMemCounter.checkDeleteCalledEq(1));
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_underaligned_buffer.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_underaligned_buffer.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ globalMemCounter.reset();
+ {
+ alignas(4) char buffer[17];
+ std::experimental::pmr::monotonic_buffer_resource mono1(buffer + 1, 16, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = mono1;
+
+ void *ret = r1.allocate(1, 1);
+ assert(ret == buffer + 1);
+ mono1.release();
+
+ ret = r1.allocate(1, 2);
+ assert(ret == buffer + 2);
+ mono1.release();
+
+ ret = r1.allocate(1, 4);
+ assert(ret == buffer + 4);
+ mono1.release();
+
+ // Test a size that is just big enough to fit in the buffer,
+ // but can't fit if it's aligned.
+ ret = r1.allocate(16, 1);
+ assert(ret == buffer + 1);
+ mono1.release();
+
+ assert(globalMemCounter.checkNewCalledEq(0));
+ ret = r1.allocate(16, 2);
+ assert(globalMemCounter.checkNewCalledEq(1));
+ assert(globalMemCounter.last_new_size >= 16);
+ // assert(globalMemCounter.last_new_align >= 2);
+ mono1.release();
+ assert(globalMemCounter.checkDeleteCalledEq(1));
+ // assert(globalMemCounter.last_new_align == globalMemCounter.last_delete_align);
+ }
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_initial_buffer.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_from_initial_buffer.pass.cpp
@@ -0,0 +1,56 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ globalMemCounter.reset();
+ char buffer[100];
+ std::experimental::pmr::monotonic_buffer_resource mono1((void *)buffer, sizeof buffer, std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = mono1;
+
+ // Check that construction with a buffer does not allocate anything from the upstream
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ // Check that an allocation that fits in the buffer does not allocate anything from the upstream
+ void *ret = r1.allocate(50);
+ assert(ret);
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ // Check a second allocation
+ ret = r1.allocate(20);
+ assert(ret);
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ r1.deallocate(ret, 50);
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ // Check an allocation that doesn't fit in the original buffer
+ ret = r1.allocate(50);
+ assert(ret);
+ assert(globalMemCounter.checkNewCalledEq(1));
+
+ r1.deallocate(ret, 50);
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ mono1.release();
+ assert(globalMemCounter.checkDeleteCalledEq(1));
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_exception_safety.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_exception_safety.pass.cpp
@@ -0,0 +1,76 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+struct repointable_resource : public std::experimental::pmr::memory_resource
+{
+ std::experimental::pmr::memory_resource *which;
+
+ explicit repointable_resource(std::experimental::pmr::memory_resource *res) : which(res) {}
+
+protected:
+ virtual void *do_allocate(size_t size, size_t align)
+ { return which->allocate(size, align); }
+
+ virtual void do_deallocate(void *p, size_t size, size_t align)
+ { return which->deallocate(p, size, align); }
+
+ virtual bool do_is_equal(std::experimental::pmr::memory_resource const &rhs) const noexcept
+ { return which->is_equal(rhs); }
+};
+
+int main()
+{
+ globalMemCounter.reset();
+ repointable_resource upstream(std::experimental::pmr::new_delete_resource());
+ alignas(16) char buffer[64];
+ std::experimental::pmr::monotonic_buffer_resource mono1(buffer, sizeof buffer, &upstream);
+ std::experimental::pmr::memory_resource & r1 = mono1;
+
+ void *res = r1.allocate(64, 16);
+ assert(res == buffer);
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ res = r1.allocate(64, 16);
+ assert(res != buffer);
+ assert(globalMemCounter.checkNewCalledEq(1));
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+ const size_t last_new_size = globalMemCounter.last_new_size;
+
+ upstream.which = std::experimental::pmr::null_memory_resource();
+ try {
+ res = r1.allocate(last_new_size, 16);
+ assert(false);
+ } catch (const std::bad_alloc&) {
+ // we expect this
+ }
+ assert(globalMemCounter.checkNewCalledEq(1));
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ upstream.which = std::experimental::pmr::new_delete_resource();
+ res = r1.allocate(last_new_size, 16);
+ assert(res != buffer);
+ assert(globalMemCounter.checkNewCalledEq(2));
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ mono1.release();
+ assert(globalMemCounter.checkNewCalledEq(2));
+ assert(globalMemCounter.checkDeleteCalledEq(2));
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_deallocate.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_deallocate.pass.cpp
@@ -0,0 +1,57 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ {
+ globalMemCounter.reset();
+
+ std::experimental::pmr::monotonic_buffer_resource mono1(std::experimental::pmr::new_delete_resource());
+ std::experimental::pmr::memory_resource & r1 = mono1;
+
+ void *ret = r1.allocate(50);
+ assert(ret);
+ assert(globalMemCounter.checkNewCalledGreaterThan(0));
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ // mem.res.monotonic.buffer 1.2
+ // A call to deallocate has no effect, thus the amount of memory
+ // consumed increases monotonically until the resource is destroyed.
+ // Check that deallocate is a no-op
+ r1.deallocate(ret, 50);
+ assert(globalMemCounter.checkDeleteCalledEq(0));
+
+ mono1.release();
+ assert(globalMemCounter.checkDeleteCalledEq(1));
+ 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.checkDeleteCalledEq(1));
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/without_buffer.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/without_buffer.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.
+//
+//===----------------------------------------------------------------------===//
+
+// REQUIRES: c++experimental
+// UNSUPPORTED: c++98, c++03
+
+// <experimental/memory_resource>
+
+// class monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ // Constructing a monotonic_buffer_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());
+
+ std::experimental::pmr::monotonic_buffer_resource r1;
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ std::experimental::pmr::monotonic_buffer_resource r2(1024);
+ assert(globalMemCounter.checkNewCalledEq(0));
+
+ std::experimental::pmr::monotonic_buffer_resource r3(1024, std::experimental::pmr::new_delete_resource());
+ assert(globalMemCounter.checkNewCalledEq(0));
+}
Index: test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/with_default_resource.pass.cpp
===================================================================
--- /dev/null
+++ test/std/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.ctor/with_default_resource.pass.cpp
@@ -0,0 +1,45 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_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);
+ {
+ char buffer[16];
+ std::experimental::pmr::monotonic_buffer_resource r1;
+ std::experimental::pmr::monotonic_buffer_resource r2(16);
+ std::experimental::pmr::monotonic_buffer_resource r3(buffer, sizeof buffer);
+ assert(r1.upstream_resource() == expected);
+ assert(r2.upstream_resource() == expected);
+ assert(r3.upstream_resource() == expected);
+ }
+
+ expected = std::experimental::pmr::new_delete_resource();
+ std::experimental::pmr::set_default_resource(expected);
+ {
+ char buffer[16];
+ std::experimental::pmr::monotonic_buffer_resource r1;
+ std::experimental::pmr::monotonic_buffer_resource r2(16);
+ std::experimental::pmr::monotonic_buffer_resource r3(buffer, sizeof buffer);
+ assert(r1.upstream_resource() == expected);
+ assert(r2.upstream_resource() == expected);
+ assert(r3.upstream_resource() == expected);
+ }
+}
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,29 @@
+//===----------------------------------------------------------------------===//
+//
+// 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>
+
+// 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>
+
+int main()
+{
+ using MBR = std::experimental::pmr::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/libcxx/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_in_geometric_progression.pass.cpp
===================================================================
--- /dev/null
+++ test/libcxx/experimental/memory/memory.resource.monotonic.buffer/monotonic.buffer.mem/allocate_in_geometric_progression.pass.cpp
@@ -0,0 +1,33 @@
+//===----------------------------------------------------------------------===//
+//
+// 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 monotonic_buffer_resource
+
+#include <experimental/memory_resource>
+#include <cassert>
+
+#include "count_new.hpp"
+
+int main()
+{
+ globalMemCounter.reset();
+ std::experimental::pmr::monotonic_buffer_resource mono;
+
+ for (int i=0; i < 100; ++i) {
+ mono.allocate(1);
+ assert(globalMemCounter.last_new_size < 1000000000);
+ mono.release();
+ assert(globalMemCounter.checkOutstandingNewEq(0));
+ }
+}
Index: src/experimental/memory_resource.cpp
===================================================================
--- src/experimental/memory_resource.cpp
+++ src/experimental/memory_resource.cpp
@@ -160,4 +160,129 @@
return __default_memory_resource(true, __new_res);
}
+// 23.12.6, mem.res.monotonic.buffer
+
+static size_t roundup(size_t count, size_t alignment)
+{
+ size_t mask = alignment - 1;
+ return (count + mask) & ~mask;
+}
+
+void *__monotonic_buffer_initial_header::try_allocate_from_chunk(size_t bytes, size_t align)
+{
+ if (!__cur_)
+ return nullptr;
+ void *new_ptr = static_cast<void*>(__cur_);
+ size_t new_capacity = (__end_ - __cur_);
+ void *aligned_ptr = _VSTD::align(align, bytes, new_ptr, new_capacity);
+ if (aligned_ptr != nullptr) {
+ __cur_ = static_cast<char*>(new_ptr) + bytes;
+ }
+ return aligned_ptr;
+}
+
+struct __monotonic_buffer_chunk_header {
+ __monotonic_buffer_chunk_header *__next_;
+ char *__start_;
+ char *__cur_;
+ size_t __align_;
+ size_t allocation_size() {
+ return (reinterpret_cast<char*>(this) - __start_) + sizeof(*this);
+ }
+ void *try_allocate_from_chunk(size_t bytes, size_t align);
+ void deallocate_self(memory_resource *upstream);
+};
+
+void *__monotonic_buffer_chunk_header::try_allocate_from_chunk(size_t bytes, size_t align)
+{
+ void *new_ptr = static_cast<void*>(__cur_);
+ size_t new_capacity = (reinterpret_cast<char*>(this) - __cur_);
+ void *aligned_ptr = _VSTD::align(align, bytes, new_ptr, new_capacity);
+ if (aligned_ptr != nullptr) {
+ __cur_ = static_cast<char*>(new_ptr) + bytes;
+ }
+ return aligned_ptr;
+}
+
+void __monotonic_buffer_chunk_header::deallocate_self(memory_resource *upstream)
+{
+ upstream->deallocate(__start_, allocation_size(), __align_);
+}
+
+monotonic_buffer_resource::monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream)
+ : __res_(upstream)
+{
+ __initial_.__start_ = static_cast<char *>(buffer);
+ if (buffer != nullptr) {
+ __initial_.__cur_ = static_cast<char *>(buffer);
+ __initial_.__end_ = static_cast<char *>(buffer) + buffer_size;
+ } else {
+ __initial_.__cur_ = nullptr;
+ __initial_.__size_ = buffer_size;
+ }
+ __chunks_ = nullptr;
+}
+
+monotonic_buffer_resource::~monotonic_buffer_resource()
+{
+ release();
+}
+
+void monotonic_buffer_resource::release()
+{
+ __initial_.__cur_ = __initial_.__start_;
+ while (__chunks_ != nullptr) {
+ __monotonic_buffer_chunk_header *next = __chunks_->__next_;
+ __chunks_->deallocate_self(__res_);
+ __chunks_ = next;
+ }
+}
+
+void* monotonic_buffer_resource::do_allocate(size_t bytes, size_t align)
+{
+ if (void *result = __initial_.try_allocate_from_chunk(bytes, align))
+ return result;
+ if (__chunks_ != nullptr) {
+ if (void *result = __chunks_->try_allocate_from_chunk(bytes, align))
+ return result;
+ }
+
+ // Allocate a brand-new chunk.
+ const size_t header_size = sizeof(__monotonic_buffer_chunk_header);
+ const size_t header_align = alignof(__monotonic_buffer_chunk_header);
+
+ if (align < header_align)
+ align = header_align;
+
+ size_t aligned_capacity = roundup(bytes, header_align) + header_size;
+ size_t previous_capacity = __previous_allocation_size();
+
+ if (aligned_capacity <= previous_capacity)
+ aligned_capacity = roundup(2 * (previous_capacity - header_size), header_align) + header_size;
+
+ char *start = (char *)__res_->allocate(aligned_capacity, align);
+ __monotonic_buffer_chunk_header *header = (__monotonic_buffer_chunk_header *)(start + aligned_capacity - header_size);
+ header->__next_ = __chunks_;
+ header->__start_ = start;
+ header->__cur_ = start;
+ header->__align_ = align;
+ __chunks_ = header;
+
+ return __chunks_->try_allocate_from_chunk(bytes, align);
+}
+
+size_t monotonic_buffer_resource::__previous_allocation_size() const
+{
+ const size_t header_size = sizeof(__monotonic_buffer_chunk_header);
+ const size_t header_align = alignof(__monotonic_buffer_chunk_header);
+
+ if (__chunks_ != nullptr) {
+ return __chunks_->allocation_size();
+ } else if (__initial_.__start_ != nullptr) {
+ return roundup(__initial_.__end_ - __initial_.__start_, header_align) + header_size;
+ } else {
+ return roundup(__initial_.__size_, header_align) + header_size;
+ }
+}
+
_LIBCPP_END_NAMESPACE_LFTS_PMR
Index: include/experimental/memory_resource
===================================================================
--- include/experimental/memory_resource
+++ include/experimental/memory_resource
@@ -420,6 +420,79 @@
typename allocator_traits<_Alloc>::template rebind_alloc<char>
>;
+// 23.12.6, mem.res.monotonic.buffer
+
+struct __monotonic_buffer_chunk_header;
+
+struct __monotonic_buffer_initial_header {
+ char *__start_;
+ char *__cur_;
+ union {
+ char *__end_;
+ size_t __size_;
+ };
+ void *try_allocate_from_chunk(size_t, size_t);
+};
+
+class _LIBCPP_TYPE_VIS monotonic_buffer_resource : public memory_resource
+{
+ static const size_t __default_buffer_capacity = 1024;
+ static const size_t __default_buffer_alignment = 16;
+
+public:
+ _LIBCPP_INLINE_VISIBILITY
+ explicit monotonic_buffer_resource(memory_resource* __upstream)
+ : monotonic_buffer_resource(nullptr, __default_buffer_capacity, __upstream) {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ monotonic_buffer_resource(size_t __initial_size, memory_resource* __upstream)
+ : monotonic_buffer_resource(nullptr, __initial_size, __upstream) {}
+
+ monotonic_buffer_resource(void* __buffer, size_t __buffer_size, memory_resource* __upstream);
+
+ _LIBCPP_INLINE_VISIBILITY
+ monotonic_buffer_resource()
+ : monotonic_buffer_resource(get_default_resource()) {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ explicit monotonic_buffer_resource(size_t __initial_size)
+ : monotonic_buffer_resource(__initial_size, get_default_resource()) {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ monotonic_buffer_resource(void* __buffer, size_t __buffer_size)
+ : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource()) {}
+
+ monotonic_buffer_resource(const monotonic_buffer_resource&) = delete;
+
+ ~monotonic_buffer_resource() override; // key function
+
+ monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete;
+
+ void release();
+
+ _LIBCPP_INLINE_VISIBILITY
+ memory_resource* upstream_resource() const
+ { return __res_; }
+
+protected:
+ void* do_allocate(size_t __bytes, size_t __alignment) override;
+
+ _LIBCPP_INLINE_VISIBILITY
+ void do_deallocate(void*, size_t, size_t) override
+ {}
+
+ _LIBCPP_INLINE_VISIBILITY
+ bool do_is_equal(const memory_resource& __other) const _NOEXCEPT override
+ { return this == _VSTD::addressof(__other); }
+
+private:
+ size_t __previous_allocation_size() const;
+
+ __monotonic_buffer_initial_header __initial_;
+ __monotonic_buffer_chunk_header *__chunks_;
+ memory_resource* __res_;
+};
+
_LIBCPP_END_NAMESPACE_LFTS_PMR
_LIBCPP_POP_MACROS
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits