memory_resource.cpp revision 303237
198937Sdes//===------------------------ memory_resource.cpp -------------------------===//
298937Sdes//
398937Sdes//                     The LLVM Compiler Infrastructure
498937Sdes//
598937Sdes// This file is dual licensed under the MIT and the University of Illinois Open
6147001Sdes// Source Licenses. See LICENSE.TXT for details.
7126274Sdes//
898937Sdes//===----------------------------------------------------------------------===//
998937Sdes
1098937Sdes#include "experimental/memory_resource"
1198937Sdes
12126274Sdes#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
13106121Sdes#include "atomic"
1498937Sdes#elif !defined(_LIBCPP_HAS_NO_THREADS)
15162852Sdes#include "mutex"
16162852Sdes#endif
17126274Sdes
18126274Sdes_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
19181111Sdes
20181111Sdes// memory_resource
21181111Sdes
2298937Sdes//memory_resource::~memory_resource() {}
23181111Sdes
24181111Sdes// new_delete_resource()
25181111Sdes
26181111Sdesclass _LIBCPP_TYPE_VIS_ONLY __new_delete_memory_resource_imp
27181111Sdes    : public memory_resource
28181111Sdes{
29181111Sdespublic:
30181111Sdes    ~__new_delete_memory_resource_imp() = default;
31181111Sdes
32181111Sdesprotected:
33181111Sdes    virtual void* do_allocate(size_t __size, size_t __align)
34181111Sdes        { return __allocate(__size); }
35181111Sdes
36181111Sdes    virtual void do_deallocate(void * __p, size_t, size_t)
3798937Sdes        { __deallocate(__p); }
3898937Sdes
39181111Sdes    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
40181111Sdes        { return &__other == this; }
41181111Sdes};
42181111Sdes
43181111Sdes// null_memory_resource()
44181111Sdes
45181111Sdesclass _LIBCPP_TYPE_VIS_ONLY __null_memory_resource_imp
46181111Sdes    : public memory_resource
47181111Sdes{
48181111Sdespublic:
4998937Sdes    ~__null_memory_resource_imp() = default;
5098937Sdes
5198937Sdesprotected:
5298937Sdes    virtual void* do_allocate(size_t, size_t) {
5398937Sdes#ifndef _LIBCPP_NO_EXCEPTIONS
5498937Sdes        throw std::bad_alloc();
55137015Sdes#else
5698937Sdes        abort();
5798937Sdes#endif
58124208Sdes    }
5998937Sdes    virtual void do_deallocate(void *, size_t, size_t) {}
60181111Sdes    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
6198937Sdes    { return &__other == this; }
62181111Sdes};
63181111Sdes
64181111Sdesnamespace {
65181111Sdes
6698937Sdesunion ResourceInitHelper {
67181111Sdes  struct {
6898937Sdes    __new_delete_memory_resource_imp new_delete_res;
6998937Sdes    __null_memory_resource_imp       null_res;
70147001Sdes  } resources;
71147001Sdes  char dummy;
72147001Sdes  _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
73147001Sdes  ~ResourceInitHelper() {}
7498937Sdes};
7598937Sdes// When compiled in C++14 this initialization should be a constant expression.
76146998Sdes// Only in C++11 is "init_priority" needed to ensure initialization order.
77147001SdesResourceInitHelper res_init __attribute__((init_priority (101)));
78162852Sdes
79162852Sdes} // end namespace
80162852Sdes
81162852Sdes
82146998Sdesmemory_resource * new_delete_resource() _NOEXCEPT {
83146998Sdes    return &res_init.resources.new_delete_res;
84146998Sdes}
85162852Sdes
86162852Sdesmemory_resource * null_memory_resource() _NOEXCEPT {
87162852Sdes    return &res_init.resources.null_res;
88181111Sdes}
89181111Sdes
90181111Sdes// default_memory_resource()
91162852Sdes
92162852Sdesstatic memory_resource *
93162852Sdes__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT
94162852Sdes{
95162852Sdes#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
96162852Sdes    static atomic<memory_resource*> __res =
97162852Sdes        ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
98162852Sdes    if (set) {
99162852Sdes        new_res = new_res ? new_res : new_delete_resource();
100162852Sdes        // TODO: Can a weaker ordering be used?
10198937Sdes        return _VSTD::atomic_exchange_explicit(
10298937Sdes            &__res, new_res, memory_order::memory_order_acq_rel);
10398937Sdes    }
10498937Sdes    else {
10598937Sdes        return _VSTD::atomic_load_explicit(
10698937Sdes            &__res, memory_order::memory_order_acquire);
10798937Sdes    }
10898937Sdes#elif !defined(_LIBCPP_HAS_NO_THREADS)
10998937Sdes    static memory_resource * res = &res_init.resources.new_delete_res;
11098937Sdes    static mutex res_lock;
11198937Sdes    if (set) {
11298937Sdes        new_res = new_res ? new_res : new_delete_resource();
11398937Sdes        lock_guard<mutex> guard(res_lock);
11498937Sdes        memory_resource * old_res = res;
11598937Sdes        res = new_res;
11698937Sdes        return old_res;
11798937Sdes    } else {
118126274Sdes        lock_guard<mutex> guard(res_lock);
11998937Sdes        return res;
12098937Sdes    }
12198937Sdes#else
12298937Sdes    static memory_resource* res = &res_init.resources.new_delete_res;
12398937Sdes    if (set) {
12498937Sdes        new_res = new_res ? new_res : new_delete_resource();
12598937Sdes        memory_resource * old_res = res;
12698937Sdes        res = new_res;
12798937Sdes        return old_res;
128147001Sdes    } else {
129147001Sdes        return res;
130147001Sdes    }
131147001Sdes#endif
13298937Sdes}
13398937Sdes
13498937Sdesmemory_resource * get_default_resource() _NOEXCEPT
13598937Sdes{
13698937Sdes    return __default_memory_resource();
13798937Sdes}
13898937Sdes
13998937Sdesmemory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT
14098937Sdes{
14198937Sdes    return __default_memory_resource(true, __new_res);
14298937Sdes}
14398937Sdes
14498937Sdes_LIBCPP_END_NAMESPACE_LFTS_PMR