/Src/Dependencies/Boost/boost/multi_index/detail/safe_mode.hpp

http://hadesmem.googlecode.com/ · C++ Header · 574 lines · 403 code · 103 blank · 68 comment · 29 complexity · 27920a9b63a3dc3f65abfb675b6143ab MD5 · raw file

  1. /* Copyright 2003-2009 Joaquin M Lopez Munoz.
  2. * Distributed under the Boost Software License, Version 1.0.
  3. * (See accompanying file LICENSE_1_0.txt or copy at
  4. * http://www.boost.org/LICENSE_1_0.txt)
  5. *
  6. * See http://www.boost.org/libs/multi_index for library home page.
  7. */
  8. #ifndef BOOST_MULTI_INDEX_DETAIL_SAFE_MODE_HPP
  9. #define BOOST_MULTI_INDEX_DETAIL_SAFE_MODE_HPP
  10. #if defined(_MSC_VER)&&(_MSC_VER>=1200)
  11. #pragma once
  12. #endif
  13. /* Safe mode machinery, in the spirit of Cay Hortmann's "Safe STL"
  14. * (http://www.horstmann.com/safestl.html).
  15. * In this mode, containers of type Container are derived from
  16. * safe_container<Container>, and their corresponding iterators
  17. * are wrapped with safe_iterator. These classes provide
  18. * an internal record of which iterators are at a given moment associated
  19. * to a given container, and properly mark the iterators as invalid
  20. * when the container gets destroyed.
  21. * Iterators are chained in a single attached list, whose header is
  22. * kept by the container. More elaborate data structures would yield better
  23. * performance, but I decided to keep complexity to a minimum since
  24. * speed is not an issue here.
  25. * Safe mode iterators automatically check that only proper operations
  26. * are performed on them: for instance, an invalid iterator cannot be
  27. * dereferenced. Additionally, a set of utilty macros and functions are
  28. * provided that serve to implement preconditions and cooperate with
  29. * the framework within the container.
  30. * Iterators can also be unchecked, i.e. they do not have info about
  31. * which container they belong in. This situation arises when the iterator
  32. * is restored from a serialization archive: only information on the node
  33. * is available, and it is not possible to determine to which container
  34. * the iterator is associated to. The only sensible policy is to assume
  35. * unchecked iterators are valid, though this can certainly generate false
  36. * positive safe mode checks.
  37. * This is not a full-fledged safe mode framework, and is only intended
  38. * for use within the limits of Boost.MultiIndex.
  39. */
  40. /* Assertion macros. These resolve to no-ops if
  41. * !defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE).
  42. */
  43. #if !defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
  44. #undef BOOST_MULTI_INDEX_SAFE_MODE_ASSERT
  45. #define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) ((void)0)
  46. #else
  47. #if !defined(BOOST_MULTI_INDEX_SAFE_MODE_ASSERT)
  48. #include <boost/assert.hpp>
  49. #define BOOST_MULTI_INDEX_SAFE_MODE_ASSERT(expr,error_code) BOOST_ASSERT(expr)
  50. #endif
  51. #endif
  52. #define BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(it) \
  53. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  54. safe_mode::check_valid_iterator(it), \
  55. safe_mode::invalid_iterator);
  56. #define BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(it) \
  57. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  58. safe_mode::check_dereferenceable_iterator(it), \
  59. safe_mode::not_dereferenceable_iterator);
  60. #define BOOST_MULTI_INDEX_CHECK_INCREMENTABLE_ITERATOR(it) \
  61. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  62. safe_mode::check_incrementable_iterator(it), \
  63. safe_mode::not_incrementable_iterator);
  64. #define BOOST_MULTI_INDEX_CHECK_DECREMENTABLE_ITERATOR(it) \
  65. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  66. safe_mode::check_decrementable_iterator(it), \
  67. safe_mode::not_decrementable_iterator);
  68. #define BOOST_MULTI_INDEX_CHECK_IS_OWNER(it,cont) \
  69. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  70. safe_mode::check_is_owner(it,cont), \
  71. safe_mode::not_owner);
  72. #define BOOST_MULTI_INDEX_CHECK_SAME_OWNER(it0,it1) \
  73. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  74. safe_mode::check_same_owner(it0,it1), \
  75. safe_mode::not_same_owner);
  76. #define BOOST_MULTI_INDEX_CHECK_VALID_RANGE(it0,it1) \
  77. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  78. safe_mode::check_valid_range(it0,it1), \
  79. safe_mode::invalid_range);
  80. #define BOOST_MULTI_INDEX_CHECK_OUTSIDE_RANGE(it,it0,it1) \
  81. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  82. safe_mode::check_outside_range(it,it0,it1), \
  83. safe_mode::inside_range);
  84. #define BOOST_MULTI_INDEX_CHECK_IN_BOUNDS(it,n) \
  85. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  86. safe_mode::check_in_bounds(it,n), \
  87. safe_mode::out_of_bounds);
  88. #define BOOST_MULTI_INDEX_CHECK_DIFFERENT_CONTAINER(cont0,cont1) \
  89. BOOST_MULTI_INDEX_SAFE_MODE_ASSERT( \
  90. safe_mode::check_different_container(cont0,cont1), \
  91. safe_mode::same_container);
  92. #if defined(BOOST_MULTI_INDEX_ENABLE_SAFE_MODE)
  93. #include <boost/config.hpp> /* keep it first to prevent nasty warns in MSVC */
  94. #include <algorithm>
  95. #include <boost/detail/iterator.hpp>
  96. #include <boost/multi_index/detail/access_specifier.hpp>
  97. #include <boost/multi_index/detail/iter_adaptor.hpp>
  98. #include <boost/multi_index/safe_mode_errors.hpp>
  99. #include <boost/noncopyable.hpp>
  100. #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
  101. #include <boost/serialization/split_member.hpp>
  102. #endif
  103. #if defined(BOOST_HAS_THREADS)
  104. #include <boost/detail/lightweight_mutex.hpp>
  105. #endif
  106. namespace boost{
  107. namespace multi_index{
  108. namespace safe_mode{
  109. /* Checking routines. Assume the best for unchecked iterators
  110. * (i.e. they pass the checking when there is not enough info
  111. * to know.)
  112. */
  113. template<typename Iterator>
  114. inline bool check_valid_iterator(const Iterator& it)
  115. {
  116. return it.valid()||it.unchecked();
  117. }
  118. template<typename Iterator>
  119. inline bool check_dereferenceable_iterator(const Iterator& it)
  120. {
  121. return it.valid()&&it!=it.owner()->end()||it.unchecked();
  122. }
  123. template<typename Iterator>
  124. inline bool check_incrementable_iterator(const Iterator& it)
  125. {
  126. return it.valid()&&it!=it.owner()->end()||it.unchecked();
  127. }
  128. template<typename Iterator>
  129. inline bool check_decrementable_iterator(const Iterator& it)
  130. {
  131. return it.valid()&&it!=it.owner()->begin()||it.unchecked();
  132. }
  133. template<typename Iterator>
  134. inline bool check_is_owner(
  135. const Iterator& it,const typename Iterator::container_type& cont)
  136. {
  137. return it.valid()&&it.owner()==&cont||it.unchecked();
  138. }
  139. template<typename Iterator>
  140. inline bool check_same_owner(const Iterator& it0,const Iterator& it1)
  141. {
  142. return it0.valid()&&it1.valid()&&it0.owner()==it1.owner()||
  143. it0.unchecked()||it1.unchecked();
  144. }
  145. template<typename Iterator>
  146. inline bool check_valid_range(const Iterator& it0,const Iterator& it1)
  147. {
  148. if(!check_same_owner(it0,it1))return false;
  149. if(it0.valid()){
  150. Iterator last=it0.owner()->end();
  151. if(it1==last)return true;
  152. for(Iterator first=it0;first!=last;++first){
  153. if(first==it1)return true;
  154. }
  155. return false;
  156. }
  157. return true;
  158. }
  159. template<typename Iterator>
  160. inline bool check_outside_range(
  161. const Iterator& it,const Iterator& it0,const Iterator& it1)
  162. {
  163. if(!check_same_owner(it0,it1))return false;
  164. if(it0.valid()){
  165. Iterator last=it0.owner()->end();
  166. bool found=false;
  167. Iterator first=it0;
  168. for(;first!=last;++first){
  169. if(first==it1)break;
  170. /* crucial that this check goes after previous break */
  171. if(first==it)found=true;
  172. }
  173. if(first!=it1)return false;
  174. return !found;
  175. }
  176. return true;
  177. }
  178. template<typename Iterator,typename Difference>
  179. inline bool check_in_bounds(const Iterator& it,Difference n)
  180. {
  181. if(it.unchecked())return true;
  182. if(!it.valid()) return false;
  183. if(n>0) return it.owner()->end()-it>=n;
  184. else return it.owner()->begin()-it<=n;
  185. }
  186. template<typename Container>
  187. inline bool check_different_container(
  188. const Container& cont0,const Container& cont1)
  189. {
  190. return &cont0!=&cont1;
  191. }
  192. /* Invalidates all iterators equivalent to that given. Safe containers
  193. * must call this when deleting elements: the safe mode framework cannot
  194. * perform this operation automatically without outside help.
  195. */
  196. template<typename Iterator>
  197. inline void detach_equivalent_iterators(Iterator& it)
  198. {
  199. if(it.valid()){
  200. {
  201. #if defined(BOOST_HAS_THREADS)
  202. boost::detail::lightweight_mutex::scoped_lock lock(it.cont->mutex);
  203. #endif
  204. Iterator *prev_,*next_;
  205. for(
  206. prev_=static_cast<Iterator*>(&it.cont->header);
  207. (next_=static_cast<Iterator*>(prev_->next))!=0;){
  208. if(next_!=&it&&*next_==it){
  209. prev_->next=next_->next;
  210. next_->cont=0;
  211. }
  212. else prev_=next_;
  213. }
  214. }
  215. it.detach();
  216. }
  217. }
  218. template<typename Container> class safe_container; /* fwd decl. */
  219. } /* namespace multi_index::safe_mode */
  220. namespace detail{
  221. class safe_container_base; /* fwd decl. */
  222. class safe_iterator_base
  223. {
  224. public:
  225. bool valid()const{return cont!=0;}
  226. bool unchecked()const{return unchecked_;}
  227. inline void detach();
  228. void uncheck()
  229. {
  230. detach();
  231. unchecked_=true;
  232. }
  233. protected:
  234. safe_iterator_base():cont(0),next(0),unchecked_(false){}
  235. explicit safe_iterator_base(safe_container_base* cont_):
  236. unchecked_(false)
  237. {
  238. attach(cont_);
  239. }
  240. safe_iterator_base(const safe_iterator_base& it):
  241. unchecked_(it.unchecked_)
  242. {
  243. attach(it.cont);
  244. }
  245. safe_iterator_base& operator=(const safe_iterator_base& it)
  246. {
  247. unchecked_=it.unchecked_;
  248. safe_container_base* new_cont=it.cont;
  249. if(cont!=new_cont){
  250. detach();
  251. attach(new_cont);
  252. }
  253. return *this;
  254. }
  255. ~safe_iterator_base()
  256. {
  257. detach();
  258. }
  259. const safe_container_base* owner()const{return cont;}
  260. BOOST_MULTI_INDEX_PRIVATE_IF_MEMBER_TEMPLATE_FRIENDS:
  261. friend class safe_container_base;
  262. #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
  263. template<typename> friend class safe_mode::safe_container;
  264. template<typename Iterator> friend
  265. void safe_mode::detach_equivalent_iterators(Iterator&);
  266. #endif
  267. inline void attach(safe_container_base* cont_);
  268. safe_container_base* cont;
  269. safe_iterator_base* next;
  270. bool unchecked_;
  271. };
  272. class safe_container_base:private noncopyable
  273. {
  274. public:
  275. safe_container_base(){}
  276. BOOST_MULTI_INDEX_PROTECTED_IF_MEMBER_TEMPLATE_FRIENDS:
  277. friend class safe_iterator_base;
  278. #if !defined(BOOST_NO_MEMBER_TEMPLATE_FRIENDS)
  279. template<typename Iterator> friend
  280. void safe_mode::detach_equivalent_iterators(Iterator&);
  281. #endif
  282. ~safe_container_base()
  283. {
  284. /* Detaches all remaining iterators, which by now will
  285. * be those pointing to the end of the container.
  286. */
  287. for(safe_iterator_base* it=header.next;it;it=it->next)it->cont=0;
  288. header.next=0;
  289. }
  290. void swap(safe_container_base& x)
  291. {
  292. for(safe_iterator_base* it0=header.next;it0;it0=it0->next)it0->cont=&x;
  293. for(safe_iterator_base* it1=x.header.next;it1;it1=it1->next)it1->cont=this;
  294. std::swap(header.cont,x.header.cont);
  295. std::swap(header.next,x.header.next);
  296. }
  297. safe_iterator_base header;
  298. #if defined(BOOST_HAS_THREADS)
  299. boost::detail::lightweight_mutex mutex;
  300. #endif
  301. };
  302. void safe_iterator_base::attach(safe_container_base* cont_)
  303. {
  304. cont=cont_;
  305. if(cont){
  306. #if defined(BOOST_HAS_THREADS)
  307. boost::detail::lightweight_mutex::scoped_lock lock(cont->mutex);
  308. #endif
  309. next=cont->header.next;
  310. cont->header.next=this;
  311. }
  312. }
  313. void safe_iterator_base::detach()
  314. {
  315. if(cont){
  316. #if defined(BOOST_HAS_THREADS)
  317. boost::detail::lightweight_mutex::scoped_lock lock(cont->mutex);
  318. #endif
  319. safe_iterator_base *prev_,*next_;
  320. for(prev_=&cont->header;(next_=prev_->next)!=this;prev_=next_){}
  321. prev_->next=next;
  322. cont=0;
  323. }
  324. }
  325. } /* namespace multi_index::detail */
  326. namespace safe_mode{
  327. /* In order to enable safe mode on a container:
  328. * - The container must derive from safe_container<container_type>,
  329. * - iterators must be generated via safe_iterator, which adapts a
  330. * preexistent unsafe iterator class.
  331. */
  332. template<typename Container>
  333. class safe_container;
  334. template<typename Iterator,typename Container>
  335. class safe_iterator:
  336. public detail::iter_adaptor<safe_iterator<Iterator,Container>,Iterator>,
  337. public detail::safe_iterator_base
  338. {
  339. typedef detail::iter_adaptor<safe_iterator,Iterator> super;
  340. typedef detail::safe_iterator_base safe_super;
  341. public:
  342. typedef Container container_type;
  343. typedef typename Iterator::reference reference;
  344. typedef typename Iterator::difference_type difference_type;
  345. safe_iterator(){}
  346. explicit safe_iterator(safe_container<container_type>* cont_):
  347. safe_super(cont_){}
  348. template<typename T0>
  349. safe_iterator(const T0& t0,safe_container<container_type>* cont_):
  350. super(Iterator(t0)),safe_super(cont_){}
  351. template<typename T0,typename T1>
  352. safe_iterator(
  353. const T0& t0,const T1& t1,safe_container<container_type>* cont_):
  354. super(Iterator(t0,t1)),safe_super(cont_){}
  355. safe_iterator& operator=(const safe_iterator& x)
  356. {
  357. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(x);
  358. this->base_reference()=x.base_reference();
  359. safe_super::operator=(x);
  360. return *this;
  361. }
  362. const container_type* owner()const
  363. {
  364. return
  365. static_cast<const container_type*>(
  366. static_cast<const safe_container<container_type>*>(
  367. this->safe_super::owner()));
  368. }
  369. /* get_node is not to be used by the user */
  370. typedef typename Iterator::node_type node_type;
  371. node_type* get_node()const{return this->base_reference().get_node();}
  372. private:
  373. friend class boost::multi_index::detail::iter_adaptor_access;
  374. reference dereference()const
  375. {
  376. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
  377. BOOST_MULTI_INDEX_CHECK_DEREFERENCEABLE_ITERATOR(*this);
  378. return *(this->base_reference());
  379. }
  380. bool equal(const safe_iterator& x)const
  381. {
  382. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
  383. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(x);
  384. BOOST_MULTI_INDEX_CHECK_SAME_OWNER(*this,x);
  385. return this->base_reference()==x.base_reference();
  386. }
  387. void increment()
  388. {
  389. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
  390. BOOST_MULTI_INDEX_CHECK_INCREMENTABLE_ITERATOR(*this);
  391. ++(this->base_reference());
  392. }
  393. void decrement()
  394. {
  395. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
  396. BOOST_MULTI_INDEX_CHECK_DECREMENTABLE_ITERATOR(*this);
  397. --(this->base_reference());
  398. }
  399. void advance(difference_type n)
  400. {
  401. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
  402. BOOST_MULTI_INDEX_CHECK_IN_BOUNDS(*this,n);
  403. this->base_reference()+=n;
  404. }
  405. difference_type distance_to(const safe_iterator& x)const
  406. {
  407. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
  408. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(x);
  409. BOOST_MULTI_INDEX_CHECK_SAME_OWNER(*this,x);
  410. return x.base_reference()-this->base_reference();
  411. }
  412. #if !defined(BOOST_MULTI_INDEX_DISABLE_SERIALIZATION)
  413. /* Serialization. Note that Iterator::save and Iterator:load
  414. * are assumed to be defined and public: at first sight it seems
  415. * like we could have resorted to the public serialization interface
  416. * for doing the forwarding to the adapted iterator class:
  417. * ar<<base_reference();
  418. * ar>>base_reference();
  419. * but this would cause incompatibilities if a saving
  420. * program is in safe mode and the loading program is not, or
  421. * viceversa --in safe mode, the archived iterator data is one layer
  422. * deeper, this is especially relevant with XML archives.
  423. * It'd be nice if Boost.Serialization provided some forwarding
  424. * facility for use by adaptor classes.
  425. */
  426. friend class boost::serialization::access;
  427. BOOST_SERIALIZATION_SPLIT_MEMBER()
  428. template<class Archive>
  429. void save(Archive& ar,const unsigned int version)const
  430. {
  431. BOOST_MULTI_INDEX_CHECK_VALID_ITERATOR(*this);
  432. this->base_reference().save(ar,version);
  433. }
  434. template<class Archive>
  435. void load(Archive& ar,const unsigned int version)
  436. {
  437. this->base_reference().load(ar,version);
  438. safe_super::uncheck();
  439. }
  440. #endif
  441. };
  442. template<typename Container>
  443. class safe_container:public detail::safe_container_base
  444. {
  445. typedef detail::safe_container_base super;
  446. public:
  447. void detach_dereferenceable_iterators()
  448. {
  449. typedef typename Container::iterator iterator;
  450. iterator end_=static_cast<Container*>(this)->end();
  451. iterator *prev_,*next_;
  452. for(
  453. prev_=static_cast<iterator*>(&this->header);
  454. (next_=static_cast<iterator*>(prev_->next))!=0;){
  455. if(*next_!=end_){
  456. prev_->next=next_->next;
  457. next_->cont=0;
  458. }
  459. else prev_=next_;
  460. }
  461. }
  462. void swap(safe_container<Container>& x)
  463. {
  464. super::swap(x);
  465. }
  466. };
  467. } /* namespace multi_index::safe_mode */
  468. } /* namespace multi_index */
  469. } /* namespace boost */
  470. #endif /* BOOST_MULTI_INDEX_ENABLE_SAFE_MODE */
  471. #endif