]>
git.saurik.com Git - wxWidgets.git/blob - src/common/hash.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: src/common/hash.cpp
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"
32 #if wxUSE_OLD_HASH_TABLE
37 // ----------------------------------------------------------------------------
39 // ----------------------------------------------------------------------------
41 IMPLEMENT_DYNAMIC_CLASS(wxHashTable
, wxObject
)
43 // ============================================================================
45 // ============================================================================
47 // ----------------------------------------------------------------------------
48 // wxHashTablleBase for working with "void *" data
49 // ----------------------------------------------------------------------------
51 wxHashTableBase::wxHashTableBase()
53 m_deleteContents
= false;
54 m_hashTable
= (wxListBase
**)NULL
;
57 m_keyType
= wxKEY_NONE
;
60 void wxHashTableBase::Create(wxKeyType keyType
, size_t size
)
66 m_hashTable
= new wxListBase
*[size
];
67 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
69 m_hashTable
[n
] = (wxListBase
*) NULL
;
73 void wxHashTableBase::Destroy()
77 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
79 delete m_hashTable
[n
];
82 delete [] m_hashTable
;
84 m_hashTable
= (wxListBase
**)NULL
;
90 void wxHashTableBase::DeleteContents(bool flag
)
92 m_deleteContents
= flag
;
93 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
97 m_hashTable
[n
]->DeleteContents(flag
);
102 wxNodeBase
*wxHashTableBase::GetNode(long key
, long value
) const
104 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
107 if ( m_hashTable
[slot
] )
109 node
= m_hashTable
[slot
]->Find(wxListKey(value
));
113 node
= (wxNodeBase
*)NULL
;
119 #if WXWIN_COMPATIBILITY_2_4
121 // ----------------------------------------------------------------------------
123 // ----------------------------------------------------------------------------
125 wxHashTableLong::~wxHashTableLong()
130 void wxHashTableLong::Init(size_t size
)
133 m_values
= new wxArrayLong
*[size
];
134 m_keys
= new wxArrayLong
*[size
];
136 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
139 m_keys
[n
] = (wxArrayLong
*)NULL
;
145 void wxHashTableLong::Create(size_t size
)
150 void wxHashTableLong::Destroy()
152 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
164 void wxHashTableLong::Put(long key
, long value
)
166 wxCHECK_RET( m_hashSize
, _T("must call Create() first") );
168 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
172 m_keys
[slot
] = new wxArrayLong
;
173 m_values
[slot
] = new wxArrayLong
;
176 m_keys
[slot
]->Add(key
);
177 m_values
[slot
]->Add(value
);
182 long wxHashTableLong::Get(long key
) const
184 wxCHECK_MSG( m_hashSize
, wxNOT_FOUND
, _T("must call Create() first") );
186 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
188 wxArrayLong
*keys
= m_keys
[slot
];
191 size_t count
= keys
->GetCount();
192 for ( size_t n
= 0; n
< count
; n
++ )
194 if ( keys
->Item(n
) == key
)
196 return m_values
[slot
]->Item(n
);
204 long wxHashTableLong::Delete(long key
)
206 wxCHECK_MSG( m_hashSize
, wxNOT_FOUND
, _T("must call Create() first") );
208 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
210 wxArrayLong
*keys
= m_keys
[slot
];
213 size_t count
= keys
->GetCount();
214 for ( size_t n
= 0; n
< count
; n
++ )
216 if ( keys
->Item(n
) == key
)
218 long val
= m_values
[slot
]->Item(n
);
221 m_values
[slot
]->RemoveAt(n
);
233 // ----------------------------------------------------------------------------
234 // wxStringHashTable: more efficient than storing strings in a list
235 // ----------------------------------------------------------------------------
237 wxStringHashTable::wxStringHashTable(size_t sizeTable
)
239 m_keys
= new wxArrayLong
*[sizeTable
];
240 m_values
= new wxArrayString
*[sizeTable
];
242 m_hashSize
= sizeTable
;
243 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
245 m_values
[n
] = (wxArrayString
*)NULL
;
246 m_keys
[n
] = (wxArrayLong
*)NULL
;
250 wxStringHashTable::~wxStringHashTable()
255 void wxStringHashTable::Destroy()
257 for ( size_t n
= 0; n
< m_hashSize
; n
++ )
268 void wxStringHashTable::Put(long key
, const wxString
& value
)
270 wxCHECK_RET( m_hashSize
, _T("must call Create() first") );
272 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
276 m_keys
[slot
] = new wxArrayLong
;
277 m_values
[slot
] = new wxArrayString
;
280 m_keys
[slot
]->Add(key
);
281 m_values
[slot
]->Add(value
);
284 wxString
wxStringHashTable::Get(long key
, bool *wasFound
) const
286 wxCHECK_MSG( m_hashSize
, wxEmptyString
, _T("must call Create() first") );
288 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
290 wxArrayLong
*keys
= m_keys
[slot
];
293 size_t count
= keys
->GetCount();
294 for ( size_t n
= 0; n
< count
; n
++ )
296 if ( keys
->Item(n
) == key
)
301 return m_values
[slot
]->Item(n
);
309 return wxEmptyString
;
312 bool wxStringHashTable::Delete(long key
) const
314 wxCHECK_MSG( m_hashSize
, false, _T("must call Create() first") );
316 size_t slot
= (size_t)abs((int)(key
% (long)m_hashSize
));
318 wxArrayLong
*keys
= m_keys
[slot
];
321 size_t count
= keys
->GetCount();
322 for ( size_t n
= 0; n
< count
; n
++ )
324 if ( keys
->Item(n
) == key
)
327 m_values
[slot
]->RemoveAt(n
);
336 #endif // WXWIN_COMPATIBILITY_2_4
338 // ----------------------------------------------------------------------------
339 // old not type safe wxHashTable
340 // ----------------------------------------------------------------------------
342 wxHashTable::wxHashTable (int the_key_type
, int size
)
345 hash_table
= (wxList
**) NULL
;
346 Create(the_key_type
, size
);
348 m_deleteContents
= false;
351 current_position = -1;
352 current_node = (wxNode *) NULL;
354 key_type = the_key_type;
355 hash_table = new wxList *[size];
357 for (i = 0; i < size; i++)
358 hash_table[i] = (wxList *) NULL;
362 wxHashTable::~wxHashTable ()
367 void wxHashTable::Destroy()
369 if (!hash_table
) return;
371 for (i
= 0; i
< n
; i
++)
373 delete hash_table
[i
];
378 bool wxHashTable::Create(int the_key_type
, int size
)
383 current_position
= -1;
384 current_node
= (wxNode
*) NULL
;
386 key_type
= the_key_type
;
387 hash_table
= new wxList
*[size
];
389 for (i
= 0; i
< size
; i
++)
390 hash_table
[i
] = (wxList
*) NULL
;
395 void wxHashTable::DoCopy(const wxHashTable
& table
)
398 m_count
= table
.m_count
;
399 current_position
= table
.current_position
;
400 current_node
= NULL
; // doesn't matter - Next() will reconstruct it
401 key_type
= table
.key_type
;
403 hash_table
= new wxList
*[n
];
404 for (int i
= 0; i
< n
; i
++) {
405 if (table
.hash_table
[i
] == NULL
)
406 hash_table
[i
] = NULL
;
408 hash_table
[i
] = new wxList(key_type
);
409 *(hash_table
[i
]) = *(table
.hash_table
[i
]);
414 void wxHashTable::Put (long key
, long value
, wxObject
* object
)
419 int position
= (int) (k
% n
);
420 if (position
< 0) position
= -position
;
422 if (!hash_table
[position
])
424 hash_table
[position
] = new wxList (wxKEY_INTEGER
);
425 if (m_deleteContents
) hash_table
[position
]->DeleteContents(true);
428 hash_table
[position
]->Append (value
, object
);
432 void wxHashTable::Put (long key
, const wxChar
*value
, wxObject
* object
)
437 int position
= (int) (k
% n
);
438 if (position
< 0) position
= -position
;
440 if (!hash_table
[position
])
442 hash_table
[position
] = new wxList (wxKEY_STRING
);
443 if (m_deleteContents
) hash_table
[position
]->DeleteContents(true);
446 hash_table
[position
]->Append (value
, object
);
450 void wxHashTable::Put (long key
, wxObject
* object
)
455 int position
= (int) (k
% n
);
456 if (position
< 0) position
= -position
;
458 if (!hash_table
[position
])
460 hash_table
[position
] = new wxList (wxKEY_INTEGER
);
461 if (m_deleteContents
) hash_table
[position
]->DeleteContents(true);
464 hash_table
[position
]->Append (k
, object
);
468 void wxHashTable::Put (const wxChar
*key
, wxObject
* object
)
470 int position
= (int) (MakeKey (key
) % n
);
471 if (position
< 0) position
= -position
;
473 if (!hash_table
[position
])
475 hash_table
[position
] = new wxList (wxKEY_STRING
);
476 if (m_deleteContents
) hash_table
[position
]->DeleteContents(true);
479 hash_table
[position
]->Append (key
, object
);
483 wxObject
*wxHashTable::Get (long key
, long value
) const
488 int position
= (int) (k
% n
);
489 if (position
< 0) position
= -position
;
491 if (!hash_table
[position
])
492 return (wxObject
*) NULL
;
495 wxNode
*node
= hash_table
[position
]->Find (value
);
497 return node
->GetData ();
499 return (wxObject
*) NULL
;
503 wxObject
*wxHashTable::Get (long key
, const wxChar
*value
) const
508 int position
= (int) (k
% n
);
509 if (position
< 0) position
= -position
;
511 if (!hash_table
[position
])
512 return (wxObject
*) NULL
;
515 wxNode
*node
= hash_table
[position
]->Find (value
);
517 return node
->GetData ();
519 return (wxObject
*) NULL
;
523 wxObject
*wxHashTable::Get (long key
) const
528 int position
= (int) (k
% n
);
529 if (position
< 0) position
= -position
;
531 if (!hash_table
[position
])
532 return (wxObject
*) NULL
;
535 wxNode
*node
= hash_table
[position
]->Find (k
);
536 return node
? node
->GetData () : (wxObject
*)NULL
;
540 wxObject
*wxHashTable::Get (const wxChar
*key
) const
542 int position
= (int) (MakeKey (key
) % n
);
543 if (position
< 0) position
= -position
;
545 if (!hash_table
[position
])
546 return (wxObject
*) NULL
;
549 wxNode
*node
= hash_table
[position
]->Find (key
);
550 return node
? node
->GetData () : (wxObject
*)NULL
;
554 wxObject
*wxHashTable::Delete (long key
)
559 int position
= (int) (k
% n
);
560 if (position
< 0) position
= -position
;
562 if (!hash_table
[position
])
563 return (wxObject
*) NULL
;
566 wxNode
*node
= hash_table
[position
]->Find (k
);
569 wxObject
*data
= node
->GetData ();
575 return (wxObject
*) NULL
;
579 wxObject
*wxHashTable::Delete (const wxChar
*key
)
581 int position
= (int) (MakeKey (key
) % n
);
582 if (position
< 0) position
= -position
;
584 if (!hash_table
[position
])
585 return (wxObject
*) NULL
;
588 wxNode
*node
= hash_table
[position
]->Find (key
);
591 wxObject
*data
= node
->GetData ();
597 return (wxObject
*) NULL
;
601 wxObject
*wxHashTable::Delete (long key
, int value
)
606 int position
= (int) (k
% n
);
607 if (position
< 0) position
= -position
;
609 if (!hash_table
[position
])
610 return (wxObject
*) NULL
;
613 wxNode
*node
= hash_table
[position
]->Find (value
);
616 wxObject
*data
= node
->GetData ();
622 return (wxObject
*) NULL
;
626 wxObject
*wxHashTable::Delete (long key
, const wxChar
*value
)
628 int position
= (int) (key
% n
);
629 if (position
< 0) position
= -position
;
631 if (!hash_table
[position
])
632 return (wxObject
*) NULL
;
635 wxNode
*node
= hash_table
[position
]->Find (value
);
638 wxObject
*data
= node
->GetData ();
644 return (wxObject
*) NULL
;
648 long wxHashTable::MakeKey (const wxChar
*string
) const
653 int_key
+= (wxUChar
) *string
++;
658 void wxHashTable::BeginFind ()
660 current_position
= -1;
661 current_node
= (wxNode
*) NULL
;
664 wxHashTable::Node
* wxHashTable::Next ()
666 wxNode
*found
= (wxNode
*) NULL
;
668 while (!end
&& !found
)
673 if (current_position
>= n
)
675 current_position
= -1;
676 current_node
= (wxNode
*) NULL
;
681 if (hash_table
[current_position
])
683 current_node
= hash_table
[current_position
]->GetFirst ();
684 found
= current_node
;
690 current_node
= current_node
->GetNext ();
691 found
= current_node
;
697 void wxHashTable::DeleteContents (bool flag
)
700 m_deleteContents
= flag
;
701 for (i
= 0; i
< n
; i
++)
704 hash_table
[i
]->DeleteContents (flag
);
708 void wxHashTable::Clear ()
713 for (i
= 0; i
< n
; i
++)
716 hash_table
[i
]->Clear ();
722 #else // if !wxUSE_OLD_HASH_TABLE
724 wxHashTableBase_Node::wxHashTableBase_Node( long key
, void* value
,
725 wxHashTableBase
* table
)
726 : m_value( value
), m_hashPtr( table
)
731 wxHashTableBase_Node::wxHashTableBase_Node( const wxChar
* key
, void* value
,
732 wxHashTableBase
* table
)
733 : m_value( value
), m_hashPtr( table
)
735 m_key
.string
= wxStrcpy( new wxChar
[wxStrlen( key
) + 1], key
);
738 wxHashTableBase_Node::~wxHashTableBase_Node()
740 if( m_hashPtr
) m_hashPtr
->DoRemoveNode( this );
745 wxHashTableBase::wxHashTableBase()
746 : m_size( 0 ), m_count( 0 ), m_table( NULL
), m_keyType( wxKEY_NONE
),
747 m_deleteContents( false )
751 void wxHashTableBase::Create( wxKeyType keyType
, size_t size
)
755 m_table
= new wxHashTableBase_Node
*[ m_size
];
757 for( size_t i
= 0; i
< m_size
; ++i
)
761 void wxHashTableBase::Clear()
763 for( size_t i
= 0; i
< m_size
; ++i
)
765 Node
* end
= m_table
[i
];
770 Node
*curr
, *next
= end
->GetNext();
775 next
= curr
->GetNext();
777 DoDestroyNode( curr
);
781 while( curr
!= end
);
789 void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node
* node
)
791 size_t bucket
= ( m_keyType
== wxKEY_INTEGER
?
792 node
->m_key
.integer
:
793 MakeKey( node
->m_key
.string
) ) % m_size
;
795 if( node
->GetNext() == node
)
797 // single-node chain (common case)
798 m_table
[bucket
] = NULL
;
802 Node
*start
= m_table
[bucket
], *curr
;
805 for( curr
= prev
->GetNext(); curr
!= node
;
806 prev
= curr
, curr
= curr
->GetNext() ) ;
808 DoUnlinkNode( bucket
, node
, prev
);
811 DoDestroyNode( node
);
814 void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node
* node
)
816 // if it is called from DoRemoveNode, node has already been
817 // removed, from other places it does not matter
818 node
->m_hashPtr
= NULL
;
820 if( m_keyType
== wxKEY_STRING
)
821 delete[] node
->m_key
.string
;
822 if( m_deleteContents
)
823 DoDeleteContents( node
);
826 void wxHashTableBase::Destroy()
836 void wxHashTableBase::DoInsertNode( size_t bucket
, wxHashTableBase_Node
* node
)
838 if( m_table
[bucket
] == NULL
)
840 m_table
[bucket
] = node
->m_next
= node
;
844 Node
*prev
= m_table
[bucket
];
845 Node
*next
= prev
->m_next
;
849 m_table
[bucket
] = node
;
855 void wxHashTableBase::DoPut( long key
, long hash
, void* data
)
857 wxASSERT( m_keyType
== wxKEY_INTEGER
);
859 size_t bucket
= size_t(hash
) % m_size
;
860 Node
* node
= new wxHashTableBase_Node( key
, data
, this );
862 DoInsertNode( bucket
, node
);
865 void wxHashTableBase::DoPut( const wxChar
* key
, long hash
, void* data
)
867 wxASSERT( m_keyType
== wxKEY_STRING
);
869 size_t bucket
= size_t(hash
) % m_size
;
870 Node
* node
= new wxHashTableBase_Node( key
, data
, this );
872 DoInsertNode( bucket
, node
);
875 void* wxHashTableBase::DoGet( long key
, long hash
) const
877 wxASSERT( m_keyType
== wxKEY_INTEGER
);
879 size_t bucket
= size_t(hash
) % m_size
;
881 if( m_table
[bucket
] == NULL
)
884 Node
*first
= m_table
[bucket
]->GetNext(),
889 if( curr
->m_key
.integer
== key
)
890 return curr
->m_value
;
892 curr
= curr
->GetNext();
894 while( curr
!= first
);
899 void* wxHashTableBase::DoGet( const wxChar
* key
, long hash
) const
901 wxASSERT( m_keyType
== wxKEY_STRING
);
903 size_t bucket
= size_t(hash
) % m_size
;
905 if( m_table
[bucket
] == NULL
)
908 Node
*first
= m_table
[bucket
]->GetNext(),
913 if( wxStrcmp( curr
->m_key
.string
, key
) == 0 )
914 return curr
->m_value
;
916 curr
= curr
->GetNext();
918 while( curr
!= first
);
923 void wxHashTableBase::DoUnlinkNode( size_t bucket
, wxHashTableBase_Node
* node
,
924 wxHashTableBase_Node
* prev
)
926 if( node
== m_table
[bucket
] )
927 m_table
[bucket
] = prev
;
929 if( prev
== node
&& prev
== node
->GetNext() )
930 m_table
[bucket
] = NULL
;
932 prev
->m_next
= node
->m_next
;
934 DoDestroyNode( node
);
938 void* wxHashTableBase::DoDelete( long key
, long hash
)
940 wxASSERT( m_keyType
== wxKEY_INTEGER
);
942 size_t bucket
= size_t(hash
) % m_size
;
944 if( m_table
[bucket
] == NULL
)
947 Node
*first
= m_table
[bucket
]->GetNext(),
949 *prev
= m_table
[bucket
];
953 if( curr
->m_key
.integer
== key
)
955 void* retval
= curr
->m_value
;
956 curr
->m_value
= NULL
;
958 DoUnlinkNode( bucket
, curr
, prev
);
965 curr
= curr
->GetNext();
967 while( curr
!= first
);
972 void* wxHashTableBase::DoDelete( const wxChar
* key
, long hash
)
974 wxASSERT( m_keyType
== wxKEY_STRING
);
976 size_t bucket
= size_t(hash
) % m_size
;
978 if( m_table
[bucket
] == NULL
)
981 Node
*first
= m_table
[bucket
]->GetNext(),
983 *prev
= m_table
[bucket
];
987 if( wxStrcmp( curr
->m_key
.string
, key
) == 0 )
989 void* retval
= curr
->m_value
;
990 curr
->m_value
= NULL
;
992 DoUnlinkNode( bucket
, curr
, prev
);
999 curr
= curr
->GetNext();
1001 while( curr
!= first
);
1006 long wxHashTableBase::MakeKey( const wxChar
*str
)
1011 int_key
+= (wxUChar
)*str
++;
1016 // ----------------------------------------------------------------------------
1018 // ----------------------------------------------------------------------------
1020 wxHashTable::wxHashTable( const wxHashTable
& table
)
1026 const wxHashTable
& wxHashTable::operator=( const wxHashTable
& table
)
1034 void wxHashTable::DoCopy( const wxHashTable
& WXUNUSED(table
) )
1036 Create( m_keyType
, m_size
);
1041 void wxHashTable::DoDeleteContents( wxHashTableBase_Node
* node
)
1043 delete ((wxHashTable_Node
*)node
)->GetData();
1046 void wxHashTable::GetNextNode( size_t bucketStart
)
1048 for( size_t i
= bucketStart
; i
< m_size
; ++i
)
1050 if( m_table
[i
] != NULL
)
1052 m_curr
= ((Node
*)m_table
[i
])->GetNext();
1062 wxHashTable::Node
* wxHashTable::Next()
1064 if( m_curr
== NULL
)
1068 m_curr
= m_curr
->GetNext();
1070 if( m_curr
== ( (Node
*)m_table
[m_currBucket
] )->GetNext() )
1071 GetNextNode( m_currBucket
+ 1 );
1077 #endif // !wxUSE_OLD_HASH_TABLE