Index: include/__functional_base =================================================================== --- include/__functional_base +++ include/__functional_base @@ -646,16 +646,6 @@ new (__storage) _Tp (_VSTD::forward<_Args>(__args)..., __a); } -// FIXME: Theis should have a version which takes a non-const alloc. -template -inline _LIBCPP_INLINE_VISIBILITY -void __user_alloc_construct (_Tp *__storage, const _Allocator &__a, _Args &&... __args) -{ - __user_alloc_construct_impl( - __uses_alloc_ctor<_Tp, _Allocator>(), - __storage, __a, _VSTD::forward<_Args>(__args)... - ); -} #endif // _LIBCPP_CXX03_LANG _LIBCPP_END_NAMESPACE_STD Index: include/__memory_resource_base =================================================================== --- /dev/null +++ include/__memory_resource_base @@ -0,0 +1,317 @@ +// -*- 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___MEMORY_RESOURCE_BASE +#define _LIBCPP___MEMORY_RESOURCE_BASE + +/** + memory_resource synopsis + +// C++17 + +namespace std { +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; + + // Global memory resources + memory_resource* set_default_resource(memory_resource* r) noexcept; + memory_resource* get_default_resource() noexcept; + +} // namespace pmr +} // namespace std + + */ + +#include <__config> +#include <__functional_base> +#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_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace pmr +{ + +// 23.12.2, mem.res.class +class _LIBCPP_TYPE_VIS memory_resource +{ + static const size_t __max_align = alignof(max_align_t); + +// 23.12.2.1, mem.res.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); } + +// 23.12.2.2, mem.res.private +private: + 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; +}; + +// 23.12.2.3, mem.res.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); +} + +// 23.12.4, mem.res.global + +_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 *) _NOEXCEPT; + +// 23.12.3, mem.poly.allocator.class +template +class _LIBCPP_TEMPLATE_VIS polymorphic_allocator +{ +public: + typedef _ValueType value_type; + + // 23.12.3.1, mem.poly.allocator.ctor + _LIBCPP_INLINE_VISIBILITY + polymorphic_allocator() _NOEXCEPT + : __res_(_VSTD::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 &) = delete; + + // 23.12.3.2, mem.poly.allocator.mem + _LIBCPP_INLINE_VISIBILITY + _ValueType* allocate(size_t __n) { + if (__n > __max_size()) { + __throw_length_error( + "std::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::__user_alloc_construct_impl( + typename __uses_alloc_ctor<_Tp, polymorphic_allocator&, _Ts...>::type(), + __p, *this, _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 __uses_alloc_ctor< + _T1, polymorphic_allocator&, _Args1... + >::type() + , _VSTD::move(__x) + , typename __make_tuple_indices::type{} + ) + , __transform_tuple( + typename __uses_alloc_ctor< + _T2, polymorphic_allocator&, _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 + 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...>) + { + 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...>) + { + using _Tup = tuple; + return _Tup(allocator_arg, *this, + _VSTD::get<_Idx>(_VSTD::move(__t))...); + } + + template + _LIBCPP_INLINE_VISIBILITY + tuple<_Args&&..., polymorphic_allocator&> + __transform_tuple(integral_constant, tuple<_Args...> && __t, + __tuple_indices<_Idx...>) + { + using _Tup = tuple<_Args&&..., polymorphic_allocator&>; + return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., *this); + } + + _LIBCPP_INLINE_VISIBILITY + size_t __max_size() const _NOEXCEPT + { return numeric_limits::max() / sizeof(value_type); } + + memory_resource * __res_; +}; + +// 23.12.3.3, mem.poly.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); +} + +} // namespace pmr + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif /* _LIBCPP___MEMORY_RESOURCE_BASE */ Index: include/deque =================================================================== --- include/deque +++ include/deque @@ -162,6 +162,10 @@ #include #include +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -2928,6 +2932,16 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template + using deque = _VSTD::deque<_ValueT, polymorphic_allocator<_ValueT>>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + _LIBCPP_POP_MACROS #endif // _LIBCPP_DEQUE Index: include/forward_list =================================================================== --- include/forward_list +++ include/forward_list @@ -178,6 +178,10 @@ #include #include +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -1742,6 +1746,16 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template + using forward_list = _VSTD::forward_list<_ValueT, polymorphic_allocator<_ValueT>>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + _LIBCPP_POP_MACROS #endif // _LIBCPP_FORWARD_LIST Index: include/list =================================================================== --- include/list +++ include/list @@ -179,6 +179,10 @@ #include <__debug> +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -2416,6 +2420,16 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template + using list = _VSTD::list<_ValueT, polymorphic_allocator<_ValueT>>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + _LIBCPP_POP_MACROS #endif // _LIBCPP_LIST Index: include/map =================================================================== --- include/map +++ include/map @@ -447,6 +447,10 @@ #include #include +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -1923,4 +1927,17 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template > + using map = _VSTD::map<_KeyT, _ValueT, _CompareT, polymorphic_allocator<_VSTD::pair>>; + + template > + using multimap = _VSTD::multimap<_KeyT, _ValueT, _CompareT, polymorphic_allocator<_VSTD::pair>>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + #endif // _LIBCPP_MAP Index: include/memory_resource =================================================================== --- /dev/null +++ include/memory_resource @@ -0,0 +1,297 @@ +// -*- 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_MEMORY_RESOURCE +#define _LIBCPP_MEMORY_RESOURCE + +/** + memory_resource synopsis + +// C++17 + +namespace std { +namespace pmr { + + // Global memory resources + memory_resource* new_delete_resource() noexcept; + memory_resource* null_memory_resource() noexcept; + + // Pool resource classes + struct pool_options; + class synchronized_pool_resource; + class unsynchronized_pool_resource; + class monotonic_buffer_resource; + +} // namespace pmr +} // namespace std + + */ + +#include <__config> +#include <__functional_base> +#include <__memory_resource_base> +#include +#include +#if !defined(_LIBCPP_HAS_NO_THREADS) +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include <__debug> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +#pragma GCC system_header +#endif + +_LIBCPP_PUSH_MACROS +#include <__undef_macros> + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace pmr +{ + +// 23.12.4, mem.res.global + +_LIBCPP_FUNC_VIS +memory_resource * new_delete_resource() _NOEXCEPT; + +_LIBCPP_FUNC_VIS +memory_resource * null_memory_resource() _NOEXCEPT; + + +// 23.12.5, mem.res.pool + +// 23.12.5.2, mem.res.pool.options + +struct pool_options { + size_t max_blocks_per_chunk = 0; + size_t largest_required_pool_block = 0; +}; + +// 23.12.5.1, mem.res.pool.overview + + +struct __pool_resource_adhoc_pool_header; + +class __pool_resource_adhoc_pool { + using __header = __pool_resource_adhoc_pool_header; + __header *__first_; + +public: + explicit __pool_resource_adhoc_pool() : __first_(nullptr) {} + void release(memory_resource *__upstream); + void *do_allocate(memory_resource *__upstream, size_t __bytes, size_t __align); + void do_deallocate(memory_resource *__upstream, void *__p, size_t __bytes, size_t __align); +}; + +class __pool_resource_fixed_pool; + +class _LIBCPP_TYPE_VIS unsynchronized_pool_resource : public memory_resource +{ + static const size_t __smallest_block_size = 8; + static const int __log2_smallest_block_size = 3; + + size_t __pool_block_size(int __i) const; + int __pool_index(size_t __bytes, size_t __align) const; + +public: + unsynchronized_pool_resource(const pool_options& __opts, memory_resource* __upstream); + + _LIBCPP_INLINE_VISIBILITY + unsynchronized_pool_resource() + : unsynchronized_pool_resource(pool_options(), get_default_resource()) {} + + _LIBCPP_INLINE_VISIBILITY + explicit unsynchronized_pool_resource(memory_resource* __upstream) + : unsynchronized_pool_resource(pool_options(), __upstream) {} + + _LIBCPP_INLINE_VISIBILITY + explicit unsynchronized_pool_resource(const pool_options& __opts) + : unsynchronized_pool_resource(__opts, get_default_resource()) {} + + unsynchronized_pool_resource(const unsynchronized_pool_resource&) = delete; + + virtual ~unsynchronized_pool_resource(); + + unsynchronized_pool_resource& operator=(const unsynchronized_pool_resource&) = delete; + + void release(); + + _LIBCPP_INLINE_VISIBILITY + memory_resource* upstream_resource() const + { return __res_; } + + _LIBCPP_INLINE_VISIBILITY + pool_options options() const + { return __options_; } + +protected: + void* do_allocate(size_t __bytes, size_t __align); + + void do_deallocate(void* __p, size_t __bytes, size_t __align); + + _LIBCPP_INLINE_VISIBILITY + bool do_is_equal(const memory_resource& __other) const _NOEXCEPT + { return this == _VSTD::addressof(__other); } + +private: + memory_resource *__res_; + __pool_resource_adhoc_pool __adhoc_pool_; + __pool_resource_fixed_pool *__fixed_pools_; + int __num_fixed_pools_; + pool_options __options_; +}; + +class _LIBCPP_TYPE_VIS synchronized_pool_resource : public memory_resource +{ +public: + synchronized_pool_resource(const pool_options& __opts, memory_resource* __upstream) + : __unsync_(__opts, __upstream) {} + + _LIBCPP_INLINE_VISIBILITY + synchronized_pool_resource() + : synchronized_pool_resource(pool_options(), get_default_resource()) {} + + _LIBCPP_INLINE_VISIBILITY + explicit synchronized_pool_resource(memory_resource* __upstream) + : synchronized_pool_resource(pool_options(), __upstream) {} + + _LIBCPP_INLINE_VISIBILITY + explicit synchronized_pool_resource(const pool_options& __opts) + : synchronized_pool_resource(__opts, get_default_resource()) {} + + synchronized_pool_resource(const synchronized_pool_resource&) = delete; + + virtual ~synchronized_pool_resource(); + + synchronized_pool_resource& operator=(const synchronized_pool_resource&) = delete; + + void release() { +#if !defined(_LIBCPP_HAS_NO_THREADS) + unique_lock __lk(__mut_); +#endif + __unsync_.release(); + } + + _LIBCPP_INLINE_VISIBILITY + memory_resource* upstream_resource() const + { return __unsync_.upstream_resource(); } + + _LIBCPP_INLINE_VISIBILITY + pool_options options() const + { return __unsync_.options(); } + +protected: + void* do_allocate(size_t __bytes, size_t __align) { +#if !defined(_LIBCPP_HAS_NO_THREADS) + unique_lock __lk(__mut_); +#endif + return __unsync_.allocate(__bytes, __align); + } + + void do_deallocate(void* __p, size_t __bytes, size_t __align) { +#if !defined(_LIBCPP_HAS_NO_THREADS) + unique_lock __lk(__mut_); +#endif + return __unsync_.deallocate(__p, __bytes, __align); + } + + _LIBCPP_INLINE_VISIBILITY + bool do_is_equal(const memory_resource& __other) const _NOEXCEPT + { return this == _VSTD::addressof(__other); } + +private: +#if !defined(_LIBCPP_HAS_NO_THREADS) + mutex __mut_; +#endif + unsynchronized_pool_resource __unsync_; +}; + +// 23.12.6, mem.res.monotonic.buffer + +struct __monotonic_buffer_header { + void *__start_; + __monotonic_buffer_header *__next_; + size_t __capacity_; + size_t __alignment_; + size_t __used_; +}; + +class _LIBCPP_TYPE_VIS monotonic_buffer_resource : public memory_resource +{ + static const size_t __default_buffer_capacity = 1024; + static const size_t __default_buffer_alignment = 16; + +public: + _LIBCPP_INLINE_VISIBILITY + explicit monotonic_buffer_resource(memory_resource* __upstream) + : monotonic_buffer_resource(nullptr, __default_buffer_capacity, __upstream) {} + + _LIBCPP_INLINE_VISIBILITY + monotonic_buffer_resource(size_t __initial_size, memory_resource* __upstream) + : monotonic_buffer_resource(nullptr, __initial_size, __upstream) {} + + monotonic_buffer_resource(void* __buffer, size_t __buffer_size, memory_resource* __upstream); + + _LIBCPP_INLINE_VISIBILITY + monotonic_buffer_resource() + : monotonic_buffer_resource(get_default_resource()) {} + + _LIBCPP_INLINE_VISIBILITY + explicit monotonic_buffer_resource(size_t __initial_size) + : monotonic_buffer_resource(__initial_size, get_default_resource()) {} + + _LIBCPP_INLINE_VISIBILITY + monotonic_buffer_resource(void* __buffer, size_t __buffer_size) + : monotonic_buffer_resource(__buffer, __buffer_size, get_default_resource()) {} + + _LIBCPP_INLINE_VISIBILITY + monotonic_buffer_resource(const monotonic_buffer_resource&) = delete; + + virtual ~monotonic_buffer_resource(); + + monotonic_buffer_resource& operator=(const monotonic_buffer_resource&) = delete; + + void release(); + + _LIBCPP_INLINE_VISIBILITY + memory_resource* upstream_resource() const + { return __res_; } + +protected: + void* do_allocate(size_t __bytes, size_t __alignment); + + _LIBCPP_INLINE_VISIBILITY + void do_deallocate(void*, size_t, size_t) + {} + + _LIBCPP_INLINE_VISIBILITY + bool do_is_equal(const memory_resource& __other) const _NOEXCEPT + { return this == _VSTD::addressof(__other); } + +private: + __monotonic_buffer_header __original_; + memory_resource* __res_; + size_t __next_buffer_size_; +}; + +} // namespace pmr + +_LIBCPP_END_NAMESPACE_STD + +_LIBCPP_POP_MACROS + +#endif /* _LIBCPP_MEMORY_RESOURCE */ Index: include/module.modulemap =================================================================== --- include/module.modulemap +++ include/module.modulemap @@ -337,6 +337,10 @@ header "memory" export * } + module memory_resource { + header "memory_resource" + export * + } module mutex { header "mutex" export * Index: include/regex =================================================================== --- include/regex +++ include/regex @@ -765,6 +765,10 @@ #include #include +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -6598,6 +6602,21 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template + using match_results = _VSTD::match_results<_BidirT, polymorphic_allocator<_VSTD::sub_match<_BidirT>>>; + + using cmatch = match_results; + using wcmatch = match_results; + using smatch = match_results<_VSTD::pmr::string::const_iterator>; + using wsmatch = match_results<_VSTD::pmr::wstring::const_iterator>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + _LIBCPP_POP_MACROS #endif // _LIBCPP_REGEX Index: include/set =================================================================== --- include/set +++ include/set @@ -389,6 +389,10 @@ #include <__tree> #include +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -1215,4 +1219,17 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template > + using set = _VSTD::set<_KeyT, _CompareT, polymorphic_allocator<_KeyT>>; + + template > + using multiset = _VSTD::multiset<_KeyT, _CompareT, polymorphic_allocator<_KeyT>>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + #endif // _LIBCPP_SET Index: include/string =================================================================== --- include/string +++ include/string @@ -500,6 +500,10 @@ #include <__debug> +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -4111,6 +4115,21 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template> + using basic_string = _VSTD::basic_string<_CharT, _TraitsT, polymorphic_allocator<_CharT>>; + + using string = basic_string; + using u16string = basic_string; + using u32string = basic_string; + using wstring = basic_string; +} +_LIBCPP_END_NAMESPACE_STD +#endif + _LIBCPP_POP_MACROS #endif // _LIBCPP_STRING Index: include/unordered_map =================================================================== --- include/unordered_map +++ include/unordered_map @@ -371,6 +371,10 @@ #include #include +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #include <__debug> #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) @@ -2040,4 +2044,17 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template , class _PredT = _VSTD::equal_to<_KeyT>> + using unordered_map = _VSTD::unordered_map<_KeyT, _ValueT, _HashT, _PredT, polymorphic_allocator<_VSTD::pair>>; + + template , class _PredT = _VSTD::equal_to<_KeyT>> + using unordered_multimap = _VSTD::unordered_multimap<_KeyT, _ValueT, _HashT, _PredT, polymorphic_allocator<_VSTD::pair>>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + #endif // _LIBCPP_UNORDERED_MAP Index: include/unordered_set =================================================================== --- include/unordered_set +++ include/unordered_set @@ -325,6 +325,10 @@ #include <__debug> +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -1347,4 +1351,17 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template , class _PredT = _VSTD::equal_to<_KeyT>> + using unordered_set = _VSTD::unordered_set<_KeyT, _HashT, _PredT, polymorphic_allocator<_KeyT>>; + + template , class _PredT = _VSTD::equal_to<_KeyT>> + using unordered_multiset = _VSTD::unordered_multiset<_KeyT, _HashT, _PredT, polymorphic_allocator<_KeyT>>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + #endif // _LIBCPP_UNORDERED_SET Index: include/vector =================================================================== --- include/vector +++ include/vector @@ -277,6 +277,10 @@ #include <__debug> +#if _LIBCPP_STD_VER > 14 +#include <__memory_resource_base> +#endif + #if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) #pragma GCC system_header #endif @@ -3363,6 +3367,16 @@ _LIBCPP_END_NAMESPACE_STD +#if _LIBCPP_STD_VER > 14 +_LIBCPP_BEGIN_NAMESPACE_STD +namespace pmr +{ + template + using vector = _VSTD::vector<_ValueT, polymorphic_allocator<_ValueT>>; +} +_LIBCPP_END_NAMESPACE_STD +#endif + _LIBCPP_POP_MACROS #endif // _LIBCPP_VECTOR Index: src/memory_resource.cpp =================================================================== --- /dev/null +++ src/memory_resource.cpp @@ -0,0 +1,494 @@ +//===------------------------ 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 "memory_resource" + +#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER +#include "atomic" +#endif +#include "memory" +#if !defined(_LIBCPP_HAS_NO_THREADS) +#include "mutex" +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +namespace pmr { + +// memory_resource + +// new_delete_resource() + +class _LIBCPP_TYPE_VIS __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 _VSTD::__libcpp_allocate(__size, __align); /* FIXME */} + + virtual void do_deallocate(void * __p, size_t, size_t __align) + { _VSTD::__libcpp_deallocate(__p, __align); /* FIXME */ } + + virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT + { return &__other == this; } +}; + +// null_memory_resource() + +class _LIBCPP_TYPE_VIS __null_memory_resource_imp + : public memory_resource +{ +public: + ~__null_memory_resource_imp() = default; + +protected: + virtual void* do_allocate(size_t, size_t) { + __throw_bad_alloc(); + } + virtual void do_deallocate(void *, size_t, size_t) {} + virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT + { return &__other == this; } +}; + +namespace { + +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. +#if _LIBCPP_STD_VER > 11 +_LIBCPP_SAFE_STATIC +#endif +ResourceInitHelper res_init __attribute__((init_priority (101))); + +} // end namespace + + +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 + _LIBCPP_SAFE_STATIC 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); + } +#elif !defined(_LIBCPP_HAS_NO_THREADS) + _LIBCPP_SAFE_STATIC 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; + } +#else + _LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res; + if (set) { + new_res = new_res ? new_res : new_delete_resource(); + memory_resource * old_res = res; + res = new_res; + return old_res; + } else { + 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); +} + +// 23.12.5, mem.res.pool + +static size_t roundup(size_t count, size_t alignment) +{ + size_t mask = alignment - 1; + return (count + mask) & ~mask; +} + +struct __pool_resource_adhoc_pool_header { + size_t bytes; + size_t alignment; + void *allocation; + __pool_resource_adhoc_pool_header *next; +}; + +void __pool_resource_adhoc_pool::release(memory_resource *upstream) +{ + while (__first_ != nullptr) { + __header *next = __first_->next; + upstream->deallocate(__first_->allocation, __first_->bytes, __first_->alignment); + __first_ = next; + } +} + +void *__pool_resource_adhoc_pool::do_allocate(memory_resource *upstream, size_t bytes, size_t align) +{ + const size_t header_size = sizeof(__header); + const size_t header_align = alignof(__header); + + if (align < header_align) { + align = header_align; + } + + size_t aligned_capacity = roundup(bytes, header_align) + header_size; + + void *result = upstream->allocate(aligned_capacity, align); + + __header *h = (__header *)((char *)result + aligned_capacity - header_size); + h->allocation = result; + h->bytes = aligned_capacity; + h->alignment = align; + h->next = __first_; + __first_ = h; + return result; +} + +void __pool_resource_adhoc_pool::do_deallocate(memory_resource *upstream, void *p, size_t bytes, size_t align) +{ + _LIBCPP_ASSERT(__first_ != nullptr, "deallocating a block that was not allocated with this allocator"); + if (__first_->allocation == p) { + __header *next = __first_->next; + upstream->deallocate(p, bytes, align); + __first_ = next; + } else { + for (__header *h = __first_; h != nullptr; h = h->next) { + if (h->next != nullptr && h->next->allocation == p) { + __header *next = h->next->next; + upstream->deallocate(p, bytes, align); + h->next = next; + return; + } + } + _LIBCPP_ASSERT(false, "deallocating a block that was not allocated with this allocator"); + } +} + +struct __pool_resource_vacancy_header { + __pool_resource_vacancy_header *next_vacancy; +}; + +struct __pool_resource_fixed_pool_header { + __pool_resource_vacancy_header *first_vacancy; + size_t bytes; + size_t alignment; + void *allocation; + __pool_resource_fixed_pool_header *next; + + bool allocation_contains(const char *p) const { + // TODO: This part technically relies on undefined behavior. + return allocation <= p && p < ((char*)allocation + bytes); + } +}; + +class __pool_resource_fixed_pool { + using __header = __pool_resource_fixed_pool_header; + __header *__first_; + +public: + explicit __pool_resource_fixed_pool() : __first_(nullptr) {} + void release(memory_resource *upstream); + void *try_allocate_from_vacancies(); + void *do_allocate_with_new_chunk(memory_resource *upstream, size_t block_size); + void do_evacuate(void *__p); + + static const size_t __default_alignment = alignof(max_align_t); +}; + +void __pool_resource_fixed_pool::release(memory_resource *upstream) +{ + while (__first_ != nullptr) { + __header *next = __first_->next; + upstream->deallocate(__first_->allocation, __first_->bytes, __first_->alignment); + __first_ = next; + } +} + +void *__pool_resource_fixed_pool::try_allocate_from_vacancies() +{ + for (__header *h = __first_; h != nullptr; h = h->next) { + if (h->first_vacancy != nullptr) { + void *result = h->first_vacancy; + h->first_vacancy = h->first_vacancy->next_vacancy; + return result; + } + } + return nullptr; +} + +void *__pool_resource_fixed_pool::do_allocate_with_new_chunk(memory_resource *upstream, size_t block_size) +{ + static_assert(__default_alignment >= alignof(std::max_align_t), ""); + static_assert(__default_alignment >= alignof(__header), ""); + static_assert(__default_alignment >= alignof(__pool_resource_vacancy_header), ""); + + const size_t header_size = sizeof(__header); + + size_t aligned_capacity = roundup(block_size, alignof(__header)) + header_size; + + void *result = upstream->allocate(aligned_capacity, __default_alignment); + + __header *h = (__header *)((char *)result + aligned_capacity - header_size); + h->allocation = result; + h->bytes = aligned_capacity; + h->alignment = __default_alignment; + h->next = __first_; + h->first_vacancy = nullptr; + __first_ = h; + return result; +} + +void __pool_resource_fixed_pool::do_evacuate(void *p) +{ + _LIBCPP_ASSERT(__first_ != nullptr, "deallocating a block that was not allocated with this allocator"); + for (__header *h = __first_; h != nullptr; h = h->next) { + if (h->allocation_contains((char*)p)) { + __pool_resource_vacancy_header *v = (__pool_resource_vacancy_header *)(p); + v->next_vacancy = h->first_vacancy; + h->first_vacancy = v; + return; + } + } + _LIBCPP_ASSERT(false, "deallocating a block that was not allocated with this allocator"); +} + +size_t unsynchronized_pool_resource::__pool_block_size(int i) const +{ + return size_t(1) << (i + __log2_smallest_block_size); +} + +int unsynchronized_pool_resource::__pool_index(size_t bytes, size_t align) const +{ + if (align > alignof(std::max_align_t) || bytes > (1 << __num_fixed_pools_)) { + return __num_fixed_pools_; + } else if (bytes <= __smallest_block_size) { + return 0; + } else { + int i = 0; + bytes -= 1; + bytes >>= __log2_smallest_block_size; + while (bytes != 0) { + bytes >>= 1; + i += 1; + } + return i; + } +} + +unsynchronized_pool_resource::unsynchronized_pool_resource(const pool_options& opts, memory_resource* upstream) + : __res_(upstream), __fixed_pools_(nullptr), __options_(opts) +{ + if (__options_.largest_required_pool_block == 0) { + __options_.largest_required_pool_block = (size_t(1) << 20); + } else if (__options_.largest_required_pool_block < __smallest_block_size) { + __options_.largest_required_pool_block = __smallest_block_size; + } else if (__options_.largest_required_pool_block > (size_t(1) << 30)) { + __options_.largest_required_pool_block = (size_t(1) << 30); + } + __num_fixed_pools_ = 1; + size_t capacity = __smallest_block_size; + while (capacity < __options_.largest_required_pool_block) { + capacity <<= 1; + __num_fixed_pools_ += 1; + } + + __options_.max_blocks_per_chunk = 0; +} + +unsynchronized_pool_resource::~unsynchronized_pool_resource() +{ + release(); +} + +void unsynchronized_pool_resource::release() +{ + __adhoc_pool_.release(__res_); + if (__fixed_pools_ != nullptr) { + const int n = __num_fixed_pools_; + for (int i=0; i < n; ++i) { + __fixed_pools_[i].release(__res_); + } + __res_->deallocate(__fixed_pools_, __num_fixed_pools_ * sizeof(__pool_resource_fixed_pool), alignof(__pool_resource_fixed_pool)); + __fixed_pools_ = nullptr; + } +} + +void* unsynchronized_pool_resource::do_allocate(size_t bytes, size_t align) +{ + // A pointer to allocated storage (6.6.4.4.1) with a size of at least bytes. + // The size and alignment of the allocated memory shall meet the requirements for + // a class derived from memory_resource (23.12). + // If the pool selected for a block of size bytes is unable to satisfy the memory request + // from its own internal data structures, it will call upstream_resource()->allocate() + // to obtain more memory. If bytes is larger than that which the largest pool can handle, + // then memory will be allocated using upstream_resource()->allocate(). + + int i = __pool_index(bytes, align); + if (i == __num_fixed_pools_) { + return __adhoc_pool_.do_allocate(__res_, bytes, align); + } else { + if (__fixed_pools_ == nullptr) { + using P = __pool_resource_fixed_pool; + __fixed_pools_ = (P*)__res_->allocate(__num_fixed_pools_ * sizeof(P), alignof(P)); + P *first = __fixed_pools_; + P *last = __fixed_pools_ + __num_fixed_pools_; + for (P *pool = first; pool != last; ++pool) { + ::new((void*)pool) P; + } + } + void *result = __fixed_pools_[i].try_allocate_from_vacancies(); + if (result == nullptr) { + result = __fixed_pools_[i].do_allocate_with_new_chunk(__res_, __pool_block_size(i)); + } + return result; + } +} + +void unsynchronized_pool_resource::do_deallocate(void* p, size_t bytes, size_t align) +{ + // Returns the memory at p to the pool. It is unspecified if, or under what circumstances, + // this operation will result in a call to upstream_resource()->deallocate(). + + int i = __pool_index(bytes, align); + if (i == __num_fixed_pools_) { + return __adhoc_pool_.do_deallocate(__res_, p, bytes, align); + } else { + _LIBCPP_ASSERT(__fixed_pools_ != nullptr, "deallocating a block that was not allocated with this allocator"); + __fixed_pools_[i].do_evacuate(p); + } +} + +// 23.12.6, mem.res.monotonic.buffer + +static void *try_allocate_from_chunk(__monotonic_buffer_header *header, size_t bytes, size_t align) +{ + if (!header || !header->__start_) return nullptr; + if (header->__capacity_ < bytes) return nullptr; + void *new_ptr = static_cast(header->__start_) + header->__used_; + size_t new_capacity = (header->__capacity_ - header->__used_); + void *aligned_ptr = _VSTD::align(align, bytes, new_ptr, new_capacity); + if (aligned_ptr == nullptr) { + return nullptr; + } + header->__used_ = (header->__capacity_ - new_capacity) + bytes; + return aligned_ptr; +} + +monotonic_buffer_resource::monotonic_buffer_resource(void* buffer, size_t buffer_size, memory_resource* upstream) + : __res_(upstream) +{ + __original_.__start_ = buffer; + __original_.__next_ = nullptr; + __original_.__capacity_ = buffer_size; + __original_.__alignment_ = 1; + __original_.__used_ = 0; + __next_buffer_size_ = buffer_size >= 1 ? buffer_size : 1; +} + +monotonic_buffer_resource::~monotonic_buffer_resource() +{ + release(); +} + +void monotonic_buffer_resource::release() +{ + const size_t header_size = sizeof(__monotonic_buffer_header); + + __original_.__used_ = 0; + while (__original_.__next_ != nullptr) { + __monotonic_buffer_header *header = __original_.__next_; + __monotonic_buffer_header *next_header = header->__next_; + size_t aligned_capacity = header->__capacity_ + header_size; + __res_->deallocate(header->__start_, aligned_capacity, header->__alignment_); + __original_.__next_ = next_header; + } +} + +void* monotonic_buffer_resource::do_allocate(size_t bytes, size_t align) +{ + if (void *result = try_allocate_from_chunk(&__original_, bytes, align)) { + return result; + } + if (void *result = try_allocate_from_chunk(__original_.__next_, bytes, align)) { + return result; + } + // Allocate a brand-new chunk. + const size_t header_size = sizeof(__monotonic_buffer_header); + const size_t header_align = alignof(__monotonic_buffer_header); + + if (align < header_align) { + align = header_align; + } + + size_t aligned_capacity = roundup(bytes, header_align) + header_size; + + if (aligned_capacity < __next_buffer_size_) { + aligned_capacity = roundup(__next_buffer_size_ - header_size, header_align) + header_size; + } + + void *result = __res_->allocate(aligned_capacity, align); + __monotonic_buffer_header *header = (__monotonic_buffer_header *)((char *)result + aligned_capacity - header_size); + header->__start_ = result; + header->__capacity_ = aligned_capacity - header_size; + header->__alignment_ = align; + header->__used_ = 0; + header->__next_ = __original_.__next_; + __original_.__next_ = header; + + size_t prospective_next_buffer_size = (__next_buffer_size_ * 5) / 4; + if (prospective_next_buffer_size <= __next_buffer_size_) { + prospective_next_buffer_size = __next_buffer_size_ + 1; + } + __next_buffer_size_ = prospective_next_buffer_size; + + return try_allocate_from_chunk(__original_.__next_, bytes, align); +} + + +} // namespace pmr + +_LIBCPP_END_NAMESPACE_STD Index: test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp =================================================================== --- test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp +++ test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp @@ -46,7 +46,7 @@ #include #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/db_deallocate.pass.cpp =================================================================== --- test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/db_deallocate.pass.cpp +++ test/libcxx/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/db_deallocate.pass.cpp @@ -23,7 +23,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp =================================================================== --- test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp +++ test/libcxx/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/db_deallocate.pass.cpp @@ -23,7 +23,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/default.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/default.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/default.pass.cpp @@ -20,7 +20,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/memory_resource_convert.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/memory_resource_convert.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.ctor/memory_resource_convert.pass.cpp @@ -19,7 +19,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/equal.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/equal.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/equal.pass.cpp @@ -23,7 +23,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/not_equal.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/not_equal.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.eq/not_equal.pass.cpp @@ -23,7 +23,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/allocate.pass.cpp @@ -24,7 +24,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp @@ -25,7 +25,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" #include "uses_alloc_types.hpp" #include "controlled_allocators.hpp" #include "test_allocator.h" Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp @@ -25,7 +25,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" #include "uses_alloc_types.hpp" #include "controlled_allocators.hpp" #include "test_allocator.h" Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp @@ -25,7 +25,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" #include "uses_alloc_types.hpp" #include "controlled_allocators.hpp" #include "test_allocator.h" Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp @@ -26,7 +26,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" #include "uses_alloc_types.hpp" #include "controlled_allocators.hpp" #include "test_allocator.h" Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp @@ -23,7 +23,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" #include "uses_alloc_types.hpp" #include "controlled_allocators.hpp" #include "test_allocator.h" Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/deallocate.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/deallocate.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/deallocate.pass.cpp @@ -20,7 +20,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_copy.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_copy.pass.cpp +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_copy.pass.cpp @@ -18,7 +18,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_move.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_move.pass.cpp +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/alloc_move.pass.cpp @@ -18,7 +18,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/default.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/default.pass.cpp +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.ctor/default.pass.cpp @@ -20,7 +20,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_allocate_and_deallocate.pass.cpp @@ -24,7 +24,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_is_equal.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_is_equal.pass.cpp +++ test/std/experimental/memory/memory.resource.adaptor/memory.resource.adaptor.mem/do_is_equal.pass.cpp @@ -19,7 +19,7 @@ #include #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" using std::size_t; namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp +++ test/std/experimental/memory/memory.resource.global/default_resource.pass.cpp @@ -33,7 +33,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" using namespace std::experimental::pmr; Index: test/std/experimental/memory/memory.resource/memory.resource.eq/equal.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource/memory.resource.eq/equal.pass.cpp +++ test/std/experimental/memory/memory.resource/memory.resource.eq/equal.pass.cpp @@ -18,7 +18,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.resource/memory.resource.eq/not_equal.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource/memory.resource.eq/not_equal.pass.cpp +++ test/std/experimental/memory/memory.resource/memory.resource.eq/not_equal.pass.cpp @@ -17,7 +17,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" namespace ex = std::experimental::pmr; Index: test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp +++ test/std/experimental/memory/memory.resource/memory.resource.public/allocate.pass.cpp @@ -28,7 +28,7 @@ #include #include "test_macros.h" -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" using std::experimental::pmr::memory_resource; Index: test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp +++ test/std/experimental/memory/memory.resource/memory.resource.public/deallocate.pass.cpp @@ -27,7 +27,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" using std::experimental::pmr::memory_resource; Index: test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp +++ test/std/experimental/memory/memory.resource/memory.resource.public/dtor.pass.cpp @@ -23,7 +23,7 @@ #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" using std::experimental::pmr::memory_resource; Index: test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp =================================================================== --- test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp +++ test/std/experimental/memory/memory.resource/memory.resource.public/is_equal.pass.cpp @@ -25,7 +25,7 @@ #include #include #include -#include "test_memory_resource.hpp" +#include "test_experimental_memory_resource.hpp" using std::experimental::pmr::memory_resource; Index: test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.ctor/assign.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.ctor/assign.pass.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 + +// + +// template class polymorphic_allocator + +// polymorphic_allocator operator=(polymorphic_allocator const &) = delete + +#include +#include +#include + +int main() +{ + typedef std::pmr::polymorphic_allocator T; + static_assert(!std::is_copy_assignable::value, ""); + static_assert(!std::is_move_assignable::value, ""); +} Index: test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.ctor/copy.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.ctor/copy.pass.cpp @@ -0,0 +1,46 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// polymorphic_allocator::polymorphic_allocator(polymorphic_allocator const &); + +#include +#include +#include + +int main() +{ + typedef std::pmr::polymorphic_allocator A1; + { + static_assert( + std::is_copy_constructible::value, "" + ); + static_assert( + std::is_move_constructible::value, "" + ); + } + // copy + { + A1 const a((std::pmr::memory_resource*)42); + A1 const a2(a); + assert(a.resource() == a2.resource()); + } + // move + { + A1 a((std::pmr::memory_resource*)42); + A1 a2(std::move(a)); + assert(a.resource() == a2.resource()); + assert(a2.resource() == (std::pmr::memory_resource*)42); + } +} Index: test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.ctor/default.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.ctor/memory_resource_convert.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.ctor/other_alloc.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.eq/equal.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.eq/not_equal.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/allocate.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp @@ -0,0 +1,137 @@ +//===----------------------------------------------------------------------===// +// +// 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 "test_macros.h" +#include "test_memory_resource.hpp" +#include "uses_alloc_types.hpp" +#include "controlled_allocators.hpp" +#include "test_allocator.h" + + +template +bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect, + std::pair const& p) +{ + using P = std::pair; + TestResource R; + std::pmr::memory_resource * M = &R; + std::pmr::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 +void test_pmr_not_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_None, UA_None, p))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_None, UA_None, p))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, p))); + } +} + +template +struct Print; + +int main() +{ + using PMR = std::pmr::memory_resource*; + using PMA = std::pmr::polymorphic_allocator; + { + int x = 42; + int y = 42; + const std::pair p(x, y); + test_pmr_not_uses_allocator(p); + test_pmr_uses_allocator(p); + } + { + int x = 42; + int y = 42; + const std::pair p(x, std::move(y)); + test_pmr_not_uses_allocator(p); + test_pmr_uses_allocator(p); + } +} Index: test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_rvalue.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_rvalue.pass.cpp @@ -0,0 +1,132 @@ +//===----------------------------------------------------------------------===// +// +// 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 "test_macros.h" +#include "test_memory_resource.hpp" +#include "uses_alloc_types.hpp" +#include "controlled_allocators.hpp" +#include "test_allocator.h" + + +template +bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect, + std::pair&& p) +{ + using P = std::pair; + TestResource R; + std::pmr::memory_resource * M = &R; + std::pmr::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)))); + } +} + +template +void test_pmr_not_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_None, UA_None, std::move(p)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_None, UA_None, std::move(p)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, std::move(p)))); + } +} + +int main() +{ + using PMR = std::pmr::memory_resource*; + using PMA = std::pmr::polymorphic_allocator; + { + int x = 42; + int y = 42; + std::pair p(x, std::move(y)); + test_pmr_not_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_not_uses_allocator(std::move(p)); + test_pmr_uses_allocator(std::move(p)); + } +} Index: test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_values.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_values.pass.cpp @@ -0,0 +1,138 @@ +//===----------------------------------------------------------------------===// +// +// 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 "test_macros.h" +#include "test_memory_resource.hpp" +#include "uses_alloc_types.hpp" +#include "controlled_allocators.hpp" +#include "test_allocator.h" + + +template +bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect, + TT&& t, UU&& u) +{ + using P = std::pair; + TestResource R; + std::pmr::memory_resource * M = &R; + std::pmr::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)))); + } +} + +template +void test_pmr_not_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_None, UA_None, + std::forward(t), std::forward(u)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_None, UA_None, + std::forward(t), std::forward(u)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, + std::forward(t), std::forward(u)))); + } +} + +int main() +{ + using PMR = std::pmr::memory_resource*; + using PMA = std::pmr::polymorphic_allocator; + { + int x = 42; + int y = 42; + test_pmr_not_uses_allocator(x, std::move(y)); + test_pmr_uses_allocator(x, std::move(y)); + } + { + int x = 42; + const int y = 42; + test_pmr_not_uses_allocator(std::move(x), y); + test_pmr_uses_allocator(std::move(x), y); + } +} Index: test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair.pass.cpp @@ -0,0 +1,152 @@ +//===----------------------------------------------------------------------===// +// +// 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 "test_macros.h" +#include "test_memory_resource.hpp" +#include "uses_alloc_types.hpp" +#include "controlled_allocators.hpp" +#include "test_allocator.h" + +template +bool doTest(UsesAllocatorType TExpect, UsesAllocatorType UExpect, + std::tuple ttuple, std::tuple utuple) +{ + using P = std::pair; + TestResource R; + std::pmr::memory_resource * M = &R; + std::pmr::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)))); + } +} + +template +void test_pmr_not_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_None, UA_None, + std::move(ttuple), std::move(utuple)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_None, UA_None, + std::move(ttuple), std::move(utuple)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, + std::move(ttuple), std::move(utuple)))); + } +} + +int main() +{ + using PMR = std::pmr::memory_resource*; + using PMA = std::pmr::polymorphic_allocator; + { + std::tuple<> t1; + test_pmr_not_uses_allocator(t1, t1); + test_pmr_uses_allocator(t1, t1); + } + { + std::tuple t1(42); + std::tuple<> t2; + test_pmr_not_uses_allocator(t1, t2); + test_pmr_not_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_not_uses_allocator( t1, std::move(t2)); + test_pmr_not_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_not_uses_allocator( t1, std::move(t2)); + test_pmr_not_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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair_evil.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_piecewise_pair_evil.pass.cpp @@ -0,0 +1,139 @@ +//===----------------------------------------------------------------------===// +// +// 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 "test_macros.h" + +template +struct EvilAlloc { + explicit EvilAlloc() : inner_(std::pmr::null_memory_resource()) {} + + EvilAlloc(std::pmr::polymorphic_allocator & a) : inner_(a) {} + EvilAlloc(std::pmr::polymorphic_allocator && a) : inner_(a) {} + EvilAlloc(std::pmr::polymorphic_allocator const & a) = delete; + EvilAlloc(std::pmr::polymorphic_allocator const && a) = delete; + + using value_type = T; + template EvilAlloc(EvilAlloc const & rhs) : inner_(rhs.inner_) {} + + std::pmr::polymorphic_allocator inner_; +}; + +struct WidgetV0 { + WidgetV0(int v) : value_(v) {} + + bool holds(int v, const std::pmr::polymorphic_allocator&) const { + return value_ == v; + } +private: + int value_; +}; + +struct WidgetV1 { + using allocator_type = EvilAlloc; + + WidgetV1(int v) : value_(v), alloc_() {} + WidgetV1(std::allocator_arg_t, EvilAlloc a, int v) : value_(v), alloc_(a) {} + + bool holds(int v, const std::pmr::polymorphic_allocator& a) const { + return value_ == v && alloc_.inner_ == a; + } +private: + int value_; + EvilAlloc alloc_; +}; + +struct WidgetV2 { + using allocator_type = EvilAlloc; + + WidgetV2(int v) : value_(v), alloc_() {} + WidgetV2(int v, EvilAlloc a) : value_(v), alloc_(a) {} + + bool holds(int v, std::pmr::polymorphic_allocator a) const { + return value_ == v && alloc_.inner_ == a; + } +private: + int value_; + EvilAlloc alloc_; +}; + +struct WidgetV3 { + using allocator_type = EvilAlloc; + + WidgetV3(int v) : value_(v), alloc_() {} + WidgetV3(std::allocator_arg_t, EvilAlloc a, int v) : value_(v), alloc_(a) {} + WidgetV3(int v, EvilAlloc a) : value_(v), alloc_(a) {} + + bool holds(int v, std::pmr::polymorphic_allocator a) const { + return value_ == v && alloc_.inner_ == a; + } +private: + int value_; + EvilAlloc alloc_; +}; + +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); + +template +void test_evil() +{ + using PMA = std::pmr::polymorphic_allocator; + PMA pma(std::pmr::new_delete_resource()); + { + using Pair = std::pair; + void *where = std::malloc(sizeof (Pair)); + Pair *p = (Pair *)where; + pma.construct(p, std::piecewise_construct, std::make_tuple(42), std::make_tuple(42)); + assert(p->first.holds(42, pma)); + assert(p->second.holds(42, pma)); + pma.destroy(p); + std::free(where); + } +} + +int main() +{ + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); +} Index: test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_types.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_types.pass.cpp @@ -0,0 +1,188 @@ +//===----------------------------------------------------------------------===// +// +// 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 "test_macros.h" +#include "test_memory_resource.hpp" +#include "uses_alloc_types.hpp" +#include "controlled_allocators.hpp" +#include "test_allocator.h" + +template +struct PMATest { + TestResource R; + std::pmr::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); + std::pmr::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 preferred 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 PMR = std::pmr::memory_resource*; + using PMA = std::pmr::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(value); + test_pmr_uses_alloc(cvalue); + test_pmr_uses_alloc(cvalue, std::move(value)); + } + { + STDA std_alloc; + TESTA test_alloc(42); + PMR mem_res = std::pmr::new_delete_resource(); + + test_non_pmr_uses_alloc(mem_res); + test_non_pmr_uses_alloc(std_alloc); + test_non_pmr_uses_alloc(test_alloc); + test_non_pmr_uses_alloc(mem_res, value); + test_non_pmr_uses_alloc(std_alloc, value); + test_non_pmr_uses_alloc(test_alloc, value); + test_non_pmr_uses_alloc(mem_res, cvalue); + test_non_pmr_uses_alloc(std_alloc, cvalue); + test_non_pmr_uses_alloc(test_alloc, cvalue); + test_non_pmr_uses_alloc(mem_res, cvalue, std::move(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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/deallocate.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/destroy.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/resource.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/select_on_container_copy_construction.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.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::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/utilities/utility/mem.res/mem.res.aliases/header_deque_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_deque_synop.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// namespace std::pmr { +// template +// using deque = +// ::std::deque> +// +// } // namespace std::pmr + +#include +#include +#include +#include + +int main() +{ + using StdDeque = std::deque>; + using PmrDeque = std::pmr::deque; + static_assert(std::is_same::value, ""); + PmrDeque d; + assert(d.get_allocator().resource() == std::pmr::get_default_resource()); +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_forward_list_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_forward_list_synop.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// namespace std::pmr { +// template +// using forward_list = +// ::std::forward_list> +// +// } // namespace std::pmr + +#include +#include +#include +#include + +int main() +{ + using StdForwardList = std::forward_list>; + using PmrForwardList = std::pmr::forward_list; + static_assert(std::is_same::value, ""); + PmrForwardList d; + assert(d.get_allocator().resource() == std::pmr::get_default_resource()); +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_list_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_list_synop.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// namespace std::pmr { +// template +// using list = +// ::std::list> +// +// } // namespace std::pmr + +#include +#include +#include +#include + +int main() +{ + using StdList = std::list>; + using PmrList = std::pmr::list; + static_assert(std::is_same::value, ""); + PmrList d; + assert(d.get_allocator().resource() == std::pmr::get_default_resource()); +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_list_synop2.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_list_synop2.pass.cpp @@ -0,0 +1,28 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: c++17 + +// + +// namespace std::pmr { +// +// typedef ... list +// +// } // namespace std::pmr + +#include + +int main() +{ + { + // Check that std::pmr::list is usable without . + std::pmr::list l; + } +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_map_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_map_synop.pass.cpp @@ -0,0 +1,65 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// namespace std::pmr { +// template > +// using map = +// ::std::map>> +// +// template > +// using multimap = +// ::std::multimap>> +// +// } // namespace std::pmr + +#include +#include +#include +#include + +int main() +{ + using K = int; + using V = char; + using DC = std::less; + using OC = std::greater; + using P = std::pair; + { + using StdMap = std::map>; + using PmrMap = std::pmr::map; + static_assert(std::is_same::value, ""); + } + { + using StdMap = std::map>; + using PmrMap = std::pmr::map; + static_assert(std::is_same::value, ""); + } + { + std::pmr::map m; + assert(m.get_allocator().resource() == std::pmr::get_default_resource()); + } + { + using StdMap = std::multimap>; + using PmrMap = std::pmr::multimap; + static_assert(std::is_same::value, ""); + } + { + using StdMap = std::multimap>; + using PmrMap = std::pmr::multimap; + static_assert(std::is_same::value, ""); + } + { + std::pmr::multimap m; + assert(m.get_allocator().resource() == std::pmr::get_default_resource()); + } +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_regex_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_regex_synop.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 + +// + +// namespace std::pmr { +// +// template +// using match_results = +// std::match_results>>; +// +// typedef match_results cmatch; +// typedef match_results wcmatch; +// typedef match_results smatch; +// typedef match_results wsmatch; +// +// } // namespace std::pmr + +#include +#include +#include + +template +void test_match_result_typedef() { + using StdMR = std::match_results>>; + using PmrMR = std::pmr::match_results; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); +} + +int main() +{ + { + test_match_result_typedef(); + test_match_result_typedef(); + test_match_result_typedef(); + test_match_result_typedef(); + } + { + // Check that std::match_results has been included and is complete. + std::pmr::smatch s; + assert(s.get_allocator().resource() == std::pmr::get_default_resource()); + } +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_set_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_set_synop.pass.cpp @@ -0,0 +1,63 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// namespace std::pmr { +// template > +// using set = +// ::std::set> +// +// template > +// using multiset = +// ::std::multiset> +// +// } // namespace std::pmr + +#include +#include +#include +#include + +int main() +{ + using V = char; + using DC = std::less; + using OC = std::greater; + { + using StdSet = std::set>; + using PmrSet = std::pmr::set; + static_assert(std::is_same::value, ""); + } + { + using StdSet = std::set>; + using PmrSet = std::pmr::set; + static_assert(std::is_same::value, ""); + } + { + std::pmr::set m; + assert(m.get_allocator().resource() == std::pmr::get_default_resource()); + } + { + using StdSet = std::multiset>; + using PmrSet = std::pmr::multiset; + static_assert(std::is_same::value, ""); + } + { + using StdSet = std::multiset>; + using PmrSet = std::pmr::multiset; + static_assert(std::is_same::value, ""); + } + { + std::pmr::multiset m; + assert(m.get_allocator().resource() == std::pmr::get_default_resource()); + } +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_string_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_string_synop.pass.cpp @@ -0,0 +1,71 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// namespace std::pmr { +// template +// using basic_string = +// ::std::basic_string> +// +// typedef ... string +// typedef ... u16string +// typedef ... u32string +// typedef ... wstring +// +// } // namespace std::pmr + +#include +#include +#include +#include + +#include "constexpr_char_traits.hpp" + +namespace pmr = std::pmr; + +template +void test_string_typedef() { + using StdStr = std::basic_string, + std::pmr::polymorphic_allocator>; + using PmrStr = std::pmr::basic_string; + static_assert(std::is_same::value, ""); + static_assert(std::is_same::value, ""); +} + +template +void test_basic_string_alias() { + using StdStr = std::basic_string>; + using PmrStr = std::pmr::basic_string; + static_assert(std::is_same::value, ""); +} + +int main() +{ + { + test_string_typedef(); + test_string_typedef(); + test_string_typedef(); + test_string_typedef(); + } + { + test_basic_string_alias>(); + test_basic_string_alias>(); + test_basic_string_alias>(); + test_basic_string_alias>(); + } + { + // Check that std::basic_string has been included and is complete. + std::pmr::string s; + assert(s.get_allocator().resource() == std::pmr::get_default_resource()); + } +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_string_synop2.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_string_synop2.pass.cpp @@ -0,0 +1,34 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// REQUIRES: c++17 + +// + +// namespace std::pmr { +// +// typedef ... string +// typedef ... u16string +// typedef ... u32string +// typedef ... wstring +// +// } // namespace std::pmr + +#include + +int main() +{ + { + // Check that std::pmr::string is usable without . + std::pmr::string s; + std::pmr::wstring ws; + std::pmr::u16string u16s; + std::pmr::u32string u32s; + } +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_unordered_map_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_unordered_map_synop.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 + +// + +// namespace std::pmr { +// template , class P = equal_to > +// using unordered_map = +// ::std::unordered_map>> +// +// template , class P = equal_to > +// using unordered_multimap = +// ::std::unordered_multimap>> +// +// } // namespace std::pmr + +#include +#include +#include +#include + +template +struct MyHash : std::hash {}; + +template +struct MyPred : std::equal_to {}; + +int main() +{ + using K = int; + using V = char; + using DH = std::hash; + using MH = MyHash; + using DP = std::equal_to; + using MP = MyPred; + using P = std::pair; + { + using StdMap = std::unordered_map>; + using PmrMap = std::pmr::unordered_map; + static_assert(std::is_same::value, ""); + } + { + using StdMap = std::unordered_map>; + using PmrMap = std::pmr::unordered_map; + static_assert(std::is_same::value, ""); + } + { + using StdMap = std::unordered_map>; + using PmrMap = std::pmr::unordered_map; + static_assert(std::is_same::value, ""); + } + { + std::pmr::unordered_map m; + assert(m.get_allocator().resource() == std::pmr::get_default_resource()); + } + { + using StdMap = std::unordered_multimap>; + using PmrMap = std::pmr::unordered_multimap; + static_assert(std::is_same::value, ""); + } + { + using StdMap = std::unordered_multimap>; + using PmrMap = std::pmr::unordered_multimap; + static_assert(std::is_same::value, ""); + } + { + using StdMap = std::unordered_multimap>; + using PmrMap = std::pmr::unordered_multimap; + static_assert(std::is_same::value, ""); + } + { + std::pmr::unordered_multimap m; + assert(m.get_allocator().resource() == std::pmr::get_default_resource()); + } +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_unordered_set_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_unordered_set_synop.pass.cpp @@ -0,0 +1,81 @@ +//===----------------------------------------------------------------------===// +// +// 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 + +// + +// namespace std::pmr { +// template , class P = equal_to > +// using unordered_set = +// ::std::unordered_set> +// +// template , class P = equal_to > +// using unordered_multiset = +// ::std::unordered_multiset> +// +// } // namespace std::pmr + +#include +#include +#include +#include + +template +struct MyHash : std::hash {}; + +template +struct MyPred : std::equal_to {}; + +int main() +{ + using V = char; + using DH = std::hash; + using MH = MyHash; + using DP = std::equal_to; + using MP = MyPred; + { + using StdSet = std::unordered_set>; + using PmrSet = std::pmr::unordered_set; + static_assert(std::is_same::value, ""); + } + { + using StdSet = std::unordered_set>; + using PmrSet = std::pmr::unordered_set; + static_assert(std::is_same::value, ""); + } + { + using StdSet = std::unordered_set>; + using PmrSet = std::pmr::unordered_set; + static_assert(std::is_same::value, ""); + } + { + std::pmr::unordered_set m; + assert(m.get_allocator().resource() == std::pmr::get_default_resource()); + } + { + using StdSet = std::unordered_multiset>; + using PmrSet = std::pmr::unordered_multiset; + static_assert(std::is_same::value, ""); + } + { + using StdSet = std::unordered_multiset>; + using PmrSet = std::pmr::unordered_multiset; + static_assert(std::is_same::value, ""); + } + { + using StdSet = std::unordered_multiset>; + using PmrSet = std::pmr::unordered_multiset; + static_assert(std::is_same::value, ""); + } + { + std::pmr::unordered_multiset m; + assert(m.get_allocator().resource() == std::pmr::get_default_resource()); + } +} Index: test/std/utilities/utility/mem.res/mem.res.aliases/header_vector_synop.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.aliases/header_vector_synop.pass.cpp @@ -0,0 +1,33 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// namespace std::pmr { +// template +// using vector = +// ::std::vector> +// +// } // namespace std::pmr + +#include +#include +#include +#include + +int main() +{ + using StdVector = std::vector>; + using PmrVector = std::pmr::vector; + static_assert(std::is_same::value, ""); + PmrVector d; + assert(d.get_allocator().resource() == std::pmr::get_default_resource()); +} Index: test/std/utilities/utility/mem.res/mem.res.global/default_resource.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.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::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/utilities/utility/mem.res/mem.res.global/new_delete_resource.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.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::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/utilities/utility/mem.res/mem.res.global/null_memory_resource.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.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::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/utilities/utility/mem.res/mem.res.monotonic.buffer/monotonic_buffer.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/monotonic_buffer.pass.cpp @@ -0,0 +1,408 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class monotonic_buffer_resource + +#include +#include +#include +#include + +#include "count_new.hpp" + +struct assert_on_compare : public std::pmr::memory_resource +{ +protected: + virtual void * do_allocate(size_t, size_t) + { assert(false); } + + virtual void do_deallocate(void *, size_t, size_t) + { assert(false); } + + virtual bool do_is_equal(std::pmr::memory_resource const &) const noexcept + { assert(false); } +}; + +struct repointable_resource : public std::pmr::memory_resource +{ + std::pmr::memory_resource *which; + + explicit repointable_resource(std::pmr::memory_resource *res) : which(res) {} + +protected: + virtual void *do_allocate(size_t size, size_t align) + { return which->allocate(size, align); } + + virtual void do_deallocate(void *p, size_t size, size_t align) + { return which->deallocate(p, size, align); } + + virtual bool do_is_equal(std::pmr::memory_resource const &rhs) const noexcept + { return which->is_equal(rhs); } +}; + +void test_construction_with_default_resource() +{ + std::pmr::memory_resource *expected = std::pmr::null_memory_resource(); + std::pmr::set_default_resource(expected); + { + char buffer[16]; + std::pmr::monotonic_buffer_resource r1; + std::pmr::monotonic_buffer_resource r2(16); + std::pmr::monotonic_buffer_resource r3(buffer, sizeof buffer); + assert(r1.upstream_resource() == expected); + assert(r2.upstream_resource() == expected); + assert(r3.upstream_resource() == expected); + } + + expected = std::pmr::new_delete_resource(); + std::pmr::set_default_resource(expected); + { + char buffer[16]; + std::pmr::monotonic_buffer_resource r1; + std::pmr::monotonic_buffer_resource r2(16); + std::pmr::monotonic_buffer_resource r3(buffer, sizeof buffer); + assert(r1.upstream_resource() == expected); + assert(r2.upstream_resource() == expected); + assert(r3.upstream_resource() == expected); + } +} + +void test_construction_without_buffer() +{ + // Constructing a monotonic_buffer_resource should not cause allocations + // by itself; the resource should wait to allocate until an allocation is + // requested. + + globalMemCounter.reset(); + std::pmr::set_default_resource(std::pmr::new_delete_resource()); + + std::pmr::monotonic_buffer_resource r1; + assert(globalMemCounter.checkNewCalledEq(0)); + + std::pmr::monotonic_buffer_resource r2(1024); + assert(globalMemCounter.checkNewCalledEq(0)); + + std::pmr::monotonic_buffer_resource r3(1024, std::pmr::new_delete_resource()); + assert(globalMemCounter.checkNewCalledEq(0)); +} + +void test_equality() +{ + // Same object + { + std::pmr::monotonic_buffer_resource r1; + std::pmr::monotonic_buffer_resource r2; + assert(r1 == r1); + assert(r1 != r2); + + std::pmr::memory_resource & p1 = r1; + std::pmr::memory_resource & p2 = r2; + assert(p1 == p1); + assert(p1 != p2); + assert(p1 == r1); + assert(r1 == p1); + assert(p1 != r2); + assert(r2 != p1); + } + // Different types + { + std::pmr::monotonic_buffer_resource mono1; + std::pmr::memory_resource & r1 = mono1; + assert_on_compare c; + std::pmr::memory_resource & r2 = c; + assert(r1 != r2); + assert(!(r1 == r2)); + } +} + +void test_allocate_deallocate() +{ + { + globalMemCounter.reset(); + + std::pmr::monotonic_buffer_resource mono1(std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = mono1; + + void *ret = r1.allocate(50); + assert(ret); + assert(globalMemCounter.checkNewCalledGreaterThan(0)); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + // mem.res.monotonic.buffer 1.2 + // A call to deallocate has no effect, thus the amount of memory + // consumed increases monotonically until the resource is destroyed. + // Check that deallocate is a no-op + r1.deallocate(ret, 50); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + mono1.release(); + assert(globalMemCounter.checkDeleteCalledEq(1)); + assert(globalMemCounter.checkOutstandingNewEq(0)); + + globalMemCounter.reset(); + + ret = r1.allocate(500); + assert(ret); + assert(globalMemCounter.checkNewCalledGreaterThan(0)); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + // Check that the destructor calls release() + } + assert(globalMemCounter.checkDeleteCalledEq(1)); + assert(globalMemCounter.checkOutstandingNewEq(0)); +} + +void test_allocate_deallocate_from_original_buffer() +{ + globalMemCounter.reset(); + char buffer[100]; + std::pmr::monotonic_buffer_resource mono1((void *)buffer, sizeof buffer, std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = mono1; + + // Check that construction with a buffer does not allocate anything from the upstream + assert(globalMemCounter.checkNewCalledEq(0)); + + // Check that an allocation that fits in the buffer does not allocate anything from the upstream + void *ret = r1.allocate(50); + assert(ret); + assert(globalMemCounter.checkNewCalledEq(0)); + + // Check a second allocation + ret = r1.allocate(20); + assert(ret); + assert(globalMemCounter.checkNewCalledEq(0)); + + r1.deallocate(ret, 50); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + // Check an allocation that doesn't fit in the original buffer + ret = r1.allocate(50); + assert(ret); + assert(globalMemCounter.checkNewCalledEq(1)); + + r1.deallocate(ret, 50); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + mono1.release(); + assert(globalMemCounter.checkDeleteCalledEq(1)); + assert(globalMemCounter.checkOutstandingNewEq(0)); +} + +void test_geometric_progression() +{ + // mem.res.monotonic.buffer 1.3 + // Each additional buffer is larger than the previous one, following a + // geometric progression. + + globalMemCounter.reset(); + std::pmr::monotonic_buffer_resource mono1(100, std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = mono1; + + assert(globalMemCounter.checkNewCalledEq(0)); + size_t next_buffer_size = 100; + void *ret = r1.allocate(10, 1); + assert(ret != nullptr); + assert(globalMemCounter.checkNewCalledEq(1)); + assert(globalMemCounter.last_new_size >= next_buffer_size); + next_buffer_size = globalMemCounter.last_new_size + 1; + + int new_called = 1; + while (new_called < 5) { + ret = r1.allocate(10, 1); + if (globalMemCounter.new_called > new_called) { + assert(globalMemCounter.new_called == new_called + 1); + assert(globalMemCounter.last_new_size >= next_buffer_size); + next_buffer_size = globalMemCounter.last_new_size + 1; + new_called += 1; + } + } +} + +void test_geometric_progression_after_release() +{ + // mem.res.monotonic.buffer 1.3 + // Each additional buffer is larger than the previous one, following a + // geometric progression. + + // mem.res.monotonic.buffer.mem 1 + // release() calls upstream_rsrc->deallocate() as necessary to release all allocated memory. + + // Implicitly: release() does not reset the geometric progression of next_buffer_size. + + globalMemCounter.reset(); + std::pmr::monotonic_buffer_resource mono1; + std::pmr::memory_resource & r1 = mono1; + + void *ret = r1.allocate(100, 1); + assert(ret != nullptr); + assert(globalMemCounter.checkNewCalledEq(1)); + size_t last_new_size = globalMemCounter.last_new_size; + + r1.allocate(last_new_size, 1); + assert(globalMemCounter.checkNewCalledEq(2)); + assert(globalMemCounter.last_new_size > last_new_size); + last_new_size = globalMemCounter.last_new_size; + + mono1.release(); + assert(globalMemCounter.checkDeleteCalledEq(2)); + + // We expect to see a large upstream allocation corresponding + // to this small request, because the upstream allocation must + // be at least `next_buffer_size` bytes. + r1.allocate(10, 1); + assert(globalMemCounter.checkNewCalledEq(3)); + assert(globalMemCounter.last_new_size >= 10); + assert(globalMemCounter.last_new_size > 100); + assert(globalMemCounter.last_new_size > last_new_size); +} + +void test_zero_sized_initial_buffer() +{ + globalMemCounter.reset(); + { + char buffer[100]; + std::pmr::monotonic_buffer_resource mono1((void *)buffer, 0, std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = mono1; + + void *ret = r1.allocate(1, 1); + assert(ret != nullptr); + assert(globalMemCounter.checkNewCalledEq(1)); + } + assert(globalMemCounter.checkDeleteCalledEq(1)); + + globalMemCounter.reset(); + { + std::pmr::monotonic_buffer_resource mono1(nullptr, 0, std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = mono1; + + void *ret = r1.allocate(1, 1); + assert(ret != nullptr); + assert(globalMemCounter.checkNewCalledEq(1)); + } + assert(globalMemCounter.checkDeleteCalledEq(1)); +} + +void test_underaligned_initial_buffer() +{ + globalMemCounter.reset(); + { + alignas(4) char buffer[17]; + std::pmr::monotonic_buffer_resource mono1(buffer + 1, 16, std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = mono1; + + void *ret = r1.allocate(1, 1); + assert(ret == buffer + 1); + mono1.release(); + + ret = r1.allocate(1, 2); + assert(ret == buffer + 2); + mono1.release(); + + ret = r1.allocate(1, 4); + assert(ret == buffer + 4); + mono1.release(); + + // Test a size that is just big enough to fit in the buffer, + // but can't fit if it's aligned. + ret = r1.allocate(16, 1); + assert(ret == buffer + 1); + mono1.release(); + + assert(globalMemCounter.checkNewCalledEq(0)); + ret = r1.allocate(16, 2); + assert(globalMemCounter.checkNewCalledEq(1)); + assert(globalMemCounter.last_new_size >= 16); + // assert(globalMemCounter.last_new_align >= 2); + mono1.release(); + assert(globalMemCounter.checkDeleteCalledEq(1)); + // assert(globalMemCounter.last_new_align == globalMemCounter.last_delete_align); + } +} + +void test_overaligned_single_allocation() +{ + globalMemCounter.reset(); + std::pmr::monotonic_buffer_resource mono1(1024, std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = mono1; + + constexpr size_t big_alignment = 8 * alignof(std::max_align_t); + static_assert(big_alignment > 4); + + void *ret = r1.allocate(2048, big_alignment); + assert(ret != nullptr); + assert(globalMemCounter.checkNewCalledEq(1)); + assert(globalMemCounter.last_new_size >= 2048); + // assert(globalMemCounter.last_new_align >= big_alignment); + + // Check that a single highly aligned allocation request doesn't + // permanently "poison" the resource to allocate only super-aligned + // blocks of memory. + ret = r1.allocate(globalMemCounter.last_new_size, 4); + assert(ret != nullptr); + assert(globalMemCounter.checkNewCalledEq(2)); + // assert(globalMemCounter.last_new_align >= 4); + // assert(globalMemCounter.last_new_align < big_alignment); +} + +void test_exception_safety() +{ + globalMemCounter.reset(); + repointable_resource upstream(std::pmr::new_delete_resource()); + alignas(16) char buffer[64]; + std::pmr::monotonic_buffer_resource mono1(buffer, sizeof buffer, &upstream); + std::pmr::memory_resource & r1 = mono1; + + void *res = r1.allocate(64, 16); + assert(res == buffer); + assert(globalMemCounter.checkNewCalledEq(0)); + + res = r1.allocate(64, 16); + assert(res != buffer); + assert(globalMemCounter.checkNewCalledEq(1)); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + upstream.which = std::pmr::null_memory_resource(); + try { + res = r1.allocate(globalMemCounter.last_new_size, 16); + assert(false); + } catch (const std::bad_alloc&) { + // we expect this + } + assert(globalMemCounter.checkNewCalledEq(1)); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + upstream.which = std::pmr::new_delete_resource(); + res = r1.allocate(64, 16); + assert(res != buffer); + assert(globalMemCounter.checkNewCalledEq(2)); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + mono1.release(); + assert(globalMemCounter.checkNewCalledEq(2)); + assert(globalMemCounter.checkDeleteCalledEq(2)); +} + +int main() +{ + test_construction_with_default_resource(); + test_construction_without_buffer(); + test_equality(); + test_allocate_deallocate(); + test_allocate_deallocate_from_original_buffer(); + test_geometric_progression(); + test_geometric_progression_after_release(); + test_zero_sized_initial_buffer(); + test_underaligned_initial_buffer(); + test_overaligned_single_allocation(); + test_exception_safety(); +} Index: test/std/utilities/utility/mem.res/mem.res.pool/unsynchronized_buffer.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res.pool/unsynchronized_buffer.pass.cpp @@ -0,0 +1,203 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// class unsynchronized_pool_resource + +#include +#include +#include +#include + +#include "count_new.hpp" + +struct assert_on_compare : public std::pmr::memory_resource +{ +protected: + virtual void * do_allocate(size_t, size_t) + { assert(false); } + + virtual void do_deallocate(void *, size_t, size_t) + { assert(false); } + + virtual bool do_is_equal(std::pmr::memory_resource const &) const noexcept + { assert(false); } +}; + +static bool is_aligned_to(void *p, size_t alignment) +{ + void *p2 = p; + size_t space = 1; + void *result = std::align(alignment, 1, p2, space); + return (result == p); +} + +void test_construction_with_default_resource() +{ + std::pmr::memory_resource *expected = std::pmr::null_memory_resource(); + std::pmr::set_default_resource(expected); + { + std::pmr::pool_options opts { 0, 0 }; + std::pmr::unsynchronized_pool_resource r1; + std::pmr::unsynchronized_pool_resource r2(opts); + assert(r1.upstream_resource() == expected); + assert(r2.upstream_resource() == expected); + } + + expected = std::pmr::new_delete_resource(); + std::pmr::set_default_resource(expected); + { + std::pmr::pool_options opts { 1024, 2048 }; + std::pmr::unsynchronized_pool_resource r1; + std::pmr::unsynchronized_pool_resource r2(opts); + assert(r1.upstream_resource() == expected); + assert(r2.upstream_resource() == expected); + } +} + +void test_construction_does_not_allocate() +{ + // Constructing a unsynchronized_pool_resource should not cause allocations + // by itself; the resource should wait to allocate until an allocation is + // requested. + + globalMemCounter.reset(); + std::pmr::set_default_resource(std::pmr::new_delete_resource()); + + std::pmr::unsynchronized_pool_resource r1; + assert(globalMemCounter.checkNewCalledEq(0)); + + std::pmr::unsynchronized_pool_resource r2(std::pmr::pool_options{ 1024, 2048 }); + assert(globalMemCounter.checkNewCalledEq(0)); + + std::pmr::unsynchronized_pool_resource r3(std::pmr::pool_options{ 1024, 2048 }, std::pmr::new_delete_resource()); + assert(globalMemCounter.checkNewCalledEq(0)); +} + +void test_equality() +{ + // Same object + { + std::pmr::unsynchronized_pool_resource r1; + std::pmr::unsynchronized_pool_resource r2; + assert(r1 == r1); + assert(r1 != r2); + + std::pmr::memory_resource & p1 = r1; + std::pmr::memory_resource & p2 = r2; + assert(p1 == p1); + assert(p1 != p2); + assert(p1 == r1); + assert(r1 == p1); + assert(p1 != r2); + assert(r2 != p1); + } + // Different types + { + std::pmr::unsynchronized_pool_resource unsync1; + std::pmr::memory_resource & r1 = unsync1; + assert_on_compare c; + std::pmr::memory_resource & r2 = c; + assert(r1 != r2); + assert(!(r1 == r2)); + } +} + +void test_allocate_deallocate() +{ + { + globalMemCounter.reset(); + + std::pmr::unsynchronized_pool_resource unsync1(std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = unsync1; + + void *ret = r1.allocate(50); + assert(ret); + assert(globalMemCounter.checkNewCalledGreaterThan(0)); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + r1.deallocate(ret, 50); + unsync1.release(); + assert(globalMemCounter.checkDeleteCalledGreaterThan(0)); + assert(globalMemCounter.checkOutstandingNewEq(0)); + + globalMemCounter.reset(); + + ret = r1.allocate(500); + assert(ret); + assert(globalMemCounter.checkNewCalledGreaterThan(0)); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + // Check that the destructor calls release() + } + assert(globalMemCounter.checkDeleteCalledGreaterThan(0)); + assert(globalMemCounter.checkOutstandingNewEq(0)); +} + +void test_overaligned_single_allocation() +{ + globalMemCounter.reset(); + std::pmr::pool_options opts { 1, 1024 }; + std::pmr::unsynchronized_pool_resource unsync1(opts, std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = unsync1; + + constexpr size_t big_alignment = 8 * alignof(std::max_align_t); + static_assert(big_alignment > 4); + + assert(globalMemCounter.checkNewCalledEq(0)); + + void *ret = r1.allocate(2048, big_alignment); + assert(ret != nullptr); + assert(is_aligned_to(ret, big_alignment)); + assert(globalMemCounter.checkNewCalledGreaterThan(0)); + + ret = r1.allocate(16, 4); + assert(ret != nullptr); + assert(is_aligned_to(ret, 4)); + assert(globalMemCounter.checkNewCalledGreaterThan(1)); +} + +void test_reuse() +{ + globalMemCounter.reset(); + std::pmr::pool_options opts { 1, 256 }; + std::pmr::unsynchronized_pool_resource unsync1(opts, std::pmr::new_delete_resource()); + std::pmr::memory_resource & r1 = unsync1; + + void *ret = r1.allocate(8); + assert(ret != nullptr); + assert(is_aligned_to(ret, 8)); + assert(globalMemCounter.checkNewCalledGreaterThan(0)); + int new_called = globalMemCounter.new_called; + + // After deallocation, the pool for 8-byte blocks should have at least one vacancy. + r1.deallocate(ret, 8); + assert(globalMemCounter.new_called == new_called); + assert(globalMemCounter.checkDeleteCalledEq(0)); + + // This should return an existing block from the pool: no new allocations. + ret = r1.allocate(8); + assert(ret != nullptr); + assert(is_aligned_to(ret, 8)); + assert(globalMemCounter.new_called == new_called); + assert(globalMemCounter.checkDeleteCalledEq(0)); +} + +int main() +{ + test_construction_with_default_resource(); + test_construction_does_not_allocate(); + test_equality(); + test_allocate_deallocate(); + test_overaligned_single_allocation(); + test_reuse(); +} Index: test/std/utilities/utility/mem.res/mem.res/construct.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/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::pmr; + +int main() +{ + ex::memory_resource m; // expected-error {{variable type 'ex::memory_resource' is an abstract class}} +} Index: test/std/utilities/utility/mem.res/mem.res/mem.res.eq/equal.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/mem.res.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::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/utilities/utility/mem.res/mem.res/mem.res.eq/not_equal.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/mem.res.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::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/utilities/utility/mem.res/mem.res/mem.res.private/private_members.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/mem.res.private/private_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); /* private */ +// memory_resource::do_deallocate(void*, size_t, size_t); /* private */ +// memory_resource::do_is_equal(memory_resource const&); /* private */ + +#include + +namespace ex = std::pmr; + +int main() { + ex::memory_resource *m = ex::new_delete_resource(); + m->do_allocate(0, 0); // expected-error{{'do_allocate' is a private member}} + m->do_deallocate(nullptr, 0, 0); // expected-error{{'do_deallocate' is a private member}} + m->do_is_equal(*m); // expected-error{{'do_is_equal' is a private member}} +} Index: test/std/utilities/utility/mem.res/mem.res/mem.res.private/protected_members.fail.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/mem.res.private/protected_members.fail.cpp @@ -0,0 +1,47 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// monotonic_buffer_resource::do_allocate(size_t, size_t); /* protected */ +// monotonic_buffer_resource::do_deallocate(void*, size_t, size_t); /* protected */ +// monotonic_buffer_resource::do_is_equal(memory_resource const&); /* protected */ + +// synchronized_pool_resource::do_allocate(size_t, size_t); /* protected */ +// synchronized_pool_resource::do_deallocate(void*, size_t, size_t); /* protected */ +// synchronized_pool_resource::do_is_equal(memory_resource const&); /* protected */ + +// unsynchronized_pool_resource::do_allocate(size_t, size_t); /* protected */ +// unsynchronized_pool_resource::do_deallocate(void*, size_t, size_t); /* protected */ +// unsynchronized_pool_resource::do_is_equal(memory_resource const&); /* protected */ + +#include + +int main() { + { + std::pmr::monotonic_buffer_resource m; + 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}} + } + { + std::pmr::synchronized_pool_resource m; + 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}} + } + { + std::pmr::unsynchronized_pool_resource m; + 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}} + } +} Index: test/std/utilities/utility/mem.res/mem.res/mem.res.public/allocate.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/mem.res.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::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& P2 = R2.getController(); + P2.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/utilities/utility/mem.res/mem.res/mem.res.public/deallocate.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/mem.res.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::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/utilities/utility/mem.res/mem.res/mem.res.public/dtor.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/mem.res.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::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/utilities/utility/mem.res/mem.res/mem.res.public/is_equal.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/mem.res/mem.res.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::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/utilities/utility/mem.res/nothing_to_do.pass.cpp =================================================================== --- /dev/null +++ test/std/utilities/utility/mem.res/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/count_new.hpp =================================================================== --- test/support/count_new.hpp +++ test/support/count_new.hpp @@ -211,6 +211,11 @@ return disable_checking || n != delete_called; } + bool checkDeleteCalledGreaterThan(int n) const + { + return disable_checking || delete_called > n; + } + bool checkAlignedNewCalledEq(int n) const { return disable_checking || n == aligned_new_called; @@ -236,6 +241,11 @@ return disable_checking || n != aligned_delete_called; } + bool checkAlignedDeleteCalledGreaterThan(int n) const + { + return disable_checking || aligned_delete_called > n; + } + bool checkLastNewSizeEq(std::size_t n) const { return disable_checking || n == last_new_size; Index: test/support/test_experimental_memory_resource.hpp =================================================================== --- /dev/null +++ test/support/test_experimental_memory_resource.hpp @@ -0,0 +1,171 @@ +//===----------------------------------------------------------------------===// +// +// 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_EXPERIMENTAL_MEMORY_RESOURCE_HPP +#define SUPPORT_TEST_EXPERIMENTAL_MEMORY_RESOURCE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "test_macros.h" +#include "controlled_allocators.hpp" +#include "uses_alloc_types.hpp" + +// FIXME: This is a hack to allow uses_allocator_types.hpp to work with +// erased_type. However we can't define that behavior directly in the header +// because it can't include +template <> +struct TransformErasedTypeAlloc { + using type = std::experimental::pmr::memory_resource*; +}; + +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_EXPERIMENTAL_MEMORY_RESOURCE_HPP */ Index: test/support/test_memory_resource.hpp =================================================================== --- test/support/test_memory_resource.hpp +++ test/support/test_memory_resource.hpp @@ -10,10 +10,10 @@ #ifndef SUPPORT_TEST_MEMORY_RESOURCE_HPP #define SUPPORT_TEST_MEMORY_RESOURCE_HPP -#include -#include #include +#include #include +#include #include #include #include @@ -23,16 +23,8 @@ #include "controlled_allocators.hpp" #include "uses_alloc_types.hpp" -// FIXME: This is a hack to allow uses_allocator_types.hpp to work with -// erased_type. However we can't define that behavior directly in the header -// because it can't include -template <> -struct TransformErasedTypeAlloc { - using type = std::experimental::pmr::memory_resource*; -}; - template -class TestResourceImp : public std::experimental::pmr::memory_resource +class TestResourceImp : public std::pmr::memory_resource { public: static int resource_alive; @@ -46,7 +38,7 @@ resource_destructed = 0; } - using memory_resource = std::experimental::pmr::memory_resource; + using memory_resource = std::pmr::memory_resource; using Provider = ProviderT; int value; Index: test/support/uses_alloc_types.hpp =================================================================== --- test/support/uses_alloc_types.hpp +++ test/support/uses_alloc_types.hpp @@ -143,7 +143,7 @@ // polymorphic allocators. However we don't want to include // in this header. Therefore in order // to inject this behavior later we use a trait. -// See test_memory_resource.hpp for more info. +// See test_experimental_memory_resource.hpp for more info. template struct TransformErasedTypeAlloc { using type = Alloc;