]> git.saurik.com Git - wxWidgets.git/blame - tests/hashes/hashes.cpp
don't attempt to convert 8bit values to Unicode in ANSI build
[wxWidgets.git] / tests / hashes / hashes.cpp
CommitLineData
cbca1e08
MB
1///////////////////////////////////////////////////////////////////////////////
2// Name: tests/hashes/hashes.cpp
7d9cfc54 3// Purpose: wxHashTable, wxHashMap, wxHashSet unit test
cbca1e08 4// Author: Vadim Zeitlin, Mattia Barbon
d8b6309b 5// Modified: Mike Wetherell
cbca1e08
MB
6// Created: 2004-05-16
7// RCS-ID: $Id$
d8b6309b 8// Copyright: (c) 2004 Vadim Zeitlin, Mattia Barbon, 2005 M. Wetherell
cbca1e08
MB
9///////////////////////////////////////////////////////////////////////////////
10
11// ----------------------------------------------------------------------------
12// headers
13// ----------------------------------------------------------------------------
14
8899b155 15#include "testprec.h"
cbca1e08
MB
16
17#ifdef __BORLANDC__
18 #pragma hdrstop
19#endif
20
21#ifndef WX_PRECOMP
22 #include "wx/wx.h"
23#endif // WX_PRECOMP
24
25#include "wx/hash.h"
26#include "wx/hashmap.h"
27#include "wx/hashset.h"
28
d8b6309b
MW
29#if defined wxLongLong_t && !defined wxLongLongIsLong && \
30 (!defined __VISUALC__ || __VISUALC__ > 1100) // doesn't work on VC5
31 #define TEST_LONGLONG
32#endif
33
cbca1e08
MB
34// --------------------------------------------------------------------------
35// helper class for typed/untyped wxHashTable
36// --------------------------------------------------------------------------
37
38struct Foo
39{
40 Foo(int n_) { n = n_; count++; }
41 ~Foo() { count--; }
42
43 int n;
44
45 static size_t count;
46};
47
48size_t Foo::count = 0;
49
50struct FooObject : public wxObject
51{
52 FooObject(int n_) { n = n_; count++; }
53 ~FooObject() { count--; }
54
55 int n;
56
57 static size_t count;
58};
59
60size_t FooObject::count = 0;
61
62// --------------------------------------------------------------------------
63// test class
64// --------------------------------------------------------------------------
65
66class HashesTestCase : public CppUnit::TestCase
67{
68public:
69 HashesTestCase() { }
70
71private:
72 CPPUNIT_TEST_SUITE( HashesTestCase );
73 CPPUNIT_TEST( wxHashTableTest );
74 CPPUNIT_TEST( wxUntypedHashTableDeleteContents );
75 CPPUNIT_TEST( wxTypedHashTableTest );
d8b6309b
MW
76 CPPUNIT_TEST( StringHashMapTest );
77 CPPUNIT_TEST( PtrHashMapTest );
78 CPPUNIT_TEST( LongHashMapTest );
79 CPPUNIT_TEST( ULongHashMapTest );
80 CPPUNIT_TEST( UIntHashMapTest );
81 CPPUNIT_TEST( IntHashMapTest );
82 CPPUNIT_TEST( ShortHashMapTest );
83 CPPUNIT_TEST( UShortHashMapTest );
84#ifdef TEST_LONGLONG
85 CPPUNIT_TEST( LLongHashMapTest );
86 CPPUNIT_TEST( ULLongHashMapTest );
87#endif
cbca1e08
MB
88 CPPUNIT_TEST( wxHashSetTest );
89 CPPUNIT_TEST_SUITE_END();
90
91 void wxHashTableTest();
92 void wxUntypedHashTableDeleteContents();
93 void wxTypedHashTableTest();
d8b6309b
MW
94 void StringHashMapTest();
95 void PtrHashMapTest();
96 void LongHashMapTest();
97 void ULongHashMapTest();
98 void UIntHashMapTest();
99 void IntHashMapTest();
100 void ShortHashMapTest();
101 void UShortHashMapTest();
102#ifdef TEST_LONGLONG
103 void LLongHashMapTest();
104 void ULLongHashMapTest();
105#endif
cbca1e08
MB
106 void wxHashSetTest();
107
108 DECLARE_NO_COPY_CLASS(HashesTestCase)
109};
110
111// register in the unnamed registry so that these tests are run by default
112CPPUNIT_TEST_SUITE_REGISTRATION( HashesTestCase );
113
114// also include in it's own registry so that these tests can be run alone
115CPPUNIT_TEST_SUITE_NAMED_REGISTRATION( HashesTestCase, "HashesTestCase" );
116
117void HashesTestCase::wxHashTableTest()
118{
119 const int COUNT = 100;
120
121 {
122 wxHashTable hash(wxKEY_INTEGER, 10), hash2(wxKEY_STRING);
123 wxObject o;
124 int i;
125
126 for ( i = 0; i < COUNT; ++i )
127 hash.Put(i, &o + i);
128
129 hash.BeginFind();
130 wxHashTable::compatibility_iterator it = hash.Next();
131 i = 0;
132
133 while (it)
134 {
135 ++i;
136 it = hash.Next();
137 }
138
139 CPPUNIT_ASSERT( i == COUNT );
140
141 for ( i = 99; i >= 0; --i )
142 CPPUNIT_ASSERT( hash.Get(i) == &o + i );
143
144 for ( i = 0; i < COUNT; ++i )
145 hash.Put(i, &o + i + 20);
146
147 for ( i = 99; i >= 0; --i )
148 CPPUNIT_ASSERT( hash.Get(i) == &o + i);
149
150 for ( i = 0; i < COUNT/2; ++i )
151 CPPUNIT_ASSERT( hash.Delete(i) == &o + i);
152
153 for ( i = COUNT/2; i < COUNT; ++i )
154 CPPUNIT_ASSERT( hash.Get(i) == &o + i);
155
156 for ( i = 0; i < COUNT/2; ++i )
157 CPPUNIT_ASSERT( hash.Get(i) == &o + i + 20);
158
159 for ( i = 0; i < COUNT/2; ++i )
160 CPPUNIT_ASSERT( hash.Delete(i) == &o + i + 20);
161
162 for ( i = 0; i < COUNT/2; ++i )
163 CPPUNIT_ASSERT( hash.Get(i) == NULL);
164
165 hash2.Put(_T("foo"), &o + 1);
166 hash2.Put(_T("bar"), &o + 2);
167 hash2.Put(_T("baz"), &o + 3);
168
169 CPPUNIT_ASSERT(hash2.Get(_T("moo")) == NULL);
170 CPPUNIT_ASSERT(hash2.Get(_T("bar")) == &o + 2);
171
172 hash2.Put(_T("bar"), &o + 0);
173
174 CPPUNIT_ASSERT(hash2.Get(_T("bar")) == &o + 2);
175 }
176
177 // and now some corner-case testing; 3 and 13 hash to the same bucket
178 {
179 wxHashTable hash(wxKEY_INTEGER, 10);
180 wxObject dummy;
181
182 hash.Put(3, &dummy);
183 hash.Delete(3);
184
185 CPPUNIT_ASSERT(hash.Get(3) == NULL);
186
187 hash.Put(3, &dummy);
188 hash.Put(13, &dummy);
189 hash.Delete(3);
190
191 CPPUNIT_ASSERT(hash.Get(3) == NULL);
192
193 hash.Delete(13);
194
195 CPPUNIT_ASSERT(hash.Get(13) == NULL);
196
197 hash.Put(3, &dummy);
198 hash.Put(13, &dummy);
199 hash.Delete(13);
200
201 CPPUNIT_ASSERT(hash.Get(13) == NULL);
202
203 hash.Delete(3);
204
205 CPPUNIT_ASSERT(hash.Get(3) == NULL);
206 }
207
208 // test for key + value access (specifically that supplying either
209 // wrong key or wrong value returns NULL)
210 {
211 wxHashTable hash(wxKEY_INTEGER, 10);
212 wxObject dummy;
213
214 hash.Put(3, 7, &dummy + 7);
215 hash.Put(4, 8, &dummy + 8);
216
217 CPPUNIT_ASSERT(hash.Get(7) == NULL);
218 CPPUNIT_ASSERT(hash.Get(3, 7) == &dummy + 7);
219 CPPUNIT_ASSERT(hash.Get(4) == NULL);
220 CPPUNIT_ASSERT(hash.Get(3) == NULL);
221 CPPUNIT_ASSERT(hash.Get(8) == NULL);
222 CPPUNIT_ASSERT(hash.Get(8, 4) == NULL);
223
224 CPPUNIT_ASSERT(hash.Delete(7) == NULL);
225 CPPUNIT_ASSERT(hash.Delete(3) == NULL);
226 CPPUNIT_ASSERT(hash.Delete(3, 7) == &dummy + 7);
227 }
228
229}
230
231void HashesTestCase::wxUntypedHashTableDeleteContents()
232{
233 // need a nested scope for destruction
234 {
235 wxHashTable hash;
236 hash.DeleteContents(true);
237
238 CPPUNIT_ASSERT( hash.GetCount() == 0 );
239 CPPUNIT_ASSERT( FooObject::count == 0 );
240
241 static const int hashTestData[] =
242 {
243 0, 1, 17, -2, 2, 4, -4, 345, 3, 3, 2, 1,
244 };
245
246 size_t n;
247 for ( n = 0; n < WXSIZEOF(hashTestData); n++ )
248 {
249 hash.Put(hashTestData[n], n, new FooObject(n));
250 }
251
252 CPPUNIT_ASSERT( hash.GetCount() == WXSIZEOF(hashTestData) );
253 CPPUNIT_ASSERT( FooObject::count == WXSIZEOF(hashTestData) );
254
255 // delete from hash without deleting object
256 FooObject* foo = (FooObject*)hash.Delete(0l);
257
258 CPPUNIT_ASSERT( FooObject::count == WXSIZEOF(hashTestData) );
259 delete foo;
260 CPPUNIT_ASSERT( FooObject::count == WXSIZEOF(hashTestData) - 1 );
261 }
262
263 // hash destroyed
264 CPPUNIT_ASSERT( FooObject::count == 0 );
265}
266
cbca1e08
MB
267WX_DECLARE_HASH(Foo, wxListFoos, wxHashFoos);
268
cbca1e08
MB
269void HashesTestCase::wxTypedHashTableTest()
270{
271 // need a nested scope for destruction
272 {
273 wxHashFoos hash;
274 hash.DeleteContents(true);
275
276 CPPUNIT_ASSERT( hash.GetCount() == 0 );
277 CPPUNIT_ASSERT( Foo::count == 0 );
278
279 static const int hashTestData[] =
280 {
281 0, 1, 17, -2, 2, 4, -4, 345, 3, 3, 2, 1,
282 };
283
284 size_t n;
285 for ( n = 0; n < WXSIZEOF(hashTestData); n++ )
286 {
287 hash.Put(hashTestData[n], n, new Foo(n));
288 }
289
290 CPPUNIT_ASSERT( hash.GetCount() == WXSIZEOF(hashTestData) );
291 CPPUNIT_ASSERT( Foo::count == WXSIZEOF(hashTestData) );
292
293 for ( n = 0; n < WXSIZEOF(hashTestData); n++ )
294 {
295 Foo *foo = hash.Get(hashTestData[n], n);
296
297 CPPUNIT_ASSERT( foo != NULL );
298 CPPUNIT_ASSERT( foo->n == (int)n );
299 }
300
301 // element not in hash
302 CPPUNIT_ASSERT( hash.Get(1234) == NULL );
303 CPPUNIT_ASSERT( hash.Get(1, 0) == NULL );
304
305 // delete from hash without deleting object
306 Foo* foo = hash.Delete(0);
307
308 CPPUNIT_ASSERT( Foo::count == WXSIZEOF(hashTestData) );
309 delete foo;
310 CPPUNIT_ASSERT( Foo::count == WXSIZEOF(hashTestData) - 1 );
311 }
312
313 // hash destroyed
314 CPPUNIT_ASSERT( Foo::count == 0 );
315}
316
7d9cfc54
MB
317// test compilation of basic map types
318WX_DECLARE_HASH_MAP( int*, int*, wxPointerHash, wxPointerEqual, myPtrHashMap );
319WX_DECLARE_HASH_MAP( long, long, wxIntegerHash, wxIntegerEqual, myLongHashMap );
320WX_DECLARE_HASH_MAP( unsigned long, unsigned, wxIntegerHash, wxIntegerEqual,
321 myUnsignedHashMap );
322WX_DECLARE_HASH_MAP( unsigned int, unsigned, wxIntegerHash, wxIntegerEqual,
323 myTestHashMap1 );
324WX_DECLARE_HASH_MAP( int, unsigned, wxIntegerHash, wxIntegerEqual,
325 myTestHashMap2 );
326WX_DECLARE_HASH_MAP( short, unsigned, wxIntegerHash, wxIntegerEqual,
327 myTestHashMap3 );
328WX_DECLARE_HASH_MAP( unsigned short, unsigned, wxIntegerHash, wxIntegerEqual,
329 myTestHashMap4 );
330
331// same as:
332// WX_DECLARE_HASH_MAP( wxString, wxString, wxStringHash, wxStringEqual,
333// myStringHashMap );
334WX_DECLARE_STRING_HASH_MAP(wxString, myStringHashMap);
335
d8b6309b
MW
336#ifdef TEST_LONGLONG
337 WX_DECLARE_HASH_MAP( wxLongLong_t, wxLongLong_t,
338 wxIntegerHash, wxIntegerEqual, myLLongHashMap );
339 WX_DECLARE_HASH_MAP( wxULongLong_t, wxULongLong_t,
340 wxIntegerHash, wxIntegerEqual, myULLongHashMap );
341#endif
342
343// Helpers to generate a key value pair for item 'i', out of a total of 'count'
344void MakeKeyValuePair(size_t i, size_t /*count*/, wxString& key, wxString& val)
345{
346 key.clear();
347 key << i;
348 val = wxT("A") + key + wxT("C");
349}
350
351// for integral keys generate a range of keys that will use all the bits of
352// the key type
353template <class IntT, class KeyT>
354IntT MakeKey(size_t i, size_t count)
355{
356 IntT max = 1;
357 max <<= sizeof(KeyT) * 8 - 2;
358 max -= count / 4 + 1;
359
360 return max / count * 4 * i + i / 3;
361}
7d9cfc54 362
d8b6309b
MW
363// make key/value pairs for integer types
364template <class KeyT, class ValueT>
365void MakeKeyValuePair(size_t i, size_t count, KeyT& key, ValueT& value)
cbca1e08 366{
d8b6309b
MW
367 key = MakeKey<KeyT, KeyT>(i, count);
368 value = wx_truncate_cast(ValueT, key);
369}
370
371// make key/values paris for pointer types
372template <class T, class ValueT>
373void MakeKeyValuePair(size_t i, size_t count, T*& key, ValueT& value)
374{
375 key = (T*)wxUIntToPtr(MakeKey<wxUIntPtr, T*>(i, count));
376 value = wx_truncate_cast(ValueT, key);
377}
378
379// the test
380template <class HashMapT>
381void HashMapTest()
382{
383#if wxUSE_STL && defined HAVE_STL_HASH_MAP
384 typedef typename HashMapT::value_type::second_type value_type;
385#else
386 typedef typename HashMapT::value_type::t2 value_type;
387#endif
388 typedef typename HashMapT::key_type key_type;
389 typedef typename HashMapT::iterator Itor;
390
391 HashMapT sh(0); // as small as possible
392 key_type buf;
393 value_type value;
7d9cfc54
MB
394 size_t i;
395 const size_t count = 10000;
396
397 // init with some data
398 for( i = 0; i < count; ++i )
399 {
d8b6309b
MW
400 MakeKeyValuePair(i, count, buf, value);
401 sh[buf] = value;
7d9cfc54
MB
402 }
403
404 // test that insertion worked
405 CPPUNIT_ASSERT( sh.size() == count );
406
407 for( i = 0; i < count; ++i )
408 {
d8b6309b
MW
409 MakeKeyValuePair(i, count, buf, value);
410 CPPUNIT_ASSERT( sh[buf] == value );
7d9cfc54
MB
411 }
412
413 // check that iterators work
414 Itor it;
415 for( i = 0, it = sh.begin(); it != sh.end(); ++it, ++i )
416 {
417 CPPUNIT_ASSERT( i != count );
418 CPPUNIT_ASSERT( it->second == sh[it->first] );
419 }
420
421 CPPUNIT_ASSERT( sh.size() == i );
422
423 // test copy ctor, assignment operator
d8b6309b 424 HashMapT h1( sh ), h2( 0 );
7d9cfc54
MB
425 h2 = sh;
426
427 for( i = 0, it = sh.begin(); it != sh.end(); ++it, ++i )
428 {
429 CPPUNIT_ASSERT( h1[it->first] == it->second );
430 CPPUNIT_ASSERT( h2[it->first] == it->second );
431 }
432
433 // other tests
434 for( i = 0; i < count; ++i )
435 {
d8b6309b 436 MakeKeyValuePair(i, count, buf, value);
7d9cfc54
MB
437 size_t sz = sh.size();
438
439 // test find() and erase(it)
440 if( i < 100 )
441 {
442 it = sh.find( buf );
443 CPPUNIT_ASSERT( it != sh.end() );
444
445 sh.erase( it );
446
447 CPPUNIT_ASSERT( sh.find( buf ) == sh.end() );
448 }
449 else
450 // test erase(key)
451 {
452 size_t c = sh.erase( buf );
453 CPPUNIT_ASSERT( c == 1 );
454 CPPUNIT_ASSERT( sh.find( buf ) == sh.end() );
455 }
456
457 // count should decrease
458 CPPUNIT_ASSERT( sh.size() == sz - 1 );
459 }
cbca1e08
MB
460}
461
d8b6309b
MW
462void HashesTestCase::StringHashMapTest() { HashMapTest<myStringHashMap>(); }
463void HashesTestCase::PtrHashMapTest() { HashMapTest<myPtrHashMap>(); }
464void HashesTestCase::LongHashMapTest() { HashMapTest<myLongHashMap>(); }
465void HashesTestCase::ULongHashMapTest() { HashMapTest<myUnsignedHashMap>(); }
466void HashesTestCase::UIntHashMapTest() { HashMapTest<myTestHashMap1>(); }
467void HashesTestCase::IntHashMapTest() { HashMapTest<myTestHashMap2>(); }
468void HashesTestCase::ShortHashMapTest() { HashMapTest<myTestHashMap3>(); }
469void HashesTestCase::UShortHashMapTest() { HashMapTest<myTestHashMap4>(); }
470
471#ifdef TEST_LONGLONG
472void HashesTestCase::LLongHashMapTest() { HashMapTest<myLLongHashMap>(); }
473void HashesTestCase::ULLongHashMapTest() { HashMapTest<myULLongHashMap>(); }
474#endif
475
7d9cfc54
MB
476// test compilation of basic set types
477WX_DECLARE_HASH_SET( int*, wxPointerHash, wxPointerEqual, myPtrHashSet );
478WX_DECLARE_HASH_SET( long, wxIntegerHash, wxIntegerEqual, myLongHashSet );
479WX_DECLARE_HASH_SET( unsigned long, wxIntegerHash, wxIntegerEqual,
480 myUnsignedHashSet );
481WX_DECLARE_HASH_SET( unsigned int, wxIntegerHash, wxIntegerEqual,
482 myTestHashSet1 );
483WX_DECLARE_HASH_SET( int, wxIntegerHash, wxIntegerEqual,
484 myTestHashSet2 );
485WX_DECLARE_HASH_SET( short, wxIntegerHash, wxIntegerEqual,
486 myTestHashSet3 );
487WX_DECLARE_HASH_SET( unsigned short, wxIntegerHash, wxIntegerEqual,
488 myTestHashSet4 );
489WX_DECLARE_HASH_SET( wxString, wxStringHash, wxStringEqual,
490 myTestHashSet5 );
491
492struct MyStruct
493{
494 int* ptr;
495 wxString str;
496};
497
498class MyHash
499{
500public:
501 unsigned long operator()(const MyStruct& s) const
502 { return m_dummy(s.ptr); }
503 MyHash& operator=(const MyHash&) { return *this; }
504private:
505 wxPointerHash m_dummy;
506};
507
508class MyEqual
509{
510public:
511 bool operator()(const MyStruct& s1, const MyStruct& s2) const
512 { return s1.ptr == s2.ptr; }
513 MyEqual& operator=(const MyEqual&) { return *this; }
514};
515
516WX_DECLARE_HASH_SET( MyStruct, MyHash, MyEqual, mySet );
517
518typedef myTestHashSet5 wxStringHashSet;
519
cbca1e08
MB
520void HashesTestCase::wxHashSetTest()
521{
7d9cfc54
MB
522 wxStringHashSet set1;
523
524 set1.insert( _T("abc") );
525
526 CPPUNIT_ASSERT( set1.size() == 1 );
527
528 set1.insert( _T("bbc") );
529 set1.insert( _T("cbc") );
530
531 CPPUNIT_ASSERT( set1.size() == 3 );
532
533 set1.insert( _T("abc") );
534
535 CPPUNIT_ASSERT( set1.size() == 3 );
536
537 mySet set2;
538 int dummy;
539 MyStruct tmp;
540
541 tmp.ptr = &dummy; tmp.str = _T("ABC");
542 set2.insert( tmp );
543 tmp.ptr = &dummy + 1;
544 set2.insert( tmp );
545 tmp.ptr = &dummy; tmp.str = _T("CDE");
546 set2.insert( tmp );
547
548 CPPUNIT_ASSERT( set2.size() == 2 );
549
550 mySet::iterator it = set2.find( tmp );
551
552 CPPUNIT_ASSERT( it != set2.end() );
553 CPPUNIT_ASSERT( it->ptr == &dummy );
554 CPPUNIT_ASSERT( it->str == _T("ABC") );
cbca1e08 555}