]>
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 );