3 * Author: Lukas Krejci <krejci.l@centrum.cz>, (C) 2008
4 * Copyright: See COPYING file that comes with this distribution
7 #ifndef BEACON_intrusive_ptr_H
8 #define BEACON_intrusive_ptr_H
10 #include <beacon/reference_countable.hpp>
11 #include <functional> // for std::less
12 #include <iosfwd> // for std::basic_ostream
15 #include <atomic_ops.h>
21 * A simple shared pointer implementation inspired by
22 * boost::intrusive_ptr that only adds a cas() operation to
23 * the usual mix of ops.
25 * It depends on two functions being overriden for type T:
27 * beacon_intrusive_ptr_add_ref(T *)
28 * beacon_intrusive_ptr_release(T *)
31 * The first is called when a reference count should be increased,
32 * the second when it should be decreased. It is the user's
33 * responsibility to implement those functions properly.
35 * beacon::reference_countable implements those functions so
36 * that any reference_countable instance is usable with this shared
37 * pointer implementation.
43 intrusive_ptr() : _p(0) {}
45 intrusive_ptr(T
* p
, bool add_ref
= true) : _p(p
) {
46 if (_p
!= 0 && add_ref
) {
47 beacon_intrusive_ptr_add_ref(_p
);
51 intrusive_ptr(intrusive_ptr
const & rhs
) : _p(rhs
._p
) {
52 if (_p
!= 0) beacon_intrusive_ptr_add_ref(_p
);
56 if (_p
!= 0) beacon_intrusive_ptr_release(_p
);
59 intrusive_ptr
& operator=(intrusive_ptr
const & rhs
) {
60 intrusive_ptr
<T
>(rhs
).swap(*this);
64 intrusive_ptr
& operator=(T
* rhs
) {
65 intrusive_ptr
<T
>(rhs
).swap(*this);
73 T
& operator*() const {
77 T
* operator->() const {
81 void swap(intrusive_ptr
& rhs
) {
87 typedef T
* intrusive_ptr
<T
>::*unspecified_bool_type
;
89 operator unspecified_bool_type () const {
90 return _p
== 0? 0: &intrusive_ptr
<T
>::_p
;
103 * @p cmp the shared_ptr to compare with
104 * @p xchg the shared_ptr to change this instance to
106 bool cas(intrusive_ptr
<T
> & cmp
, intrusive_ptr
<T
> & xchg
) {
107 AO_t
* my_ao
= (AO_t
*)(&_p
);
108 AO_t cmp_ao
= (AO_t
)(cmp
.get());
109 AO_t xchg_ao
= (AO_t
)(xchg
.get());
111 if (AO_compare_and_swap(my_ao
, cmp_ao
, xchg_ao
)) {
112 //I assigned the xchg pointer to me, tossing away
113 //my former reference that used to be the same as cmp's.
114 beacon_intrusive_ptr_add_ref(_p
);
115 beacon_intrusive_ptr_release((T
*)cmp_ao
);
127 template<class T
, class U
> inline bool operator==(intrusive_ptr
<T
> const & a
, intrusive_ptr
<U
> const & b
)
129 return a
.get() == b
.get();
132 template<class T
, class U
> inline bool operator!=(intrusive_ptr
<T
> const & a
, intrusive_ptr
<U
> const & b
)
134 return a
.get() != b
.get();
137 template<class T
, class U
> inline bool operator==(intrusive_ptr
<T
> const & a
, U
* b
)
142 template<class T
, class U
> inline bool operator!=(intrusive_ptr
<T
> const & a
, U
* b
)
147 template<class T
, class U
> inline bool operator==(T
* a
, intrusive_ptr
<U
> const & b
)
152 template<class T
, class U
> inline bool operator!=(T
* a
, intrusive_ptr
<U
> const & b
)
157 template<class T
> inline bool operator<(intrusive_ptr
<T
> const & a
, intrusive_ptr
<T
> const & b
)
159 return std::less
<T
*>()(a
.get(), b
.get());
162 template<class T
> void swap(intrusive_ptr
<T
> & lhs
, intrusive_ptr
<T
> & rhs
)
169 template<class T
> T
* get_pointer(intrusive_ptr
<T
> const & p
)
174 template<class T
, class U
> intrusive_ptr
<T
> static_pointer_cast(intrusive_ptr
<U
> const & p
)
176 return static_cast<T
*>(p
.get());
179 template<class T
, class U
> intrusive_ptr
<T
> const_pointer_cast(intrusive_ptr
<U
> const & p
)
181 return const_cast<T
*>(p
.get());
184 template<class T
, class U
> intrusive_ptr
<T
> dynamic_pointer_cast(intrusive_ptr
<U
> const & p
)
186 return dynamic_cast<T
*>(p
.get());
189 template<class E
, class T
, class Y
> std::basic_ostream
<E
, T
> & operator<< (std::basic_ostream
<E
, T
> & os
, intrusive_ptr
<Y
> const & p
)