⚠ Archived content — this site is no longer maintained.   Current WebKit documentation is at docs.webkit.org.

Changeset 244289 in webkit


Ignore:
Timestamp:
Apr 15, 2019, 2:30:38 PM (7 years ago)
Author:
rniwa@webkit.org
Message:

HashTable::removeIf always shrinks the hash table by half even if there is nothing left
https://bugs.webkit.org/show_bug.cgi?id=196681

Reviewed by Darin Adler.

Source/WTF:

Made HashTable::removeIf shrink to the "best size", which is the least power of two bigger
than twice the key count as already used in the copy constructor.

  • wtf/HashTable.h:

(WTF::HashTable::computeBestTableSize): Extracted from the copy constructor.
(WTF::HashTable::shrinkToBestSize): Added.
(WTF::HashTable::removeIf): Use shrinkToBestSize instead of shrink.
(WTF::HashTable::HashTable):

Tools:

Added tests.

  • TestWebKitAPI/Tests/WTF/HashSet.cpp:

(WTF_HashSet.RemoveIf):
(WTF_HashSet.RemoveIfShrinkToBestSize):

Location:
trunk
Files:
4 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WTF/ChangeLog

    r244223 r244289  
     12019-04-12  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        HashTable::removeIf always shrinks the hash table by half even if there is nothing left
     4        https://bugs.webkit.org/show_bug.cgi?id=196681
     5
     6        Reviewed by Darin Adler.
     7
     8        Made HashTable::removeIf shrink to the "best size", which is the least power of two bigger
     9        than twice the key count as already used in the copy constructor.
     10
     11        * wtf/HashTable.h:
     12        (WTF::HashTable::computeBestTableSize): Extracted from the copy constructor.
     13        (WTF::HashTable::shrinkToBestSize): Added.
     14        (WTF::HashTable::removeIf): Use shrinkToBestSize instead of shrink.
     15        (WTF::HashTable::HashTable):
     16
    1172019-04-12  Eric Carlson  <eric.carlson@apple.com>
    218
  • trunk/Source/WTF/wtf/HashTable.h

    r242387 r244289  
    465465        void remove(ValueType*);
    466466
     467        static constexpr unsigned computeBestTableSize(unsigned keyCount);
    467468        bool shouldExpand() const { return (m_keyCount + m_deletedCount) * m_maxLoad >= m_tableSize; }
    468469        bool mustRehashInPlace() const { return m_keyCount * m_minLoad < m_tableSize * 2; }
     
    470471        ValueType* expand(ValueType* entry = nullptr);
    471472        void shrink() { rehash(m_tableSize / 2, nullptr); }
    472 
     473        void shrinkToBestSize();
     474   
    473475        void deleteReleasedWeakBuckets();
    474476
     
    11501152
    11511153        if (shouldShrink())
    1152             shrink();
     1154            shrinkToBestSize();
    11531155       
    11541156        internalCheckTableConsistency();
     
    11941196
    11951197        return rehash(newSize, entry);
     1198    }
     1199
     1200    template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
     1201    constexpr unsigned HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::computeBestTableSize(unsigned keyCount)
     1202    {
     1203        unsigned bestTableSize = WTF::roundUpToPowerOfTwo(keyCount) * 2;
     1204
     1205        // With maxLoad at 1/2 and minLoad at 1/6, our average load is 2/6.
     1206        // If we are getting halfway between 2/6 and 1/2 (past 5/12), we double the size to avoid being too close to
     1207        // loadMax and bring the ratio close to 2/6. This give us a load in the bounds [3/12, 5/12).
     1208        bool aboveThreeQuarterLoad = keyCount * 12 >= bestTableSize * 5;
     1209        if (aboveThreeQuarterLoad)
     1210            bestTableSize *= 2;
     1211
     1212        unsigned minimumTableSize = KeyTraits::minimumTableSize;
     1213        return std::max<unsigned>(bestTableSize, minimumTableSize);
     1214    }
     1215
     1216    template<typename Key, typename Value, typename Extractor, typename HashFunctions, typename Traits, typename KeyTraits>
     1217    void HashTable<Key, Value, Extractor, HashFunctions, Traits, KeyTraits>::shrinkToBestSize()
     1218    {
     1219        unsigned minimumTableSize = KeyTraits::minimumTableSize;
     1220        rehash(std::max<unsigned>(minimumTableSize, computeBestTableSize(m_keyCount)), nullptr);
    11961221    }
    11971222
     
    13021327            return;
    13031328
    1304         unsigned bestTableSize = WTF::roundUpToPowerOfTwo(otherKeyCount) * 2;
    1305 
    1306         // With maxLoad at 1/2 and minLoad at 1/6, our average load is 2/6.
    1307         // If we are getting halfway between 2/6 and 1/2 (past 5/12), we double the size to avoid being too close to
    1308         // loadMax and bring the ratio close to 2/6. This give us a load in the bounds [3/12, 5/12).
    1309         bool aboveThreeQuarterLoad = otherKeyCount * 12 >= bestTableSize * 5;
    1310         if (aboveThreeQuarterLoad)
    1311             bestTableSize *= 2;
    1312 
    1313         unsigned minimumTableSize = KeyTraits::minimumTableSize;
    1314         m_tableSize = std::max<unsigned>(bestTableSize, minimumTableSize);
     1329        m_tableSize = computeBestTableSize(otherKeyCount);
    13151330        m_tableSizeMask = m_tableSize - 1;
    13161331        m_keyCount = otherKeyCount;
  • trunk/Tools/ChangeLog

    r244288 r244289  
     12019-04-12  Ryosuke Niwa  <rniwa@webkit.org>
     2
     3        HashTable::removeIf always shrinks the hash table by half even if there is nothing left
     4        https://bugs.webkit.org/show_bug.cgi?id=196681
     5
     6        Reviewed by Darin Adler.
     7
     8        Added tests.
     9
     10        * TestWebKitAPI/Tests/WTF/HashSet.cpp:
     11        (WTF_HashSet.RemoveIf):
     12        (WTF_HashSet.RemoveIfShrinkToBestSize):
     13
    1142019-04-15  John Wilander  <wilander@apple.com>
    215
  • trunk/Tools/TestWebKitAPI/Tests/WTF/HashSet.cpp

    r238467 r244289  
    467467}
    468468
     469TEST(WTF_HashSet, RemoveIf)
     470{
     471    HashSet<unsigned> set1 { 1, 2, 3, 4, 5 };
     472    ASSERT_EQ(set1.size(), 5u);
     473    set1.removeIf([] (unsigned item) { return item % 2;  });
     474    set1.checkConsistency();
     475    ASSERT_TRUE(!set1.contains(1));
     476    ASSERT_TRUE(set1.contains(2));
     477    ASSERT_TRUE(!set1.contains(3));
     478    ASSERT_TRUE(set1.contains(4));
     479    ASSERT_TRUE(!set1.contains(5));
     480    ASSERT_EQ(set1.size(), 2u);
     481}
     482
     483TEST(WTF_HashSet, RemoveIfShrinkToBestSize)
     484{
     485    HashSet<unsigned> set1;
     486    set1.add(1);
     487    unsigned originalCapacity = set1.capacity();
     488    while (set1.capacity() < originalCapacity * 4)
     489        set1.add(set1.size() + 1);
     490    set1.removeIf([] (unsigned item) { return item != 1; });
     491    set1.checkConsistency();
     492    ASSERT_EQ(set1.size(), 1u);
     493    ASSERT_EQ(set1.capacity(), originalCapacity);
     494
     495    set1.clear();
     496    set1.checkConsistency();
     497    while (set1.capacity() < originalCapacity * 8)
     498        set1.add(set1.size() + 1);
     499    set1.removeIf([originalCapacity] (unsigned item) { return item >= originalCapacity / 2; });
     500    set1.checkConsistency();
     501    ASSERT_EQ(set1.size(), originalCapacity / 2 - 1);
     502    ASSERT_EQ(set1.capacity(), originalCapacity);
     503}
     504
    469505} // namespace TestWebKitAPI
Note: See TracChangeset for help on using the changeset viewer.