32 #ifndef VSMC_RNG_COUNTER_HPP 33 #define VSMC_RNG_COUNTER_HPP 43 template <std::
size_t,
typename T, std::
size_t K>
48 template <std::
size_t N,
typename T, std::
size_t K>
51 if (++std::get<N>(ctr) != 0)
54 increment_single<N + 1>(ctr, std::integral_constant<bool, N + 1 < K>());
61 template <
typename T, std::
size_t K>
64 internal::increment_single<0>(ctr, std::true_type());
69 template <
typename T, std::
size_t K, T NSkip>
70 inline void increment(std::array<T, K> &ctr, std::integral_constant<T, NSkip>)
72 if (ctr.front() < std::numeric_limits<T>::max() - NSkip) {
76 internal::increment_single<1>(
77 ctr, std::integral_constant<bool, 1 < K>());
83 template <
typename T, std::
size_t K>
84 inline void increment(std::array<T, K> &ctr, T nskip)
86 if (ctr.front() < std::numeric_limits<T>::max() - nskip) {
90 internal::increment_single<1>(
91 ctr, std::integral_constant<bool, 1 < K>());
98 template <std::
size_t,
typename T, std::
size_t K, std::
size_t Blocks>
100 std::array<std::array<T, K>, Blocks> &, std::false_type)
104 template <std::
size_t B,
typename T, std::
size_t K, std::
size_t Blocks>
106 std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
108 std::get<B>(ctr_block) = ctr;
109 increment_block_set<B + 1>(
110 ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
113 template <std::
size_t,
typename T, std::
size_t K, std::
size_t Blocks>
115 std::array<std::array<T, K>, Blocks> &, std::false_type)
119 template <std::
size_t B,
typename T, std::
size_t K, std::
size_t Blocks>
121 std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
123 increment(std::get<B>(ctr_block), std::integral_constant<T, B + 1>());
124 increment_block<B + 1>(
125 ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
128 template <std::
size_t,
typename T, std::
size_t K, std::
size_t Blocks>
130 std::array<std::array<T, K>, Blocks> &, std::false_type)
134 template <std::
size_t B,
typename T, std::
size_t K, std::
size_t Blocks>
136 std::array<std::array<T, K>, Blocks> &ctr_block, std::true_type)
138 std::get<B>(ctr_block).front() += B + 1;
139 increment_block_safe<B + 1>(
140 ctr, ctr_block, std::integral_constant<bool, B + 1 < Blocks>());
148 template <
typename T, std::
size_t K, std::
size_t Blocks>
150 std::array<T, K> &ctr, std::array<std::array<T, K>, Blocks> &ctr_block)
152 internal::increment_block_set<0>(
153 ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
154 if (ctr.front() < std::numeric_limits<T>::max() -
static_cast<T
>(Blocks)) {
155 internal::increment_block_safe<0>(
156 ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
158 internal::increment_block<0>(
159 ctr, ctr_block, std::integral_constant<bool, 0 < Blocks>());
161 ctr = ctr_block.back();
186 template <
typename ResultType,
typename Generator>
189 static_assert(std::is_unsigned<ResultType>::value,
190 "**CounterEngine** USED WITH ResultType OTHER THAN UNSIGNED INTGER " 193 static_assert(Generator::size() %
sizeof(ResultType) == 0,
194 "**CounterEngine** USED WITH Generator::size() NOT DIVISIBLE BY " 195 "sizeof(ResultType)");
200 using ctr_type =
typename generator_type::ctr_type;
201 using key_type =
typename generator_type::key_type;
206 template <
typename SeedSeq>
221 std::memset(key.data(), 0,
sizeof(
key_type));
222 std::memcpy(key.data(), &s, std::min(
sizeof(s),
sizeof(key)));
226 template <
typename SeedSeq>
229 ResultType,
key_type>::value>::type * =
nullptr)
232 std::array<unsigned,
sizeof(key) /
sizeof(
unsigned) + 1> s;
233 seq.generator(s.begin(), s.end());
234 std::memcpy(key.data(), s.data(), std::min(
sizeof(s),
sizeof(key)));
251 generator_(ctr_, buffer_);
255 return buffer_[
static_cast<std::size_t
>(index_++)];
260 const std::size_t remain =
static_cast<std::size_t
>(M_ - index_);
263 std::copy_n(buffer_.data() + index_, n, r);
264 index_ +=
static_cast<unsigned>(n);
268 std::copy_n(buffer_.data() + index_, remain, r);
273 const std::size_t m = n / M_;
274 generator_(ctr_, m, reinterpret_cast<buffer_type *>(r));
278 generator_(ctr_, buffer_);
279 std::copy_n(buffer_.data(), n, r);
280 index_ =
static_cast<unsigned>(n);
286 const std::size_t remain =
static_cast<std::size_t
>(M_ - index_);
298 if (nskip <= remain) {
299 index_ +=
static_cast<unsigned>(nskip);
306 std::size_t buf_size =
sizeof(buffer_type);
307 std::size_t ctr_size =
sizeof(
ctr_type);
310 generator_(ctr_, buffer_);
311 index_ =
static_cast<unsigned>(nskip % M);
316 return std::numeric_limits<result_type>::min();
321 return std::numeric_limits<result_type>::max();
330 if (eng1.buffer_ != eng2.buffer_)
332 if (eng1.ctr_ != eng2.ctr_)
334 if (eng1.generator_ != eng2.generator_)
336 if (eng1.index_ != eng2.index_)
347 return !(eng1 == eng2);
350 template <
typename CharT,
typename Traits>
352 std::basic_ostream<CharT, Traits> &os,
358 os << eng.buffer_ <<
' ';
359 os << eng.ctr_ <<
' ';
360 os << eng.generator_ <<
' ';
366 template <
typename CharT,
typename Traits>
368 std::basic_istream<CharT, Traits> &is,
375 is >> std::ws >> eng_tmp.buffer_;
376 is >> std::ws >> eng_tmp.ctr_;
377 is >> std::ws >> eng_tmp.generator_;
378 is >> std::ws >> eng_tmp.index_;
381 eng = std::move(eng_tmp);
387 static constexpr
unsigned M_ = Generator::size() /
sizeof(ResultType);
389 using buffer_type = std::array<ResultType, M_>;
399 generator_.reset(key);
404 template <
typename ResultType,
typename Generator>
413 #endif // VSMC_RNG_COUNTER_HPP
void ctr(const ctr_type &c)
void seed(SeedSeq &seq, typename std::enable_if< internal::is_seed_seq< SeedSeq, ResultType, key_type >::value >::type *=nullptr)
friend std::basic_ostream< CharT, Traits > & operator<<(std::basic_ostream< CharT, Traits > &os, const CounterEngine< ResultType, Generator > &eng)
void increment(std::array< T, K > &ctr)
Increment a counter by one.
typename generator_type::key_type key_type
void key(const key_type &k)
CounterEngine(SeedSeq &seq, typename std::enable_if< internal::is_seed_seq< SeedSeq, ResultType, key_type, CounterEngine< ResultType, Generator >>::value >::type *=nullptr)
void increment_block(std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
Counter based RNG engine.
static constexpr result_type max()
void operator()(std::size_t n, result_type *r)
CounterEngine(result_type s=1)
void increment_block_set(const std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
static constexpr result_type min()
friend std::basic_istream< CharT, Traits > & operator>>(std::basic_istream< CharT, Traits > &is, CounterEngine< ResultType, Generator > &eng)
std::size_t discard()
Discard the buffer.
friend bool operator!=(const CounterEngine< ResultType, Generator > &eng1, const CounterEngine< ResultType, Generator > &eng2)
eng1 != eng2 is a necessary condition for subsequent call of operator() output different results...
friend bool operator==(const CounterEngine< ResultType, Generator > &eng1, const CounterEngine< ResultType, Generator > &eng2)
eng1 == eng2 is a sufficent condition for subsequent call of operator() output the same results...
typename ctr_type::value_type skip_type
CounterEngine(const key_type &k)
void discard(skip_type nskip)
void seed(const key_type &key)
typename generator_type::ctr_type ctr_type
void rand(RNGType &rng, ArcsineDistribution< RealType > &dist, std::size_t N, RealType *r)
void increment_block_safe(std::array< T, K > &, std::array< std::array< T, K >, Blocks > &, std::false_type)
void increment_single(std::array< T, K > &, std::false_type)