tracking_ptr.hpp 13 KB

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