📄 hash_test.cpp
字号:
//Has to be first for StackAllocator swap overload to be taken//into account (at least using GCC 4.0.1)#include "stack_allocator.h"#include <vector>#include <algorithm>#include <map>#include <set>#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS)# include <hash_map># include <hash_set># include <rope>#endif#include <string>#include "cppunit/cppunit_proxy.h"#if defined (__MVS__)const char star = 92;#elseconst char star = 42;#endif#if !defined (STLPORT) || defined (_STLP_USE_NAMESPACES)using namespace std;#endif//// TestCase class//class HashTest : public CPPUNIT_NS::TestCase{ CPPUNIT_TEST_SUITE(HashTest);#if !defined (STLPORT) || defined (_STLP_NO_EXTENSIONS) CPPUNIT_IGNORE;#endif CPPUNIT_TEST(hmap1); CPPUNIT_TEST(hmmap1); CPPUNIT_TEST(hmmap2); CPPUNIT_TEST(hmset1); CPPUNIT_TEST(hset2); CPPUNIT_TEST(insert_erase); CPPUNIT_TEST(allocator_with_state); //CPPUNIT_TEST(equality); CPPUNIT_TEST_SUITE_END();#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) typedef hash_multiset<char, hash<char>, equal_to<char> > hmset;#endifprotected: void hmap1(); void hmmap1(); void hmmap2(); void hmset1(); void hset2(); void insert_erase(); //void equality(); void allocator_with_state();#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) typedef hash_multimap<int, int> hashType; typedef multimap<int, int> mapType; void check_keys( hashType& h, mapType& m );#endif};CPPUNIT_TEST_SUITE_REGISTRATION(HashTest);//// tests implementation//void HashTest::hmap1(){#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) typedef hash_map<char, crope, hash<char>, equal_to<char> > maptype; maptype m; // Store mappings between roman numerals and decimals. m['l'] = "50"; m['x'] = "20"; // Deliberate mistake. m['v'] = "5"; m['i'] = "1"; CPPUNIT_ASSERT( !strcmp(m['x'].c_str(),"20") ); m['x'] = "10"; // Correct mistake. CPPUNIT_ASSERT( !strcmp(m['x'].c_str(),"10") ); CPPUNIT_ASSERT( !strcmp(m['z'].c_str(),"") ); CPPUNIT_ASSERT( m.count('z')==1 ); pair<maptype::iterator, bool> p = m.insert(pair<const char, crope>('c', crope("100"))); CPPUNIT_ASSERT(p.second); p = m.insert(pair<const char, crope>('c', crope("100"))); CPPUNIT_ASSERT(!p.second); //Some iterators compare check, really compile time checks maptype::iterator ite(m.begin()); maptype::const_iterator cite(m.begin()); cite = m.begin(); maptype const& cm = m; cite = cm.begin(); CPPUNIT_ASSERT( ite == cite ); CPPUNIT_ASSERT( !(ite != cite) ); CPPUNIT_ASSERT( cite == ite ); CPPUNIT_ASSERT( !(cite != ite) );#endif}void HashTest::hmmap1(){#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) typedef hash_multimap<char, int, hash<char>,equal_to<char> > mmap; mmap m; CPPUNIT_ASSERT(m.count('X')==0); m.insert(pair<const char,int>('X', 10)); // Standard way. CPPUNIT_ASSERT(m.count('X')==1);// m.insert('X', 20); // Non-standard, but very convenient! m.insert(pair<const char,int>('X', 20)); // jbuck: standard way CPPUNIT_ASSERT(m.count('X')==2);// m.insert('Y', 32); m.insert(pair<const char,int>('Y', 32)); // jbuck: standard way mmap::iterator i = m.find('X'); // Find first match. CPPUNIT_ASSERT((*i).first=='X'); CPPUNIT_ASSERT((*i).second==10); i++; CPPUNIT_ASSERT((*i).first=='X'); CPPUNIT_ASSERT((*i).second==20); i++; CPPUNIT_ASSERT((*i).first=='Y'); CPPUNIT_ASSERT((*i).second==32); i++; CPPUNIT_ASSERT(i==m.end()); size_t count = m.erase('X'); CPPUNIT_ASSERT(count==2); //Some iterators compare check, really compile time checks mmap::iterator ite(m.begin()); mmap::const_iterator cite(m.begin()); CPPUNIT_ASSERT( ite == cite ); CPPUNIT_ASSERT( !(ite != cite) ); CPPUNIT_ASSERT( cite == ite ); CPPUNIT_ASSERT( !(cite != ite) ); typedef hash_multimap<size_t, size_t> HMapType; HMapType hmap; //We fill the map to implicitely start a rehash. for (size_t counter = 0; counter < 3077; ++counter) hmap.insert(HMapType::value_type(1, counter)); hmap.insert(HMapType::value_type(12325, 1)); hmap.insert(HMapType::value_type(12325, 2)); CPPUNIT_ASSERT( hmap.count(12325) == 2 ); //At this point 23 goes to the same bucket as 12325, it used to reveal a bug. hmap.insert(HMapType::value_type(23, 0)); CPPUNIT_ASSERT( hmap.count(12325) == 2 );#endif}#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS)// Short demonstrator that helps reproducing a bug in the hash-table implementation// of STLPort 5.0.1/5.0.2.//// Problem: Fill a hash_multimap with entries of which many have the same key// Internally, entries with the same key are kept as one block within the same bucket.// Thus, when calling equal_range(key) the begin/end of that block is returned.// However, this code shows that for key =3, that block is destroyed after inserting the 194th element.// According to _hashtable.c we will have a rehash from size 193 to size 389 in that situation.// After that rehash, equal_range only returns 2 elements with key = 3 whereas there are 65 in it.// Reproduction:// In the main()-method we fill a hash_multimap as well as a multi_map with the same <key, data> pairs// After each insertion we call check_keys(...) to assure validity of these two containers.// This works fine up to the 193th insertion. Insertion 194 generates the bug.//// check_keys() works as follows:// (a) we check whether both containers contain the same number of elements.// (b) Assuming that the multi_map works correctly, we iterate over all its elements and check// whether we can find that key also in the hash_multimap. We collect all data for that specific// key in in a set ("collection"). Notice that data is unique by construction in main(), thus the// number of elements in the set must equal the number of entries in the hash_multimap and in the multimap// (c) We check if we have seen as many data elements in collection as we have seen in the multimap.// if so, we print "OK", otherwise we print a detailed key/data overview and assert.// Caution:// There are several configurations of the program that will NOT fail. (see comment in code below)// E.g. it seems that whenever the keys are more or less sorted, the problem does not occur.// Also, using numbers from 200 downto 1 or from 300 downto 1 cannot generate the problem,// whereas using 400 downto 1 will fail.// Finally, if we use key 1 (rather than key 3) we cannot generate a problem.void HashTest::check_keys( HashTest::hashType& h, HashTest::mapType& m ){ set<int> collection; // (a) check sizes CPPUNIT_CHECK( h.size() == m.size() ); // (b) iterate over multi_map for ( mapType::iterator i = m.begin(); i != m.end(); ++i ) { // look up that key in hash-table and keep all data in the set pair<hashType::iterator,hashType::iterator> range = h.equal_range( i->first ); for ( hashType::iterator j = range.first; j != range.second; ++j ) { collection.insert( j->second ); } } // (c) we should have seen as many elements as there are in the hash-table#if 0 if (collection.size() == h.size()) cout << " OK" << endl; else { // if not, please report cout << " FAILED: " << endl; int lastKey = -1; // iterate over all elements in multi_map for (mapType::iterator mIter = m.begin(); mIter != m.end(); mIter++) { // new key? print a new status line if (mIter->first != lastKey) { cout << endl << "Key : " << mIter->first << endl; lastKey = mIter->first; // print all hashed values for that key cout << " data in hash: "; pair<hashType::iterator,hashType::iterator> range = h.equal_range(mIter->first); for (hashType::iterator h = range.first; h != range.second; h++) { assert (h->first == lastKey); cerr << h->second << ", "; // print all data for that key in Hash-Table } cout << endl << " data in map: "; } // and print all member in multi-map until the next key occurs cout << mIter->second << ", " ; // print all data for that key in Map } }#endif CPPUNIT_CHECK( collection.size() == h.size() );}#endifvoid HashTest::hmmap2(){#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) hashType h; mapType m; // CAUTION the following configurations WORKS in our setting // for (int id = 1; id != 400; id ++) and int key = (id %3 == 0 ? 3 : id) // for (int id = 200; id != 1; id --) and int key = (id %3 == 0 ? 3 : id) // for (int id = 300; id != 1; id --) and int key = (id %3 == 0 ? 3 : id) // for (int id = 400; id != 1; id --) and int key = (id %3 == 0 ? 1 : id) // for (int id = 4000; id != 1; id --) and int key = (id %3 == 0 ? 1 : id) // // whereas these will FAIL // for (int id = 400; id != 1; id --) and int key = (id %3 == 0 ? 3 : id) // for (int id = 4000; id != 1; id --) and int key = (id %3 == 0 ? 3 : id) // for ( int id = 400; id != 1; id-- ) { // generate many entries with key 3, fill up with unique keys. Data is unique (needed in check_keys()) int key = (id % 3 == 0 ? 3 : id); // keep hash_multi_map and multimap in sync h.insert(make_pair(key, id)); m.insert(make_pair(key, id)); // check whether both contain the same elements check_keys( h, m ); }#endif}void HashTest::hmset1(){#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) hmset s; CPPUNIT_ASSERT( s.count(star) == 0 ); s.insert(star); CPPUNIT_ASSERT( s.count(star) == 1 ); s.insert(star); CPPUNIT_ASSERT( s.count(star) == 2 ); hmset::iterator i = s.find(char(40)); CPPUNIT_ASSERT( i == s.end() ); i = s.find(star); CPPUNIT_ASSERT( i != s.end() ) CPPUNIT_ASSERT( *i == '*' ); CPPUNIT_ASSERT( s.erase(star) == 2 );#endif}void HashTest::hset2(){#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) hash_set<int, hash<int>, equal_to<int> > s; pair<hash_set<int, hash<int>, equal_to<int> >::iterator, bool> p = s.insert(42); CPPUNIT_ASSERT( p.second ); CPPUNIT_ASSERT( *(p.first) == 42 ); p = s.insert(42); CPPUNIT_ASSERT( !p.second );#endif}void HashTest::insert_erase(){#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) typedef hash_map<string, size_t, hash<string>, equal_to<string> > hmap; typedef hmap::value_type val_type; { hmap values;# if !defined (__BORLANDC__) || (__BORLANDC__ >= 0x564) CPPUNIT_ASSERT( values.insert(val_type("foo", 0)).second ); CPPUNIT_ASSERT( values.insert(val_type("bar", 0)).second ); CPPUNIT_ASSERT( values.insert(val_type("abc", 0)).second );# else CPPUNIT_ASSERT( values.insert(hmap::value_type("foo", 0)).second ); CPPUNIT_ASSERT( values.insert(hmap::value_type("bar", 0)).second ); CPPUNIT_ASSERT( values.insert(hmap::value_type("abc", 0)).second );# endif CPPUNIT_ASSERT( values.erase("foo") == 1 ); CPPUNIT_ASSERT( values.erase("bar") == 1 ); CPPUNIT_ASSERT( values.erase("abc") == 1 ); } { hmap values;# if !defined (__BORLANDC__) || (__BORLANDC__ >= 0x564) CPPUNIT_ASSERT( values.insert(val_type("foo", 0)).second ); CPPUNIT_ASSERT( values.insert(val_type("bar", 0)).second ); CPPUNIT_ASSERT( values.insert(val_type("abc", 0)).second );# else CPPUNIT_ASSERT( values.insert(hmap::value_type("foo", 0)).second ); CPPUNIT_ASSERT( values.insert(hmap::value_type("bar", 0)).second ); CPPUNIT_ASSERT( values.insert(hmap::value_type("abc", 0)).second );# endif CPPUNIT_ASSERT( values.erase("abc") == 1 ); CPPUNIT_ASSERT( values.erase("bar") == 1 ); CPPUNIT_ASSERT( values.erase("foo") == 1 ); }#endif}/* * Here is the test showing why equality operator on hash containers * has no meaning:struct equality_hash_func { size_t operator () (size_t val) const { return val % 10; }};void HashTest::equality(){ hash_set<size_t, equality_hash_func, equal_to<size_t> > s1, s2; s1.insert(10); s1.insert(20); s2.insert(20); s2.insert(10); //s1 and s2 contains both 10 and 20: CPPUNIT_ASSERT( s1 == s2 );}*/void HashTest::allocator_with_state(){#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) char buf1[2048]; StackAllocator<int> stack1(buf1, buf1 + sizeof(buf1)); char buf2[2048]; StackAllocator<int> stack2(buf2, buf2 + sizeof(buf2)); { typedef hash_set<int, hash<int>, equal_to<int>, StackAllocator<int> > HashSetInt; HashSetInt hint1(10, hash<int>(), equal_to<int>(), stack1); int i; for (i = 0; i < 5; ++i) hint1.insert(i); HashSetInt hint1Cpy(hint1); HashSetInt hint2(10, hash<int>(), equal_to<int>(), stack2); for (; i < 10; ++i) hint2.insert(i); HashSetInt hint2Cpy(hint2); hint1.swap(hint2); CPPUNIT_ASSERT( hint1.get_allocator().swaped() ); CPPUNIT_ASSERT( hint2.get_allocator().swaped() ); CPPUNIT_ASSERT( hint1.get_allocator() == stack2 ); CPPUNIT_ASSERT( hint2.get_allocator() == stack1 ); } CPPUNIT_ASSERT( stack1.ok() ); CPPUNIT_ASSERT( stack2.ok() );#endif}#if defined (STLPORT) && !defined (_STLP_NO_EXTENSIONS) && \ (!defined (_STLP_USE_PTR_SPECIALIZATIONS) || defined (_STLP_CLASS_PARTIAL_SPECIALIZATION))# if !defined (__DMC__)/* Simple compilation test: Check that nested types like iterator * can be access even if type used to instanciate container is not * yet completely defined. */class IncompleteClass{ hash_set<IncompleteClass> hsinstances; typedef hash_set<IncompleteClass>::iterator hsit; hash_multiset<IncompleteClass> hsminstances; typedef hash_multiset<IncompleteClass>::iterator hsmit; hash_map<IncompleteClass, IncompleteClass> hminstances; typedef hash_map<IncompleteClass, IncompleteClass>::iterator hmit; hash_multimap<IncompleteClass, IncompleteClass> hmminstances; typedef hash_multimap<IncompleteClass, IncompleteClass>::iterator hmmit;};# endif#endif
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -