StaticHashTable.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4  \\ / O peration |
5  \\ / A nd | Copyright (C) 2011-2015 OpenFOAM Foundation
6  \\/ M anipulation |
7 -------------------------------------------------------------------------------
8 License
9  This file is part of OpenFOAM.
10 
11  OpenFOAM is free software: you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by
13  the Free Software Foundation, either version 3 of the License, or
14  (at your option) any later version.
15 
16  OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
23 
24 \*---------------------------------------------------------------------------*/
25 
26 #ifndef StaticHashTable_C
27 #define StaticHashTable_C
28 
29 #include "StaticHashTable.H"
30 #include "List.H"
31 #include "IOstreams.H"
32 
33 // * * * * * * * * * * * * Private Member Functions * * * * * * * * * * * * //
34 
35 inline
37 {
38  if (size < 1)
39  {
40  return 0;
41  }
42 
43  // enforce power of two
44  unsigned int goodSize = size;
45 
46  if (goodSize & (goodSize - 1))
47  {
48  // brute-force is fast enough
49  goodSize = 1;
50  while (goodSize < unsigned(size))
51  {
52  goodSize <<= 1;
53  }
54  }
55 
56  return goodSize;
57 }
58 
59 
60 // * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
61 
62 // Construct given initial table size
63 template<class T, class Key, class Hash>
65 :
67  keys_(StaticHashTableCore::canonicalSize(size)),
68  objects_(keys_.size()),
69  nElmts_(0),
70  endIter_(*this, keys_.size(), 0),
71  endConstIter_(*this, keys_.size(), 0)
72 {
73  if (size < 1)
74  {
76  << "Illegal size " << size << " for StaticHashTable."
77  << " Minimum size is 1" << abort(FatalError);
78  }
79 }
80 
81 
82 // Construct as copy
83 template<class T, class Key, class Hash>
85 (
86  const StaticHashTable<T, Key, Hash>& ht
87 )
88 :
89  StaticHashTableCore(),
90  keys_(ht.keys_),
91  objects_(ht.objects_),
92  nElmts_(ht.nElmts_),
93  endIter_(*this, keys_.size(), 0),
94  endConstIter_(*this, keys_.size(), 0)
95 {}
96 
97 
98 template<class T, class Key, class Hash>
100 (
101  const Xfer<StaticHashTable<T, Key, Hash> >& ht
102 )
103 :
104  StaticHashTableCore(),
105  keys_(0),
106  objects_(0),
107  nElmts_(0),
108  endIter_(*this, 0, 0),
109  endConstIter_(*this, 0, 0)
110 {
111  transfer(ht());
112 }
113 
114 
115 // * * * * * * * * * * * * * * * * Destructor * * * * * * * * * * * * * * * //
116 
117 template<class T, class Key, class Hash>
119 {}
120 
121 
122 // * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
123 
124 template<class T, class Key, class Hash>
126 {
127  if (nElmts_)
128  {
129  const label hashIdx = hashKeyIndex(key);
130  const List<Key>& localKeys = keys_[hashIdx];
131 
132  forAll(localKeys, elemIdx)
133  {
134  if (key == localKeys[elemIdx])
135  {
136  return true;
137  }
138  }
139  }
140 
141 # ifdef FULLDEBUG
142  if (debug)
143  {
144  Info<< "StaticHashTable<T, Key, Hash>::found(const Key&) : "
145  << "Entry " << key << " not found in hash table\n";
146  }
147 # endif
148 
149  return false;
150 }
151 
152 
153 template<class T, class Key, class Hash>
156 (
157  const Key& key
158 )
159 {
160  if (nElmts_)
161  {
162  const label hashIdx = hashKeyIndex(key);
163  const List<Key>& localKeys = keys_[hashIdx];
164 
165  forAll(localKeys, elemIdx)
166  {
167  if (key == localKeys[elemIdx])
168  {
169  return iterator(*this, hashIdx, elemIdx);
170  }
171  }
172  }
173 
174 # ifdef FULLDEBUG
175  if (debug)
176  {
177  Info<< "StaticHashTable<T, Key, Hash>::find(const Key&) : "
178  << "Entry " << key << " not found in hash table\n";
179  }
180 # endif
181 
182  return end();
183 }
184 
185 
186 template<class T, class Key, class Hash>
189 (
190  const Key& key
191 ) const
192 {
193  if (nElmts_)
194  {
195  const label hashIdx = hashKeyIndex(key);
196  const List<Key>& localKeys = keys_[hashIdx];
197 
198  forAll(localKeys, elemIdx)
199  {
200  if (key == localKeys[elemIdx])
201  {
202  return const_iterator(*this, hashIdx, elemIdx);
203  }
204  }
205  }
206 
207 # ifdef FULLDEBUG
208  if (debug)
209  {
210  Info<< "StaticHashTable<T, Key, Hash>::find(const Key&) const : "
211  << "Entry " << key << " not found in hash table\n";
212  }
213 # endif
214 
215  return cend();
216 }
217 
218 
219 // Return the table of contents
220 template<class T, class Key, class Hash>
222 {
223  List<Key> keys(nElmts_);
224  label keyI = 0;
225 
226  for (const_iterator iter = cbegin(); iter != cend(); ++iter)
227  {
228  keys[keyI++] = iter.key();
229  }
230 
231  return keys;
232 }
233 
234 
235 template<class T, class Key, class Hash>
237 (
238  const Key& key,
239  const T& newEntry,
240  const bool protect
241 )
242 {
243  const label hashIdx = hashKeyIndex(key);
244  List<Key>& localKeys = keys_[hashIdx];
245 
246  label existing = localKeys.size();
247  forAll(localKeys, elemIdx)
248  {
249  if (key == localKeys[elemIdx])
250  {
251  existing = elemIdx;
252  break;
253  }
254  }
255 
256  if (existing == localKeys.size())
257  {
258  // not found, append
259  List<T>& localObjects = objects_[hashIdx];
260 
261  localKeys.setSize(existing+1);
262  localObjects.setSize(existing+1);
263 
264  localKeys[existing] = key;
265  localObjects[existing] = newEntry;
266 
267  nElmts_++;
268  }
269  else if (protect)
270  {
271  // found - but protected from overwriting
272  // this corresponds to the STL 'insert' convention
273 # ifdef FULLDEBUG
274  if (debug)
275  {
276  Info<< "StaticHashTable<T, Key, Hash>::set"
277  "(const Key& key, T newEntry, true) : "
278  "Cannot insert " << key << " already in hash table\n";
279  }
280 # endif
281  return false;
282  }
283  else
284  {
285  // found - overwrite existing entry
286  // this corresponds to the Perl convention
287  objects_[hashIdx][existing] = newEntry;
288  }
289 
290  return true;
291 }
292 
293 
294 template<class T, class Key, class Hash>
295 bool Foam::StaticHashTable<T, Key, Hash>::erase(const iterator& cit)
296 {
297  if (cit != end())
298  {
299  List<Key>& localKeys = keys_[cit.hashIndex_];
300  List<T>& localObjects = objects_[cit.hashIndex_];
301 
302  // Copy down
303  for (label i = cit.elemIndex_+1; i < localKeys.size(); i++)
304  {
305  localKeys[i-1] = localKeys[i];
306  localObjects[i-1] = localObjects[i];
307  }
308  localKeys.setSize(localKeys.size()-1);
309  localObjects.setSize(localObjects.size()-1);
310 
311  // adjust iterator after erase
312  iterator& it = const_cast<iterator&>(cit);
313 
314  it.elemIndex_--;
315  if (it.elemIndex_ < 0)
316  {
317  // No previous element in the local list
318  // Mark with as special value (see notes in HashTable)
319  it.hashIndex_ = -it.hashIndex_ - 1;
320  it.elemIndex_ = 0;
321  }
322 
323  nElmts_--;
324 
325 # ifdef FULLDEBUG
326  if (debug)
327  {
328  Info<< "StaticHashTable<T, Key, Hash>::erase(iterator&) : "
329  << "hashedEntry removed.\n";
330  }
331 # endif
332 
333  return true;
334  }
335  else
336  {
337 # ifdef FULLDEBUG
338  if (debug)
339  {
340  Info<< "StaticHashTable<T, Key, Hash>::erase(iterator&) : "
341  << "cannot remove hashedEntry from hash table\n";
342  }
343 # endif
344 
345  return false;
346  }
347 }
348 
349 
350 template<class T, class Key, class Hash>
352 {
353  iterator it = find(key);
354 
355  if (it != end())
356  {
357  return erase(it);
358  }
359  else
360  {
361  return false;
362  }
363 }
364 
365 
366 template<class T, class Key, class Hash>
368 (
370 )
371 {
372  label count = 0;
373 
374  // Remove rhs elements from this table
375  // NOTE: could optimize depending on which hash is smaller
376  for (iterator iter = this->begin(); iter != this->end(); ++iter)
377  {
378  if (rhs.found(iter.key()) && erase(iter))
379  {
380  count++;
381  }
382  }
383 
384  return count;
385 }
386 
387 
388 template<class T, class Key, class Hash>
390 {
392 
393  if (newSize == keys_.size())
394  {
395 # ifdef FULLDEBUG
396  if (debug)
397  {
398  Info<< "StaticHashTable<T, Key, Hash>::resize(const label) : "
399  << "new table size == old table size\n";
400  }
401 # endif
402 
403  return;
404  }
405 
406  if (newSize < 1)
407  {
409  << "Illegal size " << newSize << " for StaticHashTable."
410  << " Minimum size is 1" << abort(FatalError);
411  }
412 
413 
414  StaticHashTable<T, Key, Hash> newTable(newSize);
415 
416  for (const_iterator iter = cbegin(); iter != cend(); ++iter)
417  {
418  newTable.insert(iter.key(), *iter);
419  }
420 
421  transfer(newTable);
422 
423  // Adapt end() iterators
424  endIter_.hashIndex_ = keys_.size();
425  endConstIter_.hashIndex_ = keys_.size();
426 }
427 
428 
429 template<class T, class Key, class Hash>
431 {
432  forAll(keys_, hashIdx)
433  {
434  keys_[hashIdx].clear();
435  objects_[hashIdx].clear();
436  }
437 
438  nElmts_ = 0;
439 }
440 
441 
442 template<class T, class Key, class Hash>
444 {
445  clear();
446  resize(1);
447 }
448 
449 
450 template<class T, class Key, class Hash>
452 (
454 )
455 {
456  // Remove existing elements
457  clear();
458 
459  // Copy data from ht
460  keys_.transfer(ht.keys_);
461  objects_.transfer(ht.objects_);
462 
463  nElmts_ = ht.nElmts_;
464  ht.nElmts_ = 0;
465 
466  // Adapt end() iterators
467  endIter_.hashIndex_ = keys_.size();
468  endConstIter_.hashIndex_ = keys_.size();
469 
470  ht.endIter_.hashIndex_ = 0;
471  ht.endConstIter_.hashIndex_ = 0;
472 }
473 
474 
475 // * * * * * * * * * * * * * * * Member Operators * * * * * * * * * * * * * //
476 
477 template<class T, class Key, class Hash>
479 (
481 )
482 {
483  // Check for assignment to self
484  if (this == &rhs)
485  {
487  << "attempted assignment to self"
488  << abort(FatalError);
489  }
490 
491 
492  // keys could be empty from a previous transfer()
493  if (keys_.empty())
494  {
495  keys_.setSize(rhs.keys_.size());
496  objects_.setSize(keys_.size());
497 
498  // Adapt end() iterators
499  endIter_.hashIndex_ = keys_.size();
500  endConstIter_.hashIndex_ = keys_.size();
501  }
502  else
503  {
504  clear();
505  // keys_.size() does not change so neither does end() iterator.
506  }
507 
508 
509  for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
510  {
511  insert(iter.key(), *iter);
512  }
513 }
514 
515 template<class T, class Key, class Hash>
517 (
519 ) const
520 {
521  // sizes (number of keys) must match
522 
523  for (const_iterator iter = rhs.cbegin(); iter != rhs.cend(); ++iter)
524  {
525  const_iterator fnd = find(iter.key());
526 
527  if (fnd == cend() || fnd() != iter())
528  {
529  return false;
530  }
531  }
532 
533  return true;
534 }
535 
536 
537 template<class T, class Key, class Hash>
539 (
541 ) const
542 {
543  return !(operator==(rhs));
544 }
545 
546 
547 // * * * * * * * * * * * * * * * Friend Operators * * * * * * * * * * * * * //
548 
549 #include "StaticHashTableIO.C"
550 
551 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
552 
553 #endif
554 
555 // ************************************************************************* //
IOstreams.H
Useful combination of include files which define Sin, Sout and Serr and the use of IO streams general...
Foam::StaticHashTable::endIter_
iterator endIter_
Iterator returned by end()
Definition: StaticHashTable.H:386
List.H
Foam::StaticHashTable::Iterator< T &, StaticHashTable< T, Key, Hash > & >
clear
UEqn clear()
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::StaticHashTable::nElmts_
label nElmts_
The current number of elements in table.
Definition: StaticHashTable.H:119
Foam::StaticHashTable::~StaticHashTable
~StaticHashTable()
Destructor.
Definition: StaticHashTable.C:118
resize
triSurfaceToAgglom resize(surfacesMesh.size())
Foam::operator==
tmp< fvMatrix< Type > > operator==(const fvMatrix< Type > &, const fvMatrix< Type > &)
erase
srcOptions erase("case")
Foam::StaticHashTable::keys_
List< List< Key > > keys_
The lookup keys, ordered per hash value.
Definition: StaticHashTable.H:113
Foam::StaticHashTable::clear
void clear()
Clear all entries from table.
Definition: StaticHashTable.C:430
StaticHashTable.H
Foam::StaticHashTable::clearStorage
void clearStorage()
Clear the table entries and the table itself.
Definition: StaticHashTable.C:443
List::size
int size() const
Definition: ListI.H:83
Foam::StaticHashTable< T, Key, Hash >
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::Info
messageStream Info
Foam::StaticHashTable::cbegin
const_iterator cbegin() const
const_iterator set to the beginning of the StaticHashTable
Definition: StaticHashTableI.H:369
StaticHashTableIO.C
Foam::T
void T(FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Definition: FieldFieldFunctions.C:55
Foam::StaticHashTable::set
bool set(const Key &, const T &newElmt, bool protect)
Assign a new hashed entry to a possibly already existing key.
Foam::StaticHashTable< T, Key, Hash >::iterator
Iterator< T &, StaticHashTable< T, Key, Hash > & > iterator
Definition: StaticHashTable.H:138
Foam::FatalError
error FatalError
Foam::StaticHashTable::endConstIter_
const_iterator endConstIter_
const_iterator returned by end()
Definition: StaticHashTable.H:389
Foam::StaticHashTable::erase
bool erase(const iterator &it)
Erase an hashed entry specified by given iterator.
Foam::StaticHashTable::toc
List< Key > toc() const
Return the table of contents.
Definition: StaticHashTable.C:221
Foam::abort
errorManip< error > abort(error &err)
Definition: errorManip.H:131
Foam::StaticHashTable::resize
void resize(const label newSize)
Resize the hash table for efficiency.
Definition: StaticHashTable.C:389
Foam::List::setSize
void setSize(const label)
Reset size of List.
Foam::StaticHashTable::find
iterator find(const Key &key)
Find and return an iterator set at the hashed entry.
Definition: StaticHashTable.C:156
FatalErrorInFunction
#define FatalErrorInFunction
Report an error message using Foam::FatalError.
Definition: error.H:318
Foam::StaticHashTableCore
Template-invariant bits for StaticHashTable.
Definition: StaticHashTable.H:78
Foam::StaticHashTableCore::canonicalSize
static label canonicalSize(const label)
Return a canonical (power-of-two) size.
Definition: StaticHashTable.C:36
Foam::StaticHashTable< T, Key, Hash >::const_iterator
Iterator< const T &, const StaticHashTable< T, Key, Hash > & > const_iterator
Definition: StaticHashTable.H:150
Foam::List
A 1D array of objects of type <T>, where the size of the vector is known and used for subscript bound...
Definition: HashTable.H:59
Foam::StaticHashTable::insert
bool insert(const Key &key, const T &newElmt)
Insert a new hashed entry.
Definition: StaticHashTableI.H:60
Foam::StaticHashTable::StaticHashTable
StaticHashTable(const label size=128)
Construct given initial table size.
List
Definition: Test.C:19
Foam::List::size
void size(const label)
Override size to be inconsistent with allocated storage.
Foam::StaticHashTable::found
bool found(const Key &key) const
Return true if hashed entry is found in table.
Definition: StaticHashTable.C:125
Foam::StaticHashTable::cend
const const_iterator & cend() const
const_iterator set to beyond the end of the StaticHashTable
Definition: StaticHashTableI.H:393
Foam::StaticHashTable::objects_
List< List< T > > objects_
For each key the corresponding object.
Definition: StaticHashTable.H:116
Foam::StaticHashTable::transfer
void transfer(StaticHashTable< T, Key, Hash > &)
Transfer the contents of the argument table into this table.
Definition: StaticHashTable.C:452
insert
timeIndices insert(timeIndex, timeDirs[timeI].value())