memory_resource.cpp revision 341825
1303237Sdim//===------------------------ memory_resource.cpp -------------------------===//
2303237Sdim//
3303237Sdim//                     The LLVM Compiler Infrastructure
4303237Sdim//
5303237Sdim// This file is dual licensed under the MIT and the University of Illinois Open
6303237Sdim// Source Licenses. See LICENSE.TXT for details.
7303237Sdim//
8303237Sdim//===----------------------------------------------------------------------===//
9303237Sdim
10303237Sdim#include "experimental/memory_resource"
11303237Sdim
12303237Sdim#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
13303237Sdim#include "atomic"
14303237Sdim#elif !defined(_LIBCPP_HAS_NO_THREADS)
15303237Sdim#include "mutex"
16303237Sdim#endif
17303237Sdim
18303237Sdim_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
19303237Sdim
20303237Sdim// memory_resource
21303237Sdim
22303237Sdim//memory_resource::~memory_resource() {}
23303237Sdim
24303237Sdim// new_delete_resource()
25303237Sdim
26314564Sdimclass _LIBCPP_TYPE_VIS __new_delete_memory_resource_imp
27303237Sdim    : public memory_resource
28303237Sdim{
29303237Sdimpublic:
30303237Sdim    ~__new_delete_memory_resource_imp() = default;
31303237Sdim
32303237Sdimprotected:
33303237Sdim    virtual void* do_allocate(size_t __size, size_t __align)
34341825Sdim        { return _VSTD::__libcpp_allocate(__size, __align); /* FIXME */}
35303237Sdim
36341825Sdim    virtual void do_deallocate(void * __p, size_t, size_t __align)
37341825Sdim        { _VSTD::__libcpp_deallocate(__p, __align); /* FIXME */ }
38303237Sdim
39303237Sdim    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
40303237Sdim        { return &__other == this; }
41303237Sdim};
42303237Sdim
43303237Sdim// null_memory_resource()
44303237Sdim
45314564Sdimclass _LIBCPP_TYPE_VIS __null_memory_resource_imp
46303237Sdim    : public memory_resource
47303237Sdim{
48303237Sdimpublic:
49303237Sdim    ~__null_memory_resource_imp() = default;
50303237Sdim
51303237Sdimprotected:
52303237Sdim    virtual void* do_allocate(size_t, size_t) {
53314564Sdim        __throw_bad_alloc();
54303237Sdim    }
55303237Sdim    virtual void do_deallocate(void *, size_t, size_t) {}
56303237Sdim    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
57303237Sdim    { return &__other == this; }
58303237Sdim};
59303237Sdim
60303237Sdimnamespace {
61303237Sdim
62303237Sdimunion ResourceInitHelper {
63303237Sdim  struct {
64303237Sdim    __new_delete_memory_resource_imp new_delete_res;
65303237Sdim    __null_memory_resource_imp       null_res;
66303237Sdim  } resources;
67303237Sdim  char dummy;
68303237Sdim  _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
69303237Sdim  ~ResourceInitHelper() {}
70303237Sdim};
71341825Sdim
72341825Sdim// Detect if the init_priority attribute is supported.
73341825Sdim#if (defined(_LIBCPP_COMPILER_GCC) && defined(__APPLE__)) \
74341825Sdim  || defined(_LIBCPP_COMPILER_MSVC)
75341825Sdim// GCC on Apple doesn't support the init priority attribute,
76341825Sdim// and MSVC doesn't support any GCC attributes.
77341825Sdim# define _LIBCPP_INIT_PRIORITY_MAX
78341825Sdim#else
79341825Sdim# define _LIBCPP_INIT_PRIORITY_MAX __attribute__((init_priority(101)))
80341825Sdim#endif
81341825Sdim
82303237Sdim// When compiled in C++14 this initialization should be a constant expression.
83303237Sdim// Only in C++11 is "init_priority" needed to ensure initialization order.
84314564Sdim#if _LIBCPP_STD_VER > 11
85314564Sdim_LIBCPP_SAFE_STATIC
86314564Sdim#endif
87341825SdimResourceInitHelper res_init _LIBCPP_INIT_PRIORITY_MAX;
88303237Sdim
89303237Sdim} // end namespace
90303237Sdim
91303237Sdim
92303237Sdimmemory_resource * new_delete_resource() _NOEXCEPT {
93303237Sdim    return &res_init.resources.new_delete_res;
94303237Sdim}
95303237Sdim
96303237Sdimmemory_resource * null_memory_resource() _NOEXCEPT {
97303237Sdim    return &res_init.resources.null_res;
98303237Sdim}
99303237Sdim
100303237Sdim// default_memory_resource()
101303237Sdim
102303237Sdimstatic memory_resource *
103303237Sdim__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT
104303237Sdim{
105303237Sdim#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
106314564Sdim    _LIBCPP_SAFE_STATIC static atomic<memory_resource*> __res =
107303237Sdim        ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
108303237Sdim    if (set) {
109303237Sdim        new_res = new_res ? new_res : new_delete_resource();
110303237Sdim        // TODO: Can a weaker ordering be used?
111303237Sdim        return _VSTD::atomic_exchange_explicit(
112303237Sdim            &__res, new_res, memory_order::memory_order_acq_rel);
113303237Sdim    }
114303237Sdim    else {
115303237Sdim        return _VSTD::atomic_load_explicit(
116303237Sdim            &__res, memory_order::memory_order_acquire);
117303237Sdim    }
118303237Sdim#elif !defined(_LIBCPP_HAS_NO_THREADS)
119314564Sdim    _LIBCPP_SAFE_STATIC static memory_resource * res = &res_init.resources.new_delete_res;
120303237Sdim    static mutex res_lock;
121303237Sdim    if (set) {
122303237Sdim        new_res = new_res ? new_res : new_delete_resource();
123303237Sdim        lock_guard<mutex> guard(res_lock);
124303237Sdim        memory_resource * old_res = res;
125303237Sdim        res = new_res;
126303237Sdim        return old_res;
127303237Sdim    } else {
128303237Sdim        lock_guard<mutex> guard(res_lock);
129303237Sdim        return res;
130303237Sdim    }
131303237Sdim#else
132314564Sdim    _LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res;
133303237Sdim    if (set) {
134303237Sdim        new_res = new_res ? new_res : new_delete_resource();
135303237Sdim        memory_resource * old_res = res;
136303237Sdim        res = new_res;
137303237Sdim        return old_res;
138303237Sdim    } else {
139303237Sdim        return res;
140303237Sdim    }
141303237Sdim#endif
142303237Sdim}
143303237Sdim
144303237Sdimmemory_resource * get_default_resource() _NOEXCEPT
145303237Sdim{
146303237Sdim    return __default_memory_resource();
147303237Sdim}
148303237Sdim
149303237Sdimmemory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT
150303237Sdim{
151303237Sdim    return __default_memory_resource(true, __new_res);
152303237Sdim}
153303237Sdim
154314564Sdim_LIBCPP_END_NAMESPACE_LFTS_PMR
155