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,402 @@
1
+ /* sp_compat.h -- the GNU C extensions the runtime and the generated C use,
2
+ * behind macros that fall back to standard C where a compiler lacks them.
3
+ *
4
+ * A compiler with the extension keeps the code it compiled before: every
5
+ * macro expands to the same builtin or attribute. One without it (an old or
6
+ * non-GNU toolchain for a small target) gets the fallback: a hint becomes
7
+ * nothing, a builtin becomes the standard (C23 <stdckdint.h>) or hand-written
8
+ * equivalent.
9
+ *
10
+ * Detection asks __has_builtin / __has_attribute / __has_include first; the
11
+ * GCC version is the last resort, for the GCCs that predate the __has_ forms.
12
+ *
13
+ * Defining SP_PORTABLE takes every fallback even where the extension exists,
14
+ * so a GCC or clang build exercises the code a plain C compiler would get.
15
+ * What no macro can express stays an extension under SP_PORTABLE too (the
16
+ * statement expressions and cleanup scopes the generated C is built from, and
17
+ * the rest listed at the end of this file).
18
+ *
19
+ * Included first by sp_types.h, the base header every runtime source and the
20
+ * generated translation unit see; it depends on nothing but <stdint.h>.
21
+ */
22
+ #ifndef SP_COMPAT_H
23
+ #define SP_COMPAT_H
24
+
25
+ #include <stdint.h>
26
+ #include <stddef.h>
27
+
28
+ /* ---- detection ---- */
29
+
30
+ #if defined(__GNUC__) && !defined(__clang__)
31
+ # define SP_GNUC_PREREQ(maj, min) (__GNUC__ > (maj) || (__GNUC__ == (maj) && __GNUC_MINOR__ >= (min)))
32
+ #else
33
+ # define SP_GNUC_PREREQ(maj, min) 0
34
+ #endif
35
+
36
+ #if defined(SP_PORTABLE)
37
+ # define SP_HAS_BUILTIN(x) 0
38
+ # define SP_HAS_ATTRIBUTE(x) 0
39
+ # define SP_GNU_OK 0
40
+ #else
41
+ # if defined(__has_builtin)
42
+ # define SP_HAS_BUILTIN(x) __has_builtin(x)
43
+ # else
44
+ # define SP_HAS_BUILTIN(x) 0
45
+ # endif
46
+ # if defined(__has_attribute)
47
+ # define SP_HAS_ATTRIBUTE(x) __has_attribute(x)
48
+ # else
49
+ # define SP_HAS_ATTRIBUTE(x) 0
50
+ # endif
51
+ /* the version fallback: a GCC before __has_builtin (10) / __has_attribute (5) */
52
+ # if defined(__GNUC__) || defined(__clang__)
53
+ # define SP_GNU_OK 1
54
+ # else
55
+ # define SP_GNU_OK 0
56
+ # endif
57
+ #endif
58
+
59
+ #if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
60
+ # define SP_C11 1
61
+ #else
62
+ # define SP_C11 0
63
+ #endif
64
+
65
+ /* ---- hints: nothing when absent ---- */
66
+
67
+ #if SP_HAS_BUILTIN(__builtin_expect) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 0))
68
+ # define SP_LIKELY(x) __builtin_expect(!!(x), 1)
69
+ # define SP_UNLIKELY(x) __builtin_expect(!!(x), 0)
70
+ /* the value itself, unnormalized: what a site wrote as __builtin_expect(x, v) */
71
+ # define SP_EXPECT(x, v) __builtin_expect((x), (v))
72
+ #else
73
+ # define SP_LIKELY(x) (x)
74
+ # define SP_UNLIKELY(x) (x)
75
+ # define SP_EXPECT(x, v) (x)
76
+ #endif
77
+
78
+ #if SP_HAS_ATTRIBUTE(cold) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(4, 3))
79
+ # define SP_COLD __attribute__((cold))
80
+ #else
81
+ # define SP_COLD
82
+ #endif
83
+
84
+ #if SP_HAS_ATTRIBUTE(noinline) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 1))
85
+ # define SP_NOINLINE __attribute__((noinline))
86
+ #else
87
+ # define SP_NOINLINE
88
+ #endif
89
+
90
+ /* `inline` stays: only the forcing is a hint. The generated C spells it
91
+ `inline SP_ALWAYS_INLINE`, so src/csplit.c still sees the `inline` word. */
92
+ #if SP_HAS_ATTRIBUTE(always_inline) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 1))
93
+ # define SP_ALWAYS_INLINE __attribute__((always_inline))
94
+ #else
95
+ # define SP_ALWAYS_INLINE
96
+ #endif
97
+ #define SP_INLINE inline SP_ALWAYS_INLINE
98
+
99
+ #if SP_HAS_ATTRIBUTE(unused) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 0))
100
+ # define SP_UNUSED __attribute__((unused))
101
+ #else
102
+ # define SP_UNUSED
103
+ #endif
104
+
105
+ #if SP_HAS_ATTRIBUTE(format) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 0))
106
+ # define SP_PRINTF_FORMAT(fmt, first) __attribute__((format(printf, fmt, first)))
107
+ #else
108
+ # define SP_PRINTF_FORMAT(fmt, first)
109
+ #endif
110
+
111
+ /* A tail call the compiler must make. Ruby does not promise one, so the plain
112
+ call a compiler without it makes means the same. Written before `return`. */
113
+ #if SP_HAS_ATTRIBUTE(musttail)
114
+ # define SP_MUSTTAIL __attribute__((musttail))
115
+ #else
116
+ # define SP_MUSTTAIL
117
+ #endif
118
+
119
+ /* noreturn is a hint to the optimizer and the warnings; C11 has its own */
120
+ #if SP_HAS_ATTRIBUTE(noreturn) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(2, 5))
121
+ # define SP_NORETURN __attribute__((noreturn))
122
+ #elif SP_C11
123
+ # define SP_NORETURN _Noreturn
124
+ #else
125
+ # define SP_NORETURN
126
+ #endif
127
+
128
+ #if SP_HAS_BUILTIN(__builtin_unreachable) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(4, 5))
129
+ # define SP_UNREACHABLE() __builtin_unreachable()
130
+ #else
131
+ # include <stdlib.h>
132
+ # define SP_UNREACHABLE() abort()
133
+ #endif
134
+
135
+ #if SP_HAS_BUILTIN(__builtin_prefetch) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 1))
136
+ # define SP_PREFETCH(p) __builtin_prefetch(p)
137
+ #else
138
+ # define SP_PREFETCH(p) ((void)(p))
139
+ #endif
140
+
141
+ /* Is `x` a constant the compiler can see? No means the general path, which
142
+ is always correct. */
143
+ #if SP_HAS_BUILTIN(__builtin_constant_p) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 1))
144
+ # define SP_CONSTANT_P(x) __builtin_constant_p(x)
145
+ #else
146
+ # define SP_CONSTANT_P(x) 0
147
+ #endif
148
+
149
+ /* The pause a spin-wait loop takes between polls. */
150
+ #if !defined(SP_PORTABLE) && (defined(__x86_64__) || defined(__i386__)) && \
151
+ (SP_HAS_BUILTIN(__builtin_ia32_pause) || SP_GNU_OK)
152
+ # define SP_CPU_RELAX() __builtin_ia32_pause()
153
+ #elif !defined(SP_PORTABLE) && (defined(__aarch64__) || defined(__arm__)) && SP_GNU_OK
154
+ # define SP_CPU_RELAX() __asm__ __volatile__("yield" ::: "memory")
155
+ #else
156
+ # define SP_CPU_RELAX() ((void)0)
157
+ #endif
158
+
159
+ /* ---- attributes with a meaning: no silent fallback ---- */
160
+
161
+ /* Run before main. There is no standard spelling; a compiler without it
162
+ leaves the hook unrun, so it is kept even under SP_PORTABLE (the
163
+ generated program would otherwise start with its hooks missing). */
164
+ #if SP_HAS_ATTRIBUTE(constructor) || defined(__GNUC__) || defined(__clang__)
165
+ # define SP_CONSTRUCTOR __attribute__((constructor))
166
+ # define SP_DESTRUCTOR __attribute__((destructor))
167
+ #else
168
+ # error "spinel: the runtime needs __attribute__((constructor)) (see sp_compat.h)"
169
+ #endif
170
+
171
+ /* An optional symbol that is NULL when nothing defines it. Without it the
172
+ feature that probes the symbol is compiled out (SP_HAVE_WEAK is 0). */
173
+ #if SP_HAS_ATTRIBUTE(weak) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 0))
174
+ # define SP_WEAK __attribute__((weak))
175
+ # define SP_HAVE_WEAK 1
176
+ #else
177
+ # define SP_WEAK
178
+ # define SP_HAVE_WEAK 0
179
+ #endif
180
+
181
+ /* Run `fn(&var)` when `var` goes out of scope, by any exit. The GC root and
182
+ regexp frame guards pop themselves this way; nothing standard does it, so
183
+ it is kept under SP_PORTABLE and a compiler without it cannot build the
184
+ generated C (the generator would have to emit every pop itself). */
185
+ #if SP_HAS_ATTRIBUTE(cleanup) || defined(__GNUC__) || defined(__clang__)
186
+ # define SP_CLEANUP(fn) __attribute__((cleanup(fn)))
187
+ #else
188
+ # error "spinel: the runtime needs __attribute__((cleanup)) (see sp_compat.h)"
189
+ #endif
190
+
191
+ /* ---- thread-local storage ---- */
192
+
193
+ #if !defined(SP_PORTABLE) && (defined(__GNUC__) || defined(__clang__))
194
+ # define SP_THREAD_LOCAL __thread
195
+ #elif SP_C11 && !defined(__STDC_NO_THREADS__)
196
+ # define SP_THREAD_LOCAL _Thread_local
197
+ #else
198
+ # define SP_THREAD_LOCAL /* no TLS: only the single-threaded build works */
199
+ # define SP_NO_THREAD_LOCAL 1
200
+ #endif
201
+
202
+ /* ---- overflow-checked arithmetic ----
203
+ The builtin first, then C23's <stdckdint.h>, then a range check by hand.
204
+ Named by operand width (intptr_t, which sp_int is, and uint64_t): the
205
+ builtins are type-generic, the hand-written checks cannot be. Each
206
+ answers nonzero on overflow and stores the wrapped result. */
207
+
208
+ #if (SP_HAS_BUILTIN(__builtin_add_overflow) && SP_HAS_BUILTIN(__builtin_sub_overflow) && \
209
+ SP_HAS_BUILTIN(__builtin_mul_overflow)) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(5, 0))
210
+ # define SP_CKD_BUILTIN 1
211
+ #elif !defined(SP_PORTABLE) && defined(__has_include)
212
+ # if __has_include(<stdckdint.h>)
213
+ # include <stdckdint.h>
214
+ # define SP_CKD_STDC 1
215
+ # endif
216
+ #endif
217
+
218
+ #if defined(SP_CKD_BUILTIN)
219
+ /* the builtin in place, as the call sites wrote it before */
220
+ # define sp_ckd_add_iptr(a, b, r) __builtin_add_overflow(a, b, r)
221
+ # define sp_ckd_sub_iptr(a, b, r) __builtin_sub_overflow(a, b, r)
222
+ # define sp_ckd_mul_iptr(a, b, r) __builtin_mul_overflow(a, b, r)
223
+ # define sp_ckd_add_u64(a, b, r) __builtin_add_overflow(a, b, r)
224
+ # define sp_ckd_mul_u64(a, b, r) __builtin_mul_overflow(a, b, r)
225
+ #elif defined(SP_CKD_STDC)
226
+ # define sp_ckd_add_iptr(a, b, r) ckd_add(r, (intptr_t)(a), (intptr_t)(b))
227
+ # define sp_ckd_sub_iptr(a, b, r) ckd_sub(r, (intptr_t)(a), (intptr_t)(b))
228
+ # define sp_ckd_mul_iptr(a, b, r) ckd_mul(r, (intptr_t)(a), (intptr_t)(b))
229
+ # define sp_ckd_add_u64(a, b, r) ckd_add(r, (uint64_t)(a), (uint64_t)(b))
230
+ # define sp_ckd_mul_u64(a, b, r) ckd_mul(r, (uint64_t)(a), (uint64_t)(b))
231
+ #else
232
+ /* unsigned arithmetic wraps, and the sign bits of the operands against the
233
+ result say whether the signed sum did */
234
+ static inline int sp_ckd_add_iptr(intptr_t a, intptr_t b, intptr_t *r) {
235
+ uintptr_t x = (uintptr_t)a, y = (uintptr_t)b, z = x + y;
236
+ *r = (intptr_t)z;
237
+ return (((x ^ z) & (y ^ z)) >> (sizeof(intptr_t) * 8 - 1)) != 0;
238
+ }
239
+ static inline int sp_ckd_sub_iptr(intptr_t a, intptr_t b, intptr_t *r) {
240
+ uintptr_t x = (uintptr_t)a, y = (uintptr_t)b, z = x - y;
241
+ *r = (intptr_t)z;
242
+ return (((x ^ z) & (~y ^ z)) >> (sizeof(intptr_t) * 8 - 1)) != 0;
243
+ }
244
+ /* the bounds are checked before multiplying: no wider type is portable */
245
+ static inline int sp_ckd_mul_iptr(intptr_t a, intptr_t b, intptr_t *r) {
246
+ int ovf;
247
+ if (a > 0) ovf = b > 0 ? a > INTPTR_MAX / b : b < INTPTR_MIN / a;
248
+ else if (a < 0) ovf = b > 0 ? a < INTPTR_MIN / b : (b < 0 && (a == INTPTR_MIN || b == INTPTR_MIN || -a > INTPTR_MAX / -b));
249
+ else ovf = 0;
250
+ *r = (intptr_t)((uintptr_t)a * (uintptr_t)b);
251
+ return ovf;
252
+ }
253
+ static inline int sp_ckd_add_u64(uint64_t a, uint64_t b, uint64_t *r) {
254
+ *r = a + b;
255
+ return *r < a;
256
+ }
257
+ static inline int sp_ckd_mul_u64(uint64_t a, uint64_t b, uint64_t *r) {
258
+ *r = a * b;
259
+ return a != 0 && *r / a != b;
260
+ }
261
+ #endif
262
+
263
+ /* ---- bit counting (64-bit operands; clz/ctz of 0 is undefined, as the
264
+ builtins leave it) ---- */
265
+
266
+ #if SP_HAS_BUILTIN(__builtin_clzll) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 4))
267
+ # define SP_CLZ64(x) __builtin_clzll((unsigned long long)(x))
268
+ #else
269
+ static inline int sp_clz64_fallback(uint64_t x) {
270
+ int n = 0;
271
+ if (!(x >> 32)) { n += 32; x <<= 32; }
272
+ if (!(x >> 48)) { n += 16; x <<= 16; }
273
+ if (!(x >> 56)) { n += 8; x <<= 8; }
274
+ if (!(x >> 60)) { n += 4; x <<= 4; }
275
+ if (!(x >> 62)) { n += 2; x <<= 2; }
276
+ if (!(x >> 63)) { n += 1; }
277
+ return n;
278
+ }
279
+ # define SP_CLZ64(x) sp_clz64_fallback((uint64_t)(x))
280
+ #endif
281
+
282
+ #if SP_HAS_BUILTIN(__builtin_ctzll) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 4))
283
+ # define SP_CTZ64(x) __builtin_ctzll((unsigned long long)(x))
284
+ #else
285
+ static inline int sp_ctz64_fallback(uint64_t x) {
286
+ int n = 0;
287
+ if (!(x & 0xffffffffu)) { n += 32; x >>= 32; }
288
+ if (!(x & 0xffffu)) { n += 16; x >>= 16; }
289
+ if (!(x & 0xffu)) { n += 8; x >>= 8; }
290
+ if (!(x & 0xfu)) { n += 4; x >>= 4; }
291
+ if (!(x & 0x3u)) { n += 2; x >>= 2; }
292
+ if (!(x & 0x1u)) { n += 1; }
293
+ return n;
294
+ }
295
+ # define SP_CTZ64(x) sp_ctz64_fallback((uint64_t)(x))
296
+ #endif
297
+
298
+ #if SP_HAS_BUILTIN(__builtin_popcountll) || (!defined(SP_PORTABLE) && SP_GNUC_PREREQ(3, 4))
299
+ # define SP_POPCOUNT64(x) __builtin_popcountll((unsigned long long)(x))
300
+ #else
301
+ static inline int sp_popcount64_fallback(uint64_t x) {
302
+ x = x - ((x >> 1) & 0x5555555555555555ULL);
303
+ x = (x & 0x3333333333333333ULL) + ((x >> 2) & 0x3333333333333333ULL);
304
+ x = (x + (x >> 4)) & 0x0f0f0f0f0f0f0f0fULL;
305
+ return (int)((x * 0x0101010101010101ULL) >> 56);
306
+ }
307
+ # define SP_POPCOUNT64(x) sp_popcount64_fallback((uint64_t)(x))
308
+ #endif
309
+
310
+ /* ---- 128-bit integers ---- */
311
+
312
+ #if !defined(SP_PORTABLE) && defined(__SIZEOF_INT128__)
313
+ # define SP_HAVE_INT128 1
314
+ __extension__ typedef __int128 sp_int128;
315
+ __extension__ typedef unsigned __int128 sp_uint128;
316
+ #else
317
+ # define SP_HAVE_INT128 0
318
+ #endif
319
+
320
+ /* ---- atomics ----
321
+ The __atomic builtins take a plain object, which C11's <stdatomic.h> does
322
+ not (it wants an _Atomic one), so the fallback is the plain operation:
323
+ right for the single-threaded runtime, which is all a compiler without
324
+ them can build. The memory-order arguments are dropped with the builtin,
325
+ so the __ATOMIC_* names need not exist there. */
326
+
327
+ /* The threaded runtime needs them for its correctness, not its speed, so
328
+ SP_PORTABLE keeps them there: its fallback is the single-threaded one. */
329
+ #if defined(SP_PORTABLE) && !defined(SP_THREADS)
330
+ # define SP_ATOMICS_BUILTIN 0
331
+ #elif SP_HAS_BUILTIN(__atomic_load_n) || SP_GNUC_PREREQ(4, 7) || defined(__clang__) || \
332
+ (defined(SP_THREADS) && defined(__GNUC__))
333
+ # define SP_ATOMICS_BUILTIN 1
334
+ #else
335
+ # define SP_ATOMICS_BUILTIN 0
336
+ #endif
337
+
338
+ #if SP_ATOMICS_BUILTIN
339
+ # define SP_HAVE_ATOMICS 1
340
+ # define SP_ATOMIC_LOAD(p, mo) __atomic_load_n(p, mo)
341
+ # define SP_ATOMIC_STORE(p, v, mo) __atomic_store_n(p, v, mo)
342
+ # define SP_ATOMIC_EXCHANGE(p, v, mo) __atomic_exchange_n(p, v, mo)
343
+ # define SP_ATOMIC_FETCH_ADD(p, v, mo) __atomic_fetch_add(p, v, mo)
344
+ # define SP_ATOMIC_FETCH_SUB(p, v, mo) __atomic_fetch_sub(p, v, mo)
345
+ # define SP_ATOMIC_FETCH_OR(p, v, mo) __atomic_fetch_or(p, v, mo)
346
+ # define SP_ATOMIC_FETCH_AND(p, v, mo) __atomic_fetch_and(p, v, mo)
347
+ # define SP_ATOMIC_ADD_FETCH(p, v, mo) __atomic_add_fetch(p, v, mo)
348
+ # define SP_ATOMIC_SUB_FETCH(p, v, mo) __atomic_sub_fetch(p, v, mo)
349
+ # define SP_ATOMIC_CAS(p, exp, des, weak, smo, fmo) __atomic_compare_exchange_n(p, exp, des, weak, smo, fmo)
350
+ # define SP_ATOMIC_FENCE(mo) __atomic_thread_fence(mo)
351
+ #else
352
+ # define SP_HAVE_ATOMICS 0
353
+ # if defined(SP_THREADS)
354
+ # error "spinel: the threaded runtime (SP_THREADS) needs the __atomic builtins"
355
+ # endif
356
+ # define SP_ATOMIC_LOAD(p, mo) (*(p))
357
+ # define SP_ATOMIC_STORE(p, v, mo) ((void)(*(p) = (v)))
358
+ /* the old value, without a temporary of the object's type: swap through
359
+ the arithmetic that restores it (integers and pointers alike) */
360
+ # define SP_ATOMIC_EXCHANGE(p, v, mo) sp_atomic_xchg_fallback((void *)(p), sizeof *(p), (uint64_t)(uintptr_t)(v))
361
+ # define SP_ATOMIC_FETCH_ADD(p, v, mo) ((*(p) += (v)) - (v))
362
+ # define SP_ATOMIC_FETCH_SUB(p, v, mo) ((*(p) -= (v)) + (v))
363
+ # define SP_ATOMIC_FETCH_OR(p, v, mo) sp_atomic_or_fallback((uint64_t *)(p), (uint64_t)(v))
364
+ # define SP_ATOMIC_FETCH_AND(p, v, mo) sp_atomic_and_fallback((uint64_t *)(p), (uint64_t)(v))
365
+ # define SP_ATOMIC_ADD_FETCH(p, v, mo) (*(p) += (v))
366
+ # define SP_ATOMIC_SUB_FETCH(p, v, mo) (*(p) -= (v))
367
+ # define SP_ATOMIC_CAS(p, exp, des, weak, smo, fmo) \
368
+ (*(p) == *(exp) ? (*(p) = (des), 1) : (*(exp) = *(p), 0))
369
+ # define SP_ATOMIC_FENCE(mo) ((void)0)
370
+ #endif
371
+
372
+ #if !SP_HAVE_ATOMICS
373
+ #include <string.h>
374
+ /* exchange on an object of 1, 2, 4 or 8 bytes, answering the old value in
375
+ the low bytes of a uint64_t that the caller's cast narrows back */
376
+ static inline uint64_t sp_atomic_xchg_fallback(void *p, size_t n, uint64_t v) {
377
+ uint64_t old = 0;
378
+ switch (n) {
379
+ case 1: { uint8_t o = *(uint8_t *)p; *(uint8_t *)p = (uint8_t)v; old = o; break; }
380
+ case 2: { uint16_t o = *(uint16_t *)p; *(uint16_t *)p = (uint16_t)v; old = o; break; }
381
+ case 4: { uint32_t o = *(uint32_t *)p; *(uint32_t *)p = (uint32_t)v; old = o; break; }
382
+ default: { uint64_t o; memcpy(&o, p, 8); memcpy(p, &v, 8); old = o; break; }
383
+ }
384
+ return old;
385
+ }
386
+ static inline uint64_t sp_atomic_or_fallback(uint64_t *p, uint64_t v) { uint64_t o = *p; *p = o | v; return o; }
387
+ static inline uint64_t sp_atomic_and_fallback(uint64_t *p, uint64_t v) { uint64_t o = *p; *p = o & v; return o; }
388
+ #endif
389
+
390
+ /* ---- what stays an extension under SP_PORTABLE ----
391
+ No macro can stand in for these; a plain C compiler needs the generator
392
+ (or the runtime) to write them differently:
393
+ - statement expressions `({ ... })`, the shape of most generated C;
394
+ - __attribute__((cleanup)) on the GC root and regexp frame guards
395
+ (SP_GC_SAVE / SP_GC_ROOT*, sp_re_frame), which pop at every scope exit;
396
+ - __COUNTER__ in the guard names, and __typeof__ in a few spliced temps;
397
+ - SP_FLOAT_NIL_CONST, a NaN with a payload as a constant expression;
398
+ - __attribute__((constructor)) hooks (SP_CONSTRUCTOR above);
399
+ - an asm label (`__asm__("sym")`) on --ffi declarations;
400
+ - the fiber context switch, written in asm per architecture. */
401
+
402
+ #endif /* SP_COMPAT_H */