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,100 @@
|
|
|
1
|
+
/* sp_time.h -- Time value type + libc-backed accessors / formatters.
|
|
2
|
+
*
|
|
3
|
+
* The whole of spinel's Time implementation lives in lib/sp_time.c
|
|
4
|
+
* (compiled into libspinel_rt.a), including the formatters, which now
|
|
5
|
+
* return GC-heap strings directly (sp_time.c includes sp_alloc.h) -- so
|
|
6
|
+
* the generated TU calls them straight, with no buffer-copying
|
|
7
|
+
* trampoline in spinel_rt.h.
|
|
8
|
+
*
|
|
9
|
+
* The value ops (constructors, accessors, shifts) use int64_t / double
|
|
10
|
+
* directly, keeping that part decoupled from the runtime's typedefs.
|
|
11
|
+
*/
|
|
12
|
+
#ifndef SP_TIME_H
|
|
13
|
+
#define SP_TIME_H
|
|
14
|
+
|
|
15
|
+
#include <stddef.h>
|
|
16
|
+
#include <stdint.h>
|
|
17
|
+
#include <time.h>
|
|
18
|
+
|
|
19
|
+
/* is_utc is a 3-state zone kind: 0 = host-local zone, 1 = UTC, 2 = a fixed
|
|
20
|
+
utc_off-seconds offset (Time.new's 7th argument). utc_off is meaningful
|
|
21
|
+
only for kind 2; the positional (sp_Time){sec, ns, kind} initializers used
|
|
22
|
+
throughout leave it zero. */
|
|
23
|
+
typedef struct { int64_t tv_sec; int32_t tv_nsec; int8_t is_utc; int32_t utc_off; } sp_Time;
|
|
24
|
+
/* Seconds as a Float the way CRuby's Time#to_f and Time#- make them: the
|
|
25
|
+
whole nanosecond count converted, then divided by 1e9. That count is not
|
|
26
|
+
always a double, so the answer can sit just below the decimal value
|
|
27
|
+
(1790544731.561 reads 1790544731.5609999), and an epoch-milliseconds
|
|
28
|
+
`(t.to_f * 1000).to_i` depends on it (#5211). Past Fixnum's reach
|
|
29
|
+
(2**62 ns) CRuby rounds the exact quotient, which the split sum is the
|
|
30
|
+
nearest to here. */
|
|
31
|
+
static inline double sp_time_ns_to_f(int64_t sec, int64_t nsec) {
|
|
32
|
+
if (sec > -4611686018LL && sec < 4611686018LL)
|
|
33
|
+
return (double)(sec * 1000000000LL + nsec) / 1e9;
|
|
34
|
+
return (double)sec + (double)nsec / 1e9;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/* Constructors */
|
|
38
|
+
sp_Time sp_time_now(void);
|
|
39
|
+
sp_Time sp_time_at_int(int64_t sec);
|
|
40
|
+
sp_Time sp_time_norm(sp_Time t); /* carry a whole second out of tv_nsec */
|
|
41
|
+
sp_Time sp_time_add_nsec(sp_Time t, int64_t ns);
|
|
42
|
+
int64_t sp_time_zone_arg_off(const char *z, int *is_utc_out);
|
|
43
|
+
sp_Time sp_time_in_zone_i(sp_Time t, int64_t off);
|
|
44
|
+
sp_Time sp_time_in_zone_s(sp_Time t, const char *z);
|
|
45
|
+
sp_Time sp_time_at_float(double epoch);
|
|
46
|
+
sp_Time sp_time_at_div(int64_t num, int64_t den);
|
|
47
|
+
sp_Time sp_time_parse(const char *s);
|
|
48
|
+
sp_Time sp_time_new(int64_t y, int64_t mo, int64_t d, int64_t h, int64_t mi, int64_t s);
|
|
49
|
+
int64_t sp_time_month_arg(const char *s);
|
|
50
|
+
sp_Time sp_time_new_utc(int64_t y, int64_t mo, int64_t d, int64_t h, int64_t mi, int64_t s);
|
|
51
|
+
sp_Time sp_time_new_off(int64_t y, int64_t mo, int64_t d, int64_t h, int64_t mi, int64_t s, int64_t off);
|
|
52
|
+
sp_Time sp_time_with_usec(sp_Time t, int64_t usec);
|
|
53
|
+
sp_Time sp_time_with_usec_f(sp_Time t, double usec);
|
|
54
|
+
sp_Time sp_time_utc(sp_Time t);
|
|
55
|
+
sp_Time sp_time_localtime(sp_Time t);
|
|
56
|
+
|
|
57
|
+
/* Broken-down resolver: is_utc selects gmtime vs localtime, off is the
|
|
58
|
+
UTC offset in seconds, zbuf is the timezone abbreviation (8 bytes). */
|
|
59
|
+
void sp_time_vtm(sp_Time t, struct tm *bd, int32_t *off, char *zbuf);
|
|
60
|
+
|
|
61
|
+
/* Field accessors */
|
|
62
|
+
int64_t sp_time_year(sp_Time t);
|
|
63
|
+
int64_t sp_time_mon(sp_Time t);
|
|
64
|
+
int64_t sp_time_mday(sp_Time t);
|
|
65
|
+
int64_t sp_time_hour(sp_Time t);
|
|
66
|
+
int64_t sp_time_min(sp_Time t);
|
|
67
|
+
int64_t sp_time_sec(sp_Time t);
|
|
68
|
+
int64_t sp_time_wday(sp_Time t);
|
|
69
|
+
int64_t sp_time_yday(sp_Time t);
|
|
70
|
+
int64_t sp_time_isdst(sp_Time t);
|
|
71
|
+
int64_t sp_time_utc_offset(sp_Time t);
|
|
72
|
+
/* Time#floor / #ceil / #round: `ndigits` decimal places of the subsecond part,
|
|
73
|
+
with mode 0 = floor, 1 = ceil, 2 = round-half-up. ndigits 0 is the no-argument
|
|
74
|
+
form (whole seconds) and >= 9 keeps the full nanosecond resolution; a carry
|
|
75
|
+
past a second bumps tv_sec. A negative ndigits is CRuby's ArgumentError. */
|
|
76
|
+
sp_Time sp_time_round_to(sp_Time t, int64_t ndigits, int mode);
|
|
77
|
+
|
|
78
|
+
/* Time + Numeric / Time - Numeric. secs may be fractional. */
|
|
79
|
+
sp_Time sp_time_add(sp_Time t, double secs);
|
|
80
|
+
|
|
81
|
+
/* Comparison + integer/float shifts + Time-Time difference (cold value ops). */
|
|
82
|
+
int sp_time_cmp(sp_Time a, sp_Time b);
|
|
83
|
+
int64_t sp_time_hash(sp_Time t);
|
|
84
|
+
sp_Time sp_time_add_f(sp_Time t, double secs);
|
|
85
|
+
sp_Time sp_time_add_i(sp_Time t, int64_t secs);
|
|
86
|
+
sp_Time sp_time_sub_i(sp_Time t, int64_t secs);
|
|
87
|
+
double sp_time_sub_t(sp_Time a, sp_Time b);
|
|
88
|
+
|
|
89
|
+
/* Formatters: return a GC-heap string (from sp_alloc.h), "" on failure. */
|
|
90
|
+
const char *sp_time_strftime(sp_Time t, const char *fmt);
|
|
91
|
+
const char *sp_time_iso8601(sp_Time t);
|
|
92
|
+
const char *sp_time_httpdate(sp_Time t);
|
|
93
|
+
const char *sp_time_rfc2822(sp_Time t);
|
|
94
|
+
const char *sp_time_iso8601_frac(sp_Time t, int64_t digits);
|
|
95
|
+
sp_Time sp_time_getlocal_off(sp_Time t, int64_t off);
|
|
96
|
+
const char *sp_time_zone(sp_Time t);
|
|
97
|
+
const char *sp_time_inspect_v(sp_Time t); /* renders fractional seconds */
|
|
98
|
+
const char *sp_time_to_s_v(sp_Time t); /* whole seconds only (Time#to_s) */
|
|
99
|
+
|
|
100
|
+
#endif
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/* sp_types.h -- core value-type definitions split out of spinel_rt.h.
|
|
2
|
+
*
|
|
3
|
+
* Holds the primitive typedefs, the small leaf value structs, the GC
|
|
4
|
+
* header, and the typed array / non-poly hash structs. Both
|
|
5
|
+
* spinel_rt.h (which includes this near the top) and libspinel_rt.a
|
|
6
|
+
* sources can include it to see the layouts without pulling in the
|
|
7
|
+
* header's static/inline function bodies. Pure type/macro definitions
|
|
8
|
+
* only -- no function definitions, no global state.
|
|
9
|
+
*
|
|
10
|
+
* Reorganisation step toward slimming spinel_rt.h; sp_RbVal, the poly
|
|
11
|
+
* containers, and the conditional Proc/Fiber/etc. types still live in
|
|
12
|
+
* spinel_rt.h pending a later pass.
|
|
13
|
+
*/
|
|
14
|
+
#ifndef SP_TYPES_H
|
|
15
|
+
#define SP_TYPES_H
|
|
16
|
+
|
|
17
|
+
#ifdef __APPLE__
|
|
18
|
+
/* _DARWIN_C_SOURCE re-enables Darwin extensions (MAP_ANON, used by the fiber
|
|
19
|
+
stack mmap in sp_fiber.c) that a strict POSIX build would otherwise hide.
|
|
20
|
+
Define it here -- the lowest shared base header -- so every TU that pulls
|
|
21
|
+
sp_types.h in sets it before the first system header.
|
|
22
|
+
No _XOPEN_SOURCE / -Wdeprecated-declarations gate is needed: the portable
|
|
23
|
+
asm context switch runs on every Darwin arch (x86_64 / arm64), so the only
|
|
24
|
+
<ucontext.h> include (sp_fiber_ctx.h's non-asm fallback) is never compiled
|
|
25
|
+
there, and PR #1563 removed the stale unconditional include from
|
|
26
|
+
spinel_rt.h. */
|
|
27
|
+
#define _DARWIN_C_SOURCE
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
#include "sp_compat.h" /* the GNU extensions behind macros; first, it sets them all */
|
|
31
|
+
#include <stdint.h>
|
|
32
|
+
#include <stdbool.h>
|
|
33
|
+
#include <stddef.h>
|
|
34
|
+
#include <float.h> /* DBL_MAX / DBL_MIN / DBL_EPSILON for Float::* constants */
|
|
35
|
+
|
|
36
|
+
#include <setjmp.h>
|
|
37
|
+
#ifdef __APPLE__
|
|
38
|
+
/* Darwin's setjmp saves the signal mask, a sigprocmask syscall on every
|
|
39
|
+
begin/rescue. Nothing here needs the mask restored (glibc's longjmp doesn't
|
|
40
|
+
restore it either), so use the _ variants. Here so the generated TU and the
|
|
41
|
+
runtime agree on the pair. */
|
|
42
|
+
#define setjmp(env) _setjmp(env)
|
|
43
|
+
#define longjmp(env, val) _longjmp(env, val)
|
|
44
|
+
#endif
|
|
45
|
+
|
|
46
|
+
/* Per-worker storage under true parallelism. In the -DSP_THREADS runtime
|
|
47
|
+
variant (and the generated TU when the program uses threads, compiled with
|
|
48
|
+
the same define) the per-thread execution state -- the GC root stack, the
|
|
49
|
+
current fiber, the match registers -- is thread-local so each OS worker keeps
|
|
50
|
+
its own. The single-threaded build leaves these plain globals, byte-identical
|
|
51
|
+
to before. Both sides must agree on the storage class, so SP_TLS lives in
|
|
52
|
+
this shared base header. */
|
|
53
|
+
#ifdef SP_THREADS
|
|
54
|
+
# ifdef SP_NO_THREAD_LOCAL
|
|
55
|
+
# error "spinel: the threaded runtime (SP_THREADS) needs thread-local storage"
|
|
56
|
+
# endif
|
|
57
|
+
# define SP_TLS SP_THREAD_LOCAL
|
|
58
|
+
#else
|
|
59
|
+
# define SP_TLS
|
|
60
|
+
#endif
|
|
61
|
+
|
|
62
|
+
/* Worker identity, shared by the allocators (per-worker string/object heaps) and
|
|
63
|
+
the scheduler that owns it. In the base header so sp_gc.h's SP_GC_HEAP_PUSH --
|
|
64
|
+
included ahead of sp_alloc.h -- can index the per-worker object heap. */
|
|
65
|
+
#ifdef SP_THREADS
|
|
66
|
+
# ifndef SP_MAX_WORKERS
|
|
67
|
+
# define SP_MAX_WORKERS 256
|
|
68
|
+
# endif
|
|
69
|
+
extern SP_TLS int sp_worker_id; /* this OS worker's slot (0 = main); sp_sched.c */
|
|
70
|
+
extern int sp_active_workers; /* live worker count; sp_sched.c */
|
|
71
|
+
#endif
|
|
72
|
+
|
|
73
|
+
/* Branch-hint / hot-cold attributes (SP_LIKELY, SP_UNLIKELY, SP_COLD,
|
|
74
|
+
SP_NOINLINE, SP_INLINE, SP_NORETURN) live in sp_compat.h. Static
|
|
75
|
+
approximation of PGO: marking rare paths (raise, dispatch fallbacks) cold
|
|
76
|
+
lets the C compiler split them out of the hot path's i-cache footprint. */
|
|
77
|
+
|
|
78
|
+
/* sp_int follows pointer width (decided at compile time via intptr_t):
|
|
79
|
+
int64_t on 64-bit hosts -- PCs, no behavior change -- and int32_t on
|
|
80
|
+
32-bit embedded targets, where it gives native-word arithmetic, half
|
|
81
|
+
the memory for every integer/array/hash slot, and a pointer-width
|
|
82
|
+
sp_RbVal union. The two paths differ only in that the 32-bit build
|
|
83
|
+
overflows / narrows foreign 64-bit values (e.g. Time#to_i) at
|
|
84
|
+
INT32 limits; see the overflow-mode handling. */
|
|
85
|
+
#if INTPTR_MAX == INT64_MAX
|
|
86
|
+
#elif INTPTR_MAX == INT32_MAX
|
|
87
|
+
#else
|
|
88
|
+
#error "spinel: unsupported intptr_t width (need 32- or 64-bit)"
|
|
89
|
+
#endif
|
|
90
|
+
typedef intptr_t sp_int;
|
|
91
|
+
typedef double sp_float;
|
|
92
|
+
typedef bool sp_bool;
|
|
93
|
+
|
|
94
|
+
/* CRuby's nil.object_id, false.object_id and true.object_id. */
|
|
95
|
+
#define SP_NIL_OBJECT_ID 4
|
|
96
|
+
#define SP_FALSE_OBJECT_ID 0
|
|
97
|
+
#define SP_TRUE_OBJECT_ID 20
|
|
98
|
+
|
|
99
|
+
/* Sentinel value reserved by the int? (scalar-nullable int) type. An
|
|
100
|
+
int? slot is bit-compatible with sp_int; SP_INT_NIL marks the
|
|
101
|
+
"nil" inhabitant. The pattern is INTPTR_MIN -- INT64_MIN on 64-bit
|
|
102
|
+
(unchanged), INT32_MIN on 32-bit.
|
|
103
|
+
`sp_int_is_nil(v)` is the canonical predicate; treat any int? value
|
|
104
|
+
produced by runtime helpers as opaque outside this macro.
|
|
105
|
+
|
|
106
|
+
KNOWN LIMITATION (32-bit builds only). The reservation is a single
|
|
107
|
+
bit pattern, so a *genuine* integer equal to the sentinel is
|
|
108
|
+
indistinguishable from nil. On 64-bit, INT64_MIN is effectively
|
|
109
|
+
unreachable in practice (CRuby would have promoted it to Bignum), so
|
|
110
|
+
this never bites. On 32-bit, INT32_MIN (-2147483648) is an ordinary
|
|
111
|
+
reachable Integer, so a real -2147483648 flowing into an int? slot
|
|
112
|
+
reads back as nil -- e.g. `[-2147483648].pop` yields nil instead of
|
|
113
|
+
the value. This affects ONLY int? (nullable-int) slots; a plain
|
|
114
|
+
(non-nullable) int holding -2147483648 is fine, since it never
|
|
115
|
+
consults sp_int_is_nil. The integer-overflow helpers deliberately do
|
|
116
|
+
NOT reserve this value (checking every add/sub/mul result against it
|
|
117
|
+
would cost the hot path the embedded build is trying to save). Code that
|
|
118
|
+
must store -2147483648 nullably on 32-bit should box it (poly) rather
|
|
119
|
+
than use a flat int? slot. */
|
|
120
|
+
#define SP_INT_NIL ((sp_int)INTPTR_MIN)
|
|
121
|
+
#define sp_int_is_nil(v) ((v) == SP_INT_NIL)
|
|
122
|
+
|
|
123
|
+
/* Nullable float (float?) sentinel: a quiet NaN with a reserved payload.
|
|
124
|
+
NaN != NaN, so nil is detected by bit pattern, not ==. The payload is
|
|
125
|
+
chosen so the canonical NaN (0x7FF8000000000000) and ordinary
|
|
126
|
+
arithmetic NaNs don't collide; a real Float element with this exact
|
|
127
|
+
bit pattern reads back as nil -- the same documented compromise
|
|
128
|
+
SP_INT_NIL makes for INTPTR_MIN. sp_float is double (8 bytes). */
|
|
129
|
+
#define SP_FLOAT_NIL_BITS ((uint64_t)0x7FF8000000000001ULL)
|
|
130
|
+
static inline sp_float sp_float_nil(void) {
|
|
131
|
+
union { uint64_t u; sp_float d; } x; x.u = SP_FLOAT_NIL_BITS; return x.d;
|
|
132
|
+
}
|
|
133
|
+
/* The same value as a CONSTANT expression, for a file-scope initializer
|
|
134
|
+
(a static ivar, a global) where the union read above is not one. The
|
|
135
|
+
payload argument is the low mantissa bits, so "0x1" is exactly
|
|
136
|
+
SP_FLOAT_NIL_BITS on gcc and clang, 32-bit lanes included. */
|
|
137
|
+
#define SP_FLOAT_NIL_CONST (__builtin_nan("0x1"))
|
|
138
|
+
static inline int sp_float_is_nil(sp_float v) {
|
|
139
|
+
union { sp_float d; uint64_t u; } x; x.d = v; return x.u == SP_FLOAT_NIL_BITS;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/* sp_sym is defined per-program in emit_sym_runtime, but poly helpers
|
|
143
|
+
below need to reference it by forward declaration. */
|
|
144
|
+
typedef sp_int sp_sym;
|
|
145
|
+
|
|
146
|
+
#ifndef TRUE
|
|
147
|
+
#define TRUE true
|
|
148
|
+
#endif
|
|
149
|
+
#ifndef FALSE
|
|
150
|
+
#define FALSE false
|
|
151
|
+
#endif
|
|
152
|
+
|
|
153
|
+
/* ---- Leaf value structs ---- */
|
|
154
|
+
/* `step` carries the iteration direction/stride for the enumerator forms that a
|
|
155
|
+
plain ascending range cannot express: n.downto(m) is {first:n,last:m,step:-1}.
|
|
156
|
+
A zero step (every range built by the literal `a..b` / sp_range_new path) is
|
|
157
|
+
treated as +1, so existing constructions need no change. */
|
|
158
|
+
/* An Integer begin with a Float end, (1..2.5): CRuby iterates it from the
|
|
159
|
+
Integer, so first / last / excl are the bounds of that walk (1..2), and the
|
|
160
|
+
end as written is kept beside them -- fe 1 for an inclusive Float end, 2
|
|
161
|
+
for an excluded one, fend its value; fe 0 (every other range, and the
|
|
162
|
+
zero-initialized one) has none. Read through sp_range_end_* (sp_range.h).
|
|
163
|
+
All three Range kinds default to frozen; dup sets their unfrozen flag.
|
|
164
|
+
Store it beside a byte-sized flag (fe 0..2, omitted 0..63, excl 0..1)
|
|
165
|
+
in the existing trailing word, keeping the by-value layouts the same size. */
|
|
166
|
+
typedef struct{sp_int first;sp_int last;sp_int excl;sp_int step;sp_float fend;unsigned char fe;unsigned char unfrozen;}sp_Range;
|
|
167
|
+
/* A Float range (1.0..3.0): endpoints kept as sp_float so cover?/include?/begin/
|
|
168
|
+
end are exact (an int-backed sp_Range truncated them). Iteration is a TypeError
|
|
169
|
+
in Ruby (only #step traverses a Float range), so no step/iteration state here.
|
|
170
|
+
beginless/endless ends use -HUGE_VAL / +HUGE_VAL. */
|
|
171
|
+
/* `omitted` records which bound was WRITTEN as absent (`(..5.0)`, `(1.0..)`),
|
|
172
|
+
as opposed to an explicit infinity (`1..Float::INFINITY`): both are +/-HUGE_VAL
|
|
173
|
+
in the value, and only #inspect / #to_s tell them apart -- CRuby prints
|
|
174
|
+
"1.0.." for the first and "1.0..Infinity" for the second (#3670).
|
|
175
|
+
bit 1 = begin omitted, bit 2 = end omitted. */
|
|
176
|
+
typedef struct{sp_float first;sp_float last;sp_int excl;unsigned char omitted;unsigned char unfrozen;}sp_FloatRange;
|
|
177
|
+
#define SP_FRANGE_NO_BEGIN 1
|
|
178
|
+
#define SP_FRANGE_NO_END 2
|
|
179
|
+
/* A mixed literal (1.5..5) is a Float range whose END was written as an
|
|
180
|
+
Integer -- and CRuby renders each endpoint as the user wrote it. The bits
|
|
181
|
+
record that, so #inspect prints "1.5..5" rather than "1.5..5.0" (#3896). */
|
|
182
|
+
#define SP_FRANGE_INT_BEGIN 4
|
|
183
|
+
#define SP_FRANGE_INT_END 8
|
|
184
|
+
/* A String range ("a".."e"): endpoints kept as GC-managed strings so #begin,
|
|
185
|
+
#end, #to_s and #inspect answer as Ruby does. Every traversal (each/to_a/
|
|
186
|
+
include?/...) materializes the element array through
|
|
187
|
+
sp_StrArray_from_string_range, which is how the range behaved before it was
|
|
188
|
+
a value of its own. */
|
|
189
|
+
typedef struct{const char *first;const char *last;unsigned char excl;unsigned char unfrozen;}sp_StrRange;
|
|
190
|
+
/* A class value. `name`, when non-NULL, is a rodata class name carried by a
|
|
191
|
+
class whose cls_id table entry may not exist (an exception's class -- the
|
|
192
|
+
Errno:: family and many builtin error classes have no assigned cls_id). It
|
|
193
|
+
takes precedence over cls_id for to_s / boxing / equality. */
|
|
194
|
+
typedef struct{sp_int cls_id;const char *name;}sp_Class;
|
|
195
|
+
/* The nil-class sentinel: a TY_CLASS value can be nil (BasicObject#superclass),
|
|
196
|
+
carried in-band via a reserved cls_id with no name -- the same nullable-scalar
|
|
197
|
+
convention as SP_INT_NIL for int?. It is distinct from every real class id
|
|
198
|
+
(user >= 0, builtins -100..-146, SP_CLASS_BY_NAME 0x7F000000). It MUST stay
|
|
199
|
+
negative: the class-chain walks route a non-negative cls_id to the user-class
|
|
200
|
+
table (`cur.cls_id>=0 ? sp_class_superclass : sp_builtin_superclass`), so a
|
|
201
|
+
positive sentinel would be looked up as a user class. */
|
|
202
|
+
#define SP_CLASS_NIL_ID ((sp_int)-900)
|
|
203
|
+
#define sp_class_nil_p(c) ((c).name == NULL && (c).cls_id == SP_CLASS_NIL_ID)
|
|
204
|
+
#define SP_CLASS_NIL ((sp_Class){SP_CLASS_NIL_ID, NULL})
|
|
205
|
+
/* A class known only by name (see sp_box_class_name in sp_alloc.h): marks a
|
|
206
|
+
boxed SP_TAG_CLASS value whose v.s carries the name instead of a resolved
|
|
207
|
+
cls_id. */
|
|
208
|
+
#define SP_CLASS_BY_NAME 0x7F000000
|
|
209
|
+
/* fl marks a component as Float-classed (renders "2.0"); clear bits keep the
|
|
210
|
+
Integer-style rendering for whole values. Zero-init (every positional
|
|
211
|
+
compound literal) is the Integer-classed default. */
|
|
212
|
+
typedef struct{sp_float re;sp_float im;unsigned char fl;}sp_Complex;
|
|
213
|
+
#define SP_CPLX_RE_F 1
|
|
214
|
+
#define SP_CPLX_IM_F 2
|
|
215
|
+
typedef struct{sp_int num;sp_int den;}sp_Rational;
|
|
216
|
+
typedef struct{const char *name;}sp_Encoding;
|
|
217
|
+
|
|
218
|
+
/* ---- GC headers ---- */
|
|
219
|
+
/* `marked` is a mark-generation STAMP, not a boolean: an object is live in
|
|
220
|
+
the current collection iff marked == sp_gc_mark_gen. Bumping the generation
|
|
221
|
+
at collect entry unmarks the whole heap in O(1), removing the two
|
|
222
|
+
full-list walks (old unmark + minor re-mark) that made every minor
|
|
223
|
+
collection O(live) even when the live set was untouched. 0 never equals a
|
|
224
|
+
generation (the counter skips it), so freshly-calloc'd headers are unmarked. */
|
|
225
|
+
typedef struct sp_gc_hdr { struct sp_gc_hdr *next; void (*finalize)(void *); void (*scan)(void *); size_t size; unsigned marked : 27; unsigned frozen : 1; unsigned pinned : 1;
|
|
226
|
+
/* `old` says the object has survived a sweep and lives on the old list, so
|
|
227
|
+
a reference stored into it may point at a younger object a minor mark
|
|
228
|
+
would not reach on its own; `dirty` says it is already on the remembered
|
|
229
|
+
set, so the write barrier's push happens once per collection rather than
|
|
230
|
+
once per store. `marked` gives up a bit for them: it is a wrapping
|
|
231
|
+
generation counter whose wrap path re-clears every stamp, and 2^27
|
|
232
|
+
collections between wraps is far past anything real.
|
|
233
|
+
|
|
234
|
+
`pinned` says the object is on sp_gc_pinned, the STICKY half of the
|
|
235
|
+
remembered set. `dirty` records a store the barrier saw and is cleared
|
|
236
|
+
every cycle; `pinned` records a holder whose stores the barrier cannot
|
|
237
|
+
see at all, so it is never cleared while the object lives. The one
|
|
238
|
+
producer is a by-reference String parameter: the callee stores through a
|
|
239
|
+
cell it cannot name the owner of, and the owner is only nameable at the
|
|
240
|
+
lending call site, which is BEFORE the store rather than after (#4391).
|
|
241
|
+
|
|
242
|
+
`aged` says the object has already survived one minor cycle while young.
|
|
243
|
+
A survivor is promoted on its SECOND survival, not its first: an object
|
|
244
|
+
that dies within a cycle or two of its birth then dies young, where the
|
|
245
|
+
next minor frees it, instead of being promoted to sit in the old
|
|
246
|
+
generation until a full cycle -- promoted garbage was a third of an
|
|
247
|
+
interpreter's heap and a third of its wall. */
|
|
248
|
+
unsigned old : 1; unsigned dirty : 1; unsigned aged : 1; void (*recycle)(struct sp_gc_hdr *); } sp_gc_hdr;
|
|
249
|
+
/* size/len packed to uint32 (4 GB per-string cap, far beyond any real
|
|
250
|
+
string) so the cached FNV `hash` fits without growing the 24-byte
|
|
251
|
+
header -- i.e. zero per-string RSS cost vs the pre-cache layout.
|
|
252
|
+
`size` is vestigial (written by sp_str_alloc, never read back; the
|
|
253
|
+
str-heap sweep no longer folds string bytes into sp_gc_bytes).
|
|
254
|
+
`hash` caches sp_str_hash for heap/heap-frozen keys; 0 == not yet
|
|
255
|
+
computed, invalidated to 0 on any in-place mutation (setbyte/set_len). */
|
|
256
|
+
typedef struct sp_str_hdr { struct sp_str_hdr *next; uint32_t size; uint32_t len; uint64_t hash; } sp_str_hdr;
|
|
257
|
+
|
|
258
|
+
/* ---- Typed arrays ---- */
|
|
259
|
+
#define SP_STRARR_INLINE 4
|
|
260
|
+
/* may_nil: the array may hold a nil analyze did not see, carried as the
|
|
261
|
+
slot's sentinel (SP_INT_NIL, the Float NaN payload). Set where the runtime
|
|
262
|
+
puts one -- a gap filled past the end, a converted boxed nil, an element a
|
|
263
|
+
builtin copies -- and carried to copies, so the whole-array reads of an
|
|
264
|
+
array analyze did not mark (sum, min, max, sort, include?(nil), the boxing
|
|
265
|
+
into a mixed array) ask one flag; a marked array scans, as its stores set
|
|
266
|
+
none. Only compact!, delete(nil) and replace drop it. It follows `frozen`,
|
|
267
|
+
which the push / [] / []= paths read, so their code is unchanged; the
|
|
268
|
+
IntArray block stays in its slab class. */
|
|
269
|
+
typedef struct{sp_int*data;sp_int start;sp_int len;sp_int cap;sp_int frozen;int may_nil;}sp_IntArray;
|
|
270
|
+
typedef struct{sp_float*data;sp_int len;sp_int cap;sp_int frozen;int may_nil;}sp_FloatArray;
|
|
271
|
+
#define SP_MAY_NIL(a) ((a)->may_nil)
|
|
272
|
+
/* elem_kind/elem_cls: what the pointers are, stamped when the array is boxed by
|
|
273
|
+
reference (the one cls_id for pointer arrays is type-erased, #4486). 0 until
|
|
274
|
+
then; a stamp never changes since a typed array holds one kind. */
|
|
275
|
+
typedef struct{void**data;sp_int len;sp_int cap;void(*scan_elem)(void*);sp_int frozen;int elem_kind;int elem_cls;}sp_PtrArray;
|
|
276
|
+
#define SP_PTR_ELEM_UNKNOWN 0
|
|
277
|
+
#define SP_PTR_ELEM_OBJ 1 /* user objects, elem_cls = the static class (-1: read each object's own) */
|
|
278
|
+
#define SP_PTR_ELEM_INT_ROWS 2 /* sp_IntArray rows (Array[Array[Integer]]) */
|
|
279
|
+
#define SP_PTR_ELEM_FLT_ROWS 3 /* sp_FloatArray rows (Array[Array[Float]]) */
|
|
280
|
+
typedef struct{const char**data;sp_int len;sp_int cap;sp_int frozen;const char*inline_data[SP_STRARR_INLINE];}sp_StrArray;
|
|
281
|
+
|
|
282
|
+
/* ---- Non-poly typed hashes ---- */
|
|
283
|
+
typedef struct{const char**keys;sp_int*vals;const char**order;sp_int len;sp_int cap;sp_int mask;sp_int default_v;}sp_StrIntHash;
|
|
284
|
+
typedef struct{const char**keys;const char**vals;const char**order;sp_int len;sp_int cap;sp_int mask;const char*default_v;}sp_StrStrHash;
|
|
285
|
+
typedef struct{sp_int*keys;const char**vals;sp_int*order;sp_bool*used;sp_int len;sp_int cap;sp_int mask;const char*default_v;}sp_IntStrHash;
|
|
286
|
+
typedef struct{sp_int*keys;sp_int*vals;sp_int*order;sp_bool*used;sp_int len;sp_int cap;sp_int mask;sp_int default_v;}sp_IntIntHash;
|
|
287
|
+
|
|
288
|
+
/* Signal table bound (0..64): shared by the trap state in the generated TU
|
|
289
|
+
and the trap machinery in lib/sp_cold.c. */
|
|
290
|
+
#define SP_SIG_MAX 65
|
|
291
|
+
|
|
292
|
+
#endif
|