• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
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 
31 using namespace boost::container;
32 
33 struct StringEqual
34 {
35    template<class Str1, class Str2>
operator ()StringEqual36    bool operator ()(const Str1 &string1, const Str2 &string2) const
37    {
38       if(string1.size() != string2.size())
39          return false;
40       return std::char_traits<typename Str1::value_type>::compare
41          (string1.c_str(), string2.c_str(), string1.size()) == 0;
42    }
43 };
44 
45 //Function to check if both lists are equal
46 template<class StrVector1, class StrVector2>
CheckEqualStringVector(StrVector1 * strvect1,StrVector2 * strvect2)47 bool CheckEqualStringVector(StrVector1 *strvect1, StrVector2 *strvect2)
48 {
49    StringEqual comp;
50    return boost::container::algo_equal(strvect1->begin(), strvect1->end(),
51                      strvect2->begin(), comp);
52 }
53 
54 template<class ForwardIt>
unique(ForwardIt first,ForwardIt const last)55 ForwardIt unique(ForwardIt first, ForwardIt const last)
56 {
57    if(first == last){
58       ForwardIt i = first;
59       //Find first adjacent pair
60       while(1){
61          if(++i == last){
62             return last;
63          }
64          else if(*first == *i){
65             break;
66          }
67          ++first;
68       }
69       //Now overwrite skipping adjacent elements
70       while (++i != last) {
71          if (!(*first == *i)) {
72             *(++first) = boost::move(*i);
73          }
74       }
75       ++first;
76    }
77    return first;
78 }
79 
80 template<class CharType>
81 struct string_literals;
82 
83 template<>
84 struct string_literals<char>
85 {
Stringstring_literals86    static const char *String()
87       {  return "String";  }
Prefixstring_literals88    static const char *Prefix()
89       {  return "Prefix";  }
Suffixstring_literals90    static const char *Suffix()
91       {  return "Suffix";  }
LongStringstring_literals92    static const char *LongString()
93       {  return "LongLongLongLongLongLongLongLongLongLongLongLongLongString";  }
Charstring_literals94    static char Char()
95       {  return 'C';  }
sprintf_numberstring_literals96    static void sprintf_number(char *buf, int number)
97    {
98       std::sprintf(buf, "%i", number);
99    }
100 };
101 
102 template<>
103 struct string_literals<wchar_t>
104 {
Stringstring_literals105    static const wchar_t *String()
106       {  return L"String";  }
Prefixstring_literals107    static const wchar_t *Prefix()
108       {  return L"Prefix";  }
Suffixstring_literals109    static const wchar_t *Suffix()
110       {  return L"Suffix";  }
LongStringstring_literals111    static const wchar_t *LongString()
112       {  return L"LongLongLongLongLongLongLongLongLongLongLongLongLongString";  }
Charstring_literals113    static wchar_t Char()
114       {  return L'C';  }
sprintf_numberstring_literals115    static void sprintf_number(wchar_t *buffer, unsigned int number)
116    {
117       //For compilers without wsprintf, print it backwards
118       const wchar_t *digits = L"0123456789";
119       wchar_t *buf = buffer;
120 
121       while(1){
122          int rem = number % 10;
123          number  = number / 10;
124 
125          *buf = digits[rem];
126          ++buf;
127          if(!number){
128             *buf = 0;
129             break;
130          }
131       }
132 
133    }
134 };
135 
136 template<class CharType>
string_test()137 int string_test()
138 {
139    typedef std::basic_string<CharType> StdString;
140    typedef vector<StdString>  StdStringVector;
141    typedef basic_string<CharType> BoostString;
142    typedef vector<BoostString> BoostStringVector;
143 
144    const int MaxSize = 100;
145 
146    {
147       BoostStringVector *boostStringVect = new BoostStringVector;
148       StdStringVector *stdStringVect = new StdStringVector;
149       BoostString auxBoostString;
150       StdString auxStdString(StdString(auxBoostString.begin(), auxBoostString.end() ));
151 
152       CharType buffer [20];
153 
154       //First, push back
155       for(int i = 0; i < MaxSize; ++i){
156          auxBoostString = string_literals<CharType>::String();
157          auxStdString = string_literals<CharType>::String();
158          string_literals<CharType>::sprintf_number(buffer, i);
159          auxBoostString += buffer;
160          auxStdString += buffer;
161          boostStringVect->push_back(auxBoostString);
162          stdStringVect->push_back(auxStdString);
163       }
164 
165       if(auxBoostString.data() != const_cast<const BoostString&>(auxBoostString).data() &&
166          auxBoostString.data() != &auxBoostString[0])
167          return 1;
168 
169       if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
170          return 1;
171       }
172 
173       //Now push back moving
174       for(int i = 0; i < MaxSize; ++i){
175          auxBoostString = string_literals<CharType>::String();
176          auxStdString = string_literals<CharType>::String();
177          string_literals<CharType>::sprintf_number(buffer, i);
178          auxBoostString += buffer;
179          auxStdString += buffer;
180          boostStringVect->push_back(boost::move(auxBoostString));
181          stdStringVect->push_back(auxStdString);
182       }
183 
184       if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
185          return 1;
186       }
187 
188       //push front
189       for(int i = 0; i < MaxSize; ++i){
190          auxBoostString = string_literals<CharType>::String();
191          auxStdString = string_literals<CharType>::String();
192          string_literals<CharType>::sprintf_number(buffer, i);
193          auxBoostString += buffer;
194          auxStdString += buffer;
195          boostStringVect->insert(boostStringVect->begin(), auxBoostString);
196          stdStringVect->insert(stdStringVect->begin(), auxStdString);
197       }
198 
199       if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
200          return 1;
201       }
202 
203       //Now push front moving
204       for(int i = 0; i < MaxSize; ++i){
205          auxBoostString = string_literals<CharType>::String();
206          auxStdString = string_literals<CharType>::String();
207          string_literals<CharType>::sprintf_number(buffer, i);
208          auxBoostString += buffer;
209          auxStdString += buffer;
210          boostStringVect->insert(boostStringVect->begin(), boost::move(auxBoostString));
211          stdStringVect->insert(stdStringVect->begin(), auxStdString);
212       }
213 
214       if(!CheckEqualStringVector(boostStringVect, stdStringVect)){
215          return 1;
216       }
217 
218       //Now test long and short representation swapping
219 
220       //Short first
221       auxBoostString = string_literals<CharType>::String();
222       auxStdString = string_literals<CharType>::String();
223       BoostString boost_swapper;
224       StdString std_swapper;
225       boost_swapper.swap(auxBoostString);
226       std_swapper.swap(auxStdString);
227       if(!StringEqual()(auxBoostString, auxStdString))
228          return 1;
229       if(!StringEqual()(boost_swapper, std_swapper))
230          return 1;
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 
238       //Shrink_to_fit
239       auxBoostString.shrink_to_fit();
240       StdString(auxStdString).swap(auxStdString);
241       if(!StringEqual()(auxBoostString, auxStdString))
242          return 1;
243 
244       //Reserve + shrink_to_fit
245       auxBoostString.reserve(boost_swapper.size()*2+1);
246       auxStdString.reserve(std_swapper.size()*2+1);
247       if(!StringEqual()(auxBoostString, auxStdString))
248          return 1;
249 
250       auxBoostString.shrink_to_fit();
251       StdString(auxStdString).swap(auxStdString);
252       if(!StringEqual()(auxBoostString, auxStdString))
253          return 1;
254 
255       //Long string
256       auxBoostString = string_literals<CharType>::LongString();
257       auxStdString   = string_literals<CharType>::LongString();
258       boost_swapper = BoostString();
259       std_swapper = StdString();
260       boost_swapper.swap(auxBoostString);
261       std_swapper.swap(auxStdString);
262       if(!StringEqual()(auxBoostString, auxStdString))
263          return 1;
264       if(!StringEqual()(boost_swapper, std_swapper))
265          return 1;
266       boost_swapper.swap(auxBoostString);
267       std_swapper.swap(auxStdString);
268 
269       //Shrink_to_fit
270       auxBoostString.shrink_to_fit();
271       StdString(auxStdString).swap(auxStdString);
272       if(!StringEqual()(auxBoostString, auxStdString))
273          return 1;
274 
275       auxBoostString.clear();
276       auxStdString.clear();
277       auxBoostString.shrink_to_fit();
278       StdString(auxStdString).swap(auxStdString);
279       if(!StringEqual()(auxBoostString, auxStdString))
280          return 1;
281 
282       //No sort
283       std::sort(boostStringVect->begin(), boostStringVect->end());
284       std::sort(stdStringVect->begin(), stdStringVect->end());
285       if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
286 
287       const CharType *prefix    = string_literals<CharType>::Prefix();
288       const int  prefix_size    = std::char_traits<CharType>::length(prefix);
289       const CharType *sufix      = string_literals<CharType>::Suffix();
290 
291       for(int i = 0; i < MaxSize; ++i){
292          (*boostStringVect)[i].append(sufix);
293          (*stdStringVect)[i].append(sufix);
294          (*boostStringVect)[i].insert((*boostStringVect)[i].begin(),
295                                     prefix, prefix + prefix_size);
296          (*stdStringVect)[i].insert((*stdStringVect)[i].begin(),
297                                     prefix, prefix + prefix_size);
298       }
299 
300       if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
301 
302       for(int i = 0; i < MaxSize; ++i){
303          std::reverse((*boostStringVect)[i].begin(), (*boostStringVect)[i].end());
304          std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end());
305       }
306 
307       if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
308 
309       for(int i = 0; i < MaxSize; ++i){
310          std::reverse((*boostStringVect)[i].begin(), (*boostStringVect)[i].end());
311          std::reverse((*stdStringVect)[i].begin(), (*stdStringVect)[i].end());
312       }
313 
314       if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
315 
316       for(int i = 0; i < MaxSize; ++i){
317          std::sort(boostStringVect->begin(), boostStringVect->end());
318          std::sort(stdStringVect->begin(), stdStringVect->end());
319       }
320 
321       if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
322 
323       for(int i = 0; i < MaxSize; ++i){
324          (*boostStringVect)[i].replace((*boostStringVect)[i].begin(),
325                                     (*boostStringVect)[i].end(),
326                                     string_literals<CharType>::String());
327          (*stdStringVect)[i].replace((*stdStringVect)[i].begin(),
328                                     (*stdStringVect)[i].end(),
329                                     string_literals<CharType>::String());
330       }
331 
332       if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
333 
334       boostStringVect->erase(::unique(boostStringVect->begin(), boostStringVect->end()),
335                            boostStringVect->end());
336       stdStringVect->erase(::unique(stdStringVect->begin(), stdStringVect->end()),
337                            stdStringVect->end());
338       if(!CheckEqualStringVector(boostStringVect, stdStringVect)) return 1;
339 
340       //Check addition
341       {
342          BoostString bs2 = string_literals<CharType>::String();
343          StdString   ss2 = string_literals<CharType>::String();
344          BoostString bs3 = string_literals<CharType>::Suffix();
345          StdString   ss3 = string_literals<CharType>::Suffix();
346          BoostString bs4 = bs2 + bs3;
347          StdString   ss4 = ss2 + ss3;
348          if(!StringEqual()(bs4, ss4)){
349             return 1;
350          }
351 
352          bs4 = bs2 + BoostString();
353          ss4 = ss2 + StdString();
354          if(!StringEqual()(bs4, ss4)){
355             return 1;
356          }
357 
358          bs4 = BoostString() + bs2;
359          ss4 = StdString() + ss2;
360          if(!StringEqual()(bs4, ss4)){
361             return 1;
362          }
363 
364          bs4 = BoostString() + boost::move(bs2);
365          ss4 = StdString() + boost::move(ss2);
366          if(!StringEqual()(bs4, ss4)){
367             return 1;
368          }
369 
370          bs2 = string_literals<CharType>::String();
371          ss2 = string_literals<CharType>::String();
372          bs4 = boost::move(bs2) + BoostString();
373          ss4 = boost::move(ss2) + StdString();
374          if(!StringEqual()(bs4, ss4)){
375             return 1;
376          }
377 
378          bs2 = string_literals<CharType>::String();
379          ss2 = string_literals<CharType>::String();
380          bs4 = string_literals<CharType>::Prefix() + boost::move(bs2);
381          ss4 = string_literals<CharType>::Prefix() + boost::move(ss2);
382          if(!StringEqual()(bs4, ss4)){
383             return 1;
384          }
385 
386          bs2 = string_literals<CharType>::String();
387          ss2 = string_literals<CharType>::String();
388          bs4 = boost::move(bs2) + string_literals<CharType>::Suffix();
389          ss4 = boost::move(ss2) + string_literals<CharType>::Suffix();
390          if(!StringEqual()(bs4, ss4)){
391             return 1;
392          }
393 
394          bs2 = string_literals<CharType>::String();
395          ss2 = string_literals<CharType>::String();
396          bs4 = string_literals<CharType>::Prefix() + bs2;
397          ss4 = string_literals<CharType>::Prefix() + ss2;
398          if(!StringEqual()(bs4, ss4)){
399             return 1;
400          }
401 
402          bs2 = string_literals<CharType>::String();
403          ss2 = string_literals<CharType>::String();
404          bs4 = bs2 + string_literals<CharType>::Suffix();
405          ss4 = ss2 + string_literals<CharType>::Suffix();
406          if(!StringEqual()(bs4, ss4)){
407             return 1;
408          }
409 
410          bs2 = string_literals<CharType>::String();
411          ss2 = string_literals<CharType>::String();
412          bs4 = string_literals<CharType>::Char() + bs2;
413          ss4 = string_literals<CharType>::Char() + ss2;
414          if(!StringEqual()(bs4, ss4)){
415             return 1;
416          }
417 
418          bs2 = string_literals<CharType>::String();
419          ss2 = string_literals<CharType>::String();
420          bs4 = bs2 + string_literals<CharType>::Char();
421          ss4 = ss2 + string_literals<CharType>::Char();
422          if(!StringEqual()(bs4, ss4)){
423             return 1;
424          }
425 
426          //Check front/back/begin/end
427 
428          if(bs4.front() != *ss4.begin())
429             return 1;
430 
431          if(bs4.back() != *(ss4.end()-1))
432             return 1;
433 
434          bs4.pop_back();
435          ss4.erase(ss4.end()-1);
436          if(!StringEqual()(bs4, ss4)){
437             return 1;
438          }
439 
440          if(*bs4.begin() != *ss4.begin())
441             return 1;
442          if(*bs4.cbegin() != *ss4.begin())
443             return 1;
444          if(*bs4.rbegin() != *ss4.rbegin())
445             return 1;
446          if(*bs4.crbegin() != *ss4.rbegin())
447             return 1;
448          if(*(bs4.end()-1) != *(ss4.end()-1))
449             return 1;
450          if(*(bs4.cend()-1) != *(ss4.end()-1))
451             return 1;
452          if(*(bs4.rend()-1) != *(ss4.rend()-1))
453             return 1;
454          if(*(bs4.crend()-1) != *(ss4.rend()-1))
455             return 1;
456       }
457 
458 #ifndef BOOST_CONTAINER_NO_CXX17_CTAD
459       //Chect Constructor Template Auto Deduction
460       {
461          auto gold = StdString(string_literals<CharType>::String());
462          auto test = basic_string(gold.begin(), gold.end());
463          if(!StringEqual()(gold, test)) {
464             return 1;
465          }
466       }
467 #endif
468 
469 
470       //When done, delete vector
471       delete boostStringVect;
472       delete stdStringVect;
473    }
474    return 0;
475 }
476 
test_expand_bwd()477 bool test_expand_bwd()
478 {
479    //Now test all back insertion possibilities
480    typedef test::expand_bwd_test_allocator<char>
481       allocator_type;
482    typedef basic_string<char, std::char_traits<char>, allocator_type>
483       string_type;
484    return  test::test_all_expand_bwd<string_type>();
485 }
486 
487 struct boost_container_string;
488 
489 namespace boost { namespace container {   namespace test {
490 
491 template<>
492 struct alloc_propagate_base<boost_container_string>
493 {
494    template <class T, class Allocator>
495    struct apply
496    {
497       typedef boost::container::basic_string<T, std::char_traits<T>, Allocator> type;
498    };
499 };
500 
501 
502 }}}   //namespace boost::container::test
503 
504 
main()505 int main()
506 {
507    if(string_test<char>()){
508       return 1;
509    }
510 
511    if(string_test<wchar_t>()){
512       return 1;
513    }
514 
515    ////////////////////////////////////
516    //    Backwards expansion test
517    ////////////////////////////////////
518    if(!test_expand_bwd())
519       return 1;
520 
521    ////////////////////////////////////
522    //    Allocator propagation testing
523    ////////////////////////////////////
524    if(!boost::container::test::test_propagate_allocator<boost_container_string>())
525       return 1;
526 
527    ////////////////////////////////////
528    //    Default init test
529    ////////////////////////////////////
530    if(!test::default_init_test< basic_string<char, std::char_traits<char>, test::default_init_allocator<char> > >()){
531       std::cerr << "Default init test failed" << std::endl;
532       return 1;
533    }
534 
535    if(!test::default_init_test< basic_string<wchar_t, std::char_traits<wchar_t>, test::default_init_allocator<wchar_t> > >()){
536       std::cerr << "Default init test failed" << std::endl;
537       return 1;
538    }
539 
540    ////////////////////////////////////
541    //    Iterator testing
542    ////////////////////////////////////
543    {
544       typedef boost::container::basic_string<char> cont_int;
545       cont_int a; a.push_back(char(1)); a.push_back(char(2)); a.push_back(char(3));
546       boost::intrusive::test::test_iterator_random< cont_int >(a);
547    }
548    {
549       typedef boost::container::basic_string<wchar_t> cont_int;
550       cont_int a; a.push_back(wchar_t(1)); a.push_back(wchar_t(2)); a.push_back(wchar_t(3));
551       boost::intrusive::test::test_iterator_random< cont_int >(a);
552    }
553 
554    ////////////////////////////////////
555    //    Comparison testing
556    ////////////////////////////////////
557    {
558       if(!boost::container::test::test_container_comparisons<string>())
559          return 1;
560       if(!boost::container::test::test_container_comparisons<wstring>())
561          return 1;
562    }
563 
564    ////////////////////////////////////
565    //    has_trivial_destructor_after_move testing
566    ////////////////////////////////////
567    // default allocator
568    {
569       typedef boost::container::basic_string<char> cont;
570       typedef cont::allocator_type allocator_type;
571       typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
572       if (boost::has_trivial_destructor_after_move<cont>::value !=
573           boost::has_trivial_destructor_after_move<allocator_type>::value &&
574           boost::has_trivial_destructor_after_move<pointer>::value) {
575          std::cerr << "has_trivial_destructor_after_move(default allocator) test failed" << std::endl;
576          return 1;
577       }
578    }
579    // std::allocator
580    {
581       typedef boost::container::basic_string<char, std::char_traits<char>, std::allocator<char> > cont;
582       typedef cont::allocator_type allocator_type;
583       typedef boost::container::allocator_traits<allocator_type>::pointer pointer;
584       if (boost::has_trivial_destructor_after_move<cont>::value !=
585           boost::has_trivial_destructor_after_move<allocator_type>::value &&
586           boost::has_trivial_destructor_after_move<pointer>::value) {
587          std::cerr << "has_trivial_destructor_after_move(std::allocator) test failed" << std::endl;
588          return 1;
589       }
590    }
591 
592    return boost::report_errors();
593 }
594