Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygenhash_test.cpp
Go to the documentation of this file.
00001 //Has to be first for StackAllocator swap overload to be taken 00002 //into account (at least using GCC 4.0.1) 00003 #include "stack_allocator.h" 00004 00005 #include <vector> 00006 #include <algorithm> 00007 #include <map> 00008 #include <set> 00009 00010 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00011 # include <hash_map> 00012 # include <hash_set> 00013 # include <rope> 00014 #endif 00015 00016 #include <string> 00017 00018 #include "cppunit/cppunit_proxy.h" 00019 00020 #if defined (__MVS__) 00021 const char star = 92; 00022 #else 00023 const char star = 42; 00024 #endif 00025 00026 #if !defined (STLPORT) || defined (_STLP_USE_NAMESPACES) 00027 using namespace std; 00028 #endif 00029 00030 // 00031 // TestCase class 00032 // 00033 class HashTest : public CPPUNIT_NS::TestCase 00034 { 00035 CPPUNIT_TEST_SUITE(HashTest); 00036 #if !defined (STLPORT) || defined (_STLP_NO_EXTENSIONS) 00037 CPPUNIT_IGNORE; 00038 #endif 00039 CPPUNIT_TEST(hmap1); 00040 CPPUNIT_TEST(hmmap1); 00041 CPPUNIT_TEST(hmmap2); 00042 CPPUNIT_TEST(hmset1); 00043 CPPUNIT_TEST(hset2); 00044 CPPUNIT_TEST(insert_erase); 00045 CPPUNIT_TEST(allocator_with_state); 00046 //CPPUNIT_TEST(equality); 00047 CPPUNIT_TEST_SUITE_END(); 00048 00049 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00050 typedef hash_multiset<char, hash<char>, equal_to<char> > hmset; 00051 #endif 00052 00053 protected: 00054 void hmap1(); 00055 void hmmap1(); 00056 void hmmap2(); 00057 void hmset1(); 00058 void hset2(); 00059 void insert_erase(); 00060 //void equality(); 00061 void allocator_with_state(); 00062 00063 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00064 typedef hash_multimap<int, int> hashType; 00065 typedef multimap<int, int> mapType; 00066 00067 void check_keys( hashType& h, mapType& m ); 00068 #endif 00069 }; 00070 00071 CPPUNIT_TEST_SUITE_REGISTRATION(HashTest); 00072 00073 // 00074 // tests implementation 00075 // 00076 void HashTest::hmap1() 00077 { 00078 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00079 typedef hash_map<char, crope, hash<char>, equal_to<char> > maptype; 00080 maptype m; 00081 // Store mappings between roman numerals and decimals. 00082 m['l'] = "50"; 00083 m['x'] = "20"; // Deliberate mistake. 00084 m['v'] = "5"; 00085 m['i'] = "1"; 00086 CPPUNIT_ASSERT( !strcmp(m['x'].c_str(),"20") ); 00087 m['x'] = "10"; // Correct mistake. 00088 CPPUNIT_ASSERT( !strcmp(m['x'].c_str(),"10") ); 00089 00090 CPPUNIT_ASSERT( !strcmp(m['z'].c_str(),"") ); 00091 00092 CPPUNIT_ASSERT( m.count('z')==1 ); 00093 pair<maptype::iterator, bool> p = m.insert(pair<const char, crope>('c', crope("100"))); 00094 00095 CPPUNIT_ASSERT(p.second); 00096 00097 p = m.insert(pair<const char, crope>('c', crope("100"))); 00098 CPPUNIT_ASSERT(!p.second); 00099 00100 //Some iterators compare check, really compile time checks 00101 maptype::iterator ite(m.begin()); 00102 maptype::const_iterator cite(m.begin()); 00103 cite = m.begin(); 00104 maptype const& cm = m; 00105 cite = cm.begin(); 00106 CPPUNIT_ASSERT( ite == cite ); 00107 CPPUNIT_ASSERT( !(ite != cite) ); 00108 CPPUNIT_ASSERT( cite == ite ); 00109 CPPUNIT_ASSERT( !(cite != ite) ); 00110 #endif 00111 } 00112 00113 void HashTest::hmmap1() 00114 { 00115 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00116 typedef hash_multimap<char, int, hash<char>,equal_to<char> > mmap; 00117 mmap m; 00118 CPPUNIT_ASSERT(m.count('X')==0); 00119 m.insert(pair<const char,int>('X', 10)); // Standard way. 00120 CPPUNIT_ASSERT(m.count('X')==1); 00121 // m.insert('X', 20); // Non-standard, but very convenient! 00122 m.insert(pair<const char,int>('X', 20)); // jbuck: standard way 00123 CPPUNIT_ASSERT(m.count('X')==2); 00124 // m.insert('Y', 32); 00125 m.insert(pair<const char,int>('Y', 32)); // jbuck: standard way 00126 mmap::iterator i = m.find('X'); // Find first match. 00127 00128 CPPUNIT_ASSERT((*i).first=='X'); 00129 CPPUNIT_ASSERT((*i).second==10); 00130 i++; 00131 CPPUNIT_ASSERT((*i).first=='X'); 00132 CPPUNIT_ASSERT((*i).second==20); 00133 i++; 00134 CPPUNIT_ASSERT((*i).first=='Y'); 00135 CPPUNIT_ASSERT((*i).second==32); 00136 i++; 00137 CPPUNIT_ASSERT(i==m.end()); 00138 00139 size_t count = m.erase('X'); 00140 CPPUNIT_ASSERT(count==2); 00141 00142 //Some iterators compare check, really compile time checks 00143 mmap::iterator ite(m.begin()); 00144 mmap::const_iterator cite(m.begin()); 00145 CPPUNIT_ASSERT( ite == cite ); 00146 CPPUNIT_ASSERT( !(ite != cite) ); 00147 CPPUNIT_ASSERT( cite == ite ); 00148 CPPUNIT_ASSERT( !(cite != ite) ); 00149 00150 typedef hash_multimap<size_t, size_t> HMapType; 00151 HMapType hmap; 00152 00153 //We fill the map to implicitely start a rehash. 00154 for (size_t counter = 0; counter < 3077; ++counter) 00155 hmap.insert(HMapType::value_type(1, counter)); 00156 00157 hmap.insert(HMapType::value_type(12325, 1)); 00158 hmap.insert(HMapType::value_type(12325, 2)); 00159 00160 CPPUNIT_ASSERT( hmap.count(12325) == 2 ); 00161 00162 //At this point 23 goes to the same bucket as 12325, it used to reveal a bug. 00163 hmap.insert(HMapType::value_type(23, 0)); 00164 00165 CPPUNIT_ASSERT( hmap.count(12325) == 2 ); 00166 #endif 00167 } 00168 00169 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00170 // Short demonstrator that helps reproducing a bug in the hash-table implementation 00171 // of STLPort 5.0.1/5.0.2. 00172 // 00173 // Problem: Fill a hash_multimap with entries of which many have the same key 00174 // Internally, entries with the same key are kept as one block within the same bucket. 00175 // Thus, when calling equal_range(key) the begin/end of that block is returned. 00176 // However, this code shows that for key =3, that block is destroyed after inserting the 194th element. 00177 // According to _hashtable.c we will have a rehash from size 193 to size 389 in that situation. 00178 // After that rehash, equal_range only returns 2 elements with key = 3 whereas there are 65 in it. 00179 // Reproduction: 00180 // In the main()-method we fill a hash_multimap as well as a multi_map with the same <key, data> pairs 00181 // After each insertion we call check_keys(...) to assure validity of these two containers. 00182 // This works fine up to the 193th insertion. Insertion 194 generates the bug. 00183 // 00184 // check_keys() works as follows: 00185 // (a) we check whether both containers contain the same number of elements. 00186 // (b) Assuming that the multi_map works correctly, we iterate over all its elements and check 00187 // whether we can find that key also in the hash_multimap. We collect all data for that specific 00188 // key in in a set ("collection"). Notice that data is unique by construction in main(), thus the 00189 // number of elements in the set must equal the number of entries in the hash_multimap and in the multimap 00190 // (c) We check if we have seen as many data elements in collection as we have seen in the multimap. 00191 // if so, we print "OK", otherwise we print a detailed key/data overview and assert. 00192 // Caution: 00193 // There are several configurations of the program that will NOT fail. (see comment in code below) 00194 // E.g. it seems that whenever the keys are more or less sorted, the problem does not occur. 00195 // Also, using numbers from 200 downto 1 or from 300 downto 1 cannot generate the problem, 00196 // whereas using 400 downto 1 will fail. 00197 // Finally, if we use key 1 (rather than key 3) we cannot generate a problem. 00198 00199 void HashTest::check_keys( HashTest::hashType& h, HashTest::mapType& m ) 00200 { 00201 set<int> collection; 00202 00203 // (a) check sizes 00204 CPPUNIT_CHECK( h.size() == m.size() ); 00205 00206 // (b) iterate over multi_map 00207 for ( mapType::iterator i = m.begin(); i != m.end(); ++i ) { 00208 // look up that key in hash-table and keep all data in the set 00209 pair<hashType::iterator,hashType::iterator> range = h.equal_range( i->first ); 00210 for ( hashType::iterator j = range.first; j != range.second; ++j ) { 00211 collection.insert( j->second ); 00212 } 00213 } 00214 // (c) we should have seen as many elements as there are in the hash-table 00215 #if 0 00216 if (collection.size() == h.size()) cout << " OK" << endl; 00217 else { 00218 // if not, please report 00219 cout << " FAILED: " << endl; 00220 int lastKey = -1; 00221 // iterate over all elements in multi_map 00222 for (mapType::iterator mIter = m.begin(); mIter != m.end(); mIter++) { 00223 // new key? print a new status line 00224 if (mIter->first != lastKey) { 00225 cout << endl << "Key : " << mIter->first << endl; 00226 lastKey = mIter->first; 00227 00228 // print all hashed values for that key 00229 cout << " data in hash: "; 00230 pair<hashType::iterator,hashType::iterator> range = h.equal_range(mIter->first); 00231 00232 for (hashType::iterator h = range.first; h != range.second; h++) { 00233 assert (h->first == lastKey); 00234 cerr << h->second << ", "; // print all data for that key in Hash-Table 00235 } 00236 cout << endl << " data in map: "; 00237 } 00238 // and print all member in multi-map until the next key occurs 00239 cout << mIter->second << ", " ; // print all data for that key in Map 00240 } 00241 } 00242 #endif 00243 CPPUNIT_CHECK( collection.size() == h.size() ); 00244 } 00245 00246 #endif 00247 00248 void HashTest::hmmap2() 00249 { 00250 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00251 hashType h; 00252 mapType m; 00253 00254 // CAUTION the following configurations WORKS in our setting 00255 // for (int id = 1; id != 400; id ++) and int key = (id %3 == 0 ? 3 : id) 00256 // for (int id = 200; id != 1; id --) and int key = (id %3 == 0 ? 3 : id) 00257 // for (int id = 300; id != 1; id --) and int key = (id %3 == 0 ? 3 : id) 00258 // for (int id = 400; id != 1; id --) and int key = (id %3 == 0 ? 1 : id) 00259 // for (int id = 4000; id != 1; id --) and int key = (id %3 == 0 ? 1 : id) 00260 // 00261 // whereas these will FAIL 00262 // for (int id = 400; id != 1; id --) and int key = (id %3 == 0 ? 3 : id) 00263 // for (int id = 4000; id != 1; id --) and int key = (id %3 == 0 ? 3 : id) 00264 // 00265 00266 for ( int id = 400; id != 1; id-- ) { 00267 // generate many entries with key 3, fill up with unique keys. Data is unique (needed in check_keys()) 00268 int key = (id % 3 == 0 ? 3 : id); 00269 00270 // keep hash_multi_map and multimap in sync 00271 h.insert(make_pair(key, id)); 00272 m.insert(make_pair(key, id)); 00273 00274 // check whether both contain the same elements 00275 check_keys( h, m ); 00276 } 00277 #endif 00278 } 00279 00280 void HashTest::hmset1() 00281 { 00282 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00283 hmset s; 00284 CPPUNIT_ASSERT( s.count(star) == 0 ); 00285 s.insert(star); 00286 CPPUNIT_ASSERT( s.count(star) == 1 ); 00287 s.insert(star); 00288 CPPUNIT_ASSERT( s.count(star) == 2 ); 00289 hmset::iterator i = s.find(char(40)); 00290 CPPUNIT_ASSERT( i == s.end() ); 00291 00292 i = s.find(star); 00293 CPPUNIT_ASSERT( i != s.end() ) 00294 CPPUNIT_ASSERT( *i == '*' ); 00295 CPPUNIT_ASSERT( s.erase(star) == 2 ); 00296 #endif 00297 } 00298 void HashTest::hset2() 00299 { 00300 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00301 hash_set<int, hash<int>, equal_to<int> > s; 00302 pair<hash_set<int, hash<int>, equal_to<int> >::iterator, bool> p = s.insert(42); 00303 CPPUNIT_ASSERT( p.second ); 00304 CPPUNIT_ASSERT( *(p.first) == 42 ); 00305 00306 p = s.insert(42); 00307 CPPUNIT_ASSERT( !p.second ); 00308 #endif 00309 } 00310 00311 void HashTest::insert_erase() 00312 { 00313 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00314 typedef hash_map<string, size_t, hash<string>, equal_to<string> > hmap; 00315 typedef hmap::value_type val_type; 00316 { 00317 hmap values; 00318 # if !defined (__BORLANDC__) || (__BORLANDC__ >= 0x564) 00319 CPPUNIT_ASSERT( values.insert(val_type("foo", 0)).second ); 00320 CPPUNIT_ASSERT( values.insert(val_type("bar", 0)).second ); 00321 CPPUNIT_ASSERT( values.insert(val_type("abc", 0)).second ); 00322 # else 00323 CPPUNIT_ASSERT( values.insert(hmap::value_type("foo", 0)).second ); 00324 CPPUNIT_ASSERT( values.insert(hmap::value_type("bar", 0)).second ); 00325 CPPUNIT_ASSERT( values.insert(hmap::value_type("abc", 0)).second ); 00326 # endif 00327 00328 CPPUNIT_ASSERT( values.erase("foo") == 1 ); 00329 CPPUNIT_ASSERT( values.erase("bar") == 1 ); 00330 CPPUNIT_ASSERT( values.erase("abc") == 1 ); 00331 } 00332 00333 { 00334 hmap values; 00335 # if !defined (__BORLANDC__) || (__BORLANDC__ >= 0x564) 00336 CPPUNIT_ASSERT( values.insert(val_type("foo", 0)).second ); 00337 CPPUNIT_ASSERT( values.insert(val_type("bar", 0)).second ); 00338 CPPUNIT_ASSERT( values.insert(val_type("abc", 0)).second ); 00339 # else 00340 CPPUNIT_ASSERT( values.insert(hmap::value_type("foo", 0)).second ); 00341 CPPUNIT_ASSERT( values.insert(hmap::value_type("bar", 0)).second ); 00342 CPPUNIT_ASSERT( values.insert(hmap::value_type("abc", 0)).second ); 00343 # endif 00344 00345 CPPUNIT_ASSERT( values.erase("abc") == 1 ); 00346 CPPUNIT_ASSERT( values.erase("bar") == 1 ); 00347 CPPUNIT_ASSERT( values.erase("foo") == 1 ); 00348 } 00349 #endif 00350 } 00351 00352 /* 00353 * Here is the test showing why equality operator on hash containers 00354 * has no meaning: 00355 00356 struct equality_hash_func { 00357 size_t operator () (size_t val) const { 00358 return val % 10; 00359 } 00360 }; 00361 00362 void HashTest::equality() 00363 { 00364 hash_set<size_t, equality_hash_func, equal_to<size_t> > s1, s2; 00365 00366 s1.insert(10); 00367 s1.insert(20); 00368 00369 s2.insert(20); 00370 s2.insert(10); 00371 00372 //s1 and s2 contains both 10 and 20: 00373 CPPUNIT_ASSERT( s1 == s2 ); 00374 } 00375 */ 00376 00377 void HashTest::allocator_with_state() 00378 { 00379 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) 00380 char buf1[2048]; 00381 StackAllocator<int> stack1(buf1, buf1 + sizeof(buf1)); 00382 00383 char buf2[2048]; 00384 StackAllocator<int> stack2(buf2, buf2 + sizeof(buf2)); 00385 00386 { 00387 typedef hash_set<int, hash<int>, equal_to<int>, StackAllocator<int> > HashSetInt; 00388 HashSetInt hint1(10, hash<int>(), equal_to<int>(), stack1); 00389 00390 int i; 00391 for (i = 0; i < 5; ++i) 00392 hint1.insert(i); 00393 HashSetInt hint1Cpy(hint1); 00394 00395 HashSetInt hint2(10, hash<int>(), equal_to<int>(), stack2); 00396 for (; i < 10; ++i) 00397 hint2.insert(i); 00398 HashSetInt hint2Cpy(hint2); 00399 00400 hint1.swap(hint2); 00401 00402 CPPUNIT_ASSERT( hint1.get_allocator().swaped() ); 00403 CPPUNIT_ASSERT( hint2.get_allocator().swaped() ); 00404 00405 CPPUNIT_ASSERT( hint1.get_allocator() == stack2 ); 00406 CPPUNIT_ASSERT( hint2.get_allocator() == stack1 ); 00407 } 00408 CPPUNIT_ASSERT( stack1.ok() ); 00409 CPPUNIT_ASSERT( stack2.ok() ); 00410 #endif 00411 } 00412 00413 #if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) && \ 00414 (!defined (_STLP_USE_PTR_SPECIALIZATIONS) || defined (_STLP_CLASS_PARTIAL_SPECIALIZATION)) 00415 # if !defined (__DMC__) 00416 00417 /* Simple compilation test: Check that nested types like iterator 00418 * can be access even if type used to instanciate container is not 00419 * yet completely defined. 00420 */ 00421 class IncompleteClass 00422 { 00423 hash_set<IncompleteClass> hsinstances; 00424 typedef hash_set<IncompleteClass>::iterator hsit; 00425 hash_multiset<IncompleteClass> hsminstances; 00426 typedef hash_multiset<IncompleteClass>::iterator hsmit; 00427 00428 hash_map<IncompleteClass, IncompleteClass> hminstances; 00429 typedef hash_map<IncompleteClass, IncompleteClass>::iterator hmit; 00430 hash_multimap<IncompleteClass, IncompleteClass> hmminstances; 00431 typedef hash_multimap<IncompleteClass, IncompleteClass>::iterator hmmit; 00432 }; 00433 # endif 00434 #endif Generated on Fri May 25 2012 04:33:53 for ReactOS by
1.7.6.1
|