1 /*=============================================================================
2     Copyright (c) 2010 Tim Blechmann
3 
4     Use, modification and distribution is subject to the Boost Software
5     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
6     http://www.boost.org/LICENSE_1_0.txt)
7 =============================================================================*/
8 
9 #ifndef COMMON_HEAP_TESTS_HPP_INCLUDED
10 #define COMMON_HEAP_TESTS_HPP_INCLUDED
11 
12 #include <algorithm>
13 #include <vector>
14 
15 #include <boost/concept/assert.hpp>
16 #include <boost/concept_archetype.hpp>
17 #include <boost/shared_ptr.hpp>
18 
19 #include <boost/heap/heap_concepts.hpp>
20 
21 
22 typedef boost::default_constructible_archetype<
23         boost::less_than_comparable_archetype<
24         boost::copy_constructible_archetype<
25         boost::assignable_archetype<
26         > > > > test_value_type;
27 
28 
29 typedef std::vector<int> test_data;
30 const int test_size = 32;
31 
32 struct dummy_run
33 {
rundummy_run34     static void run(void)
35     {}
36 };
37 
38 
make_test_data(int size,int offset=0,int strive=1)39 test_data make_test_data(int size, int offset = 0, int strive = 1)
40 {
41     test_data ret;
42 
43     for (int i = 0; i != size; ++i)
44         ret.push_back(i * strive + offset);
45     return ret;
46 }
47 
48 
49 template <typename pri_queue, typename data_container>
check_q(pri_queue & q,data_container const & expected)50 void check_q(pri_queue & q, data_container const & expected)
51 {
52     BOOST_REQUIRE_EQUAL(q.size(), expected.size());
53 
54     for (unsigned int i = 0; i != expected.size(); ++i)
55     {
56         BOOST_REQUIRE_EQUAL(q.size(), expected.size() - i);
57         BOOST_REQUIRE_EQUAL(q.top(), expected[expected.size()-1-i]);
58         q.pop();
59     }
60 
61     BOOST_REQUIRE(q.empty());
62 }
63 
64 
65 template <typename pri_queue, typename data_container>
fill_q(pri_queue & q,data_container const & data)66 void fill_q(pri_queue & q, data_container const & data)
67 {
68     for (unsigned int i = 0; i != data.size(); ++i)
69         q.push(data[i]);
70 }
71 
72 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
73 template <typename pri_queue, typename data_container>
fill_emplace_q(pri_queue & q,data_container const & data)74 void fill_emplace_q(pri_queue & q, data_container const & data)
75 {
76     for (unsigned int i = 0; i != data.size(); ++i) {
77         typename pri_queue::value_type value = data[i];
78         q.emplace(std::move(value));
79     }
80 }
81 #endif
82 
83 template <typename pri_queue>
pri_queue_test_sequential_push(void)84 void pri_queue_test_sequential_push(void)
85 {
86     for (int i = 0; i != test_size; ++i)
87     {
88         pri_queue q;
89         test_data data = make_test_data(i);
90         fill_q(q, data);
91         check_q(q, data);
92     }
93 }
94 
95 template <typename pri_queue>
pri_queue_test_sequential_reverse_push(void)96 void pri_queue_test_sequential_reverse_push(void)
97 {
98     for (int i = 0; i != test_size; ++i)
99     {
100         pri_queue q;
101         test_data data = make_test_data(i);
102         std::reverse(data.begin(), data.end());
103         fill_q(q, data);
104         std::reverse(data.begin(), data.end());
105         check_q(q, data);
106     }
107 }
108 
109 template <typename pri_queue>
pri_queue_test_emplace(void)110 void pri_queue_test_emplace(void)
111 {
112 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
113     for (int i = 0; i != test_size; ++i)
114     {
115         pri_queue q;
116         test_data data = make_test_data(i);
117         std::reverse(data.begin(), data.end());
118         fill_emplace_q(q, data);
119         std::reverse(data.begin(), data.end());
120         check_q(q, data);
121     }
122 #endif
123 }
124 
125 
126 template <typename pri_queue>
pri_queue_test_random_push(void)127 void pri_queue_test_random_push(void)
128 {
129     for (int i = 0; i != test_size; ++i)
130     {
131         pri_queue q;
132         test_data data = make_test_data(i);
133 
134         test_data shuffled (data);
135         std::random_shuffle(shuffled.begin(), shuffled.end());
136 
137         fill_q(q, shuffled);
138 
139         check_q(q, data);
140     }
141 }
142 
143 template <typename pri_queue>
pri_queue_test_copyconstructor(void)144 void pri_queue_test_copyconstructor(void)
145 {
146     for (int i = 0; i != test_size; ++i)
147     {
148         pri_queue q;
149         test_data data = make_test_data(i);
150         fill_q(q, data);
151 
152         pri_queue r(q);
153 
154         check_q(r, data);
155     }
156 }
157 
158 template <typename pri_queue>
pri_queue_test_assignment(void)159 void pri_queue_test_assignment(void)
160 {
161     for (int i = 0; i != test_size; ++i)
162     {
163         pri_queue q;
164         test_data data = make_test_data(i);
165         fill_q(q, data);
166 
167         pri_queue r;
168         r = q;
169 
170         check_q(r, data);
171     }
172 }
173 
174 template <typename pri_queue>
pri_queue_test_moveconstructor(void)175 void pri_queue_test_moveconstructor(void)
176 {
177 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
178     pri_queue q;
179     test_data data = make_test_data(test_size);
180     fill_q(q, data);
181 
182     pri_queue r(std::move(q));
183 
184     check_q(r, data);
185     BOOST_REQUIRE(q.empty());
186 #endif
187 }
188 
189 template <typename pri_queue>
pri_queue_test_move_assignment(void)190 void pri_queue_test_move_assignment(void)
191 {
192 #ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
193     pri_queue q;
194     test_data data = make_test_data(test_size);
195     fill_q(q, data);
196 
197     pri_queue r;
198     r = std::move(q);
199 
200     check_q(r, data);
201     BOOST_REQUIRE(q.empty());
202 #endif
203 }
204 
205 
206 template <typename pri_queue>
pri_queue_test_swap(void)207 void pri_queue_test_swap(void)
208 {
209     for (int i = 0; i != test_size; ++i)
210     {
211         pri_queue q;
212         test_data data = make_test_data(i);
213         test_data shuffled (data);
214         std::random_shuffle(shuffled.begin(), shuffled.end());
215         fill_q(q, shuffled);
216 
217         pri_queue r;
218 
219         q.swap(r);
220         check_q(r, data);
221         BOOST_REQUIRE(q.empty());
222     }
223 }
224 
225 
226 template <typename pri_queue>
pri_queue_test_iterators(void)227 void pri_queue_test_iterators(void)
228 {
229     for (int i = 0; i != test_size; ++i) {
230         test_data data = make_test_data(test_size);
231         test_data shuffled (data);
232         std::random_shuffle(shuffled.begin(), shuffled.end());
233         pri_queue q;
234         BOOST_REQUIRE(q.begin() == q.end());
235         fill_q(q, shuffled);
236 
237         for (unsigned long j = 0; j != data.size(); ++j)
238             BOOST_REQUIRE(std::find(q.begin(), q.end(), data[j]) != q.end());
239 
240         for (unsigned long j = 0; j != data.size(); ++j)
241             BOOST_REQUIRE(std::find(q.begin(), q.end(), data[j] + data.size()) == q.end());
242 
243         test_data data_from_queue(q.begin(), q.end());
244         std::sort(data_from_queue.begin(), data_from_queue.end());
245 
246         BOOST_REQUIRE(data == data_from_queue);
247 
248         for (unsigned long j = 0; j != data.size(); ++j) {
249             BOOST_REQUIRE_EQUAL((long)std::distance(q.begin(), q.end()), (long)(data.size() - j));
250             q.pop();
251         }
252     }
253 }
254 
255 template <typename pri_queue>
pri_queue_test_ordered_iterators(void)256 void pri_queue_test_ordered_iterators(void)
257 {
258     for (int i = 0; i != test_size; ++i) {
259         test_data data = make_test_data(i);
260         test_data shuffled (data);
261         std::random_shuffle(shuffled.begin(), shuffled.end());
262         pri_queue q;
263         BOOST_REQUIRE(q.ordered_begin() == q.ordered_end());
264         fill_q(q, shuffled);
265 
266         test_data data_from_queue(q.ordered_begin(), q.ordered_end());
267         std::reverse(data_from_queue.begin(), data_from_queue.end());
268         BOOST_REQUIRE(data == data_from_queue);
269 
270         for (unsigned long j = 0; j != data.size(); ++j)
271             BOOST_REQUIRE(std::find(q.ordered_begin(), q.ordered_end(), data[j]) != q.ordered_end());
272 
273         for (unsigned long j = 0; j != data.size(); ++j)
274             BOOST_REQUIRE(std::find(q.ordered_begin(), q.ordered_end(), data[j] + data.size()) == q.ordered_end());
275 
276         for (unsigned long j = 0; j != data.size(); ++j) {
277             BOOST_REQUIRE_EQUAL((long)std::distance(q.begin(), q.end()), (long)(data.size() - j));
278             q.pop();
279         }
280     }
281 }
282 
283 
284 template <typename pri_queue>
pri_queue_test_equality(void)285 void pri_queue_test_equality(void)
286 {
287     for (int i = 0; i != test_size; ++i)
288     {
289         pri_queue q, r;
290         test_data data = make_test_data(i);
291         fill_q(q, data);
292         std::reverse(data.begin(), data.end());
293         fill_q(r, data);
294 
295         BOOST_REQUIRE(r == q);
296     }
297 }
298 
299 template <typename pri_queue>
pri_queue_test_inequality(void)300 void pri_queue_test_inequality(void)
301 {
302     for (int i = 1; i != test_size; ++i)
303     {
304         pri_queue q, r;
305         test_data data = make_test_data(i);
306         fill_q(q, data);
307         data[0] = data.back() + 1;
308         fill_q(r, data);
309 
310         BOOST_REQUIRE(r != q);
311     }
312 }
313 
314 template <typename pri_queue>
pri_queue_test_less(void)315 void pri_queue_test_less(void)
316 {
317     for (int i = 1; i != test_size; ++i)
318     {
319         pri_queue q, r;
320         test_data data = make_test_data(i);
321         test_data r_data(data);
322         r_data.pop_back();
323 
324         fill_q(q, data);
325         fill_q(r, r_data);
326 
327         BOOST_REQUIRE(r < q);
328     }
329 
330     for (int i = 1; i != test_size; ++i)
331     {
332         pri_queue q, r;
333         test_data data = make_test_data(i);
334         test_data r_data(data);
335         data.push_back(data.back() + 1);
336 
337         fill_q(q, data);
338         fill_q(r, r_data);
339 
340         BOOST_REQUIRE(r < q);
341     }
342 
343     for (int i = 1; i != test_size; ++i)
344     {
345         pri_queue q, r;
346         test_data data = make_test_data(i);
347         test_data r_data(data);
348 
349         data.back() += 1;
350 
351         fill_q(q, data);
352         fill_q(r, r_data);
353 
354         BOOST_REQUIRE(r < q);
355     }
356 
357     for (int i = 1; i != test_size; ++i)
358     {
359         pri_queue q, r;
360         test_data data = make_test_data(i);
361         test_data r_data(data);
362 
363         r_data.front() -= 1;
364 
365         fill_q(q, data);
366         fill_q(r, r_data);
367 
368         BOOST_REQUIRE(r < q);
369     }
370 
371 }
372 
373 template <typename pri_queue>
pri_queue_test_clear(void)374 void pri_queue_test_clear(void)
375 {
376     for (int i = 0; i != test_size; ++i)
377     {
378         pri_queue q;
379         test_data data = make_test_data(i);
380         fill_q(q, data);
381 
382         q.clear();
383         BOOST_REQUIRE(q.size() == 0);
384         BOOST_REQUIRE(q.empty());
385     }
386 }
387 
388 
389 template <typename pri_queue>
run_concept_check(void)390 void run_concept_check(void)
391 {
392     BOOST_CONCEPT_ASSERT((boost::heap::PriorityQueue<pri_queue>));
393 }
394 
395 template <typename pri_queue>
run_common_heap_tests(void)396 void run_common_heap_tests(void)
397 {
398     pri_queue_test_sequential_push<pri_queue>();
399     pri_queue_test_sequential_reverse_push<pri_queue>();
400     pri_queue_test_random_push<pri_queue>();
401     pri_queue_test_equality<pri_queue>();
402     pri_queue_test_inequality<pri_queue>();
403     pri_queue_test_less<pri_queue>();
404     pri_queue_test_clear<pri_queue>();
405 
406     pri_queue_test_emplace<pri_queue>();
407 }
408 
409 template <typename pri_queue>
run_iterator_heap_tests(void)410 void run_iterator_heap_tests(void)
411 {
412     pri_queue_test_iterators<pri_queue>();
413 }
414 
415 
416 template <typename pri_queue>
run_copyable_heap_tests(void)417 void run_copyable_heap_tests(void)
418 {
419     pri_queue_test_copyconstructor <pri_queue>();
420     pri_queue_test_assignment<pri_queue>();
421     pri_queue_test_swap<pri_queue>();
422 }
423 
424 
425 template <typename pri_queue>
run_moveable_heap_tests(void)426 void run_moveable_heap_tests(void)
427 {
428     pri_queue_test_moveconstructor <pri_queue>();
429     pri_queue_test_move_assignment <pri_queue>();
430 }
431 
432 
433 template <typename pri_queue>
run_reserve_heap_tests(void)434 void run_reserve_heap_tests(void)
435 {
436     test_data data = make_test_data(test_size);
437     pri_queue q;
438     q.reserve(6);
439     fill_q(q, data);
440 
441     check_q(q, data);
442 }
443 
444 template <typename pri_queue>
run_leak_check_test(void)445 void run_leak_check_test(void)
446 {
447     pri_queue q;
448     q.push(boost::shared_ptr<int>(new int(0)));
449 }
450 
451 
452 struct less_with_T
453 {
454     typedef int T;
operator ()less_with_T455     bool operator()(const int& a, const int& b) const
456     {
457         return a < b;
458     }
459 };
460 
461 
462 #if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) && !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES)
463 
464 class thing {
465 public:
thing(int a_,int b_,int c_)466 	thing( int a_, int b_, int c_ ) : a(a_), b(b_), c(c_) {}
467 public:
468 	int a;
469 	int b;
470 	int c;
471 };
472 
473 class cmpthings {
474 public:
operator ()(const thing & lhs,const thing & rhs) const475 	bool operator() ( const thing& lhs, const thing& rhs ) const  {
476 		return lhs.a > rhs.a;
477 	}
operator ()(const thing & lhs,const thing & rhs)478 	bool operator() ( const thing& lhs, const thing& rhs ) {
479 		return lhs.a > rhs.a;
480 	}
481 };
482 
483 #define RUN_EMPLACE_TEST(HEAP_TYPE)                                     \
484     do {                                                                \
485         cmpthings ord;                                                  \
486         boost::heap::HEAP_TYPE<thing, boost::heap::compare<cmpthings> > vpq(ord); \
487         vpq.emplace(5, 6, 7);                                           \
488         boost::heap::HEAP_TYPE<thing, boost::heap::compare<cmpthings>, boost::heap::stable<true> > vpq2(ord); \
489         vpq2.emplace(5, 6, 7);                                          \
490     } while(0);
491 
492 #else
493 #define RUN_EMPLACE_TEST(HEAP_TYPE)
494 #endif
495 
496 
497 #endif // COMMON_HEAP_TESTS_HPP_INCLUDED
498