PageRenderTime 58ms CodeModel.GetById 17ms app.highlight 36ms RepoModel.GetById 1ms app.codeStats 0ms

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