[ADT] Restore handwritten vector find in SmallSet (#110254)
This patch restores handwritten linear searches instead of the use of std::find. After PR #109412, a performance regression was observed that's caused by the use of std::find for linear searches. The exact cause wasn't pinpointed, but, at the time of writing, the most likely culprit is the forced loop unrolling in the definition of libstdc++'s std::find. Presumably this is done to optimise for larger containers. However for the case of small containers such as SmallVector, this actually hurts performance.
This commit is contained in:
@@ -193,7 +193,7 @@ public:
|
||||
bool erase(const T &V) {
|
||||
if (!isSmall())
|
||||
return Set.erase(V);
|
||||
auto I = std::find(Vector.begin(), Vector.end(), V);
|
||||
auto I = vfind(V);
|
||||
if (I != Vector.end()) {
|
||||
Vector.erase(I);
|
||||
return true;
|
||||
@@ -221,7 +221,7 @@ public:
|
||||
/// Check if the SmallSet contains the given element.
|
||||
bool contains(const T &V) const {
|
||||
if (isSmall())
|
||||
return std::find(Vector.begin(), Vector.end(), V) != Vector.end();
|
||||
return vfind(V) != Vector.end();
|
||||
return Set.find(V) != Set.end();
|
||||
}
|
||||
|
||||
@@ -237,20 +237,28 @@ private:
|
||||
return {const_iterator(I), Inserted};
|
||||
}
|
||||
|
||||
auto I = std::find(Vector.begin(), Vector.end(), V);
|
||||
auto I = vfind(V);
|
||||
if (I != Vector.end()) // Don't reinsert if it already exists.
|
||||
return {const_iterator(I), false};
|
||||
if (Vector.size() < N) {
|
||||
Vector.push_back(std::forward<ArgType>(V));
|
||||
return {const_iterator(std::prev(Vector.end())), true};
|
||||
}
|
||||
|
||||
// Otherwise, grow from vector to set.
|
||||
Set.insert(std::make_move_iterator(Vector.begin()),
|
||||
std::make_move_iterator(Vector.end()));
|
||||
Vector.clear();
|
||||
return {const_iterator(Set.insert(std::forward<ArgType>(V)).first), true};
|
||||
}
|
||||
|
||||
// Handwritten linear search. The use of std::find might hurt performance as
|
||||
// its implementation may be optimized for larger containers.
|
||||
typename SmallVector<T, N>::const_iterator vfind(const T &V) const {
|
||||
for (auto I = Vector.begin(), E = Vector.end(); I != E; ++I)
|
||||
if (*I == V)
|
||||
return I;
|
||||
return Vector.end();
|
||||
}
|
||||
};
|
||||
|
||||
/// If this set is of pointer values, transparently switch over to using
|
||||
|
||||
Reference in New Issue
Block a user