aboutsummaryrefslogtreecommitdiff
path: root/src/km-rand-path.c
blob: c1d011d4740a5f12317b426ebbcb06416de16347 (plain)
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;
}