//////////////////////////////////////////////////////////////////////////////// // flex_string // Copyright (c) 2001 by Andrei Alexandrescu // Permission to use, copy, modify, distribute and sell this software for any // purpose is hereby granted without fee, provided that the above copyright // notice appear in all copies and that both that copyright notice and this // permission notice appear in supporting documentation. // The author makes no representations about the // suitability of this software for any purpose. It is provided "as is" // without express or implied warranty. //////////////////////////////////////////////////////////////////////////////// // $Id$ #ifdef _MSC_VER #pragma warning (disable : 4786) // Get rid of browser information too long names #ifdef _DEBUG #pragma warning (disable : 4786) #endif #endif #include #include #ifndef __MWERKS__ //#define NO_ALLOCATOR_REBIND //#define NO_ITERATOR_TRAITS #endif #include #include #include #include #include using namespace std; typedef flex_string< char, std::char_traits, std::allocator, AllocatorStringStorage > > my_string; template class flex_string< char, std::char_traits, std::allocator, AllocatorStringStorage > >; template Integral2 random(Integral1 low, Integral2 up) { Integral2 low2(low); assert(up >= low2); if (low2 == up) return low; Integral2 x = Integral2(low2 + (rand() * (up - low2)) / RAND_MAX); assert(x >= low2 && x <= up); return x; } template String RandomString(const String* /* model */, unsigned int maxSize) { String result(random(0, maxSize), '\0'); size_t i = 0; for (; i != result.size(); ++i) { result[i] = random('a', 'z'); } return result; } template void Num2String(String& str, Integral ) { str.resize(10, '\0'); // ultoa((unsigned long)n, &str[0], 10); sprintf(&str[0], "%ul", 10); str.resize(strlen(str.c_str())); } std::list RandomList(unsigned int maxSize) { std::list lst(random(0u, maxSize)); std::list::iterator i = lst.begin(); for (; i != lst.end(); ++i) { *i = random('a', 'z'); } return lst; } int currentTest = 0; template String Test(String, unsigned int count, bool avoidAliasing) { typedef typename String::size_type size_type; const size_type maxString = 1000; String test; while (count--) { test = RandomString(&test, maxString); static unsigned int functionSelector = 0; ++functionSelector; currentTest = functionSelector % 95; //std::cout << currentTest <<"\n"; switch (currentTest) { case 0: // test default constructor 21.3.1 return String(); break; case 1: // test copy constructor 21.3.1 { const size_type pos = random(0, test.size()); String s(test, pos, random(0, static_cast(test.size() - pos))); test = s; } break; case 2: // test constructor 21.3.1 { const size_type pos = random(0, test.size()), n = random(0, test.size() - pos); String s(test.c_str() + pos, n); test = s; } break; case 3: // test constructor 21.3.1 { const size_type pos = random(0, test.size()); String s(test.c_str() + pos); test = s; } break; case 4: // test assignment 21.3.1 { String s(random(0, 1000), '\0'); size_type i = 0; for (; i != s.size(); ++i) { s[i] = random('a', 'z'); } test = s; } break; case 5: // test assignment 21.3.1 { String s(random(0, 1000), '\0'); size_type i = 0; for (; i != s.size(); ++i) { s[i] = random('a', 'z'); } test = s.c_str(); } break; case 6: // test aliased assignment 21.3.1 { const size_t pos = random(0, test.size()); if (avoidAliasing) { test = String(test.c_str() + pos); } else { test = test.c_str() + pos; } } break; case 7: // test assignment 21.3.1 test = random('a', 'z'); break; case 8: // exercise iterators 21.3.2 test.begin(); test.end(); test.rbegin(); test.rend(); break; case 9: // exercise capacity 21.3.3 test.size(); test.length(); test.max_size(); test.capacity(); break; case 10: // test resize test.resize(random(0, test.size()), random('a', 'z')); break; case 11: // test resize with 1 arg test.resize(random(0, test.size())); break; case 12: // test reserve test.reserve(random(0, 1000)); break; case 13: // test clear test.clear(); // skip because std::string doesn't support it break; case 14: // exercise empty { const char* kEmptyString = "empty"; const char* kNonEmptyString = "not empty"; if (test.empty()) test = "empty"; else test = "not empty"; // the above assignments don't work yet; use iterator assign if (test.empty()) test = String(kEmptyString, kEmptyString + strlen(kEmptyString)); else test = String(kNonEmptyString, kNonEmptyString + strlen(kNonEmptyString)); } break; case 15: // exercise element access 21.3.4 if(!test.empty()) { test[random(0, test.size() - 1)]; test.at(random(0, test.size() - 1)); } break; case 16: // 21.3.5 modifiers test += RandomString(&test, maxString); break; case 17: // aliasing modifiers test += test; break; case 18: // 21.3.5 modifiers test += RandomString(&test, maxString).c_str(); break; case 19: // aliasing modifiers if (avoidAliasing) { test += String(test.c_str() + random(0, test.size())); } else { test += test.c_str() + random(0, test.size()); } break; case 20: // 21.3.5 modifiers test += random('a', 'z'); break; case 21: // 21.3.5 modifiers test.append(RandomString(&test, maxString)); break; case 22: // 21.3.5 modifiers { String s(RandomString(&test, maxString)); test.append(s, random(0, s.size()), random(0, maxString)); } break; case 23: // 21.3.5 modifiers { String s = RandomString(&test, maxString); test.append(s.c_str(), random(0, s.size())); } break; case 24: // 21.3.5 modifiers test.append(RandomString(&test, maxString).c_str()); break; case 25: // 21.3.5 modifiers test.append(random(0, maxString), random('a', 'z')); break; case 26: { std::list lst(RandomList(maxString)); test.append(lst.begin(), lst.end()); } break; case 27: // 21.3.5 modifiers // skip push_back, Dinkumware doesn't support it test.push_back(random('a', 'z')); break; case 28: // 21.3.5 modifiers test.assign(RandomString(&test, maxString)); break; case 29: // 21.3.5 modifiers { String str = RandomString(&test, maxString); test.assign(str, random(0, str.size()), random(0, maxString)); } break; case 30: // 21.3.5 modifiers { String str = RandomString(&test, maxString); test.assign(str.c_str(), random(0, str.size())); } break; case 31: // 21.3.5 modifiers test.assign(RandomString(&test, maxString).c_str()); break; case 32: // 21.3.5 modifiers test.assign(random(0, maxString), random('a', 'z')); break; case 33: // 21.3.5 modifiers { // skip, Dinkumware doesn't support it std::list lst(RandomList(maxString)); test.assign(lst.begin(), lst.end()); } break; case 34: // 21.3.5 modifiers test.insert(random(0, test.size()), RandomString(&test, maxString)); break; case 35: // 21.3.5 modifiers { String str = RandomString(&test, maxString); test.insert(random(0, test.size()), str, random(0, str.size()), random(0, maxString)); } break; case 36: // 21.3.5 modifiers { String str = RandomString(&test, maxString); test.insert(random(0, test.size()), str.c_str(), random(0, str.size())); } break; case 37: // 21.3.5 modifiers test.insert(random(0, test.size()), RandomString(&test, maxString).c_str()); break; case 38: // 21.3.5 modifiers test.insert(random(0, test.size()), random(0, maxString), random('a', 'z')); break; case 39: // 21.3.5 modifiers test.insert(test.begin() + random(0, test.size()), random('a', 'z')); break; case 40: // 21.3.5 modifiers { std::list lst(RandomList(maxString)); test.insert(test.begin() + random(0, test.size()), lst.begin(), lst.end()); } break; case 41: // 21.3.5 modifiers test.erase(random(0, test.size()), random(0, maxString)); break; case 42: // 21.3.5 modifiers if(!test.empty()) test.erase(test.begin() + random(0, test.size())); break; case 43: // 21.3.5 modifiers { const typename String::iterator i = test.begin() + random(0, test.size()); test.erase(i, i + random(0, size_t(test.end() - i))); } break; case 44: // 21.3.5 modifiers { const typename String::size_type pos = random(0, test.size()); if (avoidAliasing) { test.replace(pos, random(0, test.size() - pos), String(test)); } else { test.replace(pos, random(0, test.size() - pos), test); } } break; case 45: // 21.3.5 modifiers { const typename String::size_type pos = random(0, test.size()); test.replace(pos, pos + random(0, test.size() - pos), RandomString(&test, maxString)); } break; case 46: // 21.3.5 modifiers { const size_type pos1 = random(0, test.size()), pos2 = random(0, test.size()); if (avoidAliasing) { test.replace(pos1, pos1 + random(0, test.size() - pos1), String(test), pos2, pos2 + random(0, test.size() - pos2)); } else { test.replace(pos1, pos1 + random(0, test.size() - pos1), test, pos2, pos2 + random(0, test.size() - pos2)); } } break; case 47: // 21.3.5 modifiers { const size_type pos1 = random(0, test.size()); String str = RandomString(&test, maxString); const size_type pos2 = random(0, str.size()); test.replace(pos1, pos1 + random(0, test.size() - pos1), str, pos2, pos2 + random(0, str.size() - pos2)); } break; case 48: // 21.3.5 modifiers { const size_type pos = random(0, test.size()); if (avoidAliasing) { test.replace(pos, random(0, test.size() - pos), String(test).c_str(), test.size()); } else { test.replace(pos, random(0, test.size() - pos), test.c_str(), test.size()); } } break; case 49: // 21.3.5 modifiers { const size_type pos = random(0, test.size()); String str = RandomString(&test, maxString); test.replace(pos, pos + random(0, test.size() - pos), str.c_str(), str.size()); } break; case 50: // 21.3.5 modifiers { const size_type pos = random(0, test.size()); String str = RandomString(&test, maxString); test.replace(pos, pos + random(0, test.size() - pos), str.c_str()); } break; case 51: // 21.3.5 modifiers { const size_type pos = random(0, test.size()); test.replace(pos, random(0, test.size() - pos), random(0, maxString), random('a', 'z')); } break; case 52: // 21.3.5 modifiers { const size_type pos = random(0, test.size()); if (avoidAliasing) { test.replace( test.begin() + pos, test.begin() + pos + random(0, test.size() - pos), String(test)); } else { test.replace( test.begin() + pos, test.begin() + pos + random(0, test.size() - pos), test); } } break; case 53: // 21.3.5 modifiers { const size_type pos = random(0, test.size()); if (avoidAliasing) { test.replace( test.begin() + pos, test.begin() + pos + random(0, test.size() - pos), String(test).c_str(), test.size() - random(0, test.size())); } else { test.replace( test.begin() + pos, test.begin() + pos + random(0, test.size() - pos), test.c_str(), test.size() - random(0, test.size())); } } break; case 54: // 21.3.5 modifiers { const size_type pos = random(0, test.size()), n = random(0, test.size() - pos); typename String::iterator b = test.begin(); const String str = RandomString(&test, maxString); const typename String::value_type* s = str.c_str(); test.replace( b + pos, b + pos + n, s); } break; case 55: // 21.3.5 modifiers { const size_type pos = random(0, test.size()); test.replace( test.begin() + pos, test.begin() + pos + random(0, test.size() - pos), random(0, maxString), random('a', 'z')); } break; case 56: // 21.3.5 modifiers { std::vector vec(random(0, maxString)); test.copy( &vec[0], vec.size(), random(0, test.size())); } break; case 57: // 21.3.5 modifiers RandomString(&test, maxString).swap(test); break; case 58: // 21.3.6 string operations // exercise c_str() and data() assert(test.c_str() == test.data()); // exercise get_allocator() assert(test.get_allocator() == RandomString(&test, maxString).get_allocator()); break; case 59: // 21.3.6 string operations { String str = test.substr( random(0, test.size()), random(0, test.size())); Num2String(test, test.find(str, random(0, test.size()))); } break; case 60: // 21.3.6 string operations { String str = test.substr( random(0, test.size()), random(0, test.size())); Num2String(test, test.find(str.c_str(), random(0, test.size()), random(0, str.size()))); } break; case 61: // 21.3.6 string operations { String str = test.substr( random(0, test.size()), random(0, test.size())); Num2String(test, test.find(str.c_str(), random(0, test.size()))); } break; case 62: // 21.3.6 string operations Num2String(test, test.find( random('a', 'z'), random(0, test.size()))); break; case 63: // 21.3.6 string operations { String str = test.substr( random(0, test.size()), random(0, test.size())); Num2String(test, test.rfind(str, random(0, test.size()))); } break; case 64: // 21.3.6 string operations { String str = test.substr( random(0, test.size()), random(0, test.size())); Num2String(test, test.rfind(str.c_str(), random(0, test.size()), random(0, str.size()))); } break; case 65: // 21.3.6 string operations { String str = test.substr( random(0, test.size()), random(0, test.size())); Num2String(test, test.rfind(str.c_str(), random(0, test.size()))); } break; case 66: // 21.3.6 string operations Num2String(test, test.rfind( random('a', 'z'), random(0, test.size()))); break; case 67: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_first_of(str, random(0, test.size()))); } break; case 68: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_first_of(str.c_str(), random(0, test.size()), random(0, str.size()))); } break; case 69: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_first_of(str.c_str(), random(0, test.size()))); } break; case 70: // 21.3.6 string operations Num2String(test, test.find_first_of( random('a', 'z'), random(0, test.size()))); break; case 71: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_last_of(str, random(0, test.size()))); } break; case 72: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_last_of(str.c_str(), random(0, test.size()), random(0, str.size()))); } break; case 73: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_last_of(str.c_str(), random(0, test.size()))); } break; case 74: // 21.3.6 string operations Num2String(test, test.find_last_of( random('a', 'z'), random(0, test.size()))); break; case 75: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_first_not_of(str, random(0, test.size()))); } break; case 76: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_first_not_of(str.c_str(), random(0, test.size()), random(0, str.size()))); } break; case 77: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_first_not_of(str.c_str(), random(0, test.size()))); } break; case 78: // 21.3.6 string operations Num2String(test, test.find_first_not_of( random('a', 'z'), random(0, test.size()))); break; case 79: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_last_not_of(str, random(0, test.size()))); } break; case 80: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_last_not_of(str.c_str(), random(0, test.size()), random(0, str.size()))); } break; case 81: // 21.3.6 string operations { String str = RandomString(&test, maxString); Num2String(test, test.find_last_not_of(str.c_str(), random(0, test.size()))); } break; case 82: // 21.3.6 string operations Num2String(test, test.find_last_not_of( random('a', 'z'), random(0, test.size()))); break; case 83: // 21.3.6 string operations test = test.substr(random(0, test.size()), random(0, test.size())); break; case 84: { int tristate = test.compare(RandomString(&test, maxString)); if (tristate > 0) tristate = 1; else if (tristate < 0) tristate = 2; Num2String(test, tristate); } break; case 85: { int tristate = test.compare( random(0, test.size()), random(0, test.size()), RandomString(&test, maxString)); if (tristate > 0) tristate = 1; else if (tristate < 0) tristate = 2; Num2String(test, tristate); } break; case 86: { String str = RandomString(&test, maxString); int tristate = test.compare( random(0, test.size()), random(0, test.size()), str, random(0, str.size()), random(0, str.size())); if (tristate > 0) tristate = 1; else if (tristate < 0) tristate = 2; Num2String(test, tristate); } break; case 87: { int tristate = test.compare( RandomString(&test, maxString).c_str()); if (tristate > 0) tristate = 1; else if (tristate < 0) tristate = 2; Num2String(test, tristate); } break; case 88: { String str = RandomString(&test, maxString); int tristate = test.compare( random(0, test.size()), random(0, test.size()), str.c_str(), random(0, str.size())); if (tristate > 0) tristate = 1; else if (tristate < 0) tristate = 2; Num2String(test, tristate); } break; case 89: test = RandomString(&test, maxString) + RandomString(&test, maxString); break; case 90: test = RandomString(&test, maxString).c_str() + RandomString(&test, maxString); break; case 91: test = typename String::value_type(random('a', 'z')) + RandomString(&test, maxString); break; case 92: test = RandomString(&test, maxString) + RandomString(&test, maxString).c_str(); break; case 93: test = RandomString(&test, maxString) + RandomString(&test, maxString).c_str(); break; case 94: test = RandomString(&test, maxString) + typename String::value_type(random('a', 'z')); break; default: assert(((functionSelector + 1) % 96) == 0); break; } } return test; } template void checkResults(const std::string& reference, const T& tested) { if( (tested.size() != reference.size())|| (std::string(tested.data(), tested.size()) != reference) ) { std::cout << "\nTest " << currentTest << " failed: \n"; std::cout << "reference.size() = " << reference.size() << "\n"; std::cout << "tested.size() = " << tested.size() << "\n"; std::cout << "reference data = " << reference << "\n"; std::cout << "tested data = " << tested << "\n"; } //assert(tested.size() == reference.size()); //assert(std::string(tested.data(), tested.size()) == reference); } void Compare() { unsigned int count = 0; srand(10); for (;;) { cout << ++count << '\r'; unsigned long t = rand(); //time(0); srand(t); const std::string reference = Test(std::string(), 1, true); { srand(t); typedef flex_string< char, std::char_traits, std::allocator, SimpleStringStorage > > my_string; const my_string tested = Test(my_string(), 1, false); checkResults(reference, tested); } { srand(t); typedef flex_string< char, std::char_traits, std::allocator, AllocatorStringStorage > > my_string; const my_string tested = Test(my_string(), 1, false); checkResults(reference, tested); } { srand(t); typedef flex_string< char, std::char_traits, mallocator, AllocatorStringStorage > > my_string; const my_string tested = Test(my_string(), 1, false); checkResults(reference, tested); } { srand(t); typedef flex_string< char, std::char_traits, std::allocator, VectorStringStorage > > my_string; const my_string tested = Test(my_string(), 1, false); checkResults(reference, tested); } { srand(t); typedef VectorStringStorage > Storage; typedef flex_string< char, std::char_traits, std::allocator, SmallStringOpt > my_string; static my_string sample; const my_string tested(Test(sample, 1, false)); checkResults(reference, tested); } { srand(t); typedef SimpleStringStorage > Storage; typedef flex_string< char, std::char_traits, std::allocator, CowStringOpt > my_string; static my_string sample; const my_string tested(Test(sample, 1, false)); checkResults(reference, tested); } { srand(t); typedef AllocatorStringStorage > Storage; typedef flex_string< char, std::char_traits, std::allocator, CowStringOpt > my_string; static my_string sample; const my_string tested(Test(sample, 1, false)); checkResults(reference, tested); } /* { // SimpleStringStorage with UTF16 Encoding srand(t); typedef SimpleStringStorage Storage; typedef flex_string< unicode::UTF16Char, std::char_traits, std::allocator, UTF16Encoding > my_string; static my_string sample; const my_string tested(Test(sample, 1, false)); assert(tested.size() == reference.size()); //assert(std::string(tested.data(), tested.size()) == reference); } */ } } /// This function tests out a bug found by Jean-Francois Bastien in the find function. void TestBug2536490( void ) { my_string bug; std::cout << "Index of '6' in \"" << bug.c_str() << "\": " << bug.find('6') << std::endl; bug = "12345"; std::cout << "Index of '6' in \"" << bug.c_str() << "\": " << bug.find('6') << std::endl; bug = "123456"; std::cout << "Index of '6' in \"" << bug.c_str() << "\": " << bug.find('6') << std::endl; bug = "12345"; std::cout << "Index of '6' in \"" << bug.c_str() << "\": " << bug.find('6') << std::endl; bug = "12345"; std::cout << "Index of '123' in \"" << bug.c_str() << "\": " << bug.find("123") << std::endl; bug = "12345"; std::cout << "Index of '12345' in \"" << bug.c_str() << "\": " << bug.find("12345") << std::endl; bug = "12345"; std::cout << "Index of '345' in \"" << bug.c_str() << "\": " << bug.find("345") << std::endl; bug = "123456"; std::cout << "Index of '456' in \"" << bug.c_str() << "\": " << bug.find("456") << std::endl; bug = "12345"; std::cout << "Index of '456' in \"" << bug.c_str() << "\": " << bug.find("456") << std::endl; } /* #include #include #include //#include "flex_string.h" int main() { typedef wchar_t char_type; typedef std::basic_string std_string_t; typedef flex_string< char_type, std::char_traits, std::allocator, SimpleStringStorage > > flex_string_t; flex_string_t s1(L"A flex string"); std_string_t s2(L"A std string"); assert(std::numeric_limits::is_specialized); assert(std::numeric_limits::is_specialized); s1.replace(s1.begin(), s1.begin(), s2.begin(),s2.end()); return 0; } */ int main() { TestBug2536490(); srand(unsigned(time(0))); Compare(); return 0; }