| 1 |
// Safe sequence/iterator base implementation -*- C++ -*- |
| 2 |
|
| 3 |
// Copyright (C) 2003-2021 Free Software Foundation, Inc. |
| 4 |
// |
| 5 |
// This file is part of the GNU ISO C++ Library. This library is free |
| 6 |
// software; you can redistribute it and/or modify it under the |
| 7 |
// terms of the GNU General Public License as published by the |
| 8 |
// Free Software Foundation; either version 3, or (at your option) |
| 9 |
// any later version. |
| 10 |
|
| 11 |
// This library is distributed in the hope that it will be useful, |
| 12 |
// but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 13 |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| 14 |
// GNU General Public License for more details. |
| 15 |
|
| 16 |
// Under Section 7 of GPL version 3, you are granted additional |
| 17 |
// permissions described in the GCC Runtime Library Exception, version |
| 18 |
// 3.1, as published by the Free Software Foundation. |
| 19 |
|
| 20 |
// You should have received a copy of the GNU General Public License and |
| 21 |
// a copy of the GCC Runtime Library Exception along with this program; |
| 22 |
// see the files COPYING3 and COPYING.RUNTIME respectively. If not, see |
| 23 |
// <http://www.gnu.org/licenses/>. |
| 24 |
|
| 25 |
/** @file debug/safe_base.h |
| 26 |
* This file is a GNU debug extension to the Standard C++ Library. |
| 27 |
*/ |
| 28 |
|
| 29 |
#ifndef _GLIBCXX_DEBUG_SAFE_BASE_H |
| 30 |
#define _GLIBCXX_DEBUG_SAFE_BASE_H 1 |
| 31 |
|
| 32 |
#include <ext/concurrence.h> |
| 33 |
|
| 34 |
namespace __gnu_debug |
| 35 |
{ |
| 36 |
class _Safe_sequence_base; |
| 37 |
|
| 38 |
/** \brief Basic functionality for a @a safe iterator. |
| 39 |
* |
| 40 |
* The %_Safe_iterator_base base class implements the functionality |
| 41 |
* of a safe iterator that is not specific to a particular iterator |
| 42 |
* type. It contains a pointer back to the sequence it references |
| 43 |
* along with iterator version information and pointers to form a |
| 44 |
* doubly-linked list of iterators referenced by the container. |
| 45 |
* |
| 46 |
* This class must not perform any operations that can throw an |
| 47 |
* exception, or the exception guarantees of derived iterators will |
| 48 |
* be broken. |
| 49 |
*/ |
| 50 |
class _Safe_iterator_base |
| 51 |
{ |
| 52 |
friend class _Safe_sequence_base; |
| 53 |
|
| 54 |
public: |
| 55 |
/** The sequence this iterator references; may be NULL to indicate |
| 56 |
a singular iterator. */ |
| 57 |
_Safe_sequence_base* _M_sequence; |
| 58 |
|
| 59 |
/** The version number of this iterator. The sentinel value 0 is |
| 60 |
* used to indicate an invalidated iterator (i.e., one that is |
| 61 |
* singular because of an operation on the container). This |
| 62 |
* version number must equal the version number in the sequence |
| 63 |
* referenced by _M_sequence for the iterator to be |
| 64 |
* non-singular. |
| 65 |
*/ |
| 66 |
unsigned int _M_version; |
| 67 |
|
| 68 |
/** Pointer to the previous iterator in the sequence's list of |
| 69 |
iterators. Only valid when _M_sequence != NULL. */ |
| 70 |
_Safe_iterator_base* _M_prior; |
| 71 |
|
| 72 |
/** Pointer to the next iterator in the sequence's list of |
| 73 |
iterators. Only valid when _M_sequence != NULL. */ |
| 74 |
_Safe_iterator_base* _M_next; |
| 75 |
|
| 76 |
protected: |
| 77 |
/** Initializes the iterator and makes it singular. */ |
| 78 |
_Safe_iterator_base() |
| 79 |
: _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0) |
| 80 |
{ } |
| 81 |
|
| 82 |
/** Initialize the iterator to reference the sequence pointed to |
| 83 |
* by @p __seq. @p __constant is true when we are initializing a |
| 84 |
* constant iterator, and false if it is a mutable iterator. Note |
| 85 |
* that @p __seq may be NULL, in which case the iterator will be |
| 86 |
* singular. Otherwise, the iterator will reference @p __seq and |
| 87 |
* be nonsingular. |
| 88 |
*/ |
| 89 |
_Safe_iterator_base(const _Safe_sequence_base* __seq, bool __constant) |
| 90 |
: _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0) |
| 91 |
{ this->_M_attach(const_cast<_Safe_sequence_base*>(__seq), __constant); } |
| 92 |
|
| 93 |
/** Initializes the iterator to reference the same sequence that |
| 94 |
@p __x does. @p __constant is true if this is a constant |
| 95 |
iterator, and false if it is mutable. */ |
| 96 |
_Safe_iterator_base(const _Safe_iterator_base& __x, bool __constant) |
| 97 |
: _M_sequence(0), _M_version(0), _M_prior(0), _M_next(0) |
| 98 |
{ this->_M_attach(__x._M_sequence, __constant); } |
| 99 |
|
| 100 |
~_Safe_iterator_base() { this->_M_detach(); } |
| 101 |
|
| 102 |
/** For use in _Safe_iterator. */ |
| 103 |
__gnu_cxx::__mutex& |
| 104 |
_M_get_mutex() throw (); |
| 105 |
|
| 106 |
/** Attaches this iterator to the given sequence, detaching it |
| 107 |
* from whatever sequence it was attached to originally. If the |
| 108 |
* new sequence is the NULL pointer, the iterator is left |
| 109 |
* unattached. |
| 110 |
*/ |
| 111 |
void |
| 112 |
_M_attach(_Safe_sequence_base* __seq, bool __constant); |
| 113 |
|
| 114 |
/** Likewise, but not thread-safe. */ |
| 115 |
void |
| 116 |
_M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw (); |
| 117 |
|
| 118 |
/** Detach the iterator for whatever sequence it is attached to, |
| 119 |
* if any. |
| 120 |
*/ |
| 121 |
void |
| 122 |
_M_detach(); |
| 123 |
|
| 124 |
public: |
| 125 |
/** Likewise, but not thread-safe. */ |
| 126 |
void |
| 127 |
_M_detach_single() throw (); |
| 128 |
|
| 129 |
/** Determines if we are attached to the given sequence. */ |
| 130 |
bool |
| 131 |
_M_attached_to(const _Safe_sequence_base* __seq) const |
| 132 |
{ return _M_sequence == __seq; } |
| 133 |
|
| 134 |
/** Is this iterator singular? */ |
| 135 |
_GLIBCXX_PURE bool |
| 136 |
_M_singular() const throw (); |
| 137 |
|
| 138 |
/** Can we compare this iterator to the given iterator @p __x? |
| 139 |
Returns true if both iterators are nonsingular and reference |
| 140 |
the same sequence. */ |
| 141 |
_GLIBCXX_PURE bool |
| 142 |
_M_can_compare(const _Safe_iterator_base& __x) const throw (); |
| 143 |
|
| 144 |
/** Invalidate the iterator, making it singular. */ |
| 145 |
void |
| 146 |
_M_invalidate() |
| 147 |
{ _M_version = 0; } |
| 148 |
|
| 149 |
/** Reset all member variables */ |
| 150 |
void |
| 151 |
_M_reset() throw (); |
| 152 |
|
| 153 |
/** Unlink itself */ |
| 154 |
void |
| 155 |
_M_unlink() throw () |
| 156 |
{ |
| 157 |
if (_M_prior) |
| 158 |
_M_prior->_M_next = _M_next; |
| 159 |
if (_M_next) |
| 160 |
_M_next->_M_prior = _M_prior; |
| 161 |
} |
| 162 |
}; |
| 163 |
|
| 164 |
/** Iterators that derive from _Safe_iterator_base can be determined singular |
| 165 |
* or non-singular. |
| 166 |
**/ |
| 167 |
inline bool |
| 168 |
__check_singular_aux(const _Safe_iterator_base* __x) |
| 169 |
{ return __x->_M_singular(); } |
| 170 |
|
| 171 |
/** |
| 172 |
* @brief Base class that supports tracking of iterators that |
| 173 |
* reference a sequence. |
| 174 |
* |
| 175 |
* The %_Safe_sequence_base class provides basic support for |
| 176 |
* tracking iterators into a sequence. Sequences that track |
| 177 |
* iterators must derived from %_Safe_sequence_base publicly, so |
| 178 |
* that safe iterators (which inherit _Safe_iterator_base) can |
| 179 |
* attach to them. This class contains two linked lists of |
| 180 |
* iterators, one for constant iterators and one for mutable |
| 181 |
* iterators, and a version number that allows very fast |
| 182 |
* invalidation of all iterators that reference the container. |
| 183 |
* |
| 184 |
* This class must ensure that no operation on it may throw an |
| 185 |
* exception, otherwise @a safe sequences may fail to provide the |
| 186 |
* exception-safety guarantees required by the C++ standard. |
| 187 |
*/ |
| 188 |
class _Safe_sequence_base |
| 189 |
{ |
| 190 |
friend class _Safe_iterator_base; |
| 191 |
|
| 192 |
public: |
| 193 |
/// The list of mutable iterators that reference this container |
| 194 |
_Safe_iterator_base* _M_iterators; |
| 195 |
|
| 196 |
/// The list of constant iterators that reference this container |
| 197 |
_Safe_iterator_base* _M_const_iterators; |
| 198 |
|
| 199 |
/// The container version number. This number may never be 0. |
| 200 |
mutable unsigned int _M_version; |
| 201 |
|
| 202 |
protected: |
| 203 |
// Initialize with a version number of 1 and no iterators |
| 204 |
_Safe_sequence_base() _GLIBCXX_NOEXCEPT |
| 205 |
: _M_iterators(0), _M_const_iterators(0), _M_version(1) |
| 206 |
{ } |
| 207 |
|
| 208 |
#if __cplusplus >= 201103L |
| 209 |
_Safe_sequence_base(const _Safe_sequence_base&) noexcept |
| 210 |
: _Safe_sequence_base() { } |
| 211 |
|
| 212 |
// Move constructor swap iterators. |
| 213 |
_Safe_sequence_base(_Safe_sequence_base&& __seq) noexcept |
| 214 |
: _Safe_sequence_base() |
| 215 |
{ _M_swap(__seq); } |
| 216 |
#endif |
| 217 |
|
| 218 |
/** Notify all iterators that reference this sequence that the |
| 219 |
sequence is being destroyed. */ |
| 220 |
~_Safe_sequence_base() |
| 221 |
{ this->_M_detach_all(); } |
| 222 |
|
| 223 |
/** Detach all iterators, leaving them singular. */ |
| 224 |
void |
| 225 |
_M_detach_all(); |
| 226 |
|
| 227 |
/** Detach all singular iterators. |
| 228 |
* @post for all iterators i attached to this sequence, |
| 229 |
* i->_M_version == _M_version. |
| 230 |
*/ |
| 231 |
void |
| 232 |
_M_detach_singular(); |
| 233 |
|
| 234 |
/** Revalidates all attached singular iterators. This method may |
| 235 |
* be used to validate iterators that were invalidated before |
| 236 |
* (but for some reason, such as an exception, need to become |
| 237 |
* valid again). |
| 238 |
*/ |
| 239 |
void |
| 240 |
_M_revalidate_singular(); |
| 241 |
|
| 242 |
/** Swap this sequence with the given sequence. This operation |
| 243 |
* also swaps ownership of the iterators, so that when the |
| 244 |
* operation is complete all iterators that originally referenced |
| 245 |
* one container now reference the other container. |
| 246 |
*/ |
| 247 |
void |
| 248 |
_M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT; |
| 249 |
|
| 250 |
/** For use in _Safe_sequence. */ |
| 251 |
__gnu_cxx::__mutex& |
| 252 |
_M_get_mutex() throw (); |
| 253 |
|
| 254 |
/** Invalidates all iterators. */ |
| 255 |
void |
| 256 |
_M_invalidate_all() const |
| 257 |
{ if (++_M_version == 0) _M_version = 1; } |
| 258 |
|
| 259 |
private: |
| 260 |
/** Attach an iterator to this sequence. */ |
| 261 |
void |
| 262 |
_M_attach(_Safe_iterator_base* __it, bool __constant); |
| 263 |
|
| 264 |
/** Likewise but not thread safe. */ |
| 265 |
void |
| 266 |
_M_attach_single(_Safe_iterator_base* __it, bool __constant) throw (); |
| 267 |
|
| 268 |
/** Detach an iterator from this sequence */ |
| 269 |
void |
| 270 |
_M_detach(_Safe_iterator_base* __it); |
| 271 |
|
| 272 |
/** Likewise but not thread safe. */ |
| 273 |
void |
| 274 |
_M_detach_single(_Safe_iterator_base* __it) throw (); |
| 275 |
}; |
| 276 |
} // namespace __gnu_debug |
| 277 |
|
| 278 |
#endif |