From 03d180724b67d82714b631d7ce03d8f3513aff0e Mon Sep 17 00:00:00 2001 From: Mark Olesen <Mark.Olesen@esi-group.com> Date: Thu, 4 May 2017 10:17:18 +0200 Subject: [PATCH] ENH: improve HashTable iterator access and management - provide key_iterator/const_key_iterator for all hashes, reuse directly for HashSet as iterator/const_iterator, respectively. - additional keys() method for HashTable that returns a wrapped to a pair of begin/end const_iterators with additional size/empty information that allows these to be used directly by anything else expecting things with begin/end/size. Unfortunately does not yet work with std::distance(). Example, for (auto& k : labelHashTable.keys()) { ... } --- applications/test/HashSet/Test-hashSet.C | 8 +- applications/test/HashTable/Test-hashTable.C | 18 +- applications/test/cplusplus1/Make/files | 3 + applications/test/cplusplus1/Make/options | 2 + applications/test/cplusplus1/Test-cpluplus1.C | 88 ++++ applications/test/pTraits/Test-pTraits.C | 23 +- .../containers/HashTables/HashSet/HashSet.C | 34 +- .../containers/HashTables/HashSet/HashSet.H | 95 ++-- .../HashTables/HashTable/HashTable.C | 10 +- .../HashTables/HashTable/HashTable.H | 413 +++++++++++------- .../HashTables/HashTable/HashTableCore.C | 53 ++- .../HashTables/HashTable/HashTableCoreI.H | 146 +++++++ .../HashTables/HashTable/HashTableI.H | 82 ++-- .../HashTables/HashTable/HashTableIO.C | 4 +- .../StaticHashTable/StaticHashTable.H | 4 +- .../StaticHashTable/StaticHashTableCore.C | 30 +- 16 files changed, 706 insertions(+), 307 deletions(-) create mode 100644 applications/test/cplusplus1/Make/files create mode 100644 applications/test/cplusplus1/Make/options create mode 100644 applications/test/cplusplus1/Test-cpluplus1.C create mode 100644 src/OpenFOAM/containers/HashTables/HashTable/HashTableCoreI.H diff --git a/applications/test/HashSet/Test-hashSet.C b/applications/test/HashSet/Test-hashSet.C index fdfecaa08c6..0b219f2e3d1 100644 --- a/applications/test/HashSet/Test-hashSet.C +++ b/applications/test/HashSet/Test-hashSet.C @@ -69,6 +69,12 @@ int main(int argc, char *argv[]) Info<< "tableA keys: "; tableA.writeKeys(Info) << endl; + auto keyIterPair = tableA.keys(); + for (const auto& i : keyIterPair) + { + Info<<" keys: " << i << endl; + } + Map<label> mapA { { 1, 1 }, @@ -193,7 +199,7 @@ int main(int argc, char *argv[]) Info<< "setD : " << flatOutput(setD) << endl; - // this doesn't work (yet?) + // This should not work (yet?) // setD[12] = true; List<label> someLst(10); diff --git a/applications/test/HashTable/Test-hashTable.C b/applications/test/HashTable/Test-hashTable.C index ad43b6ed9bd..31bff05b0f8 100644 --- a/applications/test/HashTable/Test-hashTable.C +++ b/applications/test/HashTable/Test-hashTable.C @@ -24,6 +24,7 @@ License \*---------------------------------------------------------------------------*/ #include "HashTable.H" +#include "List.H" #include "IOstreams.H" #include "IStringStream.H" #include "OStringStream.H" @@ -177,12 +178,23 @@ int main() Info<< "\ntable1" << table1 << nl; - Info<< "\nrange-for(table1)" << nl; - for (auto const& it : table1) + Info<< "\nrange-for(table1) - returns values" << nl; + for (const auto& it : table1) { - Info<< " " << it << nl; + Info<< "val:" << it << nl; } + Info<< "\nrange-for(table1.keys()) - returns keys" << nl; + for (const auto& k : table1.keys()) + { + Info<< "key:" << k << nl; + } + + // These do not yet work. Issues resolving the distance. + // + // List<scalar> table1vals(table1.begin(), table1.end()); + // wordList table1keys(table1.begin(), table1.end()); + Info<< "\nDone\n"; return 0; diff --git a/applications/test/cplusplus1/Make/files b/applications/test/cplusplus1/Make/files new file mode 100644 index 00000000000..8beb3b204c5 --- /dev/null +++ b/applications/test/cplusplus1/Make/files @@ -0,0 +1,3 @@ +Test-cpluplus1.C + +EXE = $(FOAM_USER_APPBIN)/Test-cpluplus1 diff --git a/applications/test/cplusplus1/Make/options b/applications/test/cplusplus1/Make/options new file mode 100644 index 00000000000..6a9e9810b3d --- /dev/null +++ b/applications/test/cplusplus1/Make/options @@ -0,0 +1,2 @@ +/* EXE_INC = -I$(LIB_SRC)/cfdTools/include */ +/* EXE_LIBS = -lfiniteVolume */ diff --git a/applications/test/cplusplus1/Test-cpluplus1.C b/applications/test/cplusplus1/Test-cpluplus1.C new file mode 100644 index 00000000000..b288e9286cc --- /dev/null +++ b/applications/test/cplusplus1/Test-cpluplus1.C @@ -0,0 +1,88 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2017 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +Description + Test miscellaneous C++ templates/functionality. + +\*---------------------------------------------------------------------------*/ + +#include "string.H" +#include "IOstreams.H" +#include "UList.H" +#include "HashSet.H" + +#include <typeinfo> +#include <type_traits> +#include <utility> + +using namespace Foam; + +// Macros to stringify macro contents. +#define STRINGIFY(content) #content +#define STRING_QUOTE(input) STRINGIFY(input) + +#define PRINT_TYPEID(arg) \ + Info<< typeid(arg).name() << " <= typeid of " << STRING_QUOTE(arg) << nl + + + +// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +// Main program: + +int main(int argc, char *argv[]) +{ + Info<< "various declaration types" << nl << nl; + + PRINT_TYPEID(label); + PRINT_TYPEID(decltype(UList<label>::value_type())); + PRINT_TYPEID(decltype(std::declval<UList<label>>().cbegin())); + PRINT_TYPEID(decltype(*(std::declval<UList<label>>().cbegin()))); + Info<< nl; + + PRINT_TYPEID(decltype(HashTable<label>::key_type())); + PRINT_TYPEID(decltype(HashTable<label>::value_type())); + // Not yet: PRINT_TYPEID(decltype(HashTable<label>::mapped_type())); + PRINT_TYPEID(decltype(std::declval<HashTable<label>>().begin())); + PRINT_TYPEID(decltype(std::declval<const HashTable<label>>().begin())); + PRINT_TYPEID(decltype(*(std::declval<HashTable<label>>().begin()))); + PRINT_TYPEID(decltype(*(std::declval<const HashTable<label>>().begin()))); + + PRINT_TYPEID(decltype(std::declval<const HashTable<label>>().keys())); + Info<< nl; + + PRINT_TYPEID(decltype(HashSet<label>::key_type())); + PRINT_TYPEID(decltype(HashSet<label>::value_type())); + // Not yet: PRINT_TYPEID(decltype(HashSet<label>::mapped_type())); + PRINT_TYPEID(decltype(std::declval<HashSet<label>>().begin())); + PRINT_TYPEID(decltype(std::declval<const HashSet<label>>().begin())); + PRINT_TYPEID(decltype(*(std::declval<HashSet<label>>().begin()))); + PRINT_TYPEID(decltype(*(std::declval<const HashSet<label>>().begin()))); + Info<< nl; + + Info << "\nEnd\n" << endl; + + return 0; +} + + +// ************************************************************************* // diff --git a/applications/test/pTraits/Test-pTraits.C b/applications/test/pTraits/Test-pTraits.C index a914911d293..d300ddc87a5 100644 --- a/applications/test/pTraits/Test-pTraits.C +++ b/applications/test/pTraits/Test-pTraits.C @@ -29,6 +29,9 @@ Description #include "pTraits.H" #include "vector.H" #include "tensor.H" +#include "uLabel.H" + +#include <type_traits> using namespace Foam; @@ -40,7 +43,10 @@ void printTraits() { Info<< pTraits<T>::typeName << ": zero=" << pTraits<T>::zero - << " one=" << pTraits<T>::one << endl; + << " one=" << pTraits<T>::one + << " integral=" << std::is_integral<T>::value + << " floating=" << std::is_floating_point<T>::value + << endl; } @@ -80,6 +86,21 @@ int main() label def = label(); Info<< "intialized primitive:"<< def << endl; + Info<< nl << "some interesting label limits:" << nl; + std::cout<< "sizeof = " << sizeof(label) << nl; + std::cout<< "min = " << pTraits<label>::min << nl; + std::cout<< "max = " << pTraits<label>::max << nl; + std::cout<< "umax = " << pTraits<uLabel>::max << nl; + + std::cout<< "max_2 = " << pTraits<label>::max/2 << " == " + << (1 << (sizeof(label)*8-2)) << nl; + + std::cout<< "max_4 = " << pTraits<label>::max/4 << " == " + << (1 << (sizeof(label)*8-3)) << nl; + + std::cout<< "max_8 = " << pTraits<label>::max/8 << " == " + << (1 << (sizeof(label)*8-4)) << nl; + Info<< "End\n" << endl; return 0; diff --git a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C index 5c1b5798299..321b8dd5dfe 100644 --- a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C +++ b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.C @@ -140,6 +140,7 @@ Foam::label Foam::HashSet<Key, Hash>::insert(const UList<Key>& lst) return insertMultiple(lst.begin(), lst.end()); } + template<class Key, class Hash> template<unsigned Size> Foam::label Foam::HashSet<Key, Hash>::insert(const FixedList<Key, Size>& lst) @@ -147,6 +148,7 @@ Foam::label Foam::HashSet<Key, Hash>::insert(const FixedList<Key, Size>& lst) return insertMultiple(lst.begin(), lst.end()); } + template<class Key, class Hash> Foam::label Foam::HashSet<Key, Hash>::insert(std::initializer_list<Key> lst) { @@ -209,7 +211,7 @@ bool Foam::HashSet<Key, Hash>::operator==(const HashSet<Key, Hash>& rhs) const template<class Key, class Hash> bool Foam::HashSet<Key, Hash>::operator!=(const HashSet<Key, Hash>& rhs) const { - return !(operator==(rhs)); + return !operator==(rhs); } @@ -319,51 +321,63 @@ Foam::operator^ return out; } + // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // template<class Key, class Hash> inline typename Foam::HashSet<Key, Hash>::iterator Foam::HashSet<Key, Hash>::begin() { - return iterator(this->ParentClass::begin()); + return HashTableCore::iterator_begin<iterator> + ( + static_cast<parent_type&>(*this) + ); } + template<class Key, class Hash> inline typename Foam::HashSet<Key, Hash>::const_iterator Foam::HashSet<Key, Hash>::begin() const { - return const_iterator(this->ParentClass::cbegin()); + return HashTableCore::iterator_begin<const_iterator> + ( + static_cast<const parent_type&>(*this) + ); } + template<class Key, class Hash> inline typename Foam::HashSet<Key, Hash>::const_iterator Foam::HashSet<Key, Hash>::cbegin() const { - return this->begin(); + return HashTableCore::iterator_begin<const_iterator> + ( + static_cast<const parent_type&>(*this) + ); } + template<class Key, class Hash> inline const typename Foam::HashSet<Key, Hash>::iterator& Foam::HashSet<Key, Hash>::end() { - using iter_type = typename HashSet<Key, Hash>::iterator; - return HashTableCore::endIteratorRef<iter_type>(); + return HashTableCore::iterator_end<iterator>(); } + template<class Key, class Hash> inline const typename Foam::HashSet<Key, Hash>::const_iterator& Foam::HashSet<Key, Hash>::end() const { - using iter_type = typename HashSet<Key, Hash>::const_iterator; - return HashTableCore::endIteratorRef<iter_type>(); + return HashTableCore::iterator_end<const_iterator>(); } + template<class Key, class Hash> inline const typename Foam::HashSet<Key, Hash>::const_iterator& Foam::HashSet<Key, Hash>::cend() const { - using iter_type = typename HashSet<Key, Hash>::const_iterator; - return HashTableCore::endIteratorRef<iter_type>(); + return HashTableCore::iterator_cend<const_iterator>(); } diff --git a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H index f7f780fe715..300fc111325 100644 --- a/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H +++ b/src/OpenFOAM/containers/HashTables/HashSet/HashSet.H @@ -68,8 +68,6 @@ class HashSet : public HashTable<nil, Key, Hash> { - typedef HashTable<nil, Key, Hash> ParentClass; - // Private Member Functions //- Insert values, using begin/end iterators. @@ -92,18 +90,31 @@ class HashSet public: + //- The template instance used for this HashSet + typedef HashSet<Key, Hash> this_type; + + //- The template instance used for the parent HashTable + typedef HashTable<nil, Key, Hash> parent_type; + + //- An iterator, returning reference to the key + using iterator = typename parent_type::key_iterator; + + //- A const_iterator, returning reference to the key + using const_iterator = typename parent_type::const_key_iterator; + + // Constructors //- Construct given initial size HashSet(const label size = 128) : - ParentClass(size) + parent_type(size) {} //- Construct from Istream HashSet(Istream& is) : - ParentClass(is) + parent_type(is) {} //- Construct from UList of Key @@ -119,19 +130,19 @@ public: //- Construct as copy HashSet(const HashSet<Key, Hash>& hs) : - ParentClass(hs) + parent_type(hs) {} //- Construct by transferring the parameter contents HashSet(const Xfer<HashSet<Key, Hash>>& hs) : - ParentClass(hs) + parent_type(hs) {} //- Construct by transferring the parameter contents HashSet(const Xfer<HashTable<nil, Key, Hash>>& hs) : - HashTable<nil, Key, Hash>(hs) + parent_type(hs) {} //- Construct from the keys of another HashTable, @@ -147,7 +158,7 @@ public: //- Insert a new entry bool insert(const Key& key) { - return this->ParentClass::insert(key, nil()); + return this->parent_type::insert(key, nil()); } //- Insert keys from the list of Key @@ -191,77 +202,38 @@ public: //- Unset the specified key - same as erase bool unset(const Key& key) { - return this->ParentClass::erase(key); + return this->parent_type::erase(key); } //- Unset the listed keys - same as erase label unset(const UList<Key>& lst) { - return this->ParentClass::erase(lst); + return this->parent_type::erase(lst); } //- Unset the listed keys - same as erase template<unsigned Size> label unset(const FixedList<Key, Size>& lst) { - return this->ParentClass::erase(lst); + return this->parent_type::erase(lst); } //- Unset the listed keys - same as erase label unset(std::initializer_list<Key> lst) { - return this->ParentClass::erase(lst); + return this->parent_type::erase(lst); } - // STL iterator + // STL iterators - //- An STL-conforming iterator - struct iterator - : - public ParentClass::iterator - { - using parent = typename ParentClass::iterator; - - //- Implicit conversion - iterator(const parent& iter) - : - parent(iter) - {} - - //- Return the key - auto operator*() const -> const Key& - { - return this->key(); - } - }; - - //- An STL-conforming const_iterator - struct const_iterator - : - public ParentClass::const_iterator - { - using parent = typename ParentClass::const_iterator; + iterator begin(); + const_iterator begin() const; + const_iterator cbegin() const; - //- Implicit conversion - const_iterator(const parent& iter) - : - parent(iter) - {} - - //- Return the key - auto operator*() const -> const Key& - { - return this->key(); - } - }; - - auto begin() -> iterator; - auto begin() const -> const_iterator; - auto cbegin() const -> const_iterator; - auto end() -> const iterator&; - auto end() const -> const const_iterator&; - auto cend() const -> const const_iterator&; + const iterator& end(); + const const_iterator& end() const; + const const_iterator& cend() const; // Writing @@ -276,15 +248,18 @@ 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; //- Equality. Two hashset are equal when they have the same keys. // Independent of table size or order. - bool operator==(const HashSet<Key, Hash>& rhs) const; + bool operator==(const this_type& rhs) const; //- The opposite of the equality operation. - bool operator!=(const HashSet<Key, Hash>& rhs) const; + bool operator!=(const this_type& rhs) const; //- Assignment from a UList of keys diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C index db3256bcb1c..6e7349d6fac 100644 --- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2016 OpenFOAM Foundation - \\/ M anipulation | + \\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -336,7 +336,7 @@ bool Foam::HashTable<T, Key, Hash>::set template<class T, class Key, class Hash> -bool Foam::HashTable<T, Key, Hash>::iteratorBase::erase() +bool Foam::HashTable<T, Key, Hash>::iterator_base::erase() { // Note: entryPtr_ is nullptr for end(), so this catches that too if (entryPtr_) @@ -515,7 +515,7 @@ void Foam::HashTable<T, Key, Hash>::resize(const label sz) for (const_iterator iter = cbegin(); iter != cend(); ++iter) { - tmpTable->insert(iter.key(), *iter); + tmpTable->insert(iter.key(), iter.object()); } const label oldSize = tableSize_; @@ -645,7 +645,7 @@ void Foam::HashTable<T, Key, Hash>::operator= clear(); } - for (const Tuple2<Key, T>& pair : lst) + for (const auto& pair : lst) { insert(pair.first(), pair.second()); } @@ -684,7 +684,7 @@ bool Foam::HashTable<T, Key, Hash>::operator!= const HashTable<T, Key, Hash>& rhs ) const { - return !(operator==(rhs)); + return !operator==(rhs); } diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H index adc3f0aa744..26a7460ee5a 100644 --- a/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTable.H @@ -34,6 +34,13 @@ Note often result in a different hash order. Use a sorted table-of-contents when the hash order is important. + The end iterator of all hash-tables has a nullptr to the hash entry. + Thus avoid separate allocation for each table and use a single one with + a nullptr. The hash-table iterators always have an entry-pointer as the + first member data, which allows reinterpret_cast from anything else with + a nullptr as its first data member. + The nullObject is such an item (with a nullptr data member). + SourceFiles HashTableI.H HashTable.C @@ -78,25 +85,15 @@ Ostream& operator<<(Ostream& os, const HashTable<T, Key, Hash>& tbl); Class HashTableCore Declaration \*---------------------------------------------------------------------------*/ -//- Template-invariant bits for HashTable. -// This also includes a global end-iterator. -// -// The end iterator of all hash-tables has a nullptr to the hash entry. -// Thus avoid separate allocation for each table and use a single one with -// a nullptr. -// The hash-table iterators always have this as its first member data, -// so we can reinterpret_cast from anything else that has a nullptr for its -// first data member. This is now also the case for the NullObject. -class HashTableCore +//- Bits that are independent of the HashTable template parameters. +struct HashTableCore { -public: - - //- Return a canonical (power-of-two) size - static label canonicalSize(const label size); - - //- Maximum allowable table size + //- Maximum allowable internal table size. Approximately labelMax/4 static const label maxTableSize; + //- Return a canonical (power-of-two) of the requested size. + static label canonicalSize(const label requested_size); + //- Construct null HashTableCore() {} @@ -104,21 +101,57 @@ public: //- Define template name and debug ClassName("HashTable"); - -protected: - static_assert ( sizeof(NullObject) >= sizeof(void*), "NullObject is too small to reinterpret_cast as HashTable::iterator" ); - //- Reinterpret a NullObject as a hash-table iterator. - template<class Iterator> - inline static const Iterator& endIteratorRef() + + //- Factory method to create a non-const iterator begin + template<class IteratorType, class TableType> + inline static IteratorType iterator_begin(TableType& table); + + //- Factory method to create a const iterator begin + template<class IteratorType, class TableType> + inline static IteratorType iterator_begin(const TableType& table); + + //- Factory method to create a const iterator begin + template<class IteratorType, class TableType> + inline static IteratorType iterator_cbegin(const TableType& table); + + //- Factory method to create a non-const iterator end + // Simply reinterprets a NullObject as a hash-table iterator. + template<class IteratorType> + inline static const IteratorType& iterator_end(); + + //- Factory method to create a const iterator cend + // Simply reinterprets a NullObject as a hash-table iterator. + template<class IteratorType> + inline static const IteratorType& iterator_cend(); + + + //- Factory class for creating a begin/end pair for any const iterator. + template<class IteratorType, class TableType> + class const_iterator_pair { - return *reinterpret_cast<const Iterator*>(nullObjectPtr); - } + label size_; + IteratorType iter_; + + public: + + inline const_iterator_pair(const TableType& tbl); + + inline label size() const; + inline bool empty() const; + + inline IteratorType begin() const; + inline IteratorType cbegin() const; + + inline const IteratorType& end() const; + inline const IteratorType& cend() const; + }; + }; @@ -131,6 +164,43 @@ class HashTable : public HashTableCore { +public: + + //- The template instance used for this HashTable + typedef HashTable<T, Key, Hash> this_type; + + + // STL type definitions + + //- Type of keys that the HashTable uses. + typedef Key key_type; + + //- Type of values that the HashTable contains. + typedef T value_type; + + //- The type used for storing into value_type objects. + // This type is usually value_type&. + typedef T& reference; + + //- The type used for reading from constant value_type objects. + typedef const T& const_reference; + + //- The type to represent the difference between two iterators + typedef label difference_type; + + //- The type that can represent the size of a HashTable. + typedef label size_type; + + + //- Forward iterator with non-const access + class iterator; + + //- Forward iterator with const access + class const_iterator; + + +private: + // Private data type for table entries //- Structure to hold a hashed entry, with a SLList for collisions @@ -148,7 +218,6 @@ class HashTable //- Construct from key, next pointer and object inline hashedEntry(const Key& key, const T& obj, hashedEntry* next); - private: //- Disallow default bitwise copy construct hashedEntry(const hashedEntry&) = delete; @@ -183,6 +252,13 @@ class HashTable protected: + //- Internally used base for iterator and const_iterator + class iterator_base; + + //- Friendship with the iterator_base is required. + friend class iterator_base; + + // Protected Member Functions //- Remove using begin/end iterators of listed keys @@ -196,16 +272,6 @@ protected: public: - // Forward declaration of iterators - - class iteratorBase; - class iterator; - class const_iterator; - - //- Declare friendship with the iteratorBase - friend class iteratorBase; - - // Constructors //- Construct given initial table size @@ -230,92 +296,92 @@ public: // Member Functions - // Access + // Access - //- The size of the underlying table - inline label capacity() const; + //- The size of the underlying table + inline label capacity() const; - //- Return number of elements in table - inline label size() const; + //- Return number of elements in table + inline label size() const; - //- Return true if the hash table is empty - inline bool empty() const; + //- Return true if the hash table is empty + inline bool empty() const; - //- Return true if hashedEntry is found in table - bool found(const Key& key) const; + //- Return true if hashedEntry is found in table + bool found(const Key& key) const; - //- Find and return an iterator set at the hashedEntry - // If not found iterator = end() - iterator find(const Key& key); + //- Find and return an iterator set at the hashedEntry + // If not found iterator = end() + iterator find(const Key& key); - //- Find and return an const_iterator set at the hashedEntry - // If not found iterator = end() - const_iterator find(const Key& key) const; + //- Find and return an const_iterator set at the hashedEntry + // If not found iterator = end() + const_iterator find(const Key& key) const; - //- Return the table of contents - List<Key> toc() const; + //- Return the table of contents + List<Key> toc() const; - //- Return the table of contents as a sorted list - List<Key> sortedToc() const; + //- Return the table of contents as a sorted list + List<Key> sortedToc() const; - // Edit + // Edit - //- Insert a new hashedEntry - // 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& newEntry); + //- Insert a new hashedEntry + // 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& newEntry); - //- Assign a new hashedEntry, overwriting existing entries. - // Returns true. - inline bool set(const Key& key, const T& newEntry); + //- Assign a new hashedEntry, overwriting existing entries. + // Returns true. + inline bool set(const Key& key, const T& newEntry); - //- Erase a hashedEntry specified by given iterator - // This invalidates the iterator until the next operator++ - bool erase(const iterator& iter); + //- Erase a hashedEntry specified by given iterator + // This invalidates the iterator until the next ++ operation + bool erase(const iterator& iter); - //- Erase a hashedEntry specified by the given key - bool erase(const Key& key); + //- Erase a hashedEntry specified by the given key + bool erase(const Key& key); - //- Remove entries given by the listed keys from this HashTable - // Return the number of elements removed - label erase(const UList<Key>& keys); + //- Remove entries given by the listed keys from this HashTable + // Return the number of elements removed + label erase(const UList<Key>& keys); - //- Remove entries given by the listed keys from this HashTable - // Return the number of elements removed - template<unsigned Size> - label erase(const FixedList<Key, Size>& keys); + //- Remove entries given by the listed keys from this HashTable + // Return the number of elements removed + template<unsigned Size> + label erase(const FixedList<Key, Size>& keys); - //- Remove entries given by the listed keys from this HashTable - // Return the number of elements removed - label erase(std::initializer_list<Key> keys); + //- Remove entries given by the listed keys from this HashTable + // Return the number of elements removed + label erase(std::initializer_list<Key> keys); - //- Remove entries given by the given keys from this HashTable - // Return the number of elements removed. - // The parameter HashTable needs the same type of key, but the - // type of values held and the hashing function are arbitrary. - template<class AnyType, class AnyHash> - label erase(const HashTable<AnyType, Key, AnyHash>& other); + //- Remove entries given by the given keys from this HashTable + // Return the number of elements removed. + // The parameter HashTable needs the same type of key, but the + // type of values held and the hashing function are arbitrary. + template<class AnyType, class AnyHash> + label erase(const HashTable<AnyType, Key, AnyHash>& other); - //- Resize the hash table for efficiency - void resize(const label sz); + //- Resize the hash table for efficiency + void resize(const label sz); - //- Clear all entries from table - void clear(); + //- Clear all entries from table + void clear(); - //- Clear the table entries and the table itself. - // Equivalent to clear() followed by resize(0) - void clearStorage(); + //- Clear the table entries and the table itself. + // Equivalent to clear() followed by resize(0) + void clearStorage(); - //- Shrink the allocated table to approx. twice number of elements - void shrink(); + //- Shrink the allocated table to approx. twice number of elements + void shrink(); - //- Transfer the contents of the argument table into this table - // and annul the argument table. - void transfer(HashTable<T, Key, Hash>& ht); + //- Transfer the contents of the argument table into this table + // and annul the argument table. + void transfer(HashTable<T, Key, Hash>& ht); - //- Transfer contents to the Xfer container - inline Xfer<HashTable<T, Key, Hash>> xfer(); + //- Transfer contents to the Xfer container + inline Xfer<HashTable<T, Key, Hash>> xfer(); // Member Operators @@ -345,65 +411,25 @@ public: bool operator!=(const HashTable<T, Key, Hash>& rhs) const; - // STL type definitions - - //- Type of keys that the HashTable uses. - typedef Key key_type; - - //- Type of values that the HashTable contains. - typedef T value_type; - - //- Type that can be used for storing into HashTable::value_type - // objects. This type is usually List::value_type&. - typedef T& reference; - - //- Type that can be used for storing into constant - // HashTable::value_type objects. This type is usually const - // HashTable::value_type&. - typedef const T& const_reference; - - //- The type that can represent the size of a HashTable. - typedef label size_type; - - - // Iterator access - - //- Iterator set to the beginning of the HashTable - inline iterator begin(); - - //- const_iterator set to the beginning of the HashTable - inline const_iterator begin() const; - - //- const_iterator set to the beginning of the HashTable - inline const_iterator cbegin() const; - - //- iterator to signal the end for any HashTable - inline const iterator& end(); - - //- const_iterator to signal the end for any HashTable - inline const const_iterator& end() const; - - //- const_iterator to signal the end for any HashTable - inline const const_iterator& cend() const; - +protected: // Iterators and helpers - //- The iterator base for HashTable + //- The iterator base for HashTable (internal use only). // Note: data and functions are protected, to allow reuse by iterator // and prevent most external usage. // iterator and const_iterator have the same size, allowing // us to reinterpret_cast between them (if desired) - class iteratorBase + class iterator_base { - using entry_type = hashedEntry; - public: // Public typedefs - using table_type = HashTable<T, Key, Hash>; - using key_type = HashTable<T, Key, Hash>::key_type; + using table_type = this_type; + using key_type = this_type::key_type; + using difference_type = this_type::difference_type; private: + using entry_type = hashedEntry; // Private Data @@ -428,25 +454,25 @@ public: //- Increment to the next position inline void increment(); - //- Erase the entry at the current position - bool erase(); - //- The referenced object/value element inline T& element() const; + //- Erase the entry at the current position + bool erase(); + public: // Constructors //- Construct null (end iterator) - inline iteratorBase(); + inline iterator_base(); //- Construct from begin of hash-table - inline explicit iteratorBase(const table_type* hashTbl); + inline explicit iterator_base(const table_type* hashTbl); //- Construct from hash table, element and hash index - inline iteratorBase + inline iterator_base ( const table_type* hashTbl, const entry_type* elmt, @@ -463,27 +489,49 @@ public: inline const Key& key() const; //- Compare hash-entry element pointers - inline bool operator==(const iteratorBase& iter) const; - inline bool operator!=(const iteratorBase& iter) const; + inline bool operator==(const iterator_base& iter) const; + inline bool operator!=(const iterator_base& iter) const; }; +public: + + //- An iterator wrapper for returning a reference to the key + template<class WrappedIterator> + class key_iterator_base + : + public WrappedIterator + { + public: + using reference = const Key&; + using difference_type = typename WrappedIterator::difference_type; + + //- Implicit conversion + inline key_iterator_base(const WrappedIterator& iter); + + //- Return the key + inline reference operator*() const; + }; + + + // STL iterator - //- An STL-conforming iterator + //- Forward iterator with non-const access class iterator : - public iteratorBase + public iterator_base { - friend class HashTable; // uses iterator::erase() method + friend class HashTable; // Uses iterator::erase() method using entry_type = hashedEntry; public: // Public typedefs - using table_type = HashTable<T, Key, Hash>; - using key_type = HashTable<T, Key, Hash>::key_type; - using reference = HashTable<T, Key, Hash>::reference; + using table_type = this_type; + using key_type = this_type::key_type; + using reference = this_type::reference; + using difference_type = typename iterator_base::difference_type; // Constructors @@ -518,19 +566,20 @@ public: // STL const_iterator - //- An STL-conforming const_iterator + //- Forward iterator with const access class const_iterator : - public iteratorBase + public iterator_base { using entry_type = const hashedEntry; public: // Public typedefs - using table_type = const HashTable<T, Key, Hash>; - using key_type = HashTable<T, Key, Hash>::key_type; - using reference = HashTable<T, Key, Hash>::const_reference; + using table_type = const this_type; + using key_type = this_type::key_type; + using reference = this_type::const_reference; + using difference_type = typename iterator_base::difference_type; // Constructors @@ -566,6 +615,43 @@ public: }; + //- Iterating over keys only + + //- Forward iterator returning the key + using key_iterator = key_iterator_base<iterator>; + + //- Forward const iterator returning the key + using const_key_iterator = key_iterator_base<const_iterator>; + + //- A const iterator begin/end pair for iterating over keys + const_iterator_pair<const_key_iterator, this_type> keys() const + { + return + const_iterator_pair<const_key_iterator,this_type>(*this); + } + + + // Iterator access + + //- Iterator set to the beginning of the HashTable + inline iterator begin(); + + //- const_iterator set to the beginning of the HashTable + inline const_iterator begin() const; + + //- const_iterator set to the beginning of the HashTable + inline const_iterator cbegin() const; + + //- iterator to signal the end for any HashTable + inline const iterator& end(); + + //- const_iterator to signal the end for any HashTable + inline const const_iterator& end() const; + + //- const_iterator to signal the end for any HashTable + inline const const_iterator& cend() const; + + // Writing //- Print information @@ -598,6 +684,7 @@ public: // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // +#include "HashTableCoreI.H" #include "HashTableI.H" // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * // diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C index 58fcdf27b1c..e57192f1e36 100644 --- a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCore.C @@ -3,7 +3,7 @@ \\ / F ield | OpenFOAM: The Open Source CFD Toolbox \\ / O peration | \\ / A nd | Copyright (C) 2011-2012 OpenFOAM Foundation - \\/ M anipulation | + \\/ M anipulation | Copyright (C) 2017 OpenCFD Ltd. ------------------------------------------------------------------------------- License This file is part of OpenFOAM. @@ -33,38 +33,53 @@ namespace Foam defineTypeNameAndDebug(HashTableCore, 0); } -const Foam::label Foam::HashTableCore::maxTableSize -( - Foam::HashTableCore::canonicalSize - ( - Foam::labelMax/2 - ) -); + +// Approximately labelMax/4 +const Foam::label Foam::HashTableCore::maxTableSize(1 << (sizeof(label)*8-3)); // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // -Foam::label Foam::HashTableCore::canonicalSize(const label size) +Foam::label Foam::HashTableCore::canonicalSize(const label requested_size) { - if (size < 1) + if (requested_size < 1) { return 0; } - // enforce power of two - uLabel goodSize = size; + // Enforce power of two - makes for a vey fast modulus etc. + // 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, + // need not be extremely large for hashing. + + uLabel powerOfTwo = 8; // lower-limit - if (goodSize & (goodSize - 1)) + const uLabel size = requested_size; + if (size < powerOfTwo) + { + return powerOfTwo; + } + else if (requested_size >= maxTableSize) + { + return maxTableSize; + } + else if (size & (size-1)) // <- Modulus of i^2 { - // brute-force is fast enough - goodSize = 1; - while (goodSize < unsigned(size)) + // Determine power-of-two. Brute-force is fast enough. + while (powerOfTwo < size) { - goodSize <<= 1; + powerOfTwo <<= 1; } - } - return goodSize; + return powerOfTwo; + } + else + { + return size; + } } diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableCoreI.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCoreI.H new file mode 100644 index 00000000000..8198e2e4c33 --- /dev/null +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableCoreI.H @@ -0,0 +1,146 @@ +/*---------------------------------------------------------------------------*\ + ========= | + \\ / F ield | OpenFOAM: The Open Source CFD Toolbox + \\ / O peration | + \\ / A nd | Copyright (C) 2017 OpenCFD Ltd. + \\/ M anipulation | +------------------------------------------------------------------------------- +License + This file is part of OpenFOAM. + + OpenFOAM is free software: you can redistribute it and/or modify it + under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + OpenFOAM is distributed in the hope that it will be useful, but WITHOUT + ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License + along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>. + +\*---------------------------------------------------------------------------*/ + +// * * * * * * * * * * * * * * * helper methods * * * * * * * * * * * * * * // + +template<class IteratorType, class TableType> +inline IteratorType Foam::HashTableCore::iterator_begin +( + TableType& table +) +{ + return IteratorType(table.begin()); +} + + +template<class IteratorType, class TableType> +inline IteratorType Foam::HashTableCore::iterator_begin +( + const TableType& table +) +{ + return IteratorType(table.begin()); +} + + +template<class IteratorType, class TableType> +inline IteratorType Foam::HashTableCore::iterator_cbegin +( + const TableType& table +) +{ + return IteratorType(table.cbegin()); +} + + +template<class IteratorType> +inline const IteratorType& Foam::HashTableCore::iterator_end() +{ + return *reinterpret_cast<const IteratorType*>(nullObjectPtr); +} + + +template<class IteratorType> +inline const IteratorType& Foam::HashTableCore::iterator_cend() +{ + return *reinterpret_cast<const IteratorType*>(nullObjectPtr); +} + + +// * * * * * * * * * * * * * const iterator pair * * * * * * * * * * * * * * // + +template<class IteratorType, class TableType> +inline Foam::HashTableCore::const_iterator_pair<IteratorType, TableType> +::const_iterator_pair +( + const TableType& tbl +) +: + size_(tbl.size()), + iter_(tbl.begin()) +{} + + +template<class IteratorType, class TableType> +inline Foam::label +Foam::HashTableCore::const_iterator_pair<IteratorType, TableType>::size() const +{ + return size_; +} + + +template<class IteratorType, class TableType> +inline bool +Foam::HashTableCore::const_iterator_pair<IteratorType, TableType>::empty() const +{ + return !size_; +} + + +template<class IteratorType, class TableType> +inline IteratorType Foam::HashTableCore::const_iterator_pair +< + IteratorType, + TableType +>::begin() const +{ + return iter_; +} + + +template<class IteratorType, class TableType> +inline IteratorType Foam::HashTableCore::const_iterator_pair +< + IteratorType, + TableType +>::cbegin() const +{ + return iter_; +} + + +template<class IteratorType, class TableType> +inline const IteratorType& Foam::HashTableCore::const_iterator_pair +< + IteratorType, + TableType +>::end() const +{ + return HashTableCore::iterator_cend<IteratorType>(); +} + + +template<class IteratorType, class TableType> +inline const IteratorType& Foam::HashTableCore::const_iterator_pair +< + IteratorType, + TableType +>::cend() const +{ + return HashTableCore::iterator_cend<IteratorType>(); +} + + +// ************************************************************************* // diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableI.H b/src/OpenFOAM/containers/HashTables/HashTable/HashTableI.H index b3f6276f9ef..f8df2437591 100644 --- a/src/OpenFOAM/containers/HashTables/HashTable/HashTableI.H +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableI.H @@ -159,7 +159,7 @@ inline T& Foam::HashTable<T, Key, Hash>::operator()(const Key& key) // * * * * * * * * * * * * * * * iterator base * * * * * * * * * * * * * * * // template<class T, class Key, class Hash> -inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase() +inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base() : entryPtr_(nullptr), hashTable_(nullptr), @@ -168,7 +168,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase() template<class T, class Key, class Hash> -inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase +inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base ( const table_type* hashTbl, const entry_type* elmt, @@ -182,7 +182,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase template<class T, class Key, class Hash> -inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase +inline Foam::HashTable<T, Key, Hash>::iterator_base::iterator_base ( const table_type* hashTbl ) @@ -213,7 +213,7 @@ inline Foam::HashTable<T, Key, Hash>::iteratorBase::iteratorBase template<class T, class Key, class Hash> inline void -Foam::HashTable<T, Key, Hash>::iteratorBase::increment() +Foam::HashTable<T, Key, Hash>::iterator_base::increment() { // A negative index is a special value from erase if (hashIndex_ < 0) @@ -257,30 +257,30 @@ Foam::HashTable<T, Key, Hash>::iteratorBase::increment() template<class T, class Key, class Hash> inline bool -Foam::HashTable<T, Key, Hash>::iteratorBase::found() const +Foam::HashTable<T, Key, Hash>::iterator_base::found() const { return entryPtr_; } template<class T, class Key, class Hash> -inline const Key& Foam::HashTable<T, Key, Hash>::iteratorBase::key() const +inline const Key& Foam::HashTable<T, Key, Hash>::iterator_base::key() const { return entryPtr_->key_; } template<class T, class Key, class Hash> -inline T& Foam::HashTable<T, Key, Hash>::iteratorBase::element() const +inline T& Foam::HashTable<T, Key, Hash>::iterator_base::element() const { return entryPtr_->obj_; } template<class T, class Key, class Hash> -inline bool Foam::HashTable<T, Key, Hash>::iteratorBase::operator== +inline bool Foam::HashTable<T, Key, Hash>::iterator_base::operator== ( - const iteratorBase& iter + const iterator_base& iter ) const { return entryPtr_ == iter.entryPtr_; @@ -288,21 +288,45 @@ inline bool Foam::HashTable<T, Key, Hash>::iteratorBase::operator== template<class T, class Key, class Hash> -inline bool Foam::HashTable<T, Key, Hash>::iteratorBase::operator!= +inline bool Foam::HashTable<T, Key, Hash>::iterator_base::operator!= ( - const iteratorBase& iter + const iterator_base& iter ) const { return entryPtr_ != iter.entryPtr_; } +// * * * * * * * * * * * * * * key iterator base * * * * * * * * * * * * * * // + +template<class T, class Key, class Hash> +template<class WrappedIterator> +inline Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator> +::key_iterator_base +( + const WrappedIterator& iter +) +: + WrappedIterator(iter) +{} + + +template<class T, class Key, class Hash> +template<class WrappedIterator> +inline const Key& +Foam::HashTable<T, Key, Hash>::key_iterator_base<WrappedIterator> +::operator*() const +{ + return this->key(); +} + + // * * * * * * * * * * * * * * * * STL iterator * * * * * * * * * * * * * * // template<class T, class Key, class Hash> inline Foam::HashTable<T, Key, Hash>::iterator::iterator() : - iteratorBase() + iterator_base() {} @@ -312,7 +336,7 @@ inline Foam::HashTable<T, Key, Hash>::iterator::iterator table_type* hashTbl ) : - iteratorBase(hashTbl) + iterator_base(hashTbl) {} @@ -324,7 +348,7 @@ inline Foam::HashTable<T, Key, Hash>::iterator::iterator const label hashIndex ) : - iteratorBase(hashTbl, elmt, hashIndex) + iterator_base(hashTbl, elmt, hashIndex) {} @@ -371,12 +395,12 @@ Foam::HashTable<T, Key, Hash>::iterator::operator++(int) } -// * * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * * // +// * * * * * * * * * * * * * * * STL const_iterator * * * * * * * * * * * * // template<class T, class Key, class Hash> inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator() : - iteratorBase() + iterator_base() {} @@ -386,7 +410,7 @@ inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator const HashTable<T, Key, Hash>::iterator& iter ) : - iteratorBase(iter) + iterator_base(iter) {} @@ -396,7 +420,7 @@ inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator table_type* hashTbl ) : - iteratorBase(hashTbl) + iterator_base(hashTbl) {} @@ -408,7 +432,7 @@ inline Foam::HashTable<T, Key, Hash>::const_iterator::const_iterator const label hashIndex ) : - iteratorBase(hashTbl, elmt, hashIndex) + iterator_base(hashTbl, elmt, hashIndex) {} @@ -467,7 +491,7 @@ Foam::HashTable<T, Key, Hash>::begin() template<class T, class Key, class Hash> inline typename Foam::HashTable<T, Key, Hash>::const_iterator -Foam::HashTable<T, Key, Hash>::cbegin() const +Foam::HashTable<T, Key, Hash>::begin() const { return const_iterator(this); } @@ -475,7 +499,7 @@ Foam::HashTable<T, Key, Hash>::cbegin() const template<class T, class Key, class Hash> inline typename Foam::HashTable<T, Key, Hash>::const_iterator -Foam::HashTable<T, Key, Hash>::begin() const +Foam::HashTable<T, Key, Hash>::cbegin() const { return const_iterator(this); } @@ -485,29 +509,23 @@ template<class T, class Key, class Hash> inline const typename Foam::HashTable<T, Key, Hash>::iterator& Foam::HashTable<T, Key, Hash>::end() { - using iter_type = typename HashTable<T, Key, Hash>::iterator; - - return endIteratorRef<iter_type>(); + return iterator_end<iterator>(); } template<class T, class Key, class Hash> inline const typename Foam::HashTable<T, Key, Hash>::const_iterator& -Foam::HashTable<T, Key, Hash>::cend() const +Foam::HashTable<T, Key, Hash>::end() const { - using iter_type = typename HashTable<T, Key, Hash>::const_iterator; - - return endIteratorRef<iter_type>(); + return iterator_end<const_iterator>(); } template<class T, class Key, class Hash> inline const typename Foam::HashTable<T, Key, Hash>::const_iterator& -Foam::HashTable<T, Key, Hash>::end() const +Foam::HashTable<T, Key, Hash>::cend() const { - using iter_type = typename HashTable<T, Key, Hash>::const_iterator; - - return endIteratorRef<iter_type>(); + return iterator_cend<const_iterator>(); } diff --git a/src/OpenFOAM/containers/HashTables/HashTable/HashTableIO.C b/src/OpenFOAM/containers/HashTables/HashTable/HashTableIO.C index 97193707c16..0eb3fadb459 100644 --- a/src/OpenFOAM/containers/HashTables/HashTable/HashTableIO.C +++ b/src/OpenFOAM/containers/HashTables/HashTable/HashTableIO.C @@ -130,7 +130,7 @@ Foam::Ostream& Foam::HashTable<T, Key, Hash>::writeKeys } // Check state of IOstream - os.check("HashSet<Key>::writeList(Ostream&)"); + os.check(FUNCTION_NAME); return os; } @@ -279,7 +279,7 @@ Foam::Ostream& Foam::operator<< os << token::END_LIST; // Check state of IOstream - os.check("Ostream& operator<<(Ostream&, const HashTable&)"); + os.check(FUNCTION_NAME); return os; } diff --git a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTable.H b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTable.H index 9614b82fbbe..639a434d654 100644 --- a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTable.H +++ b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTable.H @@ -78,8 +78,8 @@ template<class T, class Key, class Hash> Ostream& operator<< //- Template-invariant bits for StaticHashTable struct StaticHashTableCore { - //- Return a canonical (power-of-two) size - static label canonicalSize(const label size); + //- Return a canonical (power-of-two) of the requested size. + static label canonicalSize(const label requested_size); //- Construct null StaticHashTableCore() diff --git a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C index 9f24c86e63a..31c02ebf5ec 100644 --- a/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C +++ b/src/OpenFOAM/containers/HashTables/StaticHashTable/StaticHashTableCore.C @@ -34,30 +34,42 @@ defineTypeNameAndDebug(StaticHashTableCore, 0); } +// Approximately labelMax/4 +static const Foam::label maxTableSize(1 << (sizeof(Foam::label)*8-3)); + + // * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * * // -Foam::label Foam::StaticHashTableCore::canonicalSize(const label size) +Foam::label Foam::StaticHashTableCore::canonicalSize(const label requested_size) { - if (size < 1) + if (requested_size < 1) { return 0; } // Enforce power of two - makes for a vey fast modulus etc. - // The value '8' is some arbitrary lower limit. - // If the hash table is too small, there will be many table collisions! + // 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, + // need not be extremely large for hashing. - const uLabel unsigned_size = size; - uLabel powerOfTwo = 8; + uLabel powerOfTwo = 8; // lower-limit + const uLabel size = requested_size; if (size < powerOfTwo) { return powerOfTwo; } - else if (unsigned_size & (unsigned_size-1)) // <- Modulus of i^2 + 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. - while (powerOfTwo < unsigned_size) + while (powerOfTwo < size) { powerOfTwo <<= 1; } @@ -66,7 +78,7 @@ Foam::label Foam::StaticHashTableCore::canonicalSize(const label size) } else { - return unsigned_size; + return size; } } -- GitLab