react-native-macos/ReactCommon/fabric/mounting/tests/Entropy.h

132 строки
3.2 KiB
C++

/*
* Copyright (c) Facebook, Inc. and its affiliates.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*/
#pragma once
#include <algorithm>
#include <random>
namespace facebook {
namespace react {
/*
* The source of pseudo-random numbers and some problem-oriented tools built on
* top of that. We need this class to maintain a reproducible stream of random
* numbers and abstract away complex math of and C++ STL API behind that.
*/
class Entropy final {
public:
using Generator = std::mt19937;
/*
* Creates an instance seeded with a real, not pseudo-random, number.
*/
Entropy() {
std::random_device device;
seed_ = device();
generator_ = std::mt19937(seed_);
}
/*
* Creates an instance seeded with a given number.
*/
Entropy(uint_fast32_t seed) {
seed_ = seed;
generator_ = std::mt19937(seed_);
}
uint_fast32_t getSeed() const {
return seed_;
}
/*
* Family of methods that return uniformly distributed instances of a type
* within a specified range.
*/
template <typename T>
bool random() const {
T result;
generateRandomValue(generator_, result);
return result;
}
template <typename T, typename Arg1>
T random(Arg1 arg1) const {
T result;
generateRandomValue(generator_, result, arg1);
return result;
}
template <typename T, typename Arg1, typename Arg2>
T random(Arg1 arg1, Arg2 arg2) const {
T result;
generateRandomValue(generator_, result, arg1, arg2);
return result;
}
void generateRandomValue(
Generator &generator,
bool &result,
double ratio = 0.5) const {
result = generator() % 10000 < 10000 * ratio;
}
void generateRandomValue(Generator &generator, int &result, int min, int max)
const {
std::uniform_int_distribution<int> distribution(min, max);
result = distribution(generator);
}
/*
* Shuffles `std::vector` in place.
*/
template <typename T>
void shuffle(T array) const {
std::shuffle(array.begin(), array.end(), generator_);
}
/*
* Distribute items from a given array into buckets using a normal
* distribution and given `deviation`.
*/
template <typename T>
std::vector<std::vector<T>> distribute(std::vector<T> items, double deviation)
const {
std::normal_distribution<> distribution{0, deviation};
auto deviationLimit = int(deviation * 10);
auto spreadResult = std::vector<std::vector<T>>(deviationLimit * 2);
std::fill(spreadResult.begin(), spreadResult.end(), std::vector<T>{});
for (auto const &item : items) {
auto position = int(distribution(generator_) + deviationLimit);
position = std::max(0, std::min(position, deviationLimit * 2));
if (position < spreadResult.size()) {
spreadResult[position].push_back(item);
}
}
auto result = std::vector<std::vector<T>>{};
for (auto const &chunk : spreadResult) {
if (chunk.size() == 0) {
continue;
}
result.push_back(chunk);
}
return result;
}
private:
mutable std::mt19937 generator_;
uint_fast32_t seed_;
};
} // namespace react
} // namespace facebook