Index: include/exception =================================================================== --- include/exception +++ include/exception @@ -80,6 +80,10 @@ #include <__config> #include #include +#if defined(_LIBCPP_HAS_NO_EXCEPTIONS) +#include +#include +#endif #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header @@ -251,4 +255,19 @@ } // std +_LIBCPP_BEGIN_NAMESPACE_STD + +template +_LIBCPP_INLINE_VISIBILITY +inline void __libcpp_throw(_Exception const& __e) { +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw __e; +#else + _VSTD::fprintf(stderr, "%s\n", __what); + _VSTD::abort(); +#endif +} + +_LIBCPP_END_NAMESPACE_STD + #endif // _LIBCPP_EXCEPTION Index: include/experimental/__config =================================================================== --- include/experimental/__config +++ include/experimental/__config @@ -25,6 +25,10 @@ #define _LIBCPP_END_NAMESPACE_LFTS } } } #define _VSTD_LFTS _VSTD_EXPERIMENTAL::fundamentals_v1 +#define _LIBCPP_BEGIN_NAMESPACE_LFTS_PMR _LIBCPP_BEGIN_NAMESPACE_LFTS namespace pmr { +#define _LIBCPP_END_NAMESPACE_LFTS_PMR _LIBCPP_END_NAMESPACE_LFTS } +#define _VSTD_LFTS_PMR _VSTD_LFTS::pmr + #define _LIBCPP_BEGIN_NAMESPACE_CHRONO_LFTS _LIBCPP_BEGIN_NAMESPACE_STD \ namespace chrono { namespace experimental { inline namespace fundamentals_v1 { #define _LIBCPP_END_NAMESPACE_CHRONO_LFTS _LIBCPP_END_NAMESPACE_STD } } } Index: include/experimental/__memory =================================================================== --- /dev/null +++ include/experimental/__memory @@ -0,0 +1,90 @@ +// -*- 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. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_EXPERIMENTAL___MEMORY +#define _LIBCPP_EXPERIMENTAL___MEMORY + +#include +#include // for erased_type +#include <__functional_base> +#include + +_LIBCPP_BEGIN_NAMESPACE_LFTS + +template < + class _Tp, class _Alloc + , bool = uses_allocator<_Tp, _Alloc>::value + , bool = __has_allocator_type<_Tp>::value + > +struct __lfts_uses_allocator : public false_type {}; + +template +struct __lfts_uses_allocator<_Tp, _Alloc, false, false> : public false_type {}; + +template +struct __lfts_uses_allocator<_Tp, _Alloc, true, HasAlloc> : public true_type {}; + +template +struct __lfts_uses_allocator<_Tp, _Alloc, false, true> + : public integral_constant::value + || is_same::value + > +{}; + +template +struct __lfts_uses_alloc_ctor_imp +{ + static const int value = 0; +}; + +template +struct __lfts_uses_alloc_ctor_imp +{ + static const bool __ic_first + = is_constructible<_Tp, allocator_arg_t, _Alloc, _Args...>::value; + + static const bool __ic_second = + conditional< + __ic_first, + false_type, + is_constructible<_Tp, _Args..., _Alloc> + >::type::value; + + static_assert(__ic_first || __ic_second, + "Request for uses allocator construction is ill-formed"); + + static const int value = __ic_first ? 1 : 2; +}; + +template +struct __lfts_uses_alloc_ctor + : integral_constant::value + , _Tp, _Alloc, _Args... + >::value + > +{}; + +template +inline _LIBCPP_INLINE_VISIBILITY +void __lfts_user_alloc_construct( + _Tp * __store, const _Alloc & __a, _Args &&... __args) +{ + _VSTD::__user_alloc_construct_impl( + typename __lfts_uses_alloc_ctor<_Tp, _Alloc, _Args...>::type() + , __store, __a, _VSTD::forward<_Args>(__args)... + ); +} + +_LIBCPP_END_NAMESPACE_LFTS + +#endif /* _LIBCPP_EXPERIMENTAL___MEMORY */ Index: include/experimental/memory_resource =================================================================== --- /dev/null +++ include/experimental/memory_resource @@ -0,0 +1,422 @@ +// -*- C++ -*- +//===------------------------ memory_resource -----------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE +#define _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE + +/** + experimental/memory_resource synopsis + +// C++1y + +namespace std { +namespace experimental { +inline namespace fundamentals_v1 { +namespace pmr { + + class memory_resource; + + bool operator==(const memory_resource& a, + const memory_resource& b) noexcept; + bool operator!=(const memory_resource& a, + const memory_resource& b) noexcept; + + template class polymorphic_allocator; + + template + bool operator==(const polymorphic_allocator& a, + const polymorphic_allocator& b) noexcept; + template + bool operator!=(const polymorphic_allocator& a, + const polymorphic_allocator& b) noexcept; + + // The name resource_adaptor_imp is for exposition only. + template class resource_adaptor_imp; + + template + using resource_adaptor = resource_adaptor_imp< + allocator_traits::rebind_alloc>; + + // Global memory resources + memory_resource* new_delete_resource() noexcept; + memory_resource* null_memory_resource() noexcept; + + // The default memory resource + memory_resource* set_default_resource(memory_resource* r) noexcept; + memory_resource* get_default_resource() noexcept; + + // Standard memory resources + struct pool_options; + class synchronized_pool_resource; + class unsynchronized_pool_resource; + class monotonic_buffer_resource; + +} // namespace pmr +} // namespace fundamentals_v1 +} // namespace experimental +} // namespace std + + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include <__debug> + +#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) + { return do_allocate(__bytes, __align); } + + _LIBCPP_INLINE_VISIBILITY + void deallocate(void * __p, size_t __bytes, size_t __align = __max_align) + { do_deallocate(__p, __bytes, __align); } + + _LIBCPP_INLINE_VISIBILITY + bool is_equal(memory_resource const & __other) const _NOEXCEPT + { return do_is_equal(__other); } + +// 8.5.3, memory.resource.priv +protected: + virtual void* do_allocate(size_t, size_t) = 0; + virtual void do_deallocate(void*, size_t, size_t) = 0; + virtual bool do_is_equal(memory_resource const &) const _NOEXCEPT = 0; +}; + +// 8.5.4, memory.resource.eq +inline _LIBCPP_INLINE_VISIBILITY +bool operator==(memory_resource const & __lhs, + memory_resource const & __rhs) _NOEXCEPT +{ + return &__lhs == &__rhs || __lhs.is_equal(__rhs); +} + +inline _LIBCPP_INLINE_VISIBILITY +bool operator!=(memory_resource const & __lhs, + memory_resource const & __rhs) _NOEXCEPT +{ + return !(__lhs == __rhs); +} + +_LIBCPP_FUNC_VIS +memory_resource * new_delete_resource() _NOEXCEPT; + +_LIBCPP_FUNC_VIS +memory_resource * null_memory_resource() _NOEXCEPT; + +_LIBCPP_FUNC_VIS +memory_resource * get_default_resource() _NOEXCEPT; + +_LIBCPP_FUNC_VIS +memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT; + +// 8.6, memory.polymorphic.allocator.class + +// 8.6.1, memory.polymorphic.allocator.overview +template +class _LIBCPP_TYPE_VIS_ONLY polymorphic_allocator +{ +public: + typedef _ValueType value_type; + + // 8.6.2, memory.polymorphic.allocator.ctor + _LIBCPP_INLINE_VISIBILITY + polymorphic_allocator() _NOEXCEPT + : __res_(_VSTD_LFTS_PMR::get_default_resource()) + {} + + _LIBCPP_INLINE_VISIBILITY + polymorphic_allocator(memory_resource * __r) _NOEXCEPT + : __res_(__r) + {} + + polymorphic_allocator(polymorphic_allocator const &) = default; + + template + _LIBCPP_INLINE_VISIBILITY + polymorphic_allocator(polymorphic_allocator<_Tp> const & __other) _NOEXCEPT + : __res_(__other.resource()) + {} + + polymorphic_allocator & + operator=(polymorphic_allocator const &) = default; + + // 8.6.3, memory.polymorphic.allocator.mem + _LIBCPP_INLINE_VISIBILITY + _ValueType* allocate(size_t __n) { + if (__n > max_size()) { + __libcpp_throw(length_error( + "std::experimental::pmr::polymorphic_allocator::allocate(size_t n)" + " 'n' exceeds maximum supported size")); + } + return static_cast<_ValueType*>( + __res_->allocate(__n * sizeof(_ValueType), alignof(_ValueType)) + ); + } + + _LIBCPP_INLINE_VISIBILITY + void deallocate(_ValueType * __p, size_t __n) _NOEXCEPT { + _LIBCPP_ASSERT(__n <= max_size(), + "deallocate called for size which exceeds max_size()"); + __res_->deallocate(__p, __n * sizeof(_ValueType), alignof(_ValueType)); + } + + template + _LIBCPP_INLINE_VISIBILITY + void construct(_Tp* __p, _Ts &&... __args) + { + _VSTD_LFTS::__lfts_user_alloc_construct( + __p, resource(), _VSTD::forward<_Ts>(__args)... + ); + } + + template + _LIBCPP_INLINE_VISIBILITY + void construct(pair<_T1, _T2>* __p, piecewise_construct_t, + tuple<_Args1...> __x, tuple<_Args2...> __y) + { + ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct + , __transform_tuple( + typename __lfts_uses_alloc_ctor< + _T1, memory_resource*, _Args1... + >::type() + , _VSTD::move(__x) + , typename __make_tuple_indices::type{} + ) + , __transform_tuple( + typename __lfts_uses_alloc_ctor< + _T2, memory_resource*, _Args2... + >::type() + , _VSTD::move(__y) + , typename __make_tuple_indices::type{} + ) + ); + } + + template + _LIBCPP_INLINE_VISIBILITY + void construct(pair<_T1, _T2>* __p) { + construct(__p, piecewise_construct, tuple<>(), tuple<>()); + } + + template + _LIBCPP_INLINE_VISIBILITY + void construct(pair<_T1, _T2> * __p, _Up && __u, _Vp && __v) { + construct(__p, piecewise_construct + , _VSTD::forward_as_tuple(_VSTD::forward<_Up>(__u)) + , _VSTD::forward_as_tuple(_VSTD::forward<_Vp>(__v))); + } + + template + _LIBCPP_INLINE_VISIBILITY + void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> const & __pr) { + construct(__p, piecewise_construct + , _VSTD::forward_as_tuple(__pr.first) + , _VSTD::forward_as_tuple(__pr.second)); + } + + template + _LIBCPP_INLINE_VISIBILITY + void construct(pair<_T1, _T2> * __p, pair<_U1, _U2> && __pr){ + construct(__p, piecewise_construct + , _VSTD::forward_as_tuple(_VSTD::forward<_U1>(__pr.first)) + , _VSTD::forward_as_tuple(_VSTD::forward<_U2>(__pr.second))); + } + + template + _LIBCPP_INLINE_VISIBILITY + void destroy(_Tp * __p) _NOEXCEPT + { __p->~_Tp(); } + + _LIBCPP_INLINE_VISIBILITY + size_t max_size() const _NOEXCEPT + { return numeric_limits::max() / sizeof(value_type); } + + _LIBCPP_INLINE_VISIBILITY + polymorphic_allocator + select_on_container_copy_construction() const _NOEXCEPT + { return polymorphic_allocator(); } + + _LIBCPP_INLINE_VISIBILITY + memory_resource * resource() const _NOEXCEPT + { return __res_; } + +private: + template + _LIBCPP_INLINE_VISIBILITY + tuple<_Args&&...> + __transform_tuple(integral_constant, tuple<_Args...>&& __t, + __tuple_indices<_Idx...>) const + { + return _VSTD::forward_as_tuple(_VSTD::get<_Idx>(_VSTD::move(__t))...); + } + + template + _LIBCPP_INLINE_VISIBILITY + tuple + __transform_tuple(integral_constant, tuple<_Args...> && __t, + __tuple_indices<_Idx...>) const + { + using _Tup = tuple; + return _Tup(allocator_arg, resource(), + _VSTD::get<_Idx>(_VSTD::move(__t))...); + } + + template + _LIBCPP_INLINE_VISIBILITY + tuple<_Args&&..., memory_resource*> + __transform_tuple(integral_constant, tuple<_Args...> && __t, + __tuple_indices<_Idx...>) const + { + using _Tup = tuple<_Args&&..., memory_resource*>; + return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., resource()); + } + + memory_resource * __res_; +}; + +// 8.6.4, memory.polymorphic.allocator.eq + +template +inline _LIBCPP_INLINE_VISIBILITY +bool operator==(polymorphic_allocator<_Tp> const & __lhs, + polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT +{ + return *__lhs.resource() == *__rhs.resource(); +} + +template +inline _LIBCPP_INLINE_VISIBILITY +bool operator!=(polymorphic_allocator<_Tp> const & __lhs, + polymorphic_allocator<_Up> const & __rhs) _NOEXCEPT +{ + return !(__lhs == __rhs); +} + +// 8.7, memory.resource.adaptor + +// 8.7.1, memory.resource.adaptor.overview +template +class _LIBCPP_TYPE_VIS_ONLY __resource_adaptor_imp + : public memory_resource +{ + using _CTraits = allocator_traits<_CharAlloc>; + static_assert(is_same::value + && 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 + >; + + using _ValueType = typename _Alloc::value_type; + + _Alloc __alloc_; + +public: + typedef _CharAlloc allocator_type; + + __resource_adaptor_imp() = default; + __resource_adaptor_imp(__resource_adaptor_imp const &) = default; + __resource_adaptor_imp(__resource_adaptor_imp &&) = default; + + // 8.7.2, memory.resource.adaptor.ctor + + _LIBCPP_INLINE_VISIBILITY + explicit __resource_adaptor_imp(allocator_type const & __a) + : __alloc_(__a) + {} + + _LIBCPP_INLINE_VISIBILITY + explicit __resource_adaptor_imp(allocator_type && __a) + : __alloc_(_VSTD::move(__a)) + {} + + __resource_adaptor_imp & + operator=(__resource_adaptor_imp const &) = default; + + _LIBCPP_INLINE_VISIBILITY + allocator_type get_allocator() const + { return __alloc_; } + +// 8.7.3, memory.resource.adaptor.mem +protected: + virtual void * do_allocate(size_t __bytes, size_t) + { + if (__bytes > __max_size()) { + __libcpp_throw(length_error( + "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; + return __alloc_.allocate(__s); + } + + virtual void do_deallocate(void * __p, size_t __bytes, size_t) + { + _LIBCPP_ASSERT(__bytes <= __max_size(), + "do_deallocate called for size which exceeds the maximum allocation size"); + size_t __s = __aligned_allocation_size(__bytes, _MaxAlign) / _MaxAlign; + __alloc_.deallocate((_ValueType*)__p, __s); + } + + virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT { + __resource_adaptor_imp const * __p + = dynamic_cast<__resource_adaptor_imp const *>(&__other); + return __p ? __alloc_ == __p->__alloc_ : false; + } + +private: + _LIBCPP_INLINE_VISIBILITY + size_t __max_size() const _NOEXCEPT { + return numeric_limits::max() - _MaxAlign; + } +}; + +template +using resource_adaptor = __resource_adaptor_imp< + typename allocator_traits<_Alloc>::template rebind_alloc + >; + +_LIBCPP_END_NAMESPACE_LFTS_PMR + +#endif /* _LIBCPP_EXPERIMENTAL_MEMORY_RESOURCE */ Index: src/experimental/memory_resource.cpp =================================================================== --- /dev/null +++ src/experimental/memory_resource.cpp @@ -0,0 +1,129 @@ +//===------------------------ memory_resource.cpp -------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#include "experimental/memory_resource" + +#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER +#include "atomic" +#else +#include "mutex" +#endif + +_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR + +// memory_resource + +//memory_resource::~memory_resource() {} + +// new_delete_resource() + +class _LIBCPP_TYPE_VIS_ONLY __new_delete_memory_resource_imp + : public memory_resource +{ +public: + ~__new_delete_memory_resource_imp() = default; + +protected: + virtual void* do_allocate(size_t __size, size_t __align) + { return __allocate(__size); } + + virtual void do_deallocate(void * __p, size_t, size_t) + { __deallocate(__p); } + + virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT + { return &__other == this; } +}; + +// null_memory_resource() + +class _LIBCPP_TYPE_VIS_ONLY __null_memory_resource_imp + : public memory_resource +{ +public: + ~__null_memory_resource_imp() = default; + +protected: + virtual void* do_allocate(size_t, size_t) { +#ifndef _LIBCPP_HAS_NO_EXCEPTIONS + throw std::bad_alloc(); +#else + abort(); +#endif + } + virtual void do_deallocate(void *, size_t, size_t) {} + virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT + { return &__other == this; } +}; + +union ResourceInitHelper { + struct { + __new_delete_memory_resource_imp new_delete_res; + __null_memory_resource_imp null_res; + } resources; + char dummy; + _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {} + ~ResourceInitHelper() {} +}; +// When compiled in C++14 this initialization should be a constant expression. +// Only in C++11 is "init_priority" needed to ensure initialization order. +ResourceInitHelper res_init __attribute__((init_priority (101))); + +memory_resource * new_delete_resource() _NOEXCEPT { + return &res_init.resources.new_delete_res; +} + +memory_resource * null_memory_resource() _NOEXCEPT { + return &res_init.resources.null_res; +} + +// default_memory_resource() + +static memory_resource * +__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT +{ +#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER + static atomic __res = + ATOMIC_VAR_INIT(&res_init.resources.new_delete_res); + if (set) { + new_res = new_res ? new_res : new_delete_resource(); + // TODO: Can a weaker ordering be used? + return _VSTD::atomic_exchange_explicit( + &__res, new_res, memory_order::memory_order_acq_rel); + } + else { + return _VSTD::atomic_load_explicit( + &__res, memory_order::memory_order_acquire); + } +#else + static memory_resource * res = &res_init.resources.new_delete_res; + static mutex res_lock; + if (set) { + new_res = new_res ? new_res : new_delete_resource(); + lock_guard guard(res_lock); + memory_resource * old_res = res; + res = new_res; + return old_res; + } else { + lock_guard guard(res_lock); + return res; + } +#endif +} + +memory_resource * get_default_resource() _NOEXCEPT +{ + return __default_memory_resource(); +} + +memory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT +{ + return __default_memory_resource(true, __new_res); +} + +_LIBCPP_END_NAMESPACE_LFTS_PMR \ No newline at end of file Index: src/experimental/placeholder.cpp =================================================================== --- src/experimental/placeholder.cpp +++ /dev/null @@ -1,14 +0,0 @@ -//===--------------------------- TODO.cpp ---------------------------------===// -// -// 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. -// -//===----------------------------------------------------------------------===// - -#include "experimental/__config" - -_LIBCPP_BEGIN_NAMESPACE_LFTS - -_LIBCPP_END_NAMESPACE_LFTS Index: test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp @@ -0,0 +1,178 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::construct(pair*, piecewise_construct_t +// tuple x, tuple) + +// The stardard specifiers a tranformation to uses-allocator construction as +// follows: +// - If uses_allocator_v is false and +// is_constructible_v is true, then xprime is x. +// - Otherwise, if uses_allocator_v is true and +// is_constructible_v is true, +// then xprime is +// tuple_cat(make_tuple(allocator_arg, this->resource()), std::move(x)). +// - Otherwise, if uses_allocator_v is true and +// is_constructible_v is true, then xprime is +// tuple_cat(std::move(x), make_tuple(this->resource())). +// - Otherwise the program is ill formed. +// +// The use of "xprime = tuple_cat(..., std::move(x), ...)" causes all of the +// objects in 'x' to be copied into 'xprime'. If 'x' contains any types which +// are stored by value this causes an unessary copy to occur. To prevent this +// libc++ changes this call into +// "xprime = forward_as_tuple(..., std::get(std::move(x))..., ...)". +// 'xprime' contains references to the values in 'x' instead of copying them. + +// This test checks the number of copies incurred to the elements in +// 'tuple' and 'tuple'. + +#include +#include +#include +#include +#include +#include +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +template +struct TestHarness { + TestResource R; + ex::memory_resource * M = &R; + ex::polymorphic_allocator A = M; + bool constructed = false; + T * ptr; + + TestHarness() : ptr(A.allocate(1)) {} + + template + void construct(Args&&... args) { + A.construct(ptr, std::forward(args)...); + constructed = true; + } + + ~TestHarness() { + if (constructed) A.destroy(ptr); + A.deallocate(ptr, 1); + } +}; + +struct CountCopies { + int count; + CountCopies() : count(0) {} + CountCopies(CountCopies const& o) : count(o.count + 1) {} +}; + +struct CountCopiesAllocV1 { + typedef ex::memory_resource* allocator_type; + allocator_type alloc; + int count; + CountCopiesAllocV1() : alloc(nullptr), count(0) {} + CountCopiesAllocV1(std::allocator_arg_t, allocator_type const& a, + CountCopiesAllocV1 const& o) : alloc(a), count(o.count + 1) + {} + + CountCopiesAllocV1(CountCopiesAllocV1 const& o) : count(o.count + 1) {} +}; + + +struct CountCopiesAllocV2 { + typedef ex::memory_resource* allocator_type; + allocator_type alloc; + int count; + CountCopiesAllocV2() : alloc(nullptr), count(0) {} + CountCopiesAllocV2(CountCopiesAllocV2 const& o, allocator_type const& a) + : alloc(a), count(o.count + 1) + { } + + CountCopiesAllocV2(CountCopiesAllocV2 const& o) : count(o.count + 1) {} +}; + + +int main() +{ + using PMR = ex::memory_resource*; + using PMA = ex::polymorphic_allocator; + + { + using T = CountCopies; + using U = CountCopiesAllocV1; + using P = std::pair; + using TH = TestHarness

; + + std::tuple t1; + std::tuple t2; + + TestHarness

h; + h.construct(std::piecewise_construct, t1, t2); + P const& p = *h.ptr; + assert(p.first.count == 2); + assert(p.second.count == 2); + assert(p.second.alloc == h.M); + } + { + using T = CountCopiesAllocV1; + using U = CountCopiesAllocV2; + using P = std::pair; + using TH = TestHarness

; + + std::tuple t1; + std::tuple t2; + + TestHarness

h; + h.construct(std::piecewise_construct, std::move(t1), std::move(t2)); + P const& p = *h.ptr; + assert(p.first.count == 2); + assert(p.first.alloc == h.M); + assert(p.second.count == 2); + assert(p.second.alloc == h.M); + } + { + using T = CountCopiesAllocV2; + using U = CountCopiesAllocV1; + using P = std::pair; + using TH = TestHarness

; + + std::tuple t1; + std::tuple t2; + + TestHarness

h; + h.construct(std::piecewise_construct, std::move(t1), std::move(t2)); + P const& p = *h.ptr; + assert(p.first.count == 2); + assert(p.first.alloc == h.M); + assert(p.second.count == 2); + assert(p.second.alloc == h.M); + } + { + using T = CountCopiesAllocV2; + using U = CountCopies; + using P = std::pair; + using TH = TestHarness

; + + std::tuple t1; + std::tuple t2; + + TestHarness

h; + h.construct(std::piecewise_construct, t1, t2); + P const& p = *h.ptr; + assert(p.first.count == 2); + assert(p.first.alloc == h.M); + assert(p.second.count == 2); + } +} Index: test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/db_deallocate.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/db_deallocate.pass.cpp @@ -0,0 +1,42 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// T* polymorphic_allocator::deallocate(T*, size_t size) + +int AssertCount = 0; + +#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++) +#define _LIBCPP_DEBUG 0 +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + using Alloc = ex::polymorphic_allocator; + using Traits = std::allocator_traits; + NullResource R; + Alloc a(&R); + const std::size_t maxSize = Traits::max_size(a); + + a.deallocate(nullptr, maxSize); + assert(AssertCount == 0); + a.deallocate(nullptr, maxSize + 1); + assert(AssertCount == 1); +} Index: test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/max_size.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/max_size.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// EXTENSION +// std::size_t polymorphic_allocator::max_size() const noexcept + +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +template +std::size_t getMaxSize() { + using T = typename std::aligned_storage::type; + static_assert(sizeof(T) == S, "Required for test"); + return ex::polymorphic_allocator{}.max_size(); +} + +template +std::size_t getMaxSize() { + using T = typename std::aligned_storage::type; + static_assert(sizeof(T) == S, "Required for test"); + return ex::polymorphic_allocator{}.max_size(); +} + +int main() +{ + { + using Alloc = ex::polymorphic_allocator; + using Traits = std::allocator_traits; + const Alloc a; + static_assert(std::is_same::value, ""); + static_assert(noexcept(a.max_size()), ""); + } + { + constexpr std::size_t Max = std::numeric_limits::max(); + assert(getMaxSize<1>() == Max); + assert(getMaxSize<2>() == Max / 2); + assert(getMaxSize<4>() == Max / 4); + assert(getMaxSize<8>() == Max / 8); + assert(getMaxSize<16>() == Max / 16); + assert(getMaxSize<32>() == Max / 32); + assert(getMaxSize<64>() == Max / 64); + assert(getMaxSize<1024>() == Max / 1024); + + assert((getMaxSize<6, 2>() == Max / 6)); + assert((getMaxSize<12, 4>() == Max / 12)); + } +} Index: test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// T* polymorphic_allocator::deallocate(T*, size_t size) + +int AssertCount = 0; + +#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++) +#define _LIBCPP_DEBUG 0 +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + using Alloc = NullAllocator; + using R = ex::resource_adaptor; + AllocController P; + ex::resource_adaptor r(Alloc{P}); + ex::memory_resource & m1 = r; + + std::size_t maxSize = std::numeric_limits::max() + - alignof(std::max_align_t); + + m1.deallocate(nullptr, maxSize); + assert(AssertCount == 0); + m1.deallocate(nullptr, maxSize + 1); + assert(AssertCount >= 1); +} Index: test/libcxx/experimental/memory/memory.resource.global/global_memory_resource_lifetime.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/memory/memory.resource.global/global_memory_resource_lifetime.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 + +// + +// memory_resource * new_delete_resource() + +// The lifetime of the value returned by 'new_delete_resource()' should +// never end, even very late into program termination. This test constructs +// attempts to use 'new_delete_resource()' very late in program termination +// to detect lifetime issues. + +#include +#include +#include + +namespace ex = std::experimental::pmr; + +struct POSType { + ex::memory_resource* res = nullptr; + void* ptr = nullptr; + int n = 0; + POSType() {} + POSType(ex::memory_resource* r, void* p, int s) : res(r), ptr(p), n(s) {} + ~POSType() { + if (ptr) { + if (!res) res = ex::get_default_resource(); + res->deallocate(ptr, n); + } + } +}; + +void swap(POSType & L, POSType & R) { + std::swap(L.res, R.res); + std::swap(L.ptr, R.ptr); + std::swap(L.n, R.n); +} + +POSType constructed_before_resources; +POSType constructed_before_resources2; + +// Constructs resources +ex::memory_resource* resource = ex::get_default_resource(); + +POSType constructed_after_resources(resource, resource->allocate(1024), 1024); +POSType constructed_after_resources2(nullptr, resource->allocate(1024), 1024); + +int main() +{ + swap(constructed_after_resources, constructed_before_resources); + swap(constructed_before_resources2, constructed_after_resources2); +} Index: test/libcxx/experimental/memory/memory.resource.global/new_delete_resource_lifetime.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/memory/memory.resource.global/new_delete_resource_lifetime.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// memory_resource * new_delete_resource() + +// The lifetime of the value returned by 'new_delete_resource()' should +// never end, even very late into program termination. This test constructs +// attempts to use 'new_delete_resource()' very late in program termination +// to detect lifetime issues. + +#include +#include +#include + +namespace ex = std::experimental::pmr; + +struct POSType { + ex::memory_resource* res = nullptr; + void* ptr = nullptr; + int n = 0; + POSType() {res = ex::new_delete_resource(); ptr = res->allocate(42); n = 42; } + POSType(ex::memory_resource* r, void* p, int s) : res(r), ptr(p), n(s) {} + ~POSType() { if (ptr) res->deallocate(ptr, n); } +}; + +void swap(POSType & L, POSType & R) { + std::swap(L.res, R.res); + std::swap(L.ptr, R.ptr); + std::swap(L.n, R.n); +} + +POSType constructed_before_resources; + +// Constructs resources +ex::memory_resource* resource = ex::new_delete_resource(); + +POSType constructed_after_resources(resource, resource->allocate(1024), 1024); + +int main() +{ + swap(constructed_after_resources, constructed_before_resources); +} Index: test/libcxx/experimental/memory/memory.resource.synop/version.pass.cpp =================================================================== --- /dev/null +++ test/libcxx/experimental/memory/memory.resource.synop/version.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +#include + +#ifndef _LIBCPP_VERSION +#error _LIBCPP_VERSION not defined +#endif + +int main() +{ +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/assign.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/assign.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// polymorphic_allocator operator=(polymorphic_allocator const &) = delete + +#include +#include +#include + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef ex::polymorphic_allocator T; + static_assert(std::is_copy_assignable::value, ""); + static_assert(std::is_move_assignable::value, ""); +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/copy.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/copy.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// polymorphic_allocator::polymorphic_allocator(polymorphic_allocator const &); + +#include +#include +#include + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef ex::polymorphic_allocator A1; + { + static_assert( + std::is_copy_constructible::value, "" + ); + static_assert( + std::is_move_constructible::value, "" + ); + } + // copy + { + A1 const a((ex::memory_resource*)42); + A1 const a2(a); + assert(a.resource() == a2.resource()); + } + // move + { + A1 a((ex::memory_resource*)42); + A1 a2(std::move(a)); + assert(a.resource() == a2.resource()); + assert(a2.resource() == (ex::memory_resource*)42); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/default.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/default.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// polymorphic_allocator::polymorphic_allocator() noexcept + +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + { + static_assert( + std::is_nothrow_default_constructible>::value + , "Must me nothrow default constructible" + ); + } + { + // test that the allocator gets its resource from get_default_resource + TestResource R1(42); + ex::set_default_resource(&R1); + + typedef ex::polymorphic_allocator A; + A const a; + assert(a.resource() == &R1); + + ex::set_default_resource(nullptr); + A const a2; + assert(a.resource() == &R1); + assert(a2.resource() == ex::new_delete_resource()); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/memory_resource_convert.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/memory_resource_convert.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// polymorphic_allocator::polymorphic_allocator(memory_resource *) + +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + { + typedef ex::polymorphic_allocator A; + static_assert( + std::is_convertible::value + , "Must be convertible" + ); + static_assert( + std::is_convertible::value + , "Must be convertible" + ); + } + { + typedef ex::polymorphic_allocator A; + TestResource R; + A const a(&R); + assert(a.resource() == &R); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/other_alloc.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/other_alloc.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// template +// polymorphic_allocator::polymorphic_allocator(polymorphic_allocator const &); + + +#include +#include +#include + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef ex::polymorphic_allocator A1; + typedef ex::polymorphic_allocator A2; + { // Test that the conversion is implicit and noexcept. + static_assert( + std::is_convertible::value, "" + ); + static_assert( + std::is_convertible::value, "" + ); + static_assert( + std::is_nothrow_constructible::value, "" + ); + static_assert( + std::is_nothrow_constructible::value, "" + ); + } + // copy other type + { + A1 const a((ex::memory_resource*)42); + A2 const a2(a); + assert(a.resource() == a2.resource()); + assert(a2.resource() == (ex::memory_resource*)42); + } + { + A1 a((ex::memory_resource*)42); + A2 const a2(std::move(a)); + assert(a.resource() == a2.resource()); + assert(a2.resource() == (ex::memory_resource*)42); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/equal.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/equal.pass.cpp @@ -0,0 +1,133 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator; + +// template +// bool operator==( +// polymorphic_allocator const & +// , polymorphic_allocator const &) noexcept + +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef ex::polymorphic_allocator A1; + typedef ex::polymorphic_allocator A2; + // check return types + { + A1 const a1; + A2 const a2; + static_assert(std::is_same::value, ""); + static_assert(noexcept(a1 == a2), ""); + } + // equal same type (different resource) + { + TestResource d1(1); + TestResource d2(1); + A1 const a1(&d1); + A1 const a2(&d2); + + assert(a1 == a2); + assert(d1.checkIsEqualCalledEq(1)); + assert(d2.checkIsEqualCalledEq(0)); + + d1.reset(); + + assert(a2 == a1); + assert(d1.checkIsEqualCalledEq(0)); + assert(d2.checkIsEqualCalledEq(1)); + } + // equal same type (same resource) + { + TestResource d1; + A1 const a1(&d1); + A1 const a2(&d1); + + assert(a1 == a2); + assert(d1.checkIsEqualCalledEq(0)); + + assert(a2 == a1); + assert(d1.checkIsEqualCalledEq(0)); + } + // equal different type (different resource) + { + TestResource d1(42); + TestResource d2(42); + A1 const a1(&d1); + A2 const a2(&d2); + + assert(a1 == a2); + assert(d1.checkIsEqualCalledEq(1)); + assert(d2.checkIsEqualCalledEq(0)); + + assert(a2 == a1); + assert(d1.checkIsEqualCalledEq(1)); + assert(d2.checkIsEqualCalledEq(1)); + + } + // equal different type (same resource) + { + TestResource d1(42); + A1 const a1(&d1); + A2 const a2(&d1); + + assert(a1 == a2); + assert(d1.checkIsEqualCalledEq(0)); + + assert(a2 == a1); + assert(d1.checkIsEqualCalledEq(0)); + + } + // not equal same type + { + TestResource d1(1); + TestResource d2(2); + A1 const a1(&d1); + A1 const a2(&d2); + + assert(!(a1 == a2)); + assert(d1.checkIsEqualCalledEq(1)); + assert(d2.checkIsEqualCalledEq(0)); + + d1.reset(); + + assert(!(a2 == a1)); + assert(d1.checkIsEqualCalledEq(0)); + assert(d2.checkIsEqualCalledEq(1)); + + } + // not equal different types + { + TestResource d1; + TestResource1 d2; + A1 const a1(&d1); + A2 const a2(&d2); + + assert(!(a1 == a2)); + assert(d1.checkIsEqualCalledEq(1)); + assert(d2.checkIsEqualCalledEq(0)); + + d1.reset(); + + assert(!(a2 == a1)); + assert(d1.checkIsEqualCalledEq(0)); + assert(d2.checkIsEqualCalledEq(1)); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/not_equal.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/not_equal.pass.cpp @@ -0,0 +1,104 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator; + +// template +// bool operator!=( +// polymorphic_allocator const & +// , polymorphic_allocator const &) noexcept + +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef ex::polymorphic_allocator A1; + typedef ex::polymorphic_allocator A2; + // check return types + { + A1 const a1; + A2 const a2; + static_assert(std::is_same::value, ""); + static_assert(noexcept(a1 != a2), ""); + } + // not equal same type (different resource) + { + TestResource d1(1); + TestResource d2(2); + A1 const a1(&d1); + A1 const a2(&d2); + + assert(a1 != a2); + assert(d1.checkIsEqualCalledEq(1)); + assert(d2.checkIsEqualCalledEq(0)); + + d1.reset(); + + assert(a2 != a1); + assert(d1.checkIsEqualCalledEq(0)); + assert(d2.checkIsEqualCalledEq(1)); + } + // equal same type (same resource) + { + TestResource d1; + A1 const a1(&d1); + A1 const a2(&d1); + + assert(!(a1 != a2)); + assert(d1.checkIsEqualCalledEq(0)); + + assert(!(a2 != a1)); + assert(d1.checkIsEqualCalledEq(0)); + } + // equal same type + { + TestResource d1(1); + TestResource d2(1); + A1 const a1(&d1); + A1 const a2(&d2); + + assert(!(a1 != a2)); + assert(d1.checkIsEqualCalledEq(1)); + assert(d2.checkIsEqualCalledEq(0)); + + d1.reset(); + + assert(!(a2 != a1)); + assert(d1.checkIsEqualCalledEq(0)); + assert(d2.checkIsEqualCalledEq(1)); + + } + // not equal different types + { + TestResource d1; + TestResource1 d2; + A1 const a1(&d1); + A2 const a2(&d2); + + assert(a1 != a2); + assert(d1.checkIsEqualCalledEq(1)); + assert(d2.checkIsEqualCalledEq(0)); + + d1.reset(); + + assert(a2 != a1); + assert(d1.checkIsEqualCalledEq(0)); + assert(d2.checkIsEqualCalledEq(1)); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp @@ -0,0 +1,111 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// T* polymorphic_allocator::allocate(size_t n) + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +template +void testForSizeAndAlign() { + using T = typename std::aligned_storage::type; + TestResource R; + ex::polymorphic_allocator a(&R); + + for (int N = 1; N <= 5; ++N) { + auto ret = a.allocate(N); + assert(R.checkAlloc(ret, N * sizeof(T), alignof(T))); + + a.deallocate(ret, N); + R.reset(); + } +} + +#ifndef TEST_HAS_NO_EXCEPTIONS +template +void testAllocForSizeThrows() { + using T = typename std::aligned_storage::type; + using Alloc = ex::polymorphic_allocator; + using Traits = std::allocator_traits; + NullResource R; + Alloc a(&R); + + // Test that allocating exactly the max size does not throw. + size_t maxSize = Traits::max_size(a); + try { + a.allocate(maxSize); + } catch (...) { + assert(false); + } + + size_t sizeTypeMax = std::numeric_limits::max(); + if (maxSize != sizeTypeMax) + { + // Test that allocating size_t(~0) throws bad alloc. + try { + a.allocate(sizeTypeMax); + assert(false); + } catch (std::exception const&) { + } + + // Test that allocating even one more than the max size does throw. + size_t overSize = maxSize + 1; + try { + a.allocate(overSize); + assert(false); + } catch (std::exception const&) { + } + } +} +#endif // TEST_HAS_NO_EXCEPTIONS + +int main() +{ + { + ex::polymorphic_allocator a; + static_assert(std::is_same::value, ""); + static_assert(!noexcept(a.allocate(0)), ""); + } + { + constexpr std::size_t MA = alignof(std::max_align_t); + testForSizeAndAlign<1, 1>(); + testForSizeAndAlign<1, 2>(); + testForSizeAndAlign<1, MA>(); + testForSizeAndAlign<2, 2>(); + testForSizeAndAlign<73, alignof(void*)>(); + testForSizeAndAlign<73, MA>(); + testForSizeAndAlign<13, MA>(); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + testAllocForSizeThrows<1>(); + testAllocForSizeThrows<2>(); + testAllocForSizeThrows<4>(); + testAllocForSizeThrows<8>(); + testAllocForSizeThrows<16>(); + testAllocForSizeThrows<73>(); + testAllocForSizeThrows<13>(); + } +#endif +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::construct(pair*) + +#include +#include +#include +#include +#include +#include +#include "uses_alloc_types.hpp" + +namespace ex = std::experimental::pmr; + +int constructed = 0; + +struct default_constructible +{ + default_constructible() : x(42) { ++constructed; } + int x{0}; +}; + +int main() +{ + // pair as T() + { + typedef default_constructible T; + typedef std::pair P; + typedef ex::polymorphic_allocator A; + P * ptr = (P*)std::malloc(sizeof(P)); + A a; + a.construct(ptr); + assert(constructed == 2); + assert(ptr->first.x == 42); + assert(ptr->second.x == 42); + std::free(ptr); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp @@ -0,0 +1,111 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::construct(pair*, pair const&) + +#include +#include +#include +#include +#include +#include +#include "uses_alloc_types.hpp" + +namespace ex = std::experimental::pmr; + + +template +bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect, + std::pair const& p) +{ + using P = std::pair; + TestResource R; + ex::memory_resource * M = &R; + ex::polymorphic_allocator

A(M); + P * ptr = (P*)std::malloc(sizeof(P)); + P * ptr2 = (P*)std::malloc(sizeof(P)); + + // UNDER TEST // + A.construct(ptr, p); + + A.construct(ptr2, std::piecewise_construct, + std::forward_as_tuple(p.first), + std::forward_as_tuple(p.second)); + // ------- // + + bool tres = checkConstruct(ptr->first, TExpect, M) && + checkConstructionEquiv(ptr->first, ptr2->first); + + bool ures = checkConstruct(ptr->second, UExpect, M) && + checkConstructionEquiv(ptr->second, ptr2->second); + + A.destroy(ptr); + std::free(ptr); + A.destroy(ptr2); + std::free(ptr2); + return tres && ures; + +} + +template +void test_pmr_uses_allocator(std::pair const& p) +{ + { + using T = NotUsesAllocator; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, p))); + } + { + using T = UsesAllocatorV1; + using U = UsesAllocatorV2; + assert((doTest(UA_AllocArg, UA_AllocLast, p))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_AllocLast, UA_AllocArg, p))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_AllocArg, UA_None, p))); + } +} +template +struct Print; + +int main() +{ + using ERT = std::experimental::erased_type; + using PMR = ex::memory_resource*; + using PMA = ex::polymorphic_allocator; + { + int x = 42; + int y = 42; + const std::pair p(x, y); + test_pmr_uses_allocator(p); + test_pmr_uses_allocator(p); + test_pmr_uses_allocator(p); + } + { + int x = 42; + int y = 42; + const std::pair p(x, std::move(y)); + test_pmr_uses_allocator(p); + test_pmr_uses_allocator(p); + test_pmr_uses_allocator(p); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp @@ -0,0 +1,108 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::construct(pair*, pair &&) + +#include +#include +#include +#include +#include +#include +#include "uses_alloc_types.hpp" + +namespace ex = std::experimental::pmr; + + + +template +bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect, + std::pair&& p) +{ + using P = std::pair; + TestResource R; + ex::memory_resource * M = &R; + ex::polymorphic_allocator

A(M); + P * ptr = A.allocate(2); + P * ptr2 = ptr + 1; + + // UNDER TEST // + A.construct(ptr, std::move(p)); + + A.construct(ptr2, std::piecewise_construct, + std::forward_as_tuple(std::forward(p.first)), + std::forward_as_tuple(std::forward(p.second))); + // ------- // + + bool tres = checkConstruct(ptr->first, TExpect, M) && + checkConstructionEquiv(ptr->first, ptr2->first); + + bool ures = checkConstruct(ptr->second, UExpect, M) && + checkConstructionEquiv(ptr->second, ptr2->second); + + A.destroy(ptr); + A.destroy(ptr2); + A.deallocate(ptr, 2); + return tres && ures; +} + +template +void test_pmr_uses_allocator(std::pair&& p) +{ + { + using T = NotUsesAllocator; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, std::move(p)))); + } + { + using T = UsesAllocatorV1; + using U = UsesAllocatorV2; + assert((doTest(UA_AllocArg, UA_AllocLast, std::move(p)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_AllocLast, UA_AllocArg, std::move(p)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_AllocArg, UA_None, std::move(p)))); + } +} + +int main() +{ + using ERT = std::experimental::erased_type; + using PMR = ex::memory_resource*; + using PMA = ex::polymorphic_allocator; + { + int x = 42; + int y = 42; + std::pair p(x, std::move(y)); + test_pmr_uses_allocator(std::move(p)); + test_pmr_uses_allocator(std::move(p)); + test_pmr_uses_allocator(std::move(p)); + } + { + int x = 42; + int y = 42; + std::pair p(std::move(x), y); + test_pmr_uses_allocator(std::move(p)); + test_pmr_uses_allocator(std::move(p)); + test_pmr_uses_allocator(std::move(p)); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp @@ -0,0 +1,109 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::construct(pair*, U1&&, U2&&) + +#include +#include +#include +#include +#include +#include +#include "uses_alloc_types.hpp" + +namespace ex = std::experimental::pmr; + + +template +bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect, + TT&& t, UU&& u) +{ + using P = std::pair; + TestResource R; + ex::memory_resource * M = &R; + ex::polymorphic_allocator

A(M); + P * ptr = (P*)std::malloc(sizeof(P)); + P * ptr2 = (P*)std::malloc(sizeof(P)); + + // UNDER TEST // + A.construct(ptr, std::forward(t), std::forward(u)); + A.construct(ptr2, std::piecewise_construct, + std::forward_as_tuple(std::forward(t)), + std::forward_as_tuple(std::forward(u))); + // ------- // + + bool tres = checkConstruct(ptr->first, TExpect, M) && + checkConstructionEquiv(ptr->first, ptr2->first); + + bool ures = checkConstruct(ptr->second, UExpect, M) && + checkConstructionEquiv(ptr->second, ptr2->second); + + A.destroy(ptr); + A.destroy(ptr2); + std::free(ptr); + std::free(ptr2); + return tres && ures; +} + +template +void test_pmr_uses_allocator(TT&& t, UU&& u) +{ + { + using T = NotUsesAllocator; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, + std::forward(t), std::forward(u)))); + } + { + using T = UsesAllocatorV1; + using U = UsesAllocatorV2; + assert((doTest(UA_AllocArg, UA_AllocLast, + std::forward(t), std::forward(u)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_AllocLast, UA_AllocArg, + std::forward(t), std::forward(u)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_AllocArg, UA_None, + std::forward(t), std::forward(u)))); + } +} + +int main() +{ + using ERT = std::experimental::erased_type; + using PMR = ex::memory_resource*; + using PMA = ex::polymorphic_allocator; + { + int x = 42; + int y = 42; + test_pmr_uses_allocator(x, std::move(y)); + test_pmr_uses_allocator(x, std::move(y)); + test_pmr_uses_allocator(x, std::move(y)); + } + { + int x = 42; + const int y = 42; + test_pmr_uses_allocator(std::move(x), y); + test_pmr_uses_allocator(std::move(x), y); + test_pmr_uses_allocator(std::move(x), y); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp @@ -0,0 +1,129 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::construct(pair*, piecewise_construct_t +// tuple, tuple) + +#include +#include +#include +#include +#include +#include +#include "uses_alloc_types.hpp" +#include "test_allocator.h" + +namespace ex = std::experimental::pmr; + +template +bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect, + std::tuple ttuple, std::tuple utuple) +{ + using P = std::pair; + TestResource R; + ex::memory_resource * M = &R; + ex::polymorphic_allocator

A(M); + P * ptr = A.allocate(1); + + // UNDER TEST // + A.construct(ptr, std::piecewise_construct, std::move(ttuple), std::move(utuple)); + // ------- // + bool tres = checkConstruct(ptr->first, TExpect, M); + bool ures = checkConstruct(ptr->second, UExpect, M); + + A.destroy(ptr); + A.deallocate(ptr, 1); + return tres && ures; +} + +template +void test_pmr_uses_allocator(std::tuple ttuple, std::tuple utuple) +{ + { + using T = NotUsesAllocator; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, + std::move(ttuple), std::move(utuple)))); + } + { + using T = UsesAllocatorV1; + using U = UsesAllocatorV2; + assert((doTest(UA_AllocArg, UA_AllocLast, + std::move(ttuple), std::move(utuple)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_AllocLast, UA_AllocArg, + std::move(ttuple), std::move(utuple)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_AllocArg, UA_None, + std::move(ttuple), std::move(utuple)))); + } +} + +int main() +{ + using ERT = std::experimental::erased_type; + using PMR = ex::memory_resource*; + using PMA = ex::polymorphic_allocator; + { + std::tuple<> t1; + test_pmr_uses_allocator(t1, t1); + test_pmr_uses_allocator(t1, t1); + test_pmr_uses_allocator(t1, t1); + } + { + std::tuple t1(42); + std::tuple<> t2; + test_pmr_uses_allocator(t1, t2); + test_pmr_uses_allocator(t2, t1); + test_pmr_uses_allocator(t1, t2); + test_pmr_uses_allocator(t2, t1); + test_pmr_uses_allocator(t1, t2); + test_pmr_uses_allocator(t2, t1); + } + { + std::tuple t1(42); + int x = 55; + double dx = 42.42; + std::tuple t2(x, std::move(dx)); + test_pmr_uses_allocator( t1, std::move(t2)); + test_pmr_uses_allocator(std::move(t2), t1); + test_pmr_uses_allocator( t1, std::move(t2)); + test_pmr_uses_allocator(std::move(t2), t1); + test_pmr_uses_allocator( t1, std::move(t2)); + test_pmr_uses_allocator(std::move(t2), t1); + } + { + void* xptr = nullptr; + long y = 4242; + std::tuple t1(42, y, xptr); + int x = 55; + double dx = 42.42; + const char* s = "hello World"; + std::tuple t2(x, std::move(dx), s); + test_pmr_uses_allocator( t1, std::move(t2)); + test_pmr_uses_allocator(std::move(t2), t1); + test_pmr_uses_allocator( t1, std::move(t2)); + test_pmr_uses_allocator(std::move(t2), t1); + test_pmr_uses_allocator( t1, std::move(t2)); + test_pmr_uses_allocator(std::move(t2), t1); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp @@ -0,0 +1,189 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::construct(U *, Args &&...) + +#include +#include +#include +#include +#include "uses_alloc_types.hpp" +#include "test_allocator.h" + +namespace ex = std::experimental::pmr; + +template +struct PMATest { + TestResource R; + ex::polymorphic_allocator A; + T* ptr; + bool constructed; + + PMATest() : A(&R), ptr(A.allocate(1)), constructed(false) {} + + template + void construct(Args&&... args) { + A.construct(ptr, std::forward(args)...); + constructed = true; + } + + ~PMATest() { + if (constructed) A.destroy(ptr); + A.deallocate(ptr, 1); + } +}; + +template +bool doTest(UsesAllocatorType UAExpect, Args&&... args) +{ + PMATest TH; + // UNDER TEST // + TH.construct(std::forward(args)...); + return checkConstruct(*TH.ptr, UAExpect, &TH.R); + // ------- // +} + + +template +bool doTestUsesAllocV0(Args&&... args) +{ + PMATest TH; + // UNDER TEST // + TH.construct(std::forward(args)...); + return checkConstruct(*TH.ptr, UA_None); + // -------- // +} + + +template +bool doTestUsesAllocV1(EAlloc const& ealloc, Args&&... args) +{ + PMATest TH; + // UNDER TEST // + TH.construct(std::allocator_arg, ealloc, std::forward(args)...); + return checkConstruct(*TH.ptr, UA_AllocArg, ealloc); + // -------- // +} + +template +bool doTestUsesAllocV2(EAlloc const& ealloc, Args&&... args) +{ + PMATest TH; + // UNDER TEST // + TH.construct(std::forward(args)..., ealloc); + return checkConstruct(*TH.ptr, UA_AllocLast, ealloc); + // -------- // +} + +template +void test_pmr_uses_alloc(Args&&... args) +{ + TestResource R(12435); + ex::memory_resource* M = &R; + { + // NotUsesAllocator provides valid signatures for each uses-allocator + // construction but does not supply the required allocator_type typedef. + // Test that we can call these constructors manually without + // polymorphic_allocator interfering. + using T = NotUsesAllocator; + assert(doTestUsesAllocV0(std::forward(args)...)); + assert((doTestUsesAllocV1(M, std::forward(args)...))); + assert((doTestUsesAllocV2(M, std::forward(args)...))); + } + { + // Test T(std::allocator_arg_t, Alloc const&, Args...) construction + using T = UsesAllocatorV1; + assert((doTest(UA_AllocArg, std::forward(args)...))); + } + { + // Test T(Args..., Alloc const&) construction + using T = UsesAllocatorV2; + assert((doTest(UA_AllocLast, std::forward(args)...))); + } + { + // Test that T(std::allocator_arg_t, Alloc const&, Args...) construction + // is prefered when T(Args..., Alloc const&) is also available. + using T = UsesAllocatorV3; + assert((doTest(UA_AllocArg, std::forward(args)...))); + } +} + +// Test that polymorphic_allocator does not prevent us from manually +// doing non-pmr uses-allocator construction. +template +void test_non_pmr_uses_alloc(AllocObj const& A, Args&&... args) +{ + { + using T = NotUsesAllocator; + assert(doTestUsesAllocV0(std::forward(args)...)); + assert((doTestUsesAllocV1(A, std::forward(args)...))); + assert((doTestUsesAllocV2(A, std::forward(args)...))); + } + { + using T = UsesAllocatorV1; + assert(doTestUsesAllocV0(std::forward(args)...)); + assert((doTestUsesAllocV1(A, std::forward(args)...))); + } + { + using T = UsesAllocatorV2; + assert(doTestUsesAllocV0(std::forward(args)...)); + assert((doTestUsesAllocV2(A, std::forward(args)...))); + } + { + using T = UsesAllocatorV3; + assert(doTestUsesAllocV0(std::forward(args)...)); + assert((doTestUsesAllocV1(A, std::forward(args)...))); + assert((doTestUsesAllocV2(A, std::forward(args)...))); + } +} + +int main() +{ + using ET = std::experimental::erased_type; + using PMR = ex::memory_resource*; + using PMA = ex::polymorphic_allocator; + using STDA = std::allocator; + using TESTA = test_allocator; + + int value = 42; + const int cvalue = 43; + { + test_pmr_uses_alloc(); + test_pmr_uses_alloc(); + test_pmr_uses_alloc(); + test_pmr_uses_alloc(value); + test_pmr_uses_alloc(value); + test_pmr_uses_alloc(value); + test_pmr_uses_alloc(cvalue); + test_pmr_uses_alloc(cvalue); + test_pmr_uses_alloc(cvalue); + test_pmr_uses_alloc(cvalue, std::move(value)); + test_pmr_uses_alloc(cvalue, std::move(value)); + test_pmr_uses_alloc(cvalue, std::move(value)); + } + { + STDA std_alloc; + TESTA test_alloc(42); + test_non_pmr_uses_alloc(std_alloc); + test_non_pmr_uses_alloc(test_alloc); + test_non_pmr_uses_alloc(std_alloc, value); + test_non_pmr_uses_alloc(test_alloc, value); + test_non_pmr_uses_alloc(std_alloc, cvalue); + test_non_pmr_uses_alloc(test_alloc, cvalue); + test_non_pmr_uses_alloc(std_alloc, cvalue, std::move(value)); + test_non_pmr_uses_alloc(test_alloc, cvalue, std::move(value)); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/deallocate.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/deallocate.pass.cpp @@ -0,0 +1,61 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// T* polymorphic_allocator::deallocate(T*, size_t size) + +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +template +void testForSizeAndAlign() { + using T = typename std::aligned_storage::type; + + TestResource R; + ex::polymorphic_allocator a(&R); + + for (int N = 1; N <= 5; ++N) { + auto ret = a.allocate(N); + assert(R.checkAlloc(ret, N * sizeof(T), alignof(T))); + + a.deallocate(ret, N); + assert(R.checkDealloc(ret, N * sizeof(T), alignof(T))); + + R.reset(); + } +} + +int main() +{ + { + ex::polymorphic_allocator a; + static_assert( + std::is_same::value, ""); + } + { + constexpr std::size_t MA = alignof(std::max_align_t); + testForSizeAndAlign<1, 1>(); + testForSizeAndAlign<1, 2>(); + testForSizeAndAlign<1, MA>(); + testForSizeAndAlign<2, 2>(); + testForSizeAndAlign<73, alignof(void*)>(); + testForSizeAndAlign<73, MA>(); + testForSizeAndAlign<13, MA>(); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/destroy.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/destroy.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 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::destroy(U * ptr); + +#include +#include +#include +#include +#include + +namespace ex = std::experimental::pmr; + +int count = 0; + +struct destroyable +{ + destroyable() { ++count; } + ~destroyable() { --count; } +}; + +int main() +{ + typedef ex::polymorphic_allocator A; + { + A a; + static_assert( + std::is_same::value, + ""); + } + { + destroyable * ptr = ::new (std::malloc(sizeof(destroyable))) destroyable(); + assert(count == 1); + A{}.destroy(ptr); + assert(count == 0); + std::free(ptr); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/resource.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/resource.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// memory_resource * +// polymorphic_allocator::resource() const + +#include +#include +#include + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef ex::polymorphic_allocator A; + { + A const a; + static_assert( + std::is_same::value + , "" + ); + } + { + ex::memory_resource * mptr = (ex::memory_resource*)42; + A const a(mptr); + assert(a.resource() == mptr); + } + { + A const a(nullptr); + assert(a.resource() == nullptr); + assert(a.resource() == nullptr); + } + { + A const a; + assert(a.resource() == ex::get_default_resource()); + } + { + ex::memory_resource * mptr = (ex::memory_resource*)42; + ex::set_default_resource(mptr); + A const a; + assert(a.resource() == mptr); + assert(a.resource() == ex::get_default_resource()); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/select_on_container_copy_construction.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/select_on_container_copy_construction.pass.cpp @@ -0,0 +1,52 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class polymorphic_allocator + +// polymorphic_allocator +// polymorphic_allocator::select_on_container_copy_construction() const + +#include +#include +#include + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef ex::polymorphic_allocator A; + { + A const a; + static_assert( + std::is_same::value, + ""); + } + { + ex::memory_resource * mptr = (ex::memory_resource*)42; + A const a(mptr); + assert(a.resource() == mptr); + A const other = a.select_on_container_copy_construction(); + assert(other.resource() == ex::get_default_resource()); + assert(a.resource() == mptr); + } + { + ex::memory_resource * mptr = (ex::memory_resource*)42; + ex::set_default_resource(mptr); + A const a(nullptr); + assert(a.resource() == nullptr); + A const other = a.select_on_container_copy_construction(); + assert(other.resource() == ex::get_default_resource()); + assert(other.resource() == mptr); + assert(a.resource() == nullptr); + } +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.overview/nothing_to_do.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.overview/nothing_to_do.pass.cpp @@ -0,0 +1,10 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main () {} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/nothing_to_do.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/nothing_to_do.pass.cpp @@ -0,0 +1,10 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main () {} Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_copy.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_copy.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class resource_adaptor_imp; + +// resource_adaptor_imp::resource_adaptor_imp(Alloc const &) + +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef CountingAllocator AllocT; + typedef ex::resource_adaptor R; + { + AllocController P; + AllocT const a(P); + R const r(a); + assert(P.copy_constructed == 1); + assert(P.move_constructed == 0); + assert(r.get_allocator() == a); + } + { + AllocController P; + AllocT a(P); + R const r(a); + assert(P.copy_constructed == 1); + assert(P.move_constructed == 0); + assert(r.get_allocator() == a); + } + { + AllocController P; + AllocT const a(P); + R const r(std::move(a)); + assert(P.copy_constructed == 1); + assert(P.move_constructed == 0); + assert(r.get_allocator() == a); + } +} Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_move.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_move.pass.cpp @@ -0,0 +1,44 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class resource_adaptor_imp; + +// resource_adaptor_imp::resource_adaptor_imp(Alloc &&) + +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef CountingAllocator AllocT; + typedef ex::resource_adaptor R; + { + AllocController P; + AllocT a(P); + R const r(std::move(a)); + assert(P.copy_constructed == 0); + assert(P.move_constructed == 1); + assert(r.get_allocator() == a); + } + { + AllocController P; + R const r(AllocT{P}); + assert(P.copy_constructed == 0); + assert(P.move_constructed == 1); + assert(r.get_allocator() == AllocT{P}); + } +} Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/default.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/default.pass.cpp @@ -0,0 +1,40 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class resource_adaptor_imp; + +// resource_adaptor_imp::resource_adaptor_imp() = default; + +#include +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + { + typedef CountingAllocator AllocT; // Not default constructible + typedef ex::resource_adaptor R; + static_assert(!std::is_default_constructible::value, ""); + } + { + typedef std::allocator AllocT; // Is default constructible + typedef ex::resource_adaptor R; + static_assert(std::is_default_constructible::value, ""); + R r; ((void)r); + } +} Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp @@ -0,0 +1,115 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class resource_adaptor_imp; + +// void * do_allocate(size_t size, size_t align) +// void do_deallocate(void*, size_t, size_t) + + +#include +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +template +void check_allocate_deallocate() +{ + typedef ex::resource_adaptor R1; + const std::size_t max_align = alignof(std::max_align_t); + + for (std::size_t s = 0; s < 5012; ++s) + { + for(std::size_t align_req = 1; align_req <= (max_align * 2); align_req *= 2) + { + const std::size_t align_exp = align_req > max_align + ? max_align : align_req; + AllocController P; + R1 r{Alloc(P)}; + ex::memory_resource & m1 = r; + + void * const ret = m1.allocate(s, align_req); + assert(P.alive == 1); + assert(P.alloc_count == 1); + assert(P.checkAllocAtLeast(ret, s, align_exp)); + + assert(((std::size_t)ret % align_exp) == 0); + + m1.deallocate(ret, s, align_req); + assert(P.alive == 0); + assert(P.dealloc_count == 1); + assert(P.checkDeallocMatchesAlloc()); + } + } +} + +void check_alloc_max_size() { + using Alloc = NullAllocator; + using R1 = ex::resource_adaptor; + const std::size_t max_align = alignof(std::max_align_t); + + auto check = [=](std::size_t s, std::size_t align_req) { + const std::size_t align_exp = align_req > max_align + ? max_align : align_req; + AllocController P; + R1 r{Alloc(P)}; + ex::memory_resource & m1 = r; + + void * const ret = m1.allocate(s, align_req); + assert(P.alive == 1); + assert(P.alloc_count == 1); + assert(P.checkAllocAtLeast(ret, s, align_exp)); + + m1.deallocate(ret, s, align_req); + assert(P.alive == 0); + assert(P.dealloc_count == 1); + assert(P.checkDeallocMatchesAlloc()); + }; + + const std::size_t sizeTypeMax = ~0; + const std::size_t testSizeStart = sizeTypeMax - (max_align * 3); + const std::size_t testSizeEnd = sizeTypeMax - max_align; + + for (std::size_t size = testSizeStart; size <= testSizeEnd; ++size) { + for (std::size_t align=1; align <= (max_align * 2); align *= 2) { + check(size, align); + } + } + +#ifndef TEST_HAS_NO_EXCEPTIONS + for (std::size_t size = sizeTypeMax; size > testSizeEnd; --size) { + AllocController P; + R1 r{Alloc(P)}; + ex::memory_resource & m1 = r; + + try { + m1.allocate(size); + assert(false); + } catch (std::exception const&) { + } + } +#endif +} + +int main() +{ + check_allocate_deallocate>(); + check_allocate_deallocate>(); + check_alloc_max_size(); +} Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_is_equal.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_is_equal.pass.cpp @@ -0,0 +1,83 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// template class resource_adaptor_imp; + +// bool do_is_equal(memory_resource const &) const noexcept; + +#include +#include +#include +#include +#include "test_memory_resource.hpp" + +using std::size_t; +namespace ex = std::experimental::pmr; + +int main() +{ + + typedef CountingAllocator Alloc1; + typedef CountingAllocator RAlloc1; + typedef ex::resource_adaptor R1; + typedef ex::resource_adaptor RR1; + static_assert(std::is_same::value, ""); + + typedef std::allocator Alloc2; + typedef ex::resource_adaptor R2; + static_assert(!std::is_same::value, ""); + + // equal same type + { + AllocController C; + Alloc1 a1(C); + R1 const r1(a1); + ex::memory_resource const & m1 = r1; + + Alloc1 a2(C); + R1 const r2(a2); + ex::memory_resource const & m2 = r2; + + assert(m1.is_equal(m2)); + assert(m2.is_equal(m1)); + } + // not equal same type + { + AllocController C; + Alloc1 a1(C); + R1 const r1(a1); + ex::memory_resource const & m1 = r1; + + AllocController C2; + Alloc1 a2(C2); + R1 const r2(a2); + ex::memory_resource const & m2 = r2; + + assert(!m1.is_equal(m2)); + assert(!m2.is_equal(m1)); + } + // different allocator types + { + AllocController C; + Alloc1 a1(C); + R1 const r1(a1); + ex::memory_resource const & m1 = r1; + + Alloc2 a2; + R2 const r2(a2); + ex::memory_resource const & m2 = r2; + + assert(!m1.is_equal(m2)); + assert(!m2.is_equal(m1)); + } +} Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.overview/overview.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.overview/overview.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 + +// + +// template class resource_adaptor_imp; + +#include +#include +#include +#include + +namespace ex = std::experimental::pmr; + +int main() +{ + typedef ex::resource_adaptor> R; + typedef ex::resource_adaptor> R2; + static_assert(std::is_same::value, ""); + { + static_assert(std::is_base_of::value, ""); + static_assert(std::is_same>::value, ""); + } + { + static_assert(std::is_default_constructible::value, ""); + 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.global/default_resource.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp @@ -0,0 +1,73 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +//----------------------------------------------------------------------------- +// TESTING memory_resource * get_default_resource() noexcept; +// memory_resource * set_default_resource(memory_resource*) noexcept; +// +// Concerns: +// A) 'get_default_resource()' returns a non-null memory_resource pointer. +// B) 'get_default_resource()' returns the value set by the last call to +// 'set_default_resource(...)' and 'new_delete_resource()' if no call +// to 'set_default_resource(...)' has occurred. +// C) 'set_default_resource(...)' returns the previous value of the default +// resource. +// D) 'set_default_resource(T* p)' for a non-null 'p' sets the default resource +// to be 'p'. +// E) 'set_default_resource(null)' sets the default resource to +// 'new_delete_resource()'. +// F) 'get_default_resource' and 'set_default_resource' are noexcept. + + +#include +#include + +#include "test_memory_resource.hpp" + +using namespace std::experimental::pmr; + +int main() { + TestResource R; + { // Test (A) and (B) + memory_resource* p = get_default_resource(); + assert(p != nullptr); + assert(p == new_delete_resource()); + assert(p == get_default_resource()); + } + { // Test (C) and (D) + memory_resource *expect = &R; + memory_resource *old = set_default_resource(expect); + assert(old != nullptr); + assert(old == new_delete_resource()); + + memory_resource *p = get_default_resource(); + assert(p != nullptr); + assert(p == expect); + assert(p == get_default_resource()); + } + { // Test (E) + memory_resource* old = set_default_resource(nullptr); + assert(old == &R); + memory_resource* p = get_default_resource(); + assert(p != nullptr); + assert(p == new_delete_resource()); + assert(p == get_default_resource()); + } + { // Test (F) + static_assert(noexcept(get_default_resource()), + "get_default_resource() must be noexcept"); + + static_assert(noexcept(set_default_resource(nullptr)), + "set_default_resource() must be noexcept"); + } +} Index: test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.global/new_delete_resource.pass.cpp @@ -0,0 +1,101 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// memory_resource * new_delete_resource() + +#include +#include +#include + +#include "count_new.hpp" + +namespace ex = std::experimental::pmr; + +struct assert_on_compare : public ex::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(ex::memory_resource const &) const noexcept + { assert(false); } +}; + +void test_return() +{ + { + static_assert(std::is_same< + decltype(ex::new_delete_resource()), ex::memory_resource* + >::value, ""); + } + // assert not null + { + assert(ex::new_delete_resource()); + } + // assert same return value + { + assert(ex::new_delete_resource() == ex::new_delete_resource()); + } +} + +void test_equality() +{ + // Same object + { + ex::memory_resource & r1 = *ex::new_delete_resource(); + ex::memory_resource & r2 = *ex::new_delete_resource(); + // check both calls returned the same object + assert(&r1 == &r2); + // check for proper equality semantics + assert(r1 == r2); + assert(r2 == r1); + assert(!(r1 != r2)); + assert(!(r2 != r1)); + } + // Different types + { + ex::memory_resource & r1 = *ex::new_delete_resource(); + assert_on_compare c; + ex::memory_resource & r2 = c; + assert(r1 != r2); + assert(!(r1 == r2)); + } +} + +void test_allocate_deallocate() +{ + ex::memory_resource & r1 = *ex::new_delete_resource(); + + globalMemCounter.reset(); + + void *ret = r1.allocate(50); + assert(ret); + assert(globalMemCounter.checkOutstandingNewEq(1)); + assert(globalMemCounter.checkLastNewSizeEq(50)); + + r1.deallocate(ret, 1); + assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(globalMemCounter.checkDeleteCalledEq(1)); + +} + +int main() +{ + static_assert(noexcept(ex::new_delete_resource()), "Must be noexcept"); + test_return(); + test_equality(); + test_allocate_deallocate(); +} Index: test/std/experimental/memory/memory.resource.global/null_memory_resource.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.global/null_memory_resource.pass.cpp @@ -0,0 +1,117 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// memory_resource * null_memory_resource() + +#include +#include +#include +#include + +#include "test_macros.h" +#include "count_new.hpp" + +namespace ex = std::experimental::pmr; + +struct assert_on_compare : public ex::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(ex::memory_resource const &) const noexcept + { assert(false); } +}; + +void test_return() +{ + { + static_assert(std::is_same< + decltype(ex::null_memory_resource()), ex::memory_resource* + >::value, ""); + } + // Test that the returned value is not null + { + assert(ex::null_memory_resource()); + } + // Test the same value is returned by repeated calls. + { + assert(ex::null_memory_resource() == ex::null_memory_resource()); + } +} + +void test_equality() +{ + // Same object + { + ex::memory_resource & r1 = *ex::null_memory_resource(); + ex::memory_resource & r2 = *ex::null_memory_resource(); + // check both calls returned the same object + assert(&r1 == &r2); + // check for proper equality semantics + assert(r1 == r2); + assert(r2 == r1); + assert(!(r1 != r2)); + assert(!(r2 != r1)); + // check the is_equal method + assert(r1.is_equal(r2)); + assert(r2.is_equal(r1)); + } + // Different types + { + ex::memory_resource & r1 = *ex::null_memory_resource(); + assert_on_compare c; + ex::memory_resource & r2 = c; + assert(r1 != r2); + assert(!(r1 == r2)); + assert(!r1.is_equal(r2)); + } +} + +void test_allocate() +{ +#ifndef TEST_HAS_NO_EXCEPTIONS + DisableAllocationGuard g; // null_memory_resource shouldn't allocate. + try { + ex::null_memory_resource()->allocate(1); + assert(false); + } catch (std::bad_alloc const &) { + // do nothing + } catch (...) { + assert(false); + } +#endif +} + +void test_deallocate() +{ + globalMemCounter.reset(); + + int x = 42; + ex::null_memory_resource()->deallocate(nullptr, 0); + ex::null_memory_resource()->deallocate(&x, 0); + + assert(globalMemCounter.checkDeleteCalledEq(0)); + assert(globalMemCounter.checkDeleteArrayCalledEq(0)); +} + +int main() +{ + test_return(); + test_equality(); + test_allocate(); + test_deallocate(); +} Index: test/std/experimental/memory/memory.resource.synop/nothing_to_do.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource.synop/nothing_to_do.pass.cpp @@ -0,0 +1,13 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main() +{ +} Index: test/std/experimental/memory/memory.resource/construct.fail.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/construct.fail.cpp @@ -0,0 +1,25 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// Check that memory_resource is not constructible + +#include +#include +#include + +namespace ex = std::experimental::pmr; + +int main() +{ + ex::memory_resource m; // expected-error {{variable type 'ex::memory_resource' is an abstract class}} +} Index: test/std/experimental/memory/memory.resource/memory.resource.eq/equal.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/memory.resource.eq/equal.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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// bool operator==(memory_resource const &, memory_resource const &) noexcept; + +#include +#include +#include + +#include "test_macros.h" +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + // check return types + { + ex::memory_resource const * mr1(nullptr); + ex::memory_resource const * mr2(nullptr); + static_assert(std::is_same::value, ""); + static_assert(noexcept(*mr1 == *mr2), ""); + } + // equal + { + TestResource r1(1); + TestResource r2(1); + ex::memory_resource const & mr1 = r1; + ex::memory_resource const & mr2 = r2; + + assert(mr1 == mr2); + assert(r1.checkIsEqualCalledEq(1)); + assert(r2.checkIsEqualCalledEq(0)); + + assert(mr2 == mr1); + assert(r1.checkIsEqualCalledEq(1)); + assert(r2.checkIsEqualCalledEq(1)); + } + // equal same object + { + TestResource r1(1); + ex::memory_resource const & mr1 = r1; + ex::memory_resource const & mr2 = r1; + + assert(mr1 == mr2); + assert(r1.checkIsEqualCalledEq(0)); + + assert(mr2 == mr1); + assert(r1.checkIsEqualCalledEq(0)); + } + // not equal + { + TestResource r1(1); + TestResource r2(2); + ex::memory_resource const & mr1 = r1; + ex::memory_resource const & mr2 = r2; + + assert(!(mr1 == mr2)); + assert(r1.checkIsEqualCalledEq(1)); + assert(r2.checkIsEqualCalledEq(0)); + + assert(!(mr2 == mr1)); + assert(r1.checkIsEqualCalledEq(1)); + assert(r2.checkIsEqualCalledEq(1)); + } +} Index: test/std/experimental/memory/memory.resource/memory.resource.eq/not_equal.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/memory.resource.eq/not_equal.pass.cpp @@ -0,0 +1,75 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// bool operator!=(memory_resource const &, memory_resource const &) noexcept; + +#include +#include +#include + +#include "test_memory_resource.hpp" + +namespace ex = std::experimental::pmr; + +int main() +{ + // check return types + { + ex::memory_resource const * mr1(nullptr); + ex::memory_resource const * mr2(nullptr); + static_assert(std::is_same::value, ""); + static_assert(noexcept(*mr1 != *mr2), ""); + } + // not equal + { + TestResource r1(1); + TestResource r2(2); + ex::memory_resource const & mr1 = r1; + ex::memory_resource const & mr2 = r2; + + assert(mr1 != mr2); + assert(r1.checkIsEqualCalledEq(1)); + assert(r2.checkIsEqualCalledEq(0)); + + assert(mr2 != mr1); + assert(r1.checkIsEqualCalledEq(1)); + assert(r2.checkIsEqualCalledEq(1)); + } + // equal + { + TestResource r1(1); + TestResource r2(1); + ex::memory_resource const & mr1 = r1; + ex::memory_resource const & mr2 = r2; + + assert(!(mr1 != mr2)); + assert(r1.checkIsEqualCalledEq(1)); + assert(r2.checkIsEqualCalledEq(0)); + + assert(!(mr2 != mr1)); + assert(r1.checkIsEqualCalledEq(1)); + assert(r2.checkIsEqualCalledEq(1)); + } + // equal same object + { + TestResource r1(1); + ex::memory_resource const & mr1 = r1; + ex::memory_resource const & mr2 = r1; + + assert(!(mr1 != mr2)); + assert(r1.checkIsEqualCalledEq(0)); + + assert(!(mr2 != mr1)); + assert(r1.checkIsEqualCalledEq(0)); + } +} Index: test/std/experimental/memory/memory.resource/memory.resource.overview/nothing_to_do.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/memory.resource.overview/nothing_to_do.pass.cpp @@ -0,0 +1,10 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main () {} Index: test/std/experimental/memory/memory.resource/memory.resource.priv/protected_members.fail.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/memory.resource.priv/protected_members.fail.cpp @@ -0,0 +1,27 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// memory_resource::do_allocate(size_t, size_t); /* protected */ +// memory_resource::do_deallocate(void*, size_t, size_t); /* protected */ +// memory_resource::do_is_equal(memory_resource const&); /* protected */ + +#include + +namespace ex = std::experimental::pmr; + +int main() { + ex::memory_resource *m = ex::new_delete_resource(); + m->do_allocate(0, 0); // expected-error{{'do_allocate' is a protected member}} + m->do_deallocate(nullptr, 0, 0); // expected-error{{'do_deallocate' is a protected member}} + m->do_is_equal(*m); // expected-error{{'do_is_equal' is a protected member}} +} \ No newline at end of file Index: test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp @@ -0,0 +1,89 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +//------------------------------------------------------------------------------ +// TESTING void * memory_resource::allocate(size_t, size_t = max_align) +// +// Concerns: +// A) 'memory_resource' contains a member 'allocate' with the required +// signature, including the default alignment parameter. +// B) The return type of 'allocate' is 'void*'. +// C) 'allocate' is not marked as 'noexcept'. +// D) Invoking 'allocate' invokes 'do_allocate' with the same arguments. +// E) If 'do_allocate' throws then 'allocate' propagates that exception. + +#include +#include +#include +#include + +#include "test_macros.h" +#include "test_memory_resource.hpp" + +using std::experimental::pmr::memory_resource; + +int main() +{ + TestResource R(42); + auto& P = R.getController(); + memory_resource& M = R; + { + static_assert( + std::is_same::value + , "Must be void*" + ); + static_assert( + std::is_same::value + , "Must be void*" + ); + } + { + static_assert( + ! noexcept(M.allocate(0, 0)) + , "Must not be noexcept." + ); + static_assert( + ! noexcept(M.allocate(0)) + , "Must not be noexcept." + ); + } + { + int s = 42; + int a = 64; + void* p = M.allocate(s, a); + assert(P.alloc_count == 1); + assert(P.checkAlloc(p, s, a)); + + s = 128; + a = MaxAlignV; + p = M.allocate(s); + assert(P.alloc_count == 2); + assert(P.checkAlloc(p, s, a)); + } +#ifndef TEST_HAS_NO_EXCEPTIONS + { + TestResource R2; + auto& P = R2.getController(); + P.throw_on_alloc = true; + memory_resource& M2 = R2; + try { + M2.allocate(42); + assert(false); + } catch (TestException const&) { + // do nothing. + } catch (...) { + assert(false); + } + } +#endif +} Index: test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp @@ -0,0 +1,74 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +//------------------------------------------------------------------------------ +// TESTING void * memory_resource::deallocate(void *, size_t, size_t = max_align) +// +// Concerns: +// A) 'memory_resource' contains a member 'deallocate' with the required +// signature, including the default alignment parameter. +// B) The return type of 'deallocate' is 'void'. +// C) 'deallocate' is not marked as 'noexcept'. +// D) Invoking 'deallocate' invokes 'do_deallocate' with the same arguments. + + +#include +#include +#include +#include + +#include "test_memory_resource.hpp" + +using std::experimental::pmr::memory_resource; + +int main() +{ + NullResource R(42); + auto& P = R.getController(); + memory_resource& M = R; + { + static_assert( + std::is_same::value + , "Must be void" + ); + static_assert( + std::is_same::value + , "Must be void" + ); + } + { + static_assert( + ! noexcept(M.deallocate(nullptr, 0, 0)) + , "Must not be noexcept." + ); + static_assert( + ! noexcept(M.deallocate(nullptr, 0)) + , "Must not be noexcept." + ); + } + { + int s = 100; + int a = 64; + void* p = reinterpret_cast(640); + M.deallocate(p, s, a); + assert(P.dealloc_count == 1); + assert(P.checkDealloc(p, s, a)); + + s = 128; + a = alignof(std::max_align_t); + p = reinterpret_cast(12800); + M.deallocate(p, s); + assert(P.dealloc_count == 2); + assert(P.checkDealloc(p, s, a)); + } +} Index: test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/memory.resource.public/dtor.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 + +// + +//------------------------------------------------------------------------------ +// TESTING virtual ~memory_resource() +// +// Concerns: +// A) 'memory_resource' is destructible. +// B) The destructor is implicitly marked noexcept. +// C) The destructor is marked virtual. + +#include +#include +#include + +#include "test_memory_resource.hpp" + +using std::experimental::pmr::memory_resource; + +int main() +{ + static_assert( + std::has_virtual_destructor::value + , "Must have virtual destructor" + ); + static_assert( + std::is_nothrow_destructible::value, + "Must be nothrow destructible" + ); + static_assert( + std::is_abstract::value + , "Must be abstract" + ); + // Check that the destructor of `TestResource` is called when + // it is deleted as a pointer to `memory_resource` + { + using TR = TestResource; + memory_resource* M = new TR(42); + assert(TR::resource_alive == 1); + assert(TR::resource_constructed == 1); + assert(TR::resource_destructed == 0); + + delete M; + + assert(TR::resource_alive == 0); + assert(TR::resource_constructed == 1); + assert(TR::resource_destructed == 1); + } +} Index: test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp @@ -0,0 +1,93 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +//------------------------------------------------------------------------------ +// TESTING virtual bool is_equal(memory_resource const &) const noexcept +// +// Concerns: +// A) 'memory_resource' provides a function 'is_equal' with the required +// signature. +// B) 'is_equal' is noexcept. +// C) 'do_is_equal' is called using the same arguments passed to 'is_equal' +// and the resulting value is returned. +// D) 'do_is_equal' is called on the LHS object and not the RHS object. + +#include +#include +#include +#include "test_memory_resource.hpp" + +using std::experimental::pmr::memory_resource; + +int main() +{ + { + memory_resource const* r1 = nullptr; + memory_resource const* r2 = nullptr; + static_assert( + noexcept(r1->is_equal(*r2)) + , "is_equal must be noexcept" + ); + } + { + TestResource1 R1(1); + auto& P1 = R1.getController(); + memory_resource const& M1 = R1; + + TestResource2 R2(1); + auto& P2 = R2.getController(); + memory_resource const& M2 = R2; + + assert(M1.is_equal(M2) == false); + assert(P1.checkIsEqualCalledEq(1)); + assert(P2.checkIsEqualCalledEq(0)); + + assert(M2.is_equal(M1) == false); + assert(P2.checkIsEqualCalledEq(1)); + assert(P1.checkIsEqualCalledEq(1)); + } + { + TestResource1 R1(1); + auto& P1 = R1.getController(); + memory_resource const& M1 = R1; + + TestResource1 R2(2); + auto& P2 = R2.getController(); + memory_resource const& M2 = R2; + + assert(M1.is_equal(M2) == false); + assert(P1.checkIsEqualCalledEq(1)); + assert(P2.checkIsEqualCalledEq(0)); + + assert(M2.is_equal(M1) == false); + assert(P2.checkIsEqualCalledEq(1)); + assert(P1.checkIsEqualCalledEq(1)); + } + { + TestResource1 R1(1); + auto& P1 = R1.getController(); + memory_resource const& M1 = R1; + + TestResource1 R2(1); + auto& P2 = R2.getController(); + memory_resource const& M2 = R2; + + assert(M1.is_equal(M2) == true); + assert(P1.checkIsEqualCalledEq(1)); + assert(P2.checkIsEqualCalledEq(0)); + + assert(M2.is_equal(M1) == true); + assert(P2.checkIsEqualCalledEq(1)); + assert(P1.checkIsEqualCalledEq(1)); + } +} Index: test/std/experimental/memory/nothing_to_do.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/nothing_to_do.pass.cpp @@ -0,0 +1,13 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +int main() +{ +} Index: test/support/test_memory_resource.hpp =================================================================== --- /dev/null +++ test/support/test_memory_resource.hpp @@ -0,0 +1,506 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef SUPPORT_TEST_MEMORY_RESOURCE_HPP +#define SUPPORT_TEST_MEMORY_RESOURCE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include "test_macros.h" + +struct AllocController; + // 'AllocController' is a concrete type that instruments and controls the + // behavior of of test allocators. + +template +class CountingAllocator; + // 'CountingAllocator' is an basic implementation of the 'Allocator' + // requirements that use the 'AllocController' interface. + +template +class MinAlignAllocator; + // 'MinAlignAllocator' is an instrumented test type which implements the + // 'Allocator' requirements. 'MinAlignAllocator' ensures that it *never* + // returns a pointer to over-aligned storage. For example + // 'MinAlignPointer{}.allocate(...)' will never a 2-byte aligned + // pointer. + +template +class NullAllocator; + // 'NullAllocator' is an instrumented test type which implements the + // 'Allocator' requirements except that 'allocator' and 'deallocate' are + // nops. + + +#define DISALLOW_COPY(Type) \ + Type(Type const&) = delete; \ + Type& operator=(Type const&) = delete + +constexpr std::size_t MaxAlignV = alignof(std::max_align_t); + +struct TestException {}; + +struct AllocController { + int copy_constructed = 0; + int move_constructed = 0; + + int alive = 0; + int alloc_count = 0; + int dealloc_count = 0; + int is_equal_count = 0; + + std::size_t alive_size; + std::size_t allocated_size; + std::size_t deallocated_size; + + std::size_t last_size = 0; + std::size_t last_align = 0; + void * last_pointer = 0; + + std::size_t last_alloc_size = 0; + std::size_t last_alloc_align = 0; + void * last_alloc_pointer = nullptr; + + std::size_t last_dealloc_size = 0; + std::size_t last_dealloc_align = 0; + void * last_dealloc_pointer = nullptr; + + bool throw_on_alloc = false; + + AllocController() = default; + + void countAlloc(void* p, size_t s, size_t a) { + ++alive; + ++alloc_count; + alive_size += s; + allocated_size += s; + last_pointer = last_alloc_pointer = p; + last_size = last_alloc_size = s; + last_align = last_alloc_align = a; + } + + void countDealloc(void* p, size_t s, size_t a) { + --alive; + ++dealloc_count; + alive_size -= s; + deallocated_size += s; + last_pointer = last_dealloc_pointer = p; + last_size = last_dealloc_size = s; + last_align = last_dealloc_align = a; + } + + void reset() { std::memset(this, 0, sizeof(*this)); } + +public: + bool checkAlloc(void* p, size_t s, size_t a) const { + return p == last_alloc_pointer && + s == last_alloc_size && + a == last_alloc_align; + } + + bool checkAlloc(void* p, size_t s) const { + return p == last_alloc_pointer && + s == last_alloc_size; + } + + bool checkAllocAtLeast(void* p, size_t s, size_t a) const { + return p == last_alloc_pointer && + s <= last_alloc_size && + a <= last_alloc_align; + } + + bool checkAllocAtLeast(void* p, size_t s) const { + return p == last_alloc_pointer && + s <= last_alloc_size; + } + + bool checkDealloc(void* p, size_t s, size_t a) const { + return p == last_dealloc_pointer && + s == last_dealloc_size && + a == last_dealloc_align; + } + + bool checkDealloc(void* p, size_t s) const { + return p == last_dealloc_pointer && + s == last_dealloc_size; + } + + bool checkDeallocMatchesAlloc() const { + return last_dealloc_pointer == last_alloc_pointer && + last_dealloc_size == last_alloc_size && + last_dealloc_align == last_alloc_align; + } + + void countIsEqual() { + ++is_equal_count; + } + + bool checkIsEqualCalledEq(int n) const { + return is_equal_count == n; + } +private: + DISALLOW_COPY(AllocController); +}; + +template +class CountingAllocator +{ +public: + typedef T value_type; + typedef T* pointer; + CountingAllocator() = delete; + explicit CountingAllocator(AllocController& PP) : P(&PP) {} + + CountingAllocator(CountingAllocator const& other) : P(other.P) { + P->copy_constructed += 1; + } + + CountingAllocator(CountingAllocator&& other) : P(other.P) { + P->move_constructed += 1; + } + + template + CountingAllocator(CountingAllocator const& other) TEST_NOEXCEPT : P(other.P) { + P->copy_constructed += 1; + } + + template + CountingAllocator(CountingAllocator&& other) TEST_NOEXCEPT : P(other.P) { + P->move_constructed += 1; + } + + T* allocate(std::size_t n) + { + void* ret = ::operator new(n*sizeof(T)); + P->countAlloc(ret, n*sizeof(T), alignof(T)); + return static_cast(ret); + } + + void deallocate(T* p, std::size_t n) + { + void* vp = static_cast(p); + P->countDealloc(vp, n*sizeof(T), alignof(T)); + ::operator delete(vp); + } + + AllocController& getController() const { return *P; } + +private: + template friend class CountingAllocator; + AllocController *P; +}; + +template +inline bool operator==(CountingAllocator const& x, + CountingAllocator const& y) { + return &x.getController() == &y.getController(); +} + +template +inline bool operator!=(CountingAllocator const& x, + CountingAllocator const& y) { + return !(x == y); +} + +template +class MinAlignedAllocator +{ +public: + typedef T value_type; + typedef T* pointer; + + MinAlignedAllocator() = delete; + + explicit MinAlignedAllocator(AllocController& R) : P(&R) {} + + MinAlignedAllocator(MinAlignedAllocator const& other) : P(other.P) { + P->copy_constructed += 1; + } + + MinAlignedAllocator(MinAlignedAllocator&& other) : P(other.P) { + P->move_constructed += 1; + } + + template + MinAlignedAllocator(MinAlignedAllocator const& other) TEST_NOEXCEPT : P(other.P) { + P->copy_constructed += 1; + } + + template + MinAlignedAllocator(MinAlignedAllocator&& other) TEST_NOEXCEPT : P(other.P) { + P->move_constructed += 1; + } + + T* allocate(std::size_t n) { + char* aligned_ptr = (char*)::operator new(alloc_size(n*sizeof(T))); + assert(is_max_aligned(aligned_ptr)); + + char* unaligned_ptr = aligned_ptr + alignof(T); + assert(is_min_aligned(unaligned_ptr)); + + P->countAlloc(unaligned_ptr, n * sizeof(T), alignof(T)); + + return ((T*)unaligned_ptr); + } + + void deallocate(T* p, std::size_t n) { + assert(is_min_aligned(p)); + + char* aligned_ptr = ((char*)p) - alignof(T); + assert(is_max_aligned(aligned_ptr)); + + P->countDealloc(p, n*sizeof(T), alignof(T)); + + return ::operator delete(static_cast(aligned_ptr)); + } + + AllocController& getController() const { return *P; } + +private: + static const std::size_t BlockSize = alignof(std::max_align_t); + + static std::size_t alloc_size(std::size_t s) { + std::size_t bytes = (s + BlockSize - 1) & ~(BlockSize - 1); + bytes += BlockSize; + assert(bytes % BlockSize == 0); + return bytes / BlockSize; + } + + static bool is_max_aligned(void* p) { + return reinterpret_cast(p) % BlockSize == 0; + } + + static bool is_min_aligned(void* p) { + if (alignof(T) == BlockSize) { + return is_max_aligned(p); + } else { + return reinterpret_cast(p) % BlockSize == alignof(T); + } + } + + template friend class MinAlignedAllocator; + mutable AllocController *P; +}; + + +template +inline bool operator==(MinAlignedAllocator const& x, + MinAlignedAllocator const& y) { + return &x.getController() == &y.getController(); +} + +template +inline bool operator!=(MinAlignedAllocator const& x, + MinAlignedAllocator const& y) { + return !(x == y); +} + +template +class NullAllocator +{ +public: + typedef T value_type; + typedef T* pointer; + NullAllocator() = delete; + explicit NullAllocator(AllocController& PP) : P(&PP) {} + + NullAllocator(NullAllocator const& other) : P(other.P) { + P->copy_constructed += 1; + } + + NullAllocator(NullAllocator&& other) : P(other.P) { + P->move_constructed += 1; + } + + template + NullAllocator(NullAllocator const& other) TEST_NOEXCEPT : P(other.P) { + P->copy_constructed += 1; + } + + template + NullAllocator(NullAllocator&& other) TEST_NOEXCEPT : P(other.P) { + P->move_constructed += 1; + } + + T* allocate(std::size_t n) + { + P->countAlloc(nullptr, n*sizeof(T), alignof(T)); + return nullptr; + } + + void deallocate(T* p, std::size_t n) + { + void* vp = static_cast(p); + P->countDealloc(vp, n*sizeof(T), alignof(T)); + } + + AllocController& getController() const { return *P; } + +private: + template friend class NullAllocator; + AllocController *P; +}; + +template +inline bool operator==(NullAllocator const& x, + NullAllocator const& y) { + return &x.getController() == &y.getController(); +} + +template +inline bool operator!=(NullAllocator const& x, + NullAllocator const& y) { + return !(x == y); +} + + + +template +class TestResourceImp : public std::experimental::pmr::memory_resource +{ +public: + static int resource_alive; + static int resource_constructed; + static int resource_destructed; + + static void resetStatics() { + assert(resource_alive == 0); + resource_alive = 0; + resource_constructed = 0; + resource_destructed = 0; + } + + using memory_resource = std::experimental::pmr::memory_resource; + using Provider = ProviderT; + + int value; + + explicit TestResourceImp(int val = 0) : value(val) { + ++resource_alive; + ++resource_constructed; + } + + ~TestResourceImp() noexcept { + --resource_alive; + ++resource_destructed; + } + + void reset() { C.reset(); P.reset(); } + AllocController& getController() { return C; } + + bool checkAlloc(void* p, std::size_t s, std::size_t a) const + { return C.checkAlloc(p, s, a); } + + bool checkDealloc(void* p, std::size_t s, std::size_t a) const + { return C.checkDealloc(p, s, a); } + + bool checkIsEqualCalledEq(int n) const { return C.checkIsEqualCalledEq(n); } + +protected: + virtual void * do_allocate(std::size_t s, std::size_t a) { + if (C.throw_on_alloc) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw TestException{}; +#else + assert(false); +#endif + } + void* ret = P.allocate(s, a); + C.countAlloc(ret, s, a); + return ret; + } + + virtual void do_deallocate(void * p, std::size_t s, std::size_t a) { + C.countDealloc(p, s, a); + P.deallocate(p, s, a); + } + + virtual bool do_is_equal(memory_resource const & other) const noexcept { + C.countIsEqual(); + TestResourceImp const * o = dynamic_cast(&other); + return o && o->value == value; + } +private: + mutable AllocController C; + mutable Provider P; + DISALLOW_COPY(TestResourceImp); +}; + +template +int TestResourceImp::resource_alive = 0; + +template +int TestResourceImp::resource_constructed = 0; + +template +int TestResourceImp::resource_destructed = 0; + + +struct NullProvider { + NullProvider() {} + void* allocate(size_t, size_t) { return nullptr; } + void deallocate(void*, size_t, size_t) {} + void reset() {} +private: + DISALLOW_COPY(NullProvider); +}; + +struct NewDeleteProvider { + NewDeleteProvider() {} + void* allocate(size_t s, size_t) { return ::operator new(s); } + void deallocate(void* p, size_t, size_t) { ::operator delete(p); } + void reset() {} +private: + DISALLOW_COPY(NewDeleteProvider); +}; + +template // 10 pages worth of memory. +struct BufferProvider { + char buffer[Size]; + void* next = &buffer; + size_t space = Size; + + BufferProvider() {} + + void* allocate(size_t s, size_t a) { + void* ret = std::align(s, a, next, space); + if (ret == nullptr) { +#ifndef TEST_HAS_NO_EXCEPTIONS + throw std::bad_alloc(); +#else + assert(false); +#endif + } + + return ret; + } + + void deallocate(void*, size_t, size_t) {} + + void reset() { + next = &buffer; + space = Size; + } +private: + DISALLOW_COPY(BufferProvider); +}; + +using NullResource = TestResourceImp; +using NewDeleteResource = TestResourceImp; +using TestResource = TestResourceImp, 0>; +using TestResource1 = TestResourceImp, 1>; +using TestResource2 = TestResourceImp, 2>; + + +#endif /* SUPPORT_TEST_MEMORY_RESOURCE_HPP */ Index: test/support/type_id.h =================================================================== --- /dev/null +++ test/support/type_id.h @@ -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. +// +//===----------------------------------------------------------------------===// +#ifndef SUPPORT_TYPE_ID_H +#define SUPPORT_TYPE_ID_H + +#include +#include + +#include "test_macros.h" + +#if TEST_STD_VER < 11 +#error This header requires C++11 or greater +#endif + +// TypeID - Represent a unique identifier for a type. TypeID allows equality +// comparisons between different types. +struct TypeID { + friend bool operator==(TypeID const& LHS, TypeID const& RHS) + {return LHS.m_id == RHS.m_id; } + friend bool operator!=(TypeID const& LHS, TypeID const& RHS) + {return LHS.m_id != RHS.m_id; } +private: + explicit constexpr TypeID(const int* xid) : m_id(xid) {} + + TypeID(const TypeID&) = delete; + TypeID& operator=(TypeID const&) = delete; + + const int* const m_id; + template friend TypeID const& makeTypeID(); + +}; + +// makeTypeID - Return the TypeID for the specified type 'T'. +template +inline TypeID const& makeTypeID() { + static int dummy; + static const TypeID id(&dummy); + return id; +} + +template +struct ArgumentListID {}; + +// makeArgumentID - Create and return a unique identifier for a given set +// of arguments. +template +inline TypeID const& makeArgumentID() { + return makeTypeID>(); +} + +#endif // SUPPORT_TYPE_ID_H Index: test/support/uses_alloc_types.hpp =================================================================== --- /dev/null +++ test/support/uses_alloc_types.hpp @@ -0,0 +1,298 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +#ifndef USES_ALLOC_TYPES_HPP +#define USES_ALLOC_TYPES_HPP + +# include +# include +# include +# include + +#include "test_memory_resource.hpp" +#include "type_id.h" + +// There are two forms of uses-allocator construction: +// (1) UA_AllocArg: 'T(allocator_arg_t, Alloc const&, Args&&...)' +// (2) UA_AllocLast: 'T(Args&&..., Alloc const&)' +// 'UA_None' represents non-uses allocator construction. +enum class UsesAllocatorType { + UA_None = 0, + UA_AllocArg = 2, + UA_AllocLast = 4 +}; +constexpr UsesAllocatorType UA_None = UsesAllocatorType::UA_None; +constexpr UsesAllocatorType UA_AllocArg = UsesAllocatorType::UA_AllocArg; +constexpr UsesAllocatorType UA_AllocLast = UsesAllocatorType::UA_AllocLast; + +template +class UsesAllocatorV1; + // Implements form (1) of uses-allocator construction from the specified + // 'Alloc' type and exactly 'N' additional arguments. It also provides + // non-uses allocator construction from 'N' arguments. This test type + // blows up when form (2) of uses-allocator is even considered. + +template +class UsesAllocatorV2; + // Implements form (2) of uses-allocator construction from the specified + // 'Alloc' type and exactly 'N' additional arguments. It also provides + // non-uses allocator construction from 'N' arguments. + +template +class UsesAllocatorV3; + // Implements both form (1) and (2) of uses-allocator construction from + // the specified 'Alloc' type and exactly 'N' additional arguments. It also + // provides non-uses allocator construction from 'N' arguments. + +template +class NotUsesAllocator; + // Implements both form (1) and (2) of uses-allocator construction from + // the specified 'Alloc' type and exactly 'N' additional arguments. It also + // provides non-uses allocator construction from 'N' arguments. However + // 'NotUsesAllocator' never provides a 'allocator_type' typedef so it is + // never automatically uses-allocator constructed. + + +template +bool checkConstruct(TestType& value, UsesAllocatorType form, + typename TestType::CtorAlloc const& alloc) + // Check that 'value' was constructed using the specified 'form' of + // construction and with the specified 'ArgTypes...'. Additionally + // check that 'value' was constructed using the specified 'alloc'. +{ + if (form == UA_None) { + return value.template checkConstruct(form); + } else { + return value.template checkConstruct(form, alloc); + } +} + + +template +bool checkConstruct(TestType& value, UsesAllocatorType form) { + return value.template checkConstruct(form); +} + +template +bool checkConstructionEquiv(TestType& T, TestType& U) + // check that 'T' and 'U' where initialized in the exact same manner. +{ + return T.checkConstructEquiv(U); +} + +//////////////////////////////////////////////////////////////////////////////// +namespace detail { + +template +struct TakeNImp; + +template +struct TakeNImp { + typedef ArgList type; +}; + +template +struct TakeNImp, F, R...> + : TakeNImp, R...> {}; + +template +struct TakeNArgs : TakeNImp, Args...> {}; + +template +struct Identity { typedef T type; }; + +template +using IdentityT = typename Identity::type; + +template +using EnableIfB = typename std::enable_if::type; + +} // end namespace detail + +using detail::EnableIfB; + +struct AllocLastTag {}; + +template +struct UsesAllocatorTestBase { +public: + using CtorAlloc = typename std::conditional< + std::is_same::value, + std::experimental::pmr::memory_resource*, + Alloc + >::type; + + template + bool checkConstruct(UsesAllocatorType expectType) const { + return expectType == constructor_called && + makeArgumentID() == *args_id; + } + + template + bool checkConstruct(UsesAllocatorType expectType, + CtorAlloc const& expectAlloc) const { + return expectType == constructor_called && + makeArgumentID() == *args_id && + expectAlloc == allocator; + } + + bool checkConstructEquiv(UsesAllocatorTestBase& O) const { + return constructor_called == O.constructor_called + && *args_id == *O.args_id + && allocator == O.allocator; + } + +protected: + explicit UsesAllocatorTestBase(const TypeID* aid) + : args_id(aid), constructor_called(UA_None), allocator() + {} + + template + UsesAllocatorTestBase(std::allocator_arg_t, CtorAlloc const& a, Args&&...) + : args_id(&makeArgumentID()), + constructor_called(UA_AllocArg), + allocator(a) + {} + + template + UsesAllocatorTestBase(AllocLastTag, Args&&... args) + : args_id(nullptr), + constructor_called(UA_AllocLast) + { + typedef typename detail::TakeNArgs::type + ArgIDL; + args_id = &makeTypeID(); + getAllocatorFromPack(ArgIDL{}, std::forward(args)...); + } + +private: + template + void getAllocatorFromPack(ArgumentListID, Args&&... args) { + getAllocatorFromPackImp(args...); + } + + template + void getAllocatorFromPackImp(typename detail::Identity::type..., CtorAlloc const& alloc) { + allocator = alloc; + } + + const TypeID* args_id; + UsesAllocatorType constructor_called = UA_None; + CtorAlloc allocator; +}; + +template +class UsesAllocatorV1 : public UsesAllocatorTestBase +{ +public: + typedef Alloc allocator_type; + + using Base = UsesAllocatorTestBase; + using CtorAlloc = typename Base::CtorAlloc; + + UsesAllocatorV1() : Base(&makeArgumentID<>()) {} + + // Non-Uses Allocator Ctor + template = false> + UsesAllocatorV1(Args&&... args) : Base(&makeArgumentID()) {}; + + // Uses Allocator Arg Ctor + template + UsesAllocatorV1(std::allocator_arg_t tag, CtorAlloc const & a, Args&&... args) + : Base(tag, a, std::forward(args)...) + { } + + // BLOWS UP: Uses Allocator Last Ctor + template _Dummy = false> + constexpr UsesAllocatorV1(_First&& __first, Args&&... args) + { + static_assert(!std::is_same<_First, _First>::value, ""); + } +}; + + +template +class UsesAllocatorV2 : public UsesAllocatorTestBase +{ +public: + typedef Alloc allocator_type; + + using Base = UsesAllocatorTestBase; + using CtorAlloc = typename Base::CtorAlloc; + + UsesAllocatorV2() : Base(&makeArgumentID<>()) {} + + // Non-Uses Allocator Ctor + template = false> + UsesAllocatorV2(Args&&... args) : Base(&makeArgumentID()) {}; + + // Uses Allocator Last Ctor + template = false> + UsesAllocatorV2(Args&&... args) + : Base(AllocLastTag{}, std::forward(args)...) + {} +}; + +template +class UsesAllocatorV3 : public UsesAllocatorTestBase +{ +public: + typedef Alloc allocator_type; + + using Base = UsesAllocatorTestBase; + using CtorAlloc = typename Base::CtorAlloc; + + UsesAllocatorV3() : Base(&makeArgumentID<>()) {} + + // Non-Uses Allocator Ctor + template = false> + UsesAllocatorV3(Args&&... args) : Base(&makeArgumentID()) {}; + + // Uses Allocator Arg Ctor + template + UsesAllocatorV3(std::allocator_arg_t tag, CtorAlloc const& alloc, Args&&... args) + : Base(tag, alloc, std::forward(args)...) + {} + + // Uses Allocator Last Ctor + template = false> + UsesAllocatorV3(Args&&... args) + : Base(AllocLastTag{}, std::forward(args)...) + {} +}; + +template +class NotUsesAllocator : public UsesAllocatorTestBase +{ +public: + // no allocator_type typedef provided + + using Base = UsesAllocatorTestBase; + using CtorAlloc = typename Base::CtorAlloc; + + NotUsesAllocator() : Base(&makeArgumentID<>()) {} + + // Non-Uses Allocator Ctor + template = false> + NotUsesAllocator(Args&&... args) : Base(&makeArgumentID()) {}; + + // Uses Allocator Arg Ctor + template + NotUsesAllocator(std::allocator_arg_t tag, CtorAlloc const& alloc, Args&&... args) + : Base(tag, alloc, std::forward(args)...) + {} + + // Uses Allocator Last Ctor + template = false> + NotUsesAllocator(Args&&... args) + : Base(AllocLastTag{}, std::forward(args)...) + {} +}; + +#endif /* USES_ALLOC_TYPES_HPP */