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