| // 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_ |