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
|
#include <stdbool.h> // bool
#include <string.h> // memset()
#include <stdio.h> // fopen()
#include "util.h"
#include "km.h"
#define MAX_BUF_ITEMS (1 << 20)
typedef struct {
FILE *fh;
size_t ofs;
uint64_t buf[MAX_BUF_ITEMS];
} ctx_t;
static inline bool
refill(
ctx_t * const ctx
) {
ctx->ofs = 0;
// D("reading %zu bytes", sizeof(ctx->buf));
return !!fread(ctx->buf, sizeof(ctx->buf), 1, ctx->fh);
}
static bool
next(
ctx_t * const ctx,
uint64_t * const r
) {
if ((ctx->ofs >= MAX_BUF_ITEMS - 1) && !refill(ctx)) {
// return failure
return false;
}
// get next value, increment offset
*r = ctx->buf[ctx->ofs];
ctx->ofs++;
// return success
return true;
}
// get N get_floats
static bool
on_get_floats(
km_rand_t * const rs,
const size_t num_vals,
float * const vals
) {
ctx_t * const ctx = rs->data;
// generate results
for (size_t i = 0; i < num_vals; i++) {
uint64_t v;
if (!next(ctx, &v)) {
// return failure
return false;
}
// add value
vals[i] = 1.0 * v / RAND_MAX;
}
// return success
return true;
}
// fill sizes callback for system random source
static bool
on_get_sizes(
km_rand_t * const rs,
const size_t num_vals,
size_t * const vals
) {
ctx_t * const ctx = rs->data;
// generate results
for (size_t i = 0; i < num_vals; i++) {
uint64_t v;
if (!next(ctx, &v)) {
// return failure
return false;
}
// add value
vals[i] = v;
}
// return success
return true;
}
static void
on_fini(
km_rand_t * const rs
) {
ctx_t * const ctx = rs->data;
// close file
fclose(ctx->fh);
// free context
free(ctx);
rs->data = NULL;
}
// path random source callbacks
static const km_rand_cbs_t
PATH_RAND_CBS = {
.get_floats = on_get_floats,
.get_sizes = on_get_sizes,
.fini = on_fini,
};
// init random source from a file (e.g. "/dev/urandom")
// (NOTE: this method is horribly slow, don't use it)
bool
km_rand_init_path(
km_rand_t * const rs,
const char * const path
) {
// open file
FILE *fh = fopen(path, "rb");
if (!fh) {
// return failure
return false;
}
// alloc context
ctx_t * const ctx = malloc(sizeof(ctx_t));
if (!ctx) {
// return failure
return false;
}
// populate context
ctx->fh = fh;
// fill buffer
if (!refill(ctx)) {
// return failure
return false;
}
// populate random source
rs->cbs = &PATH_RAND_CBS;
rs->data = ctx;
// return success
return true;
}
|