Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
25.random.shuffle.cpp
Go to the documentation of this file.
1
29#include <algorithm> // for random_shuffle
30#include <cstring> // for memset(), size_t
31
32#include <rw_alg_test.h>
33#include <rw_value.h> // for UserClass
34#include <rw_driver.h> // for rw_test()
35
36
38
39// disable explicit instantiation for compilers (like MSVC)
40// that can't handle it
41#ifndef _RWSTD_NO_EXPLICIT_INSTANTIATION
42
43template
44void
45random_shuffle (RandomAccessIter<assign<base<cpy_ctor> > >,
47
48template
49void
50random_shuffle (RandomAccessIter<assign<base<cpy_ctor> > >,
53
54#endif // _RWSTD_NO_EXPLICIT_INSTANTIATION
55
56} // namespace std
57
58
60// 25.2.11, p3 requires that a RandomNumberGenerator take
61// and return a value convertible from and to, respectively,
62// iterator::difference_type
63
64template <class DifferenceType>
66{
67 Convertible (DifferenceType val): val_ (val) { }
68 operator DifferenceType () /* non-const */ { return val_; }
69
70private:
71 const DifferenceType val_;
72
73 template <class T>
74 Convertible (T);
75};
76
77// detect assumptions made by the algorithm about the return value
78// from RandomGenerator::operator() being anything but convertible
79// to the iterator's difference type
80template <class DifferenceType, class T>
82
83template <class DifferenceType, class T>
85
86template <class DifferenceType>
88{
89 // dummy arguments to prevent the class from being default
90 // constructible or construtible by conversion from an int
91 RandomGenerator (int, int) {
92 ncalls_ = 0;
93 }
94
95 // non-const in order to detect unwarranted assumptions
96 // in the algorithm(s)
98 operator() (DifferenceType n) /* non-const */ {
99
100 ++ncalls_;
101
102 gen_ = (gen_ << 7) + gen_ % 128;
103
104 // prevent the number from going negative(!)
105 if (gen_ < 0)
106 gen_ = -gen_;
107
108 return gen_ % n;
109 }
110
111 static std::size_t ncalls_;
112
113private:
114
115 template <class T>
116 void operator() (T) /* non-const */;
117
118 static DifferenceType gen_;
119};
120
121template <class DifferenceType>
123
124template <class DifferenceType>
125DifferenceType RandomGenerator<DifferenceType>::gen_ = 12345;
126
127
130
132{
133 return sequence_start++;
134}
135
136
138// exercises 25.2.11 -- std::random_shuffle()
139template <class T, class Iterator, class RandomNumberGenerator>
140void test_random_shuffle (const int line,
141 const std::size_t N,
142 const Iterator &it,
144 const T*,
145 bool rnd_gen)
146{
147 const char* const itname = type_name (it, (T*)0);
148 const char* const fname = "random_shuffle";
149 const char* const funname = rnd_gen ? "random_generator" : "";
150
151 rw_info (0, 0, 0,
152 "std::%s (%s, %2$s%{?}, %s%{;})",
153 fname, itname, rnd_gen, funname);
154
155 // generate a sequential value for each default-constructed T
156 // starting with 0 (i.e., T::val_ will be 0 for the first T)
157 sequence_start = 0;
158 T::gen_ = sequence_generator;
159
160 T *buf = new T [N + 1];
161 char *missing = new char [N + 1];
162
163 for (std::size_t i = 0; i < N; ++i) {
164
165 // create a pair of safe iterator to pass to random_shuffle
166 // in order to test that the function doesn't write past
167 // the end of the sequence [first, last)
168 const Iterator first = make_iter (buf, buf, buf + i, it);
169 const Iterator last = make_iter (buf + i, buf, buf + i, it);
170
171 /* non-const */ RandomNumberGenerator rnd (0, 0); // dummy args
172
173 // exercise 25.2.11 - std::random_shuffle<>()
174 std::size_t n_op_assign = T::n_total_op_assign_;
175
176 // shuffle buffer elements
177 if (rnd_gen)
178 std::random_shuffle (first, last, rnd);
179 else
180 std::random_shuffle (first, last);
181
182 n_op_assign = T::n_total_op_assign_ - n_op_assign;
183
184 // verify 25.2.11, p1
185 // iterate over elements of the missing array clearing those
186 // at the index given by T::val_ to true to verify that the
187 // algorithm didn't drop any elements
188 std::size_t j;
189 std::memset (missing, 1, N);
190 for (j = 0; j != i; ++j) {
191 const std::size_t inx = std::size_t (buf [j].data_.val_);
192 if (inx < N)
193 missing [inx] = 0;
194 }
195
196 // find the first missing element (if any)
197 const char* const first_missing = (char*)std::memchr (missing, 1, i);
198
199 bool success = 0 == first_missing;
200
201 rw_assert (success, 0, line,
202 "%zu. std::%s<%s%{?}, %s%{;}>(): can't find element "
203 "with value %td: got \"%{X=*.*}\"",
204 i, fname, itname, rnd_gen, funname,
205 first_missing - missing,
206 int (sizeof (*buf)), int (i), -1, buf);
207
208
209 // verify 25.2.11, p2, complexity:
210 // exactly K = ((last - first) - 1) swaps
211 // i.e., K * 2 assignments (at 2 assignment per swap
212 // plus one copy construction)
213 success = n_op_assign == 2 * (i ? i - 1 : i);
214 rw_assert (success, 0, line,
215 "%zu. std::%s<%s%{?}, %s%{;}>(): complexity: "
216 "expected %zu swaps, got %zu",
217 i, fname, itname, rnd_gen, funname,
218 2 * i, n_op_assign);
219 }
220
221 delete[] buf;
222 delete[] missing;
223}
224
225
227void test_random_shuffle (const int line)
228{
229#ifndef _RWSTD_NO_EXT_PORTABLE_RANDOM_SEQUENCE
230
231 rw_info (0, 0, 0,
232 "verify that the randomly shuffled sequence "
233 "matches the expected result, this "
234 "depends on the implementation of the random "
235 "number generator used by random_shuffle()");
236
237 int array[] = {
238 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
239 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
240 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
241 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
242 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
243 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
244 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
245 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
246 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
247 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
248 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
249 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
250 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
251 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
252 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
253 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
254 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
255 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
256 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
257 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
258 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
259 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
260 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
261 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
262 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
263 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf,
264 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7,
265 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf,
266 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7,
267 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef,
268 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7,
269 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff
270 };
271
272 std::random_shuffle (array, array + sizeof array / sizeof *array);
273
274 const int result[] = {
275 0xdc, 0x98, 0x6c, 0xcc, 0x1c, 0xb1, 0x2f, 0x13,
276 0xa4, 0x8b, 0x96, 0x87, 0x95, 0xd8, 0x5e, 0xd5,
277 0xb6, 0xee, 0xc3, 0x07, 0x68, 0xe4, 0x4e, 0xc0,
278 0xb7, 0x40, 0x15, 0x55, 0x31, 0x5f, 0xaf, 0xce,
279 0x01, 0x51, 0x09, 0x4f, 0x0b, 0x80, 0x28, 0x0f,
280 0xec, 0x43, 0x8a, 0x14, 0x90, 0x9a, 0x7b, 0x3e,
281 0x81, 0x1e, 0xab, 0xff, 0xed, 0xf6, 0xca, 0x0c,
282 0x6a, 0x9c, 0x91, 0x60, 0x27, 0xb2, 0x04, 0xd3,
283 0x72, 0xd7, 0x08, 0x8c, 0x8e, 0x1b, 0x35, 0x49,
284 0xba, 0x7a, 0xfd, 0x53, 0x22, 0xaa, 0xf5, 0x93,
285 0xf2, 0x63, 0x05, 0xb4, 0x33, 0x9b, 0xea, 0xc8,
286 0xc5, 0x39, 0xfc, 0x5d, 0x56, 0x50, 0xe2, 0xf4,
287 0xc1, 0xa9, 0x76, 0x99, 0xe7, 0xd0, 0xc6, 0x83,
288 0x11, 0x77, 0x70, 0xa6, 0x46, 0x38, 0x1d, 0x74,
289 0x6b, 0xdf, 0x30, 0xcf, 0xd1, 0x29, 0x7f, 0x4b,
290 0xe8, 0x1f, 0xc4, 0xa1, 0x75, 0xae, 0x3f, 0xf1,
291 0xad, 0x42, 0x2d, 0xfe, 0x62, 0x61, 0x6d, 0x3d,
292 0xa7, 0x0a, 0x6e, 0xde, 0x16, 0x36, 0xd2, 0xcb,
293 0x5c, 0xc2, 0x7c, 0xd6, 0x37, 0xa0, 0x20, 0xb5,
294 0xf3, 0xac, 0x71, 0x64, 0x26, 0x66, 0x88, 0x23,
295 0x52, 0xdb, 0x2e, 0x10, 0x84, 0x0e, 0x6f, 0x89,
296 0xb3, 0x86, 0xe5, 0xe6, 0x25, 0x78, 0xd4, 0x2a,
297 0xa8, 0x5b, 0xc9, 0x44, 0x24, 0x17, 0x1a, 0xf0,
298 0x69, 0x7e, 0xbf, 0x8d, 0x5a, 0x82, 0x9e, 0xf9,
299 0xc7, 0xf7, 0x4c, 0x92, 0x9d, 0x34, 0x02, 0x45,
300 0x59, 0xe1, 0x48, 0x7d, 0xb9, 0x94, 0x41, 0x47,
301 0x54, 0x00, 0x3c, 0x65, 0xf8, 0xb8, 0xcd, 0x0d,
302 0xe9, 0x9f, 0x8f, 0x79, 0x3a, 0xda, 0x4a, 0x97,
303 0xef, 0xa2, 0x21, 0x58, 0x67, 0x32, 0xb0, 0x3b,
304 0xe0, 0x85, 0x19, 0x12, 0x2c, 0xbc, 0x4d, 0xe3,
305 0x2b, 0x03, 0xbe, 0xfb, 0xbd, 0x57, 0xeb, 0x06,
306 0xfa, 0xbb, 0xdd, 0xa5, 0xa3, 0x73, 0x18, 0xd9
307 };
308
309 for (std::size_t i = 0; i != sizeof array / sizeof *array; ++i) {
310 if (!rw_assert (array [i] == result [i], 0, line,
311 "randomly shuffled sequence failed to match "
312 "the expected result (data portability failure) "
313 "%d != %d at %zu",
314 array [i], result [i], i + 1))
315 break;
316 }
317
318#else
319 rw_note (0, 0, 0,
320 "_RWSTD_NO_EXT_PORTABLE_RANDOM_SEQUENCE is defined, "
321 "no random_test available");
322#endif // _RWSTD_NO_EXT_PORTABLE_RANDOM_SEQUENCE
323}
324
325
327/* extern */ int rw_opt_nloops = 1024; // --nloops=#
328/* extern */ int rw_opt_no_random; // --no-random
329/* extern */ int rw_opt_no_random_generator; // --no-random_generator
330/* extern */ int rw_opt_no_rand_test; // --no-rand_test
331
332
333static int run_test (int, char*[])
334{
335 const std::size_t N = std::size_t (rw_opt_nloops);
336
338 typedef RandomGenerator<DiffT> RandGenT;
339
340 if (rw_opt_no_random) {
341 rw_note (0, __FILE__, __LINE__, "std::random test disabled");
342 }
343 else {
344 rw_info (0, 0, 0,
345 "template <class %s> "
346 "std::random_shuffle (%1$s, %1$s)",
347 "RandomAccessIterator");
348
350 (RandGenT*)0, (UserClass*)0, false);
351 }
352
354 rw_note (0, __FILE__, __LINE__, "random algorithm test disabled");
355 }
356 else {
357 test_random_shuffle (__LINE__);
358 }
359
361 rw_note (0, __FILE__, __LINE__,
362 "std::random with random_generator test disabled");
363 }
364 else {
365 rw_info (0, 0, 0,
366 "template <class %s, class %s> "
367 "std::random_shuffle (%1$s, %1$s, %2$s)",
368 "RandomAccessIterator", "RandomNumberGenerator");
369
371 (RandGenT*)0, (UserClass*)0, true);
372 }
373
374 return 0;
375}
376
377
379int main (int argc, char *argv[])
380{
381 return rw_test (argc, argv, __FILE__,
382 "lib.alg.random_shuffle",
383 0 /* no comment */, run_test,
384 "|-nloops#0 " // must be non-negative
385 "|-no-random# "
386 "|-no-random_generator# "
387 "|-no-rand_test",
392}
#define N
Definition 17.names.cpp:157
#define i
Definition 17.names.cpp:126
#define T
Definition 17.names.cpp:163
#define line
Definition 17.names.cpp:490
#define last
Definition 17.names.cpp:487
#define array
Definition 17.names.cpp:447
#define buf
Definition 17.names.cpp:452
#define j
Definition 17.names.cpp:127
#define n
Definition 17.names.cpp:130
#define inx
Definition 17.names.cpp:484
#define val
Definition 17.names.cpp:570
volatile int result
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
int rw_opt_no_random_generator
void operator+(Convertible< DifferenceType >, T)
int sequence_generator()
int sequence_start
void test_random_shuffle(const int line, const std::size_t N, const Iterator &it, const RandomNumberGenerator *, const T *, bool rnd_gen)
int rw_opt_no_rand_test
int rw_opt_no_random
int rw_opt_nloops
const char * type_name()
#define main
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
A TOML array.
Definition array.hpp:258
Definition json.h:5363
T * make_iter(T *cur, const T *, const T *, T *)
_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_assert(int, const char *, int, const char *,...)
Definition driver.cpp:1630
Convertible(DifferenceType val)
static std::size_t ncalls_