qr_reader-native 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/LICENSE-mruby.txt +22 -0
- data/LICENSE-spinel.txt +19 -0
- data/LICENSE.txt +21 -0
- data/README.md +61 -0
- data/ext/qr_reader_native/SPINEL_VERSION +1 -0
- data/ext/qr_reader_native/extconf.rb +8 -0
- data/ext/qr_reader_native/mruby/error.h +13 -0
- data/ext/qr_reader_native/mruby/internal.h +145 -0
- data/ext/qr_reader_native/mruby/string.h +22 -0
- data/ext/qr_reader_native/mruby.h +93 -0
- data/ext/qr_reader_native/mruby_shim.h +118 -0
- data/ext/qr_reader_native/qr_reader_native.c +13513 -0
- data/ext/qr_reader_native/qr_reader_native.h +29 -0
- data/ext/qr_reader_native/qr_reader_native_ext.c +598 -0
- data/ext/qr_reader_native/re_cased.h +71 -0
- data/ext/qr_reader_native/re_compile.c +5784 -0
- data/ext/qr_reader_native/re_ctype.h +3540 -0
- data/ext/qr_reader_native/re_exec.c +2190 -0
- data/ext/qr_reader_native/re_internal.h +671 -0
- data/ext/qr_reader_native/re_prop.h +4629 -0
- data/ext/qr_reader_native/re_spinel.c +363 -0
- data/ext/qr_reader_native/re_spinel.h +22 -0
- data/ext/qr_reader_native/re_spinel_utf8.inc +97 -0
- data/ext/qr_reader_native/re_utf8.c +156 -0
- data/ext/qr_reader_native/sp_alloc.c +1447 -0
- data/ext/qr_reader_native/sp_alloc.h +1196 -0
- data/ext/qr_reader_native/sp_argf.h +33 -0
- data/ext/qr_reader_native/sp_array.c +1052 -0
- data/ext/qr_reader_native/sp_array.h +456 -0
- data/ext/qr_reader_native/sp_bigint.c +5826 -0
- data/ext/qr_reader_native/sp_bigint.h +117 -0
- data/ext/qr_reader_native/sp_cold.c +5259 -0
- data/ext/qr_reader_native/sp_compat.h +402 -0
- data/ext/qr_reader_native/sp_core.c +818 -0
- data/ext/qr_reader_native/sp_core.h +56 -0
- data/ext/qr_reader_native/sp_crypto.c +877 -0
- data/ext/qr_reader_native/sp_crypto.h +169 -0
- data/ext/qr_reader_native/sp_dtoa.c +1533 -0
- data/ext/qr_reader_native/sp_dtoa.h +29 -0
- data/ext/qr_reader_native/sp_encoding_names.h +172 -0
- data/ext/qr_reader_native/sp_enum.h +86 -0
- data/ext/qr_reader_native/sp_exc.c +1185 -0
- data/ext/qr_reader_native/sp_exc.h +186 -0
- data/ext/qr_reader_native/sp_exc_ctx.h +56 -0
- data/ext/qr_reader_native/sp_fiber.c +889 -0
- data/ext/qr_reader_native/sp_fiber.h +162 -0
- data/ext/qr_reader_native/sp_fiber_ctx.h +84 -0
- data/ext/qr_reader_native/sp_format.c +695 -0
- data/ext/qr_reader_native/sp_format.h +83 -0
- data/ext/qr_reader_native/sp_gc.c +1793 -0
- data/ext/qr_reader_native/sp_gc.h +762 -0
- data/ext/qr_reader_native/sp_hash.c +131 -0
- data/ext/qr_reader_native/sp_hash.h +131 -0
- data/ext/qr_reader_native/sp_inspect.c +215 -0
- data/ext/qr_reader_native/sp_inspect.h +128 -0
- data/ext/qr_reader_native/sp_io.c +1676 -0
- data/ext/qr_reader_native/sp_io.h +272 -0
- data/ext/qr_reader_native/sp_iobuffer.c +1014 -0
- data/ext/qr_reader_native/sp_iobuffer.h +167 -0
- data/ext/qr_reader_native/sp_marshal.c +487 -0
- data/ext/qr_reader_native/sp_marshal.h +60 -0
- data/ext/qr_reader_native/sp_net.c +1029 -0
- data/ext/qr_reader_native/sp_net.h +205 -0
- data/ext/qr_reader_native/sp_pack.c +1254 -0
- data/ext/qr_reader_native/sp_poly_cold.c +1220 -0
- data/ext/qr_reader_native/sp_proc.c +410 -0
- data/ext/qr_reader_native/sp_proc.h +327 -0
- data/ext/qr_reader_native/sp_process.c +547 -0
- data/ext/qr_reader_native/sp_process_status.c +211 -0
- data/ext/qr_reader_native/sp_process_status.h +66 -0
- data/ext/qr_reader_native/sp_random.c +287 -0
- data/ext/qr_reader_native/sp_random.h +52 -0
- data/ext/qr_reader_native/sp_range.h +144 -0
- data/ext/qr_reader_native/sp_re.c +1379 -0
- data/ext/qr_reader_native/sp_re.h +186 -0
- data/ext/qr_reader_native/sp_re_names.h +59 -0
- data/ext/qr_reader_native/sp_sched.c +4044 -0
- data/ext/qr_reader_native/sp_sched.h +295 -0
- data/ext/qr_reader_native/sp_slab.c +1507 -0
- data/ext/qr_reader_native/sp_str.c +1462 -0
- data/ext/qr_reader_native/sp_str.h +306 -0
- data/ext/qr_reader_native/sp_str_crypt.c +23 -0
- data/ext/qr_reader_native/sp_string.c +92 -0
- data/ext/qr_reader_native/sp_string.h +253 -0
- data/ext/qr_reader_native/sp_system.c +78 -0
- data/ext/qr_reader_native/sp_system.h +18 -0
- data/ext/qr_reader_native/sp_time.c +860 -0
- data/ext/qr_reader_native/sp_time.h +100 -0
- data/ext/qr_reader_native/sp_types.h +292 -0
- data/ext/qr_reader_native/spinel_rt.h +19017 -0
- data/ext/qr_reader_native/unicase.c +399 -0
- data/ext/qr_reader_native/unicase.h +901 -0
- data/lib/qr_reader/native.rb +6 -0
- metadata +153 -0
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
/* sp_process_status.c -- Process::Status runtime.
|
|
2
|
+
*
|
|
3
|
+
* The runtime is deliberately tiny: a heap-allocated struct holding
|
|
4
|
+
* pid + raw status, plus the W*() bit-field accessors from
|
|
5
|
+
* <sys/wait.h> wrapped as sp_int-returning helpers. Spinel's
|
|
6
|
+
* boxing layer (sp_box_obj) carries the type tag (cls_id =
|
|
7
|
+
* SP_BUILTIN_PROCESS_STATUS) so the codegen can dispatch
|
|
8
|
+
* `result[1].signaled?` to the right accessor at the call site.
|
|
9
|
+
*
|
|
10
|
+
* This TU is compiled into libspinel_rt.a; it does NOT need
|
|
11
|
+
* spinel_rt.h. It does include sp_alloc.h for sp_gc_alloc.
|
|
12
|
+
*/
|
|
13
|
+
#include <stddef.h>
|
|
14
|
+
#include <stdint.h>
|
|
15
|
+
#include <stdio.h>
|
|
16
|
+
#include <string.h>
|
|
17
|
+
#include <sys/wait.h>
|
|
18
|
+
|
|
19
|
+
#include "sp_alloc.h" /* sp_RbVal, sp_gc_alloc, sp_raise_cls */
|
|
20
|
+
#include "sp_process_status.h"
|
|
21
|
+
|
|
22
|
+
/* The W*() macros must be handed an int LVALUE, not a cast expression. macOS
|
|
23
|
+
still defines them through the legacy `union wait` bridge --
|
|
24
|
+
`#define _W_INT(w) (*(int *)&(w))` -- so the macro takes the ADDRESS of its
|
|
25
|
+
argument, and `WIFEXITED((int)s)` fails to compile there with "cannot take
|
|
26
|
+
the address of an rvalue". glibc casts instead of dereferencing, which is
|
|
27
|
+
why this built on Linux. Each accessor below copies its sp_int argument
|
|
28
|
+
into `int st` first and passes that. */
|
|
29
|
+
|
|
30
|
+
/* CRuby answers nil for exitstatus on a signaled status and for termsig on
|
|
31
|
+
one that exited, and spinel already has a spelling for a nullable Integer:
|
|
32
|
+
SP_INT_NIL, which every renderer and `.nil?` understands. -1 is a real
|
|
33
|
+
Integer here -- `p st.termsig` printed -1 rather than nil. */
|
|
34
|
+
#define SP_STATUS_NIL SP_INT_NIL
|
|
35
|
+
|
|
36
|
+
/* ---- allocator ---- */
|
|
37
|
+
|
|
38
|
+
sp_ProcessStatus *sp_process_status_recv(sp_ProcessStatus *p, const char *meth) {
|
|
39
|
+
extern void sp_nil_recv(const char *meth); /* sp_str.c */
|
|
40
|
+
if (!p) sp_nil_recv(meth);
|
|
41
|
+
return p;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
sp_ProcessStatus *sp_last_process_status(void) {
|
|
45
|
+
extern int sp_last_status, sp_last_pid; /* sp_system.c */
|
|
46
|
+
if (!sp_last_pid) return NULL;
|
|
47
|
+
sp_ProcessStatus *p = (sp_ProcessStatus *)sp_gc_alloc(sizeof(sp_ProcessStatus), NULL, NULL);
|
|
48
|
+
if (!p) sp_raise_cls("NoMemoryError", "out of memory");
|
|
49
|
+
p->pid = sp_last_pid;
|
|
50
|
+
p->status = sp_last_status;
|
|
51
|
+
return p;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
sp_ProcessStatus *sp_process_status_new(sp_int pid, sp_int status) {
|
|
55
|
+
if (status < 0 || status > 0xFFFF) {
|
|
56
|
+
sp_raise_cls("ArgumentError", "invalid status word");
|
|
57
|
+
}
|
|
58
|
+
sp_ProcessStatus *p = (sp_ProcessStatus *)sp_gc_alloc(sizeof(sp_ProcessStatus), NULL, NULL);
|
|
59
|
+
if (!p) sp_raise_cls("NoMemoryError", "out of memory");
|
|
60
|
+
p->pid = pid;
|
|
61
|
+
p->status = status;
|
|
62
|
+
return p;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/* sp_box_process_status is declared in sp_alloc.h (with a forward
|
|
66
|
+
struct decl, so sp_alloc.h does not need to include
|
|
67
|
+
sp_process_status.h). The impl lives here so a TU that links
|
|
68
|
+
against the runtime (e.g. sp_process.c) does not need to
|
|
69
|
+
include sp_process_status.h to box a Status. */
|
|
70
|
+
sp_RbVal sp_box_process_status(sp_ProcessStatus *p) {
|
|
71
|
+
return sp_box_obj(p, SP_BUILTIN_PROCESS_STATUS);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/* ---- predicates ---- */
|
|
75
|
+
|
|
76
|
+
int sp_process_status_exited_p(sp_int s) {
|
|
77
|
+
int st = (int)s;
|
|
78
|
+
return WIFEXITED(st) ? 1 : 0;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
int sp_process_status_signaled_p(sp_int s) {
|
|
82
|
+
int st = (int)s;
|
|
83
|
+
return WIFSIGNALED(st) ? 1 : 0;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
int sp_process_status_coredump_p(sp_int s) {
|
|
87
|
+
int st = (int)s;
|
|
88
|
+
if (!WIFSIGNALED(st)) return 0;
|
|
89
|
+
return WCOREDUMP(st) ? 1 : 0;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/* Tri-state, because CRuby's is: true when the process exited with status 0,
|
|
93
|
+
false when it exited with anything else, and NIL when it did not exit
|
|
94
|
+
normally at all. -1 is that nil; the call site boxes it. */
|
|
95
|
+
int sp_process_status_success_p(sp_int s) {
|
|
96
|
+
int st = (int)s;
|
|
97
|
+
if (!WIFEXITED(st)) return -1;
|
|
98
|
+
return WEXITSTATUS(st) == 0 ? 1 : 0;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/* ---- accessors ---- */
|
|
102
|
+
|
|
103
|
+
sp_int sp_process_status_pid(sp_int s) {
|
|
104
|
+
/* The runtime only sees the status word (the pid travels alongside
|
|
105
|
+
in the boxed struct). Returning the lower byte of the status is
|
|
106
|
+
wrong -- the pid is a separate field. The pid is in the boxed
|
|
107
|
+
struct, accessible via sp_ProcessStatus*.pid. To keep the
|
|
108
|
+
signature simple the accessor takes the status word; the pid
|
|
109
|
+
access is plumbed via a separate sp_process_status_pid_of helper
|
|
110
|
+
that takes the boxed struct. */
|
|
111
|
+
/* This path is unused: the codegen path uses
|
|
112
|
+
sp_process_status_pid_of for the boxed struct. */
|
|
113
|
+
(void)s;
|
|
114
|
+
return 0;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
sp_int sp_process_status_exitstatus(sp_int s) {
|
|
118
|
+
int st = (int)s;
|
|
119
|
+
if (!WIFEXITED(st)) return SP_STATUS_NIL;
|
|
120
|
+
return (sp_int)WEXITSTATUS(st);
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
sp_int sp_process_status_termsig(sp_int s) {
|
|
124
|
+
int st = (int)s;
|
|
125
|
+
if (!WIFSIGNALED(st)) return SP_STATUS_NIL;
|
|
126
|
+
return (sp_int)WTERMSIG(st);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/* ---- boxed-struct pid access ---- */
|
|
130
|
+
/* The codegen needs the pid of a boxed Process::Status. The runtime
|
|
131
|
+
accessor signatures above take the raw status word, so the pid
|
|
132
|
+
accessor goes through a separate helper that takes the boxed
|
|
133
|
+
struct directly. */
|
|
134
|
+
|
|
135
|
+
sp_int sp_process_status_pid_of(sp_ProcessStatus *st) {
|
|
136
|
+
return st->pid;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/* ---- equality ---- */
|
|
140
|
+
|
|
141
|
+
int sp_process_status_eq(sp_int a, sp_int b) {
|
|
142
|
+
return a == b;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/* ---- to_s / inspect ----
|
|
146
|
+
*
|
|
147
|
+
* CRuby renders:
|
|
148
|
+
* exited normally: "exit 0" (or "exited" prefix for inspect)
|
|
149
|
+
* signaled: "signal 9 (SIGKILL)" (or "signaled" prefix for inspect)
|
|
150
|
+
* unknown: ""? (CRuby raises; we return a generic string)
|
|
151
|
+
*
|
|
152
|
+
* The output goes into a static buffer; the codegen copies it via
|
|
153
|
+
* sp_str_dup_external when boxing the result as a String.
|
|
154
|
+
*/
|
|
155
|
+
|
|
156
|
+
static const char *sp_signal_name(int sig) {
|
|
157
|
+
/* A short list. CRuby maps every signal; we cover the common ones
|
|
158
|
+
so dvtm's signal detection reads naturally in log output. */
|
|
159
|
+
switch (sig) {
|
|
160
|
+
case 1: return "SIGHUP";
|
|
161
|
+
case 2: return "SIGINT";
|
|
162
|
+
case 3: return "SIGQUIT";
|
|
163
|
+
case 4: return "SIGILL";
|
|
164
|
+
case 6: return "SIGABRT";
|
|
165
|
+
case 8: return "SIGFPE";
|
|
166
|
+
case 9: return "SIGKILL";
|
|
167
|
+
case 11: return "SIGSEGV";
|
|
168
|
+
case 13: return "SIGPIPE";
|
|
169
|
+
case 15: return "SIGTERM";
|
|
170
|
+
case 24: return "SIGXCPU";
|
|
171
|
+
default: return NULL;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
static SP_TLS char sp_status_buf[96];
|
|
176
|
+
|
|
177
|
+
const char *sp_process_status_to_s(sp_int pid, sp_int s, int is_inspect) {
|
|
178
|
+
/* CRuby's pst_message: "pid N", then how the child ended */
|
|
179
|
+
const char *prefix = is_inspect ? "#<Process::Status: " : "";
|
|
180
|
+
const char *suffix = is_inspect ? ">" : "";
|
|
181
|
+
int st = (int)s;
|
|
182
|
+
if (WIFEXITED(st)) {
|
|
183
|
+
snprintf(sp_status_buf, sizeof sp_status_buf,
|
|
184
|
+
"%spid %lld exit %d%s", prefix, (long long)pid, WEXITSTATUS(st), suffix);
|
|
185
|
+
}
|
|
186
|
+
else if (WIFSIGNALED(st)) {
|
|
187
|
+
int sig = WTERMSIG(st);
|
|
188
|
+
const char *name = sp_signal_name(sig);
|
|
189
|
+
const char *core = WCOREDUMP(st) ? " (core dumped)" : "";
|
|
190
|
+
if (name) {
|
|
191
|
+
snprintf(sp_status_buf, sizeof sp_status_buf,
|
|
192
|
+
"%spid %lld %s (signal %d)%s%s", prefix, (long long)pid, name, sig, core, suffix);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
snprintf(sp_status_buf, sizeof sp_status_buf,
|
|
196
|
+
"%spid %lld signal %d%s%s", prefix, (long long)pid, sig, core, suffix);
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
else {
|
|
200
|
+
snprintf(sp_status_buf, sizeof sp_status_buf,
|
|
201
|
+
"%spid %lld status 0x%llx%s", prefix, (long long)pid, (unsigned long long)s, suffix);
|
|
202
|
+
}
|
|
203
|
+
return sp_status_buf;
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
/* A fresh String each call: the rendering's static buffer is shared, and
|
|
207
|
+
`[$?.to_s, $?.inspect]` read the second rendering twice. */
|
|
208
|
+
const char *sp_process_status_str(sp_ProcessStatus *p, int is_inspect) {
|
|
209
|
+
if (!p) return sp_str_dup_external(is_inspect ? "nil" : "");
|
|
210
|
+
return sp_str_dup_external(sp_process_status_to_s(p->pid, p->status, is_inspect));
|
|
211
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/* sp_process_status.h -- Process::Status value type.
|
|
2
|
+
*
|
|
3
|
+
* Process.waitpid2 returns [pid, status] where status is a
|
|
4
|
+
* Process::Status instance. This file provides the boxed runtime
|
|
5
|
+
* type plus the small set of predicates and accessors CRuby
|
|
6
|
+
* exposes on Process::Status.
|
|
7
|
+
*
|
|
8
|
+
* Layout: a single int (the raw waitpid(2) status word) plus the
|
|
9
|
+
* pid of the child the status is from. Heap-allocated because
|
|
10
|
+
* the per-instance id-tag is needed for the typecheck on
|
|
11
|
+
* `result[1].signaled?` and the like; the struct itself is small
|
|
12
|
+
* (16 bytes) so the allocation is cheap.
|
|
13
|
+
*/
|
|
14
|
+
#ifndef SP_PROCESS_STATUS_H
|
|
15
|
+
#define SP_PROCESS_STATUS_H
|
|
16
|
+
|
|
17
|
+
#include <stdint.h>
|
|
18
|
+
#include "sp_types.h" /* sp_int */
|
|
19
|
+
|
|
20
|
+
typedef struct sp_ProcessStatus_s {
|
|
21
|
+
sp_int pid;
|
|
22
|
+
sp_int status; /* the raw waitpid(2) status word */
|
|
23
|
+
} sp_ProcessStatus;
|
|
24
|
+
|
|
25
|
+
/* Boxed new: takes pid + raw status word. Returns a sp_ProcessStatus *
|
|
26
|
+
on the GC heap. Raises TypeError on a non-Integer pid or negative
|
|
27
|
+
status. */
|
|
28
|
+
sp_ProcessStatus *sp_process_status_new(sp_int pid, sp_int status);
|
|
29
|
+
|
|
30
|
+
/* `$?`: the status of the last child waited for (Kernel#system, a
|
|
31
|
+
backtick, Process.wait*), or NULL -- nil -- before any. A new object on
|
|
32
|
+
each read, carrying the raw status word as it was stored. */
|
|
33
|
+
sp_ProcessStatus *sp_last_process_status(void);
|
|
34
|
+
|
|
35
|
+
/* A reader's receiver: NULL is nil, which has none of the readers, so it
|
|
36
|
+
raises NoMethodError ("undefined method 'exitstatus' for nil"). */
|
|
37
|
+
sp_ProcessStatus *sp_process_status_recv(sp_ProcessStatus *p, const char *meth);
|
|
38
|
+
|
|
39
|
+
/* to_s / inspect of a status, or of nil ("" / "nil") for NULL */
|
|
40
|
+
const char *sp_process_status_str(sp_ProcessStatus *p, int is_inspect);
|
|
41
|
+
|
|
42
|
+
/* Predicates. All return 0 or 1 except success_p, which is tri-state: -1
|
|
43
|
+
means CRuby's nil (the process did not exit normally). */
|
|
44
|
+
int sp_process_status_exited_p(sp_int s);
|
|
45
|
+
int sp_process_status_signaled_p(sp_int s);
|
|
46
|
+
int sp_process_status_coredump_p(sp_int s);
|
|
47
|
+
int sp_process_status_success_p(sp_int s);
|
|
48
|
+
|
|
49
|
+
/* Accessors. CRuby semantics: exited? -> exitstatus, signaled? -> termsig;
|
|
50
|
+
the un-applicable accessor answers nil, carried as SP_INT_NIL -- the
|
|
51
|
+
nullable-Integer sentinel the rest of the runtime uses, so `p st.termsig`
|
|
52
|
+
renders nil and `st.termsig.nil?` is true. */
|
|
53
|
+
sp_int sp_process_status_pid(sp_int s);
|
|
54
|
+
sp_int sp_process_status_exitstatus(sp_int s);
|
|
55
|
+
sp_int sp_process_status_termsig(sp_int s);
|
|
56
|
+
|
|
57
|
+
/* Render the status to a string for to_s / inspect. The result lives
|
|
58
|
+
in a static buffer; the runtime copies it to a GC-heap string for
|
|
59
|
+
return. */
|
|
60
|
+
const char *sp_process_status_to_s(sp_int pid, sp_int s, int is_inspect);
|
|
61
|
+
|
|
62
|
+
/* Equality: two Process::Status values are equal iff their status
|
|
63
|
+
words are equal. pid is not compared. */
|
|
64
|
+
int sp_process_status_eq(sp_int a, sp_int b);
|
|
65
|
+
|
|
66
|
+
#endif
|
|
@@ -0,0 +1,287 @@
|
|
|
1
|
+
/* sp_random.c -- the shared Kernel-level PRNG stream and the Random
|
|
2
|
+
instance methods (see sp_random.h). */
|
|
3
|
+
#include <time.h>
|
|
4
|
+
#include <string.h>
|
|
5
|
+
#include "sp_random.h"
|
|
6
|
+
#include "sp_crypto.h" /* sp_crypto_entropy: the one secure source */
|
|
7
|
+
#include "sp_alloc.h"
|
|
8
|
+
#include <math.h> /* isnan/isinf for the EDOM domain checks */ /* sp_str_alloc / sp_str_set_len / sp_float_to_s / sp_raise_cls / sp_gc_alloc */
|
|
9
|
+
#include "sp_format.h" /* sp_Range_inspect */
|
|
10
|
+
#include "sp_str.h" /* sp_sprintf (defined in the generated TU) */
|
|
11
|
+
#include "sp_range.h" /* sp_range_int_only */
|
|
12
|
+
|
|
13
|
+
/* PCG-XSH-RR constants (64-bit state, 32-bit output). */
|
|
14
|
+
#define SP_PCG_MULT 6364136223846793005ULL
|
|
15
|
+
#define SP_PCG_INC 1442695040888963407ULL
|
|
16
|
+
|
|
17
|
+
uint32_t sp_pcg32_adv(uint64_t *state) {
|
|
18
|
+
uint64_t old = *state;
|
|
19
|
+
*state = old * SP_PCG_MULT + SP_PCG_INC;
|
|
20
|
+
/* output: xorshift-high folds the state, then a random rotate */
|
|
21
|
+
uint32_t xs = (uint32_t)(((old >> 18u) ^ old) >> 27u);
|
|
22
|
+
uint32_t rot = (uint32_t)(old >> 59u);
|
|
23
|
+
return (xs >> rot) | (xs << ((32 - rot) & 31));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/* The PCG init sequence: zero the state, step, add the seed, then mix.
|
|
27
|
+
The extra mixing rounds keep nearby seeds from producing correlated
|
|
28
|
+
early output. */
|
|
29
|
+
void sp_pcg_seed(uint64_t *state, uint64_t seed) {
|
|
30
|
+
*state = 0;
|
|
31
|
+
(void)sp_pcg32_adv(state);
|
|
32
|
+
*state += seed;
|
|
33
|
+
for (int i = 0; i < 10; i++) (void)sp_pcg32_adv(state);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/* Per-worker (SP_TLS) in the threaded build: the generator has no
|
|
37
|
+
internal lock, so a shared stream would race across workers. */
|
|
38
|
+
static SP_TLS uint64_t sp_krand_state;
|
|
39
|
+
static SP_TLS int sp_krand_seeded;
|
|
40
|
+
|
|
41
|
+
void sp_krand_srand(uint64_t seed) {
|
|
42
|
+
sp_pcg_seed(&sp_krand_state, seed);
|
|
43
|
+
sp_krand_seeded = 1;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
uint64_t sp_krand_next(void) {
|
|
47
|
+
if (!sp_krand_seeded) {
|
|
48
|
+
/* Auto-seed on first draw, mirroring CRuby's startup seeding so
|
|
49
|
+
unseeded rand/shuffle/sample vary per run. time() alone repeats
|
|
50
|
+
within a second; mix in clock() and the per-worker state address. */
|
|
51
|
+
sp_krand_srand((uint64_t)time(NULL) ^ ((uint64_t)clock() << 24) ^
|
|
52
|
+
(uint64_t)(uintptr_t)&sp_krand_state);
|
|
53
|
+
}
|
|
54
|
+
uint64_t hi = sp_pcg32_adv(&sp_krand_state);
|
|
55
|
+
return (hi << 32) | sp_pcg32_adv(&sp_krand_state);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
sp_int sp_krand_below(sp_int n) {
|
|
59
|
+
if (n <= 0) return 0;
|
|
60
|
+
/* uniform in [0, n) without modulo bias: reject draws below the
|
|
61
|
+
wrap-around threshold (0 for powers of two, so the loop is rare) */
|
|
62
|
+
uint64_t umax = (uint64_t)n;
|
|
63
|
+
uint64_t threshold = (uint64_t)(-(int64_t)umax) % umax;
|
|
64
|
+
uint64_t r;
|
|
65
|
+
do {
|
|
66
|
+
r = sp_krand_next();
|
|
67
|
+
} while (r < threshold);
|
|
68
|
+
return (sp_int)(r % umax);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
sp_float sp_krand_float(void) {
|
|
72
|
+
return (sp_float)(sp_krand_next() >> 11) / (sp_float)(1ULL << 53);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/* ---- Random instance methods ---- */
|
|
76
|
+
|
|
77
|
+
/* The default stream is a static, not a GC allocation -- but the class-method
|
|
78
|
+
forms (`Random.bytes`, `Random.rand`) hand it to the same entry points an
|
|
79
|
+
instance uses, and those root their receiver, which puts a .bss address on
|
|
80
|
+
the mark path. Lay a 0xfd skip byte directly before it so sp_gc_mark's
|
|
81
|
+
tag-byte protocol bails out instead of reading whatever precedes it as a GC
|
|
82
|
+
header: under SPINEL_GC_STRESS=1 that read reached a bogus scan hook and
|
|
83
|
+
crashed inside the mark walk. Same shape, and the same reason, as the root
|
|
84
|
+
fiber in sp_fiber.c: the guard array is exactly one alignment unit, so its
|
|
85
|
+
last byte always directly precedes the struct with no padding in between. */
|
|
86
|
+
static SP_TLS struct { char guard[_Alignof(sp_Random)]; sp_Random r; } sp_random_default_box
|
|
87
|
+
= { .guard = { [_Alignof(sp_Random) - 1] = (char)0xfd } };
|
|
88
|
+
#define sp_random_default (sp_random_default_box.r)
|
|
89
|
+
uint64_t sp_random_next(sp_Random *r) {SP_GC_ROOT(r);
|
|
90
|
+
if (r == &sp_random_default) return sp_krand_next();
|
|
91
|
+
uint64_t hi = sp_pcg32_adv(&r->state);
|
|
92
|
+
return (hi << 32) | sp_pcg32_adv(&r->state);
|
|
93
|
+
}
|
|
94
|
+
sp_Random *sp_Random_new(sp_int seed) {
|
|
95
|
+
sp_Random *r = (sp_Random *)sp_gc_alloc(sizeof(sp_Random), NULL, NULL);
|
|
96
|
+
sp_pcg_seed(&r->state, (uint64_t)seed);
|
|
97
|
+
r->seed = seed;
|
|
98
|
+
return r;
|
|
99
|
+
}
|
|
100
|
+
/* Random#dup / #clone: a distinct generator that continues from the same state. */
|
|
101
|
+
sp_Random *sp_Random_dup(sp_Random *r) {
|
|
102
|
+
if (!r) return NULL; /* nil.dup is nil */
|
|
103
|
+
SP_GC_ROOT(r);
|
|
104
|
+
sp_Random *d = (sp_Random *)sp_gc_alloc(sizeof(sp_Random), NULL, NULL);
|
|
105
|
+
*d = *r;
|
|
106
|
+
return d;
|
|
107
|
+
}
|
|
108
|
+
/* Random.new(Float): CRuby truncates the float to an integer seed. A plain
|
|
109
|
+
(sp_int) cast is UB when the truncated value is out of range, so seed from
|
|
110
|
+
the in-range truncation when it fits and from the raw float bits otherwise
|
|
111
|
+
-- always deterministic (same float -> same stream), which is the actual
|
|
112
|
+
contract (the exact sequence is not MT19937 anyway). */
|
|
113
|
+
sp_Random *sp_Random_new_float(sp_float f) {
|
|
114
|
+
uint64_t s;
|
|
115
|
+
if (f >= -9.2233720368547758e18 && f < 9.2233720368547758e18) {
|
|
116
|
+
s = (uint64_t)(int64_t)f;
|
|
117
|
+
}
|
|
118
|
+
else {
|
|
119
|
+
uint64_t bits; memcpy(&bits, &f, sizeof bits);
|
|
120
|
+
s = bits;
|
|
121
|
+
}
|
|
122
|
+
sp_Random *r = (sp_Random *)sp_gc_alloc(sizeof(sp_Random), NULL, NULL);
|
|
123
|
+
sp_pcg_seed(&r->state, s);
|
|
124
|
+
r->seed = (sp_int)s;
|
|
125
|
+
return r;
|
|
126
|
+
}
|
|
127
|
+
/* Random#seed: the seed the instance was constructed from. */
|
|
128
|
+
sp_int sp_Random_seed(sp_Random *r) { return r ? r->seed : 0; }
|
|
129
|
+
/* Random#== compares by internal state (two same-seed, same-position instances
|
|
130
|
+
are equal; advancing one makes them differ). */
|
|
131
|
+
sp_bool sp_Random_eq(sp_Random *a, sp_Random *b) {
|
|
132
|
+
if (a == b) return TRUE;
|
|
133
|
+
if (!a || !b) return FALSE;
|
|
134
|
+
return (a->state == b->state && a->seed == b->seed) ? TRUE : FALSE;
|
|
135
|
+
}
|
|
136
|
+
/* Random.new with no seed: OS-entropy-ish auto seed. time() alone made two
|
|
137
|
+
instances created in the same second identical; mix in a per-thread counter
|
|
138
|
+
and the object address so every instance gets its own stream. */
|
|
139
|
+
sp_Random *sp_Random_new_auto(void) {
|
|
140
|
+
static SP_TLS uint64_t sp_random_auto_ctr = 0;
|
|
141
|
+
sp_Random *r = (sp_Random *)sp_gc_alloc(sizeof(sp_Random), NULL, NULL);
|
|
142
|
+
uint64_t e = (((uint64_t)time(NULL)) << 20) ^ (++sp_random_auto_ctr * 0x9E3779B97F4A7C15ULL) ^
|
|
143
|
+
(uint64_t)(uintptr_t)r;
|
|
144
|
+
sp_pcg_seed(&r->state, e);
|
|
145
|
+
r->seed = (sp_int)(e >> 1);
|
|
146
|
+
return r;
|
|
147
|
+
}
|
|
148
|
+
/* Random#rand(Range): an integer in the (int-endpoint) range, empty raises. */
|
|
149
|
+
sp_int sp_Random_rand_range(sp_Random *r, sp_Range rg) {SP_GC_ROOT(r);
|
|
150
|
+
sp_range_int_only(rg, "Random#rand"); /* (1..2.5): CRuby answers a Float */
|
|
151
|
+
/* an open side has no span: CRuby's Errno::EDOM, where the sentinel drew
|
|
152
|
+
from a span of the whole sp_int range */
|
|
153
|
+
if (rg.first == INTPTR_MIN || rg.last == INTPTR_MAX)
|
|
154
|
+
sp_raise_cls("Errno::EDOM", "Numerical argument out of domain");
|
|
155
|
+
sp_int lo = rg.first, hi = rg.excl ? rg.last - 1 : rg.last;
|
|
156
|
+
if (hi < lo) sp_raise_cls("ArgumentError", sp_sprintf("invalid argument - %s", sp_Range_inspect(&rg)));
|
|
157
|
+
if (!r) return lo;
|
|
158
|
+
return lo + (sp_int)(sp_random_next(r) % ((uint64_t)(hi - lo) + 1));
|
|
159
|
+
}
|
|
160
|
+
sp_int sp_Random_rand_int(sp_Random *r, sp_int n) {SP_GC_ROOT(r);
|
|
161
|
+
if (n <= 0) sp_raise_cls("ArgumentError", sp_sprintf("invalid argument - %lld", (long long)n));
|
|
162
|
+
if (!r) return 0;
|
|
163
|
+
return (sp_int)(sp_random_next(r) % (uint64_t)n);
|
|
164
|
+
}
|
|
165
|
+
sp_float sp_Random_rand_float(sp_Random *r) {SP_GC_ROOT(r);
|
|
166
|
+
if (!r) return 0.0;
|
|
167
|
+
return (sp_float)(sp_random_next(r) >> 11) / (sp_float)(1ULL << 53);
|
|
168
|
+
}
|
|
169
|
+
/* Random#rand(Float bound): a random Float in [0, bound). A non-positive bound
|
|
170
|
+
raises ArgumentError like the Integer form (MRI validates both). */
|
|
171
|
+
sp_float sp_Random_rand_float_bound(sp_Random *r, sp_float bound) {SP_GC_ROOT(r);
|
|
172
|
+
/* CRuby 4: a non-finite bound is Errno::EDOM; a 0.0 bound draws in [0,1) (#3049) */
|
|
173
|
+
if (isnan(bound) || isinf(bound))
|
|
174
|
+
sp_raise_cls("Errno::EDOM", "Numerical argument out of domain");
|
|
175
|
+
if (bound == 0.0) return sp_Random_rand_float(r);
|
|
176
|
+
if (bound < 0) sp_raise_cls("ArgumentError", sp_sprintf("invalid argument - %s", sp_float_to_s(bound)));
|
|
177
|
+
return sp_Random_rand_float(r) * bound;
|
|
178
|
+
}
|
|
179
|
+
/* Class-method forms (`Random.rand` / `Random.bytes`) share the default
|
|
180
|
+
instance, mirroring CRuby's Random::DEFAULT. Its draws redirect to the
|
|
181
|
+
shared Kernel stream (see sp_random_next), which lazily self-seeds and
|
|
182
|
+
is per-worker in the threaded build. */
|
|
183
|
+
sp_Random *sp_random_default_get(void) {
|
|
184
|
+
return &sp_random_default;
|
|
185
|
+
}
|
|
186
|
+
/* Random#bytes(n) -- n random bytes as a String, tagged ASCII-8BIT as CRuby
|
|
187
|
+
does. sp_str_set_len alone was not enough: #length counts UTF-8 units, and a
|
|
188
|
+
short draw is valid UTF-8 by chance often enough that Random.bytes(8).length
|
|
189
|
+
answered less than 8 about three times in a thousand. That is #3474, which
|
|
190
|
+
fixed urandom eight lines below and left this one. */
|
|
191
|
+
const char *sp_Random_bytes(sp_Random *r, sp_int n) {SP_GC_ROOT(r);
|
|
192
|
+
if (n < 0) sp_raise_cls("ArgumentError", "negative string size (or size too big)");
|
|
193
|
+
char *b = sp_str_alloc((size_t)n);
|
|
194
|
+
for (sp_int i = 0; i < n; i++) b[i] = (char)(sp_random_next(r) & 0xff);
|
|
195
|
+
b[n] = 0;
|
|
196
|
+
sp_str_set_len(b, (size_t)n);
|
|
197
|
+
sp_str_mark_binary(b);
|
|
198
|
+
return b;
|
|
199
|
+
}
|
|
200
|
+
/* Random#rand(Float range): a Float in [lo, hi) (or [lo, hi] for an inclusive
|
|
201
|
+
range, though the float boundary is effectively open). */
|
|
202
|
+
sp_float sp_Random_rand_float_range(sp_Random *r, sp_float lo, sp_float hi) {SP_GC_ROOT(r);
|
|
203
|
+
if (isnan(lo) || isinf(lo) || isnan(hi) || isinf(hi))
|
|
204
|
+
sp_raise_cls("Errno::EDOM", "Numerical argument out of domain");
|
|
205
|
+
return lo + sp_Random_rand_float(r) * (hi - lo);
|
|
206
|
+
}
|
|
207
|
+
/* Random.new_seed: a fresh nonneg seed drawn from the default stream. */
|
|
208
|
+
sp_int sp_Random_new_seed(void) {
|
|
209
|
+
sp_int s = (sp_int)(sp_random_next(sp_random_default_get()) >> 1);
|
|
210
|
+
return s < 0 ? -s : s;
|
|
211
|
+
}
|
|
212
|
+
/* Random.urandom(n): n random bytes as a String (spinel has no real OS entropy
|
|
213
|
+
source wired up, so this draws from a freshly time-seeded stream). */
|
|
214
|
+
const char *sp_Random_urandom(sp_int n) {
|
|
215
|
+
if (n < 0) sp_raise_cls("ArgumentError", "negative string size");
|
|
216
|
+
/* CRuby's Random.urandom IS the OS entropy source, and this was a PCG seeded
|
|
217
|
+
from time()/clock() -- a deterministic-per-run stand-in, from before the
|
|
218
|
+
tree had a real source. It does now: sp_crypto_entropy is the one place
|
|
219
|
+
that decides what counts as secure, and it fails closed. A caller of this
|
|
220
|
+
name is minting something that has to be unguessable. */
|
|
221
|
+
char *b = sp_str_alloc((size_t)n);
|
|
222
|
+
{ sp_int off = 0;
|
|
223
|
+
while (off < n) {
|
|
224
|
+
int chunk = (int)((n - off) > SPC_RANDOM_MAX ? SPC_RANDOM_MAX : (n - off));
|
|
225
|
+
if (!sp_crypto_entropy((unsigned char *)b + off, chunk))
|
|
226
|
+
sp_raise_cls("RuntimeError", "Random.urandom: no secure random source available");
|
|
227
|
+
off += chunk;
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
b[n] = 0;
|
|
231
|
+
sp_str_set_len(b, (size_t)n);
|
|
232
|
+
/* CRuby hands back ASCII-8BIT, so #length is the byte count. Without the
|
|
233
|
+
mark, a short draw that happens to spell valid UTF-8 (about 1.5% of
|
|
234
|
+
4-byte draws) counted code points and answered short (#3474). */
|
|
235
|
+
sp_str_mark_binary(b);
|
|
236
|
+
return b;
|
|
237
|
+
}
|
|
238
|
+
/* Random#inspect / #to_s: CRuby's default object rendering (the seed is not
|
|
239
|
+
part of it; the address matches CRuby's zero-padded 16-digit form). */
|
|
240
|
+
const char *sp_Random_inspect(sp_Random *r) {SP_GC_ROOT(r);
|
|
241
|
+
/* and its instance variables, as CRuby lists an object's */
|
|
242
|
+
void *t = sp_ivtbl_inspect_fn ? sp_ivtbl_get(r) : NULL;
|
|
243
|
+
if (t) return sp_sprintf("#<Random:0x%016llx%s>", (unsigned long long)(uintptr_t)r, sp_ivtbl_inspect_fn(t));
|
|
244
|
+
return sp_sprintf("#<Random:0x%016llx>", (unsigned long long)(uintptr_t)r);
|
|
245
|
+
}
|
|
246
|
+
/* Kernel#srand: seed the shared Kernel stream and remember the previous
|
|
247
|
+
seed, which srand returns (CRuby returns the prior seed, not the new
|
|
248
|
+
one). Every rand form -- bare/int/range, shuffle, sample, the Random
|
|
249
|
+
default instance -- draws from that one stream, so a single srand makes
|
|
250
|
+
them all reproducible. */
|
|
251
|
+
static SP_TLS sp_int sp_kernel_seed = 0;
|
|
252
|
+
sp_int sp_kernel_srand(sp_int seed) {
|
|
253
|
+
sp_int prev = sp_kernel_seed;
|
|
254
|
+
sp_kernel_seed = seed;
|
|
255
|
+
sp_krand_srand((uint64_t)seed);
|
|
256
|
+
return prev;
|
|
257
|
+
}
|
|
258
|
+
/* Random#rand(Bignum bound): a uniform Bigint in [0, bound). Composed from
|
|
259
|
+
32-bit chunks of the instance stream; accumulating two extra chunks past
|
|
260
|
+
the bound keeps the modulo bias around 2^-64. A non-positive bound raises
|
|
261
|
+
ArgumentError like the sp_int form (#3058). */
|
|
262
|
+
typedef struct sp_Bigint sp_Bigint;
|
|
263
|
+
extern sp_Bigint *sp_bigint_new_int(int64_t v);
|
|
264
|
+
extern sp_Bigint *sp_bigint_mul(sp_Bigint *a, sp_Bigint *b);
|
|
265
|
+
extern sp_Bigint *sp_bigint_add(sp_Bigint *a, sp_Bigint *b);
|
|
266
|
+
extern sp_Bigint *sp_bigint_mod(sp_Bigint *a, sp_Bigint *b);
|
|
267
|
+
extern int sp_bigint_cmp(sp_Bigint *a, sp_Bigint *b);
|
|
268
|
+
extern const char *sp_bigint_to_s(sp_Bigint *b);
|
|
269
|
+
sp_Bigint *sp_bigint_rand(sp_Random *r, sp_Bigint *bound) {SP_GC_ROOT(r);
|
|
270
|
+
SP_GC_ROOT(bound);
|
|
271
|
+
sp_Bigint *zero = sp_bigint_new_int(0);
|
|
272
|
+
SP_GC_ROOT(zero);
|
|
273
|
+
if (sp_bigint_cmp(bound, zero) <= 0)
|
|
274
|
+
sp_raise_cls("ArgumentError", sp_sprintf("invalid argument - %s", sp_bigint_to_s(bound)));
|
|
275
|
+
sp_Bigint *acc = zero;
|
|
276
|
+
SP_GC_ROOT(acc);
|
|
277
|
+
sp_Bigint *b32 = sp_bigint_new_int((int64_t)1 << 32);
|
|
278
|
+
SP_GC_ROOT(b32);
|
|
279
|
+
int extra = 2;
|
|
280
|
+
while (extra > 0) {
|
|
281
|
+
sp_Bigint *chunk = sp_bigint_new_int((int64_t)(sp_random_next(r) & 0xffffffffULL));
|
|
282
|
+
SP_GC_ROOT(chunk);
|
|
283
|
+
acc = sp_bigint_add(sp_bigint_mul(acc, b32), chunk);
|
|
284
|
+
if (sp_bigint_cmp(acc, bound) >= 0) extra--;
|
|
285
|
+
}
|
|
286
|
+
return sp_bigint_mod(acc, bound);
|
|
287
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/* sp_random.h -- the shared Kernel-level PRNG stream (lib/sp_random.c).
|
|
2
|
+
*
|
|
3
|
+
* PCG-XSH-RR, the generator mruby's mruby-random uses: much better
|
|
4
|
+
* statistical quality than libc rand(), no cryptographic claims. One
|
|
5
|
+
* stream is shared by every runtime TU -- Kernel#rand/#srand, the array
|
|
6
|
+
* shuffle/sample paths (generated TU and libspinel_rt.a alike) and the
|
|
7
|
+
* Random default instance all draw from it, so a single `srand(n)`
|
|
8
|
+
* makes every consumer reproducible. */
|
|
9
|
+
#ifndef SP_RANDOM_H
|
|
10
|
+
#define SP_RANDOM_H
|
|
11
|
+
|
|
12
|
+
#include <stdint.h>
|
|
13
|
+
#include "sp_types.h"
|
|
14
|
+
|
|
15
|
+
uint32_t sp_pcg32_adv(uint64_t *state); /* one generator step */
|
|
16
|
+
void sp_pcg_seed(uint64_t *state, uint64_t seed);
|
|
17
|
+
uint64_t sp_krand_next(void); /* 64-bit draw, lazily self-seeded */
|
|
18
|
+
void sp_krand_srand(uint64_t seed);
|
|
19
|
+
sp_int sp_krand_below(sp_int n); /* uniform [0, n); 0 when n <= 0 */
|
|
20
|
+
sp_float sp_krand_float(void); /* uniform [0, 1) */
|
|
21
|
+
|
|
22
|
+
/* Random -- per-instance PRNG. CRuby uses MT19937; spinel uses PCG-XSH-RR
|
|
23
|
+
(above), so the *sequence* differs from MRI -- MT19937 is not part of
|
|
24
|
+
the Ruby spec -- but each Random object keeps its own reproducible
|
|
25
|
+
stream from its seed. The default instance is a window onto the shared
|
|
26
|
+
Kernel stream, so srand() governs it too. */
|
|
27
|
+
typedef struct { uint64_t state; sp_int seed; } sp_Random;
|
|
28
|
+
/* The default instance is private to sp_random.c: it is a guarded static
|
|
29
|
+
there (see the comment on its box) and is reached only through
|
|
30
|
+
sp_random_default_get below. */
|
|
31
|
+
uint64_t sp_random_next(sp_Random *r);
|
|
32
|
+
sp_Random *sp_Random_new(sp_int seed);
|
|
33
|
+
sp_Random *sp_Random_new_float(sp_float f);
|
|
34
|
+
sp_Random *sp_Random_new_auto(void);
|
|
35
|
+
sp_Random *sp_Random_dup(sp_Random *r);
|
|
36
|
+
sp_int sp_Random_seed(sp_Random *r);
|
|
37
|
+
sp_bool sp_Random_eq(sp_Random *a, sp_Random *b);
|
|
38
|
+
sp_int sp_Random_rand_range(sp_Random *r, sp_Range rg);
|
|
39
|
+
sp_int sp_Random_rand_int(sp_Random *r, sp_int n);
|
|
40
|
+
struct sp_Bigint;
|
|
41
|
+
struct sp_Bigint *sp_bigint_rand(sp_Random *r, struct sp_Bigint *bound);
|
|
42
|
+
sp_float sp_Random_rand_float(sp_Random *r);
|
|
43
|
+
sp_float sp_Random_rand_float_bound(sp_Random *r, sp_float bound);
|
|
44
|
+
sp_float sp_Random_rand_float_range(sp_Random *r, sp_float lo, sp_float hi);
|
|
45
|
+
sp_Random *sp_random_default_get(void);
|
|
46
|
+
const char *sp_Random_bytes(sp_Random *r, sp_int n);
|
|
47
|
+
sp_int sp_Random_new_seed(void);
|
|
48
|
+
const char *sp_Random_urandom(sp_int n);
|
|
49
|
+
const char *sp_Random_inspect(sp_Random *r);
|
|
50
|
+
sp_int sp_kernel_srand(sp_int seed);
|
|
51
|
+
|
|
52
|
+
#endif
|