ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

hash_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 doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.