]>
git.saurik.com Git - wxWidgets.git/blob - src/common/hash.cpp
   1 ///////////////////////////////////////////////////////////////////////////// 
   3 // Purpose:     wxHashTable implementation 
   4 // Author:      Julian Smart 
   5 // Modified by: VZ at 25.02.00: type safe hashes with WX_DECLARE_HASH() 
   8 // Copyright:   (c) Julian Smart 
   9 // Licence:     wxWindows licence 
  10 ///////////////////////////////////////////////////////////////////////////// 
  12 // ============================================================================ 
  14 // ============================================================================ 
  16 // ---------------------------------------------------------------------------- 
  18 // ---------------------------------------------------------------------------- 
  20 #if defined(__GNUG__) && !defined(NO_GCC_PRAGMA) 
  21 #pragma implementation "hash.h" 
  24 // For compilers that support precompilation, includes "wx.h". 
  25 #include "wx/wxprec.h" 
  42 // ---------------------------------------------------------------------------- 
  44 // ---------------------------------------------------------------------------- 
  46 IMPLEMENT_DYNAMIC_CLASS(wxHashTable
, wxObject
) 
  48 // ============================================================================ 
  50 // ============================================================================ 
  52 // ---------------------------------------------------------------------------- 
  53 // wxHashTablleBase for working with "void *" data 
  54 // ---------------------------------------------------------------------------- 
  56 wxHashTableBase::wxHashTableBase() 
  58     m_deleteContents 
= FALSE
; 
  59     m_hashTable 
= (wxListBase 
**)NULL
; 
  62     m_keyType 
= wxKEY_NONE
; 
  65 void wxHashTableBase::Create(wxKeyType keyType
, size_t size
) 
  71     m_hashTable 
= new wxListBase 
*[size
]; 
  72     for ( size_t n 
= 0; n 
< m_hashSize
; n
++ ) 
  74         m_hashTable
[n
] = (wxListBase 
*) NULL
; 
  78 void wxHashTableBase::Destroy() 
  82         for ( size_t n 
= 0; n 
< m_hashSize
; n
++ ) 
  84             delete m_hashTable
[n
]; 
  87         delete [] m_hashTable
; 
  89         m_hashTable 
= (wxListBase 
**)NULL
; 
  95 void wxHashTableBase::DeleteContents(bool flag
) 
  97     m_deleteContents 
= flag
; 
  98     for ( size_t n 
= 0; n 
< m_hashSize
; n
++ ) 
 100         if ( m_hashTable
[n
] ) 
 102             m_hashTable
[n
]->DeleteContents(flag
); 
 107 wxNodeBase 
*wxHashTableBase::GetNode(long key
, long value
) const 
 109     size_t slot 
= (size_t)abs((int)(key 
% (long)m_hashSize
)); 
 112     if ( m_hashTable
[slot
] ) 
 114         node 
= m_hashTable
[slot
]->Find(wxListKey(value
)); 
 118         node 
= (wxNodeBase 
*)NULL
; 
 124 #if WXWIN_COMPATIBILITY_2_4 
 126 // ---------------------------------------------------------------------------- 
 128 // ---------------------------------------------------------------------------- 
 130 wxHashTableLong::~wxHashTableLong() 
 135 void wxHashTableLong::Init(size_t size
) 
 138     m_values 
= new wxArrayLong 
*[size
]; 
 139     m_keys 
= new wxArrayLong 
*[size
]; 
 141     for ( size_t n 
= 0; n 
< m_hashSize
; n
++ ) 
 144         m_keys
[n
] = (wxArrayLong 
*)NULL
; 
 150 void wxHashTableLong::Create(size_t size
) 
 155 void wxHashTableLong::Destroy() 
 157     for ( size_t n 
= 0; n 
< m_hashSize
; n
++ ) 
 169 void wxHashTableLong::Put(long key
, long value
) 
 171     wxCHECK_RET( m_hashSize
, _T("must call Create() first") ); 
 173     size_t slot 
= (size_t)abs((int)(key 
% (long)m_hashSize
)); 
 177         m_keys
[slot
] = new wxArrayLong
; 
 178         m_values
[slot
] = new wxArrayLong
; 
 181     m_keys
[slot
]->Add(key
); 
 182     m_values
[slot
]->Add(value
); 
 187 long wxHashTableLong::Get(long key
) const 
 189     wxCHECK_MSG( m_hashSize
, wxNOT_FOUND
, _T("must call Create() first") ); 
 191     size_t slot 
= (size_t)abs((int)(key 
% (long)m_hashSize
)); 
 193     wxArrayLong 
*keys 
= m_keys
[slot
]; 
 196         size_t count 
= keys
->GetCount(); 
 197         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 199             if ( keys
->Item(n
) == key 
) 
 201                 return m_values
[slot
]->Item(n
); 
 209 long wxHashTableLong::Delete(long key
) 
 211     wxCHECK_MSG( m_hashSize
, wxNOT_FOUND
, _T("must call Create() first") ); 
 213     size_t slot 
= (size_t)abs((int)(key 
% (long)m_hashSize
)); 
 215     wxArrayLong 
*keys 
= m_keys
[slot
]; 
 218         size_t count 
= keys
->GetCount(); 
 219         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 221             if ( keys
->Item(n
) == key 
) 
 223                 long val 
= m_values
[slot
]->Item(n
); 
 226                 m_values
[slot
]->RemoveAt(n
); 
 238 // ---------------------------------------------------------------------------- 
 239 // wxStringHashTable: more efficient than storing strings in a list 
 240 // ---------------------------------------------------------------------------- 
 242 wxStringHashTable::wxStringHashTable(size_t sizeTable
) 
 244     m_keys 
= new wxArrayLong 
*[sizeTable
]; 
 245     m_values 
= new wxArrayString 
*[sizeTable
]; 
 247     m_hashSize 
= sizeTable
; 
 248     for ( size_t n 
= 0; n 
< m_hashSize
; n
++ ) 
 250         m_values
[n
] = (wxArrayString 
*)NULL
; 
 251         m_keys
[n
] = (wxArrayLong 
*)NULL
; 
 255 wxStringHashTable::~wxStringHashTable() 
 260 void wxStringHashTable::Destroy() 
 262     for ( size_t n 
= 0; n 
< m_hashSize
; n
++ ) 
 273 void wxStringHashTable::Put(long key
, const wxString
& value
) 
 275     wxCHECK_RET( m_hashSize
, _T("must call Create() first") ); 
 277     size_t slot 
= (size_t)abs((int)(key 
% (long)m_hashSize
)); 
 281         m_keys
[slot
] = new wxArrayLong
; 
 282         m_values
[slot
] = new wxArrayString
; 
 285     m_keys
[slot
]->Add(key
); 
 286     m_values
[slot
]->Add(value
); 
 289 wxString 
wxStringHashTable::Get(long key
, bool *wasFound
) const 
 291     wxCHECK_MSG( m_hashSize
, _T(""), _T("must call Create() first") ); 
 293     size_t slot 
= (size_t)abs((int)(key 
% (long)m_hashSize
)); 
 295     wxArrayLong 
*keys 
= m_keys
[slot
]; 
 298         size_t count 
= keys
->GetCount(); 
 299         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 301             if ( keys
->Item(n
) == key 
) 
 306                 return m_values
[slot
]->Item(n
); 
 317 bool wxStringHashTable::Delete(long key
) const 
 319     wxCHECK_MSG( m_hashSize
, FALSE
, _T("must call Create() first") ); 
 321     size_t slot 
= (size_t)abs((int)(key 
% (long)m_hashSize
)); 
 323     wxArrayLong 
*keys 
= m_keys
[slot
]; 
 326         size_t count 
= keys
->GetCount(); 
 327         for ( size_t n 
= 0; n 
< count
; n
++ ) 
 329             if ( keys
->Item(n
) == key 
) 
 332                 m_values
[slot
]->RemoveAt(n
); 
 341 #endif // WXWIN_COMPATIBILITY_2_4 
 343 // ---------------------------------------------------------------------------- 
 344 // old not type safe wxHashTable 
 345 // ---------------------------------------------------------------------------- 
 347 wxHashTable::wxHashTable (int the_key_type
, int size
) 
 350   hash_table 
= (wxList
**) NULL
; 
 351   Create(the_key_type
, size
); 
 353   m_deleteContents 
= FALSE
; 
 356   current_position = -1; 
 357   current_node = (wxNode *) NULL; 
 359   key_type = the_key_type; 
 360   hash_table = new wxList *[size]; 
 362   for (i = 0; i < size; i++) 
 363     hash_table[i] = (wxList *) NULL; 
 367 wxHashTable::~wxHashTable () 
 372 void wxHashTable::Destroy() 
 374   if (!hash_table
) return; 
 376   for (i 
= 0; i 
< n
; i
++) 
 378       delete hash_table
[i
]; 
 383 bool wxHashTable::Create(int the_key_type
, int size
) 
 388   current_position 
= -1; 
 389   current_node 
= (wxNode 
*) NULL
; 
 391   key_type 
= the_key_type
; 
 392   hash_table 
= new wxList 
*[size
]; 
 394   for (i 
= 0; i 
< size
; i
++) 
 395     hash_table
[i
] = (wxList 
*) NULL
; 
 400 void wxHashTable::DoCopy(const wxHashTable
& table
) 
 403   m_count 
= table
.m_count
; 
 404   current_position 
= table
.current_position
; 
 405   current_node 
= NULL
; // doesn't matter - Next() will reconstruct it 
 406   key_type 
= table
.key_type
; 
 408   hash_table 
= new wxList 
*[n
]; 
 409   for (int i 
= 0; i 
< n
; i
++) { 
 410     if (table
.hash_table
[i
] == NULL
) 
 411       hash_table
[i
] = NULL
; 
 413       hash_table
[i
] = new wxList(key_type
); 
 414       *(hash_table
[i
]) = *(table
.hash_table
[i
]); 
 419 void wxHashTable::Put (long key
, long value
, wxObject 
* object
) 
 424   int position 
= (int) (k 
% n
); 
 425   if (position 
< 0) position 
= -position
; 
 427   if (!hash_table
[position
]) 
 429     hash_table
[position
] = new wxList (wxKEY_INTEGER
); 
 430     if (m_deleteContents
) hash_table
[position
]->DeleteContents(TRUE
); 
 433   hash_table
[position
]->Append (value
, object
); 
 437 void wxHashTable::Put (long key
, const wxChar 
*value
, wxObject 
* object
) 
 442   int position 
= (int) (k 
% n
); 
 443   if (position 
< 0) position 
= -position
; 
 445   if (!hash_table
[position
]) 
 447     hash_table
[position
] = new wxList (wxKEY_STRING
); 
 448     if (m_deleteContents
) hash_table
[position
]->DeleteContents(TRUE
); 
 451   hash_table
[position
]->Append (value
, object
); 
 455 void wxHashTable::Put (long key
, wxObject 
* object
) 
 460   int position 
= (int) (k 
% n
); 
 461   if (position 
< 0) position 
= -position
; 
 463   if (!hash_table
[position
]) 
 465     hash_table
[position
] = new wxList (wxKEY_INTEGER
); 
 466     if (m_deleteContents
) hash_table
[position
]->DeleteContents(TRUE
); 
 469   hash_table
[position
]->Append (k
, object
); 
 473 void wxHashTable::Put (const wxChar 
*key
, wxObject 
* object
) 
 475   int position 
= (int) (MakeKey (key
) % n
); 
 476   if (position 
< 0) position 
= -position
; 
 478   if (!hash_table
[position
]) 
 480     hash_table
[position
] = new wxList (wxKEY_STRING
); 
 481     if (m_deleteContents
) hash_table
[position
]->DeleteContents(TRUE
); 
 484   hash_table
[position
]->Append (key
, object
); 
 488 wxObject 
*wxHashTable::Get (long key
, long value
) const 
 493   int position 
= (int) (k 
% n
); 
 494   if (position 
< 0) position 
= -position
; 
 496   if (!hash_table
[position
]) 
 497     return (wxObject 
*) NULL
; 
 500       wxNode 
*node 
= hash_table
[position
]->Find (value
); 
 502         return node
->GetData (); 
 504         return (wxObject 
*) NULL
; 
 508 wxObject 
*wxHashTable::Get (long key
, const wxChar 
*value
) const 
 513   int position 
= (int) (k 
% n
); 
 514   if (position 
< 0) position 
= -position
; 
 516   if (!hash_table
[position
]) 
 517     return (wxObject 
*) NULL
; 
 520       wxNode 
*node 
= hash_table
[position
]->Find (value
); 
 522         return node
->GetData (); 
 524         return (wxObject 
*) NULL
; 
 528 wxObject 
*wxHashTable::Get (long key
) const 
 533   int position 
= (int) (k 
% n
); 
 534   if (position 
< 0) position 
= -position
; 
 536   if (!hash_table
[position
]) 
 537     return (wxObject 
*) NULL
; 
 540       wxNode 
*node 
= hash_table
[position
]->Find (k
); 
 541       return node 
? node
->GetData () : (wxObject
*)NULL
; 
 545 wxObject 
*wxHashTable::Get (const wxChar 
*key
) const 
 547   int position 
= (int) (MakeKey (key
) % n
); 
 548   if (position 
< 0) position 
= -position
; 
 550   if (!hash_table
[position
]) 
 551     return (wxObject 
*) NULL
; 
 554       wxNode 
*node 
= hash_table
[position
]->Find (key
); 
 555       return node 
? node
->GetData () : (wxObject
*)NULL
; 
 559 wxObject 
*wxHashTable::Delete (long key
) 
 564   int position 
= (int) (k 
% n
); 
 565   if (position 
< 0) position 
= -position
; 
 567   if (!hash_table
[position
]) 
 568     return (wxObject 
*) NULL
; 
 571       wxNode 
*node 
= hash_table
[position
]->Find (k
); 
 574           wxObject 
*data 
= node
->GetData (); 
 580         return (wxObject 
*) NULL
; 
 584 wxObject 
*wxHashTable::Delete (const wxChar 
*key
) 
 586   int position 
= (int) (MakeKey (key
) % n
); 
 587   if (position 
< 0) position 
= -position
; 
 589   if (!hash_table
[position
]) 
 590     return (wxObject 
*) NULL
; 
 593       wxNode 
*node 
= hash_table
[position
]->Find (key
); 
 596           wxObject 
*data 
= node
->GetData (); 
 602         return (wxObject 
*) NULL
; 
 606 wxObject 
*wxHashTable::Delete (long key
, int value
) 
 611   int position 
= (int) (k 
% n
); 
 612   if (position 
< 0) position 
= -position
; 
 614   if (!hash_table
[position
]) 
 615     return (wxObject 
*) NULL
; 
 618       wxNode 
*node 
= hash_table
[position
]->Find (value
); 
 621           wxObject 
*data 
= node
->GetData (); 
 627         return (wxObject 
*) NULL
; 
 631 wxObject 
*wxHashTable::Delete (long key
, const wxChar 
*value
) 
 633   int position 
= (int) (key 
% n
); 
 634   if (position 
< 0) position 
= -position
; 
 636   if (!hash_table
[position
]) 
 637     return (wxObject 
*) NULL
; 
 640       wxNode 
*node 
= hash_table
[position
]->Find (value
); 
 643           wxObject 
*data 
= node
->GetData (); 
 649         return (wxObject 
*) NULL
; 
 653 long wxHashTable::MakeKey (const wxChar 
*string
) const 
 658     int_key 
+= (wxUChar
) *string
++; 
 663 void wxHashTable::BeginFind () 
 665   current_position 
= -1; 
 666   current_node 
= (wxNode 
*) NULL
; 
 669 wxHashTable::Node
* wxHashTable::Next () 
 671   wxNode 
*found 
= (wxNode 
*) NULL
; 
 673   while (!end 
&& !found
) 
 678           if (current_position 
>= n
) 
 680               current_position 
= -1; 
 681               current_node 
= (wxNode 
*) NULL
; 
 686               if (hash_table
[current_position
]) 
 688                   current_node 
= hash_table
[current_position
]->GetFirst (); 
 689                   found 
= current_node
; 
 695           current_node 
= current_node
->GetNext (); 
 696           found 
= current_node
; 
 702 void wxHashTable::DeleteContents (bool flag
) 
 705   m_deleteContents 
= flag
; 
 706   for (i 
= 0; i 
< n
; i
++) 
 709         hash_table
[i
]->DeleteContents (flag
); 
 713 void wxHashTable::Clear () 
 718         for (i 
= 0; i 
< n
; i
++) 
 721                 hash_table
[i
]->Clear (); 
 727 #else // if wxUSE_STL 
 729 #include "wx/object.h" 
 731 wxHashTableBase_Node::wxHashTableBase_Node( long key
, void* value
, 
 732                                             wxHashTableBase
* table 
) 
 733     : m_value( value 
), m_hashPtr( table 
) 
 738 wxHashTableBase_Node::wxHashTableBase_Node( const wxChar
* key
, void* value
, 
 739                                             wxHashTableBase
* table 
) 
 740     : m_value( value 
), m_hashPtr( table 
) 
 742     m_key
.string 
= wxStrcpy( new wxChar
[wxStrlen( key 
) + 1], key 
); 
 745 wxHashTableBase_Node::~wxHashTableBase_Node() 
 747     if( m_hashPtr 
) m_hashPtr
->DoRemoveNode( this ); 
 752 wxHashTableBase::wxHashTableBase() 
 753     : m_size( 0 ), m_count( 0 ), m_table( NULL 
), m_keyType( wxKEY_NONE 
), 
 754       m_deleteContents( false ) 
 758 wxHashTableBase::~wxHashTableBase() 
 763 void wxHashTableBase::Create( wxKeyType keyType
, size_t size 
) 
 767     m_table 
= new wxHashTableBase_Node
*[ m_size 
]; 
 769     for( size_t i 
= 0; i 
< m_size
; ++i 
) 
 773 void wxHashTableBase::Clear() 
 775     for( size_t i 
= 0; i 
< m_size
; ++i 
) 
 777         Node
* end 
= m_table
[i
]; 
 782         Node 
*curr
, *next 
= end
->GetNext(); 
 787             next 
= curr
->GetNext(); 
 789             DoDestroyNode( curr 
); 
 793         while( curr 
!= end 
); 
 801 void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node
* node 
) 
 803     size_t bucket 
= ( m_keyType 
== wxKEY_INTEGER 
? 
 804                       node
->m_key
.integer        
: 
 805                       MakeKey( node
->m_key
.string 
) ) % m_size
; 
 807     if( node
->GetNext() == node 
) 
 809         // single-node chain (common case) 
 810         m_table
[bucket
] = NULL
; 
 814         Node 
*start 
= m_table
[bucket
], *curr
; 
 817         for( curr 
= prev
->GetNext(); curr 
!= node
; 
 818              prev 
= curr
, curr 
= curr
->GetNext() ); 
 820         DoUnlinkNode( bucket
, node
, prev 
); 
 823     DoDestroyNode( node 
); 
 826 void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node
* node 
) 
 828     // if it is called from DoRemoveNode, node has already been 
 829     // removed, from other places it does not matter 
 830     node
->m_hashPtr 
= NULL
; 
 832     if( m_keyType 
== wxKEY_STRING 
) 
 833         delete[] node
->m_key
.string
; 
 834     if( m_deleteContents 
) 
 835         DoDeleteContents( node 
); 
 838 void wxHashTableBase::Destroy() 
 848 void wxHashTableBase::DoInsertNode( size_t bucket
, wxHashTableBase_Node
* node 
) 
 850     if( m_table
[bucket
] == NULL 
) 
 852         m_table
[bucket
] = node
->m_next 
= node
; 
 856         Node 
*prev 
= m_table
[bucket
]; 
 857         Node 
*next 
= prev
->m_next
; 
 861         m_table
[bucket
] = node
; 
 867 void wxHashTableBase::DoPut( long key
, long hash
, void* data 
) 
 869     wxASSERT( m_keyType 
== wxKEY_INTEGER 
); 
 871     size_t bucket 
= size_t(hash
) % m_size
; 
 872     Node
* node 
= new wxHashTableBase_Node( key
, data
, this ); 
 874     DoInsertNode( bucket
, node 
); 
 877 void wxHashTableBase::DoPut( const wxChar
* key
, long hash
, void* data 
) 
 879     wxASSERT( m_keyType 
== wxKEY_STRING 
); 
 881     size_t bucket 
= size_t(hash
) % m_size
; 
 882     Node
* node 
= new wxHashTableBase_Node( key
, data
, this ); 
 884     DoInsertNode( bucket
, node 
); 
 887 void* wxHashTableBase::DoGet( long key
, long hash 
) const 
 889     wxASSERT( m_keyType 
== wxKEY_INTEGER 
); 
 891     size_t bucket 
= size_t(hash
) % m_size
; 
 893     if( m_table
[bucket
] == NULL 
) 
 896     Node 
*first 
= m_table
[bucket
]->GetNext(), 
 901         if( curr
->m_key
.integer 
== key 
) 
 902             return curr
->m_value
; 
 904         curr 
= curr
->GetNext(); 
 906     while( curr 
!= first 
); 
 911 void* wxHashTableBase::DoGet( const wxChar
* key
, long hash 
) const 
 913     wxASSERT( m_keyType 
== wxKEY_STRING 
); 
 915     size_t bucket 
= size_t(hash
) % m_size
; 
 917     if( m_table
[bucket
] == NULL 
) 
 920     Node 
*first 
= m_table
[bucket
]->GetNext(), 
 925         if( wxStrcmp( curr
->m_key
.string
, key 
) == 0 ) 
 926             return curr
->m_value
; 
 928         curr 
= curr
->GetNext(); 
 930     while( curr 
!= first 
); 
 935 void wxHashTableBase::DoUnlinkNode( size_t bucket
, wxHashTableBase_Node
* node
, 
 936                                     wxHashTableBase_Node
* prev 
) 
 938     if( node 
== m_table
[bucket
] ) 
 939         m_table
[bucket
] = prev
; 
 941     if( prev 
== node 
&& prev 
== node
->GetNext() ) 
 942         m_table
[bucket
] = NULL
; 
 944         prev
->m_next 
= node
->m_next
; 
 946     DoDestroyNode( node 
); 
 950 void* wxHashTableBase::DoDelete( long key
, long hash 
) 
 952     wxASSERT( m_keyType 
== wxKEY_INTEGER 
); 
 954     size_t bucket 
= size_t(hash
) % m_size
; 
 956     if( m_table
[bucket
] == NULL 
) 
 959     Node 
*first 
= m_table
[bucket
]->GetNext(), 
 961          *prev 
= m_table
[bucket
]; 
 965         if( curr
->m_key
.integer 
== key 
) 
 967             void* retval 
= curr
->m_value
; 
 968             curr
->m_value 
= NULL
; 
 970             DoUnlinkNode( bucket
, curr
, prev 
); 
 977         curr 
= curr
->GetNext(); 
 979     while( curr 
!= first 
); 
 984 void* wxHashTableBase::DoDelete( const wxChar
* key
, long hash 
) 
 986     wxASSERT( m_keyType 
== wxKEY_STRING 
); 
 988     size_t bucket 
= size_t(hash
) % m_size
; 
 990     if( m_table
[bucket
] == NULL 
) 
 993     Node 
*first 
= m_table
[bucket
]->GetNext(), 
 995          *prev 
= m_table
[bucket
]; 
 999         if( wxStrcmp( curr
->m_key
.string
, key 
) == 0 ) 
1001             void* retval 
= curr
->m_value
; 
1002             curr
->m_value 
= NULL
; 
1004             DoUnlinkNode( bucket
, curr
, prev 
); 
1011         curr 
= curr
->GetNext(); 
1013     while( curr 
!= first 
); 
1018 long wxHashTableBase::MakeKey( const wxChar 
*str 
) 
1023         int_key 
+= (wxUChar
)*str
++; 
1030 wxHashTable::wxHashTable( const wxHashTable
& table 
) 
1035 const wxHashTable
& wxHashTable::operator=( const wxHashTable
& table 
) 
1043 void wxHashTable::DoCopy( const wxHashTable
& table 
) 
1045     Create( m_keyType
, m_size 
); 
1050 void wxHashTable::DoDeleteContents( wxHashTableBase_Node
* node 
) 
1052     delete ((wxHashTable_Node
*)node
)->GetData(); 
1055 void wxHashTable::GetNextNode( size_t bucketStart 
) 
1057     for( size_t i 
= bucketStart
; i 
< m_size
; ++i 
) 
1059         if( m_table
[i
] != NULL 
) 
1061             m_curr 
= ((Node
*)m_table
[i
])->GetNext(); 
1071 wxHashTable::Node
* wxHashTable::Next() 
1073     if( m_curr 
== NULL 
) 
1077         m_curr 
= m_curr
->GetNext(); 
1079         if( m_curr 
== ( (Node
*)m_table
[m_currBucket
] )->GetNext() ) 
1080             GetNextNode( m_currBucket 
+ 1 );