blob: cfbc85332784bf32061aca8d69a3deed23d5ce41 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef PERIDOT_LIB_RNG_RANDOM_H_
#define PERIDOT_LIB_RNG_RANDOM_H_
#include <limits>
#include <string>
#include <type_traits>
namespace rng {
// Abstraction over the random number generator.
//
// This class allows to get random values. It can generate random bytes on a
// given buffer, fill a mutable string-like object, or return a POD like
// object.
//
// Using this class allows to control the randomness when running tests by
// injecting a seedable PRNG and reseeding it with the same value to re-run the
// same test.
class Random {
public:
// An object satifying the |UniformRandomBitGenerator| requirements. See:
// https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerator
template <typename I>
class BitGenerator {
public:
static_assert(std::is_unsigned<I>::value,
"RandomBitGenerator only valid for unsigned integers");
using result_type = I;
BitGenerator(Random* random) : random_(random) {}
~BitGenerator() = default;
BitGenerator(const BitGenerator&) = default;
BitGenerator& operator=(const BitGenerator&) = default;
static constexpr result_type min() {
return std::numeric_limits<result_type>::min();
}
static constexpr result_type max() {
return std::numeric_limits<result_type>::max();
}
constexpr double entropy() const noexcept {
return std::numeric_limits<result_type>::digits;
};
result_type operator()() { return random_->Draw<I>(); }
private:
Random* const random_;
};
Random() = default;
Random(const Random&) = delete;
Random& operator=(const Random&) = delete;
virtual ~Random() = default;
// Fill |buffer| with |buffer_size| random bytes.
void Draw(void* buffer, size_t buffer_size) {
InternalDraw(buffer, buffer_size);
}
// Fills |*string_like| with random bytes. |string_like| must have a random
// access operator returning a non-const reference. |string_like must have a
// |size| method. &(*string_like)[0] must be the start of writable memory
// range of at least |string_like->size()| bytes. Usual datatype that support
// this schema are std::string and std::vector<uint8_t>.
template <typename S>
S& Draw(S* string_like) {
Draw(&(*string_like)[0], string_like->size());
return *string_like;
}
// Returns an instance of |I| where the content has been filled with randomly
// generated bytes. |I| must be trivially copyable.
template <typename I>
I Draw() {
static_assert(std::is_trivially_copyable<I>::value,
"The return type must be trivially copyable.");
I result;
Draw(&result, sizeof(I));
return result;
}
// Returns a random string that is statistically certain to be unique.
std::string RandomUniqueBytes() {
constexpr size_t kBitsCountForUnicity = 128;
char bytes[kBitsCountForUnicity / 8];
Draw(bytes, sizeof(bytes));
return std::string(bytes, sizeof(bytes));
}
// Returns an object satifying the |UniformRandomBitGenerator| requirements.
// See: https://en.cppreference.com/w/cpp/named_req/UniformRandomBitGenerator
template <typename I>
BitGenerator<I> NewBitGenerator() {
return BitGenerator<I>(this);
}
protected:
// Fills |buffer| with |buffer_size| random bytes.
virtual void InternalDraw(void* buffer, size_t buffer_size) = 0;
};
}; // namespace rng
#endif // PERIDOT_LIB_RNG_RANDOM_H_