@ -17,28 +17,82 @@
# include <algorithm>
# include <cstdint>
# include <iostream>
# include <iterator>
# include <random>
# include <string>
# include <type_traits>
# include <utility>
# include <vector>
# include "absl/base/macros.h"
# include "absl/container/inlined_vector.h"
# include "absl/meta/type_traits.h"
# include "absl/random/internal/pool_urbg.h"
# include "absl/random/internal/salted_seed_seq.h"
# include "absl/random/internal/seed_material.h"
# include "absl/types/optional.h"
# include "absl/types/span.h"
namespace absl {
ABSL_NAMESPACE_BEGIN
namespace random_internal {
// RandenPoolSeedSeq is a custom seed sequence type where generate() fills the
// provided buffer via the RandenPool entropy source.
class RandenPoolSeedSeq {
private :
struct ContiguousTag { } ;
struct BufferTag { } ;
// Generate random unsigned values directly into the buffer.
template < typename Contiguous >
void generate_impl ( ContiguousTag , Contiguous begin , Contiguous end ) {
const size_t n = std : : distance ( begin , end ) ;
auto * a = & ( * begin ) ;
RandenPool < uint8_t > : : Fill (
absl : : MakeSpan ( reinterpret_cast < uint8_t * > ( a ) , sizeof ( * a ) * n ) ) ;
}
// Construct a buffer of size n and fill it with values, then copy
// those values into the seed iterators.
template < typename RandomAccessIterator >
void generate_impl ( BufferTag , RandomAccessIterator begin ,
RandomAccessIterator end ) {
const size_t n = std : : distance ( begin , end ) ;
absl : : InlinedVector < uint32_t , 8 > data ( n , 0 ) ;
RandenPool < uint32_t > : : Fill ( absl : : MakeSpan ( data . begin ( ) , data . end ( ) ) ) ;
std : : copy ( std : : begin ( data ) , std : : end ( data ) , begin ) ;
}
public :
using result_type = uint32_t ;
size_t size ( ) { return 0 ; }
template < typename OutIterator >
void param ( OutIterator ) const { }
template < typename RandomAccessIterator >
void generate ( RandomAccessIterator begin , RandomAccessIterator end ) {
// RandomAccessIterator must be assignable from uint32_t
if ( begin ! = end ) {
using U = typename std : : iterator_traits < RandomAccessIterator > : : value_type ;
// ContiguousTag indicates the common case of a known contiguous buffer,
// which allows directly filling the buffer. In C++20,
// std::contiguous_iterator_tag provides a mechanism for testing this
// capability, however until Abseil's support requirements allow us to
// assume C++20, limit checks to a few common cases.
using TagType = absl : : conditional_t <
( std : : is_pointer < RandomAccessIterator > : : value | |
std : : is_same < RandomAccessIterator ,
typename std : : vector < U > : : iterator > : : value ) ,
ContiguousTag , BufferTag > ;
generate_impl ( TagType { } , begin , end ) ;
}
}
} ;
// Each instance of NonsecureURBGBase<URBG> will be seeded by variates produced
// by a thread-unique URBG-instance.
template < typename URBG >
template < typename URBG , typename Seeder = RandenPoolSeedSeq >
class NonsecureURBGBase {
public :
using result_type = typename URBG : : result_type ;
@ -85,49 +139,6 @@ class NonsecureURBGBase {
}
private :
// Seeder is a custom seed sequence type where generate() fills the provided
// buffer via the RandenPool entropy source.
struct Seeder {
using result_type = uint32_t ;
size_t size ( ) { return 0 ; }
template < typename OutIterator >
void param ( OutIterator ) const { }
template < typename RandomAccessIterator >
void generate ( RandomAccessIterator begin , RandomAccessIterator end ) {
if ( begin ! = end ) {
// begin, end must be random access iterators assignable from uint32_t.
generate_impl (
std : : integral_constant < bool , sizeof ( * begin ) = = sizeof ( uint32_t ) > { } ,
begin , end ) ;
}
}
// Commonly, generate is invoked with a pointer to a buffer which
// can be cast to a uint32_t.
template < typename RandomAccessIterator >
void generate_impl ( std : : integral_constant < bool , true > ,
RandomAccessIterator begin , RandomAccessIterator end ) {
auto buffer = absl : : MakeSpan ( begin , end ) ;
auto target = absl : : MakeSpan ( reinterpret_cast < uint32_t * > ( buffer . data ( ) ) ,
buffer . size ( ) ) ;
RandenPool < uint32_t > : : Fill ( target ) ;
}
// The non-uint32_t case should be uncommon, and involves an extra copy,
// filling the uint32_t buffer and then mixing into the output.
template < typename RandomAccessIterator >
void generate_impl ( std : : integral_constant < bool , false > ,
RandomAccessIterator begin , RandomAccessIterator end ) {
const size_t n = std : : distance ( begin , end ) ;
absl : : InlinedVector < uint32_t , 8 > data ( n , 0 ) ;
RandenPool < uint32_t > : : Fill ( absl : : MakeSpan ( data . begin ( ) , data . end ( ) ) ) ;
std : : copy ( std : : begin ( data ) , std : : end ( data ) , begin ) ;
}
} ;
static URBG ConstructURBG ( ) {
Seeder seeder ;
return URBG ( seeder ) ;