annotate DEPENDENCIES/generic/include/boost/xpressive/detail/utility/tracking_ptr.hpp @ 133:4acb5d8d80b6 tip

Don't fail environmental check if README.md exists (but .txt and no-suffix don't)
author Chris Cannam
date Tue, 30 Jul 2019 12:25:44 +0100
parents c530137014c0
children
rev   line source
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