source: mainline/uspace/lib/cpp/include/internal/memory/shared_payload.hpp@ 5735b111

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5735b111 was 5735b111, checked in by Dzejrou <dzejrou@…>, 7 years ago

cpp: added a basic shared_ptr implementation

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/*
2 * Copyright (c) 2018 Jaroslav Jindrak
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28
29#ifndef LIBCPP_INTERNAL_MEMORY_SHARED_PAYLOAD
30#define LIBCPP_INTERNAL_MEMORY_SHARED_PAYLOAD
31
32#include <cinttypes>
33#include <utility>
34
35namespace std
36{
37 template<class>
38 struct default_delete;
39
40 struct allocator_arg_t;
41}
42
43namespace std::aux
44{
45 /**
46 * At the moment we do not have atomics, change this
47 * to std::atomic<long> once we do.
48 */
49 using refcount_t = long;
50
51 template<class D, class T>
52 void use_payload_deleter(D* deleter, T* data)
53 {
54 if (deleter)
55 (*deleter)(data);
56 }
57
58 template<class T>
59 class shared_payload_base
60 {
61 public:
62 virtual void destroy() = 0;
63 virtual T* get() const noexcept = 0;
64
65 virtual uint8_t* deleter() const noexcept = 0;
66
67 virtual void increment() noexcept = 0;
68 virtual void increment_weak() noexcept = 0;
69 virtual bool decrement() noexcept = 0;
70 virtual bool decrement_weak() noexcept = 0;
71 virtual refcount_t refs() const noexcept = 0;
72 virtual refcount_t weak_refs() const noexcept = 0;
73 virtual bool expired() const noexcept = 0;
74
75 virtual ~shared_payload_base() = default;
76 };
77
78 template<class T, class D = default_delete<T>>
79 class shared_payload: public shared_payload_base<T>
80 {
81 public:
82 shared_payload(T* ptr, D deleter = D{})
83 : data_{ptr}, deleter_{deleter},
84 refcount_{1}, weak_refcount_{1}
85 { /* DUMMY BODY */ }
86
87 template<class... Args>
88 shared_payload(Args&&... args)
89 : data_{new T{forward<Args>(args)...}},
90 deleter_{}, refcount_{1}, weak_refcount_{1}
91 { /* DUMMY BODY */ }
92
93 template<class Alloc, class... Args>
94 shared_payload(allocator_arg_t, Alloc alloc, Args&&... args)
95 : data_{alloc.allocate(1)},
96 deleter_{}, refcount_{1}, weak_refcount_{1}
97 {
98 alloc.construct(data_, forward<Args>(args)...);
99 }
100
101 template<class Alloc, class... Args>
102 shared_payload(D deleter, Alloc alloc, Args&&... args)
103 : data_{alloc.allocate(1)},
104 deleter_{deleter}, refcount_{1}, weak_refcount_{1}
105 {
106 alloc.construct(data_, forward<Args>(args)...);
107 }
108
109 void destroy() override
110 {
111 if (refs() == 0)
112 {
113 if (data_)
114 {
115 deleter_(data_);
116 data_ = nullptr;
117 }
118
119 if (weak_refs() == 0)
120 delete this;
121 }
122 }
123
124 T* get() const noexcept override
125 {
126 return data_;
127 }
128
129 uint8_t* deleter() const noexcept override
130 {
131 return (uint8_t*)&deleter_;
132 }
133
134 void increment() noexcept override
135 {
136 __atomic_add_fetch(&refcount_, 1, __ATOMIC_ACQ_REL);
137 }
138
139 void increment_weak() noexcept override
140 {
141 __atomic_add_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL);
142 }
143
144 bool decrement() noexcept override
145 {
146 if (__atomic_sub_fetch(&refcount_, 1, __ATOMIC_ACQ_REL) == 0)
147 return decrement_weak();
148 else
149 return false;
150 }
151
152 bool decrement_weak() noexcept override
153 {
154 return __atomic_sub_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL) == 0 && refs() == 0;
155 }
156
157 refcount_t refs() const noexcept override
158 {
159 return __atomic_load_n(&refcount_, __ATOMIC_RELAXED);
160 }
161
162 refcount_t weak_refs() const noexcept override
163 {
164 return __atomic_load_n(&weak_refcount_, __ATOMIC_RELAXED);
165 }
166
167 bool expired() const noexcept override
168 {
169 return refs() == 0;
170 }
171
172 private:
173 T* data_;
174 D deleter_;
175
176 /**
177 * We're using a trick where refcount_ > 0
178 * means weak_refcount_ has 1 added to it,
179 * this makes it easier for weak_ptrs that
180 * can't decrement the weak_refcount_ to
181 * zero with shared_ptrs using this object.
182 */
183 refcount_t refcount_;
184 refcount_t weak_refcount_;
185 };
186}
187
188#endif
Note: See TracBrowser for help on using the repository browser.