// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- // vim: ts=8 sw=2 smarttab /* * Ceph - scalable distributed file system * * Copyright (C) 2017 SUSE LINUX GmbH * * This is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1, as published by the Free Software * Foundation. See file COPYING. * */ #ifndef CEPH_RANDOM_H #define CEPH_RANDOM_H 1 #include #include #include #include // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=85494 #ifdef __MINGW32__ #include using random_device_t = boost::random::random_device; #else using random_device_t = std::random_device; #endif // Basic random number facility (see N3551 for inspiration): namespace ceph::util { inline namespace version_1_0_3 { namespace detail { template using larger_of = typename std::conditional< sizeof(T0) >= sizeof(T1), T0, T1> ::type; // avoid mixing floating point and integers: template using has_compatible_numeric_types = std::disjunction< std::conjunction< std::is_floating_point, std::is_floating_point >, std::conjunction< std::is_integral, std::is_integral > >; // Select the larger of type compatible numeric types: template using select_number_t = std::enable_if_t::value, detail::larger_of>; } // namespace detail namespace detail { // Choose default distribution for appropriate types: template struct select_distribution { using type = std::uniform_int_distribution; }; template struct select_distribution { using type = std::uniform_real_distribution; }; template using default_distribution = typename select_distribution::value>::type; } // namespace detail namespace detail { template EngineT& engine(); template void randomize_rng(const SeedT seed, MutexT& m, EngineT& e) { std::lock_guard lg(m); e.seed(seed); } template void randomize_rng(MutexT& m, EngineT& e) { random_device_t rd; std::lock_guard lg(m); e.seed(rd()); } template void randomize_rng(const SeedT n) { detail::engine().seed(n); } template void randomize_rng() { random_device_t rd; detail::engine().seed(rd()); } template EngineT& engine() { thread_local boost::optional rng_engine; if (!rng_engine) { rng_engine.emplace(EngineT()); randomize_rng(); } return *rng_engine; } } // namespace detail namespace detail { template , typename EngineT> NumberT generate_random_number(const NumberT min, const NumberT max, EngineT& e) { DistributionT d { min, max }; using param_type = typename DistributionT::param_type; return d(e, param_type { min, max }); } template , typename EngineT> NumberT generate_random_number(const NumberT min, const NumberT max, MutexT& m, EngineT& e) { DistributionT d { min, max }; using param_type = typename DistributionT::param_type; std::lock_guard lg(m); return d(e, param_type { min, max }); } template , typename EngineT> NumberT generate_random_number(const NumberT min, const NumberT max) { return detail::generate_random_number (min, max, detail::engine()); } template > NumberT generate_random_number(MutexT& m, EngineT& e) { return detail::generate_random_number (0, std::numeric_limits::max(), m, e); } template NumberT generate_random_number(const NumberT max, MutexT& m, EngineT& e) { return generate_random_number(0, max, m, e); } } // namespace detail template void randomize_rng() { detail::randomize_rng(); } template , typename EngineT = std::default_random_engine> NumberT generate_random_number() { return detail::generate_random_number (0, std::numeric_limits::max()); } template > NumberT generate_random_number(const NumberT0 min, const NumberT1 max) { return detail::generate_random_number, std::default_random_engine> (static_cast(min), static_cast(max)); } template > NumberT generate_random_number(const NumberT min, const NumberT max, EngineT& e) { return detail::generate_random_number(static_cast(min), static_cast(max), e); } template NumberT generate_random_number(const NumberT max) { return generate_random_number(0, max); } // Function object: template class random_number_generator final { std::mutex l; random_device_t rd; std::default_random_engine e; using seed_type = typename decltype(e)::result_type; public: using number_type = NumberT; using random_engine_type = decltype(e); using random_device_type = decltype(rd); public: random_device_type& random_device() noexcept { return rd; } random_engine_type& random_engine() noexcept { return e; } public: random_number_generator() { detail::randomize_rng(l, e); } explicit random_number_generator(const seed_type seed) { detail::randomize_rng(seed, l, e); } random_number_generator(random_number_generator&& rhs) : e(std::move(rhs.e)) {} public: random_number_generator(const random_number_generator&) = delete; random_number_generator& operator=(const random_number_generator&) = delete; public: NumberT operator()() { return detail::generate_random_number(l, e); } NumberT operator()(const NumberT max) { return detail::generate_random_number(max, l, e); } NumberT operator()(const NumberT min, const NumberT max) { return detail::generate_random_number(min, max, l, e); } public: void seed(const seed_type n) { detail::randomize_rng(n, l, e); } }; template random_number_generator(const NumberT max) -> random_number_generator; } // inline namespace version_* } // namespace ceph::util #endif