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