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