basic_random_generator.hpp 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. #ifndef BOOST_UUID_BASIC_RANDOM_GENERATOR_HPP_INCLUDED
  2. #define BOOST_UUID_BASIC_RANDOM_GENERATOR_HPP_INCLUDED
  3. // Copyright 2010 Andy Tompkins
  4. // Copyright 2017 James E. King III
  5. // Copyright 2024 Peter Dimov
  6. // Distributed under the Boost Software License, Version 1.0.
  7. // https://www.boost.org/LICENSE_1_0.txt
  8. #include <boost/uuid/uuid.hpp>
  9. #include <boost/uuid/detail/random_provider.hpp>
  10. #include <boost/uuid/detail/endian.hpp>
  11. #include <boost/assert.hpp>
  12. #include <type_traits>
  13. #include <random>
  14. #include <cstdint>
  15. namespace boost {
  16. namespace uuids {
  17. template<class UniformRandomNumberGenerator>
  18. class basic_random_generator
  19. {
  20. private:
  21. UniformRandomNumberGenerator* p_;
  22. UniformRandomNumberGenerator g_;
  23. public:
  24. using result_type = uuid;
  25. // default constructor creates the random number generator and
  26. // if the UniformRandomNumberGenerator is a PseudoRandomNumberGenerator
  27. // then it gets seeded by a random_provider.
  28. basic_random_generator(): p_( 0 ), g_()
  29. {
  30. // seed the random number generator if it is capable
  31. seed( g_, 0 );
  32. }
  33. // keep a reference to a random number generator
  34. // don't seed a given random number generator
  35. explicit basic_random_generator( UniformRandomNumberGenerator& gen ): p_( &gen )
  36. {
  37. }
  38. // keep a pointer to a random number generator
  39. // don't seed a given random number generator
  40. explicit basic_random_generator( UniformRandomNumberGenerator* gen ): p_( gen )
  41. {
  42. BOOST_ASSERT( gen != 0 );
  43. }
  44. result_type operator()()
  45. {
  46. UniformRandomNumberGenerator& gen = p_? *p_: g_;
  47. result_type u;
  48. fill_data( gen, u );
  49. // set variant
  50. // must be 0b10xxxxxx
  51. *(u.begin() + 8) &= 0x3F;
  52. *(u.begin() + 8) |= 0x80;
  53. // set version
  54. // must be 0b0100xxxx
  55. *(u.begin() + 6) &= 0x0F; //0b00001111
  56. *(u.begin() + 6) |= 0x40; //0b01000000
  57. return u;
  58. }
  59. private:
  60. template<class URNG> static void fill_data_impl( URNG& gen, uuid& u, std::false_type, std::false_type )
  61. {
  62. std::uniform_int_distribution<std::uint32_t> dist;
  63. detail::store_little_u32( u.data + 0, dist( gen ) );
  64. detail::store_little_u32( u.data + 4, dist( gen ) );
  65. detail::store_little_u32( u.data + 8, dist( gen ) );
  66. detail::store_little_u32( u.data + 12, dist( gen ) );
  67. }
  68. template<class URNG> static void fill_data_impl( URNG& gen, uuid& u, std::true_type, std::false_type )
  69. {
  70. detail::store_little_u32( u.data + 0, static_cast<std::uint32_t>( gen() ) );
  71. detail::store_little_u32( u.data + 4, static_cast<std::uint32_t>( gen() ) );
  72. detail::store_little_u32( u.data + 8, static_cast<std::uint32_t>( gen() ) );
  73. detail::store_little_u32( u.data + 12, static_cast<std::uint32_t>( gen() ) );
  74. }
  75. template<class URNG> static void fill_data_impl( URNG& gen, uuid& u, std::false_type, std::true_type )
  76. {
  77. detail::store_little_u64( u.data + 0, static_cast<std::uint64_t>( gen() ) );
  78. detail::store_little_u64( u.data + 8, static_cast<std::uint64_t>( gen() ) );
  79. }
  80. template<class URNG> static void fill_data( URNG& gen, uuid& u )
  81. {
  82. fill_data_impl( gen, u,
  83. std::integral_constant<bool, (URNG::min)() == 0 && (URNG::max)() == static_cast<std::uint32_t>( -1 )>(),
  84. std::integral_constant<bool, (URNG::min)() == 0 && (URNG::max)() == static_cast<std::uint64_t>( -1 )>()
  85. );
  86. }
  87. // Detect whether UniformRandomNumberGenerator has a seed() method which indicates that
  88. // it is a PseudoRandomNumberGenerator and needs a seed to initialize it. This allows
  89. // basic_random_generator to take any type of UniformRandomNumberGenerator and still
  90. // meet the post-conditions for the default constructor.
  91. template<class MaybePseudoRandomNumberGenerator, class En = decltype( std::declval<MaybePseudoRandomNumberGenerator&>().seed() )>
  92. void seed( MaybePseudoRandomNumberGenerator& rng, int )
  93. {
  94. detail::random_provider seeder;
  95. rng.seed(seeder);
  96. }
  97. template<class MaybePseudoRandomNumberGenerator>
  98. void seed( MaybePseudoRandomNumberGenerator&, long )
  99. {
  100. }
  101. };
  102. }} // namespace boost::uuids
  103. #endif // BOOST_UUID_BASIC_RANDOM_GENERATOR_HPP_INCLUDED