1 ///////////////////////////////////////////////////////////////////////////////
4 // Copyright 2008 Eric Niebler. Distributed under the Boost
5 // Software License, Version 1.0. (See accompanying file
6 // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
8 #ifndef BOOST_XPRESSIVE_DETAIL_UTILITY_TRACKING_PTR_HPP_EAN_10_04_2005
9 #define BOOST_XPRESSIVE_DETAIL_UTILITY_TRACKING_PTR_HPP_EAN_10_04_2005
11 // MS compatible compilers support #pragma once
16 #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER
21 #include <boost/config.hpp>
22 #include <boost/assert.hpp>
23 #include <boost/weak_ptr.hpp>
24 #include <boost/shared_ptr.hpp>
25 #include <boost/mpl/assert.hpp>
26 #include <boost/intrusive_ptr.hpp>
27 #include <boost/detail/workaround.hpp>
28 #include <boost/detail/atomic_count.hpp>
29 #include <boost/iterator/iterator_facade.hpp>
30 #include <boost/iterator/filter_iterator.hpp>
31 #include <boost/type_traits/is_base_and_derived.hpp>
33 namespace boost { namespace xpressive { namespace detail
36 template<typename Type>
39 template<typename Derived>
40 struct enable_reference_tracking;
42 ///////////////////////////////////////////////////////////////////////////////
44 // steps through a set of weak_ptr, converts to shared_ptrs on the fly and
45 // removes from the set the weak_ptrs that have expired.
46 template<typename Derived>
50 weak_iterator<Derived>
51 , shared_ptr<Derived> const
52 , std::forward_iterator_tag
55 typedef std::set<weak_ptr<Derived> > set_type;
56 typedef typename set_type::iterator base_iterator;
65 weak_iterator(base_iterator iter, set_type *set)
74 friend class boost::iterator_core_access;
76 shared_ptr<Derived> const &dereference() const
87 bool equal(weak_iterator<Derived> const &that) const
89 return this->iter_ == that.iter_;
94 while(this->iter_ != this->set_->end())
96 this->cur_ = this->iter_->lock();
99 base_iterator tmp = this->iter_++;
100 this->set_->erase(tmp);
105 shared_ptr<Derived> cur_;
110 ///////////////////////////////////////////////////////////////////////////////
112 // for use with a filter_iterator to filter a node out of a list of dependencies
113 template<typename Derived>
116 typedef shared_ptr<Derived> argument_type;
117 typedef bool result_type;
119 filter_self(enable_reference_tracking<Derived> *self)
124 bool operator ()(shared_ptr<Derived> const &that) const
126 return this->self_ != that.get();
130 enable_reference_tracking<Derived> *self_;
133 ///////////////////////////////////////////////////////////////////////////////
134 // swap without bringing in std::swap -- must be found by ADL.
136 void adl_swap(T &t1, T &t2)
141 ///////////////////////////////////////////////////////////////////////////////
142 // enable_reference_tracking
143 // inherit from this type to enable reference tracking for a type. You can
144 // then use tracking_ptr (below) as a holder for derived objects.
146 template<typename Derived>
147 struct enable_reference_tracking
149 typedef std::set<shared_ptr<Derived> > references_type;
150 typedef std::set<weak_ptr<Derived> > dependents_type;
152 void tracking_copy(Derived const &that)
154 if(&this->derived_() != &that)
156 this->raw_copy_(that);
157 this->tracking_update();
161 void tracking_clear()
163 this->raw_copy_(Derived());
166 // called automatically as a result of a tracking_copy(). Must be called explicitly
167 // if you change the references without calling tracking_copy().
168 void tracking_update()
170 // add "this" as a dependency to all the references
171 this->update_references_();
172 // notify our dependencies that we have new references
173 this->update_dependents_();
176 void track_reference(enable_reference_tracking<Derived> &that)
178 // avoid some unbounded memory growth in certain circumstances by
179 // opportunistically removing stale dependencies from "that"
180 that.purge_stale_deps_();
181 // add "that" as a reference
182 this->refs_.insert(that.self_);
183 // also inherit that's references
184 this->refs_.insert(that.refs_.begin(), that.refs_.end());
187 long use_count() const
199 BOOST_ASSERT(0 < this->cnt_);
200 if(0 == --this->cnt_)
208 #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER
209 friend std::ostream &operator <<(std::ostream &sout, enable_reference_tracking<Derived> const &that)
219 enable_reference_tracking()
227 enable_reference_tracking(enable_reference_tracking<Derived> const &that)
233 this->operator =(that);
236 enable_reference_tracking<Derived> &operator =(enable_reference_tracking<Derived> const &that)
238 references_type(that.refs_).swap(this->refs_);
242 void swap(enable_reference_tracking<Derived> &that)
244 this->refs_.swap(that.refs_);
248 friend struct tracking_ptr<Derived>;
252 return *static_cast<Derived *>(this);
255 void raw_copy_(Derived that)
257 detail::adl_swap(this->derived_(), that);
260 bool has_deps_() const
262 return !this->deps_.empty();
265 void update_references_()
267 typename references_type::iterator cur = this->refs_.begin();
268 typename references_type::iterator end = this->refs_.end();
269 for(; cur != end; ++cur)
271 // for each reference, add this as a dependency
272 (*cur)->track_dependency_(*this);
276 void update_dependents_()
278 // called whenever this regex object changes (i.e., is assigned to). it walks
279 // the list of dependent regexes and updates *their* lists of references,
280 // thereby spreading out the reference counting responsibility evenly.
281 weak_iterator<Derived> cur(this->deps_.begin(), &this->deps_);
282 weak_iterator<Derived> end(this->deps_.end(), &this->deps_);
284 for(; cur != end; ++cur)
286 (*cur)->track_reference(*this);
290 void track_dependency_(enable_reference_tracking<Derived> &dep)
292 if(this == &dep) // never add ourself as a dependency
295 // add dep as a dependency
296 this->deps_.insert(dep.self_);
298 filter_self<Derived> not_self(this);
299 weak_iterator<Derived> begin(dep.deps_.begin(), &dep.deps_);
300 weak_iterator<Derived> end(dep.deps_.end(), &dep.deps_);
302 // also inherit dep's dependencies
304 make_filter_iterator(not_self, begin, end)
305 , make_filter_iterator(not_self, end, end)
309 void purge_stale_deps_()
311 weak_iterator<Derived> cur(this->deps_.begin(), &this->deps_);
312 weak_iterator<Derived> end(this->deps_.end(), &this->deps_);
314 for(; cur != end; ++cur)
319 #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER
320 void dump_(std::ostream &sout) const;
324 references_type refs_;
325 dependents_type deps_;
326 shared_ptr<Derived> self_;
327 boost::detail::atomic_count cnt_;
330 template<typename Derived>
331 inline void intrusive_ptr_add_ref(enable_reference_tracking<Derived> *p)
336 template<typename Derived>
337 inline void intrusive_ptr_release(enable_reference_tracking<Derived> *p)
343 #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER
344 ///////////////////////////////////////////////////////////////////////////////
347 template<typename Derived>
348 inline void enable_reference_tracking<Derived>::dump_(std::ostream &sout) const
350 shared_ptr<Derived> this_ = this->self_;
351 sout << "0x" << (void*)this << " cnt=" << this_.use_count()-1 << " refs={";
352 typename references_type::const_iterator cur1 = this->refs_.begin();
353 typename references_type::const_iterator end1 = this->refs_.end();
354 for(; cur1 != end1; ++cur1)
356 sout << "0x" << (void*)&**cur1 << ',';
359 typename dependents_type::const_iterator cur2 = this->deps_.begin();
360 typename dependents_type::const_iterator end2 = this->deps_.end();
361 for(; cur2 != end2; ++cur2)
363 // ericne, 27/nov/05: CW9_4 doesn't like if(shared_ptr x = y)
364 shared_ptr<Derived> dep = cur2->lock();
367 sout << "0x" << (void*)&*dep << ',';
375 ///////////////////////////////////////////////////////////////////////////////
377 // holder for a reference-tracked type. Does cycle-breaking, lazy initialization
378 // and copy-on-write. TODO: implement move semantics.
380 template<typename Type>
383 BOOST_MPL_ASSERT((is_base_and_derived<enable_reference_tracking<Type>, Type>));
384 typedef Type element_type;
391 tracking_ptr(tracking_ptr<element_type> const &that)
394 this->operator =(that);
397 tracking_ptr<element_type> &operator =(tracking_ptr<element_type> const &that)
399 // Note: the copy-and-swap idiom doesn't work here if has_deps_()==true
400 // because it invalidates references to the element_type object.
405 if(that.has_deps_() || this->has_deps_())
407 this->fork_(); // deep copy, forks data if necessary
408 this->impl_->tracking_copy(*that);
412 this->impl_ = that.impl_; // shallow, copy-on-write
417 this->impl_->tracking_clear();
423 // NOTE: this does *not* do tracking. Can't provide a non-throwing swap that tracks references
424 void swap(tracking_ptr<element_type> &that) // throw()
426 this->impl_.swap(that.impl_);
429 // calling this forces this->impl_ to fork.
430 shared_ptr<element_type> const &get() const
432 if(intrusive_ptr<element_type> impl = this->fork_())
434 this->impl_->tracking_copy(*impl);
436 return this->impl_->self_;
439 // smart-pointer operators
440 #if defined(__SUNPRO_CC) && BOOST_WORKAROUND(__SUNPRO_CC, <= 0x530)
442 operator bool() const
449 typedef intrusive_ptr<element_type> tracking_ptr::* unspecified_bool_type;
451 operator unspecified_bool_type() const
453 return this->impl_ ? &tracking_ptr::impl_ : 0;
458 bool operator !() const
463 // Since this does not un-share the data, it returns a ptr-to-const
464 element_type const *operator ->() const
466 return get_pointer(this->impl_);
469 // Since this does not un-share the data, it returns a ref-to-const
470 element_type const &operator *() const
477 // calling this forces impl_ to fork.
478 intrusive_ptr<element_type> fork_() const
480 intrusive_ptr<element_type> impl;
481 if(!this->impl_ || 1 != this->impl_->use_count())
484 BOOST_ASSERT(!this->has_deps_());
485 shared_ptr<element_type> simpl(new element_type);
486 this->impl_ = get_pointer(simpl->self_ = simpl);
491 // does anybody have a dependency on us?
492 bool has_deps_() const
494 return this->impl_ && this->impl_->has_deps_();
497 // mutable to allow lazy initialization
498 mutable intrusive_ptr<element_type> impl_;
501 }}} // namespace boost::xpressive::detail