Line data Source code
1 : /* 2 : * Copyright (c) 2015 Juniper Networks, Inc. All rights reserved. 3 : */ 4 : 5 : #ifndef SRC_BASE_INTRUSIVE_PTR_BACK_REF_H_ 6 : #define SRC_BASE_INTRUSIVE_PTR_BACK_REF_H_ 7 : 8 : #include <boost/intrusive_ptr.hpp> 9 : 10 : // IntrusivePtrRef Class is an extension to boost::intrusive_ptr 11 : // to provide additional functionality of making back reference 12 : // pointer available with callbacks intrusive_ptr_add_back_ref 13 : // and intrusive_ptr_del_back_ref, using which application using 14 : // IntrusivePtrRef can keep track of pointers who holds references 15 : // to the object 16 : 17 : // referrer, pair of base pointer and member pointer 18 : typedef std::pair<void*, void*> IntrusiveReferrer; 19 : 20 : template <class D> 21 : class IntrusivePtrRef : public boost::intrusive_ptr<D> { 22 : public: 23 2559 : IntrusivePtrRef() : boost::intrusive_ptr<D>(), referrer_(NULL) { 24 2559 : } 25 : 26 1082 : IntrusivePtrRef(D *data) : boost::intrusive_ptr<D>(data), referrer_(NULL) { 27 1082 : if (data) { 28 1 : intrusive_ptr_add_back_ref(IntrusiveReferrer(referrer_, this), data); 29 : } 30 1082 : } 31 : 32 8919 : IntrusivePtrRef(D *data, void *referrer) : boost::intrusive_ptr<D>(data), 33 8919 : referrer_(referrer) { 34 8919 : if (data) { 35 655 : intrusive_ptr_add_back_ref(IntrusiveReferrer(referrer, this), data); 36 : } 37 8919 : } 38 : 39 63 : IntrusivePtrRef(IntrusivePtrRef const &rhs, void *referrer) 40 63 : : boost::intrusive_ptr<D>(rhs), referrer_(referrer) { 41 63 : if (this->get()) { 42 0 : intrusive_ptr_add_back_ref(IntrusiveReferrer(referrer, this), 43 0 : this->get()); 44 : } 45 63 : } 46 : 47 13673 : virtual ~IntrusivePtrRef() { 48 13673 : if (this->get()) { 49 1565 : intrusive_ptr_del_back_ref(IntrusiveReferrer(referrer_, this), this->get()); 50 : } 51 27346 : } 52 : 53 48 : IntrusivePtrRef & operator=(IntrusivePtrRef const &rhs) { 54 48 : IntrusivePtrRef(rhs, this).swap(*this); 55 48 : return *this; 56 : } 57 : 58 334 : IntrusivePtrRef & operator=(D *rhs) { 59 334 : IntrusivePtrRef(rhs, this).swap(*this); 60 334 : return *this; 61 : } 62 : 63 0 : void reset() { 64 0 : IntrusivePtrRef(NULL, this).swap(*this); 65 0 : } 66 : 67 12 : void reset(D *rhs) { 68 12 : IntrusivePtrRef(rhs, this).swap(*this); 69 12 : } 70 : 71 394 : void swap(IntrusivePtrRef &rhs) { 72 : // Trigger Base class swap to swap values 73 394 : boost::intrusive_ptr<D>::swap(rhs); 74 : 75 : // swap the referrer for this and rhs 76 394 : D *tmp = this->get(); 77 394 : if (tmp) { 78 : // change referrer for new value of IntrusivePtrRef 79 121 : intrusive_ptr_add_back_ref(IntrusiveReferrer(referrer_, this), tmp); 80 121 : intrusive_ptr_del_back_ref(IntrusiveReferrer(rhs.referrer_, &rhs), tmp); 81 : } 82 394 : tmp = rhs.get(); 83 394 : if (tmp) { 84 : // change referrer for new value of rhs 85 209 : intrusive_ptr_add_back_ref(IntrusiveReferrer(rhs.referrer_, &rhs), tmp); 86 209 : intrusive_ptr_del_back_ref(IntrusiveReferrer(referrer_, this), tmp); 87 : } 88 394 : } 89 : 90 : private: 91 : void *referrer_; 92 : }; 93 : 94 : #endif // SRC_BASE_INTRUSIVE_PTR_BACK_REF_H_