Prechádzať zdrojové kódy

SimpleRandomizer: Use std::random

Tatsuhiro Tsujikawa 12 rokov pred
rodič
commit
986f69e5bf
3 zmenil súbory, kde vykonal 29 pridanie a 18 odobranie
  1. 1 1
      src/Context.cc
  2. 22 14
      src/SimpleRandomizer.cc
  3. 6 3
      src/SimpleRandomizer.h

+ 1 - 1
src/Context.cc

@@ -161,7 +161,7 @@ Context::Context(bool standalone,
       throw DL_ABORT_EX("Option processing failed");
     }
   }
-  SimpleRandomizer::init();
+  SimpleRandomizer::getInstance()->init();
 #ifdef ENABLE_BITTORRENT
   bittorrent::generateStaticPeerId(op->get(PREF_PEER_ID_PREFIX));
 #endif // ENABLE_BITTORRENT

+ 22 - 14
src/SimpleRandomizer.cc

@@ -38,6 +38,7 @@
 #include <unistd.h>
 #include <cstdlib>
 #include <cassert>
+#include <cstring>
 
 #include "a2time.h"
 
@@ -56,7 +57,8 @@ const std::unique_ptr<SimpleRandomizer>& SimpleRandomizer::getInstance()
 void SimpleRandomizer::init()
 {
 #ifndef __MINGW32__
-  srandom(time(nullptr)^getpid());
+  // Just in case std::random_device() is fixed, add time and pid too.
+  eng_.seed(std::random_device()()^time(nullptr)^getpid());
 #endif // !__MINGW32__
 }
 
@@ -90,7 +92,7 @@ long int SimpleRandomizer::getRandomNumber()
   }
   return val;
 #else // !__MINGW32__
-  return random();
+  return eng_();
 #endif // !__MINGW32__
 }
 
@@ -99,15 +101,18 @@ long int SimpleRandomizer::getMaxRandomNumber()
 #ifdef __MINGW32__
   return INT32_MAX;
 #else // !__MINGW32__
-  // TODO Warning: The maximum value of random() in some sytems (e.g.,
-  // Solaris and openbsd) is (2**31)-1.
-  return RAND_MAX;
+  return eng_.max();
 #endif // !__MINGW32__
 }
 
 long int SimpleRandomizer::getRandomNumber(long int to)
 {
+  assert(to > 0);
+#ifdef __MINGW32__
   return getRandomNumber() % to;
+#else // !__MINGW32__
+  return std::uniform_int_distribution<long int>(0, to - 1)(eng_);
+#endif // !__MINGW32__
 }
 
 long int SimpleRandomizer::operator()(long int to)
@@ -122,16 +127,19 @@ void SimpleRandomizer::getRandomBytes(unsigned char *buf, size_t len)
     throw std::bad_alloc();
   }
 #else
-  while (len) {
-    // If RAND_MAX is less than 2**16-1, we are in trouble.
-    union {
-      uint16_t r;
-      uint8_t b[2];
-    } r = { (uint16_t)(random() & 0xffffu) };
-    for (auto i = 0; i < 2 && len; ++i, --len) {
-      *buf++ = r.b[i];
-    }
+  uint32_t val;
+  size_t q = len / sizeof(val);
+  size_t r = len % sizeof(val);
+  auto gen = std::bind(std::uniform_int_distribution<uint32_t>
+                       (0, std::numeric_limits<uint32_t>::max()),
+                       eng_);
+  for(; q > 0; --q) {
+    val = gen();
+    memcpy(buf, &val, sizeof(val));
+    buf += sizeof(val);
   }
+  val = gen();
+  memcpy(buf, &val, r);
 #endif
 }
 

+ 6 - 3
src/SimpleRandomizer.h

@@ -38,6 +38,7 @@
 #include "Randomizer.h"
 
 #include <memory>
+#include <random>
 
 #ifdef __MINGW32__
 # include <wincrypt.h>
@@ -51,17 +52,19 @@ private:
 
 #ifdef __MINGW32__
   HCRYPTPROV cryProvider_;
-#endif //__MINGW32__
+#else // !__MINGW32__
+  std::minstd_rand eng_;
+#endif //!__MINGW32__
 
   SimpleRandomizer();
 public:
 
   static const std::unique_ptr<SimpleRandomizer>& getInstance();
 
-  static void init();
-
   virtual ~SimpleRandomizer();
 
+  void init();
+
   virtual long int getRandomNumber() CXX11_OVERRIDE;
 
   virtual long int getMaxRandomNumber() CXX11_OVERRIDE;