string_test.cpp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596
  1. //////////////////////////////////////////////////////////////////////////////
  2. //
  3. // (C) Copyright Ion Gaztanaga 2004-2013. Distributed under the Boost
  4. // Software License, Version 1.0. (See accompanying file
  5. // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
  6. //
  7. // See http://www.boost.org/libs/container for documentation.
  8. //
  9. //////////////////////////////////////////////////////////////////////////////
  10. #include <boost/container/detail/config_begin.hpp>
  11. #include <boost/container/vector.hpp>
  12. #include <boost/container/string.hpp>
  13. #include <string>
  14. #include <vector>
  15. #include <boost/container/detail/algorithm.hpp> //equal()
  16. #include <cstring>
  17. #include <cstdio>
  18. #include <cstddef>
  19. #include <new>
  20. #include "dummy_test_allocator.hpp"
  21. #include "check_equal_containers.hpp"
  22. #include "expand_bwd_test_allocator.hpp"
  23. #include "expand_bwd_test_template.hpp"
  24. #include "propagate_allocator_test.hpp"
  25. #include "default_init_test.hpp"
  26. #include "comparison_test.hpp"
  27. #include "../../intrusive/test/iterator_test.hpp"
  28. #include <boost/utility/string_view.hpp>
  29. #include <boost/core/lightweight_test.hpp>
  30. using namespace boost::container;
  31. struct StringEqual
  32. {
  33. template<class Str1, class Str2>
  34. bool operator ()(const Str1 &string1, const Str2 &string2) const
  35. {
  36. if(string1.size() != string2.size())
  37. return false;
  38. return std::char_traits<typename Str1::value_type>::compare
  39. (string1.c_str(), string2.c_str(), string1.size()) == 0;
  40. }
  41. };
  42. //Function to check if both lists are equal
  43. template<class StrVector1, class StrVector2>
  44. bool CheckEqualStringVector(StrVector1 *strvect1, StrVector2 *strvect2)
  45. {
  46. StringEqual comp;
  47. return boost::container::algo_equal(strvect1->begin(), strvect1->end(),
  48. strvect2->begin(), comp);
  49. }
  50. template<class ForwardIt>
  51. ForwardIt unique(ForwardIt first, ForwardIt const last)
  52. {
  53. if(first == last){
  54. ForwardIt i = first;
  55. //Find first adjacent pair
  56. while(1){
  57. if(++i == last){
  58. return last;
  59. }
  60. else if(*first == *i){
  61. break;
  62. }
  63. ++first;
  64. }
  65. //Now overwrite skipping adjacent elements
  66. while (++i != last) {
  67. if (!(*first == *i)) {
  68. *(++first) = boost::move(*i);
  69. }
  70. }
  71. ++first;
  72. }
  73. return first;
  74. }
  75. template<class CharType>
  76. struct string_literals;
  77. template<>
  78. struct string_literals<char>
  79. {
  80. static const char *String()
  81. { return "String"; }
  82. static const char *Prefix()
  83. { return "Prefix"; }
  84. static const char *Suffix()
  85. { return "Suffix"; }
  86. static const char *LongString()
  87. { return "LongLongLongLongLongLongLongLongLongLongLongLongLongString"; }
  88. static char Char()
  89. { return 'C'; }
  90. static void sprintf_number(char *buf, int number)
  91. {
  92. std::sprintf(buf, "%i", number);
  93. }
  94. };
  95. template<>
  96. struct string_literals<wchar_t>
  97. {
  98. static const wchar_t *String()
  99. { return L"String"; }
  100. static const wchar_t *Prefix()
  101. { return L"Prefix"; }
  102. static const wchar_t *Suffix()
  103. { return L"Suffix"; }
  104. static const wchar_t *LongString()
  105. { return L"LongLongLongLongLongLongLongLongLongLongLongLongLongString"; }
  106. static wchar_t Char()
  107. { return L'C'; }
  108. static void sprintf_number(wchar_t *buffer, unsigned int number)
  109. {
  110. //For compilers without wsprintf, print it backwards
  111. const wchar_t *digits = L"0123456789";
  112. wchar_t *buf = buffer;
  113. while(1){
  114. int rem = number % 10;
  115. number = number / 10;
  116. *buf = digits[rem];
  117. ++buf;
  118. if(!number){
  119. *buf = 0;
  120. break;
  121. }
  122. }
  123. }
  124. };
  125. template<class CharType>
  126. int string_test()
  127. {
  128. typedef std::basic_string<CharType> StdString;
  129. typedef vector<StdString> StdStringVector;
  130. typedef basic_string<CharType> BoostString;
  131. typedef vector<BoostString> BoostStringVector;
  132. const int MaxSize = 100;
  133. {
  134. BoostStringVector *boostStringVect = new BoostStringVector;
  135. StdStringVector *stdStringVect = new StdStringVector;
  136. BoostString auxBoostString;
  137. StdString auxStdString(StdString(auxBoostString.begin(), auxBoostString.end() ));
  138. CharType buffer [20];
  139. //First, push back
  140. for(int i = 0; i < MaxSize; ++i){
  141. auxBoostString = string_literals<CharType>::String();
  142. auxStdString = string_literals<CharType>::String();
  143. string_literals<CharType>::sprintf_number(buffer, i);
  144. auxBoostString += buffer;
  145. auxStdString += buffer;
  146. boostStringVect->push_back(auxBoostString);
  147. stdStringVect->push_back(auxStdString);
  148. }
  149. if(auxBoostString.data() != const_cast<const BoostString&>(auxBoostString).data() &&
  150. auxBoostString.data() != &auxBoostString[0])
  151. return 1;
  152. if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
  153. return 1;
  154. }
  155. //Now push back moving
  156. for(int i = 0; i < MaxSize; ++i){
  157. auxBoostString = string_literals<CharType>::String();
  158. auxStdString = string_literals<CharType>::String();
  159. string_literals<CharType>::sprintf_number(buffer, i);
  160. auxBoostString += buffer;
  161. auxStdString += buffer;
  162. boostStringVect->push_back(boost::move(auxBoostString));
  163. stdStringVect->push_back(auxStdString);
  164. }
  165. if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
  166. return 1;
  167. }
  168. //push front
  169. for(int i = 0; i < MaxSize; ++i){
  170. auxBoostString = string_literals<CharType>::String();
  171. auxStdString = string_literals<CharType>::String();
  172. string_literals<CharType>::sprintf_number(buffer, i);
  173. auxBoostString += buffer;
  174. auxStdString += buffer;
  175. boostStringVect->insert(boostStringVect->begin(), auxBoostString);
  176. stdStringVect->insert(stdStringVect->begin(), auxStdString);
  177. }
  178. if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
  179. return 1;
  180. }
  181. //Now push front moving
  182. for(int i = 0; i < MaxSize; ++i){
  183. auxBoostString = string_literals<CharType>::String();
  184. auxStdString = string_literals<CharType>::String();
  185. string_literals<CharType>::sprintf_number(buffer, i);
  186. auxBoostString += buffer;
  187. auxStdString += buffer;
  188. boostStringVect->insert(boostStringVect->begin(), boost::move(auxBoostString));
  189. stdStringVect->insert(stdStringVect->begin(), auxStdString);
  190. }
  191. if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
  192. return 1;
  193. }
  194. //Now test long and short representation swapping
  195. //Short first
  196. auxBoostString = string_literals<CharType>::String();
  197. auxStdString = string_literals<CharType>::String();
  198. BoostString boost_swapper;
  199. StdString std_swapper;
  200. boost_swapper.swap(auxBoostString);
  201. std_swapper.swap(auxStdString);
  202. if(!StringEqual()(auxBoostString, auxStdString))
  203. return 1;
  204. if(!StringEqual()(boost_swapper, std_swapper))
  205. return 1;
  206. boost_swapper.swap(auxBoostString);
  207. std_swapper.swap(auxStdString);
  208. if(!StringEqual()(auxBoostString, auxStdString))
  209. return 1;
  210. if(!StringEqual()(boost_swapper, std_swapper))
  211. return 1;
  212. //Shrink_to_fit
  213. auxBoostString.shrink_to_fit();
  214. StdString(auxStdString).swap(auxStdString);
  215. if(!StringEqual()(auxBoostString, auxStdString))
  216. return 1;
  217. //Reserve + shrink_to_fit
  218. auxBoostString.reserve(boost_swapper.size()*2+1);
  219. auxStdString.reserve(std_swapper.size()*2+1);
  220. if(!StringEqual()(auxBoostString, auxStdString))
  221. return 1;
  222. auxBoostString.shrink_to_fit();
  223. StdString(auxStdString).swap(auxStdString);
  224. if(!StringEqual()(auxBoostString, auxStdString))
  225. return 1;
  226. //Long string
  227. auxBoostString = string_literals<CharType>::LongString();
  228. auxStdString = string_literals<CharType>::LongString();
  229. boost_swapper = BoostString();
  230. std_swapper = StdString();
  231. boost_swapper.swap(auxBoostString);
  232. std_swapper.swap(auxStdString);
  233. if(!StringEqual()(auxBoostString, auxStdString))
  234. return 1;
  235. if(!StringEqual()(boost_swapper, std_swapper))
  236. return 1;
  237. boost_swapper.swap(auxBoostString);
  238. std_swapper.swap(auxStdString);
  239. //Shrink_to_fit
  240. auxBoostString.shrink_to_fit();
  241. StdString(auxStdString).swap(auxStdString);
  242. if(!StringEqual()(auxBoostString, auxStdString))
  243. return 1;
  244. auxBoostString.clear();
  245. auxStdString.clear();
  246. auxBoostString.shrink_to_fit();
  247. StdString(auxStdString).swap(auxStdString);
  248. if(!StringEqual()(auxBoostString, auxStdString))
  249. return 1;
  250. //No sort
  251. std::sort(boostStringVect->begin(), boostStringVect->end());
  252. std::sort(stdStringVect->begin(), stdStringVect->end());
  253. if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
  254. const CharType *prefix = string_literals<CharType>::Prefix();
  255. const int prefix_size = std::char_traits<CharType>::length(prefix);
  256. const CharType *sufix = string_literals<CharType>::Suffix();
  257. for(int i = 0; i < MaxSize; ++i){
  258. (*boostStringVect)[i].append(sufix);
  259. (*stdStringVect)[i].append(sufix);
  260. (*boostStringVect)[i].insert((*boostStringVect)[i].begin(),
  261. prefix, prefix + prefix_size);
  262. (*stdStringVect)[i].insert((*stdStringVect)[i].begin(),
  263. prefix, prefix + prefix_size);
  264. }
  265. if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
  266. for(int i = 0; i < MaxSize; ++i){
  267. std::reverse((*boostStringVect)[i].begin(), (*boostStringVect)[i].end());
  268. std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end());
  269. }
  270. if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
  271. for(int i = 0; i < MaxSize; ++i){
  272. std::reverse((*boostStringVect)[i].begin(), (*boostStringVect)[i].end());
  273. std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end());
  274. }
  275. if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
  276. for(int i = 0; i < MaxSize; ++i){
  277. std::sort(boostStringVect->begin(), boostStringVect->end());
  278. std::sort(stdStringVect->begin(), stdStringVect->end());
  279. }
  280. if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
  281. for(int i = 0; i < MaxSize; ++i){
  282. (*boostStringVect)[i].replace((*boostStringVect)[i].begin(),
  283. (*boostStringVect)[i].end(),
  284. string_literals<CharType>::String());
  285. (*stdStringVect)[i].replace((*stdStringVect)[i].begin(),
  286. (*stdStringVect)[i].end(),
  287. string_literals<CharType>::String());
  288. }
  289. if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
  290. boostStringVect->erase(::unique(boostStringVect->begin(), boostStringVect->end()),
  291. boostStringVect->end());
  292. stdStringVect->erase(::unique(stdStringVect->begin(), stdStringVect->end()),
  293. stdStringVect->end());
  294. if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
  295. //Check addition
  296. {
  297. BoostString bs2 = string_literals<CharType>::String();
  298. StdString ss2 = string_literals<CharType>::String();
  299. BoostString bs3 = string_literals<CharType>::Suffix();
  300. StdString ss3 = string_literals<CharType>::Suffix();
  301. BoostString bs4 = bs2 + bs3;
  302. StdString ss4 = ss2 + ss3;
  303. if(!StringEqual()(bs4, ss4)){
  304. return 1;
  305. }
  306. bs4 = bs2 + BoostString();
  307. ss4 = ss2 + StdString();
  308. if(!StringEqual()(bs4, ss4)){
  309. return 1;
  310. }
  311. bs4 = BoostString() + bs2;
  312. ss4 = StdString() + ss2;
  313. if(!StringEqual()(bs4, ss4)){
  314. return 1;
  315. }
  316. bs4 = BoostString() + boost::move(bs2);
  317. ss4 = StdString() + boost::move(ss2);
  318. if(!StringEqual()(bs4, ss4)){
  319. return 1;
  320. }
  321. bs2 = string_literals<CharType>::String();
  322. ss2 = string_literals<CharType>::String();
  323. bs4 = boost::move(bs2) + BoostString();
  324. ss4 = boost::move(ss2) + StdString();
  325. if(!StringEqual()(bs4, ss4)){
  326. return 1;
  327. }
  328. bs2 = string_literals<CharType>::String();
  329. ss2 = string_literals<CharType>::String();
  330. bs4 = string_literals<CharType>::Prefix() + boost::move(bs2);
  331. ss4 = string_literals<CharType>::Prefix() + boost::move(ss2);
  332. if(!StringEqual()(bs4, ss4)){
  333. return 1;
  334. }
  335. bs2 = string_literals<CharType>::String();
  336. ss2 = string_literals<CharType>::String();
  337. bs4 = boost::move(bs2) + string_literals<CharType>::Suffix();
  338. ss4 = boost::move(ss2) + string_literals<CharType>::Suffix();
  339. if(!StringEqual()(bs4, ss4)){
  340. return 1;
  341. }
  342. bs2 = string_literals<CharType>::String();
  343. ss2 = string_literals<CharType>::String();
  344. bs4 = string_literals<CharType>::Prefix() + bs2;
  345. ss4 = string_literals<CharType>::Prefix() + ss2;
  346. if(!StringEqual()(bs4, ss4)){
  347. return 1;
  348. }
  349. bs2 = string_literals<CharType>::String();
  350. ss2 = string_literals<CharType>::String();
  351. bs4 = bs2 + string_literals<CharType>::Suffix();
  352. ss4 = ss2 + string_literals<CharType>::Suffix();
  353. if(!StringEqual()(bs4, ss4)){
  354. return 1;
  355. }
  356. bs2 = string_literals<CharType>::String();
  357. ss2 = string_literals<CharType>::String();
  358. bs4 = string_literals<CharType>::Char() + bs2;
  359. ss4 = string_literals<CharType>::Char() + ss2;
  360. if(!StringEqual()(bs4, ss4)){
  361. return 1;
  362. }
  363. bs2 = string_literals<CharType>::String();
  364. ss2 = string_literals<CharType>::String();
  365. bs4 = bs2 + string_literals<CharType>::Char();
  366. ss4 = ss2 + string_literals<CharType>::Char();
  367. if(!StringEqual()(bs4, ss4)){
  368. return 1;
  369. }
  370. //Check front/back/begin/end
  371. if(bs4.front() != *ss4.begin())
  372. return 1;
  373. if(bs4.back() != *(ss4.end()-1))
  374. return 1;
  375. bs4.pop_back();
  376. ss4.erase(ss4.end()-1);
  377. if(!StringEqual()(bs4, ss4)){
  378. return 1;
  379. }
  380. if(*bs4.begin() != *ss4.begin())
  381. return 1;
  382. if(*bs4.cbegin() != *ss4.begin())
  383. return 1;
  384. if(*bs4.rbegin() != *ss4.rbegin())
  385. return 1;
  386. if(*bs4.crbegin() != *ss4.rbegin())
  387. return 1;
  388. if(*(bs4.end()-1) != *(ss4.end()-1))
  389. return 1;
  390. if(*(bs4.cend()-1) != *(ss4.end()-1))
  391. return 1;
  392. if(*(bs4.rend()-1) != *(ss4.rend()-1))
  393. return 1;
  394. if(*(bs4.crend()-1) != *(ss4.rend()-1))
  395. return 1;
  396. }
  397. #ifndef BOOST_CONTAINER_NO_CXX17_CTAD
  398. //Chect Constructor Template Auto Deduction
  399. {
  400. auto gold = StdString(string_literals<CharType>::String());
  401. auto test = basic_string(gold.begin(), gold.end());
  402. if(!StringEqual()(gold, test)) {
  403. return 1;
  404. }
  405. }
  406. #endif
  407. //When done, delete vector
  408. delete boostStringVect;
  409. delete stdStringVect;
  410. }
  411. return 0;
  412. }
  413. bool test_expand_bwd()
  414. {
  415. //Now test all back insertion possibilities
  416. typedef test::expand_bwd_test_allocator<char>
  417. allocator_type;
  418. typedef basic_string<char, std::char_traits<char>, allocator_type>
  419. string_type;
  420. return test::test_all_expand_bwd<string_type>();
  421. }
  422. struct boost_container_string;
  423. namespace boost { namespace container { namespace test {
  424. template<>
  425. struct alloc_propagate_base<boost_container_string>
  426. {
  427. template <class T, class Allocator>
  428. struct apply
  429. {
  430. typedef boost::container::basic_string<T, std::char_traits<T>, Allocator> type;
  431. };
  432. };
  433. }}} //namespace boost::container::test
  434. int main()
  435. {
  436. if(string_test<char>()){
  437. return 1;
  438. }
  439. if(string_test<wchar_t>()){
  440. return 1;
  441. }
  442. ////////////////////////////////////
  443. // Backwards expansion test
  444. ////////////////////////////////////
  445. if(!test_expand_bwd())
  446. return 1;
  447. ////////////////////////////////////
  448. // Allocator propagation testing
  449. ////////////////////////////////////
  450. if(!boost::container::test::test_propagate_allocator<boost_container_string>())
  451. return 1;
  452. ////////////////////////////////////
  453. // Default init test
  454. ////////////////////////////////////
  455. if(!test::default_init_test< basic_string<char, std::char_traits<char>, test::default_init_allocator<char> > >()){
  456. std::cerr << "Default init test failed" << std::endl;
  457. return 1;
  458. }
  459. if(!test::default_init_test< basic_string<wchar_t, std::char_traits<wchar_t>, test::default_init_allocator<wchar_t> > >()){
  460. std::cerr << "Default init test failed" << std::endl;
  461. return 1;
  462. }
  463. ////////////////////////////////////
  464. // Iterator testing
  465. ////////////////////////////////////
  466. {
  467. typedef boost::container::basic_string<char> cont_int;
  468. cont_int a; a.push_back(char(1)); a.push_back(char(2)); a.push_back(char(3));
  469. boost::intrusive::test::test_iterator_random< cont_int >(a);
  470. }
  471. {
  472. typedef boost::container::basic_string<wchar_t> cont_int;
  473. cont_int a; a.push_back(wchar_t(1)); a.push_back(wchar_t(2)); a.push_back(wchar_t(3));
  474. boost::intrusive::test::test_iterator_random< cont_int >(a);
  475. }
  476. ////////////////////////////////////
  477. // Comparison testing
  478. ////////////////////////////////////
  479. {
  480. if(!boost::container::test::test_container_comparisons<string>())
  481. return 1;
  482. if(!boost::container::test::test_container_comparisons<wstring>())
  483. return 1;
  484. }
  485. ////////////////////////////////////
  486. // has_trivial_destructor_after_move testing
  487. ////////////////////////////////////
  488. // default allocator
  489. {
  490. typedef boost::container::basic_string<char> cont;
  491. typedef cont::allocator_type allocator_type;
  492. typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
  493. if (boost::has_trivial_destructor_after_move<cont>::value !=
  494. boost::has_trivial_destructor_after_move<allocator_type>::value &&
  495. boost::has_trivial_destructor_after_move<pointer>::value) {
  496. std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl;
  497. return 1;
  498. }
  499. }
  500. // std::allocator
  501. {
  502. typedef boost::container::basic_string<char, std::char_traits<char>, std::allocator<char> > cont;
  503. typedef cont::allocator_type allocator_type;
  504. typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
  505. if (boost::has_trivial_destructor_after_move<cont>::value !=
  506. boost::has_trivial_destructor_after_move<allocator_type>::value &&
  507. boost::has_trivial_destructor_after_move<pointer>::value) {
  508. std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl;
  509. return 1;
  510. }
  511. }
  512. return boost::report_errors();
  513. }
  514. #include <boost/container/detail/config_end.hpp>