template<typename _Container>
class _Safe_unordered_container : public _Safe_unordered_container_base
{
- private:
_Container&
_M_cont() noexcept
{ return *static_cast<_Container*>(this); }
_M_self() const
{ return this; }
- protected:
- void
- _M_invalidate_locals()
- {
- auto __local_end = _M_cont()._M_base().cend(0);
- this->_M_invalidate_local_if(
- [__local_end](__decltype(__local_end) __it)
- { return __it != __local_end; });
- }
-
#if __cplusplus > 201402L
+ protected:
template<typename _ExtractKey, typename _Source>
struct _UContInvalidatePred
{
if (__size == 0)
_M_source._M_invalidate_all();
else
- {
- _M_source._M_invalidate_if(_M_pred);
- _M_source._M_invalidate_local_if(_M_pred);
- }
+ _M_source._M_invalidate_all_if(_M_pred);
}
__catch(...)
{
void
_M_invalidate_all()
{
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
auto __end = _M_cont()._M_base().cend();
- this->_M_invalidate_if([__end](__decltype(__end) __it)
- { return __it != __end; });
- _M_invalidate_locals();
+ _M_invalidate_if(
+ [__end](decltype(__end) __it)
+ { return __it != __end; },
+ sentry);
+
+ auto __local_end = _M_cont()._M_base().cend(0);
+ _M_invalidate_local_if(
+ [__local_end](decltype(__local_end) __it)
+ { return __it != __local_end; },
+ sentry);
}
+ template<typename _Predicate>
+ void
+ _M_invalidate_all_if(_Predicate __pred)
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
+ _M_invalidate_if(__pred, sentry);
+ _M_invalidate_local_if(__pred, sentry);
+ }
+
+ protected:
+ template<typename _VictimIt>
+ void
+ _M_invalidate(_VictimIt __victim)
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
+ _M_invalidate(__victim, sentry);
+ }
+
+ template<typename _VictimIt>
+ void
+ _M_invalidate(_VictimIt __victim, const __gnu_cxx::__scoped_lock& __lock)
+ {
+ auto __end = _M_cont()._M_base().cend();
+ _M_invalidate_if(
+ [__victim](decltype(__end) __it)
+ { return __it == __victim; },
+ __lock);
+
+ auto __local_end = _M_cont()._M_base().cend(0);
+ _M_invalidate_local_if(
+ [__victim](decltype(__local_end) __it)
+ { return __it == __victim; },
+ __lock);
+ }
+
+ private:
/** Invalidates all iterators @c x that reference this container,
are not singular, and for which @c __pred(x) returns @c
true. @c __pred will be invoked with the normal iterators nested
in the safe ones. */
template<typename _Predicate>
void
- _M_invalidate_if(_Predicate __pred);
+ _M_invalidate_if(_Predicate __pred, const __gnu_cxx::__scoped_lock&);
/** Invalidates all local iterators @c x that reference this container,
are not singular, and for which @c __pred(x) returns @c
nested in the safe ones. */
template<typename _Predicate>
void
- _M_invalidate_local_if(_Predicate __pred);
+ _M_invalidate_local_if(_Predicate __pred,
+ const __gnu_cxx::__scoped_lock&);
};
} // namespace __gnu_debug
template<typename _Predicate>
void
_Safe_unordered_container<_Container>::
- _M_invalidate_if(_Predicate __pred)
+ _M_invalidate_if(_Predicate __pred, const __gnu_cxx::__scoped_lock&)
{
typedef typename _Container::iterator iterator;
typedef typename _Container::const_iterator const_iterator;
- __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
for (_Safe_iterator_base* __iter = _M_iterators; __iter;)
{
iterator* __victim = static_cast<iterator*>(__iter);
template<typename _Predicate>
void
_Safe_unordered_container<_Container>::
- _M_invalidate_local_if(_Predicate __pred)
+ _M_invalidate_local_if(_Predicate __pred, const __gnu_cxx::__scoped_lock&)
{
typedef typename _Container::local_iterator local_iterator;
typedef typename _Container::const_local_iterator const_local_iterator;
- __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
for (_Safe_iterator_base* __iter = _M_local_iterators; __iter;)
{
local_iterator* __victim = static_cast<local_iterator*>(__iter);
erase(const_iterator __first, const_iterator __last)
{
__glibcxx_check_erase_range(__first, __last);
- for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
- {
- _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
- _M_message(__gnu_debug::__msg_valid_range)
- ._M_iterator(__first, "first")
- ._M_iterator(__last, "last"));
- _M_invalidate(__tmp);
- }
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
+ for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
+ {
+ _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
+ _M_message(__gnu_debug::__msg_valid_range)
+ ._M_iterator(__first, "first")
+ ._M_iterator(__last, "last"));
+ this->_M_invalidate(__tmp, sentry);
+ }
+ }
- size_type __bucket_count = this->bucket_count();
auto __next = _Base::erase(__first.base(), __last.base());
- _M_check_rehashed(__bucket_count);
return { __next, this };
}
_M_base() const noexcept { return *this; }
private:
+ const unordered_map*
+ _M_self() const noexcept
+ { return this; }
+
void
_M_check_rehashed(size_type __prev_count)
{
this->_M_invalidate_all();
}
- void
- _M_invalidate(_Base_const_iterator __victim)
- {
- this->_M_invalidate_if(
- [__victim](_Base_const_iterator __it) { return __it == __victim; });
- this->_M_invalidate_local_if(
- [__victim](_Base_const_local_iterator __it)
- { return __it == __victim; });
- }
-
_Base_iterator
_M_erase(_Base_const_iterator __victim)
{
- _M_invalidate(__victim);
- size_type __bucket_count = this->bucket_count();
- _Base_iterator __next = _Base::erase(__victim);
- _M_check_rehashed(__bucket_count);
- return __next;
+ this->_M_invalidate(__victim);
+ return _Base::erase(__victim);
}
#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
node_type
_M_extract(_Base_const_iterator __victim)
{
- _M_invalidate(__victim);
+ this->_M_invalidate(__victim);
return _Base::extract(__victim);
}
#endif
size_type
erase(const key_type& __key)
{
- size_type __ret(0);
- size_type __bucket_count = this->bucket_count();
- auto __pair = _Base::equal_range(__key);
- for (auto __victim = __pair.first; __victim != __pair.second;)
- {
- _M_invalidate(__victim);
- __victim = _Base::erase(__victim);
- ++__ret;
- }
-
- _M_check_rehashed(__bucket_count);
- return __ret;
+ auto __victims = _Base::equal_range(__key);
+ return _M_erase(__victims.first, __victims.second);
}
# ifdef __glibcxx_associative_heterogeneous_erasure
size_type
erase(_Kt&& __key)
{
- size_type __count(0);
auto __victims = _Base::equal_range(__key);
- for (auto __victim = __victims.first; __victim != __victims.second;)
- {
- _M_invalidate(__victim);
- __victim = _Base::erase(__victim);
- ++__count;
- }
- return __count;
+ return _M_erase(__victims.first, __victims.second);
}
#endif
erase(const_iterator __first, const_iterator __last)
{
__glibcxx_check_erase_range(__first, __last);
- for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
- {
- _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
- _M_message(__gnu_debug::__msg_valid_range)
- ._M_iterator(__first, "first")
- ._M_iterator(__last, "last"));
- _M_invalidate(__tmp);
- }
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
+ for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
+ {
+ _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
+ _M_message(__gnu_debug::__msg_valid_range)
+ ._M_iterator(__first, "first")
+ ._M_iterator(__last, "last"));
+ this->_M_invalidate(__tmp, sentry);
+ }
+ }
- size_type __bucket_count = this->bucket_count();
auto __next = _Base::erase(__first.base(), __last.base());
- _M_check_rehashed(__bucket_count);
return { __next, this };
}
_M_base() const noexcept { return *this; }
private:
+ const unordered_multimap*
+ _M_self() const noexcept
+ { return this; }
+
void
_M_check_rehashed(size_type __prev_count)
{
this->_M_invalidate_all();
}
- void
- _M_invalidate(_Base_const_iterator __victim)
+ _Base_iterator
+ _M_erase(_Base_const_iterator __victim)
{
- this->_M_invalidate_if(
- [__victim](_Base_const_iterator __it) { return __it == __victim; });
- this->_M_invalidate_local_if(
- [__victim](_Base_const_local_iterator __it)
- { return __it == __victim; });
+ this->_M_invalidate(__victim);
+ return _Base::erase(__victim);
}
- _Base_iterator
- _M_erase(_Base_const_iterator __victim)
+ size_type
+ _M_erase(_Base_iterator __first, _Base_iterator __last)
{
- _M_invalidate(__victim);
- size_type __bucket_count = this->bucket_count();
- _Base_iterator __next = _Base::erase(__victim);
- _M_check_rehashed(__bucket_count);
- return __next;
+ size_type __ret(0);
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
+ for (auto __victim = __first; __victim != __last; ++__victim)
+ {
+ this->_M_invalidate(__victim, sentry);
+ ++__ret;
+ }
+ }
+
+ _Base::erase(__first, __last);
+ return __ret;
}
#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
node_type
_M_extract(_Base_const_iterator __victim)
{
- _M_invalidate(__victim);
+ this->_M_invalidate(__victim);
return _Base::extract(__victim);
}
#endif
erase(const_iterator __first, const_iterator __last)
{
__glibcxx_check_erase_range(__first, __last);
- for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
- {
- _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
- _M_message(__gnu_debug::__msg_valid_range)
- ._M_iterator(__first, "first")
- ._M_iterator(__last, "last"));
- _M_invalidate(__tmp);
- }
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
+ for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
+ {
+ _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
+ _M_message(__gnu_debug::__msg_valid_range)
+ ._M_iterator(__first, "first")
+ ._M_iterator(__last, "last"));
+ this->_M_invalidate(__tmp, sentry);
+ }
+ }
- size_type __bucket_count = this->bucket_count();
auto __next = _Base::erase(__first.base(), __last.base());
- _M_check_rehashed(__bucket_count);
return { __next, this };
}
_M_base() const noexcept { return *this; }
private:
+ const unordered_set*
+ _M_self() const noexcept
+ { return this; }
+
void
_M_check_rehashed(size_type __prev_count)
{
this->_M_invalidate_all();
}
- void
- _M_invalidate(_Base_const_iterator __victim)
- {
- this->_M_invalidate_if(
- [__victim](_Base_const_iterator __it) { return __it == __victim; });
- this->_M_invalidate_local_if(
- [__victim](_Base_const_local_iterator __it)
- { return __it == __victim; });
- }
-
_Base_iterator
_M_erase(_Base_const_iterator __victim)
{
- _M_invalidate(__victim);
- size_type __bucket_count = this->bucket_count();
- _Base_iterator __next = _Base::erase(__victim);
- _M_check_rehashed(__bucket_count);
- return __next;
+ this->_M_invalidate(__victim);
+ return _Base::erase(__victim);
}
#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
node_type
_M_extract(_Base_const_iterator __victim)
{
- _M_invalidate(__victim);
+ this->_M_invalidate(__victim);
return _Base::extract(__victim);
}
#endif
size_type
erase(const key_type& __key)
{
- size_type __count(0);
auto __victims = _Base::equal_range(__key);
- for (auto __victim = __victims.first; __victim != __victims.second;)
- {
- _M_invalidate(__victim);
- __victim = _Base::erase(__victim);
- ++__count;
- }
- return __count;
+ return _M_erase(__victims.first, __victims.second);
}
# ifdef __glibcxx_associative_heterogeneous_erasure
size_type
erase(_Kt&& __key)
{
- size_type __count(0);
auto __victims = _Base::equal_range(__key);
- for (auto __victim = __victims.first; __victim != __victims.second;)
- {
- _M_invalidate(__victim);
- __victim = _Base::erase(__victim);
- ++__count;
- }
- return __count;
+ return _M_erase(__victims.first, __victims.second);
}
#endif
erase(const_iterator __first, const_iterator __last)
{
__glibcxx_check_erase_range(__first, __last);
- for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
- {
- _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
- _M_message(__gnu_debug::__msg_valid_range)
- ._M_iterator(__first, "first")
- ._M_iterator(__last, "last"));
- _M_invalidate(__tmp);
- }
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
+ for (auto __tmp = __first.base(); __tmp != __last.base(); ++__tmp)
+ {
+ _GLIBCXX_DEBUG_VERIFY(__tmp != _Base::cend(),
+ _M_message(__gnu_debug::__msg_valid_range)
+ ._M_iterator(__first, "first")
+ ._M_iterator(__last, "last"));
+ this->_M_invalidate(__tmp, sentry);
+ }
+ }
+
return { _Base::erase(__first.base(), __last.base()), this };
}
_M_base() const noexcept { return *this; }
private:
+ const unordered_multiset*
+ _M_self() const noexcept
+ { return this; }
+
void
_M_check_rehashed(size_type __prev_count)
{
this->_M_invalidate_all();
}
- void
- _M_invalidate(_Base_const_iterator __victim)
+ _Base_iterator
+ _M_erase(_Base_const_iterator __victim)
{
- this->_M_invalidate_if(
- [__victim](_Base_const_iterator __it) { return __it == __victim; });
- this->_M_invalidate_local_if(
- [__victim](_Base_const_local_iterator __it)
- { return __it == __victim; });
+ this->_M_invalidate(__victim);
+ return _Base::erase(__victim);
}
- _Base_iterator
- _M_erase(_Base_const_iterator __victim)
+ size_type
+ _M_erase(_Base_iterator __first, _Base_iterator __last)
{
- _M_invalidate(__victim);
- size_type __bucket_count = this->bucket_count();
- _Base_iterator __next = _Base::erase(__victim);
- _M_check_rehashed(__bucket_count);
- return __next;
+ size_type __count(0);
+ {
+ __gnu_cxx::__scoped_lock sentry(_M_self()->_M_get_mutex());
+ for (auto __victim = __first; __victim != __last; ++__victim)
+ {
+ this->_M_invalidate(__victim, sentry);
+ ++__count;
+ }
+ }
+
+ _Base::erase(__first, __last);
+ return __count;
}
#ifdef __glibcxx_node_extract // >= C++17 && HOSTED
node_type
_M_extract(_Base_const_iterator __victim)
{
- _M_invalidate(__victim);
+ this->_M_invalidate(__victim);
return _Base::extract(__victim);
}
#endif