diff --git a/applications/test/HashTable/Test-hashTable.C b/applications/test/HashTable/Test-hashTable.C index 8352a88ae0..5dd3ca0fa4 100644 --- a/applications/test/HashTable/Test-hashTable.C +++ b/applications/test/HashTable/Test-hashTable.C @@ -234,6 +234,97 @@ int main() Info<<"\ntable1: " << table1 << endl; + // Start again + HashTable table1start + { + {"aaa", 1.0}, + {"aba", 2.0}, + {"a_ca", 3.0}, + {"ada", 4.0}, + {"aeq_", 5.0}, + {"aaw", 6.0}, + {"abs", 7.0}, + {"a_cr", 8.0}, + {"adx", 9.0}, + {"ae_c", 10.0} + }; + + table1 = table1start; + Info<< "\ntable has keys: " + << flatOutput(table1.sortedToc()) << nl; + + wordRe matcher(".*_.*", wordRe::REGEX); + table1.filterKeys + ( + [&matcher](const word& k){ return matcher.match(k); } + ); + Info<< "retain things matching " << matcher << " => " + << flatOutput(table1.sortedToc()) << nl; + + table1 = table1start; + table1.filterKeys + ( + [&matcher](const word& k){ return matcher.match(k); }, + true + ); + + Info<< "prune things matching " << matcher << " => " + << flatOutput(table1.sortedToc()) << nl; + + // Same, without a lambda + table1 = table1start; + table1.filterKeys(matcher, true); + + Info<< "prune things matching " << matcher << " => " + << flatOutput(table1.sortedToc()) << nl; + + + // Same idea, but inverted logic inside the lambda + table1 = table1start; + table1.filterKeys + ( + [&matcher](const word& k){ return !matcher.match(k); }, + true + ); + + Info<< "prune things matching " << matcher << " => " + << flatOutput(table1.sortedToc()) << nl; + + + table1 = table1start; + Info<< "\ntable:" << table1 << nl; + + table1.filterValues + ( + [](const scalar& v){ return (v >= 5); } + ); + + Info<< "\ntable with values >= 5:" << table1 << nl; + + table1 = table1start; + Info<< "\ntable:" << table1 << nl; + + table1.filterEntries + ( + [&matcher](const word& k, const scalar& v) + { + return matcher(k) && (v >= 5); + } + ); + + Info<< "\ntable with values >= 5 and matching " << matcher + << table1 << nl; + + + table1 = table1start; + Info<< "\ntable:" << table1 << nl; + Info<< "has " + << table1.countValues([](const scalar& v) { return v >= 7; }) + << " values >= 7 with these keys: " + << table1.tocValues([](const scalar& v) { return v >= 7; }) + << nl; + + Info<< "\nDone\n"; return 0; diff --git a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C index 77ab200a42..5b1f45b839 100644 --- a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C +++ b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C @@ -158,6 +158,20 @@ Foam::label Foam::HashSet::insert(std::initializer_list lst) // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // +template +inline bool Foam::HashSet::operator()(const Key& key) const +{ + return this->found(key); +} + + +template +inline bool Foam::HashSet::operator[](const Key& key) const +{ + return this->found(key); +} + + template void Foam::HashSet::operator=(const UList& lst) { @@ -180,12 +194,6 @@ void Foam::HashSet::operator=(std::initializer_list lst) } -template -inline bool Foam::HashSet::operator[](const Key& key) const -{ - return this->found(key); -} - template bool Foam::HashSet::operator==(const HashSet& rhs) const diff --git a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H index d6171ad585..fe82253bc0 100644 --- a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H +++ b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H @@ -156,22 +156,24 @@ public: // Edit //- Insert a new entry + // \return True if the entry inserted, which means that it did + // not previously exist in the set. bool insert(const Key& key) { return this->parent_type::insert(key, nil()); } //- Insert keys from the list of Key - // Return the number of new elements inserted + // \return The number of new elements inserted label insert(const UList& lst); //- Insert keys from the list of Key - // Return the number of new elements inserted + // \return The number of new elements inserted template label insert(const FixedList& lst); //- Insert keys from a initializer list of Key - // Return the number of new elements inserted + // \return The number of new elements inserted label insert(std::initializer_list lst); //- Same as insert (cannot overwrite nil content) @@ -200,18 +202,21 @@ public: } //- Unset the specified key - same as erase + // \return True if the entry existed and was removed bool unset(const Key& key) { return this->parent_type::erase(key); } //- Unset the listed keys - same as erase + // \return The number of items removed label unset(const UList& lst) { return this->parent_type::erase(lst); } //- Unset the listed keys - same as erase + // \return The number of items removed template label unset(const FixedList& lst) { @@ -219,11 +224,36 @@ public: } //- Unset the listed keys - same as erase + // \return The number of items removed label unset(std::initializer_list lst) { return this->parent_type::erase(lst); } + //- Not applicable for HashSet + template + List tocValues(const UnaryPredicate&, const bool) = delete; + + //- Not applicable for HashSet + template + List tocEntries(const BinaryPredicate&, const bool) = delete; + + //- Not applicable for HashSet + template + label countValues(const UnaryPredicate&, const bool) = delete; + + //- Not applicable for HashSet + template + label countEntries(const BinaryPredicate&, const bool) = delete; + + //- Not applicable for HashSet + template + label filterValues(const UnaryPredicate&, const bool) = delete; + + //- Not applicable for HashSet + template + label filterEntries(const BinaryPredicate&, const bool) = delete; + // STL iterators @@ -248,12 +278,15 @@ public: // Member Operators - //- This operation doesn't make much sense for a hash-set - void operator()(const Key& key) = delete; - //- Return true if the entry exists, same as found() + inline bool operator()(const Key& key) const; + + //- Return true if the entry exists, same as found(). inline bool operator[](const Key& key) const; + + // Comparison + //- Equality. Two hashset are equal when they have the same keys. // Independent of table size or order. bool operator==(const this_type& rhs) const; @@ -262,6 +295,8 @@ public: bool operator!=(const this_type& rhs) const; + // Assignment + //- Assignment from a UList of keys void operator=(const UList& lst); @@ -273,6 +308,8 @@ public: void operator=(std::initializer_list lst); + // Logical operations + //- Combine entries from HashSets void operator|=(const HashSet& rhs); diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C index 276f617dba..2c8167adce 100644 --- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C @@ -231,25 +231,169 @@ Foam::HashTable::find template Foam::List Foam::HashTable::toc() const { - List keys(nElmts_); - label keyI = 0; + List keyLst(nElmts_); + label count = 0; for (const_iterator iter = cbegin(); iter != cend(); ++iter) { - keys[keyI++] = iter.key(); + keyLst[count++] = iter.key(); } - return keys; + return keyLst; } template Foam::List Foam::HashTable::sortedToc() const { - List sortedLst = this->toc(); - sort(sortedLst); + List keyLst = this->toc(); + Foam::sort(keyLst); - return sortedLst; + return keyLst; +} + + +template +template +Foam::List Foam::HashTable::tocKeys +( + const UnaryPredicate& pred, + const bool invert +) const +{ + List keyLst(nElmts_); + label count = 0; + + for (const_iterator iter = cbegin(); iter != cend(); ++iter) + { + if ((pred(iter.key()) ? !invert : invert)) + { + keyLst[count++] = iter.key(); + } + } + + keyLst.setSize(count); + Foam::sort(keyLst); + + return keyLst; +} + + +template +template +Foam::List Foam::HashTable::tocValues +( + const UnaryPredicate& pred, + const bool invert +) const +{ + List keyLst(nElmts_); + label count = 0; + + for (const_iterator iter = cbegin(); iter != cend(); ++iter) + { + if ((pred(iter.object()) ? !invert : invert)) + { + keyLst[count++] = iter.key(); + } + } + + keyLst.setSize(count); + Foam::sort(keyLst); + + return keyLst; +} + + +template +template +Foam::List Foam::HashTable::tocEntries +( + const BinaryPredicate& pred, + const bool invert +) const +{ + List keyLst(nElmts_); + label count = 0; + + for (const_iterator iter = cbegin(); iter != cend(); ++iter) + { + if ((pred(iter.key(), iter.object()) ? !invert : invert)) + { + keyLst[count++] = iter.key(); + } + } + + keyLst.setSize(count); + Foam::sort(keyLst); + + return keyLst; +} + + +template +template +Foam::label Foam::HashTable::countKeys +( + const UnaryPredicate& pred, + const bool invert +) const +{ + label count = 0; + + for (const_iterator iter = cbegin(); iter != cend(); ++iter) + { + if ((pred(iter.key()) ? !invert : invert)) + { + ++count; + } + } + + return count; +} + + +template +template +Foam::label Foam::HashTable::countValues +( + const UnaryPredicate& pred, + const bool invert +) const +{ + label count = 0; + + for (const_iterator iter = cbegin(); iter != cend(); ++iter) + { + if ((pred(iter.object()) ? !invert : invert)) + { + ++count; + } + } + + return count; +} + + +template +template +Foam::label Foam::HashTable::countEntries +( + const BinaryPredicate& pred, + const bool invert +) const +{ + label count = 0; + + for (const_iterator iter = cbegin(); iter != cend(); ++iter) + { + if ((pred(iter.key(), iter.object()) ? !invert : invert)) + { + ++count; + } + } + + return count; } @@ -617,6 +761,87 @@ void Foam::HashTable::transfer(HashTable& ht) } +template +template +Foam::label Foam::HashTable::filterKeys +( + const UnaryPredicate& pred, + const bool pruning +) +{ + label changed = 0; + + for (iterator iter = begin(); iter != end(); ++iter) + { + // Matches? either prune (pruning) or keep (!pruning) + if + ( + (pred(iter.key()) ? pruning : !pruning) + && erase(iter) + ) + { + ++changed; + } + } + + return changed; +} + + +template +template +Foam::label Foam::HashTable::filterValues +( + const UnaryPredicate& pred, + const bool pruning +) +{ + label changed = 0; + + for (iterator iter = begin(); iter != end(); ++iter) + { + // Matches? either prune (pruning) or keep (!pruning) + if + ( + (pred(iter.object()) ? pruning : !pruning) + && erase(iter) + ) + { + ++changed; + } + } + + return changed; +} + + +template +template +Foam::label Foam::HashTable::filterEntries +( + const BinaryPredicate& pred, + const bool pruning +) +{ + label changed = 0; + + for (iterator iter = begin(); iter != end(); ++iter) + { + // Matches? either prune (pruning) or keep (!pruning) + if + ( + (pred(iter.key(), iter.object()) ? pruning : !pruning) + && erase(iter) + ) + { + ++changed; + } + } + + return changed; +} + + // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * // template diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H index 9eef011d10..3b3338084d 100644 --- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H @@ -255,7 +255,7 @@ private: inline label hashKeyIndex(const Key& key) const; //- Assign a new hash-entry to a possibly already existing key. - // Return true if the new entry was set. + // \return True if the new entry was set. bool set(const Key& key, const T& obj, const bool protect); @@ -330,22 +330,83 @@ public: //- Return hashed entry if it exists, or return the given default inline const T& lookup(const Key& key, const T& deflt) const; + + // Table of contents + //- Return the table of contents List toc() const; //- Return the table of contents as a sorted list List sortedToc() const; + //- Return the sorted table of contents with keys that satisfy + // the unary predicate, optionally with inverted logic. + template + List tocKeys + ( + const UnaryPredicate& pred, + const bool invert = false + ) const; + + //- Return the sorted table of contents with values that satisfy + // the unary predicate, optionally with inverted logic. + template + List tocValues + ( + const UnaryPredicate& pred, + const bool invert = false + ) const; + + //- Return the sorted table of contents with keys/values that satisfy + // the binary predicate, optionally with inverted logic. + template + List tocEntries + ( + const BinaryPredicate& pred, + const bool invert = false + ) const; + + + // Counting + + //- Count the number of keys that satisfy the unary predicate, + // optionally with inverted logic. + template + label countKeys + ( + const UnaryPredicate& pred, + const bool invert = false + ) const; + + //- Count the number of values that satisfy the unary predicate, + // optionally with inverted logic. + template + label countValues + ( + const UnaryPredicate& pred, + const bool invert = false + ) const; + + //- Count the number of entries that satisfy the binary predicate, + // optionally with inverted logic. + template + label countEntries + ( + const BinaryPredicate& pred, + const bool invert = false + ) const; + // Edit //- Insert a new entry - // Return true if the entry inserted, which means that it did + // \return True if the entry inserted, which means that it did // not previously exist in the table. inline bool insert(const Key& key, const T& obj); //- Assign a new entry, overwriting existing entries. - // Returns true. + // + // \return True, since it always overwrites any entries. inline bool set(const Key& key, const T& obj); //- Erase an entry specified by given iterator @@ -357,30 +418,34 @@ public: // auto iter = table.find(unknownKey); // table.erase(iter); // \endcode - // which is what \code table.erase(unknownKey) \endcode does anyhow + // which is what \code table.erase(unknownKey) \endcode does anyhow. + // + // \return True if the corresponding entry existed and was removed bool erase(const iterator& iter); //- Erase an entry specified by the given key + // \return True if the entry existed and was removed bool erase(const Key& key); //- Remove table entries given by the listed keys - // Return the number of elements removed + // \return The number of items removed label erase(const UList& keys); //- Remove table entries given by the listed keys - // Return the number of elements removed + // \return The number of items removed template label erase(const FixedList& keys); //- Remove table entries given by the listed keys - // Return the number of elements removed + // \return The number of items removed label erase(std::initializer_list keys); //- Remove table entries given by keys of the other hash-table. - // Return the number of elements removed. // // The other hash-table must have the same type of key, but the // type of values held and the hashing function are arbitrary. + // + // \return The number of items removed template label erase(const HashTable& other); @@ -388,9 +453,66 @@ public: // // The other hash-table must have the same type of key, but the // type of values held and the hashing function are arbitrary. + // + // \return The number of items changed (removed) template label retain(const HashTable& other); + //- Generalized means to filter table entries based on their keys. + // Keep (or optionally prune) entries with keys that satisfy + // the unary predicate, which has the following signature: + // \code + // bool operator()(const Key& k); + // \endcode + // + // For example, + // \code + // wordRes goodFields = ...; + // allFieldNames.filterKeys + // ( + // [&goodFields](const word& k){ return goodFields.match(k); } + // ); + // \endcode + // + // \return The number of items changed (removed) + template + label filterKeys + ( + const UnaryPredicate& pred, + const bool pruning = false + ); + + //- Generalized means to filter table entries based on their values. + // Keep (or optionally prune) entries with values that satisfy + // the unary predicate, which has the following signature: + // \code + // bool operator()(const T& v); + // \endcode + // + // \return The number of items changed (removed) + template + label filterValues + ( + const UnaryPredicate& pred, + const bool pruning = false + ); + + //- Generalized means to filter table entries based on their key/value. + // Keep (or optionally prune) entries with keys/values that satisfy + // the binary predicate, which has the following signature: + // \code + // bool operator()(const Key& k, const T& v); + // \endcode + // + // \return The number of items changed (removed) + template + label filterEntries + ( + const BinaryPredicate& pred, + const bool pruning = false + ); + + //- Resize the hash table for efficiency void resize(const label sz); diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C index e57192f1e3..9a8b205b9e 100644 --- a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C @@ -46,26 +46,26 @@ Foam::label Foam::HashTableCore::canonicalSize(const label requested_size) { return 0; } + else if (requested_size >= maxTableSize) + { + return maxTableSize; + } - // Enforce power of two - makes for a vey fast modulus etc. + // Enforce power of two - makes for a very fast modulus. // Use unsigned for these calculations. // // - The lower limit (8) is somewhat arbitrary, but if the hash table // is too small, there will be many direct table collisions. - // - The uper limit (approx. labelMax/4) must be a power of two, + // - The upper limit (approx. labelMax/4) must be a power of two, // need not be extremely large for hashing. uLabel powerOfTwo = 8; // lower-limit const uLabel size = requested_size; - if (size < powerOfTwo) + if (size <= powerOfTwo) { return powerOfTwo; } - else if (requested_size >= maxTableSize) - { - return maxTableSize; - } else if (size & (size-1)) // <- Modulus of i^2 { // Determine power-of-two. Brute-force is fast enough. diff --git a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C index 31c02ebf5e..6ce8fc31ba 100644 --- a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C +++ b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C @@ -46,26 +46,26 @@ Foam::label Foam::StaticHashTableCore::canonicalSize(const label requested_size) { return 0; } + else if (requested_size >= maxTableSize) + { + return maxTableSize; + } - // Enforce power of two - makes for a vey fast modulus etc. + // Enforce power of two - makes for a very fast modulus. // Use unsigned for these calculations. // // - The lower limit (8) is somewhat arbitrary, but if the hash table // is too small, there will be many direct table collisions. - // - The uper limit (approx. labelMax/4) must be a power of two, + // - The upper limit (approx. labelMax/4) must be a power of two, // need not be extremely large for hashing. uLabel powerOfTwo = 8; // lower-limit const uLabel size = requested_size; - if (size < powerOfTwo) + if (size <= powerOfTwo) { return powerOfTwo; } - else if (requested_size >= maxTableSize) - { - return maxTableSize; - } else if (size & (size-1)) // <- Modulus of i^2 { // Determine power-of-two. Brute-force is fast enough. diff --git a/src/OpenFOAM/primitives/strings/wordRes/wordRes.H b/src/OpenFOAM/primitives/strings/wordRes/wordRes.H index 7a62d9d101..5cfe6b9b57 100644 --- a/src/OpenFOAM/primitives/strings/wordRes/wordRes.H +++ b/src/OpenFOAM/primitives/strings/wordRes/wordRes.H @@ -69,7 +69,7 @@ public: // Constructors //- Construct from a list of wordRe - inline wordRes(const UList& lst); + inline wordRes(const UList& list); // Static Constructors, Helpers