From b98f9f222803689b033d6f5e87d8911aabd2fdaf Mon Sep 17 00:00:00 2001 From: Squareys Date: Sat, 6 Aug 2022 22:09:28 +0200 Subject: [PATCH 1/3] Avoid some copies in SmallSetBase(std::initializer_list) Signed-off-by: Squareys --- src/support/small_set.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/support/small_set.h b/src/support/small_set.h index 7f441ab1315..02302a27c06 100644 --- a/src/support/small_set.h +++ b/src/support/small_set.h @@ -154,7 +154,7 @@ class SmallSetBase { SmallSetBase() {} SmallSetBase(std::initializer_list init) { - for (T item : init) { + for (const T& item : init) { insert(item); } } From e9f5ac4ef68bbf25cf27e500b3bfdbab13ceafe5 Mon Sep 17 00:00:00 2001 From: Squareys Date: Sat, 6 Aug 2022 22:10:27 +0200 Subject: [PATCH 2/3] Avoid std::set heap allocation in default constructor of SmallSetBase() Signed-off-by: Squareys --- src/support/small_set.h | 39 +++++++++++++++++++++++---------------- 1 file changed, 23 insertions(+), 16 deletions(-) diff --git a/src/support/small_set.h b/src/support/small_set.h index 02302a27c06..12b9062d591 100644 --- a/src/support/small_set.h +++ b/src/support/small_set.h @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -132,16 +133,20 @@ class SmallSetBase { // fixed-space storage FixedStorage fixed; - // flexible additional storage - FlexibleSet flexible; + // Flexible additional storage. We use std::optional here to reduce the + // overhead in the common case, where the flexible storage is never needed. + // With std::optional we just have a pointer taking up space, as opposed to a + // full std::set which is larger. Also, on MSVC's STL at least the std::set + // constructor does some work, which we want to avoid. + std::optional flexible; bool usingFixed() const { - // If the flexible storage contains something, then we are using it. + // If the flexible optional has a value, we are using it. // Otherwise we use the fixed storage. Note that if we grow and shrink then // we will stay in flexible mode until we reach a size of zero, at which // point we return to fixed mode. This is intentional, to avoid a lot of // movement in switching between fixed and flexible mode. - return flexible.empty(); + return !flexible || flexible->empty(); } public: @@ -165,15 +170,15 @@ class SmallSetBase { // We need to add an item but no fixed storage remains to grow. Switch // to flexible. assert(fixed.used == N); - assert(flexible.empty()); - flexible.insert(fixed.storage.begin(), - fixed.storage.begin() + fixed.used); - flexible.insert(x); + flexible = FlexibleSet{}; + flexible->insert(fixed.storage.begin(), + fixed.storage.begin() + fixed.used); + flexible->insert(x); assert(!usingFixed()); fixed.used = 0; } } else { - flexible.insert(x); + flexible->insert(x); } } @@ -181,7 +186,7 @@ class SmallSetBase { if (usingFixed()) { fixed.erase(x); } else { - flexible.erase(x); + flexible->erase(x); } } @@ -195,7 +200,7 @@ class SmallSetBase { } return 0; } else { - return flexible.count(x); + return flexible->count(x); } } @@ -203,7 +208,7 @@ class SmallSetBase { if (usingFixed()) { return fixed.used; } else { - return flexible.size(); + return flexible->size(); } } @@ -211,7 +216,9 @@ class SmallSetBase { void clear() { fixed.used = 0; - flexible.clear(); + if (flexible) { + flexible->clear(); + } } bool @@ -228,7 +235,7 @@ class SmallSetBase { other.fixed.storage.begin() + other.fixed.used, [this](const T& x) { return count(x); }); } else { - return flexible == other.flexible; + return flexible.value() == other.flexible.value(); } } @@ -264,7 +271,7 @@ class SmallSetBase { if (usingFixed) { fixedIndex = 0; } else { - flexibleIterator = parent->flexible.begin(); + flexibleIterator = parent->flexible->begin(); } } @@ -272,7 +279,7 @@ class SmallSetBase { if (usingFixed) { fixedIndex = parent->size(); } else { - flexibleIterator = parent->flexible.end(); + flexibleIterator = parent->flexible->end(); } } From fe060b896573434117d9ce5eb740cbc125814004 Mon Sep 17 00:00:00 2001 From: Squareys Date: Wed, 23 Nov 2022 13:11:10 +0100 Subject: [PATCH 3/3] Return number of removed elements from SmallSet::erase() like std::set does Signed-off-by: Squareys --- src/support/small_set.h | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/support/small_set.h b/src/support/small_set.h index 12b9062d591..b2fa4c0e173 100644 --- a/src/support/small_set.h +++ b/src/support/small_set.h @@ -68,16 +68,17 @@ struct UnorderedFixedStorage : public FixedStorageBase { return InsertResult::NoError; } - void erase(const T& x) { + size_t erase(const T& x) { for (size_t i = 0; i < this->used; i++) { if (this->storage[i] == x) { // We found the item; erase it by moving the final item to replace it // and truncating the size. this->used--; this->storage[i] = this->storage[this->used]; - return; + return 1; } } + return 0; } }; @@ -114,7 +115,7 @@ struct OrderedFixedStorage : public FixedStorageBase { return InsertResult::NoError; } - void erase(const T& x) { + size_t erase(const T& x) { for (size_t i = 0; i < this->used; i++) { if (this->storage[i] == x) { // We found the item; move things backwards and shrink. @@ -122,9 +123,10 @@ struct OrderedFixedStorage : public FixedStorageBase { this->storage[j - 1] = this->storage[j]; } this->used--; - return; + return 1; } } + return 0; } }; @@ -182,11 +184,11 @@ class SmallSetBase { } } - void erase(const T& x) { + size_t erase(const T& x) { if (usingFixed()) { - fixed.erase(x); + return fixed.erase(x); } else { - flexible->erase(x); + return flexible->erase(x); } }