зеркало из https://github.com/github/ruby.git
include/ruby/random.h: add doxygen
Must not be a bad idea to improve documents. [ci skip]
This commit is contained in:
Родитель
1c9106da8b
Коммит
2c4dccad33
|
@ -1,4 +1,4 @@
|
|||
#ifndef RUBY_RANDOM_H
|
||||
#ifndef RUBY_RANDOM_H /*-*-C++-*-vi:se ft=cpp:*/
|
||||
#define RUBY_RANDOM_H 1
|
||||
/**
|
||||
* @file
|
||||
|
@ -8,44 +8,167 @@
|
|||
* 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;
|
||||
typedef struct rb_random_struct rb_random_t; /**< @see ::rb_random_struct */
|
||||
|
||||
typedef void rb_random_init_func(rb_random_t *, const uint32_t *, size_t);
|
||||
typedef unsigned int rb_random_get_int32_func(rb_random_t *);
|
||||
typedef void rb_random_get_bytes_func(rb_random_t *, void *, size_t);
|
||||
typedef double rb_random_get_real_func(rb_random_t *, int);
|
||||
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
|
||||
|
@ -54,23 +177,103 @@ typedef struct {
|
|||
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);
|
||||
void rb_rand_bytes_int32(rb_random_get_int32_func *, rb_random_t *, void *, size_t);
|
||||
|
||||
/**
|
||||
* 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)
|
||||
{
|
||||
|
@ -81,6 +284,15 @@ rb_rand_if(VALUE obj)
|
|||
}
|
||||
|
||||
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)
|
||||
{
|
||||
|
|
Загрузка…
Ссылка в новой задаче