mirror of
				https://github.com/saitohirga/WSJT-X.git
				synced 2025-10-30 12:30:23 -04:00 
			
		
		
		
	
		
			
				
	
	
		
			199 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			199 lines
		
	
	
		
			6.2 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| //  Copyright Neil Groves 2009. Use, modification and
 | |
| //  distribution is subject to the Boost Software License, Version
 | |
| //  1.0. (See accompanying file LICENSE_1_0.txt or copy at
 | |
| //  http://www.boost.org/LICENSE_1_0.txt)
 | |
| //
 | |
| //
 | |
| // For more information, see http://www.boost.org/libs/range/
 | |
| //
 | |
| #include <boost/range/algorithm/random_shuffle.hpp>
 | |
| 
 | |
| #include <boost/test/test_tools.hpp>
 | |
| #include <boost/test/unit_test.hpp>
 | |
| 
 | |
| #include <boost/assign.hpp>
 | |
| #include <boost/bind.hpp>
 | |
| #include "../test_function/counted_function.hpp"
 | |
| #include <algorithm>
 | |
| #include <functional>
 | |
| #include <list>
 | |
| #include <numeric>
 | |
| #include <deque>
 | |
| #include <vector>
 | |
| 
 | |
| namespace boost
 | |
| {
 | |
|     namespace
 | |
|     {
 | |
|         template<class Int>
 | |
|         class counted_generator
 | |
|             : private range_test_function::counted_function
 | |
|         {
 | |
|         public:
 | |
|             typedef Int result_type;
 | |
|             typedef Int argument_type;
 | |
| 
 | |
|             using range_test_function::counted_function::invocation_count;
 | |
| 
 | |
|             result_type operator()(argument_type modulo_value)
 | |
|             {
 | |
|                 invoked();
 | |
|                 return static_cast<result_type>(std::rand() % modulo_value);
 | |
|             }
 | |
|         };
 | |
| 
 | |
|         template<class Container>
 | |
|         bool test_shuffle_result(
 | |
|             const Container& old_cont,
 | |
|             const Container& new_cont
 | |
|             )
 | |
|         {
 | |
|             typedef BOOST_DEDUCED_TYPENAME range_iterator<const Container>::type iterator_t;
 | |
| 
 | |
|             // The size must remain equal
 | |
|             BOOST_CHECK_EQUAL( old_cont.size(), new_cont.size() );
 | |
|             if (old_cont.size() != new_cont.size())
 | |
|                 return false;
 | |
| 
 | |
|             if (new_cont.size() < 2)
 | |
|             {
 | |
|                 BOOST_CHECK_EQUAL_COLLECTIONS(
 | |
|                     old_cont.begin(), old_cont.end(),
 | |
|                     new_cont.begin(), new_cont.end()
 | |
|                     );
 | |
| 
 | |
|                 return std::equal(old_cont.begin(), old_cont.end(),
 | |
|                                   new_cont.begin());
 | |
|             }
 | |
| 
 | |
|             // Elements must only be moved around. This is tested by
 | |
|             // ensuring the count of each element remains the
 | |
|             // same.
 | |
|             bool failed = false;
 | |
|             iterator_t last = old_cont.end();
 | |
|             for (iterator_t it = old_cont.begin(); !failed && (it != last); ++it)
 | |
|             {
 | |
|                 const std::size_t old_count
 | |
|                     = std::count(old_cont.begin(), old_cont.end(), *it);
 | |
| 
 | |
|                 const std::size_t new_count
 | |
|                     = std::count(new_cont.begin(), new_cont.end(), *it);
 | |
| 
 | |
|                 BOOST_CHECK_EQUAL( old_count, new_count );
 | |
| 
 | |
|                 failed = (old_count != new_count);
 | |
|             }
 | |
| 
 | |
|             return !failed;
 | |
|         }
 | |
| 
 | |
|         template<class Container>
 | |
|         void test_random_shuffle_nogen_impl(Container& cont)
 | |
|         {
 | |
|             typedef BOOST_DEDUCED_TYPENAME range_iterator<Container>::type
 | |
|                                                 iterator_t BOOST_RANGE_UNUSED;
 | |
| 
 | |
|             const int MAX_RETRIES = 10000;
 | |
| 
 | |
|             bool shuffled = false;
 | |
|             for (int attempt = 0; !shuffled && (attempt < MAX_RETRIES); ++attempt)
 | |
|             {
 | |
|                 Container test(cont);
 | |
|                 boost::random_shuffle(test);
 | |
|                 bool ok = test_shuffle_result(cont, test);
 | |
|                 if (!ok)
 | |
|                     break;
 | |
| 
 | |
|                 // Since the counts are equal, then if they are 
 | |
|                 // not equal the contents must have been shuffled
 | |
|                 if (cont.size() == test.size()
 | |
|                 &&  !std::equal(cont.begin(), cont.end(), test.begin()))
 | |
|                 {
 | |
|                     shuffled = true;
 | |
|                 }
 | |
|                 
 | |
|                 // Verify that the shuffle can be performed on a
 | |
|                 // temporary range
 | |
|                 Container test2(cont);
 | |
|                 boost::random_shuffle(boost::make_iterator_range(test2));
 | |
|                 ok = test_shuffle_result(cont, test2);
 | |
|                 if (!ok)
 | |
|                     break;
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         template<class RandomGenerator, class Container>
 | |
|         void test_random_shuffle_gen_impl(Container& cont)
 | |
|         {
 | |
|             RandomGenerator gen;
 | |
|             Container old_cont(cont);
 | |
|             boost::random_shuffle(cont, gen);
 | |
|             test_shuffle_result(cont, old_cont);
 | |
|             if (cont.size() > 2)
 | |
|             {
 | |
|                 BOOST_CHECK( gen.invocation_count() > 0 );
 | |
|             }
 | |
|             
 | |
|             // Test that random shuffle works when 
 | |
|             // passed a temporary range
 | |
|             RandomGenerator gen2;
 | |
|             Container cont2(old_cont);
 | |
|             boost::random_shuffle(boost::make_iterator_range(cont2), gen2);
 | |
|             test_shuffle_result(cont2, old_cont);
 | |
|             if (cont2.size() > 2)
 | |
|             {
 | |
|                 BOOST_CHECK( gen2.invocation_count() > 0 );
 | |
|             }
 | |
|         }
 | |
| 
 | |
|         template<class Container>
 | |
|         void test_random_shuffle_impl(Container& cont)
 | |
|         {
 | |
|             Container old_cont(cont);
 | |
|             boost::random_shuffle(cont);
 | |
|             test_shuffle_result(cont, old_cont);
 | |
|         }
 | |
| 
 | |
|         template<class Container>
 | |
|         void test_random_shuffle_impl()
 | |
|         {
 | |
|             using namespace boost::assign;
 | |
| 
 | |
|             typedef counted_generator<
 | |
|                 BOOST_DEDUCED_TYPENAME range_difference<Container>::type > generator_t;
 | |
| 
 | |
|             Container cont;
 | |
|             test_random_shuffle_nogen_impl(cont);
 | |
|             test_random_shuffle_gen_impl<generator_t>(cont);
 | |
| 
 | |
|             cont.clear();
 | |
|             cont += 1;
 | |
|             test_random_shuffle_nogen_impl(cont);
 | |
|             test_random_shuffle_gen_impl<generator_t>(cont);
 | |
| 
 | |
|             cont.clear();
 | |
|             cont += 1,2,3,4,5,6,7,8,9;
 | |
|             test_random_shuffle_nogen_impl(cont);
 | |
|             test_random_shuffle_gen_impl<generator_t>(cont);
 | |
|         }
 | |
| 
 | |
|         void test_random_shuffle()
 | |
|         {
 | |
|             test_random_shuffle_impl< std::vector<int> >();
 | |
|             test_random_shuffle_impl< std::deque<int> >();
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| 
 | |
| boost::unit_test::test_suite*
 | |
| init_unit_test_suite(int argc, char* argv[])
 | |
| {
 | |
|     boost::unit_test::test_suite* test
 | |
|         = BOOST_TEST_SUITE( "RangeTestSuite.algorithm.random_shuffle" );
 | |
| 
 | |
|     test->add( BOOST_TEST_CASE( &boost::test_random_shuffle ) );
 | |
| 
 | |
|     return test;
 | |
| }
 |