Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
23.list.special.cpp
Go to the documentation of this file.
1
27#include <list> // for list
28#include <cstddef> // size_t
29
30#include <rw_lists.h> // for ListMembers
31#include <rw_driver.h> // for rw_assert()
32#include <rw_allocator.h> // for UserAlloc
33#include <rw_new.h> // for bad_alloc, replacement operator new
34
35
37// for convenience and brevity
38#define Swap(sig) ListIds::swap_ ## sig
39
40static const char* const exceptions[] = {
41 "unknown exception", "bad_alloc", "exception"
42};
43
44
46// exercises:
47// swap (list&)
48static const ContainerTestCase
49cont_cont_test_cases [] = {
50
51#undef TEST
52#define TEST(str, arg) \
53 { __LINE__, -1, -1, -1, -1, -1, \
54 str, sizeof str - 1, arg, sizeof arg - 1, \
55 0, 0, 0 \
56 }
57
58 // +------------------------- controlled "destination" sequence
59 // | +-------- controlled "source" sequence
60 // | |
61 // V V
62 TEST ("", ""),
63};
64
65// exercises:
66// swap (list&)
67static const ContainerTestCase
68cont_test_cases [] = {
69
70 // +------------------------- controlled "destination" sequence
71 // | +-------- controlled "source" sequence
72 // | |
73 // V V
74 TEST ("", ""),
75 TEST ("", "a"),
76 TEST ("a", ""),
77 TEST ("", "<U0>"),
78 TEST ("<U0>", ""),
79
80 TEST ("a", "b"),
81 TEST ("a", "bc"),
82 TEST ("ab", "c"),
83
84 TEST ("a<U0>b<U0>@2c", "<U0>b<U0>@2c"),
85 TEST ("<U0>b<U0>@2c", "a<U0>b<U0>@2c"),
86
87 TEST ("a<U0>b<U0>@2c", "<U0>@2"),
88 TEST ("<U0>@2", "a<U0>b<U0>@2c"),
89
90 TEST ("x@4096", ""),
91 TEST ("", "x@4096"),
92 TEST ("x@4096", "<U0>@3"),
93 TEST ("<U0>@3", "x@4096"),
94 TEST ("x@4096", "x@4096"),
95
96 TEST ("", "x@128"),
97 TEST ("x@207", "x@128"),
98 TEST ("x@128", "x@334"),
99 TEST ("x@873", "x@334"),
100 TEST ("x@1412", "x@540"),
101 TEST ("x@540", "x@2284"),
102 TEST ("x@3695", "x@2284"),
103 TEST ("x@3695", "x@128"),
104
105 TEST ("", 0),
106 TEST ("<U0>", 0),
107 TEST ("abc", 0),
108 TEST ("a<U0>b<U0>@2c", 0),
109 TEST ("x@4096", 0),
110
111 TEST (0, ""),
112 TEST (0, "<U0>"),
113 TEST (0, "abc@1024"),
114 TEST (0, "a<U0>b<U0>@2c"),
115 TEST (0, "x@4096"),
116
117 TEST ("last", "test")
118};
119
120
121
123struct ListValueType { };
124
125typedef std::allocator<ListValueType> ListAllocator;
126typedef std::list<ListValueType, ListAllocator> ListType;
127
128static int list_swap_called;
129
131
132 // define an explicit specialization of the list::swap() member
133 // to verify tha the non-member swap function calls the member
134
136void ListType::swap (ListType&)
137{
138 ++list_swap_called;
139}
140
141} // namespace std
142
143
146{
147 static bool tested = false;
148
149 if (tested)
150 return;
151
152 tested = true;
153
154 rw_info (0, 0, 0,
155 "Testing std::swap (std::list&, std::list&) "
156 "calls std::list::swap");
157
158 // verify the signature of the function specialization
159 void (*pswap)(ListType&, ListType&) =
160 &std::swap<ListValueType, ListAllocator>;
161
162 _RWSTD_UNUSED (pswap);
163
164 // verify that std::swap() calls std::list::swap()
165 ListType lst;
166
167 std::swap (lst, lst);
168
169 rw_assert (1 == list_swap_called, 0, __LINE__,
170 "std::swap (std::list<T, A>&, std::list<T, A>&) called "
171 "std::list<T, A>::swap (std::list<T, A>&) exactly once; "
172 "got %d times", list_swap_called);
173}
174
175
177template <class T, class Allocator>
179 Allocator &a1,
180 Allocator &a2,
181 const ContainerTestCaseData<T> &tdata)
182{
183 typedef std::list <T, Allocator> List;
185
186 const ContainerTestCase &tcase = tdata.tcase_;
187 const ContainerFunc &func = tdata.func_;
188
189 // construct the list object to be modified
190 // and the argument list
191 List src_list (tdata.str_, tdata.str_ + tdata.strlen_, a1);
192 List dst_list (tdata.arg_, tdata.arg_ + tdata.arglen_, a2);
193
194 List& arg_list = tcase.arg ? dst_list : src_list;
195
196 // save the state of the list object before the call
197 // to detect exception safety violations (changes to
198 // the state of the object after an exception)
199 const ListState src_state (src_list);
200 const ListState arg_state (arg_list);
201
202 rwt_free_store* const pst = rwt_get_free_store (0);
203 SharedAlloc* const pal = SharedAlloc::instance ();
204
205 // iterate for`throw_count' starting at the next call to operator new,
206 // forcing each call to throw an exception, until the function finally
207 // succeeds (i.e, no exception is thrown)
208 std::size_t throw_count;
209 for (throw_count = 0; ; ++throw_count) {
210
211 const char* expected = 0;
212 const char* caught = 0;
213
214#ifndef _RWSTD_NO_EXCEPTIONS
215
216 // no exceptions expected
217 if (0 == tcase.bthrow && a1 == a2) {
218 // by default exercise the exception safety of the function
219 // by iteratively inducing an exception at each call to operator
220 // new or Allocator::allocate() until the call succeeds
221 expected = exceptions [1]; // bad_alloc
222 *pst->throw_at_calls_ [0] = pst->new_calls_ [0] + throw_count + 1;
223 pal->throw_at_calls_ [pal->m_allocate] =
224 pal->throw_at_calls_ [pal->m_allocate] + throw_count + 1;
225 }
226
227#else // if defined (_RWSTD_NO_EXCEPTIONS)
228
229 if (tcase.bthrow)
230 return;
231
232#endif // _RWSTD_NO_EXCEPTIONS
233
234 // start checking for memory leaks
235 rw_check_leaks (src_list.get_allocator ());
236 rw_check_leaks (arg_list.get_allocator ());
237
238 try {
239 const bool is_class = ListIds::UserClass == func.elem_id_;
240
241 // reset function call counters
242 if (is_class)
244
245 src_list.swap (arg_list);
246
247 if (is_class && a1 == a2) {
248
249 bool success = 0 == (UserClass::n_total_def_ctor_
252
253 rw_assert (success, 0, tcase.line,
254 "line %d. %{$FUNCALL}: complexity: %zu def ctors, "
255 "%zu copy ctors, %zu assigns", __LINE__,
259 }
260
261 if (0 == tcase.str) {
262
263 rw_assert (0 == arg_list.size (), 0, tcase.line,
264 "line %d. %{$FUNCALL}: expected 0 size, "
265 "got %zu", __LINE__, arg_list.size ());
266 }
267
268 if (a1 == a2) {
269
270 src_state.assert_equal (ListState (arg_list),
271 __LINE__, tcase.line, "swap");
272
273 arg_state.assert_equal (ListState (src_list),
274 __LINE__, tcase.line, "swap");
275 }
276 }
277
278#ifndef _RWSTD_NO_EXCEPTIONS
279
280 catch (const std::bad_alloc &ex) {
281 caught = exceptions [1];
282 rw_assert (0 == tcase.bthrow, 0, tcase.line,
283 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
284 "unexpectedly%{;} caught std::%s(%#s)",
285 __LINE__, 0 != expected, expected, caught, ex.what ());
286 }
287 catch (const std::exception &ex) {
288 caught = exceptions [2];
289 rw_assert (0, 0, tcase.line,
290 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
291 "unexpectedly%{;} caught std::%s(%#s)",
292 __LINE__, 0 != expected, expected, caught, ex.what ());
293 }
294 catch (...) {
295 caught = exceptions [0];
296 rw_assert (0, 0, tcase.line,
297 "line %d. %{$FUNCALL} %{?}expected %s,%{:}"
298 "unexpectedly%{;} caught %s",
299 __LINE__, 0 != expected, expected, caught);
300 }
301
302#endif // _RWSTD_NO_EXCEPTIONS
303
304 // FIXME: verify the number of blocks the function call
305 // is expected to allocate and detect any memory leaks
306 rw_check_leaks (src_list.get_allocator (), tcase.line,
307 std::size_t (-1), std::size_t (-1));
308
309 rw_check_leaks (arg_list.get_allocator (), tcase.line,
310 std::size_t (-1), std::size_t (-1));
311
312 if (caught) {
313 // verify that an exception thrown during allocation
314 // didn't cause a change in the state of the object
315 src_state.assert_equal (ListState (src_list),
316 __LINE__, tcase.line, caught);
317
318 arg_state.assert_equal (ListState (arg_list),
319 __LINE__, tcase.line, caught);
320
321 if (0 == tcase.bthrow) {
322 // allow this call to operator new to succeed and try
323 // to make the next one to fail during the next call
324 // to the same function again
325 continue;
326 }
327 }
328 else if (0 < tcase.bthrow) {
329 rw_assert (caught == expected, 0, tcase.line,
330 "line %d. %{$FUNCALL} %{?}expected %s, caught %s"
331 "%{:}unexpectedly caught %s%{;}",
332 __LINE__, 0 != expected, expected, caught, caught);
333 }
334
335 break;
336 }
337
338 // no exception expected
339 const std::size_t expect_throws = 0;
340
341 rw_assert (expect_throws == throw_count, 0, tcase.line,
342 "line %d: %{$FUNCALL}: expected exactly 0 %s exception "
343 "while the swap, got %zu",
344 __LINE__, exceptions [1], throw_count);
345
346 // disable bad_alloc exceptions
347 *pst->throw_at_calls_ [0] = 0;
348 pal->throw_at_calls_ [pal->m_allocate] = 0;
349}
350
351
353template <class T>
354std::allocator<T>
355make_alloc (SharedAlloc&, std::allocator<T>*) {
356 return std::allocator<T>();
357}
358
359template <class T, class Types>
362 return UserAlloc<T, Types>(&shal);
363}
364
365
367template <class T, class Allocator>
369 const ContainerTestCaseData<T> &tdata)
370{
371 if (Swap (cont_cont) == tdata.func_.which_) {
372
373 test_std_swap ();
374
375 return;
376 }
377
378 SharedAlloc sa1;
379 Allocator a1 = make_alloc(sa1, (Allocator*)0);
380
381 // test swap using the same allocator objects
382 test_swap ((T*)0, a1, a1, tdata);
383
384 SharedAlloc sa2;
385 Allocator a2 = make_alloc(sa2, (Allocator*)0);
386
387 if (a1 != a2) {
388 // test swap using different allocator objects
389 test_swap ((T*)0, a1, a2, tdata);
390 }
391}
392
393
396
397int main (int argc, char** argv)
398{
399 static const ContainerTest
400 tests [] = {
401
402#undef TEST
403#define TEST(sig) { \
404 Swap (sig), sig ## _test_cases, \
405 sizeof sig ## _test_cases / sizeof *sig ## _test_cases, \
406 }
407
408 TEST (cont),
409 TEST (cont_cont)
410 };
411
412 const std::size_t test_count = sizeof tests / sizeof *tests;
413
414 const int status =
415 rw_run_cont_test (argc, argv, __FILE__,
416 "lib.list.special",
418 test_swap_func_array, tests, test_count);
419
420 return status;
421}
#define T
Definition 17.names.cpp:163
#define a2
Definition 17.names.cpp:251
#define a1
Definition 17.names.cpp:225
void test_swap()
std::allocator< ListValueType > ListAllocator
#define TEST(str, arg)
#define Swap(sig)
void test_std_swap()
std::list< ListValueType, ListAllocator > ListType
std::allocator< T > make_alloc(SharedAlloc &, std::allocator< T > *)
#define main
int caught
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
#define _RWSTD_SPECIALIZED_FUNCTION
Definition _defs.h:556
const ContainerFunc & func_
const ContainerTestCase & tcase_
Definition json.h:5363
_TEST_EXPORT void rw_check_leaks(const SharedAlloc *=0, int=0, _RWSTD_SIZE_T=0, _RWSTD_SIZE_T=_RWSTD_SIZE_MAX)
_TEST_EXPORT int rw_run_cont_test(int, char **, const char *, const char *, ContainerIds::ContainerId, ContainerTestFunc *, const ContainerTest *, _RWSTD_SIZE_T)
#define DEFINE_CONTAINER_TEST_FUNCTIONS(fname)
_TEST_EXPORT int rw_info(int, const char *, int, const char *,...)
Definition driver.cpp:1681
_TEST_EXPORT int rw_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
_TEST_EXPORT rwt_free_store * rwt_get_free_store(rwt_free_store *)
Definition new.cpp:597
_RWSTD_SIZE_T which_
void assert_equal(const ListState &state, int line, int case_line, const char *when) const
Definition rw_lists.h:267
static SharedAlloc * instance(SharedAlloc *=0)
_RWSTD_SIZE_T throw_at_calls_[n_funs]
static _RWSTD_SIZE_T n_total_op_assign_
Definition rw_value.h:127
static void reset_totals()
Definition value.cpp:452
static _RWSTD_SIZE_T n_total_def_ctor_
Definition rw_value.h:124
static _RWSTD_SIZE_T n_total_copy_ctor_
Definition rw_value.h:125
_RWSTD_SIZE_T * throw_at_calls_[2]
Definition rw_new.h:83
_RWSTD_SIZE_T new_calls_[2]
Definition rw_new.h:47