diff --git a/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp b/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp index 6f9f9abbcd6..0f1ee8eddc0 100644 --- a/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp +++ b/Examples/Framework/include/ActsExamples/Framework/RandomNumbers.hpp @@ -20,6 +20,7 @@ #include #include +#include namespace ActsExamples { struct AlgorithmContext; @@ -65,4 +66,145 @@ class RandomNumbers { Config m_cfg; }; +/// Distribute entropy from a sequence of input values to a sequence of output +/// values. +/// +/// This function is copied from std::seed_seq::generate() and modified to avoid +/// the intermediate std::vector. +/// +/// @tparam InputIteratorBegin is the type of the input iterator begin +/// @tparam InputIteratorEnd is the type of the input iterator end +/// @tparam OutputIteratorBegin is the type of the output iterator begin +/// @tparam OutputIteratorEnd is the type of the output iterator end +/// +/// @param inputIteratorBegin is the begin of the input sequence +/// @param inputIteratorEnd is the end of the input sequence +/// @param outputIteratorBegin is the begin of the output sequence +/// @param outputIteratorEnd is the end of the output sequence +template +void distributeEntropy(InputIteratorBegin inputIteratorBegin, + InputIteratorEnd inputIteratorEnd, + OutputIteratorBegin outputIteratorBegin, + OutputIteratorEnd outputIteratorEnd) + requires((std::input_iterator && + std::random_access_iterator && + std::is_assignable_v) && + (std::input_iterator && + std::random_access_iterator && + std::is_assignable_v) && + (std::output_iterator && + std::random_access_iterator) && + (std::output_iterator && + std::random_access_iterator)) +{ + using result_type = std::uint_least32_t; + + if (inputIteratorBegin == inputIteratorEnd) { + return; + } + if (outputIteratorBegin == outputIteratorEnd) { + throw std::invalid_argument("outputIteratorBegin == outputIteratorEnd"); + } + + const auto __v_ = inputIteratorBegin; + const auto __v_size = + static_cast(inputIteratorEnd - inputIteratorBegin); + const auto __first = outputIteratorBegin; + const auto __last = outputIteratorEnd; + + std::fill(__first, __last, 0x8b8b8b8b); + const std::size_t __n = static_cast(__last - __first); + const std::size_t __s = __v_size; + const std::size_t __t = (__n >= 623) ? 11 + : (__n >= 68) ? 7 + : (__n >= 39) ? 5 + : (__n >= 7) ? 3 + : (__n - 1) / 2; + const std::size_t __p = (__n - __t) / 2; + const std::size_t __q = __p + __t; + const std::size_t __m = std::max(__s + 1, __n); + // __k = 0; + { + result_type __r = + 1664525 * _Tp(__first[0] ^ __first[__p] ^ __first[__n - 1]); + __first[__p] += __r; + __r += __s; + __first[__q] += __r; + __first[0] = __r; + } + // Initialize indexing terms used with if statements as an optimization to + // avoid calculating modulo n on every loop iteration for each term. + std::size_t __kmodn = 0; // __k % __n + std::size_t __k1modn = __n - 1; // (__k - 1) % __n + std::size_t __kpmodn = __p % __n; // (__k + __p) % __n + std::size_t __kqmodn = __q % __n; // (__k + __q) % __n + + for (std::size_t __k = 1; __k <= __s; ++__k) { + if (++__kmodn == __n) { + __kmodn = 0; + } + if (++__k1modn == __n) { + __k1modn = 0; + } + if (++__kpmodn == __n) { + __kpmodn = 0; + } + if (++__kqmodn == __n) { + __kqmodn = 0; + } + + result_type __r = + 1664525 * _Tp(__first[__kmodn] ^ __first[__kpmodn] ^ __first[__k1modn]); + __first[__kpmodn] += __r; + __r += __kmodn + __v_[__k - 1]; + __first[__kqmodn] += __r; + __first[__kmodn] = __r; + } + for (std::size_t __k = __s + 1; __k < __m; ++__k) { + if (++__kmodn == __n) { + __kmodn = 0; + } + if (++__k1modn == __n) { + __k1modn = 0; + } + if (++__kpmodn == __n) { + __kpmodn = 0; + } + if (++__kqmodn == __n) { + __kqmodn = 0; + } + + result_type __r = + 1664525 * _Tp(__first[__kmodn] ^ __first[__kpmodn] ^ __first[__k1modn]); + __first[__kpmodn] += __r; + __r += __kmodn; + __first[__kqmodn] += __r; + __first[__kmodn] = __r; + } + for (std::size_t __k = __m; __k < __m + __n; ++__k) { + if (++__kmodn == __n) { + __kmodn = 0; + } + if (++__k1modn == __n) { + __k1modn = 0; + } + if (++__kpmodn == __n) { + __kpmodn = 0; + } + if (++__kqmodn == __n) { + __kqmodn = 0; + } + + result_type __r = 1566083941 * _Tp(__first[__kmodn] + __first[__kpmodn] + + __first[__k1modn]); + __first[__kpmodn] ^= __r; + __r -= __kmodn; + __first[__kqmodn] ^= __r; + __first[__kmodn] = __r; + } +} + } // namespace ActsExamples