OpenVPN 3 Core Library
Loading...
Searching...
No Matches
rc.hpp
Go to the documentation of this file.
1// OpenVPN -- An application to securely tunnel IP networks
2// over a single port, with support for SSL/TLS-based
3// session authentication and key exchange,
4// packet encryption, packet authentication, and
5// packet compression.
6//
7// Copyright (C) 2012- OpenVPN Inc.
8//
9// SPDX-License-Identifier: MPL-2.0 OR AGPL-3.0-only WITH openvpn3-openssl-exception
10//
11
12// A basic reference-counting garbage collection scheme based
13// on intrusive pointers, where the reference count is embedded in
14// the object via inheritance. Simply inherit from RC to create an
15// object that can be tracked with an RCPtr.
16//
17// We use tend to use RCPtr (or RCWeakPtr) rather than the other
18// smart pointer classes (std or boost) for flexibility and
19// performance.
20//
21// Smart pointers have two basic attributes that determine
22// their performance. Either of these attributes, when required,
23// will degrade the performance of the smart pointer:
24//
25// 1. whether the smart pointer is thread-safe, i.e. it uses an
26// atomic reference counter
27// 2. whether the smart pointer can be referrred to via a
28// weak reference
29//
30// In keeping with the oft-stated C++ motto of only paying for
31// what you use, both attributes can be independently controlled.
32//
33// * thread-unsafe/not-weak-referenceable -- class Foo : public RC<thread_unsafe_refcount>
34// * thread-safe/not-weak-referenceable -- class Foo : public RC<thread_safe_refcount>
35// * thread-unsafe/weak-referenceable -- class Foo : public RCWeak<thread_unsafe_refcount>
36// * thread-safe/weak-referenceable -- class Foo : public RCWeak<thread_safe_refcount>
37//
38// Thread-safe reference counting can be significantly more expensive
39// because an atomic object must be used for the reference count.
40// Therefore, thread-safe reference counting should only be used for
41// objects that have visibility across multiple threads.
42//
43// In addition, having an object be weak-referenceable also
44// imposes a cost, so it should be avoided unless necessary.
45//
46// For clarity and as a general convention in the OpenVPN code,
47// any object that inherits from RC should also declare a Ptr
48// typedef that defines the smart pointer type that should be used to
49// track the object, e.g.:
50//
51// class Foo : public RC<thread_unsafe_refcount> {
52// public:
53// typedef RCPtr<Foo> Ptr; // strong pointer
54// typedef RCWeakPtr<Foo> WPtr; // weak pointer
55// };
56//
57// This allows a smart-pointer to Foo to be referred to
58// as Foo::Ptr or Foo::WPtr.
59//
60// Note that RC/RCWeak fully supports virtual inheritance. For
61// example, consider the diamond inheritance pattern below, where
62// both A and B objects contain their own reference count, but C
63// inherits from both A and B. To prevent C objects from
64// having two separate reference counts, it is necessary to
65// virtually inherit from RC.
66//
67// class A : public virtual RC<thread_unsafe_refcount> {}
68// class B : public virtual RC<thread_unsafe_refcount> {}
69// class C : public A, public B {}
70
71#ifndef OPENVPN_COMMON_RC_H
72#define OPENVPN_COMMON_RC_H
73
74#include <atomic>
75#include <utility>
76
78
79#ifdef OPENVPN_RC_DEBUG
80#include <iostream>
82#endif
83
84namespace openvpn {
85
117template <typename T>
118class RCPtr
119{
120 public:
121 using element_type = T;
122
123 RCPtr() noexcept;
124 RCPtr(T *p, const bool add_ref = true) noexcept;
125 RCPtr(const RCPtr &rhs) noexcept;
126 RCPtr(RCPtr &&rhs) noexcept;
127 template <typename U>
128 RCPtr(const RCPtr<U> &rhs) noexcept;
130
131 RCPtr &operator=(const RCPtr &rhs) noexcept;
132 RCPtr &operator=(RCPtr &&rhs) noexcept;
133
134 void reset() noexcept;
135 void reset(T *rhs) noexcept;
136 void swap(RCPtr &rhs) noexcept;
137
138 T *get() const noexcept;
139 T &operator*() const noexcept;
140 T *operator->() const noexcept;
141
142 explicit operator bool() const noexcept;
143 bool operator==(const RCPtr &rhs) const;
144 bool operator!=(const RCPtr &rhs) const;
145
146 RCPtr<T> move_strong() noexcept;
147 template <typename U>
148 RCPtr<U> static_pointer_cast() const noexcept;
149 template <typename U>
150 RCPtr<U> dynamic_pointer_cast() const noexcept;
151
152 private:
153 T *px;
154};
166template <typename T>
167RCPtr<T>::RCPtr() noexcept
168 : px(nullptr){};
194template <typename T>
195RCPtr<T>::RCPtr(T *p, const bool add_ref) noexcept
196 : px(p)
197{
198 if (px && add_ref)
200}
206template <typename T>
207RCPtr<T>::RCPtr(const RCPtr &rhs) noexcept
208 : px(rhs.px)
209{
210 if (px)
212}
218template <typename T>
219RCPtr<T>::RCPtr(RCPtr &&rhs) noexcept
220 : px(rhs.px)
221{
222 rhs.px = nullptr;
223}
232template <typename T>
233template <typename U>
234RCPtr<T>::RCPtr(const RCPtr<U> &rhs) noexcept
235 : px(rhs.get())
236{
237 if (px)
239}
248template <typename T>
250{
251 if (px)
253}
263template <typename T>
264RCPtr<T> &RCPtr<T>::operator=(const RCPtr &rhs) noexcept
265{
266 // notice that RCPtr(rhs) is a temp built from rhs, which will decrement old T when scope ends
267 RCPtr(rhs).swap(*this);
268 return *this;
269}
279template <typename T>
281{
282 RCPtr(std::move(rhs)).swap(*this);
283 return *this;
284}
289template <typename T>
290void RCPtr<T>::reset() noexcept
291{
292 RCPtr().swap(*this);
293}
300template <typename T>
301void RCPtr<T>::reset(T *rhs) noexcept
302{
303 RCPtr(rhs).swap(*this);
304}
310template <typename T>
311void RCPtr<T>::swap(RCPtr &rhs) noexcept
312{
313 std::swap(px, rhs.px);
314}
320template <typename T>
321T *RCPtr<T>::get() const noexcept
322{
323 return px;
324}
334template <typename T>
335T &RCPtr<T>::operator*() const noexcept
336{
337 return *px;
338}
344template <typename T>
345T *RCPtr<T>::operator->() const noexcept
346{
347 return px;
348}
355template <typename T>
356RCPtr<T>::operator bool() const noexcept
357{
358 return px != nullptr;
359}
368template <typename T>
369bool RCPtr<T>::operator==(const RCPtr &rhs) const
370{
371 return px == rhs.px;
372}
380template <typename T>
381bool RCPtr<T>::operator!=(const RCPtr &rhs) const
382{
383 return px != rhs.px;
384}
390template <typename T>
392{
393 T *p = px;
394 px = nullptr;
395 return RCPtr<T>(p, false);
396}
405template <typename T>
406template <typename U>
408{
409 return RCPtr<U>(static_cast<U *>(px));
410}
420template <typename T>
421template <typename U>
423{
424 return RCPtr<U>(dynamic_cast<U *>(px));
425}
449template <typename T>
451{
453
454 public:
455 using element_type = T;
456
457 RCWeakPtr() noexcept;
458 RCWeakPtr(const Strong &p) noexcept;
459 RCWeakPtr(T *p) noexcept;
460
461 void reset(const Strong &p) noexcept;
462 void reset(T *p) noexcept;
463 void reset() noexcept;
464
465 void swap(RCWeakPtr &other) noexcept;
466 olong use_count() const noexcept;
467 bool expired() const noexcept;
468 Strong lock() const noexcept;
469 Strong move_strong() noexcept;
470
471 private:
472 typename T::Controller::Ptr controller;
473};
478template <typename T>
479RCWeakPtr<T>::RCWeakPtr() noexcept {};
485template <typename T>
487{
488 if (p)
489 controller = p->refcount_.controller;
490}
496template <typename T>
498{
499 if (p)
500 controller = p->refcount_.controller;
501}
507template <typename T>
508void RCWeakPtr<T>::reset(const Strong &p) noexcept
509{
510 if (p)
511 controller = p->refcount_.controller;
512 else
513 controller.reset();
514}
520template <typename T>
521void RCWeakPtr<T>::reset(T *p) noexcept
522{
523 if (p)
524 controller = p->refcount_.controller;
525 else
526 controller.reset();
527}
532template <typename T>
533void RCWeakPtr<T>::reset() noexcept
534{
535 controller.reset();
536}
542template <typename T>
543void RCWeakPtr<T>::swap(RCWeakPtr &other) noexcept
544{
545 controller.swap(other.controller);
546}
555template <typename T>
557{
558 if (controller)
559 return controller->use_count();
560 return 0;
561}
568template <typename T>
569bool RCWeakPtr<T>::expired() const noexcept
570{
571 return use_count() == 0;
572}
581template <typename T>
583{
584 if (controller)
585 return controller->template lock<Strong>();
586 return Strong();
587}
596template <typename T>
598{
599 typename T::Controller::Ptr c;
600 c.swap(controller);
601 if (c)
602 return c->template lock<Strong>();
603 return Strong();
604}
605
606/* We're pretty sure these are false positives. They only occur with very
607 specific compiler versions and/or architectures.
608
609 For some reason some gcc versions think that the reference counter goes
610 away too soon when destructing certain MultiCompleteType objects. The
611 warnings/errors do not tell us why they think that.
612
613 So for now we display the warnings, but do not fail -Werror builds over
614 them. So that we can fail them for any other new warnings.
615 */
616#if !defined(__clang__) && defined(__GNUC__)
617#pragma GCC diagnostic push
618#if __GNUC__ == 12
619#pragma GCC diagnostic warning "-Wuse-after-free"
620#endif
621#if __GNUC__ == 13 || __GNUC__ == 14 || __GNUC__ == 15
622#pragma GCC diagnostic warning "-Wstringop-overflow"
623#endif
624#endif
638{
639 public:
640 thread_unsafe_refcount() noexcept;
641 void operator++() noexcept;
642 olong operator--() noexcept;
643 bool inc_if_nonzero() noexcept;
644 olong use_count() const noexcept;
645
646 static constexpr bool is_thread_safe();
647
648#ifdef OPENVPN_RC_NOTIFY
649 void notify_release() noexcept;
650#endif
651
652#ifdef OPENVPN_RC_NOTIFY
653 template <typename T>
654 class ListHead;
655#endif
656
657 private:
660
662};
668inline thread_unsafe_refcount::thread_unsafe_refcount() noexcept
669 : rc(olong(0)) {};
673inline void thread_unsafe_refcount::operator++() noexcept
674{
675 ++rc;
676}
681inline olong thread_unsafe_refcount::operator--() noexcept
682{
683 return --rc;
684}
690inline bool thread_unsafe_refcount::inc_if_nonzero() noexcept
691{
692 if (rc)
693 {
694 ++rc;
695 return true;
696 }
697 return false;
698}
703inline olong thread_unsafe_refcount::use_count() const noexcept
704{
705 return rc;
706}
714inline constexpr bool thread_unsafe_refcount::is_thread_safe()
715{
716 return false;
717}
718
719#ifdef OPENVPN_RC_NOTIFY
720inline void thread_unsafe_refcount::notify_release() noexcept
721{
722}
723#endif
724
725#ifdef OPENVPN_RC_NOTIFY
726template <typename T>
727class thread_unsafe_refcount::ListHead
728{
729 public:
730 ListHead() noexcept
731 : ptr(nullptr)
732 {
733 }
734
735 T *load() noexcept
736 {
737 return ptr;
738 }
739
740 void insert(T *item) noexcept
741 {
742 item->next = ptr;
743 ptr = item;
744 }
745
746 private:
747 ListHead(const ListHead &) = delete;
748 ListHead &operator=(const ListHead &) = delete;
749
750 T *ptr;
751};
752#endif
753
758{
759 public:
760 thread_safe_refcount() noexcept;
761 void operator++() noexcept;
762 olong operator--() noexcept;
763
764 bool inc_if_nonzero() noexcept;
765 olong use_count() const noexcept;
766 static constexpr bool is_thread_safe();
767
768#ifdef OPENVPN_RC_NOTIFY
769 void notify_release() noexcept;
770#endif
771
772#ifdef OPENVPN_RC_NOTIFY
773 template <typename T>
774 class ListHead;
775#endif
776
777 private:
780
781 std::atomic<olong> rc;
782};
786inline thread_safe_refcount::thread_safe_refcount() noexcept
787 : rc(olong(0))
788{
789}
793inline void thread_safe_refcount::operator++() noexcept
794{
795 rc.fetch_add(1, std::memory_order_relaxed);
796}
801inline olong thread_safe_refcount::operator--() noexcept
802{
803 // http://www.boost.org/doc/libs/1_55_0/doc/html/atomic/usage_examples.html
804 const olong ret = rc.fetch_sub(1, std::memory_order_release) - 1;
805 if (ret == 0)
806 std::atomic_thread_fence(std::memory_order_acquire);
807 return ret;
808}
816inline bool thread_safe_refcount::inc_if_nonzero() noexcept
817{
818 olong previous = rc.load(std::memory_order_relaxed);
819 while (true)
820 {
821 if (!previous)
822 break;
823 if (rc.compare_exchange_weak(previous, previous + 1, std::memory_order_relaxed))
824 break;
825 }
826 return previous > 0;
827}
832inline olong thread_safe_refcount::use_count() const noexcept
833{
834 return rc.load(std::memory_order_relaxed);
835}
843inline constexpr bool thread_safe_refcount::is_thread_safe()
844{
845 return true;
846}
847
848#ifdef OPENVPN_RC_NOTIFY
849inline void thread_safe_refcount::notify_release() noexcept
850{
851}
852#endif
853
854#ifdef OPENVPN_RC_NOTIFY
855template <typename T>
856class thread_safe_refcount::ListHead
857{
858 public:
859 ListHead() noexcept
860 : ptr(nullptr)
861 {
862 }
863
864 T *load() noexcept
865 {
866 return ptr;
867 }
868
869 void insert(T *item) noexcept
870 {
871 item->next = ptr;
872 ptr = item;
873 }
874
875 private:
876 ListHead(const ListHead &) = delete;
877 ListHead &operator=(const ListHead &) = delete;
878
879 T *ptr;
880};
881#endif
882
883
884#if !defined(__clang__) && defined(__GNUC__)
885#pragma GCC diagnostic pop
886#endif
887
906template <typename RCImpl>
907class RC
908{
909 public:
910 using Ptr = RCPtr<RC>;
911
912 RC() noexcept = default;
913 virtual ~RC() = default;
914 RC(const RC &) = delete;
915 RC &operator=(const RC &) = delete;
916
917 olong use_count() const noexcept;
918 static constexpr bool is_thread_safe();
919
920 private:
921 template <typename R>
922 friend void intrusive_ptr_add_ref(R *rcptr) noexcept;
923 template <typename R>
924 friend void intrusive_ptr_release(R *rcptr) noexcept;
925 RCImpl refcount_;
926};
932template <typename RCImpl>
933olong RC<RCImpl>::use_count() const noexcept
934{
935 return refcount_.use_count();
936}
943template <typename RCImpl>
945{
946 return RCImpl::is_thread_safe();
947}
948
973template <typename RCImpl>
975{
976 public:
977 virtual ~RCCopyable() = default;
978 RCCopyable() noexcept = default;
979 RCCopyable(const RCCopyable &) noexcept;
980 RCCopyable(RCCopyable &&) noexcept;
981 RCCopyable &operator=(const RCCopyable &) noexcept;
982 RCCopyable &operator=(RCCopyable &&) noexcept;
983 olong use_count() const noexcept;
984
985 private:
986 template <typename R>
987 friend void intrusive_ptr_add_ref(R *rcptr) noexcept;
988 template <typename R>
989 friend void intrusive_ptr_release(R *rcptr) noexcept;
990 RCImpl refcount_;
991};
992
1003template <typename RCImpl>
1004RCCopyable<RCImpl>::RCCopyable(const RCCopyable &) noexcept {};
1015template <typename RCImpl>
1028template <typename RCImpl>
1030{
1031 return *this;
1032}
1044template <typename RCImpl>
1046{
1047 return *this;
1048}
1054template <typename RCImpl>
1056{
1057 return refcount_.use_count();
1058}
1059
1084template <typename RCImpl> // RCImpl = thread_safe_refcount or thread_unsafe_refcount
1086{
1087 template <typename T>
1088 friend class RCWeakPtr;
1089
1090#ifdef OPENVPN_RC_NOTIFY
1091 // Base class of release notification callables
1092 class NotifyBase;
1093 // A release notification callable
1094 template <typename CALLABLE>
1095 class NotifyItem;
1096 // Head of a linked-list of release notification callables
1097 class NotifyListHead;
1098#endif
1099
1100 struct Controller;
1101 struct ControllerRef;
1102
1103 public:
1106
1107 RCWeak() noexcept
1108 : refcount_(this) {};
1109
1110 virtual ~RCWeak() = default;
1111 RCWeak(const RCWeak &) = delete;
1112 RCWeak &operator=(const RCWeak &) = delete;
1113
1114#ifdef OPENVPN_RC_NOTIFY
1115 // Add observers to be called just prior to object deletion,
1116 // but after refcount has been decremented to 0. At this
1117 // point, all weak pointers have expired, and no strong
1118 // pointers are outstanding. Callables can access the
1119 // object by raw pointer but must NOT attempt to create a
1120 // strong pointer referencing the object.
1121
1122 template <typename CALLABLE>
1123 void rc_release_notify(const CALLABLE &c) noexcept
1124 {
1125 refcount_.notify.add(c);
1126 }
1127
1128 template <typename CALLABLE>
1129 void rc_release_notify(CALLABLE &&c) noexcept
1130 {
1131 refcount_.notify.add(std::move(c));
1132 }
1133#endif
1134
1135 private:
1136 template <typename R>
1137 friend void intrusive_ptr_add_ref(R *rcptr) noexcept;
1138 template <typename R>
1139 friend void intrusive_ptr_release(R *rcptr) noexcept;
1140
1142};
1143
1180template <typename RCImpl>
1181struct RCWeak<RCImpl>::Controller : public RC<RCImpl>
1182{
1184
1185 Controller(RCWeak *parent_arg) noexcept;
1186
1187 olong use_count() const noexcept;
1188
1189 template <typename PTR>
1190 PTR lock() noexcept;
1191
1192 RCWeak *const parent;
1193 RCImpl rc;
1194};
1200template <typename RCImpl>
1201RCWeak<RCImpl>::Controller::Controller(RCWeak *parent_arg) noexcept
1202 : parent(parent_arg){};
1208template <typename RCImpl>
1210{
1211 return rc.use_count();
1212}
1222template <typename RCImpl>
1223template <typename PTR>
1225{
1226 if (rc.inc_if_nonzero())
1227 return PTR(static_cast<typename PTR::element_type *>(parent), false);
1228 return PTR();
1229}
1230
1238template <typename RCImpl>
1239struct RCWeak<RCImpl>::ControllerRef
1240{
1241 explicit ControllerRef(RCWeak *parent) noexcept;
1242
1243 void operator++() noexcept;
1244 olong operator--() noexcept;
1245
1246#ifdef OPENVPN_RC_NOTIFY
1247 void notify_release() noexcept;
1248#endif
1249
1251
1252#ifdef OPENVPN_RC_NOTIFY
1253 NotifyListHead notify; // linked list of callables to be notified on object release
1254#endif
1255};
1263template <typename RCImpl>
1265 : controller(new Controller(parent)){};
1273template <typename RCImpl>
1275{
1276 ++controller->rc;
1277}
1285template <typename RCImpl>
1287{
1288 return --controller->rc;
1289}
1290
1291#ifdef OPENVPN_RC_NOTIFY
1292template <typename RCImpl>
1294{
1295 notify.release();
1296}
1297#endif
1298
1299#ifdef OPENVPN_RC_NOTIFY
1300// Base class of release notification callables
1301template <typename RCImpl>
1302class RCWeak<RCImpl>::NotifyBase
1303{
1304 public:
1305 NotifyBase() noexcept = default;
1306 virtual void call() noexcept = 0;
1307 virtual ~NotifyBase() = default;
1308 NotifyBase *next = nullptr;
1309
1310 private:
1311 NotifyBase(const NotifyBase &) = delete;
1312 NotifyBase &operator=(const NotifyBase &) = delete;
1313};
1314
1315// A release notification callable
1316template <typename RCImpl>
1317template <typename CALLABLE>
1318class RCWeak<RCImpl>::NotifyItem : public NotifyBase
1319{
1320 public:
1321 NotifyItem(const CALLABLE &c) noexcept
1322 : callable(c)
1323 {
1324 }
1325
1326 NotifyItem(CALLABLE &&c) noexcept
1327 : callable(std::move(c))
1328 {
1329 }
1330
1331 private:
1332 void call() noexcept override
1333 {
1334 callable();
1335 }
1336
1337 CALLABLE callable;
1338};
1339
1340// Head of a linked-list of release notification callables
1341template <typename RCImpl>
1342class RCWeak<RCImpl>::NotifyListHead
1343{
1344 public:
1345 NotifyListHead() noexcept
1346 {
1347 }
1348
1349 template <typename CALLABLE>
1350 void add(const CALLABLE &c) noexcept
1351 {
1352 NotifyBase *item = new NotifyItem<CALLABLE>(c);
1353 head.insert(item);
1354 }
1355
1356 template <typename CALLABLE>
1357 void add(CALLABLE &&c) noexcept
1358 {
1359 NotifyBase *item = new NotifyItem<CALLABLE>(std::move(c));
1360 head.insert(item);
1361 }
1362
1363 void release() noexcept
1364 {
1365 // In thread-safe mode, list traversal is guaranteed to be
1366 // contention-free because we are not called until refcount
1367 // reaches zero and after a std::memory_order_acquire fence.
1368 NotifyBase *nb = head.load();
1369 while (nb)
1370 {
1371 NotifyBase *next = nb->next;
1372 nb->call();
1373 delete nb;
1374 nb = next;
1375 }
1376 }
1377
1378 private:
1379 NotifyListHead(const NotifyListHead &) = delete;
1380 NotifyListHead &operator=(const NotifyListHead &) = delete;
1381
1382 typename RCImpl::template ListHead<NotifyBase> head;
1383};
1384#endif
1394template <typename R>
1395inline void intrusive_ptr_add_ref(R *rcptr) noexcept
1396{
1397#ifdef OPENVPN_RC_DEBUG
1398 std::cout << "ADD REF " << cxx_demangle(typeid(rcptr).name()) << "\n";
1399#endif
1400 ++rcptr->refcount_;
1401}
1412template <typename R>
1413inline void intrusive_ptr_release(R *rcptr) noexcept
1414{
1415 if (--rcptr->refcount_ == 0)
1416 {
1417#ifdef OPENVPN_RC_DEBUG
1418 std::cout << "DEL OBJ " << cxx_demangle(typeid(rcptr).name()) << "\n";
1419#endif
1420#ifdef OPENVPN_RC_NOTIFY
1421 rcptr->refcount_.notify_release();
1422#endif
1423 delete rcptr;
1424 }
1425 else
1426 {
1427#ifdef OPENVPN_RC_DEBUG
1428 std::cout << "REL REF " << cxx_demangle(typeid(rcptr).name()) << "\n";
1429#endif
1430 }
1431}
1432
1433} // namespace openvpn
1434
1435#endif // OPENVPN_COMMON_RC_H
Reference count base class for objects tracked by RCPtr. Allows copying and assignment.
Definition rc.hpp:975
RCCopyable() noexcept=default
virtual ~RCCopyable()=default
olong use_count() const noexcept
Returns the use count as reported by defering to the injected ref count type.
Definition rc.hpp:1055
The smart pointer class.
Definition rc.hpp:119
T * px
Pointer to the controlled object.
Definition rc.hpp:153
T * operator->() const noexcept
Returns the raw pointer to the object T, or nullptr.
Definition rc.hpp:345
RCPtr< U > static_pointer_cast() const noexcept
Returns a "RCPtr<U>" that points to our T object.
Definition rc.hpp:407
~RCPtr()
Destroy the RCPtr<T>::RCPtr object.
Definition rc.hpp:249
RCPtr() noexcept
Construct a new RCPtr<T>::RCPtr object.
Definition rc.hpp:167
RCPtr< T > move_strong() noexcept
Moves ownership of the internal pointer to the returned RCPtr<T>
Definition rc.hpp:391
void reset() noexcept
Points this RCPtr<T> to nullptr safely.
Definition rc.hpp:290
void swap(RCPtr &rhs) noexcept
swaps the contents of two RCPtr<T>
Definition rc.hpp:311
bool operator==(const RCPtr &rhs) const
Evaluates to true if the two RCPtr<T> point to the same object.
Definition rc.hpp:369
RCPtr< U > dynamic_pointer_cast() const noexcept
Returns a "RCPtr<U>" that points to our T object.
Definition rc.hpp:422
T & operator*() const noexcept
Operator returns a ref to the pointed to T.
Definition rc.hpp:335
bool operator!=(const RCPtr &rhs) const
Evaluates to true if the two RCPtr<T> point to different objects.
Definition rc.hpp:381
T * get() const noexcept
Returns the raw pointer to the object T, or nullptr.
Definition rc.hpp:321
RCPtr & operator=(const RCPtr &rhs) noexcept
Assigns an existing RCPtr<T> to point to a different T.
Definition rc.hpp:264
implements a weak pointer for reference counted objects.
Definition rc.hpp:451
void swap(RCWeakPtr &other) noexcept
Swaps thing pointed to by *this withthing pointed to by other.
Definition rc.hpp:543
olong use_count() const noexcept
Returns count of references to the object.
Definition rc.hpp:556
T::Controller::Ptr controller
Smart pointer to the T::ControllerF.
Definition rc.hpp:472
void reset(const Strong &p) noexcept
Reassign this weak ptr to the object referenced by the given strong (RCPtr) pointer.
Definition rc.hpp:508
Reference count base class for objects tracked by RCPtr. Like RC, but also allows weak pointers and r...
Definition rc.hpp:1086
RCWeak() noexcept
Definition rc.hpp:1107
RCWeak & operator=(const RCWeak &)=delete
ControllerRef refcount_
Adapter instance that allows RCPtr to properly interact with RCWeak.
Definition rc.hpp:1141
RCWeak(const RCWeak &)=delete
virtual ~RCWeak()=default
Reference count base class for objects tracked by RCPtr. Disallows copying and assignment.
Definition rc.hpp:908
olong use_count() const noexcept
Delegates call to RCImpl and returns the result.
Definition rc.hpp:933
RC() noexcept=default
Implements a memory fenced ref count.
Definition rc.hpp:758
thread_safe_refcount & operator=(const thread_safe_refcount &)=delete
thread_safe_refcount(const thread_safe_refcount &)=delete
std::atomic< olong > rc
Definition rc.hpp:781
implements a simple reference count for objects.
Definition rc.hpp:638
thread_unsafe_refcount(const thread_unsafe_refcount &)=delete
olong rc
The reference count, platform efficient integer type.
Definition rc.hpp:661
thread_unsafe_refcount & operator=(const thread_unsafe_refcount &)=delete
std::string call(const std::string &cmd)
Definition call.hpp:31
void intrusive_ptr_release(R *rcptr) noexcept
Helper to decrement a ref count.
Definition rc.hpp:1413
long olong
Definition olong.hpp:23
std::string cxx_demangle(const char *mangled_name)
Definition demangle.hpp:24
void intrusive_ptr_add_ref(R *rcptr) noexcept
Helper to increment a ref count.
Definition rc.hpp:1395
Adapter object for RCWeak::Controller <—> RCPtr.
Definition rc.hpp:1240
Controller::Ptr controller
object containing actual refcount
Definition rc.hpp:1250
Controller structure for our ptr/weakptr implementation.
Definition rc.hpp:1182
std::string ret
static void add(const Time &t1, const Time::Duration &d1)