Bug 1700498 - nsTSetInserter::operator* returns a proxy - r=sg

Previously `operator*` returned the iterator, and the templated `operator=` would handle the value insertion.
However that `operator=` prevented a defaulted copy-assignment operator, which is used in some algorithms to overwrite the iterator itself.
So now `operator*` returns a proxy, which implements the templated `operator=` that is used to insert a value. This allows the nsTSetInserter to have a its defaulted `operator=`.

Side-effect: `E` (the hash's KeyClass) is not needed anymore in nsTSetInserter, so it's only templated on the set type.

Tech note: `std::back_insert_iterator` doesn't use a value, but has explicitly-defined `operator=(const typename Container::value_type&)` and  `operator=(typename Container::value_type&&)`. Unfortunately, some of our stored value types are references (e.g.: `nsStringHashKey::KeyType` is `const nsAString&`), which, due to reference collapsing, would have made both `operator=`'s have the same signature! That's why this implementation uses a proxy sub-type with a single templated `operator=` that can handle anything.

Differential Revision: https://phabricator.services.mozilla.com/D109587
This commit is contained in:
Gerald Squelart 2021-03-24 10:25:23 +00:00
parent 0c7e8b4d04
commit 2400d86309

View File

@ -152,22 +152,28 @@ inline void ImplCycleCollectionTraverse(
}
namespace mozilla {
template <typename E, typename SetT>
template <typename SetT>
class nsTSetInserter {
SetT* mSet;
class Proxy {
SetT& mSet;
public:
explicit Proxy(SetT& aSet) : mSet{aSet} {}
template <typename E2>
void operator=(E2&& aValue) {
mSet.Insert(std::forward<E2>(aValue));
}
};
public:
using iterator_category = std::output_iterator_tag;
explicit nsTSetInserter(SetT& aSet) : mSet{&aSet} {}
template <typename E2>
nsTSetInserter& operator=(E2&& aValue) {
mSet->Insert(std::forward<E2>(aValue));
return *this;
}
nsTSetInserter& operator*() { return *this; }
Proxy operator*() { return Proxy(*mSet); }
nsTSetInserter& operator++() { return *this; }
nsTSetInserter& operator++(int) { return *this; }
@ -176,7 +182,7 @@ class nsTSetInserter {
template <typename E>
auto MakeInserter(nsTBaseHashSet<E>& aSet) {
return mozilla::nsTSetInserter<E, nsTBaseHashSet<E>>{aSet};
return mozilla::nsTSetInserter<nsTBaseHashSet<E>>{aSet};
}
#endif // XPCOM_DS_NSTHASHSET_H_