Index: include/experimental/memory_resource =================================================================== --- include/experimental/memory_resource +++ include/experimental/memory_resource @@ -420,6 +420,79 @@ typename allocator_traits<_Alloc>::template rebind_alloc >; +// 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 Index: src/experimental/memory_resource.cpp =================================================================== --- src/experimental/memory_resource.cpp +++ src/experimental/memory_resource.cpp @@ -160,4 +160,136 @@ 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(__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(new_ptr) + bytes; + } + return aligned_ptr; +} + +struct __monotonic_buffer_chunk_header { + __monotonic_buffer_chunk_header *__next_; + char *__start_; + char *__cur_; + // __end_ is always implicitly "(char*)this" + size_t __align_; + void *try_allocate_from_chunk(size_t bytes, size_t align); + size_t allocation_size(); + 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(__cur_); + size_t new_capacity = (reinterpret_cast(this) - __cur_); + void *aligned_ptr = _VSTD::align(align, bytes, new_ptr, new_capacity); + if (aligned_ptr != nullptr) { + __cur_ = static_cast(new_ptr) + bytes; + } + return aligned_ptr; +} + +size_t __monotonic_buffer_chunk_header::allocation_size() +{ + return (reinterpret_cast(this) - __start_) + sizeof(__monotonic_buffer_chunk_header); +} + +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) +{ + const size_t header_size = sizeof(__monotonic_buffer_chunk_header); + const size_t header_align = alignof(__monotonic_buffer_chunk_header); + + __initial_.__start_ = static_cast(buffer); + if (buffer != nullptr) { + __initial_.__cur_ = static_cast(buffer); + __initial_.__end_ = static_cast(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: 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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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: 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 + +// + +// monotonic_buffer_resource(monotonic_buffer_resource const&) = delete; +// monotonic_buffer_resource& operator=(monotonic_buffer_resource const&) = delete; + +#include +#include +#include + +int main() +{ + using MBR = std::experimental::pmr::monotonic_buffer_resource; + static_assert(!std::is_copy_constructible::value, ""); + static_assert(!std::is_move_constructible::value, ""); + static_assert(!std::is_copy_assignable::value, ""); + static_assert(!std::is_move_assignable::value, ""); +} 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 + +// + +// class monotonic_buffer_resource + +#include +#include + +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/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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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.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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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.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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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_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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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_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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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_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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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_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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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_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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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_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 + +// + +// class monotonic_buffer_resource + +#include +#include + +#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/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 + +// + +// class monotonic_buffer_resource + +#include +#include +#include +#include + +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/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() +{ +}