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