1303237Sdim//===------------------------ memory_resource.cpp -------------------------===//
2303237Sdim//
3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4353358Sdim// See https://llvm.org/LICENSE.txt for license information.
5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6303237Sdim//
7303237Sdim//===----------------------------------------------------------------------===//
8303237Sdim
9303237Sdim#include "experimental/memory_resource"
10303237Sdim
11303237Sdim#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
12303237Sdim#include "atomic"
13303237Sdim#elif !defined(_LIBCPP_HAS_NO_THREADS)
14303237Sdim#include "mutex"
15360784Sdim#if defined(__ELF__) && defined(_LIBCPP_LINK_PTHREAD_LIB)
16353358Sdim#pragma comment(lib, "pthread")
17303237Sdim#endif
18353358Sdim#endif
19303237Sdim
20303237Sdim_LIBCPP_BEGIN_NAMESPACE_LFTS_PMR
21303237Sdim
22303237Sdim// memory_resource
23303237Sdim
24303237Sdim//memory_resource::~memory_resource() {}
25303237Sdim
26303237Sdim// new_delete_resource()
27303237Sdim
28314564Sdimclass _LIBCPP_TYPE_VIS __new_delete_memory_resource_imp
29303237Sdim    : public memory_resource
30303237Sdim{
31353358Sdim    void *do_allocate(size_t size, size_t align) override {
32353358Sdim#ifdef _LIBCPP_HAS_NO_ALIGNED_ALLOCATION
33353358Sdim        if (__is_overaligned_for_new(align))
34353358Sdim            __throw_bad_alloc();
35353358Sdim#endif
36353358Sdim        return _VSTD::__libcpp_allocate(size, align);
37353358Sdim    }
38303237Sdim
39353358Sdim    void do_deallocate(void *p, size_t n, size_t align) override {
40353358Sdim      _VSTD::__libcpp_deallocate(p, n, align);
41344779Sdim    }
42303237Sdim
43353358Sdim    bool do_is_equal(memory_resource const & other) const _NOEXCEPT override
44353358Sdim        { return &other == this; }
45353358Sdim
46353358Sdimpublic:
47353358Sdim    ~__new_delete_memory_resource_imp() override = default;
48303237Sdim};
49303237Sdim
50303237Sdim// null_memory_resource()
51303237Sdim
52314564Sdimclass _LIBCPP_TYPE_VIS __null_memory_resource_imp
53303237Sdim    : public memory_resource
54303237Sdim{
55303237Sdimpublic:
56303237Sdim    ~__null_memory_resource_imp() = default;
57303237Sdim
58303237Sdimprotected:
59303237Sdim    virtual void* do_allocate(size_t, size_t) {
60314564Sdim        __throw_bad_alloc();
61303237Sdim    }
62303237Sdim    virtual void do_deallocate(void *, size_t, size_t) {}
63303237Sdim    virtual bool do_is_equal(memory_resource const & __other) const _NOEXCEPT
64303237Sdim    { return &__other == this; }
65303237Sdim};
66303237Sdim
67303237Sdimnamespace {
68303237Sdim
69303237Sdimunion ResourceInitHelper {
70303237Sdim  struct {
71303237Sdim    __new_delete_memory_resource_imp new_delete_res;
72303237Sdim    __null_memory_resource_imp       null_res;
73303237Sdim  } resources;
74303237Sdim  char dummy;
75303237Sdim  _LIBCPP_CONSTEXPR_AFTER_CXX11 ResourceInitHelper() : resources() {}
76303237Sdim  ~ResourceInitHelper() {}
77303237Sdim};
78341825Sdim
79341825Sdim// Detect if the init_priority attribute is supported.
80341825Sdim#if (defined(_LIBCPP_COMPILER_GCC) && defined(__APPLE__)) \
81341825Sdim  || defined(_LIBCPP_COMPILER_MSVC)
82341825Sdim// GCC on Apple doesn't support the init priority attribute,
83341825Sdim// and MSVC doesn't support any GCC attributes.
84341825Sdim# define _LIBCPP_INIT_PRIORITY_MAX
85341825Sdim#else
86341825Sdim# define _LIBCPP_INIT_PRIORITY_MAX __attribute__((init_priority(101)))
87341825Sdim#endif
88341825Sdim
89303237Sdim// When compiled in C++14 this initialization should be a constant expression.
90303237Sdim// Only in C++11 is "init_priority" needed to ensure initialization order.
91314564Sdim#if _LIBCPP_STD_VER > 11
92314564Sdim_LIBCPP_SAFE_STATIC
93314564Sdim#endif
94341825SdimResourceInitHelper res_init _LIBCPP_INIT_PRIORITY_MAX;
95303237Sdim
96303237Sdim} // end namespace
97303237Sdim
98303237Sdim
99303237Sdimmemory_resource * new_delete_resource() _NOEXCEPT {
100303237Sdim    return &res_init.resources.new_delete_res;
101303237Sdim}
102303237Sdim
103303237Sdimmemory_resource * null_memory_resource() _NOEXCEPT {
104303237Sdim    return &res_init.resources.null_res;
105303237Sdim}
106303237Sdim
107303237Sdim// default_memory_resource()
108303237Sdim
109303237Sdimstatic memory_resource *
110303237Sdim__default_memory_resource(bool set = false, memory_resource * new_res = nullptr) _NOEXCEPT
111303237Sdim{
112303237Sdim#ifndef _LIBCPP_HAS_NO_ATOMIC_HEADER
113314564Sdim    _LIBCPP_SAFE_STATIC static atomic<memory_resource*> __res =
114303237Sdim        ATOMIC_VAR_INIT(&res_init.resources.new_delete_res);
115303237Sdim    if (set) {
116303237Sdim        new_res = new_res ? new_res : new_delete_resource();
117303237Sdim        // TODO: Can a weaker ordering be used?
118303237Sdim        return _VSTD::atomic_exchange_explicit(
119360784Sdim            &__res, new_res, memory_order_acq_rel);
120303237Sdim    }
121303237Sdim    else {
122303237Sdim        return _VSTD::atomic_load_explicit(
123360784Sdim            &__res, memory_order_acquire);
124303237Sdim    }
125303237Sdim#elif !defined(_LIBCPP_HAS_NO_THREADS)
126314564Sdim    _LIBCPP_SAFE_STATIC static memory_resource * res = &res_init.resources.new_delete_res;
127303237Sdim    static mutex res_lock;
128303237Sdim    if (set) {
129303237Sdim        new_res = new_res ? new_res : new_delete_resource();
130303237Sdim        lock_guard<mutex> guard(res_lock);
131303237Sdim        memory_resource * old_res = res;
132303237Sdim        res = new_res;
133303237Sdim        return old_res;
134303237Sdim    } else {
135303237Sdim        lock_guard<mutex> guard(res_lock);
136303237Sdim        return res;
137303237Sdim    }
138303237Sdim#else
139314564Sdim    _LIBCPP_SAFE_STATIC static memory_resource* res = &res_init.resources.new_delete_res;
140303237Sdim    if (set) {
141303237Sdim        new_res = new_res ? new_res : new_delete_resource();
142303237Sdim        memory_resource * old_res = res;
143303237Sdim        res = new_res;
144303237Sdim        return old_res;
145303237Sdim    } else {
146303237Sdim        return res;
147303237Sdim    }
148303237Sdim#endif
149303237Sdim}
150303237Sdim
151303237Sdimmemory_resource * get_default_resource() _NOEXCEPT
152303237Sdim{
153303237Sdim    return __default_memory_resource();
154303237Sdim}
155303237Sdim
156303237Sdimmemory_resource * set_default_resource(memory_resource * __new_res) _NOEXCEPT
157303237Sdim{
158303237Sdim    return __default_memory_resource(true, __new_res);
159303237Sdim}
160303237Sdim
161314564Sdim_LIBCPP_END_NAMESPACE_LFTS_PMR
162