forked from johnsalmon/cpp-counter-based-engine
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathphilox_prf.hpp
109 lines (97 loc) · 4.61 KB
/
philox_prf.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#pragma once
#include "detail.hpp" // a couple of helpful functions and concepts
#include <array>
#include <ranges>
namespace std{
template<typename UIntType, size_t w, size_t n, size_t r, UIntType ... consts>
class philox_prf{
static_assert(w>0);
static_assert(n==2 || n==4); // FIXME - 8, 16?
static_assert(sizeof ...(consts) == n);
// assert that all constants are < 2^w ?
public:
// Differences from P2075R1:
// output_value_type and input_value_type instead of result_type
// output_word_size and input_word_size instead of word_size
using output_value_type = UIntType; // called result_type in P2075R1
using input_value_type = UIntType; // called result_type in P2075R1
static constexpr size_t input_word_size = w; // called word_size in P2075R1
static constexpr size_t output_word_size = w;// called word_size in P2075R1
static constexpr size_t input_count = 3*n/2;
static constexpr size_t output_count = n;
// In P2075R1 this returns void, but it makes more sense to return
// the "final" OutputIterator2
template<typename InputIterator1, typename OutputIterator2>
OutputIterator2 operator()(InputIterator1 input, OutputIterator2 output){
return generate(ranges::single_view(input), output);
}
// This is a candidate for the "iterator-based API" for bulk generation. (Not in P2075R1)
template <ranges::input_range InRange, weakly_incrementable O>
requires ranges::sized_range<InRange> &&
integral<iter_value_t<ranges::range_value_t<InRange>>> &&
integral<iter_value_t<O>> &&
indirectly_writable<O, iter_value_t<O>>
O generate(InRange&& inrange, O result) const {
// FIXME - InRange should be constrained to be a range of
// InputIterators. Each InputIterator will be dereferenced
// exactly 3*n/2 times.
static_assert(is_integral_v<iter_value_t<ranges::range_value_t<InRange>>>);
for(auto initer : inrange){
if constexpr (n == 2){
input_value_type R0 = (*initer++) & inmask;
input_value_type L0 = (*initer++) & inmask;
input_value_type K0 = (*initer++) & inmask;
for(size_t i=0; i<r; ++i){
auto [hi, lo] = detail::mulhilo<w>(R0, MC[0]);
R0 = hi^K0^L0;
L0 = lo;
K0 = (K0+MC[1]) & inmask;
}
*result++ = R0;
*result++ = L0;
}else if constexpr (n == 4) {
input_value_type R0 = (*initer++) & inmask;
input_value_type L0 = (*initer++) & inmask;
input_value_type R1 = (*initer++) & inmask;
input_value_type L1 = (*initer++) & inmask;
input_value_type K0 = (*initer++) & inmask;
input_value_type K1 = (*initer++) & inmask;
for(size_t i=0; i<r; ++i){
auto [hi0, lo0] = detail::mulhilo<w>(R0, MC[0]);
auto [hi1, lo1] = detail::mulhilo<w>(R1, MC[2]);
R0 = hi1^L0^K0;
L0 = lo1;
R1 = hi0^L1^K1;
L1 = lo0;
K0 = (K0 + MC[1]) & inmask;
K1 = (K1 + MC[3]) & inmask;
}
*result++ = R0;
*result++ = L0;
*result++ = R1;
*result++ = L1;
}
// No more cases. See the static_assert(n==2 || n==4) at the top of the class
}
return result;
}
private:
static constexpr array<output_value_type, n> MC = {consts...};
static constexpr input_value_type inmask = detail::fffmask<input_value_type, input_word_size>;
};
// N.B. The template param is 'int r' in P2075R1. I think size_t is more consistent.
template <size_t r>
using philox2x32_prf_r = philox_prf<uint_fast32_t, 32, 2, r, 0xD256D193, 0x9E3779B9>;
template<size_t r>
using philox4x32_prf_r = philox_prf<uint_fast32_t, 32, 4, r, 0xD2511F53, 0x9E3779B9,
0xCD9E8D57, 0xBB67AE85>;
template <size_t r>
using philox2x64_prf_r = philox_prf<uint_fast64_t, 64, 2, r, 0xD2B74407B1CE6E93, 0x9E3779B97F4A7C15>;
template <size_t r>
using philox4x64_prf_r = philox_prf<uint_fast64_t, 64, 4, r, 0xD2E7470EE14C6C93, 0x9E3779B97F4A7C15,
0xCA5A826395121157, 0xBB67AE8584CAA73B>;
using philox2x32_prf = philox2x32_prf_r<10>;
using philox2x64_prf = philox2x64_prf_r<10>;
using philox4x32_prf = philox4x32_prf_r<10>;
using philox4x64_prf = philox4x64_prf_r<10>;
} // namespace std