- introduced a ListPolicy details to make the transition between
a short list (space separated) and a long list (newline separated)
more configurable.
We suppress line breaks for commonly used types that often have
short content: (word, wordRes, keyType).
- relocate the pair_entry (HashTable) and unary_entry (HashSet) into
the Detail namespace and add output handling.
The output handling at this level removes the reliance on zero::null
output (HashSet) and allows direct support of pointers.
This means that the following now works
HashTable<T*> tbl;
os << tbl;
It also means that we don't need to overload operator<< for
HashPtrTable anymore.
- avoid delete/new when calling HashSet::set(). If the entry already
exists there is no reason to remove it and add another one with the
same content.
STYLE: HashTable iterators now have a val() method
- identical to the object() iterator method, but shorter to type.
- can be used as a more natural test on the iterator.
For example, with
HashTable<..> table;
auto iter = table.find(...);
Following are now all equivalent:
1. if (iter != table.end()) ...
2. if (iter.found()) ...
3. if (iter) ...
- improves backward compatibility and more naming consistency.
Retain setMany(iter1, iter2) to avoid ambiguity with the
PackedList::set(index, value) method.
- disallow insert() of raw pointers, since a failed insertion
(ie, entry already existed) results in an unmanaged pointer.
Either insert using an autoPtr, or set() with raw pointers or autoPtr.
- IOobjectList::add() now takes an autoPtr instead of an object reference
- IOobjectList::remove() now returns an autoPtr instead of a raw pointer
- without these will use the normal move construct + move assign.
This is similarly efficient, but avoids the inadvertently having the
incorrect Swap being used for derived classes.
STYLE: remove unused xfer methods for HashTable, HashSet
- unneeded since move construct and move assignment are possible
- this increases the flexibility of the interface
- Add stringOps 'natural' string sorting comparison.
Digits are sorted in their natural order, which means that
(file10.txt file05.txt file2.txt)
are sorted as
(file2.txt file05.txt file10.txt)
STYLE: consistent naming of template parameters for comparators
- Compare for normal binary predicates
- ListComparePredicate for list compare binary predicates
- improve functional compatibility with DynList (remove methods)
* eg, remove an element from any position in a DynamicList
* reduce the number of template parameters
* remove/subset regions of DynamicList
- propagate Swap template specializations for lists, hashtables
- move construct/assignment to various containers.
- add find/found methods for FixedList and UList for a more succinct
(and clearer?) usage than the equivalent global findIndex() function.
- simplify List_FOR_ALL loops
- This follows the same idea as cbegin/cend and is helpful when using
C++11 auto to ensure we have unambiguous const-safe access.
Previously:
====
typename someLongClass::const_iterator iter = someTable.find(key);
... later on:
*iter = value; // Oops, but caught by compiler.
We can save some typing with auto, but it is uncertain what we get:
====
auto iter = someTable.find(key);
// iterator or const_iterator?
// depends on someTable having const or non-const access.
... later on:
*iter = value; // Oops, but not caught by compiler.
Using cfind instead, auto will deduce const_iterator as the type:
====
auto iter = someTable.cfind(key); // definitely const_iterator
... later on:
*iter = value; // Oops, but caught by compiler.
- Generalized means over filtering table entries based on their keys,
values, or both. Either filter (retain), or optionally prune elements
that satisfy the specified predicate.
filterKeys and filterValues:
- Take a unary predicate with the signature
bool operator()(const Key& k);
- filterEntries:
Takes a binary predicate with the signature
bool operator()(const Key& k, const T& v);
==
The predicates can be normal class methods, or provide on-the-fly
using a C++ lambda. For example,
wordRes goodFields = ...;
allFieldNames.filterKeys
(
[&goodFields](const word& k){ return goodFields.match(k); }
);
Note that all classes that can match a string (eg, regExp, keyType,
wordRe, wordRes) or that are derived from a Foam::string (eg, fileName,
word) are provided with a corresponding
bool operator()(const std::string&)
that either performs a regular expression or a literal match.
This allows such objects to be used directly as a unary predicate
when filtering any string hash keys.
Note that HashSet and hashedWordList both have the proper
operator() methods that also allow them to be used as a unary
predicate.
- Similar predicate selection with the following:
* tocKeys, tocValues, tocEntries
* countKeys, countValues, countEntries
except that instead of pruning, there is a simple logic inversion.
- 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.
- 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())
{
...
}
- previously had a mismash of const/non-const attributes on iterators
that were confused with the attributes of the object being accessed.
- use the iterator keys() and object() methods consistently for all
internal access of the HashTable iterators. This makes the intention
clearer, the code easier to maintain, and protects against any
possible changes in the definition of the operators.
- 'operator*': The standard form expected by STL libraries.
However, for the std::map, this dereferences to a <key,value> pair,
whereas OpenFOAM dereferences simply to <value>.
- 'operator()': OpenFOAM treats this like the 'operator*'
- adjusted the values of end() and cend() to reinterpret from nullObject
instead of returning a static iteratorEnd() object.
This means that C++ templates can now correctly deduce and match
the return types from begin() and end() consistently.
So that range-based now works.
Eg,
HashTable<label> table1 = ...;
for (auto i : table1)
{
Info<< i << endl;
}
Since the 'operator*' returns hash table values, this prints all the
values in the table.
- optimize erasure using different HashTable based on its size.
Eg, hashtable.erase(other);
If 'other' is smaller than the hashtable, it is more efficient to
use the keys from other to remove from the hashtable.
Otherwise simply iterate over the hashtable and remove it if
that key was found in other.
- explicitly mention the value-initialized status for the operator().
This means that the following code will properly use an initialized
zero.
HashTable<label> regionCount;
if (...)
regionCount("region1")++;
... and also this;
if (regionCount("something") > 0)
{
...
}
Note that the OpenFOAM HashTable uses operator[] to provide read and
write access to *existing* entries and will provoke a FatalError if
the entry does not exist.
The operator() provides write access to *existing* entries or will
create the new entry as required.
The STL hashes use operator[] for this purpose.
- This can be used as a convenient alternative to comparing against end().
Eg,
dictionaryConstructorTable::iterator cstrIter =
dictionaryConstructorTablePtr_->find(methodType);
if (cstrIter.found())
{
...
}
vs.
if (cstrIter != dictionaryConstructorTablePtr_->end())
{
...
}
- to the referenced object via a method name, which may be clearer
than deferencing the iterator
[key, value] => iter.key(), *iter
[key, value] => iter.key(), iter()
[key, value] => iter.key(), iter.object()
This resolves a whole range of issues and work-arounds with earlier
releases. This version of icpc is more or less compatible with the
latest gcc and clang compilers and only required one hack to avoid
warnings from PackedBoolList.H.
Weird one. Reported crash with gcc452 with end() iterator returning a copy.
The end() iterator returned was not initialised. No idea why & could not
repeat.