Changeset 5735b111 in mainline
- Timestamp:
- 2018-07-05T21:41:23Z (7 years ago)
- Branches:
- lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
- Children:
- 5df0491
- Parents:
- e13c378
- git-author:
- Dzejrou <dzejrou@…> (2018-05-09 20:16:49)
- git-committer:
- Dzejrou <dzejrou@…> (2018-07-05 21:41:23)
- Location:
- uspace/lib/cpp/include/internal/memory
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/cpp/include/internal/memory/shared_payload.hpp
re13c378 r5735b111 30 30 #define LIBCPP_INTERNAL_MEMORY_SHARED_PAYLOAD 31 31 32 #include <internal/list.hpp> 32 #include <cinttypes> 33 #include <utility> 34 35 namespace std 36 { 37 template<class> 38 struct default_delete; 39 40 struct allocator_arg_t; 41 } 33 42 34 43 namespace std::aux … … 40 49 using refcount_t = long; 41 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 42 58 template<class T> 43 class shared_payload 59 class shared_payload_base 44 60 { 45 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 */ } 46 86 47 87 template<class... Args> 48 88 shared_payload(Args&&... args) 89 : data_{new T{forward<Args>(args)...}}, 90 deleter_{}, refcount_{1}, weak_refcount_{1} 49 91 { /* DUMMY BODY */ } 50 92 51 93 template<class Alloc, class... Args> 52 shared_payloda(Alloc alloc, Args&&... args) 53 { /* DUMMY BODY */ } 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 } 54 100 55 T* get() const 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 56 125 { 57 126 return data_; 58 127 } 59 128 60 void increment_refcount()129 uint8_t* deleter() const noexcept override 61 130 { 62 ++refcount_;131 return (uint8_t*)&deleter_; 63 132 } 64 133 65 void increment _weak_refcount()134 void increment() noexcept override 66 135 { 67 ++weak_refcount_;136 __atomic_add_fetch(&refcount_, 1, __ATOMIC_ACQ_REL); 68 137 } 69 138 70 bool decrement_refcount()139 void increment_weak() noexcept override 71 140 { 72 return --refcount_ == 0;141 __atomic_add_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL); 73 142 } 74 143 75 bool decrement _weak_refcount()144 bool decrement() noexcept override 76 145 { 77 return --weak_refcount_ == 0; 146 if (__atomic_sub_fetch(&refcount_, 1, __ATOMIC_ACQ_REL) == 0) 147 return decrement_weak(); 148 else 149 return false; 78 150 } 79 151 80 refcount_t refs() const152 bool decrement_weak() noexcept override 81 153 { 82 return refcount_;154 return __atomic_sub_fetch(&weak_refcount_, 1, __ATOMIC_ACQ_REL) == 0 && refs() == 0; 83 155 } 84 156 85 refcount_t weak_refs() const157 refcount_t refs() const noexcept override 86 158 { 87 return weak_refcount_; 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; 88 170 } 89 171 90 172 private: 91 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 */ 92 183 refcount_t refcount_; 93 184 refcount_t weak_refcount_; -
uspace/lib/cpp/include/internal/memory/shared_ptr.hpp
re13c378 r5735b111 32 32 #include <exception> 33 33 #include <functional> 34 #include <internal/memory/allocator_arg.hpp> 35 #include <internal/memory/shared_payload.hpp> 34 36 #include <type_traits> 35 37 36 38 namespace std 37 39 { 40 template<class T> 41 class weak_ptr; 42 38 43 /** 39 44 * 20.8.2.1, class bad_weak_ptr: … … 65 70 */ 66 71 67 constexpr shared_ptr() noexcept; 68 69 template<class U> 70 explicit shared_ptr(U* ptr); 72 constexpr shared_ptr() noexcept 73 : payload_{}, data_{} 74 { /* DUMMY BODY */ } 75 76 template<class U> 77 explicit shared_ptr( 78 enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr 79 ) 80 : payload_{}, data_{ptr} 81 { 82 try 83 { 84 payload_ = new aux::shared_payload<T>{ptr}; 85 } 86 catch (const bad_alloc&) 87 { 88 delete ptr; 89 90 throw; 91 } 92 } 71 93 72 94 template<class U, class D> 73 shared_ptr(U* ptr, D deleter); 95 shared_ptr( 96 enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr, D deleter 97 ) 98 : shared_ptr{} 99 { 100 try 101 { 102 payload_ = new aux::shared_payload<T, D>{ptr, deleter}; 103 } 104 catch (const bad_alloc&) 105 { 106 deleter(ptr); 107 108 throw; 109 } 110 } 74 111 75 112 template<class U, class D, class A> 76 shared_ptr(U* ptr, D deleter, A alloc); 113 shared_ptr( 114 enable_if_t<is_convertible_v<U*, element_type*>, U*> ptr, 115 D deleter, A 116 ) 117 : shared_ptr{} 118 { 119 try 120 { 121 payload_ = new aux::shared_payload<T, D>{ptr, deleter}; 122 } 123 catch (const bad_alloc&) 124 { 125 deleter(ptr); 126 127 throw; 128 } 129 } 77 130 78 131 template<class D> 79 shared_ptr(nullptr_t, D deleter); 132 shared_ptr(nullptr_t ptr, D deleter) 133 : shared_ptr{} 134 { /* DUMMY BODY */ } 80 135 81 136 template<class D, class A> 82 shared_ptr(nullptr_t, D deleter, A alloc); 83 84 template<class U> 85 shared_ptr(const shared_ptr<U>& other, value_type* ptr); 86 87 shared_ptr(const shared_ptr& other); 88 89 template<class U> 90 shared_ptr(const shared_ptr<U>& other); 91 92 shared_ptr(shared_ptr&& other); 93 94 template<class U> 95 shared_ptr(shared_ptr<U>&& other); 96 97 template<class U> 98 explicit shared_ptr(const weak_ptr<U>& other); 137 shared_ptr(nullptr_t, D deleter, A) 138 : shared_ptr{} 139 { /* DUMMY BODY */ } 140 141 template<class U> 142 shared_ptr( 143 enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> other, 144 element_type* ptr 145 ) 146 : payload_{other.payload_}, data_{ptr} 147 { 148 if (payload_) 149 payload_->increment(); 150 } 151 152 shared_ptr(const shared_ptr& other) 153 : payload_{other.payload_}, data_{other.data_} 154 { 155 if (payload_) 156 payload_->increment(); 157 } 158 159 template<class U> 160 shared_ptr( 161 enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> other 162 ) 163 : payload_{other.payload_}, data_{other.data_} 164 { 165 if (payload_) 166 payload_->increment(); 167 } 168 169 shared_ptr(shared_ptr&& other) 170 : payload_{move(other.payload_)}, data_{move(other.data_)} 171 { 172 other.payload_ = nullptr; 173 other.data_ = nullptr; 174 } 175 176 template<class U> 177 shared_ptr( 178 enable_if_t<is_convertible_v<U*, element_type*>, shared_ptr<U>&&> other 179 ) 180 : payload_{move(other.payload_)}, data_{move(other.data_)} 181 { 182 other.payload_ = nullptr; 183 other.data_ = nullptr; 184 } 185 186 template<class U> 187 explicit shared_ptr( 188 enable_if_t<is_convertible_v<U*, element_type*>, const weak_ptr<U>&> other 189 ) 190 { 191 if (other.expired()) 192 throw bad_weak_ptr{}; 193 // TODO: 194 } 99 195 100 196 template<class U, class D> 101 shared_ptr(unique_ptr<U, D>&& other); 197 shared_ptr( 198 enable_if_t< 199 is_convertible_v< 200 typename unique_ptr<U, D>::pointer, 201 element_type* 202 >, 203 unique_ptr<U, D>&& 204 > other 205 ) // TODO: if D is a reference type, it should be ref(other.get_deleter()) 206 : shared_ptr{other.release(), other.get_deleter()} 207 { /* DUMMY BODY */ } 102 208 103 209 constexpr shared_ptr(nullptr_t) noexcept … … 109 215 */ 110 216 111 ~shared_ptr(); 217 ~shared_ptr() 218 { 219 remove_payload_(); 220 } 112 221 113 222 /** … … 115 224 */ 116 225 117 shared_ptr& operator=(const shared_ptr& rhs) noexcept; 118 119 template<class U> 120 shared_ptr& operator=(const shared_ptr<U>& rhs) noexcept; 121 122 shared_ptr& operator=(shared_ptr&& rhs) noexcept; 123 124 template<class U> 125 shared_ptr& operator=(shared_ptr<U>&& rhs) noexcept; 226 shared_ptr& operator=(const shared_ptr& rhs) noexcept 227 { 228 if (rhs.payload_) 229 rhs.payload_->increment(); 230 231 remove_payload_(); 232 233 payload_ = rhs.payload_; 234 data_ = rhs.data_; 235 236 return *this; 237 } 238 239 template<class U> 240 shared_ptr& operator=( 241 enable_if_t<is_convertible_v<U*, element_type*>, const shared_ptr<U>&> rhs 242 ) noexcept 243 { 244 if (rhs.payload_) 245 rhs.payload_->increment(); 246 247 remove_payload_(); 248 249 payload_ = rhs.payload_; 250 data_ = rhs.data_; 251 252 return *this; 253 } 254 255 shared_ptr& operator=(shared_ptr&& rhs) noexcept 256 { 257 shared_ptr{move(rhs)}.swap(*this); 258 259 return *this; 260 } 261 262 template<class U> 263 shared_ptr& operator=( 264 enable_if_t<is_convertible_v<U*, element_type*>, shared_ptr<U>&&> rhs 265 ) noexcept 266 { 267 shared_ptr{move(rhs)}.swap(*this); 268 269 return *this; 270 } 126 271 127 272 template<class U, class D> 128 shared_ptr& operator=(unique_ptr<U, D>&& rhs); 273 shared_ptr& operator=(unique_ptr<U, D>&& rhs) 274 { 275 shared_ptr{move(rhs)}.swap(*this); 276 277 return *this; 278 } 129 279 130 280 /** … … 132 282 */ 133 283 134 void swap(shared_ptr& other) noexcept; 135 136 void reset() noexcept; 137 138 template<class U> 139 void reset(U* ptr); 284 void swap(shared_ptr& other) noexcept 285 { 286 std::swap(payload_, other.payload_); 287 std::swap(data_, other.data_); 288 } 289 290 void reset() noexcept 291 { 292 shared_ptr{}.swap(*this); 293 } 294 295 template<class U> 296 void reset(U* ptr) 297 { 298 shared_ptr{ptr}.swap(*this); 299 } 140 300 141 301 template<class U, class D> 142 void reset(U* ptr, D deleter); 302 void reset(U* ptr, D deleter) 303 { 304 shared_ptr{ptr, deleter}.swap(*this); 305 } 143 306 144 307 template<class U, class D, class A> 145 void reset(U* ptr, D deleter, A alloc); 308 void reset(U* ptr, D deleter, A alloc) 309 { 310 shared_ptr{ptr, deleter, alloc}.swap(*this); 311 } 146 312 147 313 /** … … 151 317 element_type* get() const noexcept 152 318 { 153 if (payload_)154 return payload_->get();155 else 156 return nullptr;157 }158 159 T& operator*() const noexcept;319 return data_; 320 } 321 322 enable_if_t<!is_void_v<T>, T&> operator*() const noexcept 323 { 324 return *data_; 325 } 160 326 161 327 T* operator->() const noexcept … … 189 355 190 356 template<class U> 191 bool owner_before(const weak_ptr<U>& ptr) const; 357 bool owner_before(const weak_ptr<U>& ptr) const 358 { 359 return payload_ < ptr.payload_; 360 } 192 361 193 362 private: 194 aux::shared_payload<element_type>* payload_; 195 196 shared_ptr(aux::shared_payload<element_type>* payload) 197 : payload_{payload} 363 aux::shared_payload_base<element_type>* payload_; 364 element_type* data_; 365 366 shared_ptr(aux::shared_payload_base<element_type>* payload) 367 : payload_{payload}, data_{payload->get()} 198 368 { /* DUMMY BODY */ } 369 370 void remove_payload_() 371 { 372 if (payload_) 373 { 374 auto res = payload_->decrement(); 375 if (res) 376 payload_->destroy(); 377 378 payload_ = nullptr; 379 } 380 381 if (data_) 382 data_ = nullptr; 383 } 199 384 200 385 template<class U, class... Args> … … 203 388 template<class U, class A, class... Args> 204 389 friend shared_ptr<U> allocate_shared(const A&, Args&&...); 390 391 template<class D, class U> 392 D* get_deleter(const shared_ptr<U>&) noexcept; 393 394 template<class U> 395 friend class weak_ptr; 205 396 }; 206 397 … … 226 417 { 227 418 return shared_ptr<T>{ 228 new aux::shared_payload<T>{ A{alloc}, forward<Args>(args)...}419 new aux::shared_payload<T>{allocator_arg, A{alloc}, forward<Args>(args)...} 229 420 }; 230 421 } … … 394 585 D* get_deleter(const shared_ptr<T>& ptr) noexcept 395 586 { 396 // TODO: implement this through payload 587 if (ptr.payload_) 588 return static_cast<D*>(ptr.payload_->deleter()); 589 else 590 return nullptr; 397 591 } 398 592
Note:
See TracChangeset
for help on using the changeset viewer.