1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
|
/********************************************************/
/* Hash Table template class - v1.2 */
/* */
/* Author: Jake Hotson */
/* */
/* construct a hash table for objects of type TYPE */
/* */
/* HashTable<TYPE>(unsigned initialTableSizeShift */
/* = HT_DEFAULTTABLESIZESHIFT); */
/* */
/* TYPE must have boolean operator == defined, and */
/* there must be an overload of the function */
/* HashFunction() which acts as a hash */
/* function for the TYPE, taking an argument of type */
/* TYPE or a suitable conversion thereof, and returning */
/* unsigned */
/* Also, if a==b then HashFunction(a)==HashFunction(b) */
/* Additionally, TYPE must have valid assignment */
/* operator and copy constructor */
/****************************************************Jake*/
/************************************************************/
/* */
/* v1.0 public classes and functions and macros */
/* */
/* HASH_TEMPLATE_VERSION */
/* */
/* major version * 100 + minor version */
/* in this version (1.0) the value is 100 */
/* */
/* HT_NODEFAULTFNS */
/* */
/* #define to not compile default hash functions */
/* */
/* HT_DEFAULTABLESIZESHIFT */
/* */
/* #define to override default table size shift */
/* of 6 (which gives a default table size of 64) */
/* */
/* HT_FAIL(sP) */
/* */
/* this macro should expand to a function (which */
/* takes a char const * parameter) to be called */
/* in the event of an error */
/* */
/* HashFunction(unsigned) */
/* */
/* default hash function for integers */
/* */
/* HashFunction(void const *) */
/* */
/* default hash function for pointers */
/* */
/* HashFunction(char const *) */
/* */
/* default hash function for strings */
/* */
/* class HashTable<TYPE> */
/* */
/* hash table template class */
/* TYPE should have == operator defined and an */
/* overloaded HashFunction() defined which can */
/* take an argument type TYPE or suitable */
/* conversion thereof */
/* */
/* HashTable::HashTable() */
/* */
/* constructs an empty table with default table */
/* size */
/* */
/* HashTable::HashTable(unsigned) */
/* */
/* constructs an empty table with specific */
/* table size determined by 2^arg */
/* */
/* bool HashTable::AddChecked(TYPE) */
/* */
/* adds object to hash table unless it already */
/* contains it. Returns non-zero if object was */
/* added, and zero if it was already contained */
/* */
/* void HashTable::AddRegardless(TYPE) */
/* */
/* adds object to hash table but does not check */
/* if it already exists, so duplicates could */
/* occur */
/* */
/* void HashTable::AddAsserted(TYPE) */
/* */
/* adds object to hash table but throws a failure if it */
/* already exists unless NDEBUG is defined in which case */
/* this function is identical to AddRegardless */
/* */
/* TYPE const * HashTable::Contains(TYPE) const */
/* */
/* returns pointer to equivalent entry in table, */
/* or NULL, if none exists */
/* */
/* bool HashTable::Remove(TYPE) */
/* */
/* removes object from table if it exists. */
/* Returns non-zero if object was removed, or */
/* zero if object was not contained */
/* */
/* void HashTable::RemoveAll() */
/* */
/* empties the table */
/* */
/* void HashTable::RemoveAsserted(TYPE) */
/* */
/* removes object from table, but throws a */
/* failure if object was not contained */
/* */
/* unsigned HashTable::Size() const */
/* */
/* returns number of objects in table */
/* */
/* class HashTable<TYPE>::ConstIterator */
/* */
/* class for iterating through objects contained */
/* in hash table, without modifying the contents */
/* of the table */
/* */
/* HashTable::ConstIterator::ConstIterator(HashTable const) */
/* */
/* constructs an iterator linked to a table, */
/* ready for a Get() */
/* */
/* TYPE const & HashTable::ConstIterator::Get() const */
/* HashTable::ConstIterator::operator TYPE const & () const */
/* */
/* gets a constant reference to the object in */
/* the table pointed to by the iterator object */
/* */
/* bool HashTable::ConstIterator::Done() const */
/* */
/* returns non-zero only if there is no more */
/* iterating to do */
/* */
/* void HashTable::ConstIterator::Next() */
/* */
/* moves iterator to a fresh entry in the table */
/* */
/* class HashTable<TYPE>::Iterator */
/* */
/* class for iterating through objects contained */
/* in hash table, allowing their removal */
/* */
/* HashTable::Iterator::Iterator(HashTable) */
/* */
/* constructs an iterator linked to a table, */
/* ready for a Get() */
/* */
/* HashTable::Iterator::Remove() */
/* */
/* removes the current object pointed to by the */
/* iterator from the table, and advances the */
/* iterator to the next entry */
/* */
/*******************************************************Jake*/
/************************************************************/
/* */
/* v1.1 - v1.11 extended functionality */
/* */
/* class HashTable<TYPE>::Node */
/* */
/* this is the internal class for nodes in the table */
/* */
/* TYPE HashTable::Node::d */
/* */
/* this is the value of a node's data */
/* */
/* Node * HashTable::NewNode() */
/* */
/* allocates a node without inserting it into the table; */
/* you are expected to set Node::d to the required value */
/* to be added to the table, and call one of these methods */
/* to link the node into the table */
/* */
/* void HashTable::AddAsserted(Node *) */
/* */
/* like AddAsserted(TYPE const &) but takes a Node * */
/* created with NewNode(); do not use the Node * pointer */
/* after calling this method */
/* */
/* void HashTable::AddRegardless(Node *) */
/* */
/* like AddRegardless(TYPE const &) but takes a Node * */
/* created with NewNode(); do not use the Node * pointer */
/* after calling this method */
/* */
/* bool HashTable::AddChecked(Node *) */
/* */
/* like AddChecked(TYPE const &) but takes a Node * */
/* created with NewNode(); do not use the Node * pointer */
/* after calling this method if it returns true, but if it */
/* returns false (i.e. the Node was not added, then you */
/* can re-use the Node or use the following function to */
/* delete it. */
/* */
/* void HashTable::DeleteNode(Node *) */
/* */
/* destroys a Node created with NewNode. Use this only if */
/* the node created was not added to the hash table */
/* */
/*******************************************************Jake*/
/************************************************************/
/* */
/* v1.2 */
/* */
/* HashTable::Iterator::Restart() */
/* restarts the iterator */
/* */
/* HashTable::HashTable(HashTable<TYPE>) */
/* copy constructor */
/* */
/* HashTable::ValueIterator(unsigned) */
/* iterate through all entries of a specific hashvalue */
/* */
/*******************************************************Alex*/
#ifndef HASH_TEMPLATE_VERSION
#define HASH_TEMPLATE_VERSION 12 // v1.2
#include <stddef.h>
#include <ctype.h>// for toupper
// v1,0 Default Hash Functions defined:
// HashFunction(unsigned), HashFunction(void const *), HashFunction(char const *)
// you can disable the default hash functions by defining HT_NODEFAULTFNS
#ifndef HT_NODEFAULTFNS
// a hash function for integral (unsigned) values
inline unsigned HashFunction(unsigned const _i)
{
return _i ^ _i>>4 ^ _i>>9 ^ _i>>15 ^ _i>>22;
}
// a hash function for pointers
inline unsigned HashFunction(void const * const _vP)
{
// treat as integer
return HashFunction(reinterpret_cast<unsigned>(_vP));
}
// a hash function for strings
inline unsigned HashFunction(char const * _sP)
{
unsigned rv = 0;
while (*_sP) rv += toupper(*_sP++);
return rv;
}
#endif
// v1,0 Default (initial) table size (log2 of)
// Define this to another value if you like,
// or just override in the constructor.
// in v1.0, the table is not self-expanding,
// but if this feature is implememted, then
// this value will become the log2(initial table size),
// and if table becomes is self-contracting,
// this value will also give the minimum table size
#ifndef HT_DEFAULTTABLESIZESHIFT
#define HT_DEFAULTTABLESIZESHIFT 6
#endif
// for asserted functions, define HT_FAIL to be your function
// to be triggered upon a failure, eg.
// #define HT_FAIL(strP) fprintf(stderr,"%s\n",strP)
#ifndef HT_FAIL
#define HT_FAIL(strP) ((void)0)
#endif
template <class TYPE, class ARG_TYPE, class CMP_ARG_TYPE>
class _base_HashTable
{
public:
class Iterator;
class ConstIterator;
class ValueIterator;
class Node;
public:
// V1.0 Functionality
// empty constructor, with argument specifying initial table size (log2 of)
_base_HashTable(unsigned = HT_DEFAULTTABLESIZESHIFT);
// destructor
virtual ~_base_HashTable();
// copy constructor and assignment not provided in v1.0
_base_HashTable(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const &);
_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> & operator = (_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const &);
// add, checking that an equivalent entry does not already exist
// returns non-zero if entry was added
bool AddChecked(ARG_TYPE);
// add, regardless of whether an equivalent entry already exists
void AddRegardless(ARG_TYPE);
// add, checking that an equivalent entry does not already exist
// triggering fail function if one does
void AddAsserted(ARG_TYPE);
// see if entry exists, get pointer to it if it does
TYPE const * Contains(CMP_ARG_TYPE) const;
// remove an entry (once only in the case of equivalent entries listed multiple times)
// returns non-zero if entry existed and was removed
bool Remove(CMP_ARG_TYPE);
// remove an entry (once only in the case of equivalent entries listed multiple times)
// triggers fail function if no entry existed to remove
void RemoveAsserted(CMP_ARG_TYPE);
// empty the table
void RemoveAll();
// return num entries in table
unsigned Size() const;
// a _base_HashTable const iterator
class ConstIterator
{
// Nested class functions apparently have to be declared here for MSVC compatability
public:
// construct from const hash table
ConstIterator(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const & tableR)
: chainPP(tableR.chainPA)
, nChainsRemaining(tableR.tableSize)
, nEntriesRemaining(tableR.nEntries)
{
if (nEntriesRemaining)
{
while (!*chainPP)
{
++ chainPP;
-- nChainsRemaining;
}
nodePP = chainPP;
}
}
// returns non-zero if there are no more entries to get
inline bool Done() const
{
return ! nEntriesRemaining;
}
inline void Restart(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const & tableR)
{
chainPP = tableR.chainPA;
nChainsRemaining = tableR.tableSize;
nEntriesRemaining = tableR.nEntries;
if (nEntriesRemaining)
{
while (!*chainPP)
{
++ chainPP;
-- nChainsRemaining;
}
nodePP = chainPP;
}
}
// get the current entry pointed to, either with Get() or cast operator
inline operator ARG_TYPE () const
{
return Get();
}
inline ARG_TYPE Get() const
{
if( Done() )
{
HT_FAIL("HTT: Tried to Get() from an iterator which was Done()");
}
return (*nodePP)->d;
}
// advance to the next entry
void Next()
{
if (!nEntriesRemaining)
{
HT_FAIL("HTT: Tried to do Next() on an iterator which was Done()");
}
if ((*nodePP)->nextP)
{
nodePP = &(*nodePP)->nextP;
}
else
{
do
{
++ chainPP;
-- nChainsRemaining;
}
while (nChainsRemaining && !*chainPP);
nodePP = chainPP;
}
-- nEntriesRemaining;
}
private:
Node * * chainPP;
Node * * nodePP;
unsigned nChainsRemaining;
unsigned nEntriesRemaining;
friend class Iterator;
};
// a _base_HashTable non-const iterator - can remove entry pointed to
class Iterator : public ConstIterator
{
// Nested class functions apparently have to be declared here for MSVC compatability
public:
// construct from hash table
inline Iterator(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> & tableR)
: ConstIterator(tableR)
, tableNEntriesP(&tableR.nEntries)
{
}
// remove the current entry pointed to, advancing to the next
void Remove()
{
if (!ConstIterator::nEntriesRemaining)
{
HT_FAIL("HTT: Tried to Remove() via an iterator which was Done()");
}
Node * oldP = *ConstIterator::nodePP;
*ConstIterator::nodePP = oldP->nextP;
delete oldP;
if (!*ConstIterator::nodePP)
{
do
{
++ ConstIterator::chainPP;
-- ConstIterator::nChainsRemaining;
}
while (ConstIterator::nChainsRemaining && !*ConstIterator::chainPP);
ConstIterator::nodePP = ConstIterator::chainPP;
}
-- ConstIterator::nEntriesRemaining;
-- *tableNEntriesP;
}
private:
unsigned * tableNEntriesP;
};
// v1.2 extended functionality
// a _base_HashTable iterator through a specific hash value
class ValueIterator
{
// Nested class functions apparently have to be declared here for MSVC compatability
public:
// construct from const hash table
ValueIterator(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> & tableR, unsigned value)
: chainPP(tableR.chainPA)
, value(value)
, tableNEntriesP(&tableR.nEntries)
{
chainPP += (value & tableR.tableSizeMask);
nodePP = chainPP;
}
// returns non-zero if there are no more entries to get
inline bool Done() const
{
return( !(*nodePP) );
}
inline operator ARG_TYPE () const
{
return Get();
}
inline ARG_TYPE Get() const
{
if( Done() )
{
HT_FAIL("HTT: Tried to Get() from an iterator which was Done()");
}
return (*nodePP)->d;
}
inline void Restart(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const & tableR)
{
chainPP = tableR.chainPA + (value & tableR.tableSizeMask);
nodePP = chainPP;
}
// advance to the next entry
void Next()
{
if( *nodePP )
{
nodePP = &(*nodePP)->nextP; // even if it's NULL for ValueIterator
}
else
{
HT_FAIL("HTT: Tried to do Next() on a Value iterator which was Done()");
}
}
// remove the current entry pointed to, advancing to the next
void Remove()
{
if( *nodePP )
{
Node * oldP = *nodePP;
*nodePP = oldP->nextP;
delete oldP;
-- *tableNEntriesP;
}
else
{
HT_FAIL("HTT: Tried to Remove() via an iterator which was Done()");
}
}
private:
Node * * chainPP;
Node * * nodePP;
unsigned value;
unsigned * tableNEntriesP;
};
// V1.1 extended functionality
// allow user to create nodes, change
// the data using this pointer,
// then insert the node into the
// correct chain, without having
// to create a copy of the data to
// be added on the stack
virtual Node * NewNode();
// add, checking that an equivalent entry does not already exist
// triggering fail function if one does
void AddAsserted(Node *);
// add, regardless of whether an equivalent entry already exists
void AddRegardless(Node *);
// V1.11 allows AddChecked for the Node-adding interface
bool AddChecked(Node *);
// if add checked fails, you should avoid the memory leak with this function
virtual void DeleteNode(Node *);
class Node
{
public:
TYPE d;
private:
Node * nextP;
// Nested class functions apparently have to be declared here for MSVC compatability
inline Node(ARG_TYPE _dataR,Node * _nextP)
: d(_dataR)
, nextP(_nextP)
{
}
inline Node()
{
}
inline ~Node()
{
}
void DeleteChain()
{
if (nextP) nextP->DeleteChain();
delete this;
}
friend class ConstIterator;
friend class Iterator;
friend class ValueIterator;
friend class _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>;
};
private:
// virtual functions for future expansion
virtual Node * NewNode(ARG_TYPE,Node *);
unsigned nEntries;
unsigned tableSize;
unsigned tableSizeMask;
Node * * chainPA;
friend class ConstIterator;
friend class Iterator;
friend class ValueIterator;
inline void Xx(){}
};
/*******************/
/* Defined to Fail */
/**************Jake*/
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> & _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::operator = (_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const &)
{
HT_FAIL("HTT: assignment operator not allowed in this version");
return *this;
}
/*******************************/
/* Inline Function Definitions */
/**************************Jake*/
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddRegardless(ARG_TYPE _dataR)
{
Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask];
chainPR = new Node(_dataR,chainPR);
++ nEntries;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddRegardless(Node * _nodeP)
{
Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask];
_nodeP->nextP = chainPR;
chainPR = _nodeP;
++ nEntries;
}
// with NDEBUG on these functions evaluate to be identical to AddRegardless
#ifdef NDEBUG
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddAsserted(ARG_TYPE _dataR)
{
AddRegardless(_dataR);
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddAsserted(Node * _nodeP)
{
AddRegardless(_nodeP);
}
#endif
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline TYPE const * _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Contains(CMP_ARG_TYPE _dataR) const
{
for (Node const * nodeP = chainPA[HashFunction(_dataR) & tableSizeMask]; nodeP; nodeP = nodeP->nextP)
{
if (nodeP->d == _dataR) return &nodeP->d;
}
return NULL;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline unsigned _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Size() const
{
return nEntries;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::RemoveAll()
{
for (unsigned i=0; i<tableSize; ++i)
if (chainPA[i])
{
chainPA[i]->DeleteChain();
chainPA[i] = NULL;
}
nEntries = 0;
}
/*************************************************************/
/* Non inlines declared here since neither Watcom nor */
/* MS Visual C will link if they're in their own source file */
/********************************************************Jake*/
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::_base_HashTable(unsigned _initialTableSizeShift)
: nEntries(0)
, tableSize(1<<_initialTableSizeShift)
, tableSizeMask(tableSize-1)
, chainPA(new Node * [tableSize])
{
for (unsigned i=0; i<tableSize; ++i)
chainPA[i] = NULL;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
inline _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::_base_HashTable(_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE> const & ht)
: nEntries(0)
, tableSize(ht.tableSize)
, tableSizeMask(tableSize-1)
, chainPA(new Node * [tableSize])
{
for (unsigned i=0; i<tableSize; ++i) { chainPA[i] = NULL; }
// for(HashTable<TYPE>::ConstIterator it(ht); !it.Done(); it.Next() )
for (typename _base_HashTable::ConstIterator it(ht); !it.Done(); it.Next() )
{
AddRegardless( it.Get() );
}
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
_base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::~_base_HashTable()
{
for (unsigned i=0; i<tableSize; ++i)
if (chainPA[i])
chainPA[i]->DeleteChain();
delete[] chainPA;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
bool _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddChecked(ARG_TYPE _dataR)
{
Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask];
for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP)
{
if (nodeP->d == _dataR) return false;
}
chainPR = new Node(_dataR,chainPR);
++ nEntries;
return true;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
bool _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddChecked(Node * _nodeP)
{
Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask];
for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP)
{
if (nodeP->d == _nodeP->d) return false;
}
_nodeP->nextP = chainPR;
chainPR = _nodeP;
++ nEntries;
return true;
}
// with NDEBUG on these functions evaluate to be identical to AddRegardless
#ifndef NDEBUG
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddAsserted(ARG_TYPE _dataR)
{
Node * & chainPR = chainPA[HashFunction(_dataR) & tableSizeMask];
for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP)
{
if (nodeP->d == _dataR)
{
HT_FAIL("HTT: Tried to add entry which was already contained in table");
}
}
chainPR = new Node(_dataR,chainPR);
++ nEntries;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::AddAsserted(Node * _nodeP)
{
Node * & chainPR = chainPA[HashFunction(_nodeP->d) & tableSizeMask];
for (Node const * nodeP = chainPR; nodeP; nodeP = nodeP->nextP)
{
if (nodeP->d == _nodeP->d)
{
HT_FAIL("HTT: Tried to add entry which was already contained in table");
}
}
_nodeP->nextP = chainPR;
chainPR = _nodeP;
++ nEntries;
}
#endif
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
bool _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Remove(CMP_ARG_TYPE _dataR)
{
for (Node * * nodePP = &chainPA[HashFunction(_dataR) & tableSizeMask]; (*nodePP); nodePP = &(*nodePP)->nextP)
{
if ((*nodePP)->d == _dataR)
{
Node * oldP = *nodePP;
*nodePP = oldP->nextP;
delete oldP;
-- nEntries;
return true;
}
}
return false;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::RemoveAsserted(CMP_ARG_TYPE _dataR)
{
for (Node * * nodePP = &chainPA[HashFunction(_dataR) & tableSizeMask]; (*nodePP); nodePP = &(*nodePP)->nextP)
{
if ((*nodePP)->d == _dataR)
{
Node * oldP = *nodePP;
*nodePP = oldP->nextP;
delete oldP;
-- nEntries;
return;
}
}
HT_FAIL("HTT: Tried to remove entry which was not contained in table");
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
typename _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Node * _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::NewNode(ARG_TYPE _dataR,Node * _nextP)
{
return new Node(_dataR,_nextP);
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
typename _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::Node * _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::NewNode()
{
return new Node;
}
template <class TYPE,class ARG_TYPE,class CMP_ARG_TYPE>
void _base_HashTable<TYPE,ARG_TYPE,CMP_ARG_TYPE>::DeleteNode(Node * _nodeP)
{
delete _nodeP;
}
template <class TYPE> class HashTable;
#define HT_DEFINITION(T1,T2,T3) \
: public _base_HashTable<T1,T2,T3> { public: HashTable(unsigned _initialTableSizeShift = HT_DEFAULTTABLESIZESHIFT) : _base_HashTable<T1,T2,T3>(_initialTableSizeShift){} };
// for simple types
#define HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE(TYPE) \
class HashTable<TYPE> HT_DEFINITION(TYPE,TYPE,TYPE)
#define HT_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE) template<> HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE(SIMPLE_TYPE)
HT_DEFINE_FOR_SIMPLE_TYPE(unsigned long)
HT_DEFINE_FOR_SIMPLE_TYPE(signed long)
HT_DEFINE_FOR_SIMPLE_TYPE(unsigned)
HT_DEFINE_FOR_SIMPLE_TYPE(signed)
HT_DEFINE_FOR_SIMPLE_TYPE(unsigned short)
HT_DEFINE_FOR_SIMPLE_TYPE(signed short)
HT_DEFINE_FOR_SIMPLE_TYPE(unsigned char)
HT_DEFINE_FOR_SIMPLE_TYPE(signed char)
HT_DEFINE_FOR_SIMPLE_TYPE(char)
HT_DEFINE_FOR_SIMPLE_TYPE(float)
#undef HT_DEFINE_FOR_SIMPLE_TYPE
#undef HT_WATCOM_DEFINE_FOR_SIMPLE_TYPE
// for pointer types
#if 0 // doesnt't compile!!
template <class TYPE>
class HashTable<TYPE *> HT_DEFINITION(TYPE *, TYPE *, TYPE const *)
template <class TYPE>
class HashTable<TYPE const *> HT_DEFINITION(TYPE const *, TYPE const *, TYPE const *)
#endif
// for other types
template <class TYPE>
class HashTable HT_DEFINITION(TYPE,TYPE const &, TYPE const &)
//template <class TYPE *> class HashTable : public _base_HashTable<TYPE *,TYPE *,TYPE const *> {};
#undef HT_DEFINITION
#endif // ! HASH_TEMPLATE_VERSION
|