]>
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 // For compilers that support precompilation, includes "wx.h".
21 #include "wx/wxprec.h"
33 #if wxUSE_OLD_HASH_TABLE
38 // ----------------------------------------------------------------------------
40 // ----------------------------------------------------------------------------
42 IMPLEMENT_DYNAMIC_CLASS(wxHashTable
, wxObject
)
44 // ============================================================================
46 // ============================================================================
48 // ----------------------------------------------------------------------------
49 // wxHashTablleBase for working with "void *" data
50 // ----------------------------------------------------------------------------
52 wxHashTableBase::wxHashTableBase()
54 m_deleteContents
= false;
55 m_hashTable
= (wxListBase
**)NULL
;
58 m_keyType
= wxKEY_NONE
;
61 void wxHashTableBase::Create(wxKeyType keyType
, size_t size
)
67 m_hashTable
= new wxListBase
*[size
];
68 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
70 m_hashTable
[n
] = (wxListBase
*) NULL
;
74 void wxHashTableBase::Destroy()
78 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
80 delete m_hashTable
[n
];
83 delete [] m_hashTable
;
85 m_hashTable
= (wxListBase
**)NULL
;
91 void wxHashTableBase::DeleteContents(bool flag
)
93 m_deleteContents
= flag
;
94 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
98 m_hashTable
[n
]->DeleteContents(flag
);
103 wxNodeBase
*wxHashTableBase::GetNode(long key
, long value
) const
105 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
108 if ( m_hashTable
[slot
] )
110 node
= m_hashTable
[slot
]->Find(wxListKey(value
));
114 node
= (wxNodeBase
*)NULL
;
120 #if WXWIN_COMPATIBILITY_2_4
122 // ----------------------------------------------------------------------------
124 // ----------------------------------------------------------------------------
126 wxHashTableLong::~wxHashTableLong()
131 void wxHashTableLong::Init(size_t size
)
134 m_values
= new wxArrayLong
*[size
];
135 m_keys
= new wxArrayLong
*[size
];
137 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
140 m_keys
[n
] = (wxArrayLong
*)NULL
;
146 void wxHashTableLong::Create(size_t size
)
151 void wxHashTableLong::Destroy()
153 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
165 void wxHashTableLong::Put(long key
, long value
)
167 wxCHECK_RET( m_hashSize
, _T("must call Create() first") );
169 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
173 m_keys
[slot
] = new wxArrayLong
;
174 m_values
[slot
] = new wxArrayLong
;
177 m_keys
[slot
]->Add(key
);
178 m_values
[slot
]->Add(value
);
183 long wxHashTableLong::Get(long key
) const
185 wxCHECK_MSG( m_hashSize
, wxNOT_FOUND
, _T("must call Create() first") );
187 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
189 wxArrayLong
*keys
= m_keys
[slot
];
192 size_t count
= keys
->GetCount();
193 for ( size_t n
= 0; n
< count
; n
++ )
195 if ( keys
->Item(n
) == key
)
197 return m_values
[slot
]->Item(n
);
205 long wxHashTableLong::Delete(long key
)
207 wxCHECK_MSG( m_hashSize
, wxNOT_FOUND
, _T("must call Create() first") );
209 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
211 wxArrayLong
*keys
= m_keys
[slot
];
214 size_t count
= keys
->GetCount();
215 for ( size_t n
= 0; n
< count
; n
++ )
217 if ( keys
->Item(n
) == key
)
219 long val
= m_values
[slot
]->Item(n
);
222 m_values
[slot
]->RemoveAt(n
);
234 // ----------------------------------------------------------------------------
235 // wxStringHashTable: more efficient than storing strings in a list
236 // ----------------------------------------------------------------------------
238 wxStringHashTable::wxStringHashTable(size_t sizeTable
)
240 m_keys
= new wxArrayLong
*[sizeTable
];
241 m_values
= new wxArrayString
*[sizeTable
];
243 m_hashSize
= sizeTable
;
244 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
246 m_values
[n
] = (wxArrayString
*)NULL
;
247 m_keys
[n
] = (wxArrayLong
*)NULL
;
251 wxStringHashTable::~wxStringHashTable()
256 void wxStringHashTable::Destroy()
258 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
269 void wxStringHashTable::Put(long key
, const wxString
& value
)
271 wxCHECK_RET( m_hashSize
, _T("must call Create() first") );
273 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
277 m_keys
[slot
] = new wxArrayLong
;
278 m_values
[slot
] = new wxArrayString
;
281 m_keys
[slot
]->Add(key
);
282 m_values
[slot
]->Add(value
);
285 wxString
wxStringHashTable::Get(long key
, bool *wasFound
) const
287 wxCHECK_MSG( m_hashSize
, wxEmptyString
, _T("must call Create() first") );
289 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
291 wxArrayLong
*keys
= m_keys
[slot
];
294 size_t count
= keys
->GetCount();
295 for ( size_t n
= 0; n
< count
; n
++ )
297 if ( keys
->Item(n
) == key
)
302 return m_values
[slot
]->Item(n
);
310 return wxEmptyString
;
313 bool wxStringHashTable::Delete(long key
) const
315 wxCHECK_MSG( m_hashSize
, false, _T("must call Create() first") );
317 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
319 wxArrayLong
*keys
= m_keys
[slot
];
322 size_t count
= keys
->GetCount();
323 for ( size_t n
= 0; n
< count
; n
++ )
325 if ( keys
->Item(n
) == key
)
328 m_values
[slot
]->RemoveAt(n
);
337 #endif // WXWIN_COMPATIBILITY_2_4
339 // ----------------------------------------------------------------------------
340 // old not type safe wxHashTable
341 // ----------------------------------------------------------------------------
343 wxHashTable::wxHashTable (int the_key_type
, int size
)
346 hash_table
= (wxList
**) NULL
;
347 Create(the_key_type
, size
);
349 m_deleteContents
= false;
352 current_position = -1;
353 current_node = (wxNode *) NULL;
355 key_type = the_key_type;
356 hash_table = new wxList *[size];
358 for (i = 0; i < size; i++)
359 hash_table[i] = (wxList *) NULL;
363 wxHashTable::~wxHashTable ()
368 void wxHashTable::Destroy()
370 if (!hash_table
) return;
372 for (i
= 0; i
< n
; i
++)
374 delete hash_table
[i
];
379 bool wxHashTable::Create(int the_key_type
, int size
)
384 current_position
= -1;
385 current_node
= (wxNode
*) NULL
;
387 key_type
= the_key_type
;
388 hash_table
= new wxList
*[size
];
390 for (i
= 0; i
< size
; i
++)
391 hash_table
[i
] = (wxList
*) NULL
;
396 void wxHashTable::DoCopy(const wxHashTable
& table
)
399 m_count
= table
.m_count
;
400 current_position
= table
.current_position
;
401 current_node
= NULL
; // doesn't matter - Next() will reconstruct it
402 key_type
= table
.key_type
;
404 hash_table
= new wxList
*[n
];
405 for (int i
= 0; i
< n
; i
++) {
406 if (table
.hash_table
[i
] == NULL
)
407 hash_table
[i
] = NULL
;
409 hash_table
[i
] = new wxList(key_type
);
410 *(hash_table
[i
]) = *(table
.hash_table
[i
]);
415 void wxHashTable::Put (long key
, long value
, wxObject
* object
)
420 int position
= (int) (k
% n
);
421 if (position
< 0) position
= -position
;
423 if (!hash_table
[position
])
425 hash_table
[position
] = new wxList (wxKEY_INTEGER
);
426 if (m_deleteContents
) hash_table
[position
]->DeleteContents(true);
429 hash_table
[position
]->Append (value
, object
);
433 void wxHashTable::Put (long key
, const wxChar
*value
, wxObject
* object
)
438 int position
= (int) (k
% n
);
439 if (position
< 0) position
= -position
;
441 if (!hash_table
[position
])
443 hash_table
[position
] = new wxList (wxKEY_STRING
);
444 if (m_deleteContents
) hash_table
[position
]->DeleteContents(true);
447 hash_table
[position
]->Append (value
, object
);
451 void wxHashTable::Put (long key
, wxObject
* object
)
456 int position
= (int) (k
% n
);
457 if (position
< 0) position
= -position
;
459 if (!hash_table
[position
])
461 hash_table
[position
] = new wxList (wxKEY_INTEGER
);
462 if (m_deleteContents
) hash_table
[position
]->DeleteContents(true);
465 hash_table
[position
]->Append (k
, object
);
469 void wxHashTable::Put (const wxChar
*key
, wxObject
* object
)
471 int position
= (int) (MakeKey (key
) % n
);
472 if (position
< 0) position
= -position
;
474 if (!hash_table
[position
])
476 hash_table
[position
] = new wxList (wxKEY_STRING
);
477 if (m_deleteContents
) hash_table
[position
]->DeleteContents(true);
480 hash_table
[position
]->Append (key
, object
);
484 wxObject
*wxHashTable::Get (long key
, long value
) const
489 int position
= (int) (k
% n
);
490 if (position
< 0) position
= -position
;
492 if (!hash_table
[position
])
493 return (wxObject
*) NULL
;
496 wxNode
*node
= hash_table
[position
]->Find (value
);
498 return node
->GetData ();
500 return (wxObject
*) NULL
;
504 wxObject
*wxHashTable::Get (long key
, const wxChar
*value
) const
509 int position
= (int) (k
% n
);
510 if (position
< 0) position
= -position
;
512 if (!hash_table
[position
])
513 return (wxObject
*) NULL
;
516 wxNode
*node
= hash_table
[position
]->Find (value
);
518 return node
->GetData ();
520 return (wxObject
*) NULL
;
524 wxObject
*wxHashTable::Get (long key
) const
529 int position
= (int) (k
% n
);
530 if (position
< 0) position
= -position
;
532 if (!hash_table
[position
])
533 return (wxObject
*) NULL
;
536 wxNode
*node
= hash_table
[position
]->Find (k
);
537 return node
? node
->GetData () : (wxObject
*)NULL
;
541 wxObject
*wxHashTable::Get (const wxChar
*key
) const
543 int position
= (int) (MakeKey (key
) % n
);
544 if (position
< 0) position
= -position
;
546 if (!hash_table
[position
])
547 return (wxObject
*) NULL
;
550 wxNode
*node
= hash_table
[position
]->Find (key
);
551 return node
? node
->GetData () : (wxObject
*)NULL
;
555 wxObject
*wxHashTable::Delete (long key
)
560 int position
= (int) (k
% n
);
561 if (position
< 0) position
= -position
;
563 if (!hash_table
[position
])
564 return (wxObject
*) NULL
;
567 wxNode
*node
= hash_table
[position
]->Find (k
);
570 wxObject
*data
= node
->GetData ();
576 return (wxObject
*) NULL
;
580 wxObject
*wxHashTable::Delete (const wxChar
*key
)
582 int position
= (int) (MakeKey (key
) % n
);
583 if (position
< 0) position
= -position
;
585 if (!hash_table
[position
])
586 return (wxObject
*) NULL
;
589 wxNode
*node
= hash_table
[position
]->Find (key
);
592 wxObject
*data
= node
->GetData ();
598 return (wxObject
*) NULL
;
602 wxObject
*wxHashTable::Delete (long key
, int value
)
607 int position
= (int) (k
% n
);
608 if (position
< 0) position
= -position
;
610 if (!hash_table
[position
])
611 return (wxObject
*) NULL
;
614 wxNode
*node
= hash_table
[position
]->Find (value
);
617 wxObject
*data
= node
->GetData ();
623 return (wxObject
*) NULL
;
627 wxObject
*wxHashTable::Delete (long key
, const wxChar
*value
)
629 int position
= (int) (key
% n
);
630 if (position
< 0) position
= -position
;
632 if (!hash_table
[position
])
633 return (wxObject
*) NULL
;
636 wxNode
*node
= hash_table
[position
]->Find (value
);
639 wxObject
*data
= node
->GetData ();
645 return (wxObject
*) NULL
;
649 long wxHashTable::MakeKey (const wxChar
*string
) const
654 int_key
+= (wxUChar
) *string
++;
659 void wxHashTable::BeginFind ()
661 current_position
= -1;
662 current_node
= (wxNode
*) NULL
;
665 wxHashTable::Node
* wxHashTable::Next ()
667 wxNode
*found
= (wxNode
*) NULL
;
669 while (!end
&& !found
)
674 if (current_position
>= n
)
676 current_position
= -1;
677 current_node
= (wxNode
*) NULL
;
682 if (hash_table
[current_position
])
684 current_node
= hash_table
[current_position
]->GetFirst ();
685 found
= current_node
;
691 current_node
= current_node
->GetNext ();
692 found
= current_node
;
698 void wxHashTable::DeleteContents (bool flag
)
701 m_deleteContents
= flag
;
702 for (i
= 0; i
< n
; i
++)
705 hash_table
[i
]->DeleteContents (flag
);
709 void wxHashTable::Clear ()
714 for (i
= 0; i
< n
; i
++)
717 hash_table
[i
]->Clear ();
723 #else // if !wxUSE_OLD_HASH_TABLE
725 wxHashTableBase_Node::wxHashTableBase_Node( long key
, void* value
,
726 wxHashTableBase
* table
)
727 : m_value( value
), m_hashPtr( table
)
732 wxHashTableBase_Node::wxHashTableBase_Node( const wxChar
* key
, void* value
,
733 wxHashTableBase
* table
)
734 : m_value( value
), m_hashPtr( table
)
736 m_key
.string
= wxStrcpy( new wxChar
[wxStrlen( key
) + 1], key
);
739 wxHashTableBase_Node::~wxHashTableBase_Node()
741 if( m_hashPtr
) m_hashPtr
->DoRemoveNode( this );
746 wxHashTableBase::wxHashTableBase()
747 : m_size( 0 ), m_count( 0 ), m_table( NULL
), m_keyType( wxKEY_NONE
),
748 m_deleteContents( false )
752 void wxHashTableBase::Create( wxKeyType keyType
, size_t size
)
756 m_table
= new wxHashTableBase_Node
*[ m_size
];
758 for( size_t i
= 0; i
< m_size
; ++i
)
762 void wxHashTableBase::Clear()
764 for( size_t i
= 0; i
< m_size
; ++i
)
766 Node
* end
= m_table
[i
];
771 Node
*curr
, *next
= end
->GetNext();
776 next
= curr
->GetNext();
778 DoDestroyNode( curr
);
782 while( curr
!= end
);
790 void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node
* node
)
792 size_t bucket
= ( m_keyType
== wxKEY_INTEGER
?
793 node
->m_key
.integer
:
794 MakeKey( node
->m_key
.string
) ) % m_size
;
796 if( node
->GetNext() == node
)
798 // single-node chain (common case)
799 m_table
[bucket
] = NULL
;
803 Node
*start
= m_table
[bucket
], *curr
;
806 for( curr
= prev
->GetNext(); curr
!= node
;
807 prev
= curr
, curr
= curr
->GetNext() ) ;
809 DoUnlinkNode( bucket
, node
, prev
);
812 DoDestroyNode( node
);
815 void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node
* node
)
817 // if it is called from DoRemoveNode, node has already been
818 // removed, from other places it does not matter
819 node
->m_hashPtr
= NULL
;
821 if( m_keyType
== wxKEY_STRING
)
822 delete[] node
->m_key
.string
;
823 if( m_deleteContents
)
824 DoDeleteContents( node
);
827 void wxHashTableBase::Destroy()
837 void wxHashTableBase::DoInsertNode( size_t bucket
, wxHashTableBase_Node
* node
)
839 if( m_table
[bucket
] == NULL
)
841 m_table
[bucket
] = node
->m_next
= node
;
845 Node
*prev
= m_table
[bucket
];
846 Node
*next
= prev
->m_next
;
850 m_table
[bucket
] = node
;
856 void wxHashTableBase::DoPut( long key
, long hash
, void* data
)
858 wxASSERT( m_keyType
== wxKEY_INTEGER
);
860 size_t bucket
= size_t(hash
) % m_size
;
861 Node
* node
= new wxHashTableBase_Node( key
, data
, this );
863 DoInsertNode( bucket
, node
);
866 void wxHashTableBase::DoPut( const wxChar
* key
, long hash
, void* data
)
868 wxASSERT( m_keyType
== wxKEY_STRING
);
870 size_t bucket
= size_t(hash
) % m_size
;
871 Node
* node
= new wxHashTableBase_Node( key
, data
, this );
873 DoInsertNode( bucket
, node
);
876 void* wxHashTableBase::DoGet( long key
, long hash
) const
878 wxASSERT( m_keyType
== wxKEY_INTEGER
);
880 size_t bucket
= size_t(hash
) % m_size
;
882 if( m_table
[bucket
] == NULL
)
885 Node
*first
= m_table
[bucket
]->GetNext(),
890 if( curr
->m_key
.integer
== key
)
891 return curr
->m_value
;
893 curr
= curr
->GetNext();
895 while( curr
!= first
);
900 void* wxHashTableBase::DoGet( const wxChar
* key
, long hash
) const
902 wxASSERT( m_keyType
== wxKEY_STRING
);
904 size_t bucket
= size_t(hash
) % m_size
;
906 if( m_table
[bucket
] == NULL
)
909 Node
*first
= m_table
[bucket
]->GetNext(),
914 if( wxStrcmp( curr
->m_key
.string
, key
) == 0 )
915 return curr
->m_value
;
917 curr
= curr
->GetNext();
919 while( curr
!= first
);
924 void wxHashTableBase::DoUnlinkNode( size_t bucket
, wxHashTableBase_Node
* node
,
925 wxHashTableBase_Node
* prev
)
927 if( node
== m_table
[bucket
] )
928 m_table
[bucket
] = prev
;
930 if( prev
== node
&& prev
== node
->GetNext() )
931 m_table
[bucket
] = NULL
;
933 prev
->m_next
= node
->m_next
;
935 DoDestroyNode( node
);
939 void* wxHashTableBase::DoDelete( long key
, long hash
)
941 wxASSERT( m_keyType
== wxKEY_INTEGER
);
943 size_t bucket
= size_t(hash
) % m_size
;
945 if( m_table
[bucket
] == NULL
)
948 Node
*first
= m_table
[bucket
]->GetNext(),
950 *prev
= m_table
[bucket
];
954 if( curr
->m_key
.integer
== key
)
956 void* retval
= curr
->m_value
;
957 curr
->m_value
= NULL
;
959 DoUnlinkNode( bucket
, curr
, prev
);
966 curr
= curr
->GetNext();
968 while( curr
!= first
);
973 void* wxHashTableBase::DoDelete( const wxChar
* key
, long hash
)
975 wxASSERT( m_keyType
== wxKEY_STRING
);
977 size_t bucket
= size_t(hash
) % m_size
;
979 if( m_table
[bucket
] == NULL
)
982 Node
*first
= m_table
[bucket
]->GetNext(),
984 *prev
= m_table
[bucket
];
988 if( wxStrcmp( curr
->m_key
.string
, key
) == 0 )
990 void* retval
= curr
->m_value
;
991 curr
->m_value
= NULL
;
993 DoUnlinkNode( bucket
, curr
, prev
);
1000 curr
= curr
->GetNext();
1002 while( curr
!= first
);
1007 long wxHashTableBase::MakeKey( const wxChar
*str
)
1012 int_key
+= (wxUChar
)*str
++;
1017 // ----------------------------------------------------------------------------
1019 // ----------------------------------------------------------------------------
1021 wxHashTable::wxHashTable( const wxHashTable
& table
)
1027 const wxHashTable
& wxHashTable::operator=( const wxHashTable
& table
)
1035 void wxHashTable::DoCopy( const wxHashTable
& WXUNUSED(table
) )
1037 Create( m_keyType
, m_size
);
1042 void wxHashTable::DoDeleteContents( wxHashTableBase_Node
* node
)
1044 delete ((wxHashTable_Node
*)node
)->GetData();
1047 void wxHashTable::GetNextNode( size_t bucketStart
)
1049 for( size_t i
= bucketStart
; i
< m_size
; ++i
)
1051 if( m_table
[i
] != NULL
)
1053 m_curr
= ((Node
*)m_table
[i
])->GetNext();
1063 wxHashTable::Node
* wxHashTable::Next()
1065 if( m_curr
== NULL
)
1069 m_curr
= m_curr
->GetNext();
1071 if( m_curr
== ( (Node
*)m_table
[m_currBucket
] )->GetNext() )
1072 GetNextNode( m_currBucket
+ 1 );
1078 #endif // !wxUSE_OLD_HASH_TABLE