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.
Files changed (95) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE-mruby.txt +22 -0
  3. data/LICENSE-spinel.txt +19 -0
  4. data/LICENSE.txt +21 -0
  5. data/README.md +61 -0
  6. data/ext/qr_reader_native/SPINEL_VERSION +1 -0
  7. data/ext/qr_reader_native/extconf.rb +8 -0
  8. data/ext/qr_reader_native/mruby/error.h +13 -0
  9. data/ext/qr_reader_native/mruby/internal.h +145 -0
  10. data/ext/qr_reader_native/mruby/string.h +22 -0
  11. data/ext/qr_reader_native/mruby.h +93 -0
  12. data/ext/qr_reader_native/mruby_shim.h +118 -0
  13. data/ext/qr_reader_native/qr_reader_native.c +13513 -0
  14. data/ext/qr_reader_native/qr_reader_native.h +29 -0
  15. data/ext/qr_reader_native/qr_reader_native_ext.c +598 -0
  16. data/ext/qr_reader_native/re_cased.h +71 -0
  17. data/ext/qr_reader_native/re_compile.c +5784 -0
  18. data/ext/qr_reader_native/re_ctype.h +3540 -0
  19. data/ext/qr_reader_native/re_exec.c +2190 -0
  20. data/ext/qr_reader_native/re_internal.h +671 -0
  21. data/ext/qr_reader_native/re_prop.h +4629 -0
  22. data/ext/qr_reader_native/re_spinel.c +363 -0
  23. data/ext/qr_reader_native/re_spinel.h +22 -0
  24. data/ext/qr_reader_native/re_spinel_utf8.inc +97 -0
  25. data/ext/qr_reader_native/re_utf8.c +156 -0
  26. data/ext/qr_reader_native/sp_alloc.c +1447 -0
  27. data/ext/qr_reader_native/sp_alloc.h +1196 -0
  28. data/ext/qr_reader_native/sp_argf.h +33 -0
  29. data/ext/qr_reader_native/sp_array.c +1052 -0
  30. data/ext/qr_reader_native/sp_array.h +456 -0
  31. data/ext/qr_reader_native/sp_bigint.c +5826 -0
  32. data/ext/qr_reader_native/sp_bigint.h +117 -0
  33. data/ext/qr_reader_native/sp_cold.c +5259 -0
  34. data/ext/qr_reader_native/sp_compat.h +402 -0
  35. data/ext/qr_reader_native/sp_core.c +818 -0
  36. data/ext/qr_reader_native/sp_core.h +56 -0
  37. data/ext/qr_reader_native/sp_crypto.c +877 -0
  38. data/ext/qr_reader_native/sp_crypto.h +169 -0
  39. data/ext/qr_reader_native/sp_dtoa.c +1533 -0
  40. data/ext/qr_reader_native/sp_dtoa.h +29 -0
  41. data/ext/qr_reader_native/sp_encoding_names.h +172 -0
  42. data/ext/qr_reader_native/sp_enum.h +86 -0
  43. data/ext/qr_reader_native/sp_exc.c +1185 -0
  44. data/ext/qr_reader_native/sp_exc.h +186 -0
  45. data/ext/qr_reader_native/sp_exc_ctx.h +56 -0
  46. data/ext/qr_reader_native/sp_fiber.c +889 -0
  47. data/ext/qr_reader_native/sp_fiber.h +162 -0
  48. data/ext/qr_reader_native/sp_fiber_ctx.h +84 -0
  49. data/ext/qr_reader_native/sp_format.c +695 -0
  50. data/ext/qr_reader_native/sp_format.h +83 -0
  51. data/ext/qr_reader_native/sp_gc.c +1793 -0
  52. data/ext/qr_reader_native/sp_gc.h +762 -0
  53. data/ext/qr_reader_native/sp_hash.c +131 -0
  54. data/ext/qr_reader_native/sp_hash.h +131 -0
  55. data/ext/qr_reader_native/sp_inspect.c +215 -0
  56. data/ext/qr_reader_native/sp_inspect.h +128 -0
  57. data/ext/qr_reader_native/sp_io.c +1676 -0
  58. data/ext/qr_reader_native/sp_io.h +272 -0
  59. data/ext/qr_reader_native/sp_iobuffer.c +1014 -0
  60. data/ext/qr_reader_native/sp_iobuffer.h +167 -0
  61. data/ext/qr_reader_native/sp_marshal.c +487 -0
  62. data/ext/qr_reader_native/sp_marshal.h +60 -0
  63. data/ext/qr_reader_native/sp_net.c +1029 -0
  64. data/ext/qr_reader_native/sp_net.h +205 -0
  65. data/ext/qr_reader_native/sp_pack.c +1254 -0
  66. data/ext/qr_reader_native/sp_poly_cold.c +1220 -0
  67. data/ext/qr_reader_native/sp_proc.c +410 -0
  68. data/ext/qr_reader_native/sp_proc.h +327 -0
  69. data/ext/qr_reader_native/sp_process.c +547 -0
  70. data/ext/qr_reader_native/sp_process_status.c +211 -0
  71. data/ext/qr_reader_native/sp_process_status.h +66 -0
  72. data/ext/qr_reader_native/sp_random.c +287 -0
  73. data/ext/qr_reader_native/sp_random.h +52 -0
  74. data/ext/qr_reader_native/sp_range.h +144 -0
  75. data/ext/qr_reader_native/sp_re.c +1379 -0
  76. data/ext/qr_reader_native/sp_re.h +186 -0
  77. data/ext/qr_reader_native/sp_re_names.h +59 -0
  78. data/ext/qr_reader_native/sp_sched.c +4044 -0
  79. data/ext/qr_reader_native/sp_sched.h +295 -0
  80. data/ext/qr_reader_native/sp_slab.c +1507 -0
  81. data/ext/qr_reader_native/sp_str.c +1462 -0
  82. data/ext/qr_reader_native/sp_str.h +306 -0
  83. data/ext/qr_reader_native/sp_str_crypt.c +23 -0
  84. data/ext/qr_reader_native/sp_string.c +92 -0
  85. data/ext/qr_reader_native/sp_string.h +253 -0
  86. data/ext/qr_reader_native/sp_system.c +78 -0
  87. data/ext/qr_reader_native/sp_system.h +18 -0
  88. data/ext/qr_reader_native/sp_time.c +860 -0
  89. data/ext/qr_reader_native/sp_time.h +100 -0
  90. data/ext/qr_reader_native/sp_types.h +292 -0
  91. data/ext/qr_reader_native/spinel_rt.h +19017 -0
  92. data/ext/qr_reader_native/unicase.c +399 -0
  93. data/ext/qr_reader_native/unicase.h +901 -0
  94. data/lib/qr_reader/native.rb +6 -0
  95. metadata +153 -0
@@ -0,0 +1,456 @@
1
+ #ifndef SP_ARRAY_H
2
+ #define SP_ARRAY_H
3
+ /* sp_array.h -- typed array hot core + cold-op surface.
4
+ *
5
+ * The struct layouts (sp_IntArray, ...) live in sp_types.h. The hot
6
+ * accessors (new / push / pop / shift / get / set / length / empty) stay
7
+ * inline here so every generated TU compiles them identically --
8
+ * relocating them out of spinel_rt.h into this shared header is a pure
9
+ * textual move with no codegen change. The cold ops (sort / slice / dup /
10
+ * set algebra / join / ...) are compiled once into libspinel_rt.a
11
+ * (lib/sp_array.c); this header only declares them.
12
+ *
13
+ * sp_sprintf / sp_raise_cls / sp_raise_frozen_array are provided by the
14
+ * generated TU and resolved at the final link, the same way lib/sp_core.c
15
+ * calls them -- so lib/sp_array.c can use them without a runtime include.
16
+ */
17
+ #include <math.h> /* isnan / isinf / signbit / NAN / fabs for sp_float_sum_step */
18
+ #include "sp_gc.h" /* sp_gc_hdr, sp_gc_bytes, SP_GC_ROOT, sp_oom_die */
19
+ #include "sp_alloc.h" /* sp_gc_alloc, sp_str_alloc, sp_raise_cls, sp_raise_frozen_array */
20
+
21
+ const char *sp_sprintf(const char *fmt, ...); /* defined in the generated TU */
22
+
23
+ /* ============================ sp_IntArray ============================ */
24
+ /* `frozen` rides in the struct (not the GC header) so the hot push /
25
+ []= paths read it from the same cache line as len/cap -- no extra
26
+ cache miss vs. the GC-header bit. calloc in sp_gc_alloc zero-inits
27
+ it, so constructors need no change. Issue #918. */
28
+ static void sp_IntArray_fin(void*p){sp_pl_free(((sp_IntArray*)p)->data);}
29
+ static sp_IntArray*sp_IntArray_new(void){sp_IntArray*a=(sp_IntArray*)sp_gc_alloc(sizeof(sp_IntArray),sp_IntArray_fin,NULL);a->cap=16;a->data=(sp_int*)sp_pl_alloc(sizeof(sp_int)*a->cap);if(!a->data)sp_oom_die();a->start=0;a->len=0;{sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));h->size+=sizeof(sp_int)*a->cap;sp_gc_bytes_add(sizeof(sp_int)*a->cap);}return a;}
30
+ /* An Array set up inside a bigger object that starts with it -- an Array
31
+ subclass instance, whose struct embeds its Array (#7449) -- as _new sets a
32
+ fresh one up; the payload is counted to the enclosing object's header. */
33
+ static void sp_IntArray_init_embedded(sp_IntArray*a){a->cap=16;a->data=(sp_int*)sp_pl_alloc(sizeof(sp_int)*a->cap);if(!a->data)sp_oom_die();a->start=0;a->len=0;{sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));h->size+=sizeof(sp_int)*a->cap;sp_gc_bytes_add(sizeof(sp_int)*a->cap);}}
34
+ static SP_NOINLINE void sp_IntArray_push_grow(sp_IntArray*a){if(a->start>0){memmove(a->data,a->data+a->start,sizeof(sp_int)*a->len);a->start=0;if(a->len<a->cap)return;}{sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));sp_gc_bytes_sub(sizeof(sp_int)*a->cap);h->size-=sizeof(sp_int)*a->cap;a->cap=((((((a->cap*2))))))+1;void*nd=sp_pl_realloc(a->data,sizeof(sp_int)*a->cap);if(!nd)sp_oom_die();a->data=(sp_int*)nd;h->size+=sizeof(sp_int)*a->cap;sp_gc_bytes_add(sizeof(sp_int)*a->cap);}}
35
+ static inline void sp_IntArray_push(sp_IntArray*a,sp_int v){if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_INT_ARRAY);return;}if(a->start+a->len>=a->cap)sp_IntArray_push_grow(a);a->data[a->start+a->len]=v;a->len++;}
36
+ /* Array.new(n, v): the buffer is allocated at its final size and filled in
37
+ place, where n pushes grew it from 16 by doubling -- a realloc and a copy
38
+ at every step, and a frozen and a capacity test per element. */
39
+ static sp_IntArray*sp_IntArray_new_fill(sp_int n,sp_int v){sp_IntArray*a=(sp_IntArray*)sp_gc_alloc(sizeof(sp_IntArray),sp_IntArray_fin,NULL);if((uintmax_t)n>SIZE_MAX/sizeof(sp_int))sp_oom_die();a->cap=n>16?n:16;a->data=(sp_int*)sp_pl_alloc(sizeof(sp_int)*a->cap);if(!a->data)sp_oom_die();a->start=0;for(sp_int i=0;i<n;i++)a->data[i]=v;a->len=n;{sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));h->size+=sizeof(sp_int)*a->cap;sp_gc_bytes_add(sizeof(sp_int)*a->cap);}return a;}
40
+ /* Issue #826/#832: empty pop/shift return SP_INT_NIL (nullable int
41
+ sentinel) to match MRI's nil; callers treat as int?. Without the
42
+ guard, `--a->len` wraps to -1 and reads past the buffer start. */
43
+ static inline sp_int sp_IntArray_pop(sp_IntArray*a){if(!a||a->len<=0)return SP_INT_NIL;if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_INT_ARRAY);return SP_INT_NIL;}return a->data[a->start+--a->len];}
44
+ static inline sp_int sp_IntArray_shift(sp_IntArray*a){if(!a||a->len<=0)return SP_INT_NIL;if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_INT_ARRAY);return SP_INT_NIL;}sp_int v=a->data[a->start];a->start++;a->len--;return v;}
45
+ static inline sp_int sp_IntArray_length(sp_IntArray*a){return a->len;}
46
+ static inline sp_bool sp_IntArray_empty(sp_IntArray*a){return a->len==0;}
47
+ static inline sp_int sp_IntArray_get(sp_IntArray*a,sp_int i){if(!a)return SP_INT_NIL;if((unsigned long long)i<(unsigned long long)a->len)return a->data[a->start+i];if(i<0)i+=a->len;if(i<0||i>=a->len)return SP_INT_NIL;return a->data[a->start+i];}
48
+ /* A nil lands where analyze cannot see it: the array's may_nil (SP_MAY_NIL),
49
+ set out of line so the stores that test for it keep their fast path. */
50
+ static SP_NOINLINE SP_COLD void sp_IntArray_note_nil(sp_IntArray*a){if(a)SP_MAY_NIL(a)=1;}
51
+ static SP_NOINLINE SP_COLD void sp_FloatArray_note_nil(sp_FloatArray*a){if(a)SP_MAY_NIL(a)=1;}
52
+ /* Issue #769: a very-negative i leaves i negative after the `i += a->len`
53
+ adjustment. CRuby raises IndexError; spinel no-ops as the safest
54
+ fallback (raising from a typed-array set would need setjmp plumbing
55
+ throughout the call chain). */
56
+ static void sp_IntArray_set_slow(sp_IntArray*a,sp_int i,sp_int v){if(i<0)return;while(a->start+i>=a->cap){sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));sp_gc_bytes_sub(sizeof(sp_int)*a->cap);h->size-=sizeof(sp_int)*a->cap;a->cap=((((((a->cap*2))))))+1;a->data=(sp_int*)sp_pl_realloc(a->data,sizeof(sp_int)*a->cap);h->size+=sizeof(sp_int)*a->cap;sp_gc_bytes_add(sizeof(sp_int)*a->cap);}while(i>a->len){a->data[a->start+a->len]=SP_INT_NIL;a->len++;SP_MAY_NIL(a)=1;} /* gap slots read as nil, and the array may hold one */if(i==a->len)a->len++;a->data[a->start+i]=v;}
57
+ /* Issue #839: an extreme negative index (still negative after `i += len`)
58
+ raises IndexError per MRI. */
59
+ static SP_NOINLINE SP_COLD void sp_IntArray_set_cold(sp_IntArray*a,sp_int i,sp_int v){if(!a)return;if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_INT_ARRAY);return;}sp_int orig=i;if(i<0)i+=a->len;if(i<0)sp_raise_cls("IndexError",sp_sprintf("index %lld too small for array; minimum: %lld",(long long)orig,(long long)-a->len));if(i<a->len){a->data[a->start+i]=v;return;}sp_IntArray_set_slow(a,i,v);}
60
+ static inline void sp_IntArray_set(sp_IntArray*a,sp_int i,sp_int v){if(SP_LIKELY(a&&!a->frozen&&i>=0&&i<a->len)){a->data[a->start+i]=v;return;}sp_IntArray_set_cold(a,i,v);}
61
+ /* The stores for a value that may be a nil no static mark covers (a boxed
62
+ value converted to the slot, an element a builtin copies): the sentinel
63
+ sets may_nil on its way in, through a cold call off the store's path. The
64
+ plain stores above stay as they were. These and the other may_nil helpers
65
+ are macros, not inline functions: a large generated unit sits at gcc's
66
+ inlining budget, and a wrapper the inliner had to spend it on pushed the
67
+ hot accessors of an unrelated loop out of line (optcarrot's PPU loop). As
68
+ macros, the inliner sees only the plain push / set it always saw. */
69
+ #define sp_IntArray_push_nilable(a, v) ({ sp_IntArray *_pn_a = (a); sp_int _pn_v = (v); if (SP_UNLIKELY(_pn_v == SP_INT_NIL)) sp_IntArray_note_nil(_pn_a); sp_IntArray_push(_pn_a, _pn_v); })
70
+ #define sp_IntArray_set_nilable(a, i, v) ({ sp_IntArray *_sn_a = (a); sp_int _sn_i = (i); sp_int _sn_v = (v); if (SP_UNLIKELY(_sn_v == SP_INT_NIL)) sp_IntArray_note_nil(_sn_a); sp_IntArray_set(_sn_a, _sn_i, _sn_v); })
71
+ /* An array built from another inherits its flag: a copy, a slice, a sort. */
72
+ #define sp_IntArray_nil_from(d, s) ({ sp_IntArray *_nf_d = (d); const sp_IntArray *_nf_s = (s); if (SP_UNLIKELY(_nf_s && SP_MAY_NIL(_nf_s))) sp_IntArray_note_nil(_nf_d); })
73
+ #define sp_IntArray_may_nil(a) ({ const sp_IntArray *_mn_a = (a); (sp_bool)(_mn_a && SP_MAY_NIL(_mn_a)); })
74
+
75
+ /* ---- sp_IntArray cold ops (compiled in lib/sp_array.c) ---- */
76
+ sp_IntArray *sp_IntArray_from_range(sp_int s, sp_int e);
77
+ sp_IntArray *sp_IntArray_from_range_step(sp_int beg, sp_int end, sp_int step, sp_int excl);
78
+ sp_IntArray *sp_IntArray_dup(sp_IntArray *a);
79
+ sp_IntArray *sp_IntArray_slice(sp_IntArray *a, sp_int start, sp_int len);
80
+ sp_IntArray *sp_IntArray_slice_range(sp_IntArray *a, sp_int start, sp_int end_, sp_int excl);
81
+ void sp_IntArray_replace(sp_IntArray *dst, sp_IntArray *src);
82
+ void sp_IntArray_splice(sp_IntArray *a, sp_int start, sp_int len, const sp_int *src, sp_int srcn);
83
+ void sp_FloatArray_splice(sp_FloatArray *a, sp_int start, sp_int len, const sp_float *src, sp_int srcn);
84
+ void sp_StrArray_splice(sp_StrArray *a, sp_int start, sp_int len, const char *const *src, sp_int srcn);
85
+ void sp_PolyArray_splice(sp_PolyArray *a, sp_int start, sp_int len, sp_RbVal src);
86
+ void sp_IntArray_reverse_bang(sp_IntArray *a);
87
+ void sp_IntArray_rotate_bang(sp_IntArray *a, sp_int n);
88
+ sp_IntArray *sp_IntArray_sort(sp_IntArray *a);
89
+ void sp_IntArray_sort_bang(sp_IntArray *a);
90
+ void sp_IntArray_uniq_bang(sp_IntArray *a);
91
+ void sp_IntArray_shuffle_bang(sp_IntArray *a);
92
+ sp_IntArray *sp_IntArray_shuffle(sp_IntArray *a);
93
+ sp_int sp_IntArray_sample(sp_IntArray *a);
94
+ sp_int sp_IntArray_min(sp_IntArray *a);
95
+ sp_int sp_IntArray_max(sp_IntArray *a);
96
+ const char *sp_StrArray_min(sp_StrArray *a);
97
+ const char *sp_StrArray_max(sp_StrArray *a);
98
+ sp_int sp_IntArray_sum(sp_IntArray *a, sp_int init);
99
+ sp_bool sp_IntArray_include(sp_IntArray *a, sp_int v);
100
+ sp_int sp_IntArray_index(sp_IntArray *a, sp_int v);
101
+ sp_int sp_IntArray_rindex(sp_IntArray *a, sp_int v);
102
+ sp_int sp_IntArray_delete_at(sp_IntArray *a, sp_int i);
103
+ sp_int sp_IntArray_delete(sp_IntArray *a, sp_int v);
104
+ void sp_IntArray_insert(sp_IntArray *a, sp_int i, sp_int v);
105
+ sp_IntArray *sp_IntArray_uniq(sp_IntArray *a);
106
+ sp_IntArray *sp_IntArray_intersect(sp_IntArray *a, sp_IntArray *b);
107
+ sp_bool sp_IntArray_intersect_p(sp_IntArray *a, sp_IntArray *b);
108
+ sp_IntArray *sp_IntArray_union(sp_IntArray *a, sp_IntArray *b);
109
+ sp_IntArray *sp_IntArray_difference(sp_IntArray *a, sp_IntArray *b);
110
+ void sp_IntArray_unshift(sp_IntArray *a, sp_int v);
111
+ const char *sp_IntArray_join(sp_IntArray *a, const char *sep);
112
+ sp_bool sp_IntArray_eq(sp_IntArray *a, sp_IntArray *b);
113
+ sp_int sp_IntArray_cmp(sp_IntArray *a, sp_IntArray *b);
114
+
115
+ /* =========================== sp_FloatArray =========================== */
116
+ static void sp_FloatArray_fin(void*p){sp_FloatArray*a=(sp_FloatArray*)p;sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));sp_gc_bytes_sub(sizeof(sp_float)*a->cap);h->size-=sizeof(sp_float)*a->cap;sp_pl_free(a->data);}
117
+ static sp_FloatArray*sp_FloatArray_new(void){sp_FloatArray*a=(sp_FloatArray*)sp_gc_alloc(sizeof(sp_FloatArray),sp_FloatArray_fin,NULL);a->cap=16;a->data=(sp_float*)sp_pl_alloc(sizeof(sp_float)*a->cap);if(!a->data)sp_oom_die();a->len=0;{sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));h->size+=sizeof(sp_float)*a->cap;sp_gc_bytes_add(sizeof(sp_float)*a->cap);}return a;}
118
+ static void sp_FloatArray_init_embedded(sp_FloatArray*a){a->cap=16;a->data=(sp_float*)sp_pl_alloc(sizeof(sp_float)*a->cap);if(!a->data)sp_oom_die();a->len=0;{sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));h->size+=sizeof(sp_float)*a->cap;sp_gc_bytes_add(sizeof(sp_float)*a->cap);}} /* see sp_IntArray_init_embedded */
119
+ static inline void sp_FloatArray_push(sp_FloatArray*a,sp_float v){if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_FLT_ARRAY);return;}if(a->len>=a->cap){sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));sp_gc_bytes_sub(sizeof(sp_float)*a->cap);h->size-=sizeof(sp_float)*a->cap;a->cap=((((((a->cap*2))))))+1;a->data=(sp_float*)sp_pl_realloc(a->data,sizeof(sp_float)*a->cap);h->size+=sizeof(sp_float)*a->cap;sp_gc_bytes_add(sizeof(sp_float)*a->cap);}a->data[a->len++]=v;}
120
+ /* Array.new(n, v): see sp_IntArray_new_fill */
121
+ static sp_FloatArray*sp_FloatArray_new_fill(sp_int n,sp_float v){sp_FloatArray*a=(sp_FloatArray*)sp_gc_alloc(sizeof(sp_FloatArray),sp_FloatArray_fin,NULL);if((uintmax_t)n>SIZE_MAX/sizeof(sp_float))sp_oom_die();a->cap=n>16?n:16;a->data=(sp_float*)sp_pl_alloc(sizeof(sp_float)*a->cap);if(!a->data)sp_oom_die();for(sp_int i=0;i<n;i++)a->data[i]=v;a->len=n;{sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));h->size+=sizeof(sp_float)*a->cap;sp_gc_bytes_add(sizeof(sp_float)*a->cap);}return a;}
122
+ /* CRuby answers nil for pop/shift on an empty array; the int side already
123
+ returns SP_INT_NIL and the float side answered 0.0, so a drained float
124
+ array read back as a real zero (#4288). sp_float_nil() is the float slot's
125
+ own sentinel, which sp_float_opt_inspect and the boxing helpers know. */
126
+ static inline sp_float sp_FloatArray_pop(sp_FloatArray*a){if(!a||a->len<=0)return sp_float_nil();if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_FLT_ARRAY);return sp_float_nil();}return a->data[--a->len];}
127
+ static inline sp_float sp_FloatArray_shift(sp_FloatArray*a){if(!a||a->len==0)return sp_float_nil();if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_FLT_ARRAY);return sp_float_nil();}sp_float v=a->data[0];for(sp_int i=0;i+1<a->len;i++)a->data[i]=a->data[i+1];a->len--;return v;}
128
+ /* FloatArray is 0-based (no `start` offset, unlike IntArray). delete_at
129
+ (and slice!(i), which shares it) answers nil out of range, as pop and
130
+ shift do: the float slot's sentinel, not a 0.0 nothing could tell from a
131
+ real zero (#4288). */
132
+ static inline sp_float sp_FloatArray_delete_at(sp_FloatArray*a,sp_int i){if(!a)return sp_float_nil();if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_FLT_ARRAY);return sp_float_nil();}if(i<0)i+=a->len;if(i<0||i>=a->len)return sp_float_nil();sp_float v=a->data[i];for(sp_int j=i;j+1<a->len;j++)a->data[j]=a->data[j+1];a->len--;return v;}
133
+ static inline sp_int sp_FloatArray_length(sp_FloatArray*a){return a->len;}
134
+ static inline sp_bool sp_FloatArray_empty(sp_FloatArray*a){return a->len==0;}
135
+ static inline sp_float sp_FloatArray_get(sp_FloatArray*a,sp_int i){if(!a)return sp_float_nil();if(i<0)i+=a->len;if(i<0||i>=a->len)return sp_float_nil();return a->data[i];}
136
+ /* first/last as float? : nil (sentinel) when empty, else the element.
137
+ `[i]` stays non-nullable (0.0 for OOB) -- only first/last produce nil. */
138
+ static inline sp_float sp_FloatArray_first_opt(sp_FloatArray*a){return (!a||a->len<=0)?sp_float_nil():sp_FloatArray_get(a,0);}
139
+ static inline sp_float sp_FloatArray_last_opt(sp_FloatArray*a){return (!a||a->len<=0)?sp_float_nil():sp_FloatArray_get(a,a->len-1);}
140
+ /* The write at or past the end: slots up to `i` read as nil (the sentinel)
141
+ and a gap sets may_nil. Out of line and cold, as the Integer set_slow is,
142
+ so the in-range store stays small. */
143
+ static SP_NOINLINE SP_COLD void sp_FloatArray_fill_to(sp_FloatArray*a,sp_int i){if(i>a->len)SP_MAY_NIL(a)=1;while(i>=a->len){a->data[a->len]=sp_float_nil();a->len++;}}
144
+ /* Issue #769: no-op for negative index after adjustment. */
145
+ static inline void sp_FloatArray_set(sp_FloatArray*a,sp_int i,sp_float v){if(!a)return;if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_FLT_ARRAY);return;}sp_int orig=i;if(i<0)i+=a->len;if(i<0)sp_raise_cls("IndexError",sp_sprintf("index %lld too small for array; minimum: %lld",(long long)orig,(long long)-a->len));while(i>=a->cap){a->cap=((((((a->cap*2))))))+1;a->data=(sp_float*)sp_pl_realloc(a->data,sizeof(sp_float)*a->cap);}if(i>=a->len)sp_FloatArray_fill_to(a,i);a->data[i]=v;} /* the gap is nil, not 0.0 (#3836) */
146
+ /* The Float twins of the IntArray may_nil helpers above. */
147
+ #define sp_FloatArray_push_nilable(a, v) ({ sp_FloatArray *_pn_a = (a); sp_float _pn_v = (v); if (SP_UNLIKELY(sp_float_is_nil(_pn_v))) sp_FloatArray_note_nil(_pn_a); sp_FloatArray_push(_pn_a, _pn_v); })
148
+ #define sp_FloatArray_set_nilable(a, i, v) ({ sp_FloatArray *_sn_a = (a); sp_int _sn_i = (i); sp_float _sn_v = (v); if (SP_UNLIKELY(sp_float_is_nil(_sn_v))) sp_FloatArray_note_nil(_sn_a); sp_FloatArray_set(_sn_a, _sn_i, _sn_v); })
149
+ #define sp_FloatArray_nil_from(d, s) ({ sp_FloatArray *_nf_d = (d); const sp_FloatArray *_nf_s = (s); if (SP_UNLIKELY(_nf_s && SP_MAY_NIL(_nf_s))) sp_FloatArray_note_nil(_nf_d); })
150
+ #define sp_FloatArray_may_nil(a) ({ const sp_FloatArray *_mn_a = (a); (sp_bool)(_mn_a && SP_MAY_NIL(_mn_a)); })
151
+
152
+ /* One step of CRuby's compensated summation (array.c ary_sum): Kahan-Babuska-
153
+ Neumaier, where `comp` collects the low-order bits each add drops and is
154
+ folded back once the run ends. The special-value arms are CRuby's own: a
155
+ total that is already NaN stays NaN, a NaN element makes it NaN, and an
156
+ Infinity element takes the total over unless it meets an Infinity of the
157
+ other sign, which is NaN. Without them the compensation computed
158
+ (inf - inf) and `[Float::INFINITY, 1.0].sum` answered NaN where Ruby
159
+ answers Infinity. Shared so the typed float sum and the boxed fold in
160
+ spinel_rt.h cannot drift apart. */
161
+ static inline void sp_float_sum_step(sp_float *sum, sp_float *comp, sp_float x) {
162
+ sp_float f = *sum;
163
+ if (isnan(f)) return;
164
+ if (isnan(x)) { *sum = x; return; }
165
+ if (isinf(x)) {
166
+ *sum = (isinf(f) && signbit(x) != signbit(f)) ? (sp_float)NAN : x;
167
+ return;
168
+ }
169
+ if (isinf(f)) return;
170
+ {
171
+ sp_float t = f + x;
172
+ if (fabs(f) >= fabs(x)) *comp += (f - t) + x;
173
+ else *comp += (x - t) + f;
174
+ *sum = t;
175
+ }
176
+ }
177
+
178
+ /* ---- sp_FloatArray cold ops (compiled in lib/sp_array.c) ---- */
179
+ void sp_FloatArray_unshift(sp_FloatArray *a, sp_float v);
180
+ sp_FloatArray *sp_FloatArray_from_step(sp_float beg, sp_float end, sp_float step, sp_int excl);
181
+ sp_float sp_float_step_size(sp_float beg, sp_float end, sp_float unit, sp_int excl);
182
+ /* The i-th value of CRuby's ruby_float_step: computed rather than accumulated,
183
+ clamped to end on overshoot; an infinite unit only ever yields beg. */
184
+ static inline sp_float sp_float_step_at(sp_float beg, sp_float end, sp_float unit, sp_int i){if(isinf(unit))return beg;sp_float d=(sp_float)i*unit+beg;if(unit>=0?end<d:d<end)d=end;return d;}
185
+ sp_float sp_FloatArray_min(sp_FloatArray *a);
186
+ sp_float sp_FloatArray_max(sp_FloatArray *a);
187
+ sp_float sp_FloatArray_sum(sp_FloatArray *a, sp_float init);
188
+ void sp_FloatArray_replace(sp_FloatArray *dst, sp_FloatArray *src);
189
+ sp_FloatArray *sp_FloatArray_slice(sp_FloatArray *a, sp_int start, sp_int len);
190
+ sp_FloatArray *sp_FloatArray_slice_range(sp_FloatArray *a, sp_int start, sp_int end_, sp_int excl);
191
+ void sp_FloatArray_reverse_bang(sp_FloatArray *a);
192
+ void sp_FloatArray_rotate_bang(sp_FloatArray *a, sp_int n);
193
+ void sp_FloatArray_sort_bang(sp_FloatArray *a);
194
+ void sp_FloatArray_shuffle_bang(sp_FloatArray *a);
195
+ sp_FloatArray *sp_FloatArray_dup(sp_FloatArray *a);
196
+ sp_FloatArray *sp_FloatArray_sort(sp_FloatArray *a);
197
+ sp_FloatArray *sp_FloatArray_shuffle(sp_FloatArray *a);
198
+ sp_float sp_FloatArray_sample(sp_FloatArray *a);
199
+ sp_bool sp_FloatArray_include(sp_FloatArray *a, sp_float v);
200
+ sp_int sp_FloatArray_index(sp_FloatArray *a, sp_float v);
201
+ sp_int sp_FloatArray_rindex(sp_FloatArray *a, sp_float v);
202
+ sp_float sp_FloatArray_delete(sp_FloatArray *a, sp_float v);
203
+ sp_FloatArray *sp_FloatArray_intersect(sp_FloatArray *a, sp_FloatArray *b);
204
+ sp_bool sp_FloatArray_intersect_p(sp_FloatArray *a, sp_FloatArray *b);
205
+ sp_FloatArray *sp_FloatArray_union(sp_FloatArray *a, sp_FloatArray *b);
206
+ sp_FloatArray *sp_FloatArray_difference(sp_FloatArray *a, sp_FloatArray *b);
207
+ sp_FloatArray *sp_FloatArray_uniq(sp_FloatArray *a);
208
+ void sp_FloatArray_uniq_bang(sp_FloatArray *a);
209
+ void sp_FloatArray_insert(sp_FloatArray *a, sp_int i, sp_float v);
210
+
211
+ /* ============================= sp_PtrArray ============================ */
212
+ /* Array of void* pointers (user-class arrays, FFI pointer arrays). */
213
+ static void sp_PtrArray_fin(void*p){sp_PtrArray*a=(sp_PtrArray*)p;sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));sp_gc_bytes_sub(sizeof(void*)*a->cap);h->size-=sizeof(void*)*a->cap;sp_pl_free(a->data);}
214
+ static void sp_PtrArray_gc_scan(void*p){sp_PtrArray*a=(sp_PtrArray*)p;if(!a->scan_elem)return;for(sp_int i=0;i<a->len;i++){if(a->data[i])a->scan_elem(a->data[i]);}}
215
+ static sp_PtrArray*sp_PtrArray_new_scan(void(*scan_elem)(void*)){sp_PtrArray*a=(sp_PtrArray*)sp_gc_alloc(sizeof(sp_PtrArray),sp_PtrArray_fin,scan_elem?sp_PtrArray_gc_scan:NULL);a->cap=16;a->data=(void**)sp_pl_alloc(sizeof(void*)*a->cap);if(!a->data)sp_oom_die();a->len=0;a->scan_elem=scan_elem;{sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));h->size+=sizeof(void*)*a->cap;sp_gc_bytes_add(sizeof(void*)*a->cap);}return a;}
216
+ static sp_PtrArray*sp_PtrArray_new(void){return sp_PtrArray_new_scan(sp_gc_mark);}
217
+ /* PtrArray for raw external pointers (FFI `:ptr` returns, dlopen handles).
218
+ These don't carry sp_gc_hdr -- the default sp_gc_mark element scan would
219
+ read undefined bytes and crash at collection. Skip per-element scanning;
220
+ the array header itself is still GC-tracked. */
221
+ static sp_PtrArray*sp_PtrArray_new_noscan(void){return sp_PtrArray_new_scan(NULL);}
222
+ static inline void sp_PtrArray_push(sp_PtrArray*a,void*v){sp_gc_wb((void*)a); if(!a)return;if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_PTR_ARRAY);return;}if(a->len>=a->cap){sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));sp_gc_bytes_sub(sizeof(void*)*a->cap);h->size-=sizeof(void*)*a->cap;a->cap=((((((a->cap*2))))))+1;void*nd=sp_pl_realloc(a->data,sizeof(void*)*a->cap);if(!nd)sp_oom_die();a->data=(void**)nd;h->size+=sizeof(void*)*a->cap;sp_gc_bytes_add(sizeof(void*)*a->cap);}a->data[a->len++]=v;}
223
+ /* Array#pop on a `<X>_ptr_array`. Returns NULL when empty (matches CRuby's
224
+ nil for typed-element arrays since the slot can't carry nil). #520. */
225
+ static inline void *sp_PtrArray_pop(sp_PtrArray*a){sp_gc_wb((void*)a); if(!a||a->len==0)return NULL;return a->data[--a->len];}
226
+ /* A pointer array boxed by reference (#4486): its elements are what the stamp
227
+ says (sp_box_ptr_array_k), so an element read boxes a row as the typed
228
+ array it is and an object as its own class, and a store takes exactly that
229
+ kind or raises the TypeError the flat typed arrays raise. An array that was
230
+ never stamped (no emitter boxes one without stamping) reads as opaque
231
+ objects, which is what the erased id always meant. Shared by the runtime
232
+ archive and the generated TU, so only sp_alloc.h/sp_gc.h names appear. */
233
+ static inline const char *sp_PtrArray_kind_name(sp_PtrArray *a) {
234
+ switch (a->elem_kind) {
235
+ case SP_PTR_ELEM_INT_ROWS: return "Array[Integer]";
236
+ case SP_PTR_ELEM_FLT_ROWS: return "Array[Float]";
237
+ case SP_PTR_ELEM_OBJ: return (a->elem_cls >= 0 && sp_obj_cls_name_fn) ? sp_obj_cls_name_fn(a->elem_cls) : "Object";
238
+ default: return "Object";
239
+ }
240
+ }
241
+ static inline sp_RbVal sp_PtrArray_elem_box(sp_PtrArray *a, void *e) {
242
+ if (!e) return sp_box_nil();
243
+ switch (a->elem_kind) {
244
+ case SP_PTR_ELEM_INT_ROWS: return sp_box_obj(e, SP_BUILTIN_INT_ARRAY);
245
+ case SP_PTR_ELEM_FLT_ROWS: return sp_box_obj(e, SP_BUILTIN_FLT_ARRAY);
246
+ case SP_PTR_ELEM_OBJ: return sp_box_nullable_obj_dyn(e, 0); /* the object's own class id, a subclass included */
247
+ default: return sp_box_obj(e, SP_BUILTIN_OBJECT);
248
+ }
249
+ }
250
+ static inline sp_RbVal sp_PtrArray_get_box(sp_PtrArray *a, sp_int i) {
251
+ if (!a) return sp_box_nil();
252
+ if (i < 0) i += a->len;
253
+ if (i < 0 || i >= a->len) return sp_box_nil();
254
+ return sp_PtrArray_elem_box(a, a->data[i]);
255
+ }
256
+ /* the class a boxed value would name in a TypeError, from what this header can see */
257
+ static inline const char *sp_PtrArray_val_class(sp_RbVal v) {
258
+ switch (v.tag) {
259
+ case SP_TAG_INT: return "Integer"; case SP_TAG_FLT: return "Float"; case SP_TAG_STR: return "String";
260
+ case SP_TAG_NIL: return "NilClass"; case SP_TAG_SYM: return "Symbol";
261
+ case SP_TAG_BOOL: return v.v.b ? "TrueClass" : "FalseClass";
262
+ case SP_TAG_OBJ:
263
+ if (v.cls_id >= 0) return sp_obj_cls_name_fn ? sp_obj_cls_name_fn(v.cls_id) : "Object";
264
+ switch (v.cls_id) {
265
+ case SP_BUILTIN_STRBUF: return "String";
266
+ case SP_BUILTIN_INT_ARRAY: case SP_BUILTIN_FLT_ARRAY: case SP_BUILTIN_STR_ARRAY:
267
+ case SP_BUILTIN_SYM_ARRAY: case SP_BUILTIN_POLY_ARRAY: case SP_BUILTIN_PTR_ARRAY: return "Array";
268
+ default: return "Object";
269
+ }
270
+ default: return "Object";
271
+ }
272
+ }
273
+ /* can the array hold v? 1 with the pointer in *out (NULL for nil), else 0 */
274
+ static inline int sp_PtrArray_elem_ok(sp_PtrArray *a, sp_RbVal v, void **out) {
275
+ *out = NULL;
276
+ if (v.tag == SP_TAG_NIL) return 1;
277
+ if (v.tag != SP_TAG_OBJ) return 0;
278
+ switch (a->elem_kind) {
279
+ case SP_PTR_ELEM_INT_ROWS: if (v.cls_id != SP_BUILTIN_INT_ARRAY) return 0; break;
280
+ case SP_PTR_ELEM_FLT_ROWS: if (v.cls_id != SP_BUILTIN_FLT_ARRAY) return 0; break;
281
+ case SP_PTR_ELEM_OBJ:
282
+ if (!(a->elem_cls < 0 || v.cls_id == a->elem_cls ||
283
+ (v.cls_id >= 0 && sp_class_le_id_fn && sp_class_le_id_fn(v.cls_id, a->elem_cls)))) return 0;
284
+ break;
285
+ default: break;
286
+ }
287
+ *out = v.v.p;
288
+ return 1;
289
+ }
290
+ static inline void *sp_PtrArray_elem_unbox(sp_PtrArray *a, sp_RbVal v) {
291
+ void *e;
292
+ if (sp_PtrArray_elem_ok(a, v, &e)) return e;
293
+ sp_exc_stage_recv(v);
294
+ sp_raise_cls("TypeError", sp_sprintf("cannot store %s into an Array[%s]: a typed array holds one kind of element",
295
+ sp_PtrArray_val_class(v), sp_PtrArray_kind_name(a)));
296
+ return NULL;
297
+ }
298
+ /* the boxed elements of a pointer array, for the paths that work on a poly array */
299
+ static inline sp_PolyArray *sp_PtrArray_to_poly(sp_PtrArray *a) {
300
+ SP_GC_ROOT(a);
301
+ sp_PolyArray *r = sp_PolyArray_new(); SP_GC_ROOT(r);
302
+ if (a) for (sp_int i = 0; i < a->len; i++) sp_PolyArray_push(r, sp_PtrArray_elem_box(a, a->data[i]));
303
+ return r;
304
+ }
305
+ static inline void*sp_PtrArray_get(sp_PtrArray*a,sp_int i){if(!a)return NULL;if(i<0)i+=a->len;if(i<0||i>=a->len)return NULL;return a->data[i];}
306
+ /* Issue #770: bounds-check the final index; no-op out-of-range rather
307
+ than writing into adjacent memory (typed slots have a fixed shape). */
308
+ static inline void sp_PtrArray_set(sp_PtrArray*a,sp_int i,void*v){sp_gc_wb((void*)a); if(!a)return;if(i<0)i+=a->len;if(i<0||i>=a->len)return;a->data[i]=v;}
309
+ /* `a[i] = v` through a boxed pointer array: Ruby's index rules (a negative
310
+ index from the end, IndexError below -len, nil-fill past the end), where
311
+ the typed setter above answers a fixed shape (#4486) */
312
+ static inline void sp_PtrArray_set_grow(sp_PtrArray*a,sp_int i,void*v){
313
+ if(!a)return;
314
+ if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_PTR_ARRAY);return;}
315
+ sp_int orig=i; if(i<0)i+=a->len;
316
+ if(i<0)sp_raise_cls("IndexError",sp_sprintf("index %lld too small for array; minimum: %lld",(long long)orig,(long long)-a->len));
317
+ while(a->len<=i)sp_PtrArray_push(a,NULL);
318
+ sp_gc_wb((void*)a); a->data[i]=v;
319
+ }
320
+ static inline sp_int sp_PtrArray_length(sp_PtrArray*a){if(!a)return 0;return a->len;}
321
+ static inline sp_bool sp_PtrArray_empty(sp_PtrArray*a){sp_gc_wb((void*)a); if(!a)return TRUE;return a->len==0;}
322
+
323
+ /* ---- sp_PtrArray cold ops (compiled in lib/sp_array.c) ---- */
324
+ void *sp_PtrArray_delete_at(sp_PtrArray *a, sp_int i);
325
+ void sp_PtrArray_reverse_bang(sp_PtrArray *a);
326
+ void sp_PtrArray_rotate_bang(sp_PtrArray *a, sp_int n);
327
+ sp_PtrArray *sp_PtrArray_dup(sp_PtrArray *a);
328
+ sp_PtrArray *sp_PtrArray_slice(sp_PtrArray *a, sp_int start, sp_int len);
329
+ void sp_PtrArray_shuffle_bang(sp_PtrArray *a);
330
+ sp_PtrArray *sp_PtrArray_shuffle(sp_PtrArray *a);
331
+ void *sp_PtrArray_sample(sp_PtrArray *a);
332
+
333
+ /* ============================= sp_StrArray ============================ */
334
+ /* Small-array optimization: keep the first SP_STRARR_INLINE elements
335
+ inside the struct so empty/short StrArrays skip the data malloc.
336
+ data == inline_data is the discriminator for "still on inline storage". */
337
+ static void sp_StrArray_fin(void*p){sp_StrArray*a=(sp_StrArray*)p;if(a->data!=a->inline_data){sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));sp_gc_bytes_sub(sizeof(const char*)*a->cap);h->size-=sizeof(const char*)*a->cap;sp_pl_free(a->data);}}
338
+ static void sp_StrArray_scan(void*p){sp_StrArray*a=(sp_StrArray*)p;for(sp_int i=0;i<a->len;i++)sp_mark_string(a->data[i]);}
339
+ static sp_StrArray*sp_StrArray_new(void){sp_StrArray*a=(sp_StrArray*)sp_gc_alloc(sizeof(sp_StrArray),sp_StrArray_fin,sp_StrArray_scan);a->cap=SP_STRARR_INLINE;a->data=a->inline_data;a->len=0;return a;}
340
+ static void sp_StrArray_init_embedded(sp_StrArray*a){a->cap=SP_STRARR_INLINE;a->data=a->inline_data;a->len=0;} /* see sp_IntArray_init_embedded */
341
+ static inline void sp_StrArray_push(sp_StrArray*a,const char*v){sp_gc_wb((void*)a); if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_STR_ARRAY);return;}if(a->len>=a->cap){sp_gc_hdr*h=(sp_gc_hdr*)((char*)a-sizeof(sp_gc_hdr));sp_int nc=((((((a->cap*2))))))+1;if(a->data==a->inline_data){const char**nd=(const char**)sp_pl_alloc(sizeof(const char*)*nc);if(!nd)sp_oom_die();memcpy(nd,a->data,sizeof(const char*)*a->len);a->data=nd;}
342
+ else{sp_gc_bytes_sub(sizeof(const char*)*a->cap);h->size-=sizeof(const char*)*a->cap;void*nd=sp_pl_realloc(a->data,sizeof(const char*)*nc);if(!nd)sp_oom_die();a->data=(const char**)nd;}a->cap=nc;h->size+=sizeof(const char*)*a->cap;sp_gc_bytes_add(sizeof(const char*)*a->cap);}a->data[a->len++]=v;}
343
+ static inline sp_int sp_StrArray_length(sp_StrArray*a){return a ? a->len : 0;}
344
+ static inline sp_bool sp_StrArray_empty(sp_StrArray*a){sp_gc_wb((void*)a); return a->len==0;}
345
+ static inline const char*sp_StrArray_get(sp_StrArray*a,sp_int i){if(!a)return NULL;if(i<0)i+=a->len;if(i<0||i>=a->len)return NULL;return a->data[i];}
346
+ static inline void sp_StrArray_set(sp_StrArray*a,sp_int i,const char*v){sp_gc_wb((void*)a); if(!a)return;if(a->frozen){sp_raise_frozen_array_at(a, SP_BUILTIN_STR_ARRAY);return;}sp_int orig=i;if(i<0)i+=a->len;if(i<0)sp_raise_cls("IndexError",sp_sprintf("index %lld too small for array; minimum: %lld",(long long)orig,(long long)-a->len));while(i>=a->len)sp_StrArray_push(a,NULL);a->data[i]=v;} /* the gap is nil, not "" (#3836) */
347
+
348
+ /* ---- sp_StrArray cold ops (compiled in lib/sp_array.c) ---- */
349
+ void sp_StrArray_replace(sp_StrArray *dst, sp_StrArray *src);
350
+ const char *sp_StrArray_pop(sp_StrArray *a);
351
+ const char *sp_StrArray_shift(sp_StrArray *a);
352
+ sp_StrArray *sp_StrArray_slice(sp_StrArray *a, sp_int start, sp_int len);
353
+ sp_StrArray *sp_StrArray_slice_range(sp_StrArray *a, sp_int start, sp_int end_, sp_int excl);
354
+ void sp_StrArray_reverse_bang(sp_StrArray *a);
355
+ void sp_StrArray_rotate_bang(sp_StrArray *a, sp_int n);
356
+ void sp_StrArray_sort_bang(sp_StrArray *a);
357
+ void sp_StrArray_uniq_bang(sp_StrArray *a);
358
+ sp_StrArray *sp_StrArray_uniq(sp_StrArray *a);
359
+ const char *sp_StrArray_join(sp_StrArray *a, const char *sep);
360
+ sp_bool sp_StrArray_include(sp_StrArray *a, const char *v);
361
+ sp_StrArray *sp_StrArray_intersect(sp_StrArray *a, sp_StrArray *b);
362
+ sp_bool sp_StrArray_intersect_p(sp_StrArray *a, sp_StrArray *b);
363
+ sp_StrArray *sp_StrArray_union(sp_StrArray *a, sp_StrArray *b);
364
+ sp_StrArray *sp_StrArray_difference(sp_StrArray *a, sp_StrArray *b);
365
+ sp_int sp_StrArray_index(sp_StrArray *a, const char *v);
366
+ sp_int sp_StrArray_rindex(sp_StrArray *a, const char *v);
367
+ sp_StrArray *sp_StrArray_compact(sp_StrArray *a);
368
+ sp_IntArray *sp_IntArray_compact(sp_IntArray *a);
369
+ sp_FloatArray *sp_FloatArray_compact(sp_FloatArray *a);
370
+ sp_bool sp_IntArray_compact_bang(sp_IntArray *a);
371
+ sp_bool sp_FloatArray_compact_bang(sp_FloatArray *a);
372
+ sp_IntArray *sp_IntArray_nil_cmp_ck(sp_IntArray *a);
373
+ sp_FloatArray *sp_FloatArray_nil_cmp_ck(sp_FloatArray *a);
374
+ sp_IntArray *sp_IntArray_nil_sum_ck(sp_IntArray *a, int float_seed);
375
+ sp_FloatArray *sp_FloatArray_nil_sum_ck(sp_FloatArray *a, int float_seed);
376
+ /* unshift / insert of a value that may be nil (see sp_IntArray_push_nilable) */
377
+ #define sp_IntArray_unshift_nilable(a, v) ({ sp_IntArray *_un_a = (a); sp_int _un_v = (v); if (SP_UNLIKELY(_un_v == SP_INT_NIL)) sp_IntArray_note_nil(_un_a); sp_IntArray_unshift(_un_a, _un_v); })
378
+ #define sp_IntArray_insert_nilable(a, i, v) ({ sp_IntArray *_in_a = (a); sp_int _in_i = (i); sp_int _in_v = (v); if (SP_UNLIKELY(_in_v == SP_INT_NIL)) sp_IntArray_note_nil(_in_a); sp_IntArray_insert(_in_a, _in_i, _in_v); })
379
+ #define sp_FloatArray_insert_nilable(a, i, v) ({ sp_FloatArray *_in_a = (a); sp_int _in_i = (i); sp_float _in_v = (v); if (SP_UNLIKELY(sp_float_is_nil(_in_v))) sp_FloatArray_note_nil(_in_a); sp_FloatArray_insert(_in_a, _in_i, _in_v); })
380
+ #define sp_FloatArray_unshift_nilable(a, v) ({ sp_FloatArray *_un_a = (a); sp_float _un_v = (v); if (SP_UNLIKELY(sp_float_is_nil(_un_v))) sp_FloatArray_note_nil(_un_a); sp_FloatArray_unshift(_un_a, _un_v); })
381
+ /* The elements that are not nil, for all? / any? / none? / one?: the length,
382
+ unless the array is `marked` (analyze saw a nil stored) or may_nil is set. */
383
+ void sp_IntArray_note_nils(sp_IntArray *a);
384
+ void sp_FloatArray_note_nils(sp_FloatArray *a);
385
+ sp_int sp_IntArray_truthy_scan(sp_IntArray *a);
386
+ sp_int sp_FloatArray_truthy_scan(sp_FloatArray *a);
387
+ #define sp_IntArray_truthy_count(a, marked) ({ sp_IntArray *_tc_a = (a); !_tc_a ? (sp_int)0 : ((marked) || SP_MAY_NIL(_tc_a)) ? sp_IntArray_truthy_scan(_tc_a) : _tc_a->len; })
388
+ #define sp_FloatArray_truthy_count(a, marked) ({ sp_FloatArray *_tc_a = (a); !_tc_a ? (sp_int)0 : ((marked) || SP_MAY_NIL(_tc_a)) ? sp_FloatArray_truthy_scan(_tc_a) : _tc_a->len; })
389
+ /* The receiver of min, max, minmax, sort (cmp) or a blockless sum of an array
390
+ analyze did not mark, checked for a nil element: one flag test, and the
391
+ scan (the _ck above, which a marked array takes directly) only where the
392
+ runtime put a nil. */
393
+ #define sp_IntArray_nil_cmp_if_flagged(a) ({ sp_IntArray *_ff_a = (a); (_ff_a && SP_MAY_NIL(_ff_a)) ? sp_IntArray_nil_cmp_ck(_ff_a) : _ff_a; })
394
+ #define sp_FloatArray_nil_cmp_if_flagged(a) ({ sp_FloatArray *_ff_a = (a); (_ff_a && SP_MAY_NIL(_ff_a)) ? sp_FloatArray_nil_cmp_ck(_ff_a) : _ff_a; })
395
+ #define sp_IntArray_nil_sum_if_flagged(a, fs) ({ sp_IntArray *_ff_a = (a); (_ff_a && SP_MAY_NIL(_ff_a)) ? sp_IntArray_nil_sum_ck(_ff_a, (fs)) : _ff_a; })
396
+ #define sp_FloatArray_nil_sum_if_flagged(a, fs) ({ sp_FloatArray *_ff_a = (a); (_ff_a && SP_MAY_NIL(_ff_a)) ? sp_FloatArray_nil_sum_ck(_ff_a, (fs)) : _ff_a; })
397
+ const char *sp_StrArray_delete_at(sp_StrArray *a, sp_int i);
398
+ const char *sp_StrArray_delete(sp_StrArray *a, const char *v);
399
+ void sp_StrArray_insert(sp_StrArray *a, sp_int i, const char *v);
400
+ void sp_StrArray_shuffle_bang(sp_StrArray *a);
401
+ sp_StrArray *sp_StrArray_dup(sp_StrArray *a);
402
+ sp_StrArray *sp_StrArray_sort(sp_StrArray *a);
403
+ sp_StrArray *sp_StrArray_shuffle(sp_StrArray *a);
404
+ const char *sp_StrArray_sample(sp_StrArray *a);
405
+
406
+ /* ---- poly/inspect-dependent ops (lib/sp_array.c; need sp_inspect.h/sp_str.h) ---- */
407
+ void sp_str_upto_each(const char *s, const char *e, sp_int excl, int (*fn)(const char *, void *), void *arg);
408
+ sp_StrArray *sp_StrArray_from_string_range(const char *s, const char *e, sp_int excl);
409
+ const char*sp_IntArray_inspect(sp_IntArray*a);
410
+ const char*sp_FloatArray_inspect(sp_FloatArray*a);
411
+ const char*sp_FloatArray_join(sp_FloatArray*a,const char*sep);
412
+ sp_bool sp_FloatArray_eq(sp_FloatArray*a,sp_FloatArray*b);
413
+ const char*sp_StrArray_inspect(sp_StrArray*a);
414
+ const char*sp_PtrArray_inspect(sp_PtrArray*a);
415
+ sp_PtrArray*sp_IntArray_slice_before(sp_IntArray*a,sp_int d);
416
+ sp_PtrArray*sp_IntArray_slice_after(sp_IntArray*a,sp_int d);
417
+ sp_PtrArray *sp_IntArray_product(sp_IntArray *a, sp_IntArray *b);
418
+ const char*sp_PtrArray_str_join(sp_PtrArray*a,const char*sep);
419
+ sp_RbVal sp_IntArray_index_poly(sp_IntArray *a, sp_int v);
420
+ sp_RbVal sp_IntArray_rindex_poly(sp_IntArray *a, sp_int v);
421
+ sp_RbVal sp_StrArray_index_poly(sp_StrArray *a, const char *v);
422
+ sp_RbVal sp_StrArray_rindex_poly(sp_StrArray *a, const char *v);
423
+ sp_int sp_IntArray_index_opt(sp_IntArray *a, sp_int v);
424
+ sp_int sp_IntArray_rindex_opt(sp_IntArray *a, sp_int v);
425
+ sp_RbVal sp_FloatArray_index_poly(sp_FloatArray *a, sp_float v);
426
+ sp_RbVal sp_FloatArray_rindex_poly(sp_FloatArray *a, sp_float v);
427
+ sp_RbVal sp_FloatArray_index_key(sp_FloatArray *a, sp_RbVal v);
428
+ sp_RbVal sp_FloatArray_rindex_key(sp_FloatArray *a, sp_RbVal v);
429
+ sp_float sp_FloatArray_delete_key(sp_FloatArray *a, sp_RbVal v);
430
+ const int64_t *sp_IntArray_ffi_data(sp_IntArray *a);
431
+ const double *sp_FloatArray_ffi_data(sp_FloatArray *a);
432
+ sp_IntArray *sp_IntArray_concat(sp_IntArray *a, sp_IntArray *b);
433
+ sp_StrArray *sp_StrArray_concat(sp_StrArray *a, sp_StrArray *b);
434
+ sp_FloatArray *sp_FloatArray_concat(sp_FloatArray *a, sp_FloatArray *b);
435
+ sp_PolyArray *sp_IntArray_to_poly(sp_IntArray *a);
436
+ sp_PolyArray *sp_StrArray_to_poly_fmt(sp_StrArray *a);
437
+ sp_PolyArray *sp_FloatArray_to_poly(sp_FloatArray *a);
438
+ sp_IntArray *sp_IntArray_slice_bang(sp_IntArray *a, sp_int from, sp_int n);
439
+ sp_FloatArray *sp_FloatArray_slice_bang(sp_FloatArray *a, sp_int from, sp_int n);
440
+ sp_StrArray *sp_StrArray_slice_bang(sp_StrArray *a, sp_int from, sp_int n);
441
+ sp_PtrArray *sp_PtrArray_slice_bang(sp_PtrArray *a, sp_int from, sp_int n);
442
+
443
+ /* ---- more cold StrArray ops relocated from spinel_rt.h (0 optcarrot
444
+ uses). #include here (not near the top): by this point array.h's own
445
+ hot inline core (sp_StrArray_push et al) is already defined, so
446
+ sp_str.h's nested processing (it needs sp_StrArray_push for
447
+ sp_str_split_push) sees it; the reverse order undeclares it. ---- */
448
+ #include "sp_str.h" /* sp_str_eq, for the cold StrArray ops below */
449
+ const char *sp_StrArray_sum_str(sp_StrArray *a, const char *init);
450
+ sp_RbVal sp_StrArray_uniq_bangq(sp_StrArray *a);
451
+ sp_bool sp_StrArray_eq(sp_StrArray*a,sp_StrArray*b);
452
+
453
+ /* ---- sp_typed_arr_frozen relocated from spinel_rt.h (0 optcarrot uses). ---- */
454
+ int sp_typed_arr_frozen(sp_RbVal v);
455
+
456
+ #endif /* SP_ARRAY_H */