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
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 302d0fa96881495731eb70720ef57850577cd6abccdce2037be53640ad961fa2
|
|
4
|
+
data.tar.gz: 9b16290e8a14b8f8d9852e5306553bf7dc266b34a32d6e6c90b5f2fab7e02533
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: b80a5b426ca64035ed32c7f03ddb4a38bf7f784e6fc96ffd1c1bae5112ea530230ddac1aaaa053b80017e45b6798b5c3d5a47e0c82d3a44285dfe38b7615c49b
|
|
7
|
+
data.tar.gz: 4712f8478d40c573807b3d65552910e6dc1ee583b4b51c93e36cbceac92dfd7a33f4eca90788e8082e2f577e958d5ecacbeaa1738749afa870e0dff970b75f49
|
data/LICENSE-mruby.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Parts of the Spinel runtime under ext/qr_reader_native (marked "See Copyright
|
|
2
|
+
Notice in mruby.h") are derived from mruby:
|
|
3
|
+
|
|
4
|
+
Copyright (c) 2010- mruby developers
|
|
5
|
+
|
|
6
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
7
|
+
copy of this software and associated documentation files (the "Software"),
|
|
8
|
+
to deal in the Software without restriction, including without limitation
|
|
9
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
10
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
|
11
|
+
Software is furnished to do so, subject to the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be included in
|
|
14
|
+
all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
21
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
22
|
+
DEALINGS IN THE SOFTWARE.
|
data/LICENSE-spinel.txt
ADDED
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
Copyright (c) 2024- Yukihiro Matsumoto (matz@ruby.or.jp)
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a
|
|
4
|
+
copy of this software and associated documentation files (the "Software"),
|
|
5
|
+
to deal in the Software without restriction, including without limitation
|
|
6
|
+
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
7
|
+
and/or sell copies of the Software, and to permit persons to whom the
|
|
8
|
+
Software is furnished to do so, subject to the following conditions:
|
|
9
|
+
|
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
|
11
|
+
all copies or substantial portions of the Software.
|
|
12
|
+
|
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
18
|
+
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
19
|
+
DEALINGS IN THE SOFTWARE.
|
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andi Idogawa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# qr_reader-native
|
|
2
|
+
|
|
3
|
+
Optional native speed-up for [qr_reader](https://github.com/largo/qr_reader).
|
|
4
|
+
|
|
5
|
+
qr_reader is pure Ruby. Its hot loops (image decoding, binarization, pattern
|
|
6
|
+
scanning) are written as plain-Ruby "kernels" in a subset of Ruby that the
|
|
7
|
+
[Spinel](https://github.com/matz/spinel) AOT compiler understands. This gem is
|
|
8
|
+
those very kernels compiled to C by Spinel: install it next to qr_reader and
|
|
9
|
+
qr_reader uses them automatically.
|
|
10
|
+
|
|
11
|
+
```ruby
|
|
12
|
+
# Gemfile
|
|
13
|
+
gem "qr_reader"
|
|
14
|
+
gem "qr_reader-native" # optional; needs a C compiler at install time
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
```ruby
|
|
18
|
+
require "qr_reader"
|
|
19
|
+
QrReader.native? # => true when the native kernels are in use
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
- Same results: the native kernels are compiled from the same source as the
|
|
23
|
+
Ruby ones and are tested against them.
|
|
24
|
+
- Safe to omit: without this gem, or on Rubies without C extensions (JRuby,
|
|
25
|
+
ruby.wasm, ...), qr_reader runs the same code as Ruby.
|
|
26
|
+
- Version-locked: it depends on the identical qr_reader version and is only
|
|
27
|
+
used when its kernel digest matches the installed qr_reader.
|
|
28
|
+
- `QR_READER_NATIVE=0` disables it at runtime.
|
|
29
|
+
|
|
30
|
+
## Which kernels run natively
|
|
31
|
+
|
|
32
|
+
Each kernel is used natively only where that was measured to be faster
|
|
33
|
+
(`QrReader::NativeKernels::ALWAYS`/`WITHOUT_YJIT`/`NEVER`):
|
|
34
|
+
|
|
35
|
+
| kernel | with YJIT | without YJIT |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| hybrid binarization | 2.6x faster | 8.9x faster |
|
|
38
|
+
| finder-pattern scan | 9.6x faster | 6.3x faster |
|
|
39
|
+
| downscale | ~same | 8x faster |
|
|
40
|
+
| CCITT G3/G4 | ~same | 3.6x faster |
|
|
41
|
+
| JPEG IDCT rendering | 4-20x faster | 4-20x faster |
|
|
42
|
+
| PNG / pixel conversion | slower -> Ruby | 3x faster |
|
|
43
|
+
| JPEG entropy decoding | not used | not used |
|
|
44
|
+
|
|
45
|
+
JPEG entropy decoding compiled by the current Spinel (see
|
|
46
|
+
ext/qr_reader_native/SPINEL_VERSION) is 2x faster on small images but slows
|
|
47
|
+
down superlinearly with image size (32 ms at 640x480, 3 s at 2560x1920, versus
|
|
48
|
+
83 ms in Ruby), so it stays Ruby until that is fixed in Spinel. The usual
|
|
49
|
+
suspects (`byteindex`, `byteslice`, `getbyte` on strings passed from CRuby,
|
|
50
|
+
appends, Strings held in Arrays) are all linear in isolation (see
|
|
51
|
+
bench/spinel/ in the qr_reader repository).
|
|
52
|
+
|
|
53
|
+
Installing compiles about 4 MB of generated C (Spinel's runtime included);
|
|
54
|
+
Spinel itself is not needed.
|
|
55
|
+
|
|
56
|
+
## Licenses
|
|
57
|
+
|
|
58
|
+
MIT (see LICENSE.txt). `ext/qr_reader_native` contains code generated by
|
|
59
|
+
Spinel and the Spinel runtime (MIT, Copyright (c) 2024- Yukihiro Matsumoto,
|
|
60
|
+
see LICENSE-spinel.txt), parts of which derive from mruby (MIT, see
|
|
61
|
+
LICENSE-mruby.txt).
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
spinel 2026.09.12+7228 (84f5b5020) [gcc 15.2.0 (cc)]
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "mkmf"
|
|
4
|
+
|
|
5
|
+
# The sources are generated by Spinel (script/native_generate.rb) and include
|
|
6
|
+
# Spinel's runtime; they only need a C compiler.
|
|
7
|
+
$INCFLAGS << " -I$(srcdir)"
|
|
8
|
+
create_makefile("qr_reader_native/qr_reader_native")
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/* shim/mruby/error.h - see shim/mruby.h */
|
|
2
|
+
#ifndef SP_RE_SHIM_MRUBY_ERROR_H
|
|
3
|
+
#define SP_RE_SHIM_MRUBY_ERROR_H
|
|
4
|
+
#include "../mruby.h"
|
|
5
|
+
|
|
6
|
+
struct RClass;
|
|
7
|
+
struct RClass *mrb_exc_get_id(mrb_state *mrb, mrb_sym name);
|
|
8
|
+
mrb_value mrb_exc_new_str(mrb_state *mrb, struct RClass *c, mrb_value str);
|
|
9
|
+
/* the one exception the engine raises is a RegexpError, and it hands the
|
|
10
|
+
message to spinel's handler (sp_re_set_error_handler), which does not
|
|
11
|
+
return */
|
|
12
|
+
__attribute__((noreturn)) void mrb_exc_raise(mrb_state *mrb, mrb_value exc);
|
|
13
|
+
#endif
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/* shim/mruby/internal.h - see shim/mruby.h. The UTF-8 scan and the case
|
|
2
|
+
declarations below are mruby's include/mruby/internal.h as it spells them. */
|
|
3
|
+
#ifndef SP_RE_SHIM_MRUBY_INTERNAL_H
|
|
4
|
+
#define SP_RE_SHIM_MRUBY_INTERNAL_H
|
|
5
|
+
#include "../mruby.h"
|
|
6
|
+
|
|
7
|
+
#define MRB_ENC_MULTIBYTE_P 1
|
|
8
|
+
|
|
9
|
+
/* a buffer that lives until the compile ends (re_spinel.c) */
|
|
10
|
+
void *mrb_temp_alloc(mrb_state *mrb, size_t size);
|
|
11
|
+
|
|
12
|
+
mrb_int mrb_utf8_to_buf(char *buf, mrb_int cp);
|
|
13
|
+
|
|
14
|
+
#define MRB_UTF8_MALFORMED (-1)
|
|
15
|
+
#define MRB_UTF8_TRUNCATED (-2)
|
|
16
|
+
#define MRB_UTF8_REDUNDANT (-3)
|
|
17
|
+
#define MRB_UTF8_EXCLUDED (-4)
|
|
18
|
+
#define MRB_UTF8_LONG (-5)
|
|
19
|
+
|
|
20
|
+
static inline mrb_int
|
|
21
|
+
mrb_utf8_scan(const char *p, const char *e, uint32_t *uv, const uint8_t bounds[][2])
|
|
22
|
+
{
|
|
23
|
+
/* the byte length a lead byte claims, by its top five bits; the last entry
|
|
24
|
+
folds 0xF8-0xFF together and they are told apart below. The table lives
|
|
25
|
+
in the function, as the lookup tables of boxing_word.h do, so that a
|
|
26
|
+
translation unit that never reads through the scan emits neither, at
|
|
27
|
+
any optimization level. */
|
|
28
|
+
static const uint8_t lead[32] = {
|
|
29
|
+
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
|
30
|
+
0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 3, 3, 4, 0
|
|
31
|
+
};
|
|
32
|
+
const unsigned char *q = (const unsigned char*)p;
|
|
33
|
+
unsigned char c = q[0];
|
|
34
|
+
mrb_int n = lead[c >> 3];
|
|
35
|
+
|
|
36
|
+
if (n <= 1) {
|
|
37
|
+
if (n == 1) {
|
|
38
|
+
if (uv) *uv = c;
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
/* a continuation byte leads nothing; 0xF8-0xFD claim five or six,
|
|
42
|
+
the lengths RFC 3629 withdrew, which a reader that wants them reads
|
|
43
|
+
for itself */
|
|
44
|
+
return (c < 0xF8 || c >= 0xFE) ? MRB_UTF8_MALFORMED : MRB_UTF8_LONG;
|
|
45
|
+
}
|
|
46
|
+
if (n > e - p) return MRB_UTF8_TRUNCATED;
|
|
47
|
+
|
|
48
|
+
/* Each byte after the lead has to continue it. A second byte inside its
|
|
49
|
+
bounds has, since the table admits nothing else, so only one outside
|
|
50
|
+
them walks the sequence to tell a malformed one from a bounded one. The
|
|
51
|
+
later checks nest in the order the bytes come, so a length costs the
|
|
52
|
+
compares up to its own and none past it. Read as a signed char, a
|
|
53
|
+
continuation byte is one below -0x40, a single compare where the mask
|
|
54
|
+
takes three. A caller that wants the form alone passes no `uv`, and the
|
|
55
|
+
value is dead code the compiler drops. */
|
|
56
|
+
const uint8_t *b = bounds[c - 0xC0];
|
|
57
|
+
if (q[1] < b[0] || q[1] > b[1]) {
|
|
58
|
+
for (mrb_int i = 1; i < n; i++) {
|
|
59
|
+
if ((signed char)q[i] >= -0x40) return MRB_UTF8_MALFORMED;
|
|
60
|
+
}
|
|
61
|
+
return q[1] < b[0] ? MRB_UTF8_REDUNDANT : MRB_UTF8_EXCLUDED;
|
|
62
|
+
}
|
|
63
|
+
uint32_t v = ((c & (0x7F >> n)) << 6) | (q[1] & 0x3F);
|
|
64
|
+
if (n > 2) {
|
|
65
|
+
if ((signed char)q[2] >= -0x40) return MRB_UTF8_MALFORMED;
|
|
66
|
+
v = (v << 6) | (q[2] & 0x3F);
|
|
67
|
+
if (n > 3) {
|
|
68
|
+
if ((signed char)q[3] >= -0x40) return MRB_UTF8_MALFORMED;
|
|
69
|
+
v = (v << 6) | (q[3] & 0x3F);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (uv) *uv = v;
|
|
73
|
+
return n;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
mrb_int mrb_utf8len(const char *str, const char *end);
|
|
77
|
+
const char *mrb_utf8_char_head(const char *beg, const char *p, const char *end);
|
|
78
|
+
uint32_t mrb_utf8_decode(const char *p, const char *e, mrb_int *lenp);
|
|
79
|
+
|
|
80
|
+
static inline mrb_int
|
|
81
|
+
mrb_enc_charlen(const char *p, const char *e)
|
|
82
|
+
{
|
|
83
|
+
return mrb_utf8len(p, e);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
static inline const char *
|
|
87
|
+
mrb_enc_char_head(const char *beg, const char *p, const char *end)
|
|
88
|
+
{
|
|
89
|
+
return mrb_utf8_char_head(beg, p, end);
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
static inline uint32_t
|
|
93
|
+
mrb_enc_decode(const char *p, const char *e, mrb_int *lenp)
|
|
94
|
+
{
|
|
95
|
+
return mrb_utf8_decode(p, e, lenp);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
enum mrb_case_kind {
|
|
99
|
+
MRB_CASE_KIND_LOWER,
|
|
100
|
+
MRB_CASE_KIND_UPPER,
|
|
101
|
+
MRB_CASE_KIND_TITLE,
|
|
102
|
+
MRB_CASE_KIND_SWAP,
|
|
103
|
+
MRB_CASE_KIND_FOLD
|
|
104
|
+
};
|
|
105
|
+
|
|
106
|
+
/* The buffer mrb_uni_case_map() writes into. A mapping may spell several
|
|
107
|
+
characters, so this is wider than one of them; unicase.c asserts that the
|
|
108
|
+
table it carries fits. */
|
|
109
|
+
#define MRB_UNI_CASE_MAX_BYTES 8
|
|
110
|
+
|
|
111
|
+
/* The `kind` mapping of `cp`, written into `buf` as UTF-8, answering how many
|
|
112
|
+
bytes it took, or 0 for a character that maps to itself. */
|
|
113
|
+
mrb_int mrb_uni_case_map(enum mrb_case_kind kind, uint32_t cp, char *buf);
|
|
114
|
+
|
|
115
|
+
#ifdef HAVE_MRUBY_REGEXP_GEM
|
|
116
|
+
/* The four below are the foldings /i reads off the same table, in the two
|
|
117
|
+
directions a pattern needs them. A build without mruby-regexp has nothing
|
|
118
|
+
that reads them, so a caller reaching for one there is a compile error
|
|
119
|
+
rather than a link one. */
|
|
120
|
+
|
|
121
|
+
/* Simple case folding: the folded codepoint, or cp itself when it folds to
|
|
122
|
+
nothing else. A codepoint whose folding spells several characters (U+FB00
|
|
123
|
+
to "ff") folds to itself here, which is what makes this the simple folding
|
|
124
|
+
rather than the full one mrb_uni_case_map() answers with. */
|
|
125
|
+
uint32_t mrb_uni_case_fold(uint32_t cp);
|
|
126
|
+
|
|
127
|
+
/* At most this many codepoints share one folded form. */
|
|
128
|
+
#define MRB_UNI_MAX_UNFOLD 4
|
|
129
|
+
|
|
130
|
+
/* Write every other codepoint sharing cp's folded form into out, at most max
|
|
131
|
+
of them, and answer how many were written. */
|
|
132
|
+
int mrb_uni_case_unfold(uint32_t cp, uint32_t *out, int max);
|
|
133
|
+
|
|
134
|
+
/* The same two directions over a span rather than one codepoint, reporting
|
|
135
|
+
what they find by calling add() with each span of it: fold_range the folds
|
|
136
|
+
of the sources in [lo, hi], unfold_range the sources of the folds in
|
|
137
|
+
[lo, hi]. Spans may repeat or overlap what the caller already holds; the
|
|
138
|
+
caller merges. */
|
|
139
|
+
void mrb_uni_case_fold_range(uint32_t lo, uint32_t hi,
|
|
140
|
+
void (*add)(void *, uint32_t, uint32_t), void *user);
|
|
141
|
+
void mrb_uni_case_unfold_range(uint32_t lo, uint32_t hi,
|
|
142
|
+
void (*add)(void *, uint32_t, uint32_t), void *user);
|
|
143
|
+
#endif /* HAVE_MRUBY_REGEXP_GEM */
|
|
144
|
+
|
|
145
|
+
#endif /* SP_RE_SHIM_MRUBY_INTERNAL_H */
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/* shim/mruby/string.h - see shim/mruby.h */
|
|
2
|
+
#ifndef SP_RE_SHIM_MRUBY_STRING_H
|
|
3
|
+
#define SP_RE_SHIM_MRUBY_STRING_H
|
|
4
|
+
#include "../mruby.h"
|
|
5
|
+
|
|
6
|
+
struct sp_re_str {
|
|
7
|
+
char *ptr;
|
|
8
|
+
mrb_int len;
|
|
9
|
+
mrb_int capa;
|
|
10
|
+
struct sp_re_str *next; /* the compile's list of strings to release */
|
|
11
|
+
};
|
|
12
|
+
#define RSTRING_PTR(s) ((s)->ptr)
|
|
13
|
+
#define RSTRING_LEN(s) ((s)->len)
|
|
14
|
+
|
|
15
|
+
mrb_value mrb_str_new(mrb_state *mrb, const char *p, size_t len);
|
|
16
|
+
mrb_value mrb_str_new_cstr(mrb_state *mrb, const char *p);
|
|
17
|
+
mrb_value mrb_str_cat(mrb_state *mrb, mrb_value str, const char *p, size_t len);
|
|
18
|
+
mrb_value mrb_str_resize(mrb_state *mrb, mrb_value str, mrb_int len);
|
|
19
|
+
/* mruby's format: %l takes a pointer and a size_t length, %v a String, %c a
|
|
20
|
+
char; the engine uses no other directive */
|
|
21
|
+
mrb_value mrb_format(mrb_state *mrb, const char *fmt, ...);
|
|
22
|
+
#endif
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
/*
|
|
2
|
+
** shim/mruby.h - the slice of mruby's API the regexp engine reads
|
|
3
|
+
**
|
|
4
|
+
** lib/regexp holds mruby-regexp's engine as mruby carries it (re_compile.c,
|
|
5
|
+
** re_exec.c, re_utf8.c, re_internal.h, re_ctype.h, re_cased.h) together
|
|
6
|
+
** with mruby's case tables (unicase.c, unicase.h), so that a later change
|
|
7
|
+
** there is taken by copying the files again. The engine is written against
|
|
8
|
+
** mruby's API; spinel has no mruby VM, and these headers answer the calls
|
|
9
|
+
** the engine makes with the C library. re_spinel.c defines the functions
|
|
10
|
+
** declared here and gives the engine the entry points spinel calls.
|
|
11
|
+
*/
|
|
12
|
+
#ifndef SP_RE_SHIM_MRUBY_H
|
|
13
|
+
#define SP_RE_SHIM_MRUBY_H
|
|
14
|
+
|
|
15
|
+
#include "sp_re_names.h"
|
|
16
|
+
|
|
17
|
+
#include <stdint.h>
|
|
18
|
+
#include <stddef.h>
|
|
19
|
+
#include <stdlib.h>
|
|
20
|
+
#include <string.h>
|
|
21
|
+
#include <assert.h>
|
|
22
|
+
|
|
23
|
+
/* the build the engine reads a string as: UTF-8, with the Unicode tables
|
|
24
|
+
(RE_UNICODE_CASE, and re_ctype.h above ASCII) unless a -DMRB_USE_ASCII_CTYPE
|
|
25
|
+
build leaves them out */
|
|
26
|
+
#ifndef MRB_UTF8_STRING
|
|
27
|
+
# define MRB_UTF8_STRING
|
|
28
|
+
#endif
|
|
29
|
+
#ifndef HAVE_MRUBY_REGEXP_GEM
|
|
30
|
+
# define HAVE_MRUBY_REGEXP_GEM
|
|
31
|
+
#endif
|
|
32
|
+
/* spinel's switches for a build without the Unicode tables: mruby has the
|
|
33
|
+
one, which leaves out the case foldings and the classes above ASCII
|
|
34
|
+
together */
|
|
35
|
+
#if (defined(RE_NO_UNICODE_CASE) || defined(RE_NO_UNICODE_CTYPE)) && !defined(MRB_USE_ASCII_CTYPE)
|
|
36
|
+
# define MRB_USE_ASCII_CTYPE
|
|
37
|
+
#endif
|
|
38
|
+
|
|
39
|
+
#ifdef __cplusplus
|
|
40
|
+
# define MRB_BEGIN_DECL extern "C" {
|
|
41
|
+
# define MRB_END_DECL }
|
|
42
|
+
#else
|
|
43
|
+
# define MRB_BEGIN_DECL
|
|
44
|
+
# define MRB_END_DECL
|
|
45
|
+
#endif
|
|
46
|
+
|
|
47
|
+
/* The backtracking engine's ceiling, as spinel's engine had it before this
|
|
48
|
+
one: mruby's default of 2048 entries refuses a subject spinel matched
|
|
49
|
+
(a backreference to a run of 20000, test/regexp_backtrack_heap_stack.rb),
|
|
50
|
+
and a limit is not lowered because what it counts moved. */
|
|
51
|
+
#ifndef MRB_REGEXP_STACK_LIMIT
|
|
52
|
+
# define MRB_REGEXP_STACK_LIMIT 32768
|
|
53
|
+
#endif
|
|
54
|
+
|
|
55
|
+
typedef int64_t mrb_int;
|
|
56
|
+
typedef uint8_t mrb_bool;
|
|
57
|
+
#ifndef TRUE
|
|
58
|
+
# define TRUE 1
|
|
59
|
+
#endif
|
|
60
|
+
#ifndef FALSE
|
|
61
|
+
# define FALSE 0
|
|
62
|
+
#endif
|
|
63
|
+
#define MRB_INT_MAX INT64_MAX
|
|
64
|
+
|
|
65
|
+
/* The engine threads an mrb_state through every call it makes; nothing
|
|
66
|
+
reads it here. */
|
|
67
|
+
typedef struct mrb_state { int unused; } mrb_state;
|
|
68
|
+
|
|
69
|
+
/* A String, as the engine uses one: a growable buffer it builds a message or
|
|
70
|
+
a table in. Every one made during a compile is released when the compile
|
|
71
|
+
ends (re_spinel.c), as mruby's GC would release it. */
|
|
72
|
+
typedef struct sp_re_str *mrb_value;
|
|
73
|
+
static inline mrb_value mrb_nil_value(void) { return NULL; }
|
|
74
|
+
static inline mrb_bool mrb_nil_p(mrb_value v) { return v == NULL; }
|
|
75
|
+
|
|
76
|
+
typedef int mrb_sym;
|
|
77
|
+
#define MRB_SYM(name) 0
|
|
78
|
+
|
|
79
|
+
#ifdef MRB_DEBUG
|
|
80
|
+
# define mrb_assert(p) assert(p)
|
|
81
|
+
#else
|
|
82
|
+
# define mrb_assert(p) ((void)0)
|
|
83
|
+
#endif
|
|
84
|
+
#define mrb_static_assert(...) _Static_assert(__VA_ARGS__)
|
|
85
|
+
|
|
86
|
+
void *mrb_malloc(mrb_state *mrb, size_t len);
|
|
87
|
+
void *mrb_malloc_simple(mrb_state *mrb, size_t len);
|
|
88
|
+
void *mrb_calloc(mrb_state *mrb, size_t nelem, size_t len);
|
|
89
|
+
void *mrb_realloc(mrb_state *mrb, void *p, size_t len);
|
|
90
|
+
void *mrb_realloc_simple(mrb_state *mrb, void *p, size_t len);
|
|
91
|
+
void mrb_free(mrb_state *mrb, void *p);
|
|
92
|
+
|
|
93
|
+
#endif /* SP_RE_SHIM_MRUBY_H */
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Minimal shim to compile mruby-bigint without the full mruby runtime.
|
|
3
|
+
* Provides just enough types and macros for bigint.c to compile standalone.
|
|
4
|
+
*/
|
|
5
|
+
#ifndef MRUBY_SHIM_H
|
|
6
|
+
#define MRUBY_SHIM_H
|
|
7
|
+
|
|
8
|
+
#include <stdio.h>
|
|
9
|
+
#include <stdlib.h>
|
|
10
|
+
#include <stdint.h>
|
|
11
|
+
#include <string.h>
|
|
12
|
+
#include <assert.h>
|
|
13
|
+
|
|
14
|
+
/* GCC < 10 doesn't predefine __has_builtin, so #if expressions like
|
|
15
|
+
`defined(__GNUC__) || __has_builtin(...)` choke on the bare token.
|
|
16
|
+
Provide a no-op fallback so the || short-circuits cleanly on the
|
|
17
|
+
left when the compiler doesn't support __has_builtin (issue #55). */
|
|
18
|
+
#ifndef __has_builtin
|
|
19
|
+
#define __has_builtin(x) 0
|
|
20
|
+
#endif
|
|
21
|
+
|
|
22
|
+
/* Basic mruby types */
|
|
23
|
+
typedef int64_t mrb_int;
|
|
24
|
+
typedef uint64_t mrb_uint;
|
|
25
|
+
typedef double mrb_float;
|
|
26
|
+
typedef int mrb_bool;
|
|
27
|
+
#define TRUE 1
|
|
28
|
+
#define FALSE 0
|
|
29
|
+
#define MRB_INT_MAX INT64_MAX
|
|
30
|
+
#define MRB_INT_MIN INT64_MIN
|
|
31
|
+
#define MRB_INT_BIT 64
|
|
32
|
+
|
|
33
|
+
/* mrb_state stub */
|
|
34
|
+
typedef struct mrb_state {
|
|
35
|
+
int dummy;
|
|
36
|
+
} mrb_state;
|
|
37
|
+
|
|
38
|
+
/* Memory allocation */
|
|
39
|
+
#define mrb_malloc(mrb, sz) malloc(sz)
|
|
40
|
+
#define mrb_realloc(mrb, p, sz) realloc(p, sz)
|
|
41
|
+
#define mrb_free(mrb, p) free(p)
|
|
42
|
+
#define mrb_malloc_simple(mrb, sz) malloc(sz)
|
|
43
|
+
|
|
44
|
+
/* Error handling — sp_bigint.c is compiled as a separate TU and
|
|
45
|
+
would otherwise hard-exit on internal errors (mini-gmp's zero-
|
|
46
|
+
divisor check, allocation overflow, etc.). The mrb_raise macro
|
|
47
|
+
now dispatches on the symbolic class enum: ZeroDivisionError is
|
|
48
|
+
routed through sp_bigint_raise_zerodiv (defined non-static in
|
|
49
|
+
spinel_rt.h, linked from gen.c) so it reaches spinel's longjmp
|
|
50
|
+
rescue net and is catchable by `rescue ZeroDivisionError`.
|
|
51
|
+
Other classes still hard-exit — they're internal invariants
|
|
52
|
+
(allocation overflow) where graceful handling buys little. */
|
|
53
|
+
extern void sp_bigint_raise_zerodiv(const char *msg);
|
|
54
|
+
#define E_RANGE_ERROR 1
|
|
55
|
+
#define E_RUNTIME_ERROR 2
|
|
56
|
+
#define E_ARGUMENT_ERROR 3
|
|
57
|
+
#define E_TYPE_ERROR 4
|
|
58
|
+
#define E_ZERODIV_ERROR 5
|
|
59
|
+
#define mrb_raise(mrb, cls, msg) do { \
|
|
60
|
+
if ((cls) == E_ZERODIV_ERROR) { sp_bigint_raise_zerodiv(msg); } \
|
|
61
|
+
else { fprintf(stderr, "%s\n", msg); exit(1); } \
|
|
62
|
+
} while(0)
|
|
63
|
+
#define mrb_int_zerodiv(mrb) sp_bigint_raise_zerodiv("divided by 0")
|
|
64
|
+
|
|
65
|
+
/* mrb_value stub - tagged union */
|
|
66
|
+
typedef struct mrb_value {
|
|
67
|
+
union {
|
|
68
|
+
mrb_int i;
|
|
69
|
+
mrb_float f;
|
|
70
|
+
void *p;
|
|
71
|
+
} value;
|
|
72
|
+
int tt;
|
|
73
|
+
} mrb_value;
|
|
74
|
+
|
|
75
|
+
enum mrb_vtype {
|
|
76
|
+
MRB_TT_FALSE = 0,
|
|
77
|
+
MRB_TT_TRUE,
|
|
78
|
+
MRB_TT_INTEGER,
|
|
79
|
+
MRB_TT_FLOAT,
|
|
80
|
+
MRB_TT_STRING,
|
|
81
|
+
MRB_TT_BIGINT,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
#define mrb_integer(v) ((v).value.i)
|
|
85
|
+
#define mrb_float(v) ((v).value.f)
|
|
86
|
+
#define mrb_ptr(v) ((v).value.p)
|
|
87
|
+
#define mrb_type(v) ((v).tt)
|
|
88
|
+
#define mrb_integer_p(v) ((v).tt == MRB_TT_INTEGER)
|
|
89
|
+
#define mrb_float_p(v) ((v).tt == MRB_TT_FLOAT)
|
|
90
|
+
#define mrb_bigint_p(v) ((v).tt == MRB_TT_BIGINT)
|
|
91
|
+
#define mrb_fixnum_value(i) ((mrb_value){{.i=(i)}, MRB_TT_INTEGER})
|
|
92
|
+
#define mrb_int_value(mrb, i) mrb_fixnum_value(i)
|
|
93
|
+
|
|
94
|
+
/* Object header stub */
|
|
95
|
+
#define MRB_OBJECT_HEADER uint32_t flags; uint32_t _pad
|
|
96
|
+
#define mrb_obj_ptr(v) ((struct RBasic*)mrb_ptr(v))
|
|
97
|
+
#define mrb_static_assert_object_size(t) /* nop */
|
|
98
|
+
#define mrb_assert(x) assert(x)
|
|
99
|
+
|
|
100
|
+
/* String */
|
|
101
|
+
#define RSTRING_PTR(s) ((const char*)mrb_ptr(s))
|
|
102
|
+
#define RSTRING_LEN(s) ((mrb_int)strlen(RSTRING_PTR(s)))
|
|
103
|
+
|
|
104
|
+
/* nil value */
|
|
105
|
+
static inline mrb_value mrb_nil_value(void) {
|
|
106
|
+
mrb_value v; v.tt = MRB_TT_FALSE; v.value.i = 0; return v;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
/* MRB_ENSURE stub - execute body, no exception handling */
|
|
110
|
+
#define MRB_ENSURE(mrb, exc, body, data) \
|
|
111
|
+
{ mrb_value exc = body(mrb, data); (void)exc; } if(0)
|
|
112
|
+
|
|
113
|
+
/* Bigint object creation */
|
|
114
|
+
struct RBasic {
|
|
115
|
+
MRB_OBJECT_HEADER;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
#endif /* MRUBY_SHIM_H */
|