HashTbl avoid backward search in erase()

- The ideas as discussed in email

- The speedup is really there.

Before
loop 0 - Erased 100000 elements:   3.82 s
loop 1 - Erased 100000 elements:   11.45 s
loop 2 - Erased 100000 elements:   19.46 s
loop 3 - Erased 100000 elements:   27.73 s
loop 4 - Erased 100000 elements:   38.74 s
^C

After
loop 0 - Erased 100000 elements (size 2900000 capacity 8388608) 0.01 s
loop 1 - Erased 100000 elements (size 2800000 capacity 8388608) 0 s
loop 2 - Erased 100000 elements (size 2700000 capacity 8388608) 0.01 s
loop 3 - Erased 100000 elements (size 2600000 capacity 8388608) 0 s
loop 4 - Erased 100000 elements (size 2500000 capacity 8388608) 0 s
loop 5 - Erased 100000 elements (size 2400000 capacity 8388608) 0 s
loop 6 - Erased 100000 elements (size 2300000 capacity 8388608) 0 s
loop 7 - Erased 100000 elements (size 2200000 capacity 8388608) 0 s
...
This commit is contained in:
Mark Olesen
2009-10-30 18:54:51 +01:00
parent 55a89e9db3
commit 2c73afb6ec
4 changed files with 47 additions and 48 deletions

View File

@ -56,15 +56,16 @@ int main(int argc, char *argv[])
HashTbl<label, label, Hash<label> > map(2 * nSize); HashTbl<label, label, Hash<label> > map(2 * nSize);
Info<< "Constructed map of size: " << nSize Info<< "Constructed map of size: " << nSize
<< " (size " << map.size() << " capacity " << map.capacity() << ") "
<< " " << timer.cpuTimeIncrement() << " s\n\n"; << " " << timer.cpuTimeIncrement() << " s\n\n";
for (label i = 0; i < nSize; i++) for (label i = 0; i < nSize; i++)
{ {
map.insert(i, i); map.insert(i, i);
} }
Info<< "Inserted " << nSize << " elements: " Info<< "Inserted " << nSize << " elements"
<< timer.cpuTimeIncrement() << " s\n\n"; << " (size " << map.size() << " capacity " << map.capacity() << ") "
<< timer.cpuTimeIncrement() << " s\n";
label elemI = 0; label elemI = 0;
for (label iLoop = 0; iLoop < nLoops; iLoop++) for (label iLoop = 0; iLoop < nLoops; iLoop++)
@ -73,8 +74,9 @@ int main(int argc, char *argv[])
{ {
map.erase(elemI++); map.erase(elemI++);
} }
Info<< "loop " << iLoop << " - Erased " << nBase << " elements: " Info<< "loop " << iLoop << " - Erased " << nBase << " elements"
<< " " << timer.cpuTimeIncrement() << " s\n"; << " (size " << map.size() << " capacity " << map.capacity() << ") "
<< timer.cpuTimeIncrement() << " s\n";
} }
return 0; return 0;

View File

@ -346,55 +346,41 @@ bool Foam::HashTbl<T, Key, Hash>::erase(const iterator& cit)
{ {
if (cit.elmtPtr_) // note: endIter_ also has 0 elmtPtr_ if (cit.elmtPtr_) // note: endIter_ also has 0 elmtPtr_
{ {
iterator& it = const_cast<iterator&>(cit);
// Search element before elmtPtr_ // Search element before elmtPtr_
hashedEntry* prev = 0; hashedEntry* prev = 0;
for (hashedEntry* ep = table_[it.hashIndex_]; ep; ep = ep->next_) for (hashedEntry* ep = table_[cit.hashIndex_]; ep; ep = ep->next_)
{ {
if (ep == it.elmtPtr_) if (ep == cit.elmtPtr_)
{ {
break; break;
} }
prev = ep; prev = ep;
} }
// adjust iterator after erase
iterator& iter = const_cast<iterator&>(cit);
if (prev) if (prev)
{ {
// Have element before elmtPtr // has an element before elmtPtr - reposition to there
prev->next_ = it.elmtPtr_->next_; prev->next_ = iter.elmtPtr_->next_;
delete it.elmtPtr_; delete iter.elmtPtr_;
it.elmtPtr_ = prev; iter.elmtPtr_ = prev;
} }
else else
{ {
// elmtPtr is first element on SLList // elmtPtr was first element on SLList
table_[it.hashIndex_] = it.elmtPtr_->next_; table_[iter.hashIndex_] = iter.elmtPtr_->next_;
delete it.elmtPtr_; delete iter.elmtPtr_;
// Search back for previous non-zero table entry // assign an non-NULL value so it doesn't look like end()/cend()
while (--it.hashIndex_ >= 0 && !table_[it.hashIndex_]) iter.elmtPtr_ = reinterpret_cast<hashedEntry*>(this);
{}
if (it.hashIndex_ >= 0) // mark with special hashIndex value
{ // to signal that it has been rewound
// In table entry search for last element // the next increment will bring it bach to the present location
it.elmtPtr_ = table_[it.hashIndex_]; iter.hashIndex_ = -iter.hashIndex_ - 1;
while (it.elmtPtr_ && it.elmtPtr_->next_)
{
it.elmtPtr_ = it.elmtPtr_->next_;
}
}
else
{
// No previous found. Mark with special value which is
// - not end()/cend()
// - handled by operator++
it.elmtPtr_ = reinterpret_cast<hashedEntry*>(this);
it.hashIndex_ = -1;
}
} }
nElmts_--; nElmts_--;
@ -402,8 +388,8 @@ bool Foam::HashTbl<T, Key, Hash>::erase(const iterator& cit)
# ifdef FULLDEBUG # ifdef FULLDEBUG
if (debug) if (debug)
{ {
Info<< "HashTbl<T, Key, Hash>::erase(iterator&) : " Info<< "HashTbl<T, Key, Hash>::erase(const iterator&) : "
<< "hashedEntry " << it.elmtPtr_->key_ << " removed.\n"; << "hashedEntry " << iter.elmtPtr_->key_ << " removed.\n";
} }
# endif # endif

View File

@ -178,6 +178,9 @@ public:
// Access // Access
//- The size of the underlying table
inline label capacity() const;
//- Return number of elements in table. //- Return number of elements in table.
inline label size() const; inline label size() const;

View File

@ -55,6 +55,13 @@ Foam::HashTbl<T, Key, Hash>::hashKeyIndex(const Key& key) const
// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * // // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
template<class T, class Key, class Hash>
inline Foam::label Foam::HashTbl<T, Key, Hash>::capacity() const
{
return tableSize_;
}
template<class T, class Key, class Hash> template<class T, class Key, class Hash>
inline Foam::label Foam::HashTbl<T, Key, Hash>::size() const inline Foam::label Foam::HashTbl<T, Key, Hash>::size() const
{ {
@ -256,15 +263,16 @@ inline
typename Foam::HashTbl<T, Key, Hash>::iterator& typename Foam::HashTbl<T, Key, Hash>::iterator&
Foam::HashTbl<T, Key, Hash>::iterator::operator++() Foam::HashTbl<T, Key, Hash>::iterator::operator++()
{ {
// Check for special value from erase. (sets hashIndex to -1) // Check for special value (from erase) - this indicates the previous bin
if (hashIndex_ >= 0) if (hashIndex_ < 0)
{
hashIndex_ = -hashIndex_;
}
else if (elmtPtr_ && elmtPtr_->next_)
{ {
// Do we have additional elements on the SLList? // Do we have additional elements on the SLList?
if (elmtPtr_ && elmtPtr_->next_) elmtPtr_ = elmtPtr_->next_;
{ return *this;
elmtPtr_ = elmtPtr_->next_;
return *this;
}
} }
// Step to the next table entry // Step to the next table entry
@ -275,9 +283,9 @@ Foam::HashTbl<T, Key, Hash>::iterator::operator++()
) )
{} {}
if (hashIndex_ == hashTable_.tableSize_) if (hashIndex_ >= hashTable_.tableSize_)
{ {
// make end iterator // make an end iterator
elmtPtr_ = 0; elmtPtr_ = 0;
hashIndex_ = 0; hashIndex_ = 0;
} }