Commit 03d18072 authored by Mark Olesen's avatar Mark Olesen
Browse files

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())
     {
        ...
     }
parent 759306a3
......@@ -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);
......
......@@ -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;
......
Test-cpluplus1.C
EXE = $(FOAM_USER_APPBIN)/Test-cpluplus1
/* EXE_INC = -I$(LIB_SRC)/cfdTools/include */
/* EXE_LIBS = -lfiniteVolume */
/*---------------------------------------------------------------------------*\
========= |
\\ / 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;
}
// ************************************************************************* //
......@@ -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;
......
......@@ -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>();
}
......
......@@ -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
......
......@@ -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);
}
......
......@@ -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;
}
}
......