#include // bool #include // memset() #include // 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; }