Commit 2c73afb6 authored by Mark Olesen's avatar Mark Olesen
Browse files

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
...
parent 55a89e9d
......@@ -56,15 +56,16 @@ int main(int argc, char *argv[])
HashTbl<label, label, Hash<label> > map(2 * nSize);
Info<< "Constructed map of size: " << nSize
<< " (size " << map.size() << " capacity " << map.capacity() << ") "
<< " " << timer.cpuTimeIncrement() << " s\n\n";
for (label i = 0; i < nSize; i++)
{
map.insert(i, i);
}
Info<< "Inserted " << nSize << " elements: "
<< timer.cpuTimeIncrement() << " s\n\n";
Info<< "Inserted " << nSize << " elements"
<< " (size " << map.size() << " capacity " << map.capacity() << ") "
<< timer.cpuTimeIncrement() << " s\n";
label elemI = 0;
for (label iLoop = 0; iLoop < nLoops; iLoop++)
......@@ -73,8 +74,9 @@ int main(int argc, char *argv[])
{
map.erase(elemI++);
}
Info<< "loop " << iLoop << " - Erased " << nBase << " elements: "
<< " " << timer.cpuTimeIncrement() << " s\n";
Info<< "loop " << iLoop << " - Erased " << nBase << " elements"
<< " (size " << map.size() << " capacity " << map.capacity() << ") "
<< timer.cpuTimeIncrement() << " s\n";
}
return 0;
......
......@@ -346,55 +346,41 @@ bool Foam::HashTbl<T, Key, Hash>::erase(const iterator& cit)
{
if (cit.elmtPtr_) // note: endIter_ also has 0 elmtPtr_
{
iterator& it = const_cast<iterator&>(cit);
// Search element before elmtPtr_
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;
}
prev = ep;
}
// adjust iterator after erase
iterator& iter = const_cast<iterator&>(cit);
if (prev)
{
// Have element before elmtPtr
prev->next_ = it.elmtPtr_->next_;
delete it.elmtPtr_;
it.elmtPtr_ = prev;
// has an element before elmtPtr - reposition to there
prev->next_ = iter.elmtPtr_->next_;
delete iter.elmtPtr_;
iter.elmtPtr_ = prev;
}
else
{
// elmtPtr is first element on SLList
table_[it.hashIndex_] = it.elmtPtr_->next_;
delete it.elmtPtr_;
// elmtPtr was first element on SLList
table_[iter.hashIndex_] = iter.elmtPtr_->next_;
delete iter.elmtPtr_;
// Search back for previous non-zero table entry
while (--it.hashIndex_ >= 0 && !table_[it.hashIndex_])
{}
// assign an non-NULL value so it doesn't look like end()/cend()
iter.elmtPtr_ = reinterpret_cast<hashedEntry*>(this);
if (it.hashIndex_ >= 0)
{
// In table entry search for last element
it.elmtPtr_ = table_[it.hashIndex_];
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;
}
// mark with special hashIndex value
// to signal that it has been rewound
// the next increment will bring it bach to the present location
iter.hashIndex_ = -iter.hashIndex_ - 1;
}
nElmts_--;
......@@ -402,8 +388,8 @@ bool Foam::HashTbl<T, Key, Hash>::erase(const iterator& cit)
# ifdef FULLDEBUG
if (debug)
{
Info<< "HashTbl<T, Key, Hash>::erase(iterator&) : "
<< "hashedEntry " << it.elmtPtr_->key_ << " removed.\n";
Info<< "HashTbl<T, Key, Hash>::erase(const iterator&) : "
<< "hashedEntry " << iter.elmtPtr_->key_ << " removed.\n";
}
# endif
......
......@@ -178,6 +178,9 @@ public:
// Access
//- The size of the underlying table
inline label capacity() const;
//- Return number of elements in table.
inline label size() const;
......
......@@ -55,6 +55,13 @@ Foam::HashTbl<T, Key, Hash>::hashKeyIndex(const Key& key) const
// * * * * * * * * * * * * * * * 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>
inline Foam::label Foam::HashTbl<T, Key, Hash>::size() const
{
......@@ -256,15 +263,16 @@ inline
typename Foam::HashTbl<T, Key, Hash>::iterator&
Foam::HashTbl<T, Key, Hash>::iterator::operator++()
{
// Check for special value from erase. (sets hashIndex to -1)
if (hashIndex_ >= 0)
// Check for special value (from erase) - this indicates the previous bin
if (hashIndex_ < 0)
{
hashIndex_ = -hashIndex_;
}
else if (elmtPtr_ && elmtPtr_->next_)
{
// 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
......@@ -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;
hashIndex_ = 0;
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment