#ifndef RUBY_RANDOM_H /*-*-C++-*-vi:se ft=cpp:*/ #define RUBY_RANDOM_H 1 /** * @file * @date Sat May 7 11:51:14 JST 2016 * @copyright 2007-2020 Yukihiro Matsumoto * @copyright This file is a part of the programming language Ruby. * Permission is hereby granted, to either redistribute and/or * modify this file, provided that the conditions mentioned in the * file COPYING are met. Consult the file for details. * * This is a set of APIs to roll your own subclass of ::rb_cRandom. An * illustrative example of such PRNG can be found at * `ext/-test-/ramdom/loop.c`. */ #include "ruby/ruby.h" RBIMPL_SYMBOL_EXPORT_BEGIN() /** * Base components of the random interface. * * @internal * * Ideally this could be an empty class if we could assume C++, but in C a * struct must have at least one field. */ struct rb_random_struct { /** Seed, passed through e.g. `Random.new` */ VALUE seed; }; typedef struct rb_random_struct rb_random_t; /**< @see ::rb_random_struct */ RBIMPL_ATTR_NONNULL(()) /** * This is the type of functions called when your random object is initialised. * Passed buffer is the seed object basically. But in Ruby a number can be * really big. This type of functions accept such big integers as a series of * machine words. * * @param[out] rng Your random struct to fill in. * @param[in] buf Seed, maybe converted from a bignum. * @param[in] len Number of words of `buf`. * @post `rng` is initialised using the passed seeds. */ typedef void rb_random_init_func(rb_random_t *rng, const uint32_t *buf, size_t len); RBIMPL_ATTR_NONNULL(()) /** * This is the type of functions called from your object's `#rand` method. * * @param[out] rng Your random struct to extract an integer from. * @return A random number. * @post `rng` is consumed somehow. */ typedef unsigned int rb_random_get_int32_func(rb_random_t *rng); RBIMPL_ATTR_NONNULL(()) /** * This is the type of functions called from your object's `#bytes` method. * * @param[out] rng Your random struct to extract an integer from. * @param[out] buf Return buffer of at least `len` bytes length. * @param[in] len Number of bytes of `buf`. * @post `rng` is consumed somehow. * @post `buf` is filled with random bytes. */ typedef void rb_random_get_bytes_func(rb_random_t *rng, void *buf, size_t len); RBIMPL_ATTR_NONNULL(()) /** * This is the type of functions called from your object's `#rand` method. * * @param[out] rng Your random struct to extract an integer from. * @param[in] excl Pass nonzero value here to indicate you don't want 1.0. * @return A random number of range 0.0 to 1.0. * @post `rng` is consumed somehow. */ typedef double rb_random_get_real_func(rb_random_t *rng, int excl); /** PRNG algorithmic interface, analogous to Ruby level classes. */ typedef struct { /** Number of bits of seed numbers. */ size_t default_seed_bits; /** Initialiser function. */ rb_random_init_func *init; /** Function to obtain a random integer. */ rb_random_get_int32_func *get_int32; /** * Function to obtain a series of random bytes. If your PRNG have a native * method to yield arbitrary number of bytes use that to implement this. * But in case you lack such things, you can do so by using * rb_rand_bytes_int32() * * ```CXX * extern rb_random_get_int32_func your_get_int32_func; * * void * your_get_byes_func(rb_random_t *rng, void *buf, size_t len) * { * rb_rand_bytes_int32(your_get_int32_func, rng, buf, len); * } * ``` */ rb_random_get_bytes_func *get_bytes; /** * Function to obtain a random double. If your PRNG have a native method * to yield a floating point random number use that to implement this. But * in case you lack such things, you can do so by using * rb_int_pair_to_real(). * * ```CXX * extern rb_random_get_int32_func your_get_int32_func; * * void * your_get_real_func(rb_random_t *rng, int excl) * { * auto a = your_get_int32_func(rng); * auto b = your_get_int32_func(rng); * return rb_int_pair_to_real(a, b, excl); * } * ``` */ rb_random_get_real_func *get_real; } rb_random_interface_t; /** * This utility macro defines 3 functions named prefix_init, prefix_get_int32, * prefix_get_bytes. */ #define RB_RANDOM_INTERFACE_DECLARE(prefix) \ static void prefix##_init(rb_random_t *, const uint32_t *, size_t); \ static unsigned int prefix##_get_int32(rb_random_t *); \ static void prefix##_get_bytes(rb_random_t *, void *, size_t) /** * Identical to #RB_RANDOM_INTERFACE_DECLARE except it also declares * prefix_get_real. */ #define RB_RANDOM_INTERFACE_DECLARE_WITH_REAL(prefix) \ RB_RANDOM_INTERFACE_DECLARE(prefix); \ static double prefix##_get_real(rb_random_t *, int) /** * This utility macro expands to the names declared using * #RB_RANDOM_INTERFACE_DECLARE. Expected to be used inside of a * ::rb_random_interface_t initialiser: * * ```CXX * RB_RANDOM_INTERFACE_DECLARE(foo); * * static inline constexpr rb_random_interface_t foo_interface = { * 32768, // bits * RB_RANDOM_INTERFACE_DEFINE(foo), * }; * ``` */ #define RB_RANDOM_INTERFACE_DEFINE(prefix) \ prefix##_init, \ prefix##_get_int32, \ prefix##_get_bytes /** * Identical to #RB_RANDOM_INTERFACE_DEFINE except it also defines * prefix_get_real. */ #define RB_RANDOM_INTERFACE_DEFINE_WITH_REAL(prefix) \ RB_RANDOM_INTERFACE_DEFINE(prefix), \ prefix##_get_real #if defined _WIN32 && !defined __CYGWIN__ typedef rb_data_type_t rb_random_data_type_t; # define RB_RANDOM_PARENT 0 #else /** This is the type of ::rb_random_data_type. */ typedef const rb_data_type_t rb_random_data_type_t; /** * This utility macro can be used when you define your own PRNG type: * * ```CXX * static inline constexpr rb_random_interface_t your_if = { * 0, RB_RANDOM_INTERFACE_DEFINE(your), * }; * * static inline constexpr your_prng = { * "your PRNG", * { rb_random_mark, }, * RB_RANDOM_PARENT, // <<-- HERE * &your_if, * 0, * } * ``` */ # define RB_RANDOM_PARENT &rb_random_data_type #endif /** * This macro is expected to be called exactly once at the beginning of a * program, possibly from inside of your `Init_Foo()` function. Depending on * platforms #RB_RANDOM_PARENT can require a fixup. This routine does that * when necessary. */ #define RB_RANDOM_DATA_INIT_PARENT(random_data) \ rbimpl_random_data_init_parent(&random_data) /** * This is the implementation of ::rb_data_type_struct::dmark for * ::rb_random_data_type. In case your PRNG does not involve Ruby objects at * all (which is quite likely), you can simply reuse it. * * @param[out] ptr Target to mark, which is a ::rb_random_t this case. */ void rb_random_mark(void *ptr); /** * Initialises an allocated ::rb_random_t instance. Call it from your own * initialiser appropriately. * * @param[out] rnd Your PRNG's base part. * @post `rnd` is filled with an initial state. */ void rb_random_base_init(rb_random_t *rnd); /** * Generates a 64 bit floating point number by concatenating two 32bit unsigned * integers. * * @param[in] a Most significant 32 bits of the result. * @param[in] b Least significant 32 bits of the result. * @param[in] excl Whether the result should exclude 1.0 or not. * @return A double, whose range is either `[0, 1)` or `[0, 1]`. * @see ::rb_random_interface_t::get_real() * * @internal * * This in fact has nothing to do with PRNGs. */ double rb_int_pair_to_real(uint32_t a, uint32_t b, int excl); /** * Repeatedly calls the passed function over and over again until the passed * buffer is filled with random bytes. * * @param[in] func Generator function. * @param[out] prng Passed as-is to `func`. * @param[out] buff Return buffer. * @param[in] size Number of words of `buff`. * @post `buff` is filled with random bytes. * @post `prng` is updated by `func`. * @see ::rb_random_interface_t::get_bytes() */ void rb_rand_bytes_int32(rb_random_get_int32_func *func, rb_random_t *prng, void *buff, size_t size); /** * The data that holds the backend type of ::rb_cRandom. Used as your PRNG's * ::rb_data_type_struct::parent. */ RUBY_EXTERN const rb_data_type_t rb_random_data_type; RBIMPL_SYMBOL_EXPORT_END() RBIMPL_ATTR_PURE_UNLESS_DEBUG() /* :TODO: can this function be __attribute__((returns_nonnull)) or not? */ /** * Queries the interface of the passed random object. * * @param[in] obj An instance (of a subclass) of ::rb_cRandom. * @return Its corresponding ::rb_random_interface_t interface. */ static inline const rb_random_interface_t * rb_rand_if(VALUE obj) { RBIMPL_ASSERT_OR_ASSUME(RTYPEDDATA_P(obj)); const struct rb_data_type_struct *t = RTYPEDDATA_TYPE(obj); const void *ret = t->data; return RBIMPL_CAST((const rb_random_interface_t *)ret); } RBIMPL_ATTR_NOALIAS() /** * @private * * This is an implementation detail of #RB_RANDOM_DATA_INIT_PARENT. People * don't use it directly. * * @param[out] random_data Region to fill. * @post ::rb_random_data_type is filled appropriately. */ static inline void rbimpl_random_data_init_parent(rb_random_data_type_t *random_data) { #if defined _WIN32 && !defined __CYGWIN__ random_data->parent = &rb_random_data_type; #endif } #endif /* RUBY_RANDOM_H */