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 2778 : IntrusivePtrRef() : boost::intrusive_ptr<D>(), referrer_(NULL) { 24 2778 : } 25 : 26 1156 : IntrusivePtrRef(D *data) : boost::intrusive_ptr<D>(data), referrer_(NULL) { 27 1156 : if (data) { 28 3 : intrusive_ptr_add_back_ref(IntrusiveReferrer(referrer_, this), data); 29 : } 30 1156 : } 31 : 32 9463 : IntrusivePtrRef(D *data, void *referrer) : boost::intrusive_ptr<D>(data), 33 9463 : referrer_(referrer) { 34 9463 : if (data) { 35 713 : intrusive_ptr_add_back_ref(IntrusiveReferrer(referrer, this), data); 36 : } 37 9463 : } 38 : 39 60 : IntrusivePtrRef(IntrusivePtrRef const &rhs, void *referrer) 40 60 : : boost::intrusive_ptr<D>(rhs), referrer_(referrer) { 41 60 : if (this->get()) { 42 0 : intrusive_ptr_add_back_ref(IntrusiveReferrer(referrer, this), 43 0 : this->get()); 44 : } 45 60 : } 46 : 47 14776 : virtual ~IntrusivePtrRef() { 48 14776 : if (this->get()) { 49 1893 : intrusive_ptr_del_back_ref(IntrusiveReferrer(referrer_, this), this->get()); 50 : } 51 29552 : } 52 : 53 46 : IntrusivePtrRef & operator=(IntrusivePtrRef const &rhs) { 54 46 : IntrusivePtrRef(rhs, this).swap(*this); 55 46 : return *this; 56 : } 57 : 58 394 : IntrusivePtrRef & operator=(D *rhs) { 59 394 : IntrusivePtrRef(rhs, this).swap(*this); 60 394 : 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 452 : void swap(IntrusivePtrRef &rhs) { 72 : // Trigger Base class swap to swap values 73 452 : boost::intrusive_ptr<D>::swap(rhs); 74 : 75 : // swap the referrer for this and rhs 76 452 : D *tmp = this->get(); 77 452 : if (tmp) { 78 : // change referrer for new value of IntrusivePtrRef 79 144 : intrusive_ptr_add_back_ref(IntrusiveReferrer(referrer_, this), tmp); 80 144 : intrusive_ptr_del_back_ref(IntrusiveReferrer(rhs.referrer_, &rhs), tmp); 81 : } 82 452 : tmp = rhs.get(); 83 452 : if (tmp) { 84 : // change referrer for new value of rhs 85 249 : intrusive_ptr_add_back_ref(IntrusiveReferrer(rhs.referrer_, &rhs), tmp); 86 249 : intrusive_ptr_del_back_ref(IntrusiveReferrer(referrer_, this), tmp); 87 : } 88 452 : } 89 : 90 : private: 91 : void *referrer_; 92 : }; 93 : 94 : #endif // SRC_BASE_INTRUSIVE_PTR_BACK_REF_H_