Index: include/experimental/memory_resource =================================================================== --- include/experimental/memory_resource +++ include/experimental/memory_resource @@ -97,7 +97,7 @@ // 8.5, memory.resource class _LIBCPP_TYPE_VIS memory_resource { - static const size_t __max_align = _LIBCPP_ALIGNOF(max_align_t); + static _LIBCPP_CONSTEXPR const size_t __max_align = _LIBCPP_ALIGNOF(max_align_t); // 8.5.2, memory.resource.public public: @@ -344,7 +344,7 @@ && is_same::value && is_same::value, ""); - static const size_t _MaxAlign = _LIBCPP_ALIGNOF(max_align_t); + static _LIBCPP_CONSTEXPR const size_t _MaxAlign = _LIBCPP_ALIGNOF(max_align_t); using _Alloc = typename _CTraits::template rebind_alloc< typename aligned_storage<_MaxAlign, _MaxAlign>::type @@ -419,6 +419,121 @@ typename allocator_traits<_Alloc>::template rebind_alloc >; +// 23.12.6, mem.res.monotonic.buffer + +class _LIBCPP_TYPE_VIS monotonic_buffer_resource : public memory_resource +{ + static _LIBCPP_CONSTEXPR const size_t __default_buffer_capacity = 1024; + static _LIBCPP_CONSTEXPR const size_t __default_buffer_alignment = 16; + + struct __chunk_header { + __chunk_header *__next_; + char *__start_; + char *__cur_; + size_t __align_; + size_t __allocation_size() { + return (reinterpret_cast(this) - __start_) + sizeof(*this); + } + void *__try_allocate_from_chunk(size_t, size_t); + }; + + struct __initial_header { + char *__start_; + char *__cur_; + union { + char *__end_; + size_t __size_; + }; + void *__try_allocate_from_chunk(size_t, size_t); + }; + +public: + _LIBCPP_INLINE_VISIBILITY + monotonic_buffer_resource() + : monotonic_buffer_resource( + nullptr, __default_buffer_capacity, get_default_resource()) {} + + _LIBCPP_INLINE_VISIBILITY + explicit monotonic_buffer_resource(size_t __initial_size) + : monotonic_buffer_resource( + nullptr, __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()) {} + + _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) {} + + _LIBCPP_INLINE_VISIBILITY + monotonic_buffer_resource(void *__buffer, size_t __buffer_size, + memory_resource *__upstream) + : __res_(__upstream) + { + __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(const monotonic_buffer_resource&) = delete; + + _LIBCPP_INLINE_VISIBILITY + ~monotonic_buffer_resource() override + { release(); } + + monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; + + _LIBCPP_INLINE_VISIBILITY + void release() + { + __initial_.__cur_ = __initial_.__start_; + while (__chunks_ != nullptr) { + __chunk_header *__next = __chunks_->__next_; + __res_->deallocate( + __chunks_->__start_, + __chunks_->__allocation_size(), + __chunks_->__align_ + ); + __chunks_ = __next; + } + } + + _LIBCPP_INLINE_VISIBILITY + memory_resource *upstream_resource() const _NOEXCEPT + { return __res_; } + +protected: + void *do_allocate(size_t __bytes, size_t __alignment) override; // key function + + _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: + __initial_header __initial_; + __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 @@ -158,4 +158,83 @@ 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_resource::__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; +} + +void *monotonic_buffer_resource::__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; +} + +void* monotonic_buffer_resource::do_allocate(size_t bytes, size_t align) +{ + const size_t header_size = sizeof(__chunk_header); + const size_t header_align = alignof(__chunk_header); + + auto previous_allocation_size = [&]() { + if (__chunks_ != nullptr) + return __chunks_->__allocation_size(); + + size_t newsize = (__initial_.__start_ != nullptr) ? + (__initial_.__end_ - __initial_.__start_) : __initial_.__size_; + + return roundup(newsize, header_align) + header_size; + }; + + 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. + + 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) { + size_t newsize = 2 * (previous_capacity - header_size); + aligned_capacity = roundup(newsize, header_align) + header_size; + } + + char *start = (char *)__res_->allocate(aligned_capacity, align); + __chunk_header *header = + (__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); +} + _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,35 @@ +//===----------------------------------------------------------------------===// +// +// 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.h" + +int main(int, char**) +{ + 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)); + } + + return 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,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. +// +//===----------------------------------------------------------------------===// + +// 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(int, char**) +{ + 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, ""); + + return 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,47 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: c++experimental +// UNSUPPORTED: c++98, c++03 + +// + +// class monotonic_buffer_resource + +#include +#include + +int main(int, char**) +{ + 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); + } + + return 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,41 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: c++experimental +// UNSUPPORTED: c++98, c++03 + +// + +// class monotonic_buffer_resource + +#include +#include + +#include "count_new.h" + +int main(int, char**) +{ + // 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)); + + return 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,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. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: c++experimental +// UNSUPPORTED: c++98, c++03 + +// + +// class monotonic_buffer_resource + +#include +#include + +#include "count_new.h" + +int main(int, char**) +{ + { + 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)); + + return 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,78 @@ +//===----------------------------------------------------------------------===// +// +// 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.h" + +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: + void *do_allocate(size_t size, size_t align) + { return which->allocate(size, align); } + + void do_deallocate(void *p, size_t size, size_t align) + { return which->deallocate(p, size, align); } + + bool do_is_equal(std::experimental::pmr::memory_resource const &rhs) const noexcept + { return which->is_equal(rhs); } +}; + +int main(int, char**) +{ + 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)); + + return 0; +} 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,58 @@ +//===----------------------------------------------------------------------===// +// +// 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.h" + +int main(int, char**) +{ + 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)); + + return 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,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. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: c++experimental +// UNSUPPORTED: c++98, c++03 + +// + +// class monotonic_buffer_resource + +#include +#include + +#include "count_new.h" + +int main(int, char**) +{ + 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); + } + + return 0; +} 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,48 @@ +//===----------------------------------------------------------------------===// +// +// 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.h" + +int main(int, char**) +{ + 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)); + + return 0; +} 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,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.h" + +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(int, char**) +{ + test_geometric_progression(); + return 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,49 @@ +//===----------------------------------------------------------------------===// +// +// 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.h" + +int main(int, char**) +{ +#ifndef TEST_HAS_NO_ALIGNED_ALLOCATION + + 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 * TEST_ALIGNOF(std::max_align_t); + + 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, sizeof(int)); + assert(ret != nullptr); + assert(globalMemCounter.checkNewCalledEq(2)); + assert(globalMemCounter.last_new_align < big_alignment); + +#endif + + return 0; +} 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,53 @@ +//===----------------------------------------------------------------------===// +// +// 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.h" + +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(int, char**) +{ + test(1); + test(8); + test(10); + test(100); + test(256); + test(1000); + test(1024); + test(1000000); + assert(globalMemCounter.checkOutstandingNewEq(0)); + + return 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,64 @@ +//===----------------------------------------------------------------------===// +// +// 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: + void *do_allocate(size_t, size_t) + { assert(false); } + + void do_deallocate(void *, size_t, size_t) + { assert(false); } + + bool do_is_equal(std::experimental::pmr::memory_resource const &) const noexcept + { assert(false); } +}; + +int main(int, char**) +{ + // 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)); + } + + return 0; +}