Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: downloads/boost_1_34_1/boost/xpressive/detail/utility/tracking_ptr.hpp @ 33

Last change on this file since 33 was 29, checked in by landauf, 17 years ago

updated boost from 1_33_1 to 1_34_1

File size: 13.1 KB
Line 
1///////////////////////////////////////////////////////////////////////////////
2// tracking_ptr.hpp
3//
4//  Copyright 2004 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)
7
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
10
11// MS compatible compilers support #pragma once
12#if defined(_MSC_VER) && (_MSC_VER >= 1020)
13# pragma once
14#endif
15
16#ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER
17# include <iostream>
18#endif
19#include <set>
20#include <functional>
21#include <boost/config.hpp>
22#include <boost/assert.hpp>
23#include <boost/shared_ptr.hpp>
24#include <boost/mpl/assert.hpp>
25#include <boost/enable_shared_from_this.hpp>
26#include <boost/type_traits/is_base_and_derived.hpp>
27#include <boost/iterator/iterator_facade.hpp>
28#include <boost/iterator/filter_iterator.hpp>
29
30namespace boost { namespace xpressive { namespace detail
31{
32
33template<typename Type>
34struct tracking_ptr;
35
36template<typename Derived>
37struct enable_reference_tracking;
38
39///////////////////////////////////////////////////////////////////////////////
40// weak_iterator
41//  steps through a set of weak_ptr, converts to shared_ptrs on the fly and
42//  removes from the set the weak_ptrs that have expired.
43template<typename Derived>
44struct weak_iterator
45  : boost::iterator_facade
46    <
47        weak_iterator<Derived>
48      , boost::shared_ptr<Derived> const
49      , std::forward_iterator_tag
50    >
51{
52    typedef std::set<boost::weak_ptr<Derived> > set_type;
53    typedef typename set_type::iterator base_iterator;
54
55    weak_iterator()
56      : cur_()
57      , iter_()
58      , set_(0)
59    {
60    }
61
62    weak_iterator(base_iterator iter, set_type *set)
63      : cur_()
64      , iter_(iter)
65      , set_(set)
66    {
67        this->satisfy_();
68    }
69
70private:
71    friend class boost::iterator_core_access;
72
73    boost::shared_ptr<Derived> const &dereference() const
74    {
75        return this->cur_;
76    }
77
78    void increment()
79    {
80        ++this->iter_;
81        this->satisfy_();
82    }
83
84    bool equal(weak_iterator<Derived> const &that) const
85    {
86        return this->iter_ == that.iter_;
87    }
88
89    void satisfy_()
90    {
91        while(this->iter_ != this->set_->end())
92        {
93            this->cur_ = this->iter_->lock();
94            if(this->cur_)
95                return;
96            base_iterator tmp = this->iter_++;
97            this->set_->erase(tmp);
98        }
99        this->cur_.reset();
100    }
101
102    boost::shared_ptr<Derived> cur_;
103    base_iterator iter_;
104    set_type *set_;
105};
106
107///////////////////////////////////////////////////////////////////////////////
108// reference_deleter
109//
110template<typename Derived>
111struct reference_deleter
112{
113    void operator ()(void *pv) const
114    {
115        typedef enable_reference_tracking<Derived> impl_type;
116        impl_type *pimpl = static_cast<impl_type *>(pv);
117        pimpl->refs_.clear();
118    }
119};
120
121///////////////////////////////////////////////////////////////////////////////
122// filter_self
123//  for use with a filter_iterator to filter a node out of a list of dependencies
124template<typename Derived>
125struct filter_self
126  : std::unary_function<boost::shared_ptr<Derived>, bool>
127{
128    filter_self(enable_reference_tracking<Derived> *self)
129      : self_(self)
130    {
131    }
132
133    bool operator ()(boost::shared_ptr<Derived> const &that) const
134    {
135        return this->self_ != that.get();
136    }
137
138private:
139    enable_reference_tracking<Derived> *self_;
140};
141
142///////////////////////////////////////////////////////////////////////////////
143// enable_reference_tracking
144//   inherit from this type to enable reference tracking for a type. You can
145//   then use tracking_ptr (below) as a holder for derived objects.
146//
147template<typename Derived>
148struct enable_reference_tracking
149  : enable_shared_from_this<Derived>
150{
151    typedef enable_reference_tracking<Derived> this_type;
152    typedef std::set<shared_ptr<Derived> > references_type;
153    typedef std::set<weak_ptr<Derived> > dependents_type;
154
155    void tracking_copy(Derived const &that)
156    {
157        this->derived_() = that;
158        this->tracking_update();
159    }
160
161    // called automatically as a result of a tracking_copy(). Must be called explicitly
162    // if you change the references without calling tracking_copy().
163    void tracking_update()
164    {
165        // add "this" as a dependency to all the references
166        this->update_references_();
167        // notify our dependencies that we have new references
168        this->update_dependents_();
169    }
170
171    void tracking_clear()
172    {
173        this->derived_() = Derived();
174    }
175
176    void track_reference(shared_ptr<Derived> const &that)
177    {
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);
183        // also inherit that's references
184        this->refs_.insert(that->refs_.begin(), that->refs_.end());
185    }
186
187    //{{AFX_DEBUG
188    #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER
189    friend std::ostream &operator <<(std::ostream &sout, enable_reference_tracking<Derived> const &that)
190    {
191        that.dump_(sout);
192        return sout;
193    }
194    #endif
195    //}}AFX_DEBUG
196
197protected:
198
199    enable_reference_tracking()
200      : refs_()
201      , deps_()
202    {
203    }
204
205    enable_reference_tracking(enable_reference_tracking<Derived> const &that)
206      : refs_()
207      , deps_()
208    {
209        this->operator =(that);
210    }
211
212    enable_reference_tracking<Derived> &operator =(enable_reference_tracking<Derived> const &that)
213    {
214        // BUGBUG derived classes will need to do something special to make their
215        // assignment operators exception-safe. Can we make this easier?
216        references_type(that.refs_).swap(this->refs_);
217        return *this;
218    }
219
220    void swap(enable_reference_tracking<Derived> &that)
221    {
222        this->refs_.swap(that.refs_);
223    }
224
225private:
226
227    friend struct tracking_ptr<Derived>;
228    friend struct reference_deleter<Derived>;
229
230    Derived &derived_()
231    {
232        return *static_cast<Derived *>(this);
233    }
234
235    bool has_deps_() const
236    {
237        return !this->deps_.empty();
238    }
239
240    shared_ptr<void> get_ref_deleter_()
241    {
242        return shared_ptr<void>(static_cast<void*>(this), reference_deleter<Derived>());
243    }
244
245    void update_references_()
246    {
247        typename references_type::iterator cur = this->refs_.begin();
248        typename references_type::iterator end = this->refs_.end();
249        for(; cur != end; ++cur)
250        {
251            if(this != cur->get()) // not necessary, but avoids a call to shared_from_this()
252            {
253                // for each reference, add this as a dependency
254                (*cur)->track_dependency_(this->shared_from_this());
255            }
256        }
257    }
258
259    void update_dependents_()
260    {
261        // called whenever this regex object changes (i.e., is assigned to). it walks
262        // the list of dependent regexes and updates *their* lists of references,
263        // thereby spreading out the reference counting responsibility evenly.
264        if(!this->refs_.empty())
265        {
266            weak_iterator<Derived> cur(this->deps_.begin(), &this->deps_);
267            weak_iterator<Derived> end(this->deps_.end(), &this->deps_);
268
269            for(; cur != end; ++cur)
270            {
271                (*cur)->track_reference(this->shared_from_this());
272            }
273        }
274    }
275
276    void track_dependency_(shared_ptr<Derived> const &dep)
277    {
278        if(this != dep.get()) // never add ourself as a dependency
279        {
280            // add dep as a dependency
281            this->deps_.insert(dep);
282
283            filter_self<Derived> not_self(this);
284            weak_iterator<Derived> begin(dep->deps_.begin(), &dep->deps_);
285            weak_iterator<Derived> end(dep->deps_.end(), &dep->deps_);
286
287            // also inherit dep's dependencies
288            this->deps_.insert(
289                boost::make_filter_iterator(not_self, begin, end)
290              , boost::make_filter_iterator(not_self, end, end)
291            );
292        }
293    }
294
295    void purge_stale_deps_()
296    {
297        weak_iterator<Derived> cur(this->deps_.begin(), &this->deps_);
298        weak_iterator<Derived> end(this->deps_.end(), &this->deps_);
299
300        for(; cur != end; ++cur)
301            ;
302    }
303
304    //{{AFX_DEBUG
305    #ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER
306    void dump_(std::ostream &sout) const;
307    #endif
308    //}}AFX_DEBUG
309
310    references_type refs_;
311    dependents_type deps_;
312};
313
314//{{AFX_DEBUG
315#ifdef BOOST_XPRESSIVE_DEBUG_TRACKING_POINTER
316///////////////////////////////////////////////////////////////////////////////
317// dump_
318//
319template<typename Derived>
320inline void enable_reference_tracking<Derived>::dump_(std::ostream &sout) const
321{
322    shared_ptr<Derived const> this_ = this->shared_from_this();
323    sout << "0x" << (void*)this << " cnt=" << this_.use_count()-1 << " refs={";
324    typename references_type::const_iterator cur1 = this->refs_.begin();
325    typename references_type::const_iterator end1 = this->refs_.end();
326    for(; cur1 != end1; ++cur1)
327    {
328        sout << "0x" << (void*)&**cur1 << ',';
329    }
330    sout << "} deps={";
331    typename dependents_type::const_iterator cur2 = this->deps_.begin();
332    typename dependents_type::const_iterator end2 = this->deps_.end();
333    for(; cur2 != end2; ++cur2)
334    {
335        // ericne, 27/nov/05: CW9_4 doesn't like if(shared_ptr x = y)
336        shared_ptr<Derived> dep = cur2->lock();
337        if(dep.get())
338        {
339            sout << "0x" << (void*)&*dep << ',';
340        }
341    }
342    sout << '}';
343}
344#endif
345//}}AFX_DEBUG
346
347///////////////////////////////////////////////////////////////////////////////
348// tracking_ptr
349//   holder for a reference-tracked type. Does cycle-breaking, lazy initialization
350//   and copy-on-write. TODO: implement move semantics.
351//
352template<typename Type>
353struct tracking_ptr
354{
355private:
356    struct dummy_ { int n_; };
357    BOOST_MPL_ASSERT((is_base_and_derived<enable_reference_tracking<Type>, Type>));
358
359public:
360
361    typedef Type element_type;
362
363    tracking_ptr()
364      : data_()
365      , refs_()
366    {
367    }
368
369    tracking_ptr(tracking_ptr<element_type> const &that)
370      : data_()
371      , refs_()
372    {
373        this->operator =(that);
374    }
375
376    tracking_ptr<element_type> &operator =(tracking_ptr<element_type> const &that)
377    {
378        // Note: the copy-and-swap idiom doesn't work here if has_deps_()==true
379        // because it invalidates references to the element_type object.
380
381        if(that)
382        {
383            if(that.has_deps_() || this->has_deps_())
384            {
385                this->tracking_copy(*that.data_); // deep copy, forks data if necessary
386            }
387            else
388            {
389                this->refs_ = that.refs_; // shallow, copy-on-write
390                this->data_ = that.data_;
391            }
392        }
393        else if(*this)
394        {
395            this->data_->tracking_clear();
396        }
397
398        return *this;
399    }
400
401    // NOTE: this does *not* do tracking. Can't provide a non-throwing swap that tracks references
402    void swap(tracking_ptr<element_type> &that) // throw()
403    {
404        this->data_.swap(that.data_);
405        this->refs_.swap(that.refs_);
406    }
407
408    // deep copy, forces a fork and calls update() to update all the
409    // dependents and references.
410    void tracking_copy(element_type const &that)
411    {
412        this->get_(false)->tracking_copy(that);
413    }
414
415    // calling this forces this->data_ to fork.
416    shared_ptr<element_type> const &get() const
417    {
418        return this->get_(true); // copy == true
419    }
420
421    // smart-pointer operators
422    operator int dummy_::*() const
423    {
424        return this->data_ ? &dummy_::n_ : 0;
425    }
426
427    bool operator !() const
428    {
429        return !this->data_;
430    }
431
432    // Since this does not un-share the data, it returns a ptr-to-const
433    element_type const *operator ->() const
434    {
435        return this->data_.get();
436    }
437
438    // Since this does not un-share the data, it returns a ref-to-const
439    element_type const &operator *() const
440    {
441        return *this->data_;
442    }
443
444private:
445
446    // calling this forces data_ to fork. if 'copy' is true, then
447    // the old data is copied into the fork.
448    shared_ptr<element_type> const &get_(bool copy) const
449    {
450        if(!*this)
451        {
452            this->data_.reset(new element_type);
453            this->refs_ = this->data_->get_ref_deleter_();
454        }
455        else if(!this->unique_())
456        {
457            BOOST_ASSERT(!this->has_deps_());
458            shared_ptr<element_type> new_data(new element_type);
459            if(copy)
460            {
461                new_data->tracking_copy(*this->data_);
462            }
463            this->data_.swap(new_data);
464            this->refs_ = this->data_->get_ref_deleter_();
465        }
466
467        return this->data_;
468    }
469
470    // are we the only holders of this data?
471    bool unique_() const
472    {
473        return this->refs_.unique();
474    }
475
476    // does anybody have a dependency on us?
477    bool has_deps_() const
478    {
479        return this->data_ && this->data_->has_deps_();
480    }
481
482    // mutable to allow lazy initialization
483    mutable shared_ptr<element_type> data_;
484    mutable shared_ptr<void> refs_;
485};
486
487}}} // namespace boost::xpressive::detail
488
489#endif
Note: See TracBrowser for help on using the repository browser.