summaryrefslogtreecommitdiff
path: root/ext/-test-/random/loop.c
blob: b789ab1d0177d4f865b4f39c8ef9054284023697 (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
#include "ruby/random.h"

static const uint32_t max_seeds = 1024;

typedef struct {
    rb_random_t base;
    uint32_t num, idx, *buf;
} rand_loop_t;

RB_RANDOM_INTERFACE_DECLARE_WITH_REAL(loop);
static const rb_random_interface_t random_loop_if = {
    32,
    RB_RANDOM_INTERFACE_DEFINE_WITH_REAL(loop)
};

RB_RANDOM_DEFINE_INIT_INT32_FUNC(loop)
static size_t
random_loop_memsize(const void *ptr)
{
    const rand_loop_t *r = ptr;
    return sizeof(*r) + r->num * sizeof(r->buf[0]);
}

static rb_random_data_type_t random_loop_type = {
    "random/loop",
    {
        rb_random_mark,
        RUBY_TYPED_DEFAULT_FREE,
        random_loop_memsize,
    },
    RB_RANDOM_PARENT,
    (void *)&random_loop_if,
    RUBY_TYPED_FREE_IMMEDIATELY
};


static VALUE
loop_alloc(VALUE klass)
{
    rand_loop_t *rnd;
    VALUE obj = TypedData_Make_Struct(klass, rand_loop_t, &random_loop_type, rnd);
    rb_random_base_init(&rnd->base);
    return obj;
}

static void
loop_init(rb_random_t *rnd, const uint32_t *buf, size_t len)
{
    rand_loop_t *r = (rand_loop_t *)rnd;

    if (len > max_seeds) len = max_seeds;

    REALLOC_N(r->buf, uint32_t, len);
    MEMCPY(r->buf, buf, uint32_t, (r->num = (uint32_t)len));
}

static void
loop_get_bytes(rb_random_t *rnd, void *p, size_t n)
{
    uint8_t *buf = p;
    while (n > 0) {
        uint32_t x = loop_get_int32(rnd);
        switch (n % 4) {
          case 0:
            *buf++ = (uint8_t)x;
            n--;
            /* FALLTHROUGH */
          case 3:
            *buf++ = (uint8_t)x;
            n--;
            /* FALLTHROUGH */
          case 2:
            *buf++ = (uint8_t)x;
            n--;
            /* FALLTHROUGH */
          case 1:
            *buf++ = (uint8_t)x;
            n--;
        }
    }
}

static uint32_t
loop_get_int32(rb_random_t *rnd)
{
    rand_loop_t *r = (rand_loop_t *)rnd;
    if (r->idx < r->num) {
        uint32_t x = r->buf[r->idx++];
        if (r->idx >= r->num) r->idx = 0;
        return x;
    }
    else if (r->num) {
        return r->buf[r->idx = 0];
    }
    return 0;
}

static double
loop_get_real(rb_random_t *rnd, int excl)
{
    uint32_t a = loop_get_int32(rnd);
    return ldexp(a, -16);
}

void
Init_random_loop(VALUE mod, VALUE base)
{
    VALUE c = rb_define_class_under(mod, "Loop", base);
    rb_define_alloc_func(c, loop_alloc);
    RB_RANDOM_DATA_INIT_PARENT(random_loop_type);
}