Add <experimental/memory_resource>
Reviewers: mclow.lists, EricWF Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D20007 git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@268829 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
@@ -0,0 +1,178 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/memory_resource>
|
||||
|
||||
// template <class T> class polymorphic_allocator
|
||||
|
||||
// template <class U1, class U2, class ...Args1, class ...Args2>
|
||||
// void polymorphic_allocator<T>::construct(pair<T1, T2>*, piecewise_construct_t
|
||||
// tuple<Args1...> x, tuple<Args2...>)
|
||||
|
||||
// The stardard specifiers a tranformation to uses-allocator construction as
|
||||
// follows:
|
||||
// - If uses_allocator_v<T1,memory_resource*> is false and
|
||||
// is_constructible_v<T,Args1...> is true, then xprime is x.
|
||||
// - Otherwise, if uses_allocator_v<T1,memory_resource*> is true and
|
||||
// is_constructible_v<T1,allocator_arg_t,memory_resource*,Args1...> is true,
|
||||
// then xprime is
|
||||
// tuple_cat(make_tuple(allocator_arg, this->resource()), std::move(x)).
|
||||
// - Otherwise, if uses_allocator_v<T1,memory_resource*> is true and
|
||||
// is_constructible_v<T1,Args1...,memory_resource*> is true, then xprime is
|
||||
// tuple_cat(std::move(x), make_tuple(this->resource())).
|
||||
// - Otherwise the program is ill formed.
|
||||
//
|
||||
// The use of "xprime = tuple_cat(..., std::move(x), ...)" causes all of the
|
||||
// objects in 'x' to be copied into 'xprime'. If 'x' contains any types which
|
||||
// are stored by value this causes an unessary copy to occur. To prevent this
|
||||
// libc++ changes this call into
|
||||
// "xprime = forward_as_tuple(..., std::get<Idx>(std::move(x))..., ...)".
|
||||
// 'xprime' contains references to the values in 'x' instead of copying them.
|
||||
|
||||
// This test checks the number of copies incurred to the elements in
|
||||
// 'tuple<Args1...>' and 'tuple<Args2...>'.
|
||||
|
||||
#include <experimental/memory_resource>
|
||||
#include <type_traits>
|
||||
#include <utility>
|
||||
#include <tuple>
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
#include "test_memory_resource.hpp"
|
||||
|
||||
namespace ex = std::experimental::pmr;
|
||||
|
||||
template <class T>
|
||||
struct TestHarness {
|
||||
TestResource R;
|
||||
ex::memory_resource * M = &R;
|
||||
ex::polymorphic_allocator<T> A = M;
|
||||
bool constructed = false;
|
||||
T * ptr;
|
||||
|
||||
TestHarness() : ptr(A.allocate(1)) {}
|
||||
|
||||
template <class ...Args>
|
||||
void construct(Args&&... args) {
|
||||
A.construct(ptr, std::forward<Args>(args)...);
|
||||
constructed = true;
|
||||
}
|
||||
|
||||
~TestHarness() {
|
||||
if (constructed) A.destroy(ptr);
|
||||
A.deallocate(ptr, 1);
|
||||
}
|
||||
};
|
||||
|
||||
struct CountCopies {
|
||||
int count;
|
||||
CountCopies() : count(0) {}
|
||||
CountCopies(CountCopies const& o) : count(o.count + 1) {}
|
||||
};
|
||||
|
||||
struct CountCopiesAllocV1 {
|
||||
typedef ex::memory_resource* allocator_type;
|
||||
allocator_type alloc;
|
||||
int count;
|
||||
CountCopiesAllocV1() : alloc(nullptr), count(0) {}
|
||||
CountCopiesAllocV1(std::allocator_arg_t, allocator_type const& a,
|
||||
CountCopiesAllocV1 const& o) : alloc(a), count(o.count + 1)
|
||||
{}
|
||||
|
||||
CountCopiesAllocV1(CountCopiesAllocV1 const& o) : count(o.count + 1) {}
|
||||
};
|
||||
|
||||
|
||||
struct CountCopiesAllocV2 {
|
||||
typedef ex::memory_resource* allocator_type;
|
||||
allocator_type alloc;
|
||||
int count;
|
||||
CountCopiesAllocV2() : alloc(nullptr), count(0) {}
|
||||
CountCopiesAllocV2(CountCopiesAllocV2 const& o, allocator_type const& a)
|
||||
: alloc(a), count(o.count + 1)
|
||||
{ }
|
||||
|
||||
CountCopiesAllocV2(CountCopiesAllocV2 const& o) : count(o.count + 1) {}
|
||||
};
|
||||
|
||||
|
||||
int main()
|
||||
{
|
||||
using PMR = ex::memory_resource*;
|
||||
using PMA = ex::polymorphic_allocator<char>;
|
||||
|
||||
{
|
||||
using T = CountCopies;
|
||||
using U = CountCopiesAllocV1;
|
||||
using P = std::pair<T, U>;
|
||||
using TH = TestHarness<P>;
|
||||
|
||||
std::tuple<T> t1;
|
||||
std::tuple<U> t2;
|
||||
|
||||
TestHarness<P> h;
|
||||
h.construct(std::piecewise_construct, t1, t2);
|
||||
P const& p = *h.ptr;
|
||||
assert(p.first.count == 2);
|
||||
assert(p.second.count == 2);
|
||||
assert(p.second.alloc == h.M);
|
||||
}
|
||||
{
|
||||
using T = CountCopiesAllocV1;
|
||||
using U = CountCopiesAllocV2;
|
||||
using P = std::pair<T, U>;
|
||||
using TH = TestHarness<P>;
|
||||
|
||||
std::tuple<T> t1;
|
||||
std::tuple<U> t2;
|
||||
|
||||
TestHarness<P> h;
|
||||
h.construct(std::piecewise_construct, std::move(t1), std::move(t2));
|
||||
P const& p = *h.ptr;
|
||||
assert(p.first.count == 2);
|
||||
assert(p.first.alloc == h.M);
|
||||
assert(p.second.count == 2);
|
||||
assert(p.second.alloc == h.M);
|
||||
}
|
||||
{
|
||||
using T = CountCopiesAllocV2;
|
||||
using U = CountCopiesAllocV1;
|
||||
using P = std::pair<T, U>;
|
||||
using TH = TestHarness<P>;
|
||||
|
||||
std::tuple<T> t1;
|
||||
std::tuple<U> t2;
|
||||
|
||||
TestHarness<P> h;
|
||||
h.construct(std::piecewise_construct, std::move(t1), std::move(t2));
|
||||
P const& p = *h.ptr;
|
||||
assert(p.first.count == 2);
|
||||
assert(p.first.alloc == h.M);
|
||||
assert(p.second.count == 2);
|
||||
assert(p.second.alloc == h.M);
|
||||
}
|
||||
{
|
||||
using T = CountCopiesAllocV2;
|
||||
using U = CountCopies;
|
||||
using P = std::pair<T, U>;
|
||||
using TH = TestHarness<P>;
|
||||
|
||||
std::tuple<T> t1;
|
||||
std::tuple<U> t2;
|
||||
|
||||
TestHarness<P> h;
|
||||
h.construct(std::piecewise_construct, t1, t2);
|
||||
P const& p = *h.ptr;
|
||||
assert(p.first.count == 2);
|
||||
assert(p.first.alloc == h.M);
|
||||
assert(p.second.count == 2);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/memory_resource>
|
||||
|
||||
// template <class T> class polymorphic_allocator
|
||||
|
||||
// T* polymorphic_allocator<T>::deallocate(T*, size_t size)
|
||||
|
||||
int AssertCount = 0;
|
||||
|
||||
#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++)
|
||||
#define _LIBCPP_DEBUG 0
|
||||
#include <experimental/memory_resource>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_memory_resource.hpp"
|
||||
|
||||
namespace ex = std::experimental::pmr;
|
||||
|
||||
int main()
|
||||
{
|
||||
using Alloc = ex::polymorphic_allocator<int>;
|
||||
using Traits = std::allocator_traits<Alloc>;
|
||||
NullResource R;
|
||||
Alloc a(&R);
|
||||
const std::size_t maxSize = Traits::max_size(a);
|
||||
|
||||
a.deallocate(nullptr, maxSize);
|
||||
assert(AssertCount == 0);
|
||||
a.deallocate(nullptr, maxSize + 1);
|
||||
assert(AssertCount == 1);
|
||||
}
|
||||
@@ -0,0 +1,64 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/memory_resource>
|
||||
|
||||
// template <class T> class polymorphic_allocator
|
||||
|
||||
// EXTENSION
|
||||
// std::size_t polymorphic_allocator<T>::max_size() const noexcept
|
||||
|
||||
#include <experimental/memory_resource>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_memory_resource.hpp"
|
||||
|
||||
namespace ex = std::experimental::pmr;
|
||||
|
||||
template <std::size_t S>
|
||||
std::size_t getMaxSize() {
|
||||
using T = typename std::aligned_storage<S>::type;
|
||||
static_assert(sizeof(T) == S, "Required for test");
|
||||
return ex::polymorphic_allocator<T>{}.max_size();
|
||||
}
|
||||
|
||||
template <std::size_t S, std::size_t A>
|
||||
std::size_t getMaxSize() {
|
||||
using T = typename std::aligned_storage<S, A>::type;
|
||||
static_assert(sizeof(T) == S, "Required for test");
|
||||
return ex::polymorphic_allocator<T>{}.max_size();
|
||||
}
|
||||
|
||||
int main()
|
||||
{
|
||||
{
|
||||
using Alloc = ex::polymorphic_allocator<int>;
|
||||
using Traits = std::allocator_traits<Alloc>;
|
||||
const Alloc a;
|
||||
static_assert(std::is_same<decltype(a.max_size()), Traits::size_type>::value, "");
|
||||
static_assert(noexcept(a.max_size()), "");
|
||||
}
|
||||
{
|
||||
constexpr std::size_t Max = std::numeric_limits<std::size_t>::max();
|
||||
assert(getMaxSize<1>() == Max);
|
||||
assert(getMaxSize<2>() == Max / 2);
|
||||
assert(getMaxSize<4>() == Max / 4);
|
||||
assert(getMaxSize<8>() == Max / 8);
|
||||
assert(getMaxSize<16>() == Max / 16);
|
||||
assert(getMaxSize<32>() == Max / 32);
|
||||
assert(getMaxSize<64>() == Max / 64);
|
||||
assert(getMaxSize<1024>() == Max / 1024);
|
||||
|
||||
assert((getMaxSize<6, 2>() == Max / 6));
|
||||
assert((getMaxSize<12, 4>() == Max / 12));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
// <experimental/memory_resource>
|
||||
|
||||
// template <class T> class polymorphic_allocator
|
||||
|
||||
// T* polymorphic_allocator<T>::deallocate(T*, size_t size)
|
||||
|
||||
int AssertCount = 0;
|
||||
|
||||
#define _LIBCPP_ASSERT(x, m) ((x) ? (void)0 : (void)::AssertCount++)
|
||||
#define _LIBCPP_DEBUG 0
|
||||
#include <experimental/memory_resource>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
#include "test_memory_resource.hpp"
|
||||
|
||||
namespace ex = std::experimental::pmr;
|
||||
|
||||
int main()
|
||||
{
|
||||
using Alloc = NullAllocator<char>;
|
||||
using R = ex::resource_adaptor<Alloc>;
|
||||
AllocController P;
|
||||
ex::resource_adaptor<Alloc> r(Alloc{P});
|
||||
ex::memory_resource & m1 = r;
|
||||
|
||||
std::size_t maxSize = std::numeric_limits<std::size_t>::max()
|
||||
- alignof(std::max_align_t);
|
||||
|
||||
m1.deallocate(nullptr, maxSize);
|
||||
assert(AssertCount == 0);
|
||||
m1.deallocate(nullptr, maxSize + 1);
|
||||
assert(AssertCount >= 1);
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/memory_resource>
|
||||
|
||||
// memory_resource * new_delete_resource()
|
||||
|
||||
// The lifetime of the value returned by 'new_delete_resource()' should
|
||||
// never end, even very late into program termination. This test constructs
|
||||
// attempts to use 'new_delete_resource()' very late in program termination
|
||||
// to detect lifetime issues.
|
||||
|
||||
#include <experimental/memory_resource>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace ex = std::experimental::pmr;
|
||||
|
||||
struct POSType {
|
||||
ex::memory_resource* res = nullptr;
|
||||
void* ptr = nullptr;
|
||||
int n = 0;
|
||||
POSType() {}
|
||||
POSType(ex::memory_resource* r, void* p, int s) : res(r), ptr(p), n(s) {}
|
||||
~POSType() {
|
||||
if (ptr) {
|
||||
if (!res) res = ex::get_default_resource();
|
||||
res->deallocate(ptr, n);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void swap(POSType & L, POSType & R) {
|
||||
std::swap(L.res, R.res);
|
||||
std::swap(L.ptr, R.ptr);
|
||||
std::swap(L.n, R.n);
|
||||
}
|
||||
|
||||
POSType constructed_before_resources;
|
||||
POSType constructed_before_resources2;
|
||||
|
||||
// Constructs resources
|
||||
ex::memory_resource* resource = ex::get_default_resource();
|
||||
|
||||
POSType constructed_after_resources(resource, resource->allocate(1024), 1024);
|
||||
POSType constructed_after_resources2(nullptr, resource->allocate(1024), 1024);
|
||||
|
||||
int main()
|
||||
{
|
||||
swap(constructed_after_resources, constructed_before_resources);
|
||||
swap(constructed_before_resources2, constructed_after_resources2);
|
||||
}
|
||||
@@ -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
|
||||
|
||||
// <experimental/memory_resource>
|
||||
|
||||
// memory_resource * new_delete_resource()
|
||||
|
||||
// The lifetime of the value returned by 'new_delete_resource()' should
|
||||
// never end, even very late into program termination. This test constructs
|
||||
// attempts to use 'new_delete_resource()' very late in program termination
|
||||
// to detect lifetime issues.
|
||||
|
||||
#include <experimental/memory_resource>
|
||||
#include <type_traits>
|
||||
#include <cassert>
|
||||
|
||||
namespace ex = std::experimental::pmr;
|
||||
|
||||
struct POSType {
|
||||
ex::memory_resource* res = nullptr;
|
||||
void* ptr = nullptr;
|
||||
int n = 0;
|
||||
POSType() {res = ex::new_delete_resource(); ptr = res->allocate(42); n = 42; }
|
||||
POSType(ex::memory_resource* r, void* p, int s) : res(r), ptr(p), n(s) {}
|
||||
~POSType() { if (ptr) res->deallocate(ptr, n); }
|
||||
};
|
||||
|
||||
void swap(POSType & L, POSType & R) {
|
||||
std::swap(L.res, R.res);
|
||||
std::swap(L.ptr, R.ptr);
|
||||
std::swap(L.n, R.n);
|
||||
}
|
||||
|
||||
POSType constructed_before_resources;
|
||||
|
||||
// Constructs resources
|
||||
ex::memory_resource* resource = ex::new_delete_resource();
|
||||
|
||||
POSType constructed_after_resources(resource, resource->allocate(1024), 1024);
|
||||
|
||||
int main()
|
||||
{
|
||||
swap(constructed_after_resources, constructed_before_resources);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is dual licensed under the MIT and the University of Illinois Open
|
||||
// Source Licenses. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// UNSUPPORTED: c++98, c++03
|
||||
|
||||
// <experimental/memory_resource>
|
||||
|
||||
#include <experimental/memory_resource>
|
||||
|
||||
#ifndef _LIBCPP_VERSION
|
||||
#error _LIBCPP_VERSION not defined
|
||||
#endif
|
||||
|
||||
int main()
|
||||
{
|
||||
}
|
||||
Reference in New Issue
Block a user