Skip to content

Commit

Permalink
Move basic_random_generator to basic_random_generator.hpp
Browse files Browse the repository at this point in the history
  • Loading branch information
pdimov committed Apr 22, 2024
1 parent f64dd2a commit 5f3850b
Show file tree
Hide file tree
Showing 2 changed files with 185 additions and 162 deletions.
172 changes: 172 additions & 0 deletions include/boost/uuid/basic_random_generator.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#ifndef BOOST_UUID_BASIC_RANDOM_GENERATOR_HPP_INCLUDED
#define BOOST_UUID_BASIC_RANDOM_GENERATOR_HPP_INCLUDED

// Copyright 2010 Andy Tompkins
// Copyright 2017 James E. King III
// Copyright 2024 Peter Dimov
// Distributed under the Boost Software License, Version 1.0.
// https://www.boost.org/LICENSE_1_0.txt

#include <boost/uuid/detail/random_provider.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <type_traits>
#include <random>
#include <limits>
#include <cstring>
#include <cstdint>

namespace boost {
namespace uuids {

//! generate a random-based uuid
//! \param[in] UniformRandomNumberGenerator see Boost.Random documentation
template <typename UniformRandomNumberGenerator>
class basic_random_generator
{
private:

typedef std::uniform_int_distribution<unsigned long> distribution_type;

struct impl
{
UniformRandomNumberGenerator* purng;
distribution_type dist;

explicit impl(UniformRandomNumberGenerator* purng_arg) :
purng(purng_arg), dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)())
{
}

virtual ~impl() = default;

impl(impl const&) = delete;
impl& operator= (impl const&) = delete;
};

struct urng_holder
{
UniformRandomNumberGenerator urng;
};

#if defined(BOOST_MSVC)
#pragma warning(push)
// 'this' : used in base member initializer list
#pragma warning(disable: 4355)
#endif

struct self_contained_impl :
public urng_holder,
public impl
{
self_contained_impl() : impl(&this->urng_holder::urng)
{
}
};

#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif

public:

typedef uuid result_type;

// default constructor creates the random number generator and
// if the UniformRandomNumberGenerator is a PseudoRandomNumberGenerator
// then it gets seeded by a random_provider.
basic_random_generator() : m_impl(new self_contained_impl())
{
// seed the random number generator if it is capable
seed(static_cast< self_contained_impl* >(m_impl)->urng, 0);
}

// keep a reference to a random number generator
// don't seed a given random number generator
explicit basic_random_generator(UniformRandomNumberGenerator& gen) : m_impl(new impl(&gen))
{
}

// keep a pointer to a random number generator
// don't seed a given random number generator
explicit basic_random_generator(UniformRandomNumberGenerator* gen) : m_impl(new impl(gen))
{
BOOST_ASSERT(!!gen);
}

basic_random_generator(basic_random_generator&& that) BOOST_NOEXCEPT : m_impl(that.m_impl)
{
that.m_impl = 0;
}

basic_random_generator& operator= (basic_random_generator&& that) BOOST_NOEXCEPT
{
if( this != &that )
{
delete m_impl;
m_impl = that.m_impl;
that.m_impl = 0;
}

return *this;
}

~basic_random_generator()
{
delete m_impl;
}

result_type operator()()
{
result_type u;

int i = 0;
unsigned long random_value = m_impl->dist( *m_impl->purng );
for (uuid::iterator it = u.begin(), end = u.end(); it != end; ++it, ++i) {
if (i==sizeof(unsigned long)) {
random_value = m_impl->dist( *m_impl->purng );
i = 0;
}

// static_cast gets rid of warnings of converting unsigned long to boost::uint8_t
*it = static_cast<uuid::value_type>((random_value >> (i*8)) & 0xFF);
}

// set variant
// must be 0b10xxxxxx
*(u.begin() + 8) &= 0xBF;
*(u.begin() + 8) |= 0x80;

// set version
// must be 0b0100xxxx
*(u.begin() + 6) &= 0x4F; //0b01001111
*(u.begin() + 6) |= 0x40; //0b01000000

return u;
}

private:
// Detect whether UniformRandomNumberGenerator has a seed() method which indicates that
// it is a PseudoRandomNumberGenerator and needs a seed to initialize it. This allows
// basic_random_generator to take any type of UniformRandomNumberGenerator and still
// meet the post-conditions for the default constructor.

template<class MaybePseudoRandomNumberGenerator, class En = decltype( std::declval<MaybePseudoRandomNumberGenerator&>().seed() )>
void seed(MaybePseudoRandomNumberGenerator& rng, int)
{
detail::random_provider seeder;
rng.seed(seeder);
}

template<class MaybePseudoRandomNumberGenerator>
void seed(MaybePseudoRandomNumberGenerator&, long)
{
}

impl* m_impl;
};

}} // namespace boost::uuids

#endif // BOOST_UUID_BASIC_RANDOM_GENERATOR_HPP_INCLUDED
175 changes: 13 additions & 162 deletions include/boost/uuid/random_generator.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,174 +9,15 @@
// accompanying file LICENSE_1_0.txt or copy at
// https://www.boost.org/LICENSE_1_0.txt)

#include <boost/uuid/detail/random_provider.hpp>
#include <boost/uuid/basic_random_generator.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/assert.hpp>
#include <boost/config.hpp>
#include <type_traits>
#include <random>
#include <limits>
#include <boost/uuid/detail/random_provider.hpp>
#include <cstring>
#include <cstdint>

namespace boost {
namespace uuids {

namespace detail {
template<class U>
U& set_uuid_random_vv(U& u)
{
// set variant
// must be 0b10xxxxxx
*(u.begin() + 8) &= 0xBF;
*(u.begin() + 8) |= 0x80;

// set version
// must be 0b0100xxxx
*(u.begin() + 6) &= 0x4F; //0b01001111
*(u.begin() + 6) |= 0x40; //0b01000000

return u;
}
}

//! generate a random-based uuid
//! \param[in] UniformRandomNumberGenerator see Boost.Random documentation
template <typename UniformRandomNumberGenerator>
class basic_random_generator
{
private:

typedef std::uniform_int_distribution<unsigned long> distribution_type;

struct impl
{
UniformRandomNumberGenerator* purng;
distribution_type dist;

explicit impl(UniformRandomNumberGenerator* purng_arg) :
purng(purng_arg), dist((std::numeric_limits<unsigned long>::min)(), (std::numeric_limits<unsigned long>::max)())
{
}

virtual ~impl() = default;

impl(impl const&) = delete;
impl& operator= (impl const&) = delete;
};

struct urng_holder
{
UniformRandomNumberGenerator urng;
};

#if defined(BOOST_MSVC)
#pragma warning(push)
// 'this' : used in base member initializer list
#pragma warning(disable: 4355)
#endif

struct self_contained_impl :
public urng_holder,
public impl
{
self_contained_impl() : impl(&this->urng_holder::urng)
{
}
};

#if defined(BOOST_MSVC)
#pragma warning(pop)
#endif

public:

typedef uuid result_type;

// default constructor creates the random number generator and
// if the UniformRandomNumberGenerator is a PseudoRandomNumberGenerator
// then it gets seeded by a random_provider.
basic_random_generator() : m_impl(new self_contained_impl())
{
// seed the random number generator if it is capable
seed(static_cast< self_contained_impl* >(m_impl)->urng, 0);
}

// keep a reference to a random number generator
// don't seed a given random number generator
explicit basic_random_generator(UniformRandomNumberGenerator& gen) : m_impl(new impl(&gen))
{
}

// keep a pointer to a random number generator
// don't seed a given random number generator
explicit basic_random_generator(UniformRandomNumberGenerator* gen) : m_impl(new impl(gen))
{
BOOST_ASSERT(!!gen);
}

basic_random_generator(basic_random_generator&& that) BOOST_NOEXCEPT : m_impl(that.m_impl)
{
that.m_impl = 0;
}

basic_random_generator& operator= (basic_random_generator&& that) BOOST_NOEXCEPT
{
if( this != &that )
{
delete m_impl;
m_impl = that.m_impl;
that.m_impl = 0;
}

return *this;
}

~basic_random_generator()
{
delete m_impl;
}

result_type operator()()
{
result_type u;

int i = 0;
unsigned long random_value = m_impl->dist( *m_impl->purng );
for (uuid::iterator it = u.begin(), end = u.end(); it != end; ++it, ++i) {
if (i==sizeof(unsigned long)) {
random_value = m_impl->dist( *m_impl->purng );
i = 0;
}

// static_cast gets rid of warnings of converting unsigned long to boost::uint8_t
*it = static_cast<uuid::value_type>((random_value >> (i*8)) & 0xFF);
}

return detail::set_uuid_random_vv(u);
}

private:
// Detect whether UniformRandomNumberGenerator has a seed() method which indicates that
// it is a PseudoRandomNumberGenerator and needs a seed to initialize it. This allows
// basic_random_generator to take any type of UniformRandomNumberGenerator and still
// meet the post-conditions for the default constructor.

template<class MaybePseudoRandomNumberGenerator, class En = decltype( std::declval<MaybePseudoRandomNumberGenerator&>().seed() )>
void seed(MaybePseudoRandomNumberGenerator& rng, int)
{
detail::random_provider seeder;
rng.seed(seeder);
}

template<class MaybePseudoRandomNumberGenerator>
void seed(MaybePseudoRandomNumberGenerator&, long)
{
}

impl* m_impl;
};

//! \brief a far less complex random generator that uses
//! operating system provided entropy which will
//! satisfy the majority of use cases
Expand All @@ -202,7 +43,17 @@ class random_generator_pure

std::memcpy( result.data, tmp, 16 );

return detail::set_uuid_random_vv(result);
// set variant
// must be 0b10xxxxxx
*(result.begin() + 8) &= 0xBF;
*(result.begin() + 8) |= 0x80;

// set version
// must be 0b0100xxxx
*(result.begin() + 6) &= 0x4F; //0b01001111
*(result.begin() + 6) |= 0x40; //0b01000000

return result;
}

private:
Expand Down

0 comments on commit 5f3850b

Please sign in to comment.