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,399 @@
1
+ /*
2
+ ** unicase.c - what case a Unicode character has
3
+ **
4
+ ** The tables in unicase.h and the lookups over them. What a string does with
5
+ ** the answers is string.c's business, and what a pattern does with them is
6
+ ** mruby-regexp's; this file knows only about codepoints.
7
+ **
8
+ ** See Copyright Notice in mruby.h
9
+ */
10
+
11
+ #include <string.h>
12
+ #include <mruby.h>
13
+
14
+ #if defined(MRB_UTF8_STRING) && !defined(MRB_USE_ASCII_CTYPE)
15
+
16
+ #include <mruby/internal.h>
17
+ #include "unicase.h"
18
+
19
+ mrb_static_assert(UNI_CASE_MAX_BYTES <= MRB_UNI_CASE_MAX_BYTES,
20
+ "a mapping outgrew the buffer its callers hand over");
21
+
22
+ static const struct case_table {
23
+ const uint8_t *runs;
24
+ size_t run_count;
25
+ const uint8_t *multi;
26
+ size_t multi_count;
27
+ uint32_t min, max;
28
+ } case_tables[] = {
29
+ {UNI_LOWER_RUNS, UNI_LOWER_RUN_COUNT, UNI_LOWER_MULTI, UNI_LOWER_MULTI_COUNT,
30
+ UNI_LOWER_MIN, UNI_LOWER_MAX},
31
+ {UNI_UPPER_RUNS, UNI_UPPER_RUN_COUNT, UNI_UPPER_MULTI, UNI_UPPER_MULTI_COUNT,
32
+ UNI_UPPER_MIN, UNI_UPPER_MAX},
33
+ {UNI_TITLE_RUNS, UNI_TITLE_RUN_COUNT, UNI_TITLE_MULTI, UNI_TITLE_MULTI_COUNT,
34
+ UNI_TITLE_MIN, UNI_TITLE_MAX},
35
+ {UNI_SWAP_RUNS, UNI_SWAP_RUN_COUNT, UNI_SWAP_MULTI, UNI_SWAP_MULTI_COUNT,
36
+ UNI_SWAP_MIN, UNI_SWAP_MAX},
37
+ {UNI_FOLD_RUNS, UNI_FOLD_RUN_COUNT, UNI_FOLD_MULTI, UNI_FOLD_MULTI_COUNT,
38
+ UNI_FOLD_MIN, UNI_FOLD_MAX},
39
+ };
40
+
41
+ /* The `n` bytes at `p`, least significant first, which is how unicase.h packs
42
+ both of its entry kinds. */
43
+ static uint64_t
44
+ case_bits(const uint8_t *p, int n)
45
+ {
46
+ uint64_t v = 0;
47
+ for (int i = 0; i < n; i++) v |= (uint64_t)p[i] << (8 * i);
48
+ return v;
49
+ }
50
+
51
+ typedef struct case_run {
52
+ uint32_t start, count, stride;
53
+ int32_t delta;
54
+ } case_run;
55
+
56
+ static void
57
+ case_run_at(const uint8_t *runs, size_t i, case_run *r)
58
+ {
59
+ uint64_t v = case_bits(runs + i * UNI_CASE_RUN_BYTES, UNI_CASE_RUN_BYTES);
60
+ r->start = (uint32_t)(v & 0x1FFFFF);
61
+ r->count = (uint32_t)((v >> 21) & 0x7F);
62
+ r->stride = (uint32_t)((v >> 28) & 1) + 1;
63
+ r->delta = (int32_t)((v >> 29) & 0x1FFFF) - UNI_CASE_DELTA_BIAS;
64
+ }
65
+
66
+ /* Locate the run holding cp. Runs are emitted in ascending source order and
67
+ never overlap, so a binary search on start is enough; a run with stride 2
68
+ covers only every other codepoint in its span, which the modulo check
69
+ rejects. */
70
+ static mrb_bool
71
+ case_run_for(const struct case_table *t, uint32_t cp, case_run *out)
72
+ {
73
+ size_t lo = 0, hi = t->run_count;
74
+ while (lo < hi) {
75
+ size_t mid = lo + (hi - lo) / 2;
76
+ case_run r;
77
+ case_run_at(t->runs, mid, &r);
78
+ uint32_t last = r.start + (r.count - 1) * r.stride;
79
+ if (cp < r.start) hi = mid;
80
+ else if (cp > last) lo = mid + 1;
81
+ else {
82
+ if ((cp - r.start) % r.stride != 0) return FALSE;
83
+ *out = r;
84
+ return TRUE;
85
+ }
86
+ }
87
+ return FALSE;
88
+ }
89
+
90
+ static mrb_bool
91
+ case_multi_for(const struct case_table *t, uint32_t cp, uint32_t *off, uint32_t *len)
92
+ {
93
+ size_t lo = 0, hi = t->multi_count;
94
+ while (lo < hi) {
95
+ size_t mid = lo + (hi - lo) / 2;
96
+ uint64_t v = case_bits(t->multi + mid * UNI_CASE_MULTI_BYTES, UNI_CASE_MULTI_BYTES);
97
+ uint32_t mcp = (uint32_t)(v & 0x1FFFFF);
98
+ if (cp < mcp) hi = mid;
99
+ else if (cp > mcp) lo = mid + 1;
100
+ else {
101
+ *off = (uint32_t)((v >> 21) & 0xFFF);
102
+ *len = (uint32_t)((v >> 33) & 7);
103
+ return TRUE;
104
+ }
105
+ }
106
+ return FALSE;
107
+ }
108
+
109
+ /* Ask one table about cp, writing what it says into buf. Answers the byte
110
+ count written, 0 for a character the table maps to itself, and -1 for one
111
+ the table says nothing about. The two apart is what lets title case hand a
112
+ character it says nothing about on to upper case while keeping the ones it
113
+ deliberately maps to themselves. */
114
+ static mrb_int
115
+ case_map_one(enum mrb_case_kind kind, uint32_t cp, char *buf)
116
+ {
117
+ const struct case_table *t = &case_tables[kind];
118
+ if (cp < t->min || t->max < cp) return -1;
119
+
120
+ uint32_t off, len;
121
+ if (case_multi_for(t, cp, &off, &len)) {
122
+ memcpy(buf, uni_case_pool + off, len);
123
+ return (mrb_int)len;
124
+ }
125
+ case_run r;
126
+ if (!case_run_for(t, cp, &r)) return -1;
127
+ if (r.delta == 0) return 0;
128
+ return mrb_utf8_to_buf(buf, (mrb_int)cp + r.delta);
129
+ }
130
+
131
+ mrb_int
132
+ mrb_uni_case_map(enum mrb_case_kind kind, uint32_t cp, char *buf)
133
+ {
134
+ mrb_int n = case_map_one(kind, cp, buf);
135
+ if (n >= 0) return n;
136
+
137
+ switch (kind) {
138
+ case MRB_CASE_KIND_TITLE:
139
+ /* Title case is the difference from upper case, so a character the
140
+ difference says nothing about takes the upper case answer. */
141
+ n = case_map_one(MRB_CASE_KIND_UPPER, cp, buf);
142
+ break;
143
+ case MRB_CASE_KIND_SWAP:
144
+ /* Swapping is the difference from this rule: a character with a lower
145
+ case is an upper case one and swaps down, and one without swaps up. */
146
+ n = case_map_one(MRB_CASE_KIND_LOWER, cp, buf);
147
+ if (n < 0) n = case_map_one(MRB_CASE_KIND_UPPER, cp, buf);
148
+ break;
149
+ case MRB_CASE_KIND_FOLD:
150
+ /* Folding is the difference from the lowercase mapping, so a character
151
+ the difference says nothing about folds the way it lower cases. */
152
+ n = case_map_one(MRB_CASE_KIND_LOWER, cp, buf);
153
+ break;
154
+ default:
155
+ break;
156
+ }
157
+ return n < 0 ? 0 : n;
158
+ }
159
+
160
+ #ifdef HAVE_MRUBY_REGEXP_GEM
161
+
162
+ /* ------------------------------------------------------------- folding
163
+
164
+ Simple case folding is what a pattern asks for under /i, and it is the two
165
+ run tables read in order: the folding difference first, and the lowercase
166
+ mapping under it for the sources the difference passes over. A source whose
167
+ folding spells several characters (U+FB00 to "ff") is in a multi table and
168
+ in neither set of runs, which is exactly the set simple folding leaves
169
+ alone.
170
+
171
+ /i is the whole of what asks, so the gem that has one says it is here and
172
+ the rest of this file goes with it. Nothing else would drop it: the mapping
173
+ above is in the same object, every build calls that, and the linker takes
174
+ an object whole. */
175
+
176
+ /* Whether the folding difference holds a run over any of [lo, hi]. A caller
177
+ walking the lowercase runs asks this to know whether the difference has
178
+ something to say about the span it is about to report whole. Runs ascend
179
+ and never overlap, so their ends ascend too: the first run whose end
180
+ reaches lo is the only one that can start before hi, and the search below
181
+ keeps its start, since the last run it steps h down to is that one. */
182
+ static mrb_bool
183
+ fold_diff_touches(uint32_t lo, uint32_t hi)
184
+ {
185
+ const struct case_table *t = &case_tables[MRB_CASE_KIND_FOLD];
186
+ size_t l = 0, h = t->run_count;
187
+ uint32_t start = UINT32_MAX; /* past any hi, so no run found means FALSE */
188
+ while (l < h) {
189
+ size_t mid = l + (h - l) / 2;
190
+ case_run r;
191
+ case_run_at(t->runs, mid, &r);
192
+ if (r.start + (r.count - 1) * r.stride < lo) l = mid + 1;
193
+ else {
194
+ h = mid;
195
+ start = r.start;
196
+ }
197
+ }
198
+ return start <= hi;
199
+ }
200
+
201
+ uint32_t
202
+ mrb_uni_case_fold(uint32_t cp)
203
+ {
204
+ /* ASCII is out of the tables, being what the tables are the rest of. */
205
+ if (cp < 128) return (cp >= 'A' && cp <= 'Z') ? cp + 32 : cp;
206
+
207
+ case_run r;
208
+ const struct case_table *f = &case_tables[MRB_CASE_KIND_FOLD];
209
+ if (f->min <= cp && cp <= f->max && case_run_for(f, cp, &r)) {
210
+ /* A run of delta 0 here is the difference saying the source folds to
211
+ itself where it lower cases to something, which is an answer. */
212
+ return (uint32_t)((int32_t)cp + r.delta);
213
+ }
214
+ const struct case_table *l = &case_tables[MRB_CASE_KIND_LOWER];
215
+ if (l->min <= cp && cp <= l->max && case_run_for(l, cp, &r)) {
216
+ return (uint32_t)((int32_t)cp + r.delta);
217
+ }
218
+ return cp;
219
+ }
220
+
221
+ /* Every source in `t` whose folded form is `folded`, checked back through
222
+ mrb_uni_case_fold() so that a source the difference overrides is not
223
+ reported from the mapping under it. */
224
+ static int
225
+ unfold_from(const struct case_table *t, uint32_t cp, uint32_t folded,
226
+ uint32_t *out, int max, int n)
227
+ {
228
+ for (size_t i = 0; i < t->run_count && n < max; i++) {
229
+ case_run r;
230
+ case_run_at(t->runs, i, &r);
231
+ int32_t s = (int32_t)folded - r.delta;
232
+ if (s < (int32_t)r.start) continue;
233
+ uint32_t off = (uint32_t)s - r.start;
234
+ if (off % r.stride) continue;
235
+ if (off / r.stride >= r.count) continue;
236
+ if ((uint32_t)s == cp) continue;
237
+ if (mrb_uni_case_fold((uint32_t)s) != folded) continue;
238
+ for (int k = 0; k < n; k++) if (out[k] == (uint32_t)s) goto next;
239
+ out[n++] = (uint32_t)s;
240
+ next:
241
+ ;
242
+ }
243
+ return n;
244
+ }
245
+
246
+ int
247
+ mrb_uni_case_unfold(uint32_t cp, uint32_t *out, int max)
248
+ {
249
+ int n = 0;
250
+ uint32_t folded = mrb_uni_case_fold(cp);
251
+
252
+ /* The folded form is itself a member of the class. */
253
+ if (folded != cp && n < max) out[n++] = folded;
254
+
255
+ /* ASCII sources are in no table, so the upper case letter that folds into a
256
+ lower case one is added here. */
257
+ if (folded >= 'a' && folded <= 'z' && folded - 32 != cp && n < max) {
258
+ out[n++] = folded - 32;
259
+ }
260
+
261
+ /* A non-ASCII source folding into ASCII (U+017F into 's') is the only thing
262
+ an ASCII source can find in a table, and the generator lists those beside
263
+ the tables, so the list is the whole answer for one. What that saves is
264
+ the two full scans below, which an ASCII source would otherwise make to
265
+ collect the entries the list already holds. Most patterns are ASCII and
266
+ nothing else, and this is what /i costs them. */
267
+ if (cp < 128) {
268
+ #define X(src, to) if (folded == (to) && n < max) out[n++] = (src);
269
+ UNI_FOLD_TO_ASCII
270
+ #undef X
271
+ return n;
272
+ }
273
+
274
+ n = unfold_from(&case_tables[MRB_CASE_KIND_FOLD], cp, folded, out, max, n);
275
+ n = unfold_from(&case_tables[MRB_CASE_KIND_LOWER], cp, folded, out, max, n);
276
+ return n;
277
+ }
278
+
279
+ /* Both range walks read the tables run by run, which keeps a wide range cheap:
280
+ a run of stride 1 contributes one span whatever its length. A run the
281
+ folding difference has something to say about is reported one codepoint at a
282
+ time instead, since the difference may override any part of it. */
283
+ static void
284
+ fold_span(uint32_t lo, uint32_t hi, void (*add)(void *, uint32_t, uint32_t), void *user)
285
+ {
286
+ for (uint32_t cp = lo; cp <= hi; cp++) {
287
+ uint32_t f = mrb_uni_case_fold(cp);
288
+ if (f != cp) add(user, f, f);
289
+ }
290
+ }
291
+
292
+ static void
293
+ fold_range_of(const struct case_table *t, mrb_bool guard, uint32_t lo, uint32_t hi,
294
+ void (*add)(void *, uint32_t, uint32_t), void *user)
295
+ {
296
+ for (size_t i = 0; i < t->run_count; i++) {
297
+ case_run r;
298
+ case_run_at(t->runs, i, &r);
299
+ uint32_t span = (r.count - 1) * r.stride;
300
+
301
+ uint32_t s_lo = r.start > lo ? r.start : lo;
302
+ uint32_t s_hi = r.start + span < hi ? r.start + span : hi;
303
+ if (s_lo > s_hi) continue;
304
+ /* Round s_lo up and s_hi down to codepoints the run actually holds. */
305
+ uint32_t off = s_lo - r.start;
306
+ if (off % r.stride) s_lo += r.stride - (off % r.stride);
307
+ s_hi -= (s_hi - r.start) % r.stride;
308
+ if (s_lo > s_hi) continue;
309
+
310
+ if (guard && fold_diff_touches(s_lo, s_hi)) {
311
+ fold_span(s_lo, s_hi, add, user);
312
+ }
313
+ else if (r.stride == 1) {
314
+ if (r.delta != 0) {
315
+ add(user, (uint32_t)((int32_t)s_lo + r.delta), (uint32_t)((int32_t)s_hi + r.delta));
316
+ }
317
+ }
318
+ else {
319
+ for (uint32_t cp = s_lo; cp <= s_hi; cp += r.stride) {
320
+ if (r.delta == 0) continue;
321
+ uint32_t f = (uint32_t)((int32_t)cp + r.delta);
322
+ add(user, f, f);
323
+ }
324
+ }
325
+ }
326
+ }
327
+
328
+ void
329
+ mrb_uni_case_fold_range(uint32_t lo, uint32_t hi,
330
+ void (*add)(void *, uint32_t, uint32_t), void *user)
331
+ {
332
+ fold_range_of(&case_tables[MRB_CASE_KIND_FOLD], FALSE, lo, hi, add, user);
333
+ fold_range_of(&case_tables[MRB_CASE_KIND_LOWER], TRUE, lo, hi, add, user);
334
+ }
335
+
336
+ /* The sources of the folds landing in [lo, hi]. A source found through the
337
+ lowercase mapping is checked back through mrb_uni_case_fold(), since the
338
+ difference may fold it elsewhere or leave it alone. */
339
+ static void
340
+ unfold_range_of(const struct case_table *t, mrb_bool guard, uint32_t lo, uint32_t hi,
341
+ void (*add)(void *, uint32_t, uint32_t), void *user)
342
+ {
343
+ for (size_t i = 0; i < t->run_count; i++) {
344
+ case_run r;
345
+ case_run_at(t->runs, i, &r);
346
+ uint32_t span = (r.count - 1) * r.stride;
347
+
348
+ int32_t f_start = (int32_t)r.start + r.delta;
349
+ if (f_start < 0) continue;
350
+ int32_t f_end = f_start + (int32_t)span;
351
+ uint32_t f_lo = (uint32_t)f_start > lo ? (uint32_t)f_start : lo;
352
+ uint32_t f_hi = (uint32_t)f_end < hi ? (uint32_t)f_end : hi;
353
+ if (f_lo > f_hi) continue;
354
+ uint32_t off = f_lo - (uint32_t)f_start;
355
+ if (off % r.stride) f_lo += r.stride - (off % r.stride);
356
+ f_hi -= (f_hi - (uint32_t)f_start) % r.stride;
357
+ if (f_lo > f_hi) continue;
358
+
359
+ uint32_t s_lo = (uint32_t)((int32_t)f_lo - r.delta);
360
+ uint32_t s_hi = (uint32_t)((int32_t)f_hi - r.delta);
361
+ if (guard && fold_diff_touches(s_lo, s_hi)) {
362
+ for (uint32_t cp = s_lo; cp <= s_hi; cp += r.stride) {
363
+ uint32_t f = mrb_uni_case_fold(cp);
364
+ if (f != cp && lo <= f && f <= hi) add(user, cp, cp);
365
+ }
366
+ }
367
+ else if (r.stride == 1) {
368
+ if (r.delta != 0) add(user, s_lo, s_hi);
369
+ }
370
+ else {
371
+ for (uint32_t cp = s_lo; cp <= s_hi; cp += r.stride) {
372
+ if (r.delta != 0) add(user, cp, cp);
373
+ }
374
+ }
375
+ }
376
+ }
377
+
378
+ void
379
+ mrb_uni_case_unfold_range(uint32_t lo, uint32_t hi,
380
+ void (*add)(void *, uint32_t, uint32_t), void *user)
381
+ {
382
+ /* An ASCII fold has the listed sources and no others, for the reason
383
+ mrb_uni_case_unfold() gives, so the ASCII part of the span is answered
384
+ from the list and the walks below are handed what is left of it. A class
385
+ of nothing but ASCII, which is most classes, reaches neither walk. */
386
+ if (lo < 128) {
387
+ #define X(src, to) if (lo <= (to) && (to) <= hi) add(user, (src), (src));
388
+ UNI_FOLD_TO_ASCII
389
+ #undef X
390
+ if (hi < 128) return;
391
+ lo = 128;
392
+ }
393
+ unfold_range_of(&case_tables[MRB_CASE_KIND_FOLD], FALSE, lo, hi, add, user);
394
+ unfold_range_of(&case_tables[MRB_CASE_KIND_LOWER], TRUE, lo, hi, add, user);
395
+ }
396
+
397
+ #endif /* HAVE_MRUBY_REGEXP_GEM */
398
+
399
+ #endif /* MRB_UTF8_STRING && !MRB_USE_ASCII_CTYPE */