]>
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"
37 #if wxUSE_OLD_HASH_TABLE
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
, wxEmptyString
, _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
);
314 return wxEmptyString
;
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_OLD_HASH_TABLE
729 wxHashTableBase_Node::wxHashTableBase_Node( long key
, void* value
,
730 wxHashTableBase
* table
)
731 : m_value( value
), m_hashPtr( table
)
736 wxHashTableBase_Node::wxHashTableBase_Node( const wxChar
* key
, void* value
,
737 wxHashTableBase
* table
)
738 : m_value( value
), m_hashPtr( table
)
740 m_key
.string
= wxStrcpy( new wxChar
[wxStrlen( key
) + 1], key
);
743 wxHashTableBase_Node::~wxHashTableBase_Node()
745 if( m_hashPtr
) m_hashPtr
->DoRemoveNode( this );
750 wxHashTableBase::wxHashTableBase()
751 : m_size( 0 ), m_count( 0 ), m_table( NULL
), m_keyType( wxKEY_NONE
),
752 m_deleteContents( false )
756 void wxHashTableBase::Create( wxKeyType keyType
, size_t size
)
760 m_table
= new wxHashTableBase_Node
*[ m_size
];
762 for( size_t i
= 0; i
< m_size
; ++i
)
766 void wxHashTableBase::Clear()
768 for( size_t i
= 0; i
< m_size
; ++i
)
770 Node
* end
= m_table
[i
];
775 Node
*curr
, *next
= end
->GetNext();
780 next
= curr
->GetNext();
782 DoDestroyNode( curr
);
786 while( curr
!= end
);
794 void wxHashTableBase::DoRemoveNode( wxHashTableBase_Node
* node
)
796 size_t bucket
= ( m_keyType
== wxKEY_INTEGER
?
797 node
->m_key
.integer
:
798 MakeKey( node
->m_key
.string
) ) % m_size
;
800 if( node
->GetNext() == node
)
802 // single-node chain (common case)
803 m_table
[bucket
] = NULL
;
807 Node
*start
= m_table
[bucket
], *curr
;
810 for( curr
= prev
->GetNext(); curr
!= node
;
811 prev
= curr
, curr
= curr
->GetNext() ) ;
813 DoUnlinkNode( bucket
, node
, prev
);
816 DoDestroyNode( node
);
819 void wxHashTableBase::DoDestroyNode( wxHashTableBase_Node
* node
)
821 // if it is called from DoRemoveNode, node has already been
822 // removed, from other places it does not matter
823 node
->m_hashPtr
= NULL
;
825 if( m_keyType
== wxKEY_STRING
)
826 delete[] node
->m_key
.string
;
827 if( m_deleteContents
)
828 DoDeleteContents( node
);
831 void wxHashTableBase::Destroy()
841 void wxHashTableBase::DoInsertNode( size_t bucket
, wxHashTableBase_Node
* node
)
843 if( m_table
[bucket
] == NULL
)
845 m_table
[bucket
] = node
->m_next
= node
;
849 Node
*prev
= m_table
[bucket
];
850 Node
*next
= prev
->m_next
;
854 m_table
[bucket
] = node
;
860 void wxHashTableBase::DoPut( long key
, long hash
, void* data
)
862 wxASSERT( m_keyType
== wxKEY_INTEGER
);
864 size_t bucket
= size_t(hash
) % m_size
;
865 Node
* node
= new wxHashTableBase_Node( key
, data
, this );
867 DoInsertNode( bucket
, node
);
870 void wxHashTableBase::DoPut( const wxChar
* key
, long hash
, void* data
)
872 wxASSERT( m_keyType
== wxKEY_STRING
);
874 size_t bucket
= size_t(hash
) % m_size
;
875 Node
* node
= new wxHashTableBase_Node( key
, data
, this );
877 DoInsertNode( bucket
, node
);
880 void* wxHashTableBase::DoGet( long key
, long hash
) const
882 wxASSERT( m_keyType
== wxKEY_INTEGER
);
884 size_t bucket
= size_t(hash
) % m_size
;
886 if( m_table
[bucket
] == NULL
)
889 Node
*first
= m_table
[bucket
]->GetNext(),
894 if( curr
->m_key
.integer
== key
)
895 return curr
->m_value
;
897 curr
= curr
->GetNext();
899 while( curr
!= first
);
904 void* wxHashTableBase::DoGet( const wxChar
* key
, long hash
) const
906 wxASSERT( m_keyType
== wxKEY_STRING
);
908 size_t bucket
= size_t(hash
) % m_size
;
910 if( m_table
[bucket
] == NULL
)
913 Node
*first
= m_table
[bucket
]->GetNext(),
918 if( wxStrcmp( curr
->m_key
.string
, key
) == 0 )
919 return curr
->m_value
;
921 curr
= curr
->GetNext();
923 while( curr
!= first
);
928 void wxHashTableBase::DoUnlinkNode( size_t bucket
, wxHashTableBase_Node
* node
,
929 wxHashTableBase_Node
* prev
)
931 if( node
== m_table
[bucket
] )
932 m_table
[bucket
] = prev
;
934 if( prev
== node
&& prev
== node
->GetNext() )
935 m_table
[bucket
] = NULL
;
937 prev
->m_next
= node
->m_next
;
939 DoDestroyNode( node
);
943 void* wxHashTableBase::DoDelete( long key
, long hash
)
945 wxASSERT( m_keyType
== wxKEY_INTEGER
);
947 size_t bucket
= size_t(hash
) % m_size
;
949 if( m_table
[bucket
] == NULL
)
952 Node
*first
= m_table
[bucket
]->GetNext(),
954 *prev
= m_table
[bucket
];
958 if( curr
->m_key
.integer
== key
)
960 void* retval
= curr
->m_value
;
961 curr
->m_value
= NULL
;
963 DoUnlinkNode( bucket
, curr
, prev
);
970 curr
= curr
->GetNext();
972 while( curr
!= first
);
977 void* wxHashTableBase::DoDelete( const wxChar
* key
, long hash
)
979 wxASSERT( m_keyType
== wxKEY_STRING
);
981 size_t bucket
= size_t(hash
) % m_size
;
983 if( m_table
[bucket
] == NULL
)
986 Node
*first
= m_table
[bucket
]->GetNext(),
988 *prev
= m_table
[bucket
];
992 if( wxStrcmp( curr
->m_key
.string
, key
) == 0 )
994 void* retval
= curr
->m_value
;
995 curr
->m_value
= NULL
;
997 DoUnlinkNode( bucket
, curr
, prev
);
1004 curr
= curr
->GetNext();
1006 while( curr
!= first
);
1011 long wxHashTableBase::MakeKey( const wxChar
*str
)
1016 int_key
+= (wxUChar
)*str
++;
1021 // ----------------------------------------------------------------------------
1023 // ----------------------------------------------------------------------------
1025 wxHashTable::wxHashTable( const wxHashTable
& table
)
1031 const wxHashTable
& wxHashTable::operator=( const wxHashTable
& table
)
1039 void wxHashTable::DoCopy( const wxHashTable
& WXUNUSED(table
) )
1041 Create( m_keyType
, m_size
);
1046 void wxHashTable::DoDeleteContents( wxHashTableBase_Node
* node
)
1048 delete ((wxHashTable_Node
*)node
)->GetData();
1051 void wxHashTable::GetNextNode( size_t bucketStart
)
1053 for( size_t i
= bucketStart
; i
< m_size
; ++i
)
1055 if( m_table
[i
] != NULL
)
1057 m_curr
= ((Node
*)m_table
[i
])->GetNext();
1067 wxHashTable::Node
* wxHashTable::Next()
1069 if( m_curr
== NULL
)
1073 m_curr
= m_curr
->GetNext();
1075 if( m_curr
== ( (Node
*)m_table
[m_currBucket
] )->GetNext() )
1076 GetNextNode( m_currBucket
+ 1 );
1082 #endif // !wxUSE_OLD_HASH_TABLE