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