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

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

cpp: added weak_ptr

  • Property mode set to 100644
File size: 6.9 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 virtual shared_payload_base* lock() noexcept = 0;
75
76 virtual ~shared_payload_base() = default;
77 };
78
79 template<class T, class D = default_delete<T>>
80 class shared_payload: public shared_payload_base<T>
81 {
82 public:
83 shared_payload(T* ptr, D deleter = D{})
84 : data_{ptr}, deleter_{deleter},
85 refcount_{1}, weak_refcount_{1}
86 { /* DUMMY BODY */ }
87
88 template<class... Args>
89 shared_payload(Args&&... args)
90 : data_{new T{forward<Args>(args)...}},
91 deleter_{}, refcount_{1}, weak_refcount_{1}
92 { /* DUMMY BODY */ }
93
94 template<class Alloc, class... Args>
95 shared_payload(allocator_arg_t, Alloc alloc, Args&&... args)
96 : data_{alloc.allocate(1)},
97 deleter_{}, refcount_{1}, weak_refcount_{1}
98 {
99 alloc.construct(data_, forward<Args>(args)...);
100 }
101
102 template<class Alloc, class... Args>
103 shared_payload(D deleter, Alloc alloc, Args&&... args)
104 : data_{alloc.allocate(1)},
105 deleter_{deleter}, refcount_{1}, weak_refcount_{1}
106 {
107 alloc.construct(data_, forward<Args>(args)...);
108 }
109
110 void destroy() override
111 {
112 if (refs() == 0)
113 {
114 if (data_)
115 {
116 deleter_(data_);
117 data_ = nullptr;
118 }
119
120 if (weak_refs() == 0)
121 delete this;
122 }
123 }
124
125 T* get() const noexcept override
126 {
127 return data_;
128 }
129
130 uint8_t* deleter() const noexcept override
131 {
132 return (uint8_t*)&deleter_;
133 }
134
135 void increment() noexcept override
136 {
137 __atomic_add_fetch(&refcount_, 1, __ATOMIC_ACQ_REL);
138 }
139
140 void increment_weak() noexcept override
141 {
142 __atomic_add_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL);
143 }
144
145 bool decrement() noexcept override
146 {
147 if (__atomic_sub_fetch(&refcount_, 1, __ATOMIC_ACQ_REL) == 0)
148 {
149 /**
150 * First call to destroy() will delete the held object,
151 * so it doesn't matter what the weak_refcount_ is,
152 * but we added one and we need to remove it now.
153 */
154 decrement_weak();
155
156 return true;
157 }
158 else
159 return false;
160 }
161
162 bool decrement_weak() noexcept override
163 {
164 return __atomic_sub_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL) == 0 && refs() == 0;
165 }
166
167 refcount_t refs() const noexcept override
168 {
169 return __atomic_load_n(&refcount_, __ATOMIC_RELAXED);
170 }
171
172 refcount_t weak_refs() const noexcept override
173 {
174 return __atomic_load_n(&weak_refcount_, __ATOMIC_RELAXED);
175 }
176
177 bool expired() const noexcept override
178 {
179 return refs() == 0;
180 }
181
182 shared_payload_base<T>* lock() noexcept override
183 {
184 refcount_t rfs = refs();
185 while (rfs != 0L)
186 {
187 if (__atomic_compare_exchange_n(&refcount_, &rfs, rfs + 1,
188 true, __ATOMIC_RELAXED,
189 __ATOMIC_RELAXED))
190 {
191 return this;
192 }
193 }
194
195 return nullptr;
196 }
197
198 private:
199 T* data_;
200 D deleter_;
201
202 /**
203 * We're using a trick where refcount_ > 0
204 * means weak_refcount_ has 1 added to it,
205 * this makes it easier for weak_ptrs that
206 * can't decrement the weak_refcount_ to
207 * zero with shared_ptrs using this object.
208 */
209 refcount_t refcount_;
210 refcount_t weak_refcount_;
211 };
212}
213
214#endif
Note: See TracBrowser for help on using the repository browser.