forked from SevenChords/CipesAtHome
-
Notifications
You must be signed in to change notification settings - Fork 0
/
thread_local_random.h
158 lines (135 loc) · 4.09 KB
/
thread_local_random.h
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
/*
* thread_local_random.h
*
* Created on: Jun 26, 2021
* Author: TechSY730
*/
#ifndef _THREAD_LOCAL_RANDOM_H_
#define _THREAD_LOCAL_RANDOM_H_
#include <stdint.h>
#include "absl/base/attributes.h"
#include "base.h"
#include "openmp_once.h"
extern openmp_once_t _listed_rng_selection_state;
extern bool _local_listed_rng_selection_state;
#pragma omp threadprivate(_local_listed_rng_selection_state)
inline void _printRNGImplementation() {
OPENMP_ONCE_WITH_LOCAL_NAME(_local_listed_rng_selection_state, _listed_rng_selection_state, print_rng_impl) {
printf("Using RNG engine %s\n", _XSTR(_RANDOM_IMPL_STR));
}
OPENMP_ONCE_CLOSE
}
// NOTE: Do not use _RANDOM_IMPL_STR in #if statement, string comparison is not supported in preprocessor state.
// Instead, it should only be used for error reporting
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE
#define _HAS_RANDR 1
#endif
#define _NEED_EXTERN_DEF 1
#if _USE_system_RANDOM
#define _USING_SYSTEM_RAND 1
#elif _USE_lehmer_RANDOM || _USE_wyhash_RANDOM
#include <stdint.h>
typedef uint64_t u_random_output_t;
typedef int64_t random_output_t;
typedef uint64_t random_seed_t;
#elif _USE_pcg_RANDOM
#include <stdint.h>
typedef uint32_t u_random_output_t;
typedef int32_t random_output_t;
#if _CIPES_SUPPORTS_INT128
typedef unsigned __int128 random_seed_t;
#else
typedef unsigned uint64_t random_seed_t;
#endif
#elif _USE_CPP_RANDOM
#undef _NEED_EXTERN_DEF
#define _NEED_EXTERN_DEF 0
#include "cpp_random_adapter.h"
typedef u_random_output_cpp_t u_random_output_t;
typedef random_output_cpp_t random_output_t;
typedef random_seed_cpp_t random_seed_t;
#elif !defined(_RANDOM_IMPL_STR) || _IS_EMPTY(_RANDOM_IMPL_STR) || _RANDOM_IMPL_STR == 0
#define _USING_SYSTEM_RAND 1
#else
#if _NEED_MANUAL_ERROR_DIRECTIVE
#error Unrecognized random implementation selection. See RNG_OPTIONS.md
#else
_COMPILER_ERROR(Unrecognized _STR(_RANDOM_IMPL_STR) (RNG implementation) selected. Value: =_XSTR(_RANDOM_IMPL_STR)\n See RNG_OPTIONS.md)
#endif
#endif
#if _USING_SYSTEM_RAND
#include <stdlib.h>
#include "internal/real_rands.h"
typedef int u_random_output_t;
typedef int random_output_t;
typedef unsigned random_seed_t;
#undef _NEED_EXTERN_DEF
#define _NEED_EXTERN_DEF 0
#endif
#if !_USE_CPP_RANDOM
ABSL_ATTRIBUTE_HOT
#endif
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline random_output_t _internal_scale_to_bounds(random_output_t raw, random_output_t low, random_output_t high) {
// Not an ideal way, but we can tolerate a bit non-uniformity.
_assert_for_shifting_function(low <= high);
return (high - low != 0) ? (raw % (high - low)) + low : low;
}
#if _USING_SYSTEM_RAND && _HAS_RANDR
extern random_seed_t _threadlocal_seed;
#pragma omp threadprivate(_threadlocal_seed)
#endif
#if _NEED_EXTERN_DEF
void threadlocal_rand_init();
void threadlocal_srand(random_seed_t seed);
u_random_output_t threadlocal_rand();
random_output_t threadlocal_randint(random_output_t low, random_output_t high);
void threadlocal_rand_destroy();
#else
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline void threadlocal_rand_init() {
_printRNGImplementation();
#if _USE_CPP_RANDOM
cpp_rand_init();
#endif
}
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline void threadlocal_srand(random_seed_t seed) {
#if _USE_CPP_RANDOM
cpp_srand(seed);
#elif _HAS_RANDR
_threadlocal_seed = seed;
#else
real_srand(seed);
#endif
}
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline u_random_output_t threadlocal_rand() {
#if _USE_CPP_RANDOM
return cpp_rand();
#elif _HAS_RANDR
return rand_r(&_threadlocal_seed);
#else
// Better a thread unsafe rand then nothing.
// But on Windows this is threadsafe for free!
return real_rand();
#endif
}
ABSL_ATTRIBUTE_ALWAYS_INLINE ABSL_ATTRIBUTE_HOT
inline random_output_t threadlocal_randint(random_output_t low, random_output_t high) {
#if _USE_CPP_RANDOM
return cpp_randint(low, high);
#elif _USING_SYSTEM_RAND && _HAS_RANDR
return _internal_scale_to_bounds(threadlocal_rand(), low, high);
#else
return _internal_scale_to_bounds(real_rand(), low, high);
#endif
}
ABSL_ATTRIBUTE_ALWAYS_INLINE
inline void threadlocal_rand_destroy() {
#if _USE_CPP_RANDOM
cpp_rand_destroy();
#endif
}
#endif // _NEED_EXTERN_DEF
#endif /* _THREAD_LOCAL_RANDOM_H_ */