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