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