ENH: added HashTable 'lookup' and 'retain' methods

- lookup(): with a default value (const access)
  For example,
      Map<label> something;
      value = something.lookup(key, -1);

    being equivalent to the following:

      Map<label> something;
      value = -1;  // bad value
      if (something.found(key))
      {
          value = something[key];
      }

    except that lookup also makes it convenient to handle const references.
    Eg,

      const labelList& ids = someHash.lookup(key, labelList());

- For consistency, provide a two parameter HashTable '()' operator.
  The lookup() method is, however, normally preferable when
  const-only access is to be ensured.

- retain(): the counterpart to erase(), it only retains entries
  corresponding to the listed keys.

  For example,
      HashTable<someType> largeCache;
      wordHashSet preserve = ...;

      largeCache.retain(preserve);

    being roughly equivalent to the following two-stage process,
    but with reduced overhead and typing, and fewer potential mistakes.

      HashTable<someType> largeCache;
      wordHashSet preserve = ...;

      {
          wordHashSet cull(largeCache.toc()); // all keys
          cull.erase(preserve);               // except those to preserve
          largeCache.erase(cull);             //
      }

  The HashSet &= operator and retain() are functionally equivalent,
  but retain() also works with dissimilar value types.
This commit is contained in:
Mark Olesen
2017-05-11 12:25:35 +02:00
parent 8728e8353f
commit f73b5b629f
10 changed files with 168 additions and 64 deletions

View File

@ -257,7 +257,7 @@ template<class T, class Key, class Hash>
bool Foam::HashTable<T, Key, Hash>::set
(
const Key& key,
const T& newEntry,
const T& obj,
const bool protect
)
{
@ -284,7 +284,7 @@ bool Foam::HashTable<T, Key, Hash>::set
if (!existing)
{
// Not found, insert it at the head
table_[hashIdx] = new hashedEntry(key, newEntry, table_[hashIdx]);
table_[hashIdx] = new hashedEntry(key, obj, table_[hashIdx]);
nElmts_++;
if (double(nElmts_)/tableSize_ > 0.8 && tableSize_ < maxTableSize)
@ -316,7 +316,7 @@ bool Foam::HashTable<T, Key, Hash>::set
{
// Found - overwrite existing entry
// this corresponds to the Perl convention
hashedEntry* ep = new hashedEntry(key, newEntry, existing->next_);
hashedEntry* ep = new hashedEntry(key, obj, existing->next_);
// Replace existing element - within list or insert at the head
if (prev)
@ -450,15 +450,15 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
const HashTable<AnyType, Key, AnyHash>& other
)
{
// Remove other keys from this table
const label nTotal = this->size();
label changed = 0;
if (other.size() < nTotal)
using other_iter =
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
if (other.size() <= nTotal)
{
// other is smaller, use its keys for removal
using other_iter =
typename HashTable<AnyType, Key, AnyHash>::const_iterator;
// The other is smaller/same-size, use its keys for removal
for
(
@ -475,7 +475,7 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
}
else
{
// other is same/larger: iterate ourselves and check for key in other
// We are smaller: remove if found in the other hash
for
(
iterator iter = begin();
@ -494,6 +494,39 @@ Foam::label Foam::HashTable<T, Key, Hash>::erase
}
template<class T, class Key, class Hash>
template<class AnyType, class AnyHash>
Foam::label Foam::HashTable<T, Key, Hash>::retain
(
const HashTable<AnyType, Key, AnyHash>& other
)
{
const label nTotal = this->size();
label changed = 0;
if (other.empty())
{
// Trivial case
changed = nTotal;
this->clear();
}
else
{
// Inverted logic: remove if *not* found in the other hash
for (iterator iter = begin(); iter != end(); ++iter)
{
if (!other.found(iter.key()) && erase(iter))
{
++changed;
}
}
}
return changed;
}
template<class T, class Key, class Hash>
void Foam::HashTable<T, Key, Hash>::resize(const label sz)
{