3 #include "ge211_error.hxx"
4 #include "ge211_if_cpp.hxx"
5 #include "ge211_forward.hxx"
6 #include "ge211_type_traits.hxx"
13 #include <type_traits>
22 construct_generator();
26 bound_between(T value, T lo, T hi)
28 return std::max(lo, std::min(hi, value));
31 template <
typename RESULT_TYPE>
34 using result_type = RESULT_TYPE;
36 virtual result_type
next() = 0;
38 virtual result_type next_between(result_type, result_type) = 0;
40 virtual ~Random_engine() =
default;
43 template <
typename RESULT_TYPE,
typename ENABLE =
void>
49 } error =
"ge211::Random_source<RESULT_TYPE> requires "
50 "RESULT_TYPE to be a built-in arithmetic type like int "
54 template <
typename RESULT_TYPE>
57 std::enable_if_t<Is_Integral<RESULT_TYPE>>
61 using result_type = RESULT_TYPE;
68 Distribution(result_type lo, result_type hi)
72 explicit Distribution(result_type end)
76 result_type operator()(Generator &gen)
83 template <
typename RESULT_TYPE>
86 std::enable_if_t<Is_Floating_Point<RESULT_TYPE>>>
89 using result_type = RESULT_TYPE;
96 Distribution(result_type lo, result_type hi)
100 result_type operator()(Generator &gen)
106 template <
typename RESULT_TYPE>
107 class Pseudo_random_engine
108 :
public Random_engine<RESULT_TYPE>
111 using result_type = RESULT_TYPE;
113 template <
typename... Args>
114 Pseudo_random_engine(Args&&... args);
116 result_type
next()
override;
118 result_type next_between(result_type, result_type)
override;
121 Distribution<result_type> distribution_;
122 Generator generator_;
126 class Pseudo_random_engine<bool>
127 :
public Random_engine<bool>
130 explicit Pseudo_random_engine(
double p_true);
132 bool next()
override;
134 bool next_between(
bool,
bool)
override;
138 Distribution<double> distribution_;
139 Generator generator_;
142 template <
typename RESULT_TYPE>
143 class Stub_random_engine
144 :
public Random_engine<RESULT_TYPE>
147 using result_type = RESULT_TYPE;
149 using iterator_type =
typename container_type::const_iterator;
152 Stub_random_engine(container_type&& container);
154 result_type
next()
override;
156 result_type next_between(result_type, result_type)
override;
159 container_type container_;
214 template <
typename RESULT_TYPE>
243 IF_COMPILER(DECLARE_IF(!Is_Same<result_type, bool>))
256 IF_COMPILER(DECLARE_IF(
257 Is_Integral<result_type> &&
258 !Is_Same<result_type, bool>))
287 IF_COMPILER(DECLARE_IF(Is_Same<result_type, bool>))
313 IF_COMPILER(DECLARE_IF(!Is_Same<result_type, bool>))
329 return engine_->next();
383 IF_COMPILER(DECLARE_IF(!Is_Same<result_type, bool>))
386 return engine_->next_between(lo, hi);
396 IF_COMPILER(DECLARE_IF(!Is_Same<result_type, bool>))
477 IF_COMPILER(DECLARE_IF(!Is_Same<result_type, bool>))
490 using Engine = detail::random::Random_engine<result_type>;
491 using Prng = detail::random::Pseudo_random_engine<result_type>;
492 using Stub = detail::random::Stub_random_engine<result_type>;
508 template <
typename RESULT_TYPE>
509 template <
typename... Args>
510 Pseudo_random_engine<RESULT_TYPE>::Pseudo_random_engine(Args&&... args)
511 : distribution_{std::forward<Args>(args)...},
512 generator_{construct_generator()}
515 template <
typename RESULT_TYPE>
517 Pseudo_random_engine<RESULT_TYPE>::next()
519 return distribution_(generator_);
522 template <
typename RESULT_TYPE>
524 Pseudo_random_engine<RESULT_TYPE>::next_between(result_type lo, result_type hi)
526 return Distribution<result_type>{lo, hi}(generator_);
529 template <
typename RESULT_TYPE>
530 Stub_random_engine<RESULT_TYPE>::Stub_random_engine(container_type&& container)
531 : container_(std::move(container)),
532 next_(begin(container_))
534 if (next_ == end(container_)) {
536 "Random_source: cannot stub with empty container"};
540 template <
typename RESULT_TYPE>
542 Stub_random_engine<RESULT_TYPE>::next()
544 result_type result = *next_++;
545 if (next_ == end(container_)) next_ = begin(container_);
549 template <
typename RESULT_TYPE>
551 Stub_random_engine<RESULT_TYPE>::next_between(result_type lo, result_type hi)
553 return bound_between<result_type>(next(), lo, hi);
559 template <
typename RESULT_TYPE>
560 IF_COMPILER(DEFINE_IF)
562 : engine_{std::make_unique<Prng>(lo, hi)}
565 template <
typename RESULT_TYPE>
566 IF_COMPILER(DEFINE_IF)
568 : engine_{std::make_unique<Prng>(limit)}
571 template <
typename RESULT_TYPE>
572 IF_COMPILER(DEFINE_IF)
574 : engine_{std::make_unique<Prng>(p_true)}
577 template <
typename RESULT_TYPE>
578 IF_COMPILER(DEFINE_IF)
583 template <
typename RESULT_TYPE>
587 engine_ = std::make_unique<Stub>(std::move(values));
590 template <
typename RESULT_TYPE>
597 template <
typename RESULT_TYPE>
604 template <
typename RESULT_TYPE>
605 IF_COMPILER(DEFINE_IF)
612 return detail::random::bound_between<result_type>(value, lo, hi);