/* rand.c -- rand_r/random_r interface */ /* Copyright (c) 2009-2017 Alex Shinn. All rights reserved. */ /* BSD-style license: http://synthcode.com/license.txt */ #include #include #define SEXP_RANDOM_STATE_SIZE 128 #define ZERO sexp_make_fixnum(0) #define ONE sexp_make_fixnum(1) #define STATE_SIZE sexp_make_fixnum(SEXP_RANDOM_STATE_SIZE) #define sexp_random_source_p(self, x) (!self || ((sexp_pointerp(x) && (sexp_pointer_tag(x) == sexp_unbox_fixnum(sexp_opcode_arg1_type(self)))))) #define sexp_random_state(x) (sexp_slot_ref((x), 0)) #define sexp_random_data(x) ((sexp_random_t*)(&sexp_slot_ref((x), 1))) #define sexp_sizeof_random (sexp_sizeof_header + sizeof(sexp_random_t) + sizeof(sexp)) #ifdef __GNU_SOURCE__ typedef struct random_data sexp_random_t; #define sexp_random_init(rs, seed) \ initstate_r(seed, \ sexp_bytes_data(sexp_random_state(rs)), \ SEXP_RANDOM_STATE_SIZE, \ sexp_random_data(rs)) #define sexp_call_random(rs, dst) random_r(sexp_random_data(rs), &dst) #define sexp_seed_random(n, rs) srandom_r(n, sexp_random_data(rs)) #elif _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _POSIX_SOURCE typedef unsigned int sexp_random_t; #define sexp_random_init(rs, seed) *sexp_random_data(rs) = (seed) #define sexp_call_random(rs, dst) ((dst) = rand_r(sexp_random_data(rs))) #define sexp_seed_random(n, rs) *sexp_random_data(rs) = (n) #else typedef unsigned int sexp_random_t; #define sexp_random_init(rs, seed) (void)0 /* FIXME: MSVC CRT has rand_s() for "cryptographically secure" random number * for WinXP or later. */ #define sexp_call_random(rs, dst) ((dst) = rand()) #define sexp_seed_random(n, rs) srand(n) #endif sexp sexp_rs_random_integer (sexp ctx, sexp self, sexp_sint_t n, sexp rs, sexp bound) { sexp_gc_var1(res); int64_t m; sexp_int32_t m2; #if SEXP_USE_BIGNUMS /* sexp_uint_t mod; */ sexp_uint32_t *data; sexp_int32_t hi, len, i; #endif if (!sexp_random_source_p(self, rs)) return sexp_type_exception(ctx, self, sexp_unbox_fixnum(sexp_opcode_arg1_type(self)), rs); if (sexp_fixnump(bound)) { if (sexp_unbox_fixnum(bound) <= 0) { res = sexp_xtype_exception(ctx, self, "random bound must be positive", bound); } else { /* ensure we have sufficient bits */ for (i=m=0; i <= 1<<(CHAR_BIT*sizeof(m))/RAND_MAX; ++i) { sexp_call_random(rs, m2); m = m * RAND_MAX + m2; } res = sexp_make_fixnum(m % sexp_unbox_fixnum(bound)); } #if SEXP_USE_BIGNUMS } else if (sexp_bignump(bound)) { sexp_gc_preserve1(ctx, res); hi = sexp_bignum_hi(bound); len = hi * (sizeof(sexp_uint_t) / sizeof(sexp_int32_t)); res = sexp_make_bignum(ctx, hi + 1); data = (sexp_uint32_t*) sexp_bignum_data(res); for (i=0; i