/////////////////////////////////////////////////////////////////////////////// // tracking_ptr.hpp // // Copyright 2007 Eric Niebler. Distributed under the Boost // Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #ifndef BOOST_XPRESSIVE_DETAIL_UTILITY_TRACKING_PTR_HPP_EAN_10_04_2005 #define BOOST_XPRESSIVE_DETAIL_UTILITY_TRACKING_PTR_HPP_EAN_10_04_2005 // MS compatible compilers support #pragma once #if defined(_MSC_VER) && (_MSC_VER >= 1020) # pragma once #endif #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER # include #endif #include #include #include #include #include #include #include #include #include #include #include #include namespace boost { namespace xpressive { namespace detail { template struct tracking_ptr; template struct enable_reference_tracking; /////////////////////////////////////////////////////////////////////////////// // weak_iterator // steps through a set of weak_ptr, converts to shared_ptrs on the fly and // removes from the set the weak_ptrs that have expired. template struct weak_iterator : iterator_facade < weak_iterator , shared_ptr const , std::forward_iterator_tag > { typedef std::set > set_type; typedef typename set_type::iterator base_iterator; weak_iterator() : cur_() , iter_() , set_(0) { } weak_iterator(base_iterator iter, set_type *set) : cur_() , iter_(iter) , set_(set) { this->satisfy_(); } private: friend class boost::iterator_core_access; shared_ptr const &dereference() const { return this->cur_; } void increment() { ++this->iter_; this->satisfy_(); } bool equal(weak_iterator const &that) const { return this->iter_ == that.iter_; } void satisfy_() { while(this->iter_ != this->set_->end()) { this->cur_ = this->iter_->lock(); if(this->cur_) return; base_iterator tmp = this->iter_++; this->set_->erase(tmp); } this->cur_.reset(); } shared_ptr cur_; base_iterator iter_; set_type *set_; }; /////////////////////////////////////////////////////////////////////////////// // filter_self // for use with a filter_iterator to filter a node out of a list of dependencies template struct filter_self : std::unary_function, bool> { filter_self(enable_reference_tracking *self) : self_(self) { } bool operator ()(shared_ptr const &that) const { return this->self_ != that.get(); } private: enable_reference_tracking *self_; }; /////////////////////////////////////////////////////////////////////////////// // swap without bringing in std::swap -- must be found by ADL. template void adl_swap(T &t1, T &t2) { swap(t1, t2); } /////////////////////////////////////////////////////////////////////////////// // enable_reference_tracking // inherit from this type to enable reference tracking for a type. You can // then use tracking_ptr (below) as a holder for derived objects. // template struct enable_reference_tracking { typedef std::set > references_type; typedef std::set > dependents_type; void tracking_copy(Derived const &that) { if(&this->derived_() != &that) { this->raw_copy_(that); this->tracking_update(); } } void tracking_clear() { this->raw_copy_(Derived()); } // called automatically as a result of a tracking_copy(). Must be called explicitly // if you change the references without calling tracking_copy(). void tracking_update() { // add "this" as a dependency to all the references this->update_references_(); // notify our dependencies that we have new references this->update_dependents_(); } void track_reference(enable_reference_tracking &that) { // avoid some unbounded memory growth in certain circumstances by // opportunistically removing stale dependencies from "that" that.purge_stale_deps_(); // add "that" as a reference this->refs_.insert(that.self_); // also inherit that's references this->refs_.insert(that.refs_.begin(), that.refs_.end()); } long use_count() const { return this->cnt_; } void add_ref() { ++this->cnt_; } void release() { BOOST_ASSERT(0 < this->cnt_); if(0 == --this->cnt_) { this->refs_.clear(); this->self_.reset(); } } //{{AFX_DEBUG #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER friend std::ostream &operator <<(std::ostream &sout, enable_reference_tracking const &that) { that.dump_(sout); return sout; } #endif //}}AFX_DEBUG protected: enable_reference_tracking() : refs_() , deps_() , self_() , cnt_(0) { } enable_reference_tracking(enable_reference_tracking const &that) : refs_() , deps_() , self_() , cnt_(0) { this->operator =(that); } enable_reference_tracking &operator =(enable_reference_tracking const &that) { references_type(that.refs_).swap(this->refs_); return *this; } void swap(enable_reference_tracking &that) { this->refs_.swap(that.refs_); } private: friend struct tracking_ptr; Derived &derived_() { return *static_cast(this); } void raw_copy_(Derived that) { detail::adl_swap(this->derived_(), that); } bool has_deps_() const { return !this->deps_.empty(); } void update_references_() { typename references_type::iterator cur = this->refs_.begin(); typename references_type::iterator end = this->refs_.end(); for(; cur != end; ++cur) { // for each reference, add this as a dependency (*cur)->track_dependency_(*this); } } void update_dependents_() { // called whenever this regex object changes (i.e., is assigned to). it walks // the list of dependent regexes and updates *their* lists of references, // thereby spreading out the reference counting responsibility evenly. weak_iterator cur(this->deps_.begin(), &this->deps_); weak_iterator end(this->deps_.end(), &this->deps_); for(; cur != end; ++cur) { (*cur)->track_reference(*this); } } void track_dependency_(enable_reference_tracking &dep) { if(this == &dep) // never add ourself as a dependency return; // add dep as a dependency this->deps_.insert(dep.self_); filter_self not_self(this); weak_iterator begin(dep.deps_.begin(), &dep.deps_); weak_iterator end(dep.deps_.end(), &dep.deps_); // also inherit dep's dependencies this->deps_.insert( make_filter_iterator(not_self, begin, end) , make_filter_iterator(not_self, end, end) ); } void purge_stale_deps_() { weak_iterator cur(this->deps_.begin(), &this->deps_); weak_iterator end(this->deps_.end(), &this->deps_); for(; cur != end; ++cur) ; } //{{AFX_DEBUG #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER void dump_(std::ostream &sout) const; #endif //}}AFX_DEBUG references_type refs_; dependents_type deps_; shared_ptr self_; boost::detail::atomic_count cnt_; }; template inline void intrusive_ptr_add_ref(enable_reference_tracking *p) { p->add_ref(); } template inline void intrusive_ptr_release(enable_reference_tracking *p) { p->release(); } //{{AFX_DEBUG #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER /////////////////////////////////////////////////////////////////////////////// // dump_ // template inline void enable_reference_tracking::dump_(std::ostream &sout) const { shared_ptr this_ = this->self_; sout << "0x" << (void*)this << " cnt=" << this_.use_count()-1 << " refs={"; typename references_type::const_iterator cur1 = this->refs_.begin(); typename references_type::const_iterator end1 = this->refs_.end(); for(; cur1 != end1; ++cur1) { sout << "0x" << (void*)&**cur1 << ','; } sout << "} deps={"; typename dependents_type::const_iterator cur2 = this->deps_.begin(); typename dependents_type::const_iterator end2 = this->deps_.end(); for(; cur2 != end2; ++cur2) { // ericne, 27/nov/05: CW9_4 doesn't like if(shared_ptr x = y) shared_ptr dep = cur2->lock(); if(dep.get()) { sout << "0x" << (void*)&*dep << ','; } } sout << '}'; } #endif //}}AFX_DEBUG /////////////////////////////////////////////////////////////////////////////// // tracking_ptr // holder for a reference-tracked type. Does cycle-breaking, lazy initialization // and copy-on-write. TODO: implement move semantics. // template struct tracking_ptr { BOOST_MPL_ASSERT((is_base_and_derived, Type>)); typedef Type element_type; tracking_ptr() : impl_() { } tracking_ptr(tracking_ptr const &that) : impl_() { this->operator =(that); } tracking_ptr &operator =(tracking_ptr const &that) { // Note: the copy-and-swap idiom doesn't work here if has_deps_()==true // because it invalidates references to the element_type object. if(this != &that) { if(that) { if(that.has_deps_() || this->has_deps_()) { this->fork_(); // deep copy, forks data if necessary this->impl_->tracking_copy(*that); } else { this->impl_ = that.impl_; // shallow, copy-on-write } } else if(*this) { this->impl_->tracking_clear(); } } return *this; } // NOTE: this does *not* do tracking. Can't provide a non-throwing swap that tracks references void swap(tracking_ptr &that) // throw() { this->impl_.swap(that.impl_); } // calling this forces this->impl_ to fork. shared_ptr const &get() const { if(intrusive_ptr impl = this->fork_()) { this->impl_->tracking_copy(*impl); } return this->impl_->self_; } #if defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x530) typedef bool unspecified_bool_type; #else typedef typename intrusive_ptr::unspecified_bool_type unspecified_bool_type; #endif // smart-pointer operators operator unspecified_bool_type() const { return this->impl_; } bool operator !() const { return !this->impl_; } // Since this does not un-share the data, it returns a ptr-to-const element_type const *operator ->() const { return get_pointer(this->impl_); } // Since this does not un-share the data, it returns a ref-to-const element_type const &operator *() const { return *this->impl_; } private: // calling this forces impl_ to fork. intrusive_ptr fork_() const { intrusive_ptr impl; if(!this->impl_ || 1 != this->impl_->use_count()) { impl = this->impl_; BOOST_ASSERT(!this->has_deps_()); shared_ptr simpl(new element_type); this->impl_ = get_pointer(simpl->self_ = simpl); } return impl; } // does anybody have a dependency on us? bool has_deps_() const { return this->impl_ && this->impl_->has_deps_(); } // mutable to allow lazy initialization mutable intrusive_ptr impl_; }; }}} // namespace boost::xpressive::detail #endif