Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
23.containers.cpp
Go to the documentation of this file.
1
27// expand _TEST_EXPORT macros
28#define _RWSTD_TEST_SRC
29
30#include <memory> // for allocator
31
32#include <rw_containers.h>
33#include <rw_lists.h>
34#include <rw_cmdopt.h> // for rw_enabled()
35#include <rw_driver.h> // for rw_note()
36#include <rw_allocator.h> // for UserAlloc
37#include <rw_printf.h> // for rw_asnprintf()
38
39#include <ctype.h> // for isdigit()
40#include <stdarg.h> // for va_arg, ...
41#include <stddef.h> // for size_t
42#include <stdlib.h> // for free()
43#include <string.h> // for strcpy()
44
45
47static const char
48_rw_this_file[] = __FILE__;
49
50
51static const char* const
52_rw_elem_names[] = {
53 "UserPOD", "UserClass"
54};
55
56
57static const char* const
58_rw_alloc_names[] = {
59 "allocator", "UserAlloc"
60};
61
62
63static const char* const
64_rw_iter_names[] = {
65 "",
66 "InputIterator", "ForwardIterator", "BidirectionalIterator",
67 "RandomAccessIterator",
68 "pointer", "const_pointer",
69 "iterator", "const_iterator",
70 "reverse_iterator", "const_reverse_iterator"
71};
72
73
74static const char* const
75_rw_cont_names[] = {
76 "list", "vector", "deque", "queue", "stack"
77};
78
79
80// order of elements depends on the values of ContainerIds::FuncId
81static const char* const
82_rw_func_names[] = {
83 0 /* special handling for the ctor */, "operator=", "assign",
84 "get_allocator", "begin", "end", "rbegin", "rend", "empty",
85 "size", "max_size", "resize", "insert", "erase", "swap",
86 "clear", "operator==", "operator<", "operator!=", "operator>",
87 "operator>=", "operator<=", "push_back", "front", "back",
88 "pop_back", "push_front", "pop_front", "splice", "remove",
89 "remove_if", "unique", "merge", "sort", "reverse", "operator[]",
90 "at", "capacity", "reserve", "flip"
91};
92
93
95const size_t MAX_OVERLOADS = 32;
96
97// disabled (-1) or explicitly enabled (+1) for each overload
98// of the cont function being tested
99static int
100_rw_opt_func [MAX_OVERLOADS];
101
102// array of tests each exercising a single cont function
103static const ContainerTest*
104_rw_cont_tests;
105
106// size of the array above
107static size_t
108_rw_cont_test_count;
109
110static int
111_rw_opt_elem_types [sizeof _rw_elem_names / sizeof *_rw_elem_names];
112
113static int
114_rw_opt_alloc_types [sizeof _rw_alloc_names / sizeof *_rw_alloc_names];
115
116static int
117_rw_opt_iter_types [sizeof _rw_iter_names / sizeof *_rw_iter_names];
118
119static int
120_rw_opt_no_exceptions;
121
122static int
123_rw_opt_no_exception_safety;
124
125static int
126_rw_opt_self_ref;
127
128
130static size_t
131_rw_get_func_inx (size_t fid)
132{
133 size_t inx = _RWSTD_SIZE_MAX;
134
135 for (size_t i = 0; _rw_cont_test_count; ++i) {
136 if (fid == _rw_cont_tests [i].which) {
137 inx = i;
138 break;
139 }
140 }
141
142 RW_ASSERT (inx < _RWSTD_SIZE_MAX);
143
144 return inx;
145}
146
147
149static const char*
150_rw_class_name (const ContainerFunc & func)
151{
152 return _rw_cont_names [func.cont_id_];
153}
154
155
157// appends the signature of the function specified by which
158// to the provided buffer; when the second argument is null,
159// appends the mnemonic representing the signature, including
160// the name of the function, as specified by the third argument
161static void
162_rw_sigcat (char **pbuf, size_t *pbufsize,
163 const ContainerFunc *func,
164 size_t which = 0)
165{
166 // for convenience
167 typedef ContainerIds Ids;
168
169 if (func)
170 which = func->which_;
171
172 // determine whether the function is a member function
173 const bool is_member = 0 != (Ids::bit_member & which);
174
175 // get the bitmap describing the function's argument types
176 int argmap = int ((which & ~Ids::bit_member) >> Ids::fid_bits);
177
178 // determine whether the function is a const member function
179 bool is_const_member =
180 is_member && Ids::arg_ccont == (argmap & Ids::arg_mask);
181
182 // remove the *this argument if the function is a member
183 if (is_member)
184 argmap >>= Ids::arg_bits;
185
186 const char* funcname = 0;
187
188 if (0 == func) {
189 const Ids::FuncId fid = Ids::FuncId (which & ContainerIds::fid_mask);
190
191 switch (fid) {
192 // translate names with funky characters to mnemonics
193 case Ids::fid_ctor: funcname = "ctor"; break;
194 case Ids::fid_op_index: funcname = "op_index"; break;
195 case Ids::fid_op_set: funcname = "op_assign"; break;
196 case Ids::fid_op_equal: funcname = "op_equal"; break;
197 case Ids::fid_op_less: funcname = "op_less"; break;
198 case Ids::fid_op_not_equal: funcname = "op_not_equal"; break;
199 case Ids::fid_op_greater: funcname = "op_greater"; break;
200 case Ids::fid_op_greater_equal: funcname = "op_greater_equal"; break;
201 case Ids::fid_op_less_equal: funcname = "op_less_equal"; break;
202
203 case Ids::fid_get_allocator:
204 case Ids::fid_empty:
205 case Ids::fid_size:
206 case Ids::fid_max_size:
207 // prevent appending the "_const" bit to the mnemonics
208 // of member functions not overloaded on const
209 is_const_member = false;
210
211 // fall through
212
213 default: {
214 // determine the cont function name (for brief output)
215 const size_t nfuncs =
216 sizeof _rw_func_names / sizeof *_rw_func_names;
217
218 RW_ASSERT (size_t (fid) < nfuncs);
219
220 funcname = _rw_func_names [fid];
221 RW_ASSERT (0 != funcname);
222 break;
223 }
224 }
225 }
226
227 // iterator name for member templates, empty cont for other functions
228 const char* const iname = func ? _rw_iter_names [func->iter_id_] : "";
229
230 rw_asnprintf (pbuf, pbufsize,
231 "%{+}%{?}%s%{?}_const%{;}%{:}%{?}<%s>%{;}(%{;}",
232 0 == func, funcname, is_const_member, 0 != *iname, iname);
233
234 char iname_buf [80];
235 *iname_buf = '\0';
236
237 // iterate through the map of argument types one field at a time
238 // determining and formatting the type of each argument until
239 // void is reached
240 for (size_t argno = 0; argmap; ++argno, argmap >>= Ids::arg_bits) {
241
242 const char* pfx = "";
243 const char* sfx = "";
244
245 const int argtype = argmap & Ids::arg_mask;
246
247 const char* tname = 0;
248
249 if (func) {
250 switch (argtype) {
251 case Ids::arg_size: tname = "size_type"; break;
252 case Ids::arg_val: tname = "value_type"; break;
253 case Ids::arg_ref: tname = "reference"; break;
254 case Ids::arg_cref: tname = "const_reference"; break;
255 case Ids::arg_iter: tname = "iterator"; break;
256 case Ids::arg_citer: tname = "const_iterator"; break;
257 case Ids::arg_range:
258 if ('\0' == *iname_buf) {
259 strcpy (iname_buf, iname);
260 strcat (iname_buf, ", ");
261 strcat (iname_buf, iname);
262 }
263 tname = iname_buf;
264 break;
265
266 case Ids::arg_ccont:
267 pfx = "const ";
268 // fall through
269 case Ids::arg_cont:
270 tname = _rw_class_name (*func);
271 sfx = "&";
272 break;
273
274 case Ids::arg_alloc: tname = "const allocator_type&"; break;
275 case Ids::arg_pred: tname = "Predicate"; break;
276 case Ids::arg_bpred: tname = "BinaryPredicate"; break;
277 case Ids::arg_comp: tname = "Compare"; break;
278 }
279 }
280 else {
281 switch (argtype) {
282 case Ids::arg_size: tname = "size"; break;
283 case Ids::arg_val: tname = "val"; break;
284 case Ids::arg_ref: tname = "ref"; break;
285 case Ids::arg_cref: tname = "cref"; break;
286 case Ids::arg_iter: tname = "iter"; break;
287 case Ids::arg_citer: tname = "citer"; break;
288 case Ids::arg_range: tname = "range"; break;
289 case Ids::arg_cont: tname = "cont"; break;
290 case Ids::arg_ccont: tname = "ccont"; break;
291 case Ids::arg_alloc: tname = "alloc"; break;
292 case Ids::arg_pred: tname = "pred"; break;
293 case Ids::arg_bpred: tname = "bpred"; break;
294 case Ids::arg_comp: tname = "comp"; break;
295 }
296 }
297
298 RW_ASSERT (0 != tname);
299
300 if ( 0 == func || is_member
301 || (Ids::arg_cont != argtype && Ids::arg_ccont != argtype)) {
302 // append the name or mnemonic of the argument type
303 rw_asnprintf (pbuf, pbufsize,
304 "%{+}%{?}_%{:}%{?}, %{;}%{;}%s%s%s",
305 0 == func, 0 < argno, pfx, tname, sfx);
306 }
307 else {
308 // in non-member functions use ${CLASS} to format
309 // the cont argument in order to expand
310 // its template argument cont
311 rw_asnprintf (pbuf, pbufsize,
312 "%{+}%{?}, %{;}%{?}const %{;}%{$CLASS}&",
313 0 < argno, Ids::arg_ccont == argtype);
314
315 }
316 }
317
318 if (func)
319 rw_asnprintf (pbuf, pbufsize, "%{+})%{?} const%{;}", is_const_member);
320}
321
322
324// returns the zero-based index of the argument type specified
325// by arg in the function signature given by which
326static int
327_rw_argno (size_t which, int arg)
328{
329 // get the bitmap describing the function's argument types
330 int argmap = int ((which & ~ContainerIds::bit_member)
332
333 int argno = 0;
334
335 // iterate over argument types looking for the first one
336 // that equals arg
337 for (; argmap; argmap >>= ContainerIds::arg_bits, ++argno) {
338 if ((argmap & ContainerIds::arg_mask) == arg) {
339 return argno;
340 }
341 }
342
343 // return -1 when the function doesn't take an argument
344 // of the specified type
345 return -1;
346}
347
348
350static void
351_rw_list_sigcat (char** pbuf, size_t * pbufsize, ListIds::OverloadId which,
352 bool self, const char* str, size_t str_len,
353 const char* arg, size_t arg_len,
354 const ContainerTestCase &tcase)
355{
356 // compute the end offsets for convenience
357 const size_t range1_end = tcase.off + tcase.size;
358 const size_t range2_end = tcase.off2 + tcase.size2;
359
360 // determine whether the function takes an allocator_type argument
361 const bool use_alloc = 0 < _rw_argno (which, ContainerIds::arg_alloc);
362
363 // format and append cont function arguments abbreviating complex
364 // expressions as much as possible to make them easy to understand
365 switch (which) {
366 case ListIds::ctor_ccont:
367 case ListIds::op_set_ccont:
368 case ListIds::swap_cont:
369 case ListIds::merge_cont:
370 // format self-referential cont argument as *this
371 rw_asnprintf (pbuf, pbufsize,
372 "%{+} (%{?}*this%{:}%{$Container}(%{#*s})%{;}"
373 "%{?}, const allocator_type&%{;})",
374 self, int (arg_len), arg, use_alloc);
375 break;
376
377 case ListIds::assign_size_cref:
378 case ListIds::ctor_size_cref:
379 case ListIds::ctor_size_cref_alloc:
380 rw_asnprintf (pbuf, pbufsize,
381 "%{+} (%zu, %{#c}%{?}, const allocator_type&%{;})",
382 tcase.size, tcase.val, use_alloc);
383 break;
384
385 case ListIds::assign_range:
386 case ListIds::ctor_range:
387 case ListIds::ctor_range_alloc:
388 rw_asnprintf (pbuf, pbufsize, "%{+}<%{$Iterator:-Iterator}>("
389 "%{?}begin()%{:}%{$Iterator:-Iterator}(%{#*s})%{;}"
390 "%{?} + %zu%{;}, "
391 "%{?}begin()%{:}%{$Iterator:-Iterator}(...)%{;}"
392 "%{?} + %zu%{;}"
393 "%{?}, const allocator_type&%{;})",
394 self, int (arg_len), arg,
395 0 != tcase.off2, tcase.off2,
396 self, 0 != range2_end, range2_end, use_alloc);
397 break;
398
399 case ListIds::insert_iter_cref:
400 rw_asnprintf (pbuf, pbufsize,
401 "%{+} (begin()%{?} + %zu%{;}, %{#c})",
402 0 != tcase.off, tcase.off, tcase.val);
403 break;
404
405 case ListIds::insert_iter_size_cref:
406 rw_asnprintf (pbuf, pbufsize,
407 "%{+} (begin()%{?} + %zu%{;}, %zu, %{#c})",
408 0 != tcase.off, tcase.off, tcase.size, tcase.val);
409 break;
410
411 case ListIds::insert_iter_range:
412 rw_asnprintf (pbuf, pbufsize, "%{+}<%{$Iterator:-Iterator}>"
413 "(begin()%{?} + %zu%{;}, "
414 "%{?}begin()%{:}%{$Iterator:-Iterator}(%{#*s})%{;}"
415 "%{?} + %zu%{;}, "
416 "%{?}begin()%{:}%{$Iterator:-Iterator}(...)%{;}"
417 "%{?} + %zu%{;})",
418 0 != tcase.off, tcase.off,
419 self, int (arg_len), arg,
420 0 != tcase.off2, tcase.off2,
421 self, 0 != range2_end, range2_end);
422 break;
423
424 case ListIds::push_front_cref:
425 case ListIds::push_back_cref:
426 case ListIds::remove_cref:
427 rw_asnprintf (pbuf, pbufsize,
428 "%{+} (%{#c})", tcase.val);
429 break;
430
431 case ListIds::ctor_void:
432 case ListIds::get_allocator_void:
433 case ListIds::begin_void:
434 case ListIds::end_void:
435 case ListIds::rbegin_void:
436 case ListIds::rend_void:
437 case ListIds::empty_void:
438 case ListIds::size_void:
439 case ListIds::max_size_void:
440 case ListIds::front_void:
441 case ListIds::back_void:
442 case ListIds::pop_front_void:
443 case ListIds::pop_back_void:
444 case ListIds::clear_void:
445 case ListIds::sort_void:
446 case ListIds::reverse_void:
447 rw_asnprintf (pbuf, pbufsize,
448 "%{+} ()");
449 break;
450
451 case ListIds::begin_const_void:
452 case ListIds::end_const_void:
453 case ListIds::rbegin_const_void:
454 case ListIds::rend_const_void:
455 case ListIds::front_const_void:
456 case ListIds::back_const_void:
457 rw_asnprintf (pbuf, pbufsize,
458 "%{+} () const");
459 break;
460
461 case ListIds::ctor_alloc:
462 rw_asnprintf (pbuf, pbufsize,
463 "%{+} (const allocator_type&)");
464 break;
465
466 case ListIds::erase_iter:
467 rw_asnprintf (pbuf, pbufsize,
468 "%{+} (begin()%{?} + %zu%{;})",
469 0 != tcase.off, tcase.off);
470 break;
471
472 case ListIds::erase_iter_iter:
473 rw_asnprintf (pbuf, pbufsize,
474 "%{+} (begin()%{?} + %zu%{;}, begin()%{?} + %zu%{;})",
475 0 != tcase.off, tcase.off,
476 0 != range1_end, range1_end);
477 break;
478
479 case ListIds::op_equal_ccont_ccont:
480 case ListIds::op_less_ccont_ccont:
481 case ListIds::op_not_equal_ccont_ccont:
482 case ListIds::op_greater_ccont_ccont:
483 case ListIds::op_greater_equal_ccont_ccont:
484 case ListIds::op_less_equal_ccont_ccont:
485 // format zero cont argument without size as arg
486 rw_asnprintf (pbuf, pbufsize,
487 "%{+} (%{?}arg2%{:}%{$CLASS}(%{#*s})%{;}, "
488 "%{?}arg1%{:}%{$CLASS}(%{#*s})%{;})",
489 0 == str, int (str_len), str, self, int (arg_len), arg);
490 break;
491
492 case ListIds::ctor_size:
493 case ListIds::resize_size:
494 rw_asnprintf (pbuf, pbufsize,
495 "%{+} (%zu)", tcase.size);
496 break;
497
498 case ListIds::resize_size_val:
499 rw_asnprintf (pbuf, pbufsize,
500 "%{+} (%zu, %{#c})", tcase.size, tcase.val);
501 break;
502
503 case ListIds::swap_cont_cont:
504 case ListIds::splice_iter_cont:
505 case ListIds::splice_iter_cont_iter:
506 case ListIds::splice_iter_cont_iter_iter:
507 case ListIds::remove_if_pred:
508 case ListIds::unique_bpred:
509 case ListIds::merge_cont_comp:
510 case ListIds::sort_comp:
511 rw_asnprintf (pbuf, pbufsize,
512 "not yet defined");
513 break;
514
515 default:
516 RW_ASSERT (!"test logic error: unknown list overload");
517 }
518}
519
520
522// temporary, should be defined in 23.deque.h
524{
526 dummy
527 };
528};
529
530static void
531_rw_vector_sigcat (char** pbuf, size_t * pbufsize, VectorIds::OverloadId which,
532 bool self, const char* str, size_t str_len,
533 const char* arg, size_t arg_len,
534 const ContainerTestCase &tcase)
535{
536 // temporary empty
537
538 _RWSTD_UNUSED (pbuf);
539 _RWSTD_UNUSED (pbufsize);
541 _RWSTD_UNUSED (self);
543 _RWSTD_UNUSED (str_len);
545 _RWSTD_UNUSED (arg_len);
546 _RWSTD_UNUSED (tcase);
547}
548
549
551// temporary, should be defined in 23.deque.h
553{
555 dummy
556 };
557};
558
559static void
560_rw_deque_sigcat (char** pbuf, size_t * pbufsize, DequeIds::OverloadId which,
561 bool self, const char* str, size_t str_len,
562 const char* arg, size_t arg_len,
563 const ContainerTestCase &tcase)
564{
565 // temporary empty
566
567 _RWSTD_UNUSED (pbuf);
568 _RWSTD_UNUSED (pbufsize);
570 _RWSTD_UNUSED (self);
572 _RWSTD_UNUSED (str_len);
574 _RWSTD_UNUSED (arg_len);
575 _RWSTD_UNUSED (tcase);
576}
577
578
580// temporary, should be defined in 23.queue.h
582{
584 dummy
585 };
586};
587
588static void
589_rw_queue_sigcat (char** pbuf, size_t * pbufsize, QueueIds::OverloadId which,
590 bool self, const char* str, size_t str_len,
591 const char* arg, size_t arg_len,
592 const ContainerTestCase &tcase)
593{
594 // temporary empty
595
596 _RWSTD_UNUSED (pbuf);
597 _RWSTD_UNUSED (pbufsize);
599 _RWSTD_UNUSED (self);
601 _RWSTD_UNUSED (str_len);
603 _RWSTD_UNUSED (arg_len);
604 _RWSTD_UNUSED (tcase);
605}
606
607
609// temporary, should be defined in 23.stack.h
611{
613 dummy
614 };
615};
616
617static void
618_rw_stack_sigcat (char** pbuf, size_t * pbufsize, StackIds::OverloadId which,
619 bool self, const char* str, size_t str_len,
620 const char* arg, size_t arg_len,
621 const ContainerTestCase &tcase)
622{
623 // temporary empty
624
625 _RWSTD_UNUSED (pbuf);
626 _RWSTD_UNUSED (pbufsize);
628 _RWSTD_UNUSED (self);
630 _RWSTD_UNUSED (str_len);
632 _RWSTD_UNUSED (arg_len);
633 _RWSTD_UNUSED (tcase);
634}
635
636
638// sets the {CLASS}, {FUNC}, {FUNCSIG}, and optionally {FUNCALL}
639// environment variables as follows:
640// CLASS: the name of cont specialization
641// FUNC: the name of the cont function
642// FUNCSIG: the name and signature of a specific overload
643// of the cont function
644// FUNCALL: a cont describing the call to the cont function
645// with function with function arguments expanded (as specified
646// by the TestCase argument)
647static void
648_rw_setvars (const ContainerFunc &func,
649 const ContainerTestCase *pcase = 0)
650{
651 char* buf = 0;
652 size_t bufsize = 0;
653
654 const char* const class_name = _rw_class_name (func);
655
656 if (0 == pcase) {
657 // set the {Elem}, {Allocator}, {Iterator} and {Container}
658 // environment variables to the name of the element type
659 // and the Allocator and Iterator and Container specializations
660 rw_fprintf (0, "%{$Elem!:*}", _rw_elem_names [func.elem_id_]);
661
662 rw_fprintf (0, "%{$Allocator!:*}", _rw_alloc_names [func.alloc_id_]);
663
664 rw_fprintf (0, "%{$Iterator!:*}", _rw_iter_names [func.iter_id_]);
665
666 rw_fprintf (0, "%{$Container!:*}", class_name);
667
668 // set the {CLASS}, {FUNC}, and {FUNCSIG} environment variables
669 // to the name of the specialization of the template, the name
670 // of the container function, and the name of the overload of the
671 // container function, respectively, when no test case is given
672
673 // format container specializations, leaving out the name
674 // of the default allocator for brevity
675 rw_asnprintf (&buf, &bufsize,
676 "std::%s<%s%{?}, %s<%2$s>%{;}>",
677 class_name,
678 _rw_elem_names [func.elem_id_],
679 ContainerIds::DefaultAlloc != func.alloc_id_,
680 _rw_alloc_names [func.alloc_id_]);
681
682 // set the {CLASS} variable to the name of the specialization
683 // of container
684 rw_fprintf (0, "%{$CLASS!:*}", buf);
685 free (buf);
686 buf = 0;
687 bufsize = 0;
688
689 // determine the container function name
690 const size_t funcinx = func.which_ & ContainerIds::fid_mask;
691 const size_t nfuncs = sizeof _rw_func_names / sizeof *_rw_func_names;
692
693 RW_ASSERT (funcinx < nfuncs);
694
695 // get the undecorated function name; ctors are treated
696 // specially so that we can have string, wstring, or
697 // cont, depending on the template arguments
698 const char* const funcname = _rw_func_names [funcinx] ?
699 _rw_func_names [funcinx] : class_name;
700
701 // determine whether the function is a member function
702 const bool is_member = 0 != (func.which_ & ContainerIds::bit_member);
703
704 // set the {FUNC} variable to the unqualified/undecorated
705 // name of the container function (member or otherwise)
706 rw_asnprintf (&buf, &bufsize, "%{?}std::%{;}%s",
707 !is_member, funcname);
708
709 rw_fprintf (0, "%{$FUNC!:*}", buf);
710
711 // append the function signature
712 _rw_sigcat (&buf, &bufsize, &func);
713
714 rw_fprintf (0, "%{$FUNCSIG!:*}", buf);
715 free (buf);
716
717 return;
718 }
719
720 // do the function call arguments reference *this?
721 const bool self = 0 == pcase->arg;
722
723 char str_buf [256];
724 char arg_buf [256];
725
726 char *str;
727 char *arg;
728
729 size_t str_len = sizeof str_buf;
730 size_t arg_len = sizeof arg_buf;
731
732 if (pcase->str)
733 str = rw_expand (str_buf, pcase->str, pcase->str_len, &str_len);
734 else
735 str = 0;
736
737 if (pcase->arg)
738 arg = rw_expand (arg_buf, pcase->arg, pcase->arg_len, &arg_len);
739 else
740 arg = 0;
741
742 // determine whether the function is a member function
743 const bool is_member = 0 != (func.which_ & ContainerIds::bit_member);
744
745 // determine whether the function is a ctor
746 bool is_ctor = ContainerIds::fid_ctor == (func.which_ & ContainerIds::fid_mask);
747
748 if (is_ctor) {
749 // for ctors append just the class name here
750 // the class name will inserted below during argument
751 // formatting
752 rw_asnprintf (&buf, &bufsize, "%{$CLASS}::%s", class_name);
753 }
754 else if (is_member) {
755 // for other members append the ctor argument(s) followed
756 // by the cont member function name
757 rw_asnprintf (&buf, &bufsize,
758 "%{$CLASS} (%{?}%{#*s}%{;}).%{$FUNC}",
759 str != 0, int (str_len), str);
760 }
761 else {
762 // for non-members append just the function name here
763 // the class name will inserted below during argument
764 // formatting
765 rw_asnprintf (&buf, &bufsize, "%{$FUNC}");
766 }
767
768 // format and append container function arguments abbreviating complex
769 // expressions as much as possible to make them easy to understand
770 switch (func.cont_id_) {
771
773 _rw_list_sigcat (&buf, &bufsize,
775 self, str, str_len, arg, arg_len, *pcase);
776 break;
777
779 _rw_vector_sigcat (&buf, &bufsize,
781 self, str, str_len, arg, arg_len, *pcase);
782 break;
783
785 _rw_deque_sigcat (&buf, &bufsize,
787 self, str, str_len, arg, arg_len, *pcase);
788 break;
789
791 _rw_queue_sigcat (&buf, &bufsize,
793 self, str, str_len, arg, arg_len, *pcase);
794 break;
795
797 _rw_stack_sigcat (&buf, &bufsize,
799 self, str, str_len, arg, arg_len, *pcase);
800 break;
801
802 default:
803 RW_ASSERT (!"unknown container id");
804 }
805
806 rw_fprintf (0, "%{$FUNCALL!:*}", buf);
807 free (buf);
808
809 if (str != str_buf)
810 delete[] str;
811
812 if (arg != arg_buf)
813 delete[] arg;
814}
815
816
818// helper function to reverse substring in the resulting sequence
821 size_t off, size_t ext)
822{
823 // expand expected results
824 size_t res_len = 0;
825 char* const new_res = rw_expand ((char*)0, tsrc.res, tsrc.nres, &res_len);
826
827 // reverse them
828 const size_t res_off = off;
829 const size_t res_ext = (ext < res_len ? ext : res_len) - 1;
830
831 char* beg = new_res + res_off;
832 char* end = beg + res_ext;
833
834 for (; beg < end; ++beg, --end) {
835 const char tmp = *beg;
836 *beg = *end;
837 *end = tmp;
838 }
839
840 // form new test case
841 const ContainerTestCase new_case = {
842 tsrc.line, tsrc.off, tsrc.size, tsrc.off2,
843 tsrc.size2, tsrc.val, tsrc.str, tsrc.str_len,
844 tsrc.arg, tsrc.arg_len, new_res, res_len, tsrc.bthrow
845 };
846
847 return new_case;
848}
849
850
851template <class T, class Allocator>
852void
854 VoidFunc* const *farray,
855 const ContainerFunc &func,
856 const ContainerTestCase &tcase)
857{
858 typedef ContainerTestCaseData<T> Data;
859 typedef void TestFunc (T*, Allocator*, const Data&);
860
861 const size_t inx = func.elem_id_ * 2 + func.alloc_id_;
862
863 TestFunc* const tfunc = _RWSTD_REINTERPRET_CAST (TestFunc*, farray [inx]);
864
865 if (0 == tfunc) {
866 rw_error (0, __FILE__, __LINE__,
867 "logic error: null test function for %{$FUNCSIG}");
868 return;
869 }
870
871 const bool reverse_iter =
874
875 const Data tdata (func, tcase);
876
877 if (reverse_iter) {
878 // special processing for reverse iterators
879
880 const size_t func_id = tdata.func_.which_ & ContainerIds::fid_mask;
881
882 const bool like_ctor =
883 ContainerIds::fid_ctor == func_id
884 || ContainerIds::fid_assign == func_id;
885
886 // ctor and assignment operator require the full container reverse
887 const size_t off = like_ctor ? 0 : tdata.off1_;
888 const size_t ext = like_ctor ? tdata.reslen_ : tdata.ext2_;
889
890 const ContainerTestCase rev_tcase =
891 _rw_reverse_results (tcase, off, ext);
892
893 const Data rev_tdata (func, rev_tcase);
894
895 tfunc ((T*)0, (Allocator*)0, rev_tdata);
896
897 // clean up allocated memory, if any
898 delete[] rev_tcase.res;
899 }
900 else
901 tfunc ((T*)0, (Allocator*)0, tdata);
902}
903
904
905template <class T>
906void
908 VoidFunc* const *farray,
909 const ContainerFunc &func,
910 const ContainerTestCase &tcase)
911{
912 if (ContainerIds::DefaultAlloc == func.alloc_id_) {
913 typedef std::allocator<T> Alloc;
914 _rw_dispatch ((T*)0, (Alloc*)0, farray, func, tcase);
915 }
916 else if (ContainerIds::UserAlloc == func.alloc_id_) {
917 typedef UserAlloc<T> Alloc;
918 _rw_dispatch ((T*)0, (Alloc*)0, farray, func, tcase);
919 }
920 else {
921 RW_ASSERT (!"logic error: unknown Allocator argument");
922 }
923}
924
925
926static void
927_rw_dispatch (VoidFunc* const *farray,
928 const ContainerFunc &func,
929 const ContainerTestCase &tcase)
930{
931 if (ContainerIds::UserPOD == func.elem_id_) {
932 _rw_dispatch ((UserPOD*)0, farray, func, tcase);
933 }
934 else if (ContainerIds::UserClass == func.elem_id_) {
935 _rw_dispatch ((UserClass*)0, farray, func, tcase);
936 }
937 else {
938 RW_ASSERT (!"logic error: unknown T argument");
939 }
940}
941
942
944// exercise a single test case for the given function
945static void
946_rw_test_case (const ContainerFunc &func,
947 const ContainerTestCase &tcase,
948 ContainerTestFunc *test_callback,
949 VoidFunc* const *farray)
950{
951 // check to see if this is an exception safety test case
952 // and avoid running it when exception safety has been
953 // disabled via a command line option
954 if (-1 == tcase.bthrow && _rw_opt_no_exception_safety) {
955
956 // issue only the first note
957 rw_note (1 < _rw_opt_no_exception_safety++, _rw_this_file, __LINE__,
958 "exception safety tests disabled");
959 return;
960 }
961
962 // check to see if this is a test case that involves the throwing
963 // of an exception and avoid running it when exceptions have been
964 // disabled
965 if (tcase.bthrow && _rw_opt_no_exceptions) {
966
967 // issue only the first note
968 rw_note (1 < _rw_opt_no_exceptions++, _rw_this_file, __LINE__,
969 "exception tests disabled");
970 return;
971 }
972
973 const bool self_ref = 0 == tcase.arg;
974
975 // check for tests exercising self-referential modifications
976 // (e.g., insert(1, *this))
977 if (_rw_opt_self_ref < 0 && self_ref) {
978 // issue only the first note
979 rw_note (0, _rw_this_file, tcase.line,
980 "self-referential test disabled");
981 return;
982 }
983 else if (0 < _rw_opt_self_ref && !self_ref) {
984 // issue only the first note
985 rw_note (0, _rw_this_file, tcase.line,
986 "non-self-referential test disabled");
987 return;
988 }
989
990 // check to see if the test case is enabled
991 if (rw_enabled (tcase.line)) {
992
993 // set the {FUNCALL} environment variable to describe
994 // the function call specified by this test case
995 _rw_setvars (func, &tcase);
996
997 if (test_callback) {
998 // invoke the test callback function
999 test_callback (func, tcase);
1000 }
1001 else {
1002 _rw_dispatch (farray, func, tcase);
1003 }
1004 }
1005 else
1006 rw_note (0, _rw_this_file, tcase.line,
1007 "test on line %d disabled", tcase.line);
1008}
1009
1010
1013_rw_container_id;
1014
1015static ContainerTestFunc*
1016_rw_test_callback;
1017
1018
1019static VoidFunc* const*
1020_rw_func_array;
1021
1022
1023// exercise all test cases defined for the given function
1024static void
1025_rw_run_cases (const ContainerFunc &func,
1026 const ContainerTest &test)
1027{
1028 // set the {CLASS}, {FUNC}, and {FUNCSIG} environment
1029 // variable to the name of the container specialization
1030 // and the container function being exercised
1031 _rw_setvars (func);
1032
1033 // determine whether the function is a member function
1034 const bool is_member = 0 != (ContainerIds::bit_member & test.which);
1035
1036 // compute the function overload's 0-based index
1037 const size_t siginx = _rw_get_func_inx (test.which);
1038
1039 // check if tests of the function overload
1040 // have been disabled
1041 if (0 == rw_note (0 <= _rw_opt_func [siginx], _rw_this_file, __LINE__,
1042 "%{?}%{$CLASS}::%{;}%{$FUNCSIG} tests disabled",
1043 is_member))
1044 return;
1045
1046 rw_info (0, 0, 0, "%{?}%{$CLASS}::%{;}%{$FUNCSIG}", is_member);
1047
1048 const size_t case_count = test.case_count;
1049
1050 // iterate over all test cases for this function
1051 // overload invoking the test case handler for each
1052 // in turn
1053 for (size_t n = 0; n != case_count; ++n) {
1054
1055 const ContainerTestCase& tcase = test.cases [n];
1056
1057 _rw_test_case (func, tcase, _rw_test_callback, _rw_func_array);
1058 }
1059}
1060
1061
1063void
1064_rw_toggle_options (int *opts, size_t count)
1065{
1066 for (size_t i = 0; i != count; ++i) {
1067 if (0 < opts [i]) {
1068 // if one or more options has been explicitly enabled
1069 // treat all those that haven't been as if they had
1070 // been disabled
1071 for (i = 0; i != count; ++i) {
1072 if (0 == opts [i])
1073 opts [i] = -1;
1074 }
1075 break;
1076 }
1077 }
1078}
1079
1080
1081static int
1082_rw_run_test (int, char*[])
1083{
1084#ifdef _RWSTD_NO_EXCEPTIONS
1085
1086 rw_note (0, 0, 0, "exception tests disabled (macro "
1087 "_RWSTD_NO_EXCEPTIONS #defined)");
1088
1089 // disable all exception tests and avoid further notes
1090 _rw_no_exceptions = 2;
1091 _rw_no_exception_safety = 2;
1092
1093#endif // _RWSTD_NO_EXCEPTIONS
1094
1095 // see if any option controlling a container function has been
1096 // explicitly enabled and if so disable all those that haven't
1097 // been (i.e., so that --enable-foo-size will have the effect
1098 // of specifying --disable-foo-val and --disable-foo-range,
1099 // given the three overloads of foo)
1100 const size_t nopts = sizeof _rw_opt_func / sizeof *_rw_opt_func;
1101 _rw_toggle_options (_rw_opt_func, nopts);
1102
1103 static const ContainerIds::ElemId elem_types[] = {
1105 };
1106
1107 static const ContainerIds::AllocId alloc_types[] = {
1109 };
1110
1111 static const ContainerIds::IteratorId iter_types[] = {
1117 };
1118
1119 const size_t n_elem_types = sizeof elem_types / sizeof *elem_types;
1120 const size_t n_alloc_types = sizeof alloc_types / sizeof *alloc_types;
1121 const size_t n_iter_types = sizeof iter_types / sizeof *iter_types;
1122
1123 // see if any option controlling the container template arguments
1124 // explicitly enabled and if so disable all those that haven't been
1125 _rw_toggle_options (_rw_opt_elem_types, n_elem_types);
1126 _rw_toggle_options (_rw_opt_alloc_types, n_alloc_types);
1127 _rw_toggle_options (_rw_opt_iter_types, n_iter_types);
1128
1129 // exercise different T specializations last
1130 for (size_t i = 0; i != n_elem_types; ++i) {
1131
1132 if (_rw_opt_elem_types [i] < 0) {
1133 // issue only the first note
1134 rw_note (-1 > _rw_opt_elem_types [i]--,
1135 _rw_this_file, __LINE__,
1136 "%s tests disabled", _rw_elem_names [i]);
1137 continue;
1138 }
1139
1140 for (size_t k = 0; k != n_alloc_types; ++k) {
1141
1142 if (_rw_opt_alloc_types [k] < 0) {
1143 // issue only the first note
1144 rw_note (-1 > _rw_opt_alloc_types [k]--,
1145 _rw_this_file, __LINE__,
1146 "%s tests disabled", _rw_alloc_names [k]);
1147 continue;
1148 }
1149
1150 for (size_t m = 0; m != _rw_cont_test_count; ++m) {
1151
1152 const ContainerTest& test = _rw_cont_tests [m];
1153
1154 // create an object uniquely identifying the overload
1155 // of the container function exercised by the set of test
1156 // cases defined to exercise it
1158 elem_types [i],
1159 alloc_types [k],
1161 _rw_container_id,
1162 test.which
1163 };
1164
1165 // determine whether the function is a template
1166 if (-1 < _rw_argno (test.which, ContainerIds::arg_range)) {
1167
1168 // iterate over the standard iterator categories
1169 // and iterator types the template might perhaps
1170 // be specialized on
1171 for (size_t l = 0; l != n_iter_types; ++l) {
1172
1173 if (_rw_opt_iter_types [l] < 0) {
1174 // issue only the first note
1175 rw_note (-1 > _rw_opt_iter_types [l]--,
1176 _rw_this_file, __LINE__,
1177 "%s tests disabled",
1178 _rw_iter_names [l]);
1179 continue;
1180 }
1181
1182 func.iter_id_ = iter_types [l];
1183
1184 // exercise all test cases defined for
1185 // the function template
1186 _rw_run_cases (func, test);
1187 }
1188 }
1189 else {
1190 // exercise all test cases defined for the ordinary
1191 // (i.e., non-template) function
1192 _rw_run_cases (func, test);
1193 }
1194 }
1195 }
1196 }
1197
1198 return 0;
1199}
1200
1201
1203// add a bunch of toggle-type command line options based on the names array
1204static void
1205_rw_add_toggles (char **pbuf, size_t *pbufsize,
1206 const char* const names[], size_t count)
1207{
1208 for (size_t i = 0; i != count; ++i) {
1209 rw_asnprintf (pbuf, pbufsize, "%{+}|-%s~ ", names [i]);
1210 }
1211}
1212
1213static void
1214_rw_add_container_toggles (char **pbuf, size_t *pbufsize)
1215{
1216 _rw_add_toggles (pbuf, pbufsize, _rw_alloc_names,
1217 sizeof _rw_alloc_names / sizeof *_rw_alloc_names);
1218 _rw_add_toggles (pbuf, pbufsize, _rw_iter_names + 1,
1219 sizeof _rw_iter_names / sizeof *_rw_iter_names - 1);
1220}
1221
1222
1223static int
1224_rw_run_test (int argc,
1225 char *argv [],
1226 const char *file,
1227 const char *clause,
1228 ContainerIds::ContainerId container,
1229 ContainerTestFunc *test_callback,
1230 VoidFunc* const *func_array,
1231 const ContainerTest *tests,
1232 size_t test_count)
1233{
1234 // set the global variables accessed in _rw_run_test
1235 _rw_container_id = container;
1236 _rw_test_callback = test_callback;
1237 _rw_func_array = func_array,
1238 _rw_cont_tests = tests;
1239 _rw_cont_test_count = test_count;
1240
1241 // put together a command line option specification with options
1242 // to enable and disable tests exercising functions for all known
1243 // specializations of the functions specified by the test array
1244 char *optbuf = 0;
1245 size_t optbufsize = 0;
1246
1247 rw_asnprintf (&optbuf, &optbufsize,
1248 "|-no-exceptions# "
1249 "|-no-exception-safety# "
1250 "|-self-ref~ ");
1251
1252 const size_t n_elems = sizeof _rw_elem_names / sizeof *_rw_elem_names;
1253
1254 // see if any option has been explicitly enabled and if so,
1255 // unconditionally disable all those that have not been
1256 _rw_add_toggles (&optbuf, &optbufsize, _rw_elem_names, n_elems);
1257 _rw_add_container_toggles (&optbuf, &optbufsize);
1258
1259 for (size_t i = 0; i != test_count; ++i) {
1260
1261 // for each function append a command line option specification
1262 // to allow to enable or disable it
1263 rw_asnprintf (&optbuf, &optbufsize, "%{+}|-");
1264 _rw_sigcat (&optbuf, &optbufsize, 0, tests [i].which);
1265 rw_asnprintf (&optbuf, &optbufsize, "%{+}~ ");
1266 }
1267
1268 RW_ASSERT (test_count <= 32);
1269 RW_ASSERT (test_count <= MAX_OVERLOADS);
1270
1271 // process command line arguments run tests
1272 const int status =
1273 rw_test (argc, argv, file, clause,
1274 0, // comment
1275 _rw_run_test, // test callback
1276 optbuf, // option specification
1277
1278 // handlers controlling exceptions
1279 &_rw_opt_no_exceptions,
1280 &_rw_opt_no_exception_safety,
1281
1282 // handler controlling self-referential modifiers
1283 &_rw_opt_self_ref,
1284
1285 // handlers controlling specializations of the template
1286 // ...on the T template parameter
1287 _rw_opt_elem_types + 0,
1288 _rw_opt_elem_types + 1,
1289
1290 // ...on the Allocator template parameter
1291 _rw_opt_alloc_types + 0,
1292 _rw_opt_alloc_types + 1,
1293
1294 // FIXME: add handlers (and options) only for tests
1295 // that exercise member templates
1296
1297 // handlers controlling specializations of the member
1298 // template (if this is one) on the InputIterator
1299 // template parameter
1300 _rw_opt_iter_types + 0,
1301 _rw_opt_iter_types + 1,
1302 _rw_opt_iter_types + 2,
1303 _rw_opt_iter_types + 3,
1304 _rw_opt_iter_types + 4,
1305 _rw_opt_iter_types + 5,
1306 _rw_opt_iter_types + 6,
1307 _rw_opt_iter_types + 7,
1308 _rw_opt_iter_types + 8,
1309 _rw_opt_iter_types + 9,
1310
1311 // FIXME: install exactly as many handlers (and options)
1312 // as there are distinct functions being exercised
1313
1314 // handlers for up to 32 overloads
1315 _rw_opt_func + 0,
1316 _rw_opt_func + 1,
1317 _rw_opt_func + 2,
1318 _rw_opt_func + 3,
1319 _rw_opt_func + 4,
1320 _rw_opt_func + 5,
1321 _rw_opt_func + 6,
1322 _rw_opt_func + 7,
1323 _rw_opt_func + 8,
1324 _rw_opt_func + 9,
1325 _rw_opt_func + 10,
1326 _rw_opt_func + 11,
1327 _rw_opt_func + 12,
1328 _rw_opt_func + 13,
1329 _rw_opt_func + 14,
1330 _rw_opt_func + 15,
1331 _rw_opt_func + 16,
1332 _rw_opt_func + 17,
1333 _rw_opt_func + 18,
1334 _rw_opt_func + 19,
1335 _rw_opt_func + 20,
1336 _rw_opt_func + 21,
1337 _rw_opt_func + 22,
1338 _rw_opt_func + 23,
1339 _rw_opt_func + 24,
1340 _rw_opt_func + 25,
1341 _rw_opt_func + 26,
1342 _rw_opt_func + 27,
1343 _rw_opt_func + 28,
1344 _rw_opt_func + 29,
1345 _rw_opt_func + 30,
1346 _rw_opt_func + 31,
1347
1348 // sentinel
1349 (void*)0);
1350
1351 // free storage allocated for the option specification
1352 free (optbuf);
1353
1354 return status;
1355}
1356
1357
1358
1359_TEST_EXPORT int
1361 char *argv [],
1362 const char *file,
1363 const char *clause,
1364 ContainerIds::ContainerId container,
1365 ContainerTestFunc *callback,
1366 const ContainerTest *tests,
1367 size_t count)
1368{
1369 return _rw_run_test (argc, argv, file, clause, container,
1370 callback, 0, tests, count);
1371}
1372
1373
1374_TEST_EXPORT int
1376 char *argv [],
1377 const char *file,
1378 const char *clause,
1379 ContainerIds::ContainerId container,
1380 VoidFunc* const *farray,
1381 const ContainerTest *tests,
1382 size_t count)
1383{
1384 return _rw_run_test (argc, argv, file, clause, container,
1385 0, farray, tests, count);
1386}
void count(T, T, const U &,...)
#define m
Definition 17.names.cpp:129
#define i
Definition 17.names.cpp:126
#define T
Definition 17.names.cpp:163
#define k
Definition 17.names.cpp:128
#define which
Definition 17.names.cpp:575
#define Alloc
Definition 17.names.cpp:439
#define buf
Definition 17.names.cpp:452
#define off
Definition 17.names.cpp:507
#define tmp
Definition 17.names.cpp:553
#define n
Definition 17.names.cpp:130
#define inx
Definition 17.names.cpp:484
_RWSTD_INTERNAL ContainerTestCase _rw_reverse_results(const ContainerTestCase &tsrc, size_t off, size_t ext)
const size_t MAX_OVERLOADS
void _rw_dispatch(T *, Allocator *, VoidFunc *const *farray, const ContainerFunc &func, const ContainerTestCase &tcase)
_TEST_EXPORT int rw_run_cont_test(int argc, char *argv[], const char *file, const char *clause, ContainerIds::ContainerId container, ContainerTestFunc *callback, const ContainerTest *tests, size_t count)
void _rw_toggle_options(int *opts, size_t count)
const int end
#define _RWSTD_REINTERPRET_CAST(T, x)
Definition _defs.h:535
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_INTERNAL
Definition _defs.h:1005
#define _RWSTD_STATIC_CAST(T, x)
Definition _defs.h:534
const char * str
Definition exec.cpp:170
_TEST_EXPORT char * rw_expand(char *, const char *, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX, _RWSTD_SIZE_T *=0)
_TEST_EXPORT int rw_enabled(const char *name)
void VoidFunc()
void ContainerTestFunc(const ContainerFunc &, const ContainerTestCase &)
_TEST_EXPORT int rw_test(int argc, char *argv[], const char *filename, const char *clause, const char *comment, int(*testfun)(int, char **), const char *optspec,...)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_note(int, const char *, int, const char *,...)
Definition driver.cpp:1664
_TEST_EXPORT int rw_error(int, const char *, int, const char *,...)
Definition driver.cpp:1613
_TEST_EXPORT int rw_fprintf(rw_file *, const char *,...)
Definition printf.cpp:3397
_TEST_EXPORT int rw_asnprintf(char **pbuf, _RWSTD_SIZE_T *pbufsize, const char *fmt,...)
#define _TEST_EXPORT
Definition rw_testdefs.h:55
#define RW_ASSERT(expr)
_RWSTD_SIZE_T str_len
_RWSTD_SIZE_T arg_len
_RWSTD_SIZE_T nres
int arg
Definition locale.cpp:2806