Ne.app NeANT
The Ne.app NeANT User module of the NeANT distribution.
25.sort.cpp
Go to the documentation of this file.
1
29#include <algorithm> // for sort, stable_sort
30#include <cstring> // for strlen, size_t
31#include <cstddef> // for ptrdiff_t
32
33#include <rw_alg_test.h>
34#include <rw_value.h> // for UserClass
35#include <rw_driver.h> // for rw_test()
36
37
40
41// disable explicit instantiation for compilers (like MSVC)
42// that can't handle it
43#ifndef _RWSTD_NO_EXPLICIT_INSTANTIATION
44
45template
46void
49
50template
51void
55
56template
57void
60
61template
62void
66
67#endif // _RWSTD_NO_EXPLICIT_INSTANTIATION
68
69} // namespace std
70
71
73template <class T>
74struct Less
75{
76 static std::size_t funcalls_;
77
78 // dummy arguments provided to prevent the class from being
79 // default constructible and implicit conversion from int
80 Less (int /* dummy */, int /* dummy */) {
81 funcalls_ = 0;
82 }
83
84 // return a type other than bool but one that is implicitly
85 // convertible to bool to detect incorrect assumptions
86 conv_to_bool operator() (const T &x, const T &y) /* non-const */ {
87 ++funcalls_;
88 return conv_to_bool::make (x.data_.val_ < y.data_.val_);
89 }
90
91 static const char* name () { return "Less"; }
92
93private:
94 void operator= (Less&); // not assignable
95};
96
97template<class T> std::size_t Less<T>::funcalls_;
98
99
101template <class T, class Predicate>
102void test_sort (int line,
103 const char *src,
104 const std::size_t N,
105 const T*,
106 const Predicate *ppred,
107 bool stable,
108 bool alloc)
109{
110 typedef RandomAccessIter<T> RandIter;
111 const RandIter it(0, 0, 0);
112
113 const char* const itname = "RandomAccessIterator";
114 const char* const fname = stable ? "stable_sort" : "sort";
115 const char* const funname = ppred ? Predicate::name() : "operator<()";
116
117 // generate random values for each default constructed T
118 T::gen_ = gen_rnd;
119
120 const std::size_t nsrc = src ? std::strlen (src) : N;
121
122 T* const xsrc = src ? T::from_char (src, nsrc) : new T[nsrc];
123
124 T* const xsrc_end = xsrc + nsrc;
125
126 RandIter first = make_iter (xsrc, xsrc, xsrc_end, it);
127 RandIter last = make_iter (xsrc_end, xsrc, xsrc_end, it);
128
129 const Predicate pred(0, 0);
130
131 std::size_t last_n_op_lt = T::n_total_op_lt_;
132 std::size_t last_n_op_cpy = T::n_total_op_assign_ + T::n_total_copy_ctor_;
133
134 _RWSTD_UNUSED (last_n_op_cpy);
135
136 if (stable) {
137 std::pair<UserClass*, std::ptrdiff_t> dummy;
138 if (alloc) {
139 dummy = std::_GET_TEMP_BUFFER (T, nsrc + 1);
140 rw_assert (0 != dummy.first, 0, 0,
141 "line %d: %s<%s%{?}, %s%{;}> (): "
142 "memory allocation failed for %zu elements",
143 __LINE__, fname, itname, ppred, funname, nsrc);
144 }
145
146 if (ppred)
147 std::stable_sort (first, last, pred);
148 else
149 std::stable_sort (first, last);
150
151 if (alloc && dummy.first)
152 std::return_temporary_buffer (dummy.first);
153 }
154 else {
155 if (ppred)
156 std::sort (first, last, pred);
157 else
158 std::sort (first, last);
159 }
160
161 // some tracing goes here
162 /*
163 if (! stable) {
164 // number of comparison operations
165 std::size_t ops = std::size_t (T::n_total_op_lt_ - last_n_op_lt);
166 // number of copy ctor and assignmen operator calls
167 std::size_t cpy =
168 std::size_t (T::n_total_op_assign_ + T::n_total_copy_ctor_)
169 - std::size_t (last_n_op_cpy);
170
171 // expected complexity (number opf comparisons)
172 std::size_t cmplx = (nsrc + 1) * ilog2 (nsrc + 2);
173 double x = double (ops) / cmplx;
174
175 // max and min T
176 static double x_max = 0.0;
177 static double x_min = 1.0;
178
179 if (x > x_max)
180 x_max = x;
181
182 if (nsrc > 16 && x < x_min)
183 x_min = x;
184
185 // complexity: UserClass * N * log (N),
186 // ideally with UserClass approaching 1
187
188 if (!(nsrc % 20)) {
189 rw_info (0, 0, 0,
190 "\n+------+------+------+------+------+------+------+\n"
191 "| N | COMP | COPY |N lg N| X | max X| min X|\n"
192 "+======+======+======+======+======+======+======+\n");
193
194 // # | comp | assign | exp. complexity | X | max X | min X
195 rw_info (0, 0, 0, "\n|%6d|%6d|%6d|%6d|%6.2f|%6.2f|%6.2f|\n",
196 nsrc + 1, ops, cpy, cmplx, x, x_max, x_min);
197 }
198 }
199 */
200
201 static const int cwidth = sizeof (T);
202
203 // check that the array is sorted
204 bool success = is_sorted_lt (xsrc, xsrc_end);
205 if (src) {
206 rw_assert (success, 0, line,
207 "line %d: %s<%s%{?}, %s%{;}> (\"%s\", ...) ==> "
208 "\"%{X=*.*}\" not sorted",
209 __LINE__, fname, itname, ppred, funname, src,
210 cwidth, int (nsrc), -1, xsrc);
211 }
212 else {
213 rw_assert (success, 0, line,
214 "line %d: %s<%s%{?}, %s%{;}> (%zu, ...): "
215 "not sorted",
216 __LINE__, fname, itname, ppred, funname, nsrc);
217 }
218
219 // verify 25.3.1.1, p2 and 25.3.1.2, p3
220 // the complexity of our implementation is no worse than
221 // 3.33 * N * log (N) (hence the magic 7 and 2)
222 const std::size_t n_ops =
223 ppred ? Predicate::funcalls_ : T::n_total_op_lt_ - last_n_op_lt;
224
225 const std::size_t exp_ops = 7 * nsrc * ::ilog2 (nsrc);
226 success = 2 * n_ops <= exp_ops;
227 rw_assert (success, 0, line,
228 "line %d: %s<%s%{?}, %s%{;}> (): complexity for "
229 "length %zu is %zu, expected no more than %zu",
230 __LINE__, fname, itname, ppred, funname, nsrc,
231 n_ops, exp_ops / 2);
232
233 // verify 25.3.1.2 p2
234 if (stable) {
235 std::size_t j = 1;
236 for ( ; j < N; j++) {
237 if (xsrc[j - 1].data_.val_ == xsrc[j].data_.val_)
238 success = xsrc[j - 1].origin_ < xsrc[j].origin_;
239
240 if (!success)
241 break;
242 }
243
244 // to avoid errors in --trace mode
245 j = j < nsrc ? j : nsrc - 1;
246
247 if (src) {
248 rw_assert (success, 0, line,
249 "line %d: %s<%s%{?}, %s%{;}> (\"%s\", ...) ==> "
250 "\"%{X=*.*}\" relative order is broken at %zu: "
251 "got ids %zu and %zu for values %#c and %#c",
252 __LINE__, fname, itname, ppred, funname, src,
253 cwidth, int (nsrc), -1, xsrc, j, xsrc[j - 1].origin_,
254 xsrc[j].origin_, xsrc[j - 1].data_.val_,
255 xsrc[j].data_.val_);
256 }
257 else {
258 rw_assert (success, 0, line,
259 "line %d: %s<%s%{?}, %s%{;}> (): relative order "
260 "is broken for %zu at %zu: got ids %zu and %zu "
261 "for values %d and %d",
262 __LINE__, fname, itname, ppred, funname,
263 nsrc, j, xsrc[j - 1].origin_, xsrc[j].origin_,
264 xsrc[j - 1].data_.val_, xsrc[j].data_.val_);
265 }
266 }
267
268 delete[] xsrc;
269}
270
271
273/* extern */ int rw_opt_nloops = 256; // --nloops=#
274/* extern */ int rw_opt_no_sort; // --no-sort
275/* extern */ int rw_opt_no_stable_sort; // --no-stable_sort
276/* extern */ int rw_opt_no_predicate; // --no-predicate
277/* extern */ int rw_opt_no_complexity; // --no-complexity
278
279
281template <class T, class Predicate>
282void test_sort (const std::size_t N,
283 const T*,
284 const Predicate *ppred,
285 bool stable,
286 bool alloc)
287{
288 rw_info (0, 0, 0,
289 "template <class %s%{?}, class %s%{;}> "
290 "void std::%{?}stable_%{;}sort (%1$s, %1$s%{?}, %3$s%{;})"
291 "%{?} with memory allocation%{;}",
292 "RandomAccessIterator", ppred, "StrictWeakComp",
293 stable, ppred, stable && alloc);
294
295 const char* const itname = "RandomAccessIterator";
296 const char* const fname = stable ? "stable_sort" : "sort";
297 const char* const funname = ppred ? Predicate::name() : "operator<()";
298
299 rw_info (0, 0, 0,
300 "std::%s (%s, %2$s%{?}, %s%{;})",
301 fname, itname, ppred, funname);
302
303#define TEST(src) \
304 test_sort (__LINE__, src, 0, (T*)0, ppred, stable, alloc)
305
306 TEST ("a");
307
308 TEST ("ba");
309 TEST ("cba");
310 TEST ("dcba");
311 TEST ("edcba");
312 TEST ("fedcba");
313 TEST ("gfedcba");
314 TEST ("hgfedcba");
315 TEST ("ihgfedcba");
316 TEST ("jihgfedcba");
317
318 TEST ("ab");
319 TEST ("abc");
320 TEST ("abcd");
321 TEST ("abcde");
322 TEST ("abcdef");
323 TEST ("abcdefg");
324 TEST ("abcdefgh");
325 TEST ("abcdefghi");
326 TEST ("abcdefghij");
327
328 TEST ("aa");
329 TEST ("aabb");
330 TEST ("bbccaa");
331 TEST ("ddbbccaa");
332 TEST ("ddeebbccaa");
333
334 TEST ("aaaaaaaaaa");
335 TEST ("ababababab");
336 TEST ("bababababa");
337
338#undef TEST
339
341 rw_note (0, 0, 0,
342 "std::%s (%s, %2$s%{?}, %s%{;}) complexity test disabled",
343 fname, itname, ppred, funname);
344 }
345 else {
346 rw_info (0, 0, 0,
347 "std::%s (%s, %2$s%{?}, %s%{;}): complexity test",
348 fname, itname, ppred, funname);
349
350 for (std::size_t i = 1; i < N; i++)
351 test_sort (__LINE__, 0, i, (T*)0, ppred, stable, alloc);
352 }
353}
354
355
357template <class T>
358void test_sort (const std::size_t N,
359 const T*,
360 bool stable,
361 bool alloc)
362{
363 test_sort (N, (T*)0, (Less<T>*)0, stable, alloc);
364
366 rw_note (0, __FILE__, __LINE__,
367 "std::%{?}stable_%{;}sort predicate test disabled",
368 stable);
369 }
370 else {
371 const Less<T> pred(0, 0);
372 test_sort (N, (T*)0, &pred, stable, alloc);
373 }
374}
375
376
379static int run_test (int, char*[])
380{
381 const std::size_t N = std::size_t (rw_opt_nloops);
382
383 if (rw_opt_no_sort) {
384 rw_note (0, __FILE__, __LINE__, "std::sort test disabled");
385 }
386 else {
387 test_sort (N, (UserClass*)0, false, false);
388 }
389
391 rw_note (0, __FILE__, __LINE__, "std::stable_sort test disabled");
392 }
393 else {
394 test_sort (N, (UserClass*)0, true, false);
395 // test with memory reallocation
396 test_sort (N, (UserClass*)0, true, true);
397 }
398
399 return 0;
400}
401
402
403
405int main (int argc, char *argv[])
406{
407 return rw_test (argc, argv, __FILE__,
408 "lib.sort",
409 0 /* no comment */,
410 run_test,
411 "|-nloops#0 " // must be non-negative
412 "|-no-sort# "
413 "|-no-stable_sort# "
414 "|-no-predicate",
420}
#define N
Definition 17.names.cpp:157
#define i
Definition 17.names.cpp:126
#define T
Definition 17.names.cpp:163
#define y
Definition 17.names.cpp:141
#define alloc
Definition 17.names.cpp:441
#define line
Definition 17.names.cpp:490
#define last
Definition 17.names.cpp:487
#define x
Definition 17.names.cpp:140
#define j
Definition 17.names.cpp:127
const MyBuffer< char > nsrc[]
void run_test(const ForwardIterator &dummy, T *, Predicate *pred)
int rw_opt_no_predicate
Definition 25.sort.cpp:276
int rw_opt_no_complexity
Definition 25.sort.cpp:277
#define TEST(src)
int rw_opt_no_sort
Definition 25.sort.cpp:274
int rw_opt_no_stable_sort
Definition 25.sort.cpp:275
void test_sort(int line, const char *src, const std::size_t N, const T *, const Predicate *ppred, bool stable, bool alloc)
Definition 25.sort.cpp:102
int rw_opt_nloops
Definition 25.sort.cpp:273
#define main
#define _RWSTD_UNUSED(arg)
Definition _defs.h:972
#define _RWSTD_NAMESPACE(name)
Definition _defs.h:567
Definition json.h:5363
T * make_iter(T *cur, const T *, const T *, T *)
_TEST_EXPORT unsigned ilog2(_RWSTD_SIZE_T)
bool is_sorted_lt(InputIterator first, InputIterator last)
Definition rw_alg_test.h:75
_TEST_EXPORT int gen_rnd()
Definition alg_test.cpp:66
_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
static const char * name()
Definition 25.sort.cpp:91
Less(int, int)
Definition 25.sort.cpp:80
static conv_to_bool make(bool val)