random_generator.hpp 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228
  1. // Boost random_generator.hpp header file ----------------------------------------------//
  2. // Copyright 2010 Andy Tompkins.
  3. // Copyright 2017 James E. King III
  4. // Distributed under the Boost Software License, Version 1.0. (See
  5. // accompanying file LICENSE_1_0.txt or copy at
  6. // https://www.boost.org/LICENSE_1_0.txt)
  7. #ifndef BOOST_UUID_RANDOM_GENERATOR_HPP
  8. #define BOOST_UUID_RANDOM_GENERATOR_HPP
  9. #include <boost/config.hpp>
  10. #include <boost/assert.hpp>
  11. #include <boost/move/core.hpp>
  12. #include <boost/move/utility_core.hpp>
  13. #include <boost/core/enable_if.hpp>
  14. #include <boost/random/mersenne_twister.hpp>
  15. #include <boost/random/uniform_int.hpp>
  16. #include <boost/random/variate_generator.hpp>
  17. #include <boost/tti/has_member_function.hpp>
  18. #include <boost/uuid/detail/random_provider.hpp>
  19. #include <boost/uuid/uuid.hpp>
  20. #include <limits>
  21. namespace boost {
  22. namespace uuids {
  23. namespace detail {
  24. template<class U>
  25. U& set_uuid_random_vv(U& u)
  26. {
  27. // set variant
  28. // must be 0b10xxxxxx
  29. *(u.begin() + 8) &= 0xBF;
  30. *(u.begin() + 8) |= 0x80;
  31. // set version
  32. // must be 0b0100xxxx
  33. *(u.begin() + 6) &= 0x4F; //0b01001111
  34. *(u.begin() + 6) |= 0x40; //0b01000000
  35. return u;
  36. }
  37. BOOST_TTI_HAS_MEMBER_FUNCTION(seed)
  38. }
  39. //! generate a random-based uuid
  40. //! \param[in] UniformRandomNumberGenerator see Boost.Random documentation
  41. template <typename UniformRandomNumberGenerator>
  42. class basic_random_generator
  43. {
  44. BOOST_MOVABLE_BUT_NOT_COPYABLE(basic_random_generator)
  45. private:
  46. typedef uniform_int<unsigned long> distribution_type;
  47. typedef variate_generator<UniformRandomNumberGenerator*, distribution_type> generator_type;
  48. struct impl
  49. {
  50. generator_type generator;
  51. explicit impl(UniformRandomNumberGenerator* purng_arg) :
  52. generator(purng_arg, distribution_type((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)()))
  53. {
  54. }
  55. virtual ~impl() {}
  56. BOOST_DELETED_FUNCTION(impl(impl const&))
  57. BOOST_DELETED_FUNCTION(impl& operator= (impl const&))
  58. };
  59. struct urng_holder
  60. {
  61. UniformRandomNumberGenerator urng;
  62. };
  63. #if defined(BOOST_MSVC)
  64. #pragma warning(push)
  65. // 'this' : used in base member initializer list
  66. #pragma warning(disable: 4355)
  67. #endif
  68. struct self_contained_impl :
  69. public urng_holder,
  70. public impl
  71. {
  72. self_contained_impl() : impl(&this->urng_holder::urng)
  73. {
  74. }
  75. };
  76. #if defined(BOOST_MSVC)
  77. #pragma warning(pop)
  78. #endif
  79. public:
  80. typedef uuid result_type;
  81. // default constructor creates the random number generator and
  82. // if the UniformRandomNumberGenerator is a PseudoRandomNumberGenerator
  83. // then it gets seeded by a random_provider.
  84. basic_random_generator() : m_impl(new self_contained_impl())
  85. {
  86. // seed the random number generator if it is capable
  87. seed(static_cast< self_contained_impl* >(m_impl)->urng);
  88. }
  89. // keep a reference to a random number generator
  90. // don't seed a given random number generator
  91. explicit basic_random_generator(UniformRandomNumberGenerator& gen) : m_impl(new impl(&gen))
  92. {
  93. }
  94. // keep a pointer to a random number generator
  95. // don't seed a given random number generator
  96. explicit basic_random_generator(UniformRandomNumberGenerator* gen) : m_impl(new impl(gen))
  97. {
  98. BOOST_ASSERT(!!gen);
  99. }
  100. basic_random_generator(BOOST_RV_REF(basic_random_generator) that) BOOST_NOEXCEPT : m_impl(that.m_impl)
  101. {
  102. that.m_impl = 0;
  103. }
  104. basic_random_generator& operator= (BOOST_RV_REF(basic_random_generator) that) BOOST_NOEXCEPT
  105. {
  106. delete m_impl;
  107. m_impl = that.m_impl;
  108. that.m_impl = 0;
  109. return *this;
  110. }
  111. ~basic_random_generator()
  112. {
  113. delete m_impl;
  114. }
  115. result_type operator()()
  116. {
  117. result_type u;
  118. int i=0;
  119. unsigned long random_value = m_impl->generator();
  120. for (uuid::iterator it = u.begin(), end = u.end(); it != end; ++it, ++i) {
  121. if (i==sizeof(unsigned long)) {
  122. random_value = m_impl->generator();
  123. i = 0;
  124. }
  125. // static_cast gets rid of warnings of converting unsigned long to boost::uint8_t
  126. *it = static_cast<uuid::value_type>((random_value >> (i*8)) & 0xFF);
  127. }
  128. return detail::set_uuid_random_vv(u);
  129. }
  130. private:
  131. // Detect whether UniformRandomNumberGenerator has a seed() method which indicates that
  132. // it is a PseudoRandomNumberGenerator and needs a seed to initialize it. This allows
  133. // basic_random_generator to take any type of UniformRandomNumberGenerator and still
  134. // meet the post-conditions for the default constructor.
  135. template<class MaybePseudoRandomNumberGenerator>
  136. typename boost::enable_if<detail::has_member_function_seed<MaybePseudoRandomNumberGenerator, void> >::type
  137. seed(MaybePseudoRandomNumberGenerator& rng)
  138. {
  139. detail::random_provider seeder;
  140. rng.seed(seeder);
  141. }
  142. template<class MaybePseudoRandomNumberGenerator>
  143. typename boost::disable_if<detail::has_member_function_seed<MaybePseudoRandomNumberGenerator, void> >::type
  144. seed(MaybePseudoRandomNumberGenerator&)
  145. {
  146. }
  147. impl* m_impl;
  148. };
  149. //! \brief a far less complex random generator that uses
  150. //! operating system provided entropy which will
  151. //! satisfy the majority of use cases
  152. class random_generator_pure
  153. {
  154. BOOST_MOVABLE_BUT_NOT_COPYABLE(random_generator_pure)
  155. public:
  156. typedef uuid result_type;
  157. BOOST_DEFAULTED_FUNCTION(random_generator_pure(), {})
  158. random_generator_pure(BOOST_RV_REF(random_generator_pure) that) BOOST_NOEXCEPT :
  159. prov_(boost::move(that.prov_))
  160. {
  161. }
  162. random_generator_pure& operator= (BOOST_RV_REF(random_generator_pure) that) BOOST_NOEXCEPT
  163. {
  164. prov_ = boost::move(that.prov_);
  165. return *this;
  166. }
  167. //! \returns a random, valid uuid
  168. //! \throws entropy_error
  169. result_type operator()()
  170. {
  171. result_type result;
  172. prov_.get_random_bytes(&result, sizeof(result_type));
  173. return detail::set_uuid_random_vv(result);
  174. }
  175. private:
  176. detail::random_provider prov_;
  177. };
  178. #if defined(BOOST_UUID_RANDOM_GENERATOR_COMPAT)
  179. typedef basic_random_generator<mt19937> random_generator;
  180. #else
  181. typedef random_generator_pure random_generator;
  182. typedef basic_random_generator<mt19937> random_generator_mt19937;
  183. #endif
  184. }} // namespace boost::uuids
  185. #endif // BOOST_UUID_RANDOM_GENERATOR_HPP