tracking_ptr.hpp 13 KB

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