forked from ceph/ceph
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
common: implement random number generator (following N3551)
Adds new mini-library for random number generation using C++11's <random> header. Refer-to: https://isocpp.org/files/papers/n3551.pdf Signed-off-by: Jesse Williamson <[email protected]>
- Loading branch information
Jesse Williamson
committed
Aug 22, 2017
1 parent
af33c8b
commit 8ac5472
Showing
3 changed files
with
478 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,288 @@ | ||
// -*- 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 <mutex> | ||
#include <random> | ||
|
||
#include "boost/optional.hpp" | ||
|
||
#include "common/backport14.h" | ||
|
||
// Basic random number facility, adapted from N3551: | ||
namespace ceph { | ||
namespace util { | ||
|
||
inline namespace version_1_0 { | ||
|
||
namespace detail { | ||
|
||
template <typename EngineT> | ||
EngineT& engine(); | ||
|
||
template <typename MutexT, typename EngineT> | ||
void randomize_rng(const int seed, MutexT& m, EngineT& e) | ||
{ | ||
std::lock_guard<MutexT> lg(m); | ||
e.seed(seed); | ||
} | ||
|
||
template <typename MutexT, typename EngineT> | ||
void randomize_rng(MutexT& m, EngineT& e) | ||
{ | ||
thread_local std::random_device rd; | ||
|
||
std::lock_guard<MutexT> lg(m); | ||
e.seed(rd()); | ||
} | ||
|
||
template <typename EngineT = std::default_random_engine> | ||
void randomize_rng(const int n) | ||
{ | ||
detail::engine<EngineT>().seed(n); | ||
} | ||
|
||
template <typename EngineT = std::default_random_engine> | ||
void randomize_rng() | ||
{ | ||
thread_local std::random_device rd; | ||
detail::engine<EngineT>().seed(rd()); | ||
} | ||
|
||
template <typename EngineT> | ||
EngineT& engine() | ||
{ | ||
thread_local boost::optional<EngineT> rng_engine; | ||
|
||
if (!rng_engine) { | ||
rng_engine.emplace(EngineT()); | ||
randomize_rng<EngineT>(); | ||
} | ||
|
||
return *rng_engine; | ||
} | ||
|
||
} // namespace detail | ||
|
||
namespace detail { | ||
|
||
template <typename NumberT, | ||
typename DistributionT, | ||
typename EngineT> | ||
NumberT generate_random_number(const NumberT min, const NumberT max, | ||
EngineT& e) | ||
{ | ||
thread_local DistributionT d { min, max }; | ||
|
||
using param_type = typename DistributionT::param_type; | ||
return d(e, param_type { min, max }); | ||
} | ||
|
||
template <typename NumberT, | ||
typename MutexT, | ||
typename DistributionT, | ||
typename EngineT> | ||
NumberT generate_random_number(const NumberT min, const NumberT max, | ||
MutexT& m, EngineT& e) | ||
{ | ||
thread_local DistributionT d { min, max }; | ||
|
||
using param_type = typename DistributionT::param_type; | ||
|
||
std::lock_guard<MutexT> lg(m); | ||
return d(e, param_type { min, max }); | ||
} | ||
|
||
template <typename NumberT, | ||
typename DistributionT, | ||
typename EngineT> | ||
NumberT generate_random_number(const NumberT min, const NumberT max) | ||
{ | ||
return detail::generate_random_number<NumberT, DistributionT, EngineT> | ||
(min, max, detail::engine<EngineT>()); | ||
} | ||
|
||
template <typename MutexT, typename EngineT, | ||
int min = 0, | ||
int max = std::numeric_limits<int>::max(), | ||
typename DistributionT = std::uniform_int_distribution<int>> | ||
int generate_random_number(MutexT& m, EngineT& e) | ||
{ | ||
return detail::generate_random_number<int, MutexT, DistributionT, EngineT> | ||
(min, max, m, e); | ||
} | ||
|
||
} // namespace detail | ||
|
||
template <typename EngineT = std::default_random_engine> | ||
void randomize_rng() | ||
{ | ||
detail::randomize_rng<EngineT>(); | ||
} | ||
|
||
template <int min = 0, | ||
int max = std::numeric_limits<int>::max(), | ||
typename DistributionT = std::uniform_int_distribution<int>, | ||
typename EngineT = std::default_random_engine> | ||
int generate_random_number() | ||
{ | ||
return detail::generate_random_number<int, DistributionT, EngineT> | ||
(min, max); | ||
} | ||
|
||
template <typename IntegerT> | ||
IntegerT generate_random_number(const IntegerT min, const IntegerT max, | ||
ceph::enable_if_t<std::is_integral<IntegerT>::value>* = nullptr) | ||
{ | ||
return detail::generate_random_number<IntegerT, | ||
std::uniform_int_distribution<IntegerT>, | ||
std::default_random_engine> | ||
(min, max); | ||
} | ||
|
||
namespace detail { | ||
|
||
template <typename IntegerT, typename MutexT, typename EngineT> | ||
int generate_random_number(const IntegerT min, const IntegerT max, | ||
MutexT& m, EngineT& e, | ||
ceph::enable_if_t<std::is_integral<IntegerT>::value>* = nullptr) | ||
{ | ||
return detail::generate_random_number<IntegerT, MutexT, | ||
std::uniform_int_distribution<IntegerT>, | ||
EngineT> | ||
(min, max, m, e); | ||
} | ||
|
||
template <typename IntegerT, typename MutexT, typename EngineT> | ||
int generate_random_number(const IntegerT max, | ||
MutexT& m, EngineT& e, | ||
ceph::enable_if_t<std::is_integral<IntegerT>::value>* = nullptr) | ||
{ | ||
constexpr IntegerT zero = 0; | ||
return generate_random_number(zero, max, m, e); | ||
} | ||
|
||
} // namespace detail | ||
|
||
template <typename IntegerT> | ||
int generate_random_number(const IntegerT max, | ||
ceph::enable_if_t<std::is_integral<IntegerT>::value>* = nullptr) | ||
{ | ||
constexpr IntegerT zero = 0; | ||
return generate_random_number(zero, max); | ||
} | ||
|
||
template <typename RealT> | ||
RealT generate_random_number(const RealT min, const RealT max, | ||
ceph::enable_if_t<std::is_floating_point<RealT>::value>* = nullptr) | ||
{ | ||
return detail::generate_random_number<RealT, | ||
std::uniform_real_distribution<RealT>, | ||
std::default_random_engine> | ||
(min, max); | ||
} | ||
|
||
namespace detail { | ||
|
||
template <typename RealT, typename MutexT> | ||
RealT generate_random_number(const RealT max, MutexT& m, | ||
ceph::enable_if_t<std::is_floating_point<RealT>::value>* = nullptr) | ||
{ | ||
constexpr RealT zero = 0.0; | ||
return generate_random_number(zero, max, m); | ||
} | ||
|
||
template <typename RealT, typename MutexT, typename EngineT> | ||
RealT generate_random_number(const RealT min, const RealT max, MutexT& m, EngineT& e, | ||
ceph::enable_if_t<std::is_floating_point<RealT>::value>* = nullptr) | ||
{ | ||
return detail::generate_random_number<RealT, MutexT, | ||
std::uniform_real_distribution<RealT>, | ||
EngineT> | ||
(min, max, m, e); | ||
} | ||
|
||
|
||
template <typename RealT, typename MutexT, typename EngineT> | ||
RealT generate_random_number(const RealT max, MutexT& m, EngineT& e, | ||
ceph::enable_if_t<std::is_floating_point<RealT>::value>* = nullptr) | ||
{ | ||
constexpr RealT zero = 0.0; | ||
return generate_random_number(zero, max, m, e); | ||
} | ||
|
||
} // namespace detail | ||
|
||
template <typename RealT> | ||
RealT generate_random_number(const RealT max, | ||
ceph::enable_if_t<std::is_floating_point<RealT>::value>* = nullptr) | ||
{ | ||
constexpr RealT zero = 0.0; | ||
return generate_random_number(zero, max); | ||
} | ||
|
||
// Function object: | ||
template <typename NumberT> | ||
class random_number_generator final | ||
{ | ||
std::mutex l; | ||
std::random_device rd; | ||
std::default_random_engine e; | ||
|
||
public: | ||
using number_type = NumberT; | ||
|
||
public: | ||
random_number_generator() { | ||
detail::randomize_rng(l, e); | ||
} | ||
|
||
explicit random_number_generator(const int 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 int n) { | ||
detail::randomize_rng(n, l, e); | ||
} | ||
}; | ||
|
||
} // inline namespace version_1_0 | ||
|
||
}} // namespace ceph::util | ||
|
||
#endif |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.