/* * Copyright (C) 2018-present ScyllaDB */ /* * SPDX-License-Identifier: LicenseRef-ScyllaDB-Source-Available-1.0 */ #pragma once #include #include #include #include #include #include #include "bytes.hh" #include "utils/assert.hh" #include "utils/preempt.hh" namespace tests::random { inline std::default_random_engine& gen() { return seastar::testing::local_random_engine; } /// Produces random integers from a set of steps. /// /// Each step has a weight and a uniform distribution that determines the range /// of values for that step. The probability of the generated number to be from /// any given step is Ws/Wt, where Ws is the weight of the step and Wt is the /// sum of the weight of all steps. template class stepped_int_distribution { public: struct step { double weight; std::pair range; }; private: std::discrete_distribution _step_index_dist; std::vector> _step_ranges; public: explicit stepped_int_distribution(std::initializer_list steps) { std::vector step_weights; for (auto& s : steps) { step_weights.push_back(s.weight); _step_ranges.emplace_back(s.range.first, s.range.second); } _step_index_dist = std::discrete_distribution{step_weights.begin(), step_weights.end()}; } template Integer operator()(RandomEngine& engine) { return _step_ranges[_step_index_dist(engine)](engine); } }; template T get_int(T min, T max, RandomEngine& engine) { std::uniform_int_distribution dist(min, max); return dist(engine); } template T get_int(T max, RandomEngine& engine) { return get_int(T{0}, max, engine); } template T get_int(RandomEngine& engine) { return get_int(T{0}, std::numeric_limits::max(), engine); } template T get_int() { return get_int(T{0}, std::numeric_limits::max(), gen()); } template T get_int(T max) { return get_int(T{0}, max, gen()); } template T get_int(T min, T max) { return get_int(min, max, gen()); } template Real get_real(Real min, Real max, RandomEngine& engine) { auto dist = std::uniform_real_distribution(min, max); return dist(engine); } template Real get_real(Real max, RandomEngine& engine) { return get_real(Real{0}, max, engine); } /// Returns true with probability p. /// p = 1.0 means 100%. inline bool with_probability(double p) { return get_real(1, gen()) < p; } template Real get_real(RandomEngine& engine) { return get_real(Real{0}, std::numeric_limits::max(), engine); } template Real get_real(Real min, Real max) { return get_real(min, max, gen()); } template Real get_real(Real max) { return get_real(Real{0}, max, gen()); } template Real get_real() { return get_real(Real{0}, std::numeric_limits::max(), gen()); } template inline bool get_bool(RandomEngine& engine) { static std::bernoulli_distribution dist; return dist(engine); } inline bool get_bool() { return get_bool(gen()); } template inline bytes get_bytes(size_t n, RandomEngine& engine) { bytes b(bytes::initialized_later(), n); std::ranges::generate(b, [&engine] { return get_int(engine); }); return b; } inline bytes get_bytes(size_t n) { return get_bytes(n, gen()); } inline bytes get_bytes() { return get_bytes(get_int(128 * 1024)); } template inline sstring get_sstring(size_t n, RandomEngine& engine) { sstring str = uninitialized_string(n); std::ranges::generate(str, [&engine] { return get_int('a', 'z', engine); }); return str; } inline sstring get_sstring(size_t n) { return get_sstring(n, gen()); } inline sstring get_sstring() { return get_sstring(get_int(1024)); } // Picks a random subset of size `m` from the given vector. template std::vector random_subset(std::vector v, unsigned m, std::mt19937& engine) { SCYLLA_ASSERT(m <= v.size()); std::shuffle(v.begin(), v.end(), engine); return {v.begin(), v.begin() + m}; } // Picks a random subset of size `m` from the set {0, ..., `n` - 1}. template std::vector random_subset(unsigned n, unsigned m, std::mt19937& engine) { SCYLLA_ASSERT(m <= n); std::vector the_set(n); std::iota(the_set.begin(), the_set.end(), T{}); return random_subset(std::move(the_set), m, engine); } inline preemption_check random_preempt() { return [] () noexcept { return get_bool(); }; } }