-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathsets.H
More file actions
665 lines (575 loc) · 20 KB
/
sets.H
File metadata and controls
665 lines (575 loc) · 20 KB
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
// Note that until the bug in egcs-2.90.27 980315 (egcs-1.0.2 release)
// gets fixed this file needs to be compiled with -fguiding-decls.
// Trying to fix the warning caused by compileing without -fguiding-decls
// causes an internal compiler error.
#ifndef _INC_SETS_DOT_H
#define _INC_SETS_DOT_H
#include<stdio.h>
#include<stdlib.h>
#include<iostream>
#include<ostream>
#include<strstream>
#include<ctype.h>
extern "C" {
#include<tcl/tcl.h>
}
// **********************************************************************
//
// See the html documentation for how to use these classes
//
// This file implements sets through tcl hash tables.
//
// **********************************************************************
// The SetDatabase is intended to be accessed only by the SetDatabaseHandle
// class. This allows an instance of SetDatabase to be pointed
// to by an aribtrary number of SetDatabaseHandle instances. When
// the last SetDatabaseHandle instance stops pointing to a database,
// the database deletes itself.
//
// The advantages of this approach are:
//
// (1) If more than one thing wants to point to a given database,
// we don't have to make copies of the database or jump through
// hoops to make sure memory is managed properly.
//
// (2) Passing the database around is much easier because no class
// that holds the database has to worry about who owns the
// database.
typedef Tcl_HashEntry * SetEntryToken;
const SetEntryToken STE_NULL_TOKEN = NULL;
template <class KeyClass, class ValueClass> class SetDatabaseHandle;
template <class KeyClass, class ValueClass> class SetDatabaseHandleIterator;
template <class KeyClass, class ValueClass>
class SetDatabase {
friend class SetDatabaseHandleIterator<KeyClass,ValueClass>;
friend class SetDatabaseHandle<KeyClass,ValueClass>;
/*
friend std::ostream & operator<<<KeyClass, ValueClass>(std::ostream & s, const SetDatabase & d);
friend std::istream & operator>><KeyClass, ValueClass>(std::istream & s, SetDatabase & d);
*/
public:
inline int GetKeyType() const {return databaseKeyType;}
inline int Size() const {return itemsInTable;}
// WARNING: DANGER: casting going on here
ValueClass Search( const KeyClass key, int * found) const
{
Tcl_HashEntry * entry =
Tcl_FindHashEntry((Tcl_HashTable*)(&hashTable), (char *) key);
if (entry == NULL) {
if (found != NULL) *found = 0;
return (ValueClass) NULL;
}
if (found != NULL) *found = 1;
return (ValueClass) Tcl_GetHashValue(entry);
}
void ForEachItemInSetDo(void (*function)(KeyClass key,ValueClass value))
{
Tcl_HashSearch searchPtr;
Tcl_HashEntry * currentEntry = Tcl_FirstHashEntry(&hashTable, &searchPtr);
while (currentEntry != NULL) {
KeyClass key = (KeyClass) Tcl_GetHashKey(&hashTable,currentEntry);
ValueClass value = (ValueClass ) Tcl_GetHashValue(currentEntry);
function(key,value);
currentEntry = Tcl_NextHashEntry(&searchPtr);
}
}
void ForEachItemInSetDo(void (*function)(KeyClass key,ValueClass value,
void * extraArg),
void * extraArgForFunction)
{
Tcl_HashSearch searchPtr;
Tcl_HashEntry * currentEntry = Tcl_FirstHashEntry(&hashTable, &searchPtr);
while (currentEntry != NULL) {
KeyClass key = (KeyClass) Tcl_GetHashKey(&hashTable,currentEntry);
ValueClass value = (ValueClass ) Tcl_GetHashValue(currentEntry);
function(key,value,extraArgForFunction);
currentEntry = Tcl_NextHashEntry(&searchPtr);
}
}
int Add( const KeyClass & key, const ValueClass object,
ValueClass * oldObject , SetEntryToken * token)
{
int notAlreadyInTable;
InvalidateIteratorsAttachedToThisDatabase();
*token = Tcl_CreateHashEntry(&hashTable, (char *) key, ¬AlreadyInTable);
if (notAlreadyInTable)
itemsInTable++;
else *oldObject = (ValueClass) Tcl_GetHashValue(*token);
Tcl_SetHashValue(*token,object);
return notAlreadyInTable;
}
int Add( const KeyClass & key, const ValueClass object, SetEntryToken * token)
{
int notAlreadyInTable;
InvalidateIteratorsAttachedToThisDatabase();
*token = Tcl_CreateHashEntry(&hashTable, (char *) key, ¬AlreadyInTable);
if (notAlreadyInTable)
itemsInTable++;
Tcl_SetHashValue(*token,object);
return notAlreadyInTable;
}
int Add( const KeyClass & key, const ValueClass object)
{
int notAlreadyInTable;
InvalidateIteratorsAttachedToThisDatabase();
Tcl_HashEntry * newEntry =
Tcl_CreateHashEntry(&hashTable, (char *) key, ¬AlreadyInTable);
if (notAlreadyInTable)
itemsInTable++;
Tcl_SetHashValue(newEntry,object);
return notAlreadyInTable;
}
void DeleteEntryForToken(SetEntryToken token)
{
InvalidateIteratorsAttachedToThisDatabase();
Tcl_DeleteHashEntry(token);
itemsInTable--;
}
ValueClass Delete( const KeyClass & key, int * found)
{
ValueClass returnValue = (ValueClass) NULL;
Tcl_HashEntry * entry = Tcl_FindHashEntry(&hashTable, (char *) key);
if (entry != NULL) {
InvalidateIteratorsAttachedToThisDatabase();
itemsInTable--;
returnValue = (ValueClass ) Tcl_GetHashValue(entry);
Tcl_DeleteHashEntry(entry);
if (found != NULL) *found = 1;
} else
if (found != NULL) *found = 0;
return returnValue;
}
protected:
SetDatabase(int typeOfKeys)
:numberOfHandlesToThisObject(0), _numberRefs(0),
databaseKeyType(typeOfKeys) ,
itemsInTable(0), _IDNumber(0)
{
Tcl_InitHashTable(&hashTable, typeOfKeys);
}
~SetDatabase()
{
Tcl_DeleteHashTable(&hashTable);
}
bool MatchesIDNumber(const int IDNumber) {return IDNumber == _IDNumber;}
void InvalidateIteratorsAttachedToThisDatabase()
{
#ifdef CHECK_ASSUMPTIONS
_IDNumber++;
#endif
}
int numberOfHandlesToThisObject;
int _numberRefs;
Tcl_HashTable hashTable;
int databaseKeyType;
int itemsInTable;
private:
SetDatabase( const SetDatabase &); // no one should use this!
int _IDNumber;
};
template <class KeyClass, class ValueClass>
class SetDatabaseHandle {
/*
friend class SetDatabaseHandleIterator<KeyClass,ValueClass>;
friend SetDatabaseHandle operator&<KeyClass, ValueClass>
(SetDatabaseHandle&, SetDatabaseHandle &);
friend SetDatabaseHandle operator|<KeyClass, ValueClass>
(SetDatabaseHandle &, SetDatabaseHandle &);
friend SetDatabaseHandle operator-<KeyClass, ValueClass>
(SetDatabaseHandle &, SetDatabaseHandle &);
friend std::ostream& operator<<<KeyClass, ValueClass>
(std::ostream&,const SetDatabaseHandle<KeyClass,ValueClass>&);
friend std::istream& operator>><KeyClass, ValueClass>
(std::istream&,SetDatabaseHandle<KeyClass,ValueClass>&);
*/
public:
SetDatabaseHandle(int typeOfKeys)
:database(new SetDatabase<KeyClass,ValueClass>(typeOfKeys))
{
GrabDb(database);
}
SetDatabaseHandle(SetDatabase<KeyClass,ValueClass> * d)
:database(d)
{
GrabDb(d);
}
SetDatabaseHandle(SetDatabaseHandle * c)
:database(c->database)
{
GrabDb(c->database);
}
SetDatabaseHandle( const SetDatabaseHandle & c)
:database(c.database)
{
GrabDb(c.database);
}
~SetDatabaseHandle()
{
LetGoDb(database);
}
SetDatabaseHandle & operator=(const SetDatabaseHandle &);
bool operator==(const SetDatabaseHandle &);
bool operator!=(const SetDatabaseHandle &);
inline void ForEachItemInSetDo(void (*function)(KeyClass key,
ValueClass value))
{
database->ForEachItemInSetDo(function);
}
inline void ForEachItemInSetDo(void (*function)(KeyClass , ValueClass ,
void * extraArg),
void * extraArgForFunction)
{
database->ForEachItemInSetDo(function,extraArgForFunction);
}
inline int Size() const {return database->Size();}
inline ValueClass Search( const KeyClass object, int * found = NULL) const
{
return database->Search(object,found);
}
inline ValueClass Delete(KeyClass k,int * found = NULL)
{return database->Delete(k,found);}
inline void DeleteEntryForToken(SetEntryToken token)
{database->DeleteEntryForToken(token);}
inline int Add( const KeyClass & key, const ValueClass object)
{
return database->Add(key,object);
}
inline int Add
( const KeyClass & key, const ValueClass object, SetEntryToken * token)
{
return database->Add(key,object,token);
}
inline int Add
( const KeyClass & key, const ValueClass object,
ValueClass * oldObject, SetEntryToken * token)
{
return database->Add(key,object,oldObject,token);
}
protected:
// The LetGoDb function decrements the number of things pointing
// to s by 1. If the number of things pointing to s goes below
// 1, then s is delete'd. This handles the memory management
// for the SetDatabase class pointed to by the SetDatabaseHandles.
void LetGoDb(SetDatabase<KeyClass,ValueClass> * s){
if (--(s->numberOfHandlesToThisObject) < 1) delete s;}
// The Grab function increments the number of things pointing
// to s by 1. See the comment for the LetGoDb function for
// more information.
void GrabDb(SetDatabase<KeyClass,ValueClass> * s)
{s->numberOfHandlesToThisObject++;}
bool MatchesIDNumber(const int IDNumber) const
{return database->MatchesIDNumber(IDNumber);}
inline Tcl_HashTable * GetDatabaseHashTable(){return &(database->hashTable);}
SetDatabase<KeyClass,ValueClass> * database;
// these two routines are for maintaining a count of references
// to values inside the database, because the database should not
// be deleted if the number of refs != 0
void LetGoRef()
{database->_numberRefs--;}
void GrabRef()
{database->_numberRefs++;}
bool HasRef() const
{return (database->_numberRefs != 0);}
// indicate if this is the only handle
// may be needed to delete objects if this handle is about to die
bool OnlyHandle() const
{return (database->numberOfHandlesToThisObject == 1);}
};
/* **********************************************************************
*
* FUNCTION: AndDatabases
*
* INPUTS: smaller is the smaller Tcl_HashTable to and with larger
* larger is the larger Tcl_HashTable to and with smaller
* result is where the (smaller & larger) is stored.
*
* OUTPUT: none
*
* PURPOSE: This function goes through every item in smaller.
* Each item that is also present in larger is added
* to result. This function is meant to be used bye operator&.
*
* MODIFIED: Emin Martinian, emin@iname.com, Wed Jan 14 13:08:57 PST 1998
*
********************************************************************** */
template <class KeyClass, class ValueClass>
void AndDatabases(Tcl_HashTable * smaller,
Tcl_HashTable * larger,
SetDatabase<KeyClass,ValueClass> * result)
{
Tcl_HashSearch searchPtr;
Tcl_HashEntry * currentEntry = Tcl_FirstHashEntry(smaller, &searchPtr);
while (currentEntry != NULL) {
KeyClass key = (KeyClass) Tcl_GetHashKey(smaller,currentEntry);
if (NULL != Tcl_FindHashEntry(larger, (char *) key))
result->Add(key,(ValueClass) Tcl_GetHashValue(currentEntry));
currentEntry = Tcl_NextHashEntry(&searchPtr);
}
}
/* **********************************************************************
*
* FUNCTION: SubtractDatabases
*
* INPUTS: negative is the database to be subtracted from positive
* result is set to contain everything in positive that is
* not in negative.
*
* OUTPUT: none
*
* PURPOSE: This "Subtracts" everything in the negative hash table
* from the positive hash table and stores the result in
* result. This function is meant to be used by operator-.
*
* MODIFIED: Emin Martinian, emin@iname.com, Wed Jan 14 13:11:06 PST 1998
*
********************************************************************** */
template <class KeyClass, class ValueClass>
void SubtractDatabases(Tcl_HashTable * positive,
Tcl_HashTable * negative,
SetDatabase<KeyClass, ValueClass> * result)
{
Tcl_HashSearch searchPtr;
Tcl_HashEntry * currentEntry = Tcl_FirstHashEntry(positive, &searchPtr);
while (currentEntry != NULL) {
KeyClass key = (KeyClass) Tcl_GetHashKey(positive,currentEntry);
if (NULL == Tcl_FindHashEntry(negative, (char *) key))
result->Add(key,(ValueClass ) Tcl_GetHashValue(currentEntry));
currentEntry = Tcl_NextHashEntry(&searchPtr);
}
}
/* **********************************************************************
*
* FUNCTION: MergeDatabases
*
* INPUTS: Everything in the input hash table is put into the
* result database.
*
* OUTPUT: none
*
* PURPOSE: This puts everything in input into result to implement
* operator|.
*
* MODIFIED: Emin Martinian, emin@iname.com, Wed Jan 14 13:39:24 PST 1998
*
********************************************************************** */
template <class KeyClass, class ValueClass>
void MergeDatabases(Tcl_HashTable * input,
SetDatabase<KeyClass,ValueClass> * result)
{
Tcl_HashSearch searchPtr;
Tcl_HashEntry * currentEntry = Tcl_FirstHashEntry(input, &searchPtr);
while (currentEntry != NULL) {
result->Add((KeyClass) Tcl_GetHashKey(input,currentEntry),
(ValueClass ) Tcl_GetHashValue(currentEntry));
currentEntry = Tcl_NextHashEntry(&searchPtr);
}
}
/* **********************************************************************
*
* FUNCTION: operator|
*
* INPUTS: a and b are SetDatabaseHandles to combine
*
* OUTPUT: returns a SetDatabaseHandle containing everything in a and b.
*
* PURPOSE: This is used to implement a union of the two input sets.
*
* MODIFIED: Emin Martinian, emin@iname.com, Wed Jan 14 13:41:02 PST 1998
*
********************************************************************** */
template <class KeyClass, class ValueClass>
SetDatabaseHandle<KeyClass,ValueClass>
operator|(SetDatabaseHandle<KeyClass,ValueClass> & a,
SetDatabaseHandle<KeyClass,ValueClass> & b)
{
ASSUME(a.database->GetKeyType() == b.database->GetKeyType());
SetDatabaseHandle<KeyClass,ValueClass> result(a.database->GetKeyType());
MergeDatabases(a.GetDatabaseHashTable(),result.database);
MergeDatabases(b.GetDatabaseHashTable(),result.database);
return result;
}
/* **********************************************************************
*
* FUNCTION: operator&
*
* INPUTS: a and b are SetDatabaseHandles to intersect
*
* OUTPUT: returns a new SetDatabaseHandle containing the intersection
* of a nd b.
*
* PURPOSE: This is used to implement the intersection of two sets.
*
* MODIFIED: Emin Martinian, emin@iname.com, Wed Jan 14 13:42:27 PST 1998
*
********************************************************************** */
template <class KeyClass, class ValueClass>SetDatabaseHandle<KeyClass,ValueClass>
operator&(SetDatabaseHandle<KeyClass,ValueClass> & a,
SetDatabaseHandle<KeyClass,ValueClass> & b)
{
ASSUME(a.database->GetKeyType() == b.database->GetKeyType());
SetDatabaseHandle<KeyClass,ValueClass> result(a.database->GetKeyType());
if (a.database->Size() < b.database->Size())
AndDatabases(a.GetDatabaseHashTable(),
b.GetDatabaseHashTable(),
result.database);
else
AndDatabases(b.GetDatabaseHashTable(),
a.GetDatabaseHashTable(),
result.database);
return result;
}
/* **********************************************************************
*
* FUNCTION: operator-
*
* INPUTS: b is subtracted from a
*
* OUTPUT: Returns a new SetDatabaseHandle containing everything that
* is in a but not in b.
*
* PURPOSE: This implements subtraction of sets.
*
* MODIFIED: Emin Martinian, emin@iname.com, Wed Jan 14 13:43:31 PST 1998
*
********************************************************************** */
template <class KeyClass, class ValueClass>SetDatabaseHandle<KeyClass,ValueClass>
operator-(SetDatabaseHandle<KeyClass,ValueClass> &a,
SetDatabaseHandle<KeyClass,ValueClass> &b)
{
ASSUME(a.database->GetKeyType() == b.database->GetKeyType());
SetDatabaseHandle<KeyClass,ValueClass> result(a.database->GetKeyType());
SubtractDatabases(a.GetDatabaseHashTable(),
b.GetDatabaseHashTable(),
result.database);
return result;
}
template <class KeyClass, class ValueClass>
SetDatabaseHandle<KeyClass,ValueClass> &
SetDatabaseHandle<KeyClass,ValueClass>::operator=
(const SetDatabaseHandle<KeyClass,ValueClass> & other)
{
if (other.database != database) {
LetGoDb(database);
database = other.database;
GrabDb(database);
}
return *this;
}
template <class KeyClass, class ValueClass>
bool
SetDatabaseHandle<KeyClass,ValueClass>::operator==
(const SetDatabaseHandle<KeyClass,ValueClass> & other)
{
return (other.database == database);
}
template <class KeyClass, class ValueClass>
bool
SetDatabaseHandle<KeyClass,ValueClass>::operator!=
(const SetDatabaseHandle<KeyClass,ValueClass> & other)
{
return (other.database != database);
}
template <class KeyClass, class ValueClass>
std::ostream & operator<<(std::ostream & s,
const SetDatabase<KeyClass,ValueClass> & d)
{
Tcl_HashSearch searchPtr;
Tcl_HashEntry * currentEntry =
Tcl_FirstHashEntry((Tcl_HashTable *) // this cast discards the const
&(d.hashTable), &searchPtr);
while (currentEntry != NULL) {
KeyClass key = Tcl_GetHashKey(&(d.hashTable),currentEntry);
s << "{{" << (KeyClass) key << "} ";
s << "{" << (ValueClass) Tcl_GetHashValue(currentEntry) << "}} " ;
currentEntry = Tcl_NextHashEntry(&searchPtr);
}
return s;
}
template <class KeyClass, class ValueClass>
std::ostream & operator<<(std::ostream & s,
const SetDatabaseHandle<KeyClass,ValueClass> & h)
{
s << *(h.database);
return s;
}
/* FIXME
template <class KeyClass, class ValueClass>
std::istream & operator>>(std::istream & s, SetDatabase<KeyClass,ValueClass> & d)
{
char c;
char ** mainArgv = NULL;
char ** subArgv = NULL;
int mainArgc, subArgc, notInteger, index;
char * inputString = NULL;
while ( (s >> c) && (isspace(c)) ); // eat up white space
if ( (!s) || (c != '{') ) goto stopBecauseOfError;
s.putback(c);
s.gets(&inputString);
if (!s) goto stopBecauseOfError;
if (TCL_OK != (Tcl_SplitList(NULL,inputString,&mainArgc,&mainArgv)))
goto stopBecauseOfError;
for (int i = 0; i < mainArgc; ++i) {
if ( (TCL_OK != (Tcl_SplitList(NULL,mainArgv[i],&subArgc,&subArgv)))
|| (subArgc != 2) ) goto stopBecauseOfError;
index = strtintOnlyCheck(subArgv[1],¬Integer);
if (notInteger || (! d.Add(subArgv[0], index))) goto stopBecauseOfError;
Tcl_Free((char*) subArgv);
subArgv = NULL;
}
delete [] inputString;
Tcl_Free( (char*) mainArgv);
return s;
stopBecauseOfError:
if (mainArgv != NULL) Tcl_Free( (char*) mainArgv);
if (subArgv != NULL) Tcl_Free( (char*) subArgv);
s.clear(ios::badbit); // set state of stream to bad;
if (inputString != NULL) delete [] inputString;
return s;
}
*/
template <class KeyClass, class ValueClass>
std::istream & operator>>(std::istream & s,
SetDatabaseHandle<KeyClass,ValueClass> & h)
{
s >> *(h.database);
return s;
}
template <class KeyType, class ValueType>
class SetDatabaseHandleIterator {
public:
SetDatabaseHandleIterator(SetDatabaseHandle<KeyType,ValueType> const & handle)
:_handle(handle), _IDNumber(handle.database->_IDNumber),
_currentHashEntry(Tcl_FirstHashEntry(&_handle.database->hashTable,&_searchPtr))
{ }
inline bool ItemsRemaining()
{
return _currentHashEntry != NULL;
}
inline KeyType GetCurrentKey()
{
ASSUME( ItemsRemaining() );
ASSUME( _handle.MatchesIDNumber(_IDNumber) );
return (KeyType) Tcl_GetHashKey(&_handle.database->hashTable,_currentHashEntry);
}
inline ValueType GetCurrentValue()
{
ASSUME( ItemsRemaining() );
ASSUME( _handle.MatchesIDNumber(_IDNumber) );
return (ValueType) Tcl_GetHashValue(_currentHashEntry);
}
KeyType operator++(int) // postfix operator
{
ASSUME(ItemsRemaining());
ASSUME( _handle.MatchesIDNumber(_IDNumber) );
KeyType returnValue =
(KeyType) Tcl_GetHashKey(&_handle.database->hashTable,_currentHashEntry);
_currentHashEntry = Tcl_NextHashEntry(&_searchPtr);
return returnValue;
}
protected:
const SetDatabaseHandle<KeyType,ValueType> & _handle;
int _IDNumber;
Tcl_HashSearch _searchPtr;
Tcl_HashEntry * _currentHashEntry;
};
#endif