sl@0: /* boost random/shuffle_output.hpp header file sl@0: * sl@0: * Copyright Jens Maurer 2000-2001 sl@0: * Distributed under the Boost Software License, Version 1.0. (See sl@0: * accompanying file LICENSE_1_0.txt or copy at sl@0: * http://www.boost.org/LICENSE_1_0.txt) sl@0: * sl@0: * See http://www.boost.org for most recent version including documentation. sl@0: * sl@0: * $Id: shuffle_output.hpp,v 1.10 2005/08/25 16:27:22 johnmaddock Exp $ sl@0: * sl@0: * Revision history sl@0: * 2001-02-18 moved to individual header files sl@0: */ sl@0: sl@0: #ifndef BOOST_RANDOM_SHUFFLE_OUTPUT_HPP sl@0: #define BOOST_RANDOM_SHUFFLE_OUTPUT_HPP sl@0: sl@0: #include sl@0: #include // std::copy sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: #include sl@0: sl@0: namespace boost { sl@0: namespace random { sl@0: sl@0: // Carter Bays and S.D. Durham 1979 sl@0: template sl@0: class shuffle_output sl@0: { sl@0: public: sl@0: typedef UniformRandomNumberGenerator base_type; sl@0: typedef typename base_type::result_type result_type; sl@0: sl@0: BOOST_STATIC_CONSTANT(bool, has_fixed_range = false); sl@0: BOOST_STATIC_CONSTANT(int, buffer_size = k); sl@0: sl@0: shuffle_output() : _rng() { init(); } sl@0: #if defined(BOOST_MSVC) && _MSC_VER < 1300 sl@0: // MSVC does not implicitly generate the copy constructor here sl@0: shuffle_output(const shuffle_output & x) sl@0: : _rng(x._rng), y(x.y) { std::copy(x.v, x.v+k, v); } sl@0: #endif sl@0: template sl@0: explicit shuffle_output(T seed) : _rng(seed) { init(); } sl@0: explicit shuffle_output(const base_type & rng) : _rng(rng) { init(); } sl@0: template shuffle_output(It& first, It last) sl@0: : _rng(first, last) { init(); } sl@0: void seed() { _rng.seed(); init(); } sl@0: template sl@0: void seed(T s) { _rng.seed(s); init(); } sl@0: template void seed(It& first, It last) sl@0: { sl@0: _rng.seed(first, last); sl@0: init(); sl@0: } sl@0: sl@0: const base_type& base() const { return _rng; } sl@0: sl@0: result_type operator()() { sl@0: // calculating the range every time may seem wasteful. However, this sl@0: // makes the information locally available for the optimizer. sl@0: result_type range = (max)()-(min)()+1; sl@0: int j = k*(y-(min)())/range; sl@0: // assert(0 <= j && j < k); sl@0: y = v[j]; sl@0: v[j] = _rng(); sl@0: return y; sl@0: } sl@0: sl@0: result_type min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (_rng.min)(); } sl@0: result_type max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return (_rng.max)(); } sl@0: static bool validation(result_type x) { return val == x; } sl@0: sl@0: #ifndef BOOST_NO_OPERATORS_IN_NAMESPACE sl@0: sl@0: #ifndef BOOST_NO_MEMBER_TEMPLATE_FRIENDS sl@0: template sl@0: friend std::basic_ostream& sl@0: operator<<(std::basic_ostream& os, const shuffle_output& s) sl@0: { sl@0: os << s._rng << " " << s.y << " "; sl@0: for(int i = 0; i < s.buffer_size; ++i) sl@0: os << s.v[i] << " "; sl@0: return os; sl@0: } sl@0: sl@0: template sl@0: friend std::basic_istream& sl@0: operator>>(std::basic_istream& is, shuffle_output& s) sl@0: { sl@0: is >> s._rng >> std::ws >> s.y >> std::ws; sl@0: for(int i = 0; i < s.buffer_size; ++i) sl@0: is >> s.v[i] >> std::ws; sl@0: return is; sl@0: } sl@0: #endif sl@0: sl@0: friend bool operator==(const shuffle_output& x, const shuffle_output& y) sl@0: { return x._rng == y._rng && x.y == y.y && std::equal(x.v, x.v+k, y.v); } sl@0: friend bool operator!=(const shuffle_output& x, const shuffle_output& y) sl@0: { return !(x == y); } sl@0: #else sl@0: // Use a member function; Streamable concept not supported. sl@0: bool operator==(const shuffle_output& rhs) const sl@0: { return _rng == rhs._rng && y == rhs.y && std::equal(v, v+k, rhs.v); } sl@0: bool operator!=(const shuffle_output& rhs) const sl@0: { return !(*this == rhs); } sl@0: #endif sl@0: private: sl@0: void init() sl@0: { sl@0: #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS sl@0: BOOST_STATIC_ASSERT(std::numeric_limits::is_integer); sl@0: #endif sl@0: result_type range = (max)()-(min)(); sl@0: assert(range > 0); // otherwise there would be little choice sl@0: if(static_cast(k * range) < sl@0: static_cast(range)) // not a sufficient condition sl@0: // likely overflow with bucket number computation sl@0: assert(!"overflow will occur"); sl@0: sl@0: // we cannot use std::generate, because it uses pass-by-value for _rng sl@0: for(result_type * p = v; p != v+k; ++p) sl@0: *p = _rng(); sl@0: y = _rng(); sl@0: } sl@0: sl@0: base_type _rng; sl@0: result_type v[k]; sl@0: result_type y; sl@0: }; sl@0: sl@0: #ifndef BOOST_NO_INCLASS_MEMBER_INITIALIZATION sl@0: // A definition is required even for integral static constants sl@0: template sl@0: const bool shuffle_output::has_fixed_range; sl@0: sl@0: template sl@0: const int shuffle_output::buffer_size; sl@0: #endif sl@0: sl@0: } // namespace random sl@0: sl@0: // validation by experiment from Harry Erwin's generator.h (private e-mail) sl@0: typedef random::shuffle_output< sl@0: random::linear_congruential, sl@0: 97, 139726> kreutzer1986; sl@0: sl@0: sl@0: } // namespace boost sl@0: sl@0: #endif // BOOST_RANDOM_SHUFFLE_OUTPUT_HPP