Boost logo

Boost-Commit :

Subject: [Boost-commit] svn:boost r53699 - in trunk: boost/random boost/random/detail libs/random
From: steven_at_[hidden]
Date: 2009-06-06 15:41:39


Author: steven_watanabe
Date: 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
New Revision: 53699
URL: http://svn.boost.org/trac/boost/changeset/53699

Log:
Fix overload resolution for generator constructors/seed. Fixes #351. Fixes #2424. Fixes #2887
Added:
   trunk/boost/random/detail/seed.hpp (contents, props changed)
Text files modified:
   trunk/boost/random/additive_combine.hpp | 8 +++++
   trunk/boost/random/discard_block.hpp | 1
   trunk/boost/random/lagged_fibonacci.hpp | 14 +++++----
   trunk/boost/random/linear_congruential.hpp | 22 +++++++++++----
   trunk/boost/random/mersenne_twister.hpp | 22 ++++-----------
   trunk/boost/random/subtract_with_carry.hpp | 14 +++++----
   trunk/boost/random/xor_combine.hpp | 3 ++
   trunk/libs/random/instantiate.cpp | 55 ++++++++++++++++++++++++++++++++++++++-
   8 files changed, 103 insertions(+), 36 deletions(-)

Modified: trunk/boost/random/additive_combine.hpp
==============================================================================
--- trunk/boost/random/additive_combine.hpp (original)
+++ trunk/boost/random/additive_combine.hpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -54,6 +54,8 @@
   additive_combine(typename MLCG1::result_type seed1,
                    typename MLCG2::result_type seed2)
     : _mlcg1(seed1), _mlcg2(seed2) { }
+ additive_combine(result_type seed)
+ : _mlcg1(seed), _mlcg2(seed) { }
   template<class It> additive_combine(It& first, It last)
     : _mlcg1(first, last), _mlcg2(first, last) { }
 
@@ -63,6 +65,12 @@
     _mlcg2.seed();
   }
 
+ void seed(result_type seed)
+ {
+ _mlcg1.seed(seed);
+ _mlcg2.seed(seed);
+ }
+
   void seed(typename MLCG1::result_type seed1,
             typename MLCG2::result_type seed2)
   {

Added: trunk/boost/random/detail/seed.hpp
==============================================================================
--- (empty file)
+++ trunk/boost/random/detail/seed.hpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -0,0 +1,88 @@
+/* boost random/detail/seed.hpp header file
+ *
+ * Copyright Steven Watanabe 2009
+ * Distributed under 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)
+ *
+ * See http://www.boost.org for most recent version including documentation.
+ *
+ * $Id$
+ */
+
+#ifndef BOOST_RANDOM_DETAIL_SEED_HPP
+#define BOOST_RANDOM_DETAIL_SEED_HPP
+
+#include <boost/config.hpp>
+
+#if !defined(BOOST_NO_SFINAE)
+
+#include <boost/utility/enable_if.hpp>
+#include <boost/type_traits/is_arithmetic.hpp>
+
+namespace boost {
+namespace random {
+namespace detail {
+
+template<class T>
+struct disable_seed : boost::disable_if<boost::is_arithmetic<T> > {};
+
+template<class Engine, class T>
+struct disable_constructor : disable_seed<T> {};
+
+template<class Engine>
+struct disable_constructor<Engine, Engine> {
+};
+
+#define BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(Self, Generator, gen) \
+ template<class Generator> \
+ explicit Self(Generator& gen, typename ::boost::random::detail::disable_constructor<Self, Generator>::type* = 0)
+
+#define BOOST_RANDOM_DETAIL_GENERATOR_SEED(Self, Generator, gen) \
+ template<class Generator> \
+ void seed(Generator& gen, typename ::boost::random::detail::disable_seed<Generator>::type* = 0)
+
+#define BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(Self, T, x) \
+ explicit Self(const T& x)
+
+#define BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(Self, T, x) \
+ void seed(const T& x)
+
+}
+}
+}
+
+#else
+
+#include <boost/type_traits/is_arithmetic.hpp>
+#include <boost/mpl/bool.hpp>
+
+#define BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(Self, Generator, gen) \
+ Self(Self& other) { *this = other; } \
+ Self(const Self& other) { *this = other; } \
+ template<class Generator> \
+ explicit Self(Generator& gen) { \
+ boost_random_constructor_impl(gen, ::boost::is_arithmetic<Generator>());\
+ } \
+ template<class Generator> \
+ void boost_random_constructor_impl(Generator& gen, ::boost::mpl::false_)
+
+#define BOOST_RANDOM_DETAIL_GENERATOR_SEED(Self, Generator, gen) \
+ template<class Generator> \
+ void seed(Generator& gen) { \
+ boost_random_seed_impl(gen, ::boost::is_arithmetic<Generator>());\
+ }\
+ template<class Generator>\
+ void boost_random_seed_impl(Generator& gen, ::boost::mpl::false_)
+
+#define BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(Self, T, x) \
+ explicit Self(const T& x) { boost_random_constructor_impl(x, ::boost::mpl::true_()); }\
+ void boost_random_constructor_impl(const T& x, ::boost::mpl::true_)
+
+#define BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(Self, T, x) \
+ void seed(const T& x) { boost_random_seed_impl(x, ::boost::mpl::true_()); }\
+ void boost_random_seed_impl(const T& x, ::boost::mpl::true_)
+
+#endif
+
+#endif

Modified: trunk/boost/random/discard_block.hpp
==============================================================================
--- trunk/boost/random/discard_block.hpp (original)
+++ trunk/boost/random/discard_block.hpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -43,6 +43,7 @@
 
   discard_block() : _rng(), _n(0) { }
   explicit discard_block(const base_type & rng) : _rng(rng), _n(0) { }
+ template<class T> explicit discard_block(T s) : _rng(s), _n(0) {}
   template<class It> discard_block(It& first, It last)
     : _rng(first, last), _n(0) { }
   void seed() { _rng.seed(); _n = 0; }

Modified: trunk/boost/random/lagged_fibonacci.hpp
==============================================================================
--- trunk/boost/random/lagged_fibonacci.hpp (original)
+++ trunk/boost/random/lagged_fibonacci.hpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -28,6 +28,7 @@
 #include <boost/random/linear_congruential.hpp>
 #include <boost/random/uniform_01.hpp>
 #include <boost/random/detail/config.hpp>
+#include <boost/random/detail/seed.hpp>
 #include <boost/random/detail/pass_through_engine.hpp>
 
 namespace boost {
@@ -267,9 +268,10 @@
   BOOST_STATIC_CONSTANT(unsigned int, short_lag = q);
 
   lagged_fibonacci_01() { init_modulus(); seed(); }
- explicit lagged_fibonacci_01(uint32_t value) { init_modulus(); seed(value); }
- template<class Generator>
- explicit lagged_fibonacci_01(Generator & gen) { init_modulus(); seed(gen); }
+ BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(lagged_fibonacci_01, uint32_t, value)
+ { init_modulus(); seed(value); }
+ BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(lagged_fibonacci_01, Generator, gen)
+ { init_modulus(); seed(gen); }
   template<class It> lagged_fibonacci_01(It& first, It last)
   { init_modulus(); seed(first, last); }
   // compiler-generated copy ctor and assignment operator are fine
@@ -285,7 +287,8 @@
   }
 
 public:
- void seed(uint32_t value = 331u)
+ void seed() { seed(331u); }
+ BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(lagged_fibonacci_01, uint32_t, value)
   {
     minstd_rand0 intgen(value);
     seed(intgen);
@@ -294,8 +297,7 @@
   // For GCC, moving this function out-of-line prevents inlining, which may
   // reduce overall object code size. However, MSVC does not grok
   // out-of-line template member functions.
- template<class Generator>
- void seed(Generator & gen)
+ BOOST_RANDOM_DETAIL_GENERATOR_SEED(lagged_fibonacci, Generator, gen)
   {
     // use pass-by-reference, but wrap argument in pass_through_engine
     typedef detail::pass_through_engine<Generator&> ref_gen;

Modified: trunk/boost/random/linear_congruential.hpp
==============================================================================
--- trunk/boost/random/linear_congruential.hpp (original)
+++ trunk/boost/random/linear_congruential.hpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -212,12 +212,12 @@
   int32_t min BOOST_PREVENT_MACRO_SUBSTITUTION () const { return 0; }
   int32_t max BOOST_PREVENT_MACRO_SUBSTITUTION () const { return std::numeric_limits<int32_t>::max BOOST_PREVENT_MACRO_SUBSTITUTION (); }
   
- explicit rand48(int32_t x0 = 1) : lcf(cnv(x0)) { }
- explicit rand48(uint64_t x0) : lcf(x0) { }
+ rand48() : lcf(cnv(static_cast<int32_t>(1))) {}
+ template<class T> explicit rand48(T x0) : lcf(cnv(x0)) { }
   template<class It> rand48(It& first, It last) : lcf(first, last) { }
   // compiler-generated copy ctor and assignment operator are fine
- void seed(int32_t x0 = 1) { lcf.seed(cnv(x0)); }
- void seed(uint64_t x0) { lcf.seed(x0); }
+ void seed() { seed(static_cast<int32_t>(1)); }
+ template<class T> void seed(T x0) { lcf.seed(cnv(x0)); }
   template<class It> void seed(It& first, It last) { lcf.seed(first,last); }
 
   int32_t operator()() { return static_cast<int32_t>(lcf() >> 17); }
@@ -253,8 +253,18 @@
   random::linear_congruential<uint64_t,
     uint64_t(0xDEECE66DUL) | (uint64_t(0x5) << 32), // xxxxULL is not portable
     0xB, uint64_t(1)<<48, /* unknown */ 0> lcf;
- static uint64_t cnv(int32_t x)
- { return (static_cast<uint64_t>(x) << 16) | 0x330e; }
+ template<class T>
+ static uint64_t cnv(T x)
+ {
+ if(sizeof(T) < sizeof(uint64_t)) {
+ return (static_cast<uint64_t>(x) << 16) | 0x330e;
+ } else {
+ return(static_cast<uint64_t>(x));
+ }
+ }
+ static uint64_t cnv(float x) { return(static_cast<uint64_t>(x)); }
+ static uint64_t cnv(double x) { return(static_cast<uint64_t>(x)); }
+ static uint64_t cnv(long double x) { return(static_cast<uint64_t>(x)); }
 };
 #endif /* !BOOST_NO_INT64_T && !BOOST_NO_INTEGRAL_INT64_T */
 

Modified: trunk/boost/random/mersenne_twister.hpp
==============================================================================
--- trunk/boost/random/mersenne_twister.hpp (original)
+++ trunk/boost/random/mersenne_twister.hpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -28,6 +28,7 @@
 #include <boost/detail/workaround.hpp>
 #include <boost/random/detail/config.hpp>
 #include <boost/random/detail/ptr_helper.hpp>
+#include <boost/random/detail/seed.hpp>
 
 namespace boost {
 namespace random {
@@ -55,28 +56,18 @@
   
   mersenne_twister() { seed(); }
 
-#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x520)
- // Work around overload resolution problem (Gennadiy E. Rozental)
- explicit mersenne_twister(const UIntType& value)
-#else
- explicit mersenne_twister(UIntType value)
-#endif
+ BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(mersenne_twister, UIntType, value)
   { seed(value); }
   template<class It> mersenne_twister(It& first, It last) { seed(first,last); }
 
- template<class Generator>
- explicit mersenne_twister(Generator & gen) { seed(gen); }
+ BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(mersenne_twister, Generator, gen)
+ { seed(gen); }
 
   // compiler-generated copy ctor and assignment operator are fine
 
   void seed() { seed(UIntType(5489)); }
 
-#if defined(__SUNPRO_CC) && (__SUNPRO_CC <= 0x520)
- // Work around overload resolution problem (Gennadiy E. Rozental)
- void seed(const UIntType& value)
-#else
- void seed(UIntType value)
-#endif
+ BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(mersenne_twister, UIntType, value)
   {
     // New seeding algorithm from
     // http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/MT2002/emt19937ar.html
@@ -93,8 +84,7 @@
   // For GCC, moving this function out-of-line prevents inlining, which may
   // reduce overall object code size. However, MSVC does not grok
   // out-of-line definitions of member function templates.
- template<class Generator>
- void seed(Generator & gen)
+ BOOST_RANDOM_DETAIL_GENERATOR_SEED(mersenne_twister, Generator, gen)
   {
 #ifndef BOOST_NO_LIMITS_COMPILE_TIME_CONSTANTS
     BOOST_STATIC_ASSERT(!std::numeric_limits<result_type>::is_signed);

Modified: trunk/boost/random/subtract_with_carry.hpp
==============================================================================
--- trunk/boost/random/subtract_with_carry.hpp (original)
+++ trunk/boost/random/subtract_with_carry.hpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -27,6 +27,7 @@
 #include <boost/static_assert.hpp>
 #include <boost/detail/workaround.hpp>
 #include <boost/random/detail/config.hpp>
+#include <boost/random/detail/seed.hpp>
 #include <boost/random/linear_congruential.hpp>
 
 
@@ -86,14 +87,16 @@
 #endif
     seed();
   }
- explicit subtract_with_carry(uint32_t value) { seed(value); }
- template<class Generator>
- explicit subtract_with_carry(Generator & gen) { seed(gen); }
+ BOOST_RANDOM_DETAIL_ARITHMETIC_CONSTRUCTOR(subtract_with_carry, uint32_t, value)
+ { seed(value); }
+ BOOST_RANDOM_DETAIL_GENERATOR_CONSTRUCTOR(subtract_with_carry, Generator, gen)
+ { seed(gen); }
   template<class It> subtract_with_carry(It& first, It last) { seed(first,last); }
 
   // compiler-generated copy ctor and assignment operator are fine
 
- void seed(uint32_t value = 19780503u)
+ void seed() { seed(19780503u); }
+ BOOST_RANDOM_DETAIL_ARITHMETIC_SEED(subtract_with_carry, uint32_t, value)
   {
     random::linear_congruential<int32_t, 40014, 0, 2147483563, 0> intgen(value);
     seed(intgen);
@@ -102,8 +105,7 @@
   // For GCC, moving this function out-of-line prevents inlining, which may
   // reduce overall object code size. However, MSVC does not grok
   // out-of-line template member functions.
- template<class Generator>
- void seed(Generator & gen)
+ BOOST_RANDOM_DETAIL_GENERATOR_SEED(subtract_with_carry, Generator, gen)
   {
     // I could have used std::generate_n, but it takes "gen" by value
     for(unsigned int j = 0; j < long_lag; ++j)

Modified: trunk/boost/random/xor_combine.hpp
==============================================================================
--- trunk/boost/random/xor_combine.hpp (original)
+++ trunk/boost/random/xor_combine.hpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -49,9 +49,12 @@
   { }
   xor_combine(const base1_type & rng1, const base2_type & rng2)
     : _rng1(rng1), _rng2(rng2) { }
+ xor_combine(const result_type & v)
+ : _rng1(v), _rng2(v) { }
   template<class It> xor_combine(It& first, It last)
     : _rng1(first, last), _rng2( /* advanced by other call */ first, last) { }
   void seed() { _rng1.seed(); _rng2.seed(); }
+ void seed(const result_type & v) { _rng1.seed(v); _rng2.seed(v); }
   template<class It> void seed(It& first, It last)
   {
     _rng1.seed(first, last);

Modified: trunk/libs/random/instantiate.cpp
==============================================================================
--- trunk/libs/random/instantiate.cpp (original)
+++ trunk/libs/random/instantiate.cpp 2009-06-06 15:41:38 EDT (Sat, 06 Jun 2009)
@@ -129,12 +129,61 @@
                    boost::gamma_distribution<RealType>(1));
 }
 
+template<class URNG, class T>
+void test_seed(URNG & urng, const T & t) {
+ URNG urng2(t);
+ BOOST_CHECK(urng == urng2);
+ urng2.seed(t);
+ BOOST_CHECK(urng == urng2);
+}
+
+// rand48 uses non-standard seeding
+template<class T>
+void test_seed(boost::rand48 & urng, const T & t) {
+ boost::rand48 urng2(t);
+ urng2.seed(t);
+}
+
 template<class URNG, class ResultType>
-void instantiate_urng(const std::string & s, const URNG &, const ResultType &)
+void instantiate_seed(const URNG &, const ResultType &) {
+ {
+ URNG urng;
+ URNG urng2;
+ urng2.seed();
+ BOOST_CHECK(urng == urng2);
+ }
+ {
+ int value = 127;
+ URNG urng(value);
+
+ // integral types
+ test_seed(urng, static_cast<char>(value));
+ test_seed(urng, static_cast<signed char>(value));
+ test_seed(urng, static_cast<unsigned char>(value));
+ test_seed(urng, static_cast<short>(value));
+ test_seed(urng, static_cast<unsigned short>(value));
+ test_seed(urng, static_cast<int>(value));
+ test_seed(urng, static_cast<unsigned int>(value));
+ test_seed(urng, static_cast<long>(value));
+ test_seed(urng, static_cast<unsigned long>(value));
+#if !defined(BOOST_NO_INT64_T)
+ test_seed(urng, static_cast<boost::int64_t>(value));
+ test_seed(urng, static_cast<boost::uint64_t>(value));
+#endif
+
+ // floating point types
+ test_seed(urng, static_cast<float>(value));
+ test_seed(urng, static_cast<double>(value));
+ test_seed(urng, static_cast<long double>(value));
+ }
+}
+
+template<class URNG, class ResultType>
+void instantiate_urng(const std::string & s, const URNG & u, const ResultType & r)
 {
   std::cout << "Basic tests for " << s;
   URNG urng;
- urng.seed(); // seed() member function
+ instantiate_seed(u, r); // seed() member function
   int a[URNG::has_fixed_range ? 5 : 10]; // compile-time constant
   (void) a; // avoid "unused" warning
   typename URNG::result_type x1 = urng();
@@ -148,6 +197,8 @@
   urng();
   urng2 = urng; // copy assignment
   BOOST_CHECK(urng == urng2);
+ urng2 = URNG(urng2); // copy constructor, not templated constructor
+ BOOST_CHECK(urng == urng2);
 #endif // BOOST_MSVC
 
   const std::vector<int> v(9999u, 0x41);


Boost-Commit list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk