libstdc++
safe_unordered_container.h
Go to the documentation of this file.
1// Safe container implementation -*- C++ -*-
2
3// Copyright (C) 2011-2026 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_unordered_container.h
26 * This file is a GNU debug extension to the Standard C++ Library.
27 */
28
29#ifndef _GLIBCXX_DEBUG_SAFE_UNORDERED_CONTAINER_H
30#define _GLIBCXX_DEBUG_SAFE_UNORDERED_CONTAINER_H 1
31
32#include <debug/assertions.h>
33#include <debug/macros.h>
34#include <debug/functions.h>
36
37namespace __gnu_debug
38{
39 /**
40 * @brief Base class for constructing a @a safe unordered container type
41 * that tracks iterators that reference it.
42 *
43 * The class template %_Safe_unordered_container simplifies the
44 * construction of @a safe unordered containers that track the iterators
45 * that reference the container, so that the iterators are notified of
46 * changes in the container that may affect their operation, e.g., if
47 * the container invalidates its iterators or is destructed. This class
48 * template may only be used by deriving from it and passing the name
49 * of the derived class as its template parameter via the curiously
50 * recurring template pattern. The derived class must have @c
51 * iterator and @c const_iterator types that are instantiations of
52 * class template _Safe_iterator for this container and @c local_iterator
53 * and @c const_local_iterator types that are instantiations of class
54 * template _Safe_local_iterator for this container. Iterators will
55 * then be tracked automatically.
56 */
57 template<typename _Container>
58 class _Safe_unordered_container : public _Safe_unordered_container_base
59 {
60 _Container&
61 _M_cont() noexcept
62 { return *static_cast<_Container*>(this); }
63
65 _M_self() const
66 { return this; }
67
68#if __cplusplus > 201402L
69 protected:
70 template<typename _ExtractKey, typename _Source>
71 struct _UContInvalidatePred
72 {
73 template<typename _Iterator>
74 bool
75 operator()(_Iterator __it) const
76 { return _M_source.count(_ExtractKey{}(*__it)) == 0; }
77
78 const _Source& _M_source;
79 };
80
81 template<typename _ExtractKey, typename _Source>
82 struct _UMContInvalidatePred
83 {
84 template<typename _Iterator>
85 bool
86 operator()(_Iterator __it) const
87 {
88 auto __rng =
89 _M_source._M_base().equal_range(_ExtractKey{}(*__it));
90 for (auto __rit = __rng.first;
91 __rit != __rng.second; ++__rit)
92 {
93 if (__it == __rit)
94 return false;
95 }
96
97 return true;
98 }
99
100 const _Source& _M_source;
101 };
102
103 template<typename _Source, typename _InvalidatePred>
104 struct _UContMergeGuard
105 {
106 _UContMergeGuard(_Source& __src) noexcept
107 : _M_source(__src), _M_size(__src.size()), _M_pred { __src }
108 { }
109
110 _UContMergeGuard(const _UContMergeGuard&) = delete;
111
112 ~_UContMergeGuard()
113 {
114 const std::size_t __size = _M_source.size();
115 if (__size == _M_size)
116 return;
117
118 __try
119 {
120 if (__size == 0)
121 _M_source._M_invalidate_all();
122 else
123 _M_source._M_invalidate_all_if(_M_pred);
124 }
125 __catch(...)
126 {
127 _M_source._M_invalidate_all();
128 }
129 }
130
131 _Source& _M_source;
132 const std::size_t _M_size;
133 _InvalidatePred _M_pred;
134 };
135
136 template<typename _ExtractKey, typename _Source>
137 static _UContMergeGuard<_Source,
138 _UContInvalidatePred<_ExtractKey, _Source>>
139 _S_uc_guard(_ExtractKey, _Source& __src)
140 {
141 typedef _UContInvalidatePred<_ExtractKey, _Source> _InvalidatePred;
142 return _UContMergeGuard<_Source, _InvalidatePred>(__src);
143 }
144
145 template<typename _ExtractKey, typename _Source>
146 static _UContMergeGuard<_Source,
147 _UMContInvalidatePred<_ExtractKey, _Source>>
148 _S_umc_guard(_ExtractKey, _Source& __src)
149 {
150 typedef _UMContInvalidatePred<_ExtractKey, _Source> _InvalidatePred;
151 return _UContMergeGuard<_Source, _InvalidatePred>(__src);
152 }
153#endif // C++17
154
155 public:
156 void
158 {
159 __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
160 auto __end = _M_cont()._M_base().cend();
161 _M_invalidate_if(
162 [__end](decltype(__end) __it)
163 { return __it != __end; },
164 sentry);
165
166 auto __local_end = _M_cont()._M_base().cend(0);
167 _M_invalidate_local_if(
168 [__local_end](decltype(__local_end) __it)
169 { return __it != __local_end; },
170 sentry);
171 }
172
173 template<typename _Predicate>
174 void
175 _M_invalidate_all_if(_Predicate __pred)
176 {
177 __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
178 _M_invalidate_if(__pred, sentry);
179 _M_invalidate_local_if(__pred, sentry);
180 }
181
182 protected:
183 template<typename _VictimIt>
184 void
185 _M_invalidate(_VictimIt __victim)
186 {
187 __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
188 _M_invalidate(__victim, sentry);
189 }
190
191 template<typename _VictimIt>
192 void
193 _M_invalidate(_VictimIt __victim, const __gnu_cxx::__scoped_lock& __lock)
194 {
195 auto __end = _M_cont()._M_base().cend();
196 _M_invalidate_if(
197 [__victim](decltype(__end) __it)
198 { return __it == __victim; },
199 __lock);
200
201 auto __local_end = _M_cont()._M_base().cend(0);
202 _M_invalidate_local_if(
203 [__victim](decltype(__local_end) __it)
204 { return __it == __victim; },
205 __lock);
206 }
207
208 private:
209 /** Invalidates all iterators @c x that reference this container,
210 are not singular, and for which @c __pred(x) returns @c
211 true. @c __pred will be invoked with the normal iterators nested
212 in the safe ones. */
213 template<typename _Predicate>
214 void
215 _M_invalidate_if(_Predicate __pred, const __gnu_cxx::__scoped_lock&);
216
217 /** Invalidates all local iterators @c x that reference this container,
218 are not singular, and for which @c __pred(x) returns @c
219 true. @c __pred will be invoked with the normal local iterators
220 nested in the safe ones. */
221 template<typename _Predicate>
222 void
223 _M_invalidate_local_if(_Predicate __pred,
225 };
226} // namespace __gnu_debug
227
229
230#endif
GNU debug classes for public use.
constexpr void _M_invalidate_all() const
Definition safe_base.h:314
__gnu_cxx::__mutex & _M_get_mutex() const noexcept
Base class for constructing a safe unordered container type that tracks iterators that reference it.
Scoped lock idiom.