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