]>
Commit | Line | Data |
---|---|---|
285b36d6 BK |
1 | // Safe sequence/iterator base implementation -*- C++ -*- |
2 | ||
99dee823 | 3 | // Copyright (C) 2003-2021 Free Software Foundation, Inc. |
285b36d6 BK |
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 | |
748086b7 | 8 | // Free Software Foundation; either version 3, or (at your option) |
285b36d6 BK |
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 | ||
748086b7 JJ |
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/>. | |
285b36d6 | 24 | |
78a53887 BK |
25 | /** @file debug/safe_base.h |
26 | * This file is a GNU debug extension to the Standard C++ Library. | |
27 | */ | |
28 | ||
285b36d6 BK |
29 | #ifndef _GLIBCXX_DEBUG_SAFE_BASE_H |
30 | #define _GLIBCXX_DEBUG_SAFE_BASE_H 1 | |
31 | ||
eebbe2c7 PC |
32 | #include <ext/concurrence.h> |
33 | ||
285b36d6 BK |
34 | namespace __gnu_debug |
35 | { | |
36 | class _Safe_sequence_base; | |
37 | ||
2a60a9f6 | 38 | /** \brief Basic functionality for a @a safe iterator. |
285b36d6 BK |
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 | { | |
5d045324 FD |
52 | friend class _Safe_sequence_base; |
53 | ||
285b36d6 BK |
54 | public: |
55 | /** The sequence this iterator references; may be NULL to indicate | |
56 | a singular iterator. */ | |
15ee1a77 | 57 | _Safe_sequence_base* _M_sequence; |
285b36d6 BK |
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 | |
526da49c | 64 | * non-singular. |
285b36d6 | 65 | */ |
15ee1a77 | 66 | unsigned int _M_version; |
285b36d6 BK |
67 | |
68 | /** Pointer to the previous iterator in the sequence's list of | |
69 | iterators. Only valid when _M_sequence != NULL. */ | |
15ee1a77 | 70 | _Safe_iterator_base* _M_prior; |
285b36d6 BK |
71 | |
72 | /** Pointer to the next iterator in the sequence's list of | |
73 | iterators. Only valid when _M_sequence != NULL. */ | |
15ee1a77 | 74 | _Safe_iterator_base* _M_next; |
285b36d6 BK |
75 | |
76 | protected: | |
77 | /** Initializes the iterator and makes it singular. */ | |
526da49c | 78 | _Safe_iterator_base() |
285b36d6 BK |
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 | |
7897a1c0 | 83 | * by @p __seq. @p __constant is true when we are initializing a |
285b36d6 BK |
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 | |
526da49c | 87 | * be nonsingular. |
285b36d6 BK |
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 | ||
eebbe2c7 | 102 | /** For use in _Safe_iterator. */ |
15ee1a77 FD |
103 | __gnu_cxx::__mutex& |
104 | _M_get_mutex() throw (); | |
eebbe2c7 | 105 | |
285b36d6 BK |
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. | |
526da49c | 110 | */ |
15ee1a77 FD |
111 | void |
112 | _M_attach(_Safe_sequence_base* __seq, bool __constant); | |
285b36d6 | 113 | |
eebbe2c7 | 114 | /** Likewise, but not thread-safe. */ |
15ee1a77 FD |
115 | void |
116 | _M_attach_single(_Safe_sequence_base* __seq, bool __constant) throw (); | |
eebbe2c7 | 117 | |
285b36d6 | 118 | /** Detach the iterator for whatever sequence it is attached to, |
526da49c | 119 | * if any. |
285b36d6 | 120 | */ |
15ee1a77 FD |
121 | void |
122 | _M_detach(); | |
285b36d6 | 123 | |
f2fe9e0a | 124 | public: |
eebbe2c7 | 125 | /** Likewise, but not thread-safe. */ |
15ee1a77 FD |
126 | void |
127 | _M_detach_single() throw (); | |
eebbe2c7 | 128 | |
285b36d6 | 129 | /** Determines if we are attached to the given sequence. */ |
15ee1a77 FD |
130 | bool |
131 | _M_attached_to(const _Safe_sequence_base* __seq) const | |
285b36d6 BK |
132 | { return _M_sequence == __seq; } |
133 | ||
134 | /** Is this iterator singular? */ | |
15ee1a77 FD |
135 | _GLIBCXX_PURE bool |
136 | _M_singular() const throw (); | |
285b36d6 BK |
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. */ | |
15ee1a77 FD |
141 | _GLIBCXX_PURE bool |
142 | _M_can_compare(const _Safe_iterator_base& __x) const throw (); | |
afe96d41 FD |
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 (); | |
8c9f4dfa FD |
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 | } | |
285b36d6 BK |
162 | }; |
163 | ||
adad2a7d FD |
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 | ||
285b36d6 BK |
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 | |
2a60a9f6 | 185 | * exception, otherwise @a safe sequences may fail to provide the |
285b36d6 BK |
186 | * exception-safety guarantees required by the C++ standard. |
187 | */ | |
188 | class _Safe_sequence_base | |
189 | { | |
5d045324 FD |
190 | friend class _Safe_iterator_base; |
191 | ||
285b36d6 BK |
192 | public: |
193 | /// The list of mutable iterators that reference this container | |
194 | _Safe_iterator_base* _M_iterators; | |
526da49c | 195 | |
285b36d6 BK |
196 | /// The list of constant iterators that reference this container |
197 | _Safe_iterator_base* _M_const_iterators; | |
526da49c | 198 | |
285b36d6 BK |
199 | /// The container version number. This number may never be 0. |
200 | mutable unsigned int _M_version; | |
526da49c | 201 | |
285b36d6 BK |
202 | protected: |
203 | // Initialize with a version number of 1 and no iterators | |
15ee1a77 | 204 | _Safe_sequence_base() _GLIBCXX_NOEXCEPT |
285b36d6 BK |
205 | : _M_iterators(0), _M_const_iterators(0), _M_version(1) |
206 | { } | |
526da49c | 207 | |
ace295af | 208 | #if __cplusplus >= 201103L |
f7491277 | 209 | _Safe_sequence_base(const _Safe_sequence_base&) noexcept |
15ee1a77 | 210 | : _Safe_sequence_base() { } |
5d045324 FD |
211 | |
212 | // Move constructor swap iterators. | |
213 | _Safe_sequence_base(_Safe_sequence_base&& __seq) noexcept | |
214 | : _Safe_sequence_base() | |
215 | { _M_swap(__seq); } | |
ace295af FD |
216 | #endif |
217 | ||
285b36d6 BK |
218 | /** Notify all iterators that reference this sequence that the |
219 | sequence is being destroyed. */ | |
220 | ~_Safe_sequence_base() | |
221 | { this->_M_detach_all(); } | |
526da49c | 222 | |
285b36d6 | 223 | /** Detach all iterators, leaving them singular. */ |
526da49c | 224 | void |
285b36d6 | 225 | _M_detach_all(); |
526da49c BI |
226 | |
227 | /** Detach all singular iterators. | |
228 | * @post for all iterators i attached to this sequence, | |
285b36d6 BK |
229 | * i->_M_version == _M_version. |
230 | */ | |
231 | void | |
232 | _M_detach_singular(); | |
526da49c | 233 | |
285b36d6 BK |
234 | /** Revalidates all attached singular iterators. This method may |
235 | * be used to validate iterators that were invalidated before | |
28dac70a | 236 | * (but for some reason, such as an exception, need to become |
285b36d6 BK |
237 | * valid again). |
238 | */ | |
239 | void | |
240 | _M_revalidate_singular(); | |
526da49c | 241 | |
285b36d6 BK |
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 | */ | |
526da49c | 247 | void |
15ee1a77 | 248 | _M_swap(_Safe_sequence_base& __x) _GLIBCXX_USE_NOEXCEPT; |
526da49c | 249 | |
eebbe2c7 | 250 | /** For use in _Safe_sequence. */ |
15ee1a77 FD |
251 | __gnu_cxx::__mutex& |
252 | _M_get_mutex() throw (); | |
eebbe2c7 | 253 | |
285b36d6 | 254 | /** Invalidates all iterators. */ |
526da49c | 255 | void |
285b36d6 BK |
256 | _M_invalidate_all() const |
257 | { if (++_M_version == 0) _M_version = 1; } | |
afe96d41 | 258 | |
5d045324 | 259 | private: |
afe96d41 FD |
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 (); | |
285b36d6 BK |
275 | }; |
276 | } // namespace __gnu_debug | |
277 | ||
526da49c | 278 | #endif |