mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
Merge branch 'master' into stable
This commit is contained in:
@@ -7,11 +7,17 @@ build:
|
||||
- any:
|
||||
- changed-files:
|
||||
- any-glob-to-any-file:
|
||||
- Dockerfile
|
||||
- Makefile
|
||||
- Rakefile
|
||||
- appveyor.yml
|
||||
- build_config.rb
|
||||
- build_config/**/*
|
||||
- docker-compose.yml
|
||||
- lib/**/*
|
||||
- minirake
|
||||
- tasks/**/*
|
||||
- .travis.yml
|
||||
core:
|
||||
- any:
|
||||
- changed-files:
|
||||
|
||||
@@ -19,7 +19,7 @@ jobs:
|
||||
pip install pre-commit
|
||||
- name: Set PY
|
||||
run: echo "PY=$(python -VV | sha256sum | cut -d' ' -f1)" >> $GITHUB_ENV
|
||||
- uses: actions/cache@v3
|
||||
- uses: actions/cache@v4
|
||||
with:
|
||||
path: ~/.cache/pre-commit
|
||||
key: pre-commit|${{ env.PY }}|${{ hashFiles('.pre-commit-config.yaml') }}
|
||||
|
||||
@@ -20,9 +20,8 @@ jobs:
|
||||
# Full git history is needed to get a proper list of changed files within `super-linter`
|
||||
fetch-depth: 0
|
||||
- name: Lint Code Base
|
||||
uses: super-linter/super-linter/slim@v5.7.2
|
||||
uses: super-linter/super-linter/slim@v6.0.0
|
||||
env:
|
||||
ERROR_ON_MISSING_EXEC_BIT: true
|
||||
VALIDATE_BASH: true
|
||||
# VALIDATE_BASH_EXEC: true
|
||||
# VALIDATE_EDITORCONFIG: true
|
||||
|
||||
@@ -20,6 +20,8 @@ repos:
|
||||
- id: check-shebang-scripts-are-executable
|
||||
- id: check-vcs-permalinks
|
||||
- id: check-yaml
|
||||
- id: detect-aws-credentials
|
||||
args: [--allow-missing-credentials]
|
||||
- id: detect-private-key
|
||||
- id: end-of-file-fixer
|
||||
- id: file-contents-sorter
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
# Authors of mruby (mruby developers)
|
||||
|
||||
## The List of Contributors sorted by number of commits (as of 2023-12-28 67cb987)
|
||||
## The List of Contributors sorted by number of commits (as of 2024-02-10 d2af9da)
|
||||
|
||||
9477 Yukihiro "Matz" Matsumoto (@matz)*
|
||||
9592 Yukihiro "Matz" Matsumoto (@matz)*
|
||||
586 KOBAYASHI Shuji (@shuujii)
|
||||
533 dearblue (@dearblue)*
|
||||
547 dearblue (@dearblue)*
|
||||
378 Daniel Bovensiepen (@bovi)*
|
||||
346 Takeshi Watanabe (@take-cheeze)*
|
||||
334 Masaki Muranaka (@monaka)
|
||||
@@ -12,7 +12,7 @@
|
||||
234 Jun Hiroe (@suzukaze)
|
||||
220 Cremno (@cremno)*
|
||||
209 Yuki Kurihara (@ksss)+
|
||||
166 John Bampton (@jbampton)
|
||||
170 John Bampton (@jbampton)
|
||||
151 Yasuhiro Matsumoto (@mattn)*
|
||||
113 Carson McDonald (@carsonmcdonald)
|
||||
103 Tomasz Dąbrowski (@dabroz)*
|
||||
@@ -156,6 +156,7 @@
|
||||
3 bamchoh (@bamchoh)
|
||||
3 sasaki takeru (@takeru)
|
||||
3 windwiny (@windwiny)
|
||||
3 星湖新 (@hoshiumiarata)
|
||||
2 Akira Moroo (@retrage)
|
||||
2 Artur K (@nemerle)
|
||||
2 Christian Mauceri (@mauceri)
|
||||
@@ -290,6 +291,7 @@
|
||||
1 Yusuke Tanaka (@csouls)
|
||||
1 alpha.netzilla (@alpha-netzilla)
|
||||
1 arton (@arton)
|
||||
1 buty4649 (@buty4649)
|
||||
1 duangsuse (@duangsuse)
|
||||
1 fl0l0u (@fl0l0u)
|
||||
1 hhc0null (@hhc0null)
|
||||
|
||||
@@ -4,10 +4,41 @@ LEGAL NOTICE INFORMATION
|
||||
All the files in this distribution are covered under the MIT license
|
||||
(see the file LICENSE) except some files mentioned below:
|
||||
|
||||
- src/string.c: mrb_memsearch_ss() is based on 2 clause BSD license code by Wojciech Muła (@WojciechMula)
|
||||
- src/readfloat.c: public domain by Yasuhiro Matsumoto (@mattn)
|
||||
- src/fmt_fp.c: public domain by Dave Hylands (@dhylands)
|
||||
- mrbgems/mruby-dir/src/Win/dirent.c: MIT-like license by Kevlin Henney
|
||||
|
||||
[src/string.c]
|
||||
The implementation of mrb_memsearch_ss() is taken from
|
||||
https://github.com/WojciechMula/sse4-strstr.git
|
||||
|
||||
Copyright (c) 2008-2016, Wojciech Muła
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are
|
||||
met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright
|
||||
notice, this list of conditions and the following disclaimer.
|
||||
|
||||
2. Redistributions in binary form must reproduce the above copyright
|
||||
notice, this list of conditions and the following disclaimer in the
|
||||
documentation and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
|
||||
IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
|
||||
TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
|
||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
||||
LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
[src/readfloat.c]
|
||||
|
||||
strtod implementation.
|
||||
|
||||
@@ -798,6 +798,8 @@ MRB_API struct RClass * mrb_module_get_under_id(mrb_state *mrb, struct RClass *o
|
||||
MRB_API void mrb_notimplement(mrb_state*);
|
||||
/* a function to be replacement of unimplemented method */
|
||||
MRB_API mrb_value mrb_notimplement_m(mrb_state*, mrb_value);
|
||||
/* just return it self */
|
||||
MRB_API mrb_value mrb_obj_itself(mrb_state*, mrb_value);
|
||||
|
||||
/**
|
||||
* Duplicate an object.
|
||||
|
||||
@@ -17,8 +17,8 @@ MRB_BEGIN_DECL
|
||||
struct RException {
|
||||
MRB_OBJECT_HEADER;
|
||||
struct iv_tbl *iv;
|
||||
struct RObject *mesg; // NULL or probably RString
|
||||
struct RObject *backtrace; // NULL, RArray or RData
|
||||
struct RBasic *mesg; // NULL or probably RString
|
||||
struct RBasic *backtrace; // NULL, RArray or RData
|
||||
};
|
||||
|
||||
/* error that should terminate execution */
|
||||
|
||||
@@ -61,6 +61,18 @@ mrb_value mrb_exc_mesg_get(mrb_state *mrb, struct RException *exc);
|
||||
mrb_value mrb_f_raise(mrb_state*, mrb_value);
|
||||
mrb_value mrb_make_exception(mrb_state *mrb, mrb_value exc, mrb_value mesg);
|
||||
|
||||
struct RBacktrace {
|
||||
MRB_OBJECT_HEADER;
|
||||
size_t len;
|
||||
struct mrb_backtrace_location *locations;
|
||||
};
|
||||
|
||||
struct mrb_backtrace_location {
|
||||
mrb_sym method_id;
|
||||
int32_t idx;
|
||||
const mrb_irep *irep;
|
||||
};
|
||||
|
||||
/* gc */
|
||||
void mrb_gc_mark_mt(mrb_state*, struct RClass*);
|
||||
size_t mrb_gc_mark_mt_size(mrb_state*, struct RClass*);
|
||||
|
||||
+12
-11
@@ -79,18 +79,19 @@ struct RStringEmbed {
|
||||
#define RSTR_UNSET_NOFREE_FLAG(s) ((s)->flags &= ~MRB_STR_NOFREE)
|
||||
|
||||
#ifdef MRB_UTF8_STRING
|
||||
# define RSTR_ASCII_P(s) ((s)->flags & MRB_STR_ASCII)
|
||||
# define RSTR_SET_ASCII_FLAG(s) ((s)->flags |= MRB_STR_ASCII)
|
||||
# define RSTR_UNSET_ASCII_FLAG(s) ((s)->flags &= ~MRB_STR_ASCII)
|
||||
# define RSTR_WRITE_ASCII_FLAG(s, v) (RSTR_UNSET_ASCII_FLAG(s), (s)->flags |= v)
|
||||
# define RSTR_COPY_ASCII_FLAG(dst, src) RSTR_WRITE_ASCII_FLAG(dst, RSTR_ASCII_P(src))
|
||||
# define RSTR_SINGLE_BYTE_P(s) ((s)->flags & MRB_STR_SINGLE_BYTE)
|
||||
# define RSTR_SET_SINGLE_BYTE_FLAG(s) ((s)->flags |= MRB_STR_SINGLE_BYTE)
|
||||
# define RSTR_UNSET_SINGLE_BYTE_FLAG(s) ((s)->flags &= ~MRB_STR_SINGLE_BYTE)
|
||||
# define RSTR_WRITE_SINGLE_BYTE_FLAG(s, v) (RSTR_UNSET_SINGLE_BYTE_FLAG(s), (s)->flags |= v)
|
||||
# define RSTR_COPY_SINGLE_BYTE_FLAG(dst, src) RSTR_WRITE_SINGLE_BYTE_FLAG(dst, RSTR_SINGLE_BYTE_P(src))
|
||||
#else
|
||||
# define RSTR_ASCII_P(s) (void)0
|
||||
# define RSTR_SET_ASCII_FLAG(s) (void)0
|
||||
# define RSTR_UNSET_ASCII_FLAG(s) (void)0
|
||||
# define RSTR_WRITE_ASCII_FLAG(s, v) (void)0
|
||||
# define RSTR_COPY_ASCII_FLAG(dst, src) (void)0
|
||||
# define RSTR_SINGLE_BYTE_P(s) (void)1
|
||||
# define RSTR_SET_SINGLE_BYTE_FLAG(s) (void)0
|
||||
# define RSTR_UNSET_SINGLE_BYTE_FLAG(s) (void)0
|
||||
# define RSTR_WRITE_SINGLE_BYTE_FLAG(s, v) (void)0
|
||||
# define RSTR_COPY_SINGLE_BYTE_FLAG(dst, src) (void)0
|
||||
#endif
|
||||
#define RSTR_SET_ASCII_FLAG(s) RSTR_SET_SINGLE_BYTE_FLAG(s)
|
||||
|
||||
/**
|
||||
* Returns a pointer from a Ruby string
|
||||
@@ -108,7 +109,7 @@ struct RStringEmbed {
|
||||
#define MRB_STR_FSHARED 2
|
||||
#define MRB_STR_NOFREE 4
|
||||
#define MRB_STR_EMBED 8 /* type flags up to here */
|
||||
#define MRB_STR_ASCII 16
|
||||
#define MRB_STR_SINGLE_BYTE 16
|
||||
#define MRB_STR_EMBED_LEN_SHIFT 6
|
||||
#define MRB_STR_EMBED_LEN_BIT 5
|
||||
#define MRB_STR_EMBED_LEN_MASK (((1 << MRB_STR_EMBED_LEN_BIT) - 1) << MRB_STR_EMBED_LEN_SHIFT)
|
||||
|
||||
@@ -159,7 +159,8 @@ static const unsigned int IEEE754_INFINITY_BITS_SINGLE = 0x7F800000;
|
||||
f(MRB_TT_BREAK, struct RBreak, "break") \
|
||||
f(MRB_TT_COMPLEX, struct RComplex, "Complex") \
|
||||
f(MRB_TT_RATIONAL, struct RRational, "Rational") \
|
||||
f(MRB_TT_BIGINT, struct RBigint, "Integer")
|
||||
f(MRB_TT_BIGINT, struct RBigint, "Integer") \
|
||||
f(MRB_TT_BACKTRACE, struct RBacktrace, "backtrace")
|
||||
|
||||
enum mrb_vtype {
|
||||
#define MRB_VTYPE_DEFINE(tt, type, name) tt,
|
||||
|
||||
@@ -372,6 +372,7 @@ module MRuby
|
||||
|
||||
def each(&b)
|
||||
@ary.each(&b)
|
||||
self
|
||||
end
|
||||
|
||||
def [](name)
|
||||
@@ -384,6 +385,7 @@ module MRuby
|
||||
else
|
||||
# GEM was already added to this list
|
||||
end
|
||||
self
|
||||
end
|
||||
|
||||
def empty?
|
||||
|
||||
@@ -478,7 +478,6 @@ udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy)
|
||||
}
|
||||
|
||||
mpz_t q, x, y;
|
||||
size_t i;
|
||||
|
||||
mrb_assert(!uzero(yy)); /* divided by zero */
|
||||
mpz_init(mrb, &q);
|
||||
@@ -502,6 +501,8 @@ udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy)
|
||||
else
|
||||
qhat = (((mp_dbl_limb)x.p[j+yd] << DIG_SIZE) + x.p[j+yd-1]) / z;
|
||||
if (qhat) {
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<yd; i++) {
|
||||
mp_dbl_limb zz = qhat * y.p[i];
|
||||
mp_dbl_limb_signed u = LOW(b)+x.p[i+j]-LOW(zz);
|
||||
@@ -512,7 +513,7 @@ udiv(mrb_state *mrb, mpz_t *qq, mpz_t *rr, mpz_t *xx, mpz_t *yy)
|
||||
}
|
||||
for (; b!=0; qhat--) {
|
||||
mp_dbl_limb c = 0;
|
||||
for (i=0; i<yd; i++) {
|
||||
for (size_t i=0; i<yd; i++) {
|
||||
c += (mp_dbl_limb)x.p[i+j] + (mp_dbl_limb)y.p[i];
|
||||
x.p[i+j] = LOW(c);
|
||||
c = HIGH(c);
|
||||
@@ -1111,7 +1112,6 @@ mrb_bint_new_float(mrb_state *mrb, mrb_float x)
|
||||
mrb_float bi = 1.0 / b;
|
||||
size_t rn;
|
||||
mp_limb *rp;
|
||||
mp_limb f;
|
||||
|
||||
for (rn = 1; x >= b; rn++)
|
||||
x *= bi;
|
||||
@@ -1119,7 +1119,7 @@ mrb_bint_new_float(mrb_state *mrb, mrb_float x)
|
||||
mpz_realloc(mrb, r, rn);
|
||||
rp = r->p;
|
||||
for (size_t i=rn-1;;i--) {
|
||||
f = LOW((mp_limb)x);
|
||||
mp_limb f = LOW((mp_limb)x);
|
||||
x -= f;
|
||||
mrb_assert(x < 1.0);
|
||||
rp[i] = f;
|
||||
|
||||
@@ -98,8 +98,8 @@ options_opt(struct options *opts)
|
||||
while (++opts->argv, --opts->argc) {
|
||||
opts->opt = *opts->argv;
|
||||
|
||||
/* empty || not start with `-` || `-` */
|
||||
if (!opts->opt[0] || opts->opt[0] != '-' || !opts->opt[1]) return NULL;
|
||||
/* not start with `-` || `-` */
|
||||
if (opts->opt[0] != '-' || !opts->opt[1]) return NULL;
|
||||
|
||||
if (opts->opt[1] == '-') {
|
||||
/* `--` */
|
||||
@@ -278,10 +278,8 @@ main(int argc, char **argv)
|
||||
{
|
||||
mrb_state *mrb = mrb_open();
|
||||
int n = -1;
|
||||
int i;
|
||||
struct _args args;
|
||||
mrb_value ARGV;
|
||||
mrb_ccontext *c;
|
||||
mrb_value v;
|
||||
|
||||
if (mrb == NULL) {
|
||||
@@ -297,7 +295,7 @@ main(int argc, char **argv)
|
||||
else {
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
ARGV = mrb_ary_new_capa(mrb, args.argc);
|
||||
for (i = 0; i < args.argc; i++) {
|
||||
for (int i = 0; i < args.argc; i++) {
|
||||
char* utf8 = mrb_utf8_from_locale(args.argv[i], -1);
|
||||
if (utf8) {
|
||||
mrb_ary_push(mrb, ARGV, mrb_str_new_cstr(mrb, utf8));
|
||||
@@ -307,7 +305,7 @@ main(int argc, char **argv)
|
||||
mrb_define_global_const(mrb, "ARGV", ARGV);
|
||||
mrb_gv_set(mrb, mrb_intern_lit(mrb, "$DEBUG"), mrb_bool_value(args.debug));
|
||||
|
||||
c = mrb_ccontext_new(mrb);
|
||||
mrb_ccontext *c = mrb_ccontext_new(mrb);
|
||||
if (args.verbose)
|
||||
c->dump_result = TRUE;
|
||||
if (args.check_syntax)
|
||||
@@ -324,7 +322,7 @@ main(int argc, char **argv)
|
||||
mrb_gv_set(mrb, mrb_intern_lit(mrb, "$0"), mrb_str_new_cstr(mrb, cmdline));
|
||||
|
||||
/* Load libraries */
|
||||
for (i = 0; i < args.libc; i++) {
|
||||
for (int i = 0; i < args.libc; i++) {
|
||||
FILE *lfp = fopen(args.libv[i], "rb");
|
||||
if (lfp == NULL) {
|
||||
fprintf(stderr, "%s: Cannot open library file: %s\n", *argv, args.libv[i]);
|
||||
@@ -334,10 +332,10 @@ main(int argc, char **argv)
|
||||
}
|
||||
mrb_ccontext_filename(mrb, c, args.libv[i]);
|
||||
if (mrb_extension_p(args.libv[i])) {
|
||||
v = mrb_load_irep_file_cxt(mrb, lfp, c);
|
||||
mrb_load_irep_file_cxt(mrb, lfp, c);
|
||||
}
|
||||
else {
|
||||
v = mrb_load_detect_file_cxt(mrb, lfp, c);
|
||||
mrb_load_detect_file_cxt(mrb, lfp, c);
|
||||
}
|
||||
fclose(lfp);
|
||||
mrb_vm_ci_env_clear(mrb, mrb->c->cibase);
|
||||
|
||||
@@ -149,12 +149,6 @@ mrb_complex_to_i(mrb_state *mrb, mrb_value self)
|
||||
return mrb_int_value(mrb, (mrb_int)p->real);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
complex_to_c(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
mrb_bool
|
||||
mrb_complex_eq(mrb_state *mrb, mrb_value x, mrb_value y)
|
||||
{
|
||||
@@ -406,7 +400,7 @@ void mrb_mruby_complex_gem_init(mrb_state *mrb)
|
||||
mrb_define_method(mrb, comp, "imaginary", complex_imaginary, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, comp, "to_f", mrb_complex_to_f, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, comp, "to_i", mrb_complex_to_i, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, comp, "to_c", complex_to_c, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, comp, "to_c", mrb_obj_itself, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, comp, "+", complex_add, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, comp, "-", complex_sub, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, comp, "*", complex_mul, MRB_ARGS_REQ(1));
|
||||
|
||||
@@ -840,6 +840,17 @@ module Enumerable
|
||||
|
||||
alias filter select
|
||||
|
||||
def grep_v(pattern, &block)
|
||||
ary = []
|
||||
self.each{|*val|
|
||||
sv = val.__svalue
|
||||
unless pattern === sv
|
||||
ary.push((block)? block.call(*val): sv)
|
||||
end
|
||||
}
|
||||
ary
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# enum.tally -> a_hash
|
||||
|
||||
@@ -195,3 +195,10 @@ end
|
||||
assert("Enumerable#tally") do
|
||||
assert_equal({"a"=>1, "b"=>2, "c"=>1}, ["a", "b", "c", "b"].tally)
|
||||
end
|
||||
|
||||
assert("Enumerable#grep_v") do
|
||||
a = [1, 2, 3, 4, 5, 0]
|
||||
assert_equal [1, 5, 0], a.grep_v(2..4)
|
||||
assert_equal [1, 2, 3, 4, 5, 0], a.grep_v(6..8)
|
||||
assert_equal [2, 4, 6, 8, 10], a.grep_v(0) {|v| v * 2}
|
||||
end
|
||||
|
||||
@@ -701,4 +701,72 @@ module Enumerable
|
||||
|
||||
result
|
||||
end
|
||||
|
||||
##
|
||||
# call-seq:
|
||||
# enum.chunk -> enumerator
|
||||
# enum.chunk { |arr| block } -> enumerator
|
||||
#
|
||||
# Each element in the returned enumerator is a 2-element array consisting of:
|
||||
#
|
||||
# - A value returned by the block.
|
||||
# - An array ("chunk") containing the element for which that value was returned,
|
||||
# and all following elements for which the block returned the same value:
|
||||
#
|
||||
# So that:
|
||||
#
|
||||
# - Each block return value that is different from its predecessor
|
||||
# begins a new chunk.
|
||||
# - Each block return value that is the same as its predecessor
|
||||
# continues the same chunk.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# e = (0..10).chunk {|i| (i / 3).floor } # => #<Enumerator: ...>
|
||||
# # The enumerator elements.
|
||||
# e.next # => [0, [0, 1, 2]]
|
||||
# e.next # => [1, [3, 4, 5]]
|
||||
# e.next # => [2, [6, 7, 8]]
|
||||
# e.next # => [3, [9, 10]]
|
||||
#
|
||||
# You can use the special symbol <tt>:_alone</tt> to force an element
|
||||
# into its own separate chuck:
|
||||
#
|
||||
# a = [0, 0, 1, 1]
|
||||
# e = a.chunk{|i| i.even? ? :_alone : true }
|
||||
# e.to_a # => [[:_alone, [0]], [:_alone, [0]], [true, [1, 1]]]
|
||||
#
|
||||
# You can use the special symbol <tt>:_separator</tt> or +nil+
|
||||
# to force an element to be ignored (not included in any chunk):
|
||||
#
|
||||
# a = [0, 0, -1, 1, 1]
|
||||
# e = a.chunk{|i| i < 0 ? :_separator : true }
|
||||
# e.to_a # => [[true, [0, 0]], [true, [1, 1]]]
|
||||
def chunk(&block)
|
||||
return to_enum :chunk unless block
|
||||
|
||||
enum = self
|
||||
Enumerator.new do |y|
|
||||
last_value, arr = nil, []
|
||||
enum.each do |element|
|
||||
value = block.call(element)
|
||||
case value
|
||||
when :_alone
|
||||
y.yield [last_value, arr] if arr.size > 0
|
||||
y.yield [value, [element]]
|
||||
last_value, arr = nil, []
|
||||
when :_separator, nil
|
||||
y.yield [last_value, arr] if arr.size > 0
|
||||
last_value, arr = nil, []
|
||||
when last_value
|
||||
arr << element
|
||||
else
|
||||
raise 'symbols beginning with an underscore are reserved' if value.is_a?(Symbol) && value.to_s[0] == '_'
|
||||
y.yield [last_value, arr] if arr.size > 0
|
||||
last_value, arr = value, [element]
|
||||
end
|
||||
end
|
||||
y.yield [last_value, arr] if arr.size > 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -598,3 +598,52 @@ assert 'Enumerator.produce' do
|
||||
], enum.to_a
|
||||
}
|
||||
end
|
||||
|
||||
assert("Enumerable#chunk") do
|
||||
chunk = [1, 2, 3, 1, 2].chunk
|
||||
assert_equal Enumerator, chunk.class
|
||||
result = chunk.with_index { |elt, i| elt - i }.to_a
|
||||
assert_equal [[1, [1, 2, 3]], [-2, [1, 2]]], result
|
||||
|
||||
assert_equal Enumerator, [].chunk {}.class
|
||||
|
||||
e = [1, 2, 3]
|
||||
recorded = []
|
||||
e.chunk { |x| recorded << x }.to_a
|
||||
assert_equal [1, 2, 3], recorded
|
||||
|
||||
e = [1, 2, 3, 2, 3, 2, 1]
|
||||
result = e.chunk { |x| x < 3 && 1 || 0 }.to_a
|
||||
assert_equal [[1, [1, 2]], [0, [3]], [1, [2]], [0, [3]], [1, [2, 1]]], result
|
||||
|
||||
e = [1, 2, 3]
|
||||
assert_equal [[1, 2], [3]], e.chunk { |x| x > 2 }.map(&:last)
|
||||
|
||||
e = [1, 2, 3, 2, 1]
|
||||
result = e.chunk { |x| x < 2 && :_alone }.to_a
|
||||
assert_equal [[:_alone, [1]], [false, [2, 3, 2]], [:_alone, [1]]], result
|
||||
|
||||
e = [[1, 2]]
|
||||
inner_value = []
|
||||
e.chunk { |*x| inner_value << x }.to_a
|
||||
assert_equal [[[1, 2]]], inner_value
|
||||
|
||||
e = [1, 2, 3, 3, 2, 1]
|
||||
result = e.chunk { |x| x == 2 ? :_separator : 1 }.to_a
|
||||
assert_equal [[1, [1]], [1, [3, 3]], [1, [1]]], result
|
||||
|
||||
e = [1, 2, 3, 2, 1]
|
||||
result = e.chunk { |x| x == 2 ? nil : 1 }.to_a
|
||||
assert_equal [[1, [1]], [1, [3]], [1, [1]]], result
|
||||
|
||||
|
||||
e = [1, 2, 3, 2, 1]
|
||||
assert_raise(RuntimeError) { e.chunk { |x| :_arbitrary }.to_a }
|
||||
|
||||
e = [1, 2, 3]
|
||||
assert_raise(ArgumentError) { e.chunk(1) {} }
|
||||
|
||||
e = [1, 2, 3, 2, 1]
|
||||
enum = e.chunk { |x| true }
|
||||
assert_nil enum.size
|
||||
end
|
||||
|
||||
@@ -288,7 +288,6 @@ mrb_sce_sys_fail(mrb_state *mrb, mrb_value cls)
|
||||
if (argc == 1) {
|
||||
msg = mrb_nil_value();
|
||||
}
|
||||
exc = mrb_obj_value(e);
|
||||
mrb_sce_init(mrb, exc, msg, no);
|
||||
mrb_exc_raise(mrb, exc);
|
||||
return mrb_nil_value(); /* NOTREACHED */
|
||||
|
||||
@@ -344,8 +344,8 @@ mrb_mruby_eval_gem_init(mrb_state* mrb)
|
||||
{
|
||||
mrb_define_module_function(mrb, mrb->kernel_module, "eval", f_eval, MRB_ARGS_ARG(1, 3));
|
||||
mrb_define_method_id(mrb, mrb_class_get_id(mrb, MRB_SYM(BasicObject)), MRB_SYM(instance_eval), f_instance_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK());
|
||||
mrb_define_method_id(mrb, mrb_class_get_id(mrb, MRB_SYM(Module)), MRB_SYM(module_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK());
|
||||
mrb_define_method_id(mrb, mrb_class_get_id(mrb, MRB_SYM(Module)), MRB_SYM(class_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK());
|
||||
mrb_define_method_id(mrb, mrb->module_class, MRB_SYM(module_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK());
|
||||
mrb_define_method_id(mrb, mrb->module_class, MRB_SYM(class_eval), f_class_eval, MRB_ARGS_OPT(3)|MRB_ARGS_BLOCK());
|
||||
|
||||
struct RClass *binding = mrb_class_get_id(mrb, MRB_SYM(Binding));
|
||||
mrb_define_method(mrb, binding, "eval", mrb_binding_eval, MRB_ARGS_ANY());
|
||||
|
||||
@@ -43,12 +43,12 @@ fiber_init_fiber(mrb_state *mrb, struct RFiber *f, const struct RProc *p)
|
||||
c->stend = c->stbase + slen;
|
||||
|
||||
{
|
||||
mrb_value *p = c->stbase;
|
||||
mrb_value *pend = c->stend;
|
||||
mrb_value *s = c->stbase;
|
||||
mrb_value *send = c->stend;
|
||||
|
||||
while (p < pend) {
|
||||
SET_NIL_VALUE(*p);
|
||||
p++;
|
||||
while (s < send) {
|
||||
SET_NIL_VALUE(*s);
|
||||
s++;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -252,8 +252,6 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
|
||||
}
|
||||
fiber_switch_context(mrb, c);
|
||||
if (status == MRB_FIBER_CREATED) {
|
||||
mrb_value *b, *e;
|
||||
|
||||
if (!c->ci->proc) {
|
||||
return fiber_error(mrb, "double resume (current)");
|
||||
}
|
||||
@@ -267,8 +265,10 @@ fiber_switch(mrb_state *mrb, mrb_value self, mrb_int len, const mrb_value *a, mr
|
||||
}
|
||||
else {
|
||||
mrb_stack_extend(mrb, len+2); /* for receiver and (optional) block */
|
||||
b = c->stbase+1;
|
||||
e = b + len;
|
||||
|
||||
mrb_value *b = c->stbase+1;
|
||||
mrb_value *e = b + len;
|
||||
|
||||
while (b<e) {
|
||||
*b++ = *a++;
|
||||
}
|
||||
|
||||
@@ -24,14 +24,14 @@ hash_values_at(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
const mrb_value *argv;
|
||||
mrb_value result;
|
||||
mrb_int argc, i;
|
||||
mrb_int argc;
|
||||
int ai;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
result = mrb_ary_new_capa(mrb, argc);
|
||||
if (argc == 0) return result;
|
||||
ai = mrb_gc_arena_save(mrb);
|
||||
for (i = 0; i < argc; i++) {
|
||||
for (mrb_int i = 0; i < argc; i++) {
|
||||
mrb_ary_push(mrb, result, mrb_hash_get(mrb, hash, argv[i]));
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
@@ -53,12 +53,12 @@ hash_slice(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
const mrb_value *argv;
|
||||
mrb_value result;
|
||||
mrb_int argc, i;
|
||||
mrb_int argc;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
result = mrb_hash_new_capa(mrb, argc);
|
||||
if (argc == 0) return result; /* empty hash */
|
||||
for (i = 0; i < argc; i++) {
|
||||
for (mrb_int i = 0; i < argc; i++) {
|
||||
mrb_value key = argv[i];
|
||||
mrb_value val;
|
||||
|
||||
@@ -85,11 +85,11 @@ hash_except(mrb_state *mrb, mrb_value hash)
|
||||
{
|
||||
const mrb_value *argv;
|
||||
mrb_value result;
|
||||
mrb_int argc, i;
|
||||
mrb_int argc;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
result = mrb_hash_dup(mrb, hash);
|
||||
for (i = 0; i < argc; i++) {
|
||||
for (mrb_int i = 0; i < argc; i++) {
|
||||
mrb_hash_delete_key(mrb, result, argv[i]);
|
||||
}
|
||||
return result;
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#define MRUBY_IO_H
|
||||
|
||||
#include <mruby.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
#ifdef MRB_NO_STDIO
|
||||
# error IO and File conflicts 'MRB_NO_STDIO' in your build configuration
|
||||
@@ -63,8 +64,8 @@ struct mrb_io {
|
||||
#define MRB_O_DSYNC 0x00008000
|
||||
#define MRB_O_RSYNC 0x00010000
|
||||
|
||||
#define E_IO_ERROR (mrb_exc_get(mrb, "IOError"))
|
||||
#define E_EOF_ERROR (mrb_exc_get(mrb, "EOFError"))
|
||||
#define E_IO_ERROR mrb_exc_get_id(mrb, MRB_SYM(IOError))
|
||||
#define E_EOF_ERROR mrb_exc_get_id(mrb, MRB_SYM(EOFError))
|
||||
|
||||
int mrb_io_fileno(mrb_state *mrb, mrb_value io);
|
||||
|
||||
|
||||
@@ -120,15 +120,13 @@ mrb_file_s_unlink(mrb_state *mrb, mrb_value obj)
|
||||
{
|
||||
const mrb_value *argv;
|
||||
mrb_int argc, i;
|
||||
char *path;
|
||||
|
||||
mrb_get_args(mrb, "*", &argv, &argc);
|
||||
for (i = 0; i < argc; i++) {
|
||||
const char *utf8_path;
|
||||
mrb_value pathv = argv[i];
|
||||
mrb_ensure_string_type(mrb, pathv);
|
||||
utf8_path = RSTRING_CSTR(mrb, pathv);
|
||||
path = mrb_locale_from_utf8(utf8_path, -1);
|
||||
const char *utf8_path = RSTRING_CSTR(mrb, pathv);
|
||||
char *path = mrb_locale_from_utf8(utf8_path, -1);
|
||||
if (UNLINK(path) < 0) {
|
||||
mrb_locale_free(path);
|
||||
mrb_sys_fail(mrb, utf8_path);
|
||||
|
||||
@@ -102,12 +102,11 @@ io_get_open_fptr(mrb_state *mrb, mrb_value io)
|
||||
static void
|
||||
io_set_process_status(mrb_state *mrb, pid_t pid, int status)
|
||||
{
|
||||
struct RClass *c_process, *c_status;
|
||||
struct RClass *c_status = NULL;
|
||||
mrb_value v;
|
||||
|
||||
c_status = NULL;
|
||||
if (mrb_class_defined_id(mrb, MRB_SYM(Process))) {
|
||||
c_process = mrb_module_get_id(mrb, MRB_SYM(Process));
|
||||
struct RClass *c_process = mrb_module_get_id(mrb, MRB_SYM(Process));
|
||||
if (mrb_const_defined(mrb, mrb_obj_value(c_process), MRB_SYM(Status))) {
|
||||
c_status = mrb_class_get_under_id(mrb, c_process, MRB_SYM(Status));
|
||||
}
|
||||
@@ -522,8 +521,6 @@ io_s_popen(mrb_state *mrb, mrb_value klass)
|
||||
}
|
||||
|
||||
if (!doexec) {
|
||||
// XXX
|
||||
fflush(stdin);
|
||||
fflush(stdout);
|
||||
fflush(stderr);
|
||||
}
|
||||
@@ -1223,26 +1220,22 @@ time2timeval(mrb_state *mrb, mrb_value time)
|
||||
static mrb_value
|
||||
io_s_pipe(mrb_state *mrb, mrb_value klass)
|
||||
{
|
||||
mrb_value r = mrb_nil_value();
|
||||
mrb_value w = mrb_nil_value();
|
||||
struct mrb_io *fptr_r;
|
||||
struct mrb_io *fptr_w;
|
||||
int pipes[2];
|
||||
|
||||
if (io_pipe(mrb, pipes) == -1) {
|
||||
mrb_sys_fail(mrb, "pipe");
|
||||
}
|
||||
|
||||
r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
fptr_r = io_alloc(mrb);
|
||||
mrb_value r = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
struct mrb_io *fptr_r = io_alloc(mrb);
|
||||
fptr_r->fd = pipes[0];
|
||||
fptr_r->readable = 1;
|
||||
DATA_TYPE(r) = &mrb_io_type;
|
||||
DATA_PTR(r) = fptr_r;
|
||||
io_init_buf(mrb, fptr_r);
|
||||
|
||||
w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
fptr_w = io_alloc(mrb);
|
||||
mrb_value w = mrb_obj_value(mrb_data_object_alloc(mrb, mrb_class_ptr(klass), NULL, &mrb_io_type));
|
||||
struct mrb_io *fptr_w = io_alloc(mrb);
|
||||
fptr_w->fd = pipes[1];
|
||||
fptr_w->writable = 1;
|
||||
fptr_w->sync = 1;
|
||||
|
||||
@@ -59,7 +59,7 @@ mrb_f_caller(mrb_state *mrb, mrb_value self)
|
||||
if (n < 0) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "negative size (%d)", n);
|
||||
}
|
||||
if (n == 0 || bt_len <= lev) {
|
||||
if (n == 0) {
|
||||
return mrb_ary_new(mrb);
|
||||
}
|
||||
if (bt_len <= n + lev) n = bt_len - lev - 1;
|
||||
|
||||
@@ -74,7 +74,7 @@ atanh(double x)
|
||||
}
|
||||
else {
|
||||
/* Basic formula for atanh */
|
||||
y = 0.5 * (log(1.0+x) - log(1.0-x));
|
||||
y = 0.5 * (log1p(x) - log1p(-x));
|
||||
}
|
||||
|
||||
return y;
|
||||
@@ -105,7 +105,7 @@ double erfc(double x);
|
||||
double
|
||||
erf(double x)
|
||||
{
|
||||
static const double two_sqrtpi = 1.128379167095512574;
|
||||
static const double two_sqrtpi = 1.128379167095512574;
|
||||
double sum = x;
|
||||
double term = x;
|
||||
double xsqr = x*x;
|
||||
@@ -129,7 +129,7 @@ erf(double x)
|
||||
double
|
||||
erfc(double x)
|
||||
{
|
||||
static const double one_sqrtpi= 0.564189583547756287;
|
||||
static const double one_sqrtpi = 0.564189583547756287;
|
||||
double a = 1;
|
||||
double b = x;
|
||||
double c = x;
|
||||
@@ -137,15 +137,15 @@ erfc(double x)
|
||||
double q1;
|
||||
double q2 = b/d;
|
||||
double n = 1.0;
|
||||
double t;
|
||||
|
||||
if (fabs(x) < 2.2) {
|
||||
return 1.0 - erf(x);
|
||||
return erfc(x);
|
||||
}
|
||||
if (x < 0.0) { /*signbit(x)*/
|
||||
return 2.0 - erfc(-x);
|
||||
}
|
||||
do {
|
||||
t = a*n+b*x;
|
||||
double t = a*n+b*x;
|
||||
a = b;
|
||||
b = t;
|
||||
t = c*n+d*x;
|
||||
|
||||
@@ -176,7 +176,6 @@ static mrb_value
|
||||
mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass *klass)
|
||||
{
|
||||
mrb_value ary;
|
||||
struct RClass *oldklass;
|
||||
khash_t(st) *set = kh_init(st, mrb);
|
||||
|
||||
if (!recur) {
|
||||
@@ -187,8 +186,8 @@ mrb_class_instance_method_list(mrb_state *mrb, mrb_bool recur, struct RClass *kl
|
||||
}
|
||||
else {
|
||||
khash_t(st) *undef = kh_init(st, mrb);
|
||||
struct RClass *oldklass = NULL;
|
||||
|
||||
oldklass = NULL;
|
||||
while (klass && (klass != oldklass)) {
|
||||
method_entry_loop(mrb, klass, set, undef);
|
||||
oldklass = klass;
|
||||
|
||||
@@ -165,8 +165,7 @@ int_digits(mrb_state *mrb, mrb_value self)
|
||||
}
|
||||
|
||||
while (mrb_bint_cmp(mrb, x, zero) > 0) {
|
||||
mrb_value q = mrb_bint_mod(mrb, x, bv);
|
||||
mrb_ary_push(mrb, digits, q);
|
||||
mrb_ary_push(mrb, digits, mrb_bint_mod(mrb, x, bv));
|
||||
x = mrb_bint_div(mrb, x, bv);
|
||||
if (!mrb_bigint_p(x)) {
|
||||
mrb_int n = mrb_integer(x);
|
||||
|
||||
@@ -60,6 +60,8 @@ nil_to_i(mrb_state *mrb, mrb_value obj)
|
||||
}
|
||||
|
||||
/*
|
||||
* Document-method: Kernel#itself
|
||||
*
|
||||
* call-seq:
|
||||
* obj.itself -> an_object
|
||||
*
|
||||
@@ -69,11 +71,6 @@ nil_to_i(mrb_state *mrb, mrb_value obj)
|
||||
* string.itself.object_id == string.object_id #=> true
|
||||
*
|
||||
*/
|
||||
static mrb_value
|
||||
f_itself(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
@@ -122,7 +119,7 @@ mrb_mruby_object_ext_gem_init(mrb_state* mrb)
|
||||
mrb_define_method(mrb, n, "to_h", nil_to_h, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, n, "to_i", nil_to_i, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_method(mrb, mrb->kernel_module, "itself", f_itself, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, mrb->kernel_module, "itself", mrb_obj_itself, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_method(mrb, mrb_class_get_id(mrb, MRB_SYM(BasicObject)), "instance_exec", obj_instance_exec, MRB_ARGS_ANY() | MRB_ARGS_BLOCK());
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#include <mruby.h>
|
||||
#include <mruby/error.h>
|
||||
#include <mruby/gc.h>
|
||||
#include <mruby/hash.h>
|
||||
#include <mruby/class.h>
|
||||
@@ -167,6 +168,9 @@ os_memsize_of_object(mrb_state* mrb, mrb_value obj)
|
||||
case MRB_TT_ISTRUCT:
|
||||
size += mrb_objspace_page_slot_size();
|
||||
break;
|
||||
case MRB_TT_BACKTRACE:
|
||||
size += ((struct RBacktrace*)mrb_obj_ptr(obj))->len * sizeof(struct mrb_backtrace_location);
|
||||
break;
|
||||
/* zero heap size types.
|
||||
* immediate VM stack values, contained within mrb_state, or on C stack */
|
||||
case MRB_TT_TRUE:
|
||||
|
||||
@@ -45,7 +45,9 @@ There is no dependency on other mrbgems.
|
||||
- V : 32-bit unsigned, VAX (little-endian) byte order
|
||||
- v : 16-bit unsigned, VAX (little-endian) byte order
|
||||
- x : null byte
|
||||
- X : back up bytes
|
||||
- Z : same as "a", except that null is added with \*
|
||||
- @ : absolute position
|
||||
|
||||
## License
|
||||
|
||||
|
||||
@@ -291,27 +291,24 @@ static void
|
||||
u64tostr(char *buf, size_t len, uint64_t n)
|
||||
{
|
||||
#ifdef MRB_NO_STDIO
|
||||
char *bufend = buf + len;
|
||||
char *p = bufend - 1;
|
||||
mrb_assert(len > 0);
|
||||
|
||||
if (len < 1) {
|
||||
if (n < 10) {
|
||||
buf[0] = '0' + n;
|
||||
buf[1] = '\0';
|
||||
return;
|
||||
}
|
||||
|
||||
char *bufend = buf + len;
|
||||
char *p = bufend - 1;
|
||||
|
||||
*p-- = '\0';
|
||||
len--;
|
||||
|
||||
if (n > 0) {
|
||||
for (; len > 0 && n > 0; len--, n /= 10) {
|
||||
*p-- = '0' + (n % 10);
|
||||
}
|
||||
p++;
|
||||
for (; len > 0 && n > 0; len--, n /= 10) {
|
||||
*p-- = '0' + (n % 10);
|
||||
}
|
||||
else if (len > 0) {
|
||||
*p = '0';
|
||||
len--;
|
||||
}
|
||||
|
||||
p++;
|
||||
memmove(buf, p, bufend - p);
|
||||
#else
|
||||
snprintf(buf, len, "%" PRIu64, n);
|
||||
@@ -323,9 +320,7 @@ static void
|
||||
i64tostr(char *buf, size_t len, int64_t n)
|
||||
{
|
||||
#ifdef MRB_NO_STDIO
|
||||
if (len < 1) {
|
||||
return;
|
||||
}
|
||||
mrb_assert(len > 0);
|
||||
|
||||
if (n < 0) {
|
||||
*buf++ = '-';
|
||||
@@ -731,7 +726,7 @@ unpack_str(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count,
|
||||
CHECK_UNPACK_LEN(mrb, slen, ary);
|
||||
|
||||
mrb_value dst;
|
||||
const char *cp, *sptr;
|
||||
const char *sptr;
|
||||
int copylen;
|
||||
|
||||
sptr = (const char*)src;
|
||||
@@ -741,6 +736,8 @@ unpack_str(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count,
|
||||
copylen = slen;
|
||||
|
||||
if (slen >= 0 && flags & PACK_FLAG_Z) { /* "Z" */
|
||||
const char *cp;
|
||||
|
||||
if ((cp = (const char*)memchr(sptr, '\0', slen)) != NULL) {
|
||||
copylen = (int)(cp - sptr);
|
||||
if (count == -1) {
|
||||
@@ -764,7 +761,6 @@ unpack_str(mrb_state *mrb, const void *src, int slen, mrb_value ary, int count,
|
||||
static int
|
||||
pack_hex(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count, unsigned int flags)
|
||||
{
|
||||
int a, b;
|
||||
unsigned int ashift, bshift;
|
||||
long slen;
|
||||
char *dptr, *dptr0, *sptr;
|
||||
@@ -793,7 +789,8 @@ pack_hex(mrb_state *mrb, mrb_value src, mrb_value dst, mrb_int didx, int count,
|
||||
|
||||
dptr0 = dptr;
|
||||
for (; count > 0; count -= 2) {
|
||||
a = b = 0;
|
||||
int a = 0, b = 0;
|
||||
|
||||
if (slen > 0) {
|
||||
a = hex2int(*sptr++);
|
||||
if (a < 0) break;
|
||||
@@ -1498,19 +1495,17 @@ static mrb_value
|
||||
mrb_pack_pack(mrb_state *mrb, mrb_value ary)
|
||||
{
|
||||
mrb_value o, result;
|
||||
mrb_int aidx;
|
||||
struct tmpl tmpl;
|
||||
int count;
|
||||
enum pack_type type;
|
||||
int count, size;
|
||||
unsigned int flags;
|
||||
enum pack_dir dir;
|
||||
enum pack_type type;
|
||||
int ridx, size;
|
||||
|
||||
prepare_tmpl(mrb, &tmpl);
|
||||
|
||||
result = mrb_str_new(mrb, NULL, 128); /* allocate initial buffer */
|
||||
aidx = 0;
|
||||
ridx = 0;
|
||||
mrb_int aidx = 0;
|
||||
mrb_int ridx = 0;
|
||||
while (has_tmpl(&tmpl)) {
|
||||
dir = read_tmpl(mrb, &tmpl, &type, &size, &count, &flags);
|
||||
|
||||
@@ -1667,18 +1662,23 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
|
||||
switch (dir) {
|
||||
case PACK_DIR_HEX:
|
||||
srcidx += unpack_hex(mrb, sptr, srclen - srcidx, result, count, flags);
|
||||
if (single) goto single_return;
|
||||
continue;
|
||||
case PACK_DIR_BSTR:
|
||||
srcidx += unpack_bstr(mrb, sptr, srclen - srcidx, result, count, flags);
|
||||
if (single) goto single_return;
|
||||
continue;
|
||||
case PACK_DIR_STR:
|
||||
srcidx += unpack_str(mrb, sptr, srclen - srcidx, result, count, flags);
|
||||
if (single) goto single_return;
|
||||
continue;
|
||||
case PACK_DIR_BASE64:
|
||||
srcidx += unpack_base64(mrb, sptr, srclen - srcidx, result);
|
||||
if (single) goto single_return;
|
||||
continue;
|
||||
case PACK_DIR_QENC:
|
||||
srcidx += unpack_qenc(mrb, sptr, srclen - srcidx, result);
|
||||
if (single) goto single_return;
|
||||
continue;
|
||||
default:
|
||||
break;
|
||||
@@ -1729,6 +1729,7 @@ pack_unpack(mrb_state *mrb, mrb_value str, int single)
|
||||
}
|
||||
}
|
||||
if (single) {
|
||||
single_return:
|
||||
if (RARRAY_LEN(result) > 0) {
|
||||
return RARRAY_PTR(result)[0];
|
||||
}
|
||||
|
||||
@@ -156,3 +156,18 @@ assert 'pack/unpack "U"' do
|
||||
assert_raise(RangeError) { [-1].pack("U") }
|
||||
assert_raise(RangeError) { [0x40000000].pack("U") }
|
||||
end
|
||||
|
||||
assert 'unpack1' do
|
||||
d = 1234
|
||||
assert_equal(d, [d].pack("i").unpack1("i"))
|
||||
d = "foobar"
|
||||
assert_equal(d, [d].pack("a*").unpack1("a*"))
|
||||
assert_equal(d, [d].pack("A*").unpack1("A*"))
|
||||
assert_equal(d, [d].pack("Z*").unpack1("Z*"))
|
||||
assert_equal(d, [d].pack("m").unpack1("m"))
|
||||
assert_equal(d, [d].pack("M").unpack1("M"))
|
||||
d = "10010101"
|
||||
assert_equal(d, [d].pack("b*").unpack1("b*"))
|
||||
d = "f00b00"
|
||||
assert_equal(d, [d].pack("h*").unpack1("h*"))
|
||||
end
|
||||
|
||||
@@ -344,28 +344,27 @@ mrb_ary_sample(mrb_state *mrb, mrb_value ary)
|
||||
}
|
||||
else {
|
||||
mrb_value result;
|
||||
mrb_int i, j;
|
||||
|
||||
if (n < 0) mrb_raise(mrb, E_ARGUMENT_ERROR, "negative sample number");
|
||||
if (n > len) n = len;
|
||||
result = mrb_ary_new_capa(mrb, n);
|
||||
for (i=0; i<n; i++) {
|
||||
mrb_int r;
|
||||
for (mrb_int i=0; i<n; i++) {
|
||||
mrb_int idx;
|
||||
|
||||
for (;;) {
|
||||
retry:
|
||||
r = rand_i(random, len);
|
||||
idx = rand_i(random, len);
|
||||
|
||||
for (j=0; j<i; j++) {
|
||||
if (mrb_integer(RARRAY_PTR(result)[j]) == r) {
|
||||
for (mrb_int j=0; j<i; j++) {
|
||||
if (mrb_integer(RARRAY_PTR(result)[j]) == idx) {
|
||||
goto retry; /* retry if duplicate */
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
mrb_ary_push(mrb, result, mrb_int_value(mrb, r));
|
||||
mrb_ary_push(mrb, result, mrb_int_value(mrb, idx));
|
||||
}
|
||||
for (i=0; i<n; i++) {
|
||||
for (mrb_int i=0; i<n; i++) {
|
||||
mrb_int idx = mrb_integer(RARRAY_PTR(result)[i]);
|
||||
mrb_value elem = RARRAY_PTR(ary)[idx];
|
||||
mrb_ary_set(mrb, result, i, elem);
|
||||
|
||||
@@ -254,47 +254,6 @@ rational_new_f(mrb_state *mrb, mrb_float f0)
|
||||
}
|
||||
#endif
|
||||
|
||||
static mrb_value
|
||||
rational_s_new(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
mrb_int numerator, denominator;
|
||||
|
||||
#ifdef MRB_NO_FLOAT
|
||||
mrb_get_args(mrb, "ii", &numerator, &denominator);
|
||||
#else
|
||||
|
||||
mrb_value numv, denomv;
|
||||
|
||||
mrb_get_args(mrb, "oo", &numv, &denomv);
|
||||
if (mrb_integer_p(numv)) {
|
||||
numerator = mrb_integer(numv);
|
||||
|
||||
if (mrb_integer_p(denomv)) {
|
||||
denominator = mrb_integer(denomv);
|
||||
}
|
||||
else {
|
||||
mrb_float numf = (mrb_float)numerator;
|
||||
mrb_float denomf = mrb_as_float(mrb, denomv);
|
||||
|
||||
return rational_new_f(mrb, numf/denomf);
|
||||
}
|
||||
}
|
||||
else {
|
||||
mrb_float numf = mrb_as_float(mrb, numv);
|
||||
mrb_float denomf;
|
||||
|
||||
if (mrb_integer_p(denomv)) {
|
||||
denomf = (mrb_float)mrb_integer(denomv);
|
||||
}
|
||||
else {
|
||||
denomf = mrb_as_float(mrb, denomv);
|
||||
}
|
||||
return rational_new_f(mrb, numf/denomf);
|
||||
}
|
||||
#endif
|
||||
return rational_new(mrb, numerator, denominator);
|
||||
}
|
||||
|
||||
#ifndef MRB_NO_FLOAT
|
||||
static mrb_float
|
||||
rat_float(struct mrb_rational *p)
|
||||
@@ -329,12 +288,6 @@ mrb_rational_to_i(mrb_state *mrb, mrb_value self)
|
||||
return mrb_int_value(mrb, p->numerator / p->denominator);
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
rational_to_r(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
rational_negative_p(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
@@ -702,9 +655,10 @@ rational_div(mrb_state *mrb, mrb_value x)
|
||||
static mrb_value
|
||||
rational_pow(mrb_state *mrb, mrb_value x)
|
||||
{
|
||||
#ifndef MRB_NO_FLOAT
|
||||
mrb_value y = mrb_get_arg1(mrb);
|
||||
struct mrb_rational *p1 = rational_ptr(mrb, x);
|
||||
#ifndef MRB_NO_FLOAT
|
||||
|
||||
double d1, d2;
|
||||
|
||||
switch (mrb_type(y)) {
|
||||
@@ -770,14 +724,13 @@ void mrb_mruby_rational_gem_init(mrb_state *mrb)
|
||||
MRB_SET_INSTANCE_TT(rat, MRB_TT_RATIONAL);
|
||||
MRB_UNDEF_ALLOCATOR(rat);
|
||||
mrb_undef_class_method(mrb, rat, "new");
|
||||
mrb_define_class_method(mrb, rat, "_new", rational_s_new, MRB_ARGS_REQ(2));
|
||||
mrb_define_method(mrb, rat, "numerator", rational_numerator, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, rat, "denominator", rational_denominator, MRB_ARGS_NONE());
|
||||
#ifndef MRB_NO_FLOAT
|
||||
mrb_define_method(mrb, rat, "to_f", mrb_rational_to_f, MRB_ARGS_NONE());
|
||||
#endif
|
||||
mrb_define_method(mrb, rat, "to_i", mrb_rational_to_i, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, rat, "to_r", rational_to_r, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, rat, "to_r", mrb_obj_itself, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, rat, "negative?", rational_negative_p, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, rat, "==", rational_eq, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, rat, "<=>", rational_cmp, MRB_ARGS_REQ(1));
|
||||
|
||||
@@ -53,7 +53,7 @@ int_chr_utf8(mrb_state *mrb, mrb_value num)
|
||||
char utf8[4];
|
||||
mrb_int len;
|
||||
mrb_value str;
|
||||
uint32_t ascii_flag = 0;
|
||||
uint32_t sb_flag = 0;
|
||||
|
||||
if (cp < 0 || 0x10FFFF < cp) {
|
||||
mrb_raisef(mrb, E_RANGE_ERROR, "%v out of char range", num);
|
||||
@@ -61,7 +61,7 @@ int_chr_utf8(mrb_state *mrb, mrb_value num)
|
||||
if (cp < 0x80) {
|
||||
utf8[0] = (char)cp;
|
||||
len = 1;
|
||||
ascii_flag = MRB_STR_ASCII;
|
||||
sb_flag = MRB_STR_SINGLE_BYTE;
|
||||
}
|
||||
else if (cp < 0x800) {
|
||||
utf8[0] = (char)(0xC0 | (cp >> 6));
|
||||
@@ -82,7 +82,7 @@ int_chr_utf8(mrb_state *mrb, mrb_value num)
|
||||
len = 4;
|
||||
}
|
||||
str = mrb_str_new(mrb, utf8, len);
|
||||
mrb_str_ptr(str)->flags |= ascii_flag;
|
||||
mrb_str_ptr(str)->flags |= sb_flag;
|
||||
return str;
|
||||
}
|
||||
#endif
|
||||
@@ -1304,10 +1304,6 @@ str_uplus(mrb_state *mrb, mrb_value str)
|
||||
*
|
||||
* Returns a frozen, possibly pre-existing copy of the string.
|
||||
*
|
||||
* The returned \String will be deduplicated as long as it does not have
|
||||
* any instance variables set on it and is not a String subclass.
|
||||
*
|
||||
* String#dedup is an alias for String#-@.
|
||||
*/
|
||||
static mrb_value
|
||||
str_uminus(mrb_state *mrb, mrb_value str)
|
||||
@@ -1332,34 +1328,39 @@ str_valid_enc_p(mrb_state *mrb, mrb_value str)
|
||||
#define utf8_islead(c) ((unsigned char)((c)&0xc0) != 0x80)
|
||||
|
||||
struct RString *s = mrb_str_ptr(str);
|
||||
if (RSTR_ASCII_P(s)) return mrb_true_value();
|
||||
if (RSTR_SINGLE_BYTE_P(s)) return mrb_true_value();
|
||||
|
||||
mrb_int byte_len = RSTR_LEN(s);
|
||||
mrb_int utf8_len = 0;
|
||||
const char *p = RSTR_PTR(s);
|
||||
const char *e = p + byte_len;
|
||||
while (p < e) {
|
||||
mrb_int len = mrb_utf8len_table[(unsigned char)p[0] >> 3];
|
||||
if (len == 0 || len > e - p)
|
||||
return mrb_false_value();
|
||||
switch (len) {
|
||||
case 4:
|
||||
if (utf8_islead(p[3])) return mrb_false_value();
|
||||
case 3:
|
||||
if (utf8_islead(p[2])) return mrb_false_value();
|
||||
case 2:
|
||||
if (utf8_islead(p[1])) return mrb_false_value();
|
||||
default:
|
||||
break;
|
||||
}
|
||||
mrb_int len = mrb_utf8len(p, e);
|
||||
|
||||
if (len == 1 && (*p & 0x80)) return mrb_false_value();
|
||||
p += len;
|
||||
utf8_len++;
|
||||
}
|
||||
if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s);
|
||||
if (byte_len == utf8_len) RSTR_SET_SINGLE_BYTE_FLAG(s);
|
||||
#endif
|
||||
return mrb_true_value();
|
||||
}
|
||||
|
||||
static mrb_value
|
||||
str_ascii_only_p(mrb_state *mrb, mrb_value str)
|
||||
{
|
||||
struct RString *s = mrb_str_ptr(str);
|
||||
const char *p = RSTR_PTR(s);
|
||||
const char *e = p + RSTR_LEN(s);
|
||||
|
||||
while (p < e) {
|
||||
if (*p & 0x80) return mrb_false_value();
|
||||
p++;
|
||||
}
|
||||
RSTR_SET_SINGLE_BYTE_FLAG(mrb_str_ptr(str));
|
||||
return mrb_true_value();
|
||||
}
|
||||
|
||||
void
|
||||
mrb_mruby_string_ext_gem_init(mrb_state* mrb)
|
||||
{
|
||||
@@ -1398,6 +1399,7 @@ mrb_mruby_string_ext_gem_init(mrb_state* mrb)
|
||||
mrb_define_method(mrb, s, "+@", str_uplus, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, s, "-@", str_uminus, MRB_ARGS_REQ(1));
|
||||
mrb_define_method(mrb, s, "valid_encoding?", str_valid_enc_p, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, s, "ascii_only?", str_ascii_only_p, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_method(mrb, s, "__lines", str_lines, MRB_ARGS_NONE());
|
||||
mrb_define_method(mrb, s, "__codepoints", str_codepoints, MRB_ARGS_NONE());
|
||||
|
||||
+4
-4
@@ -215,18 +215,18 @@ ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len)
|
||||
capa = len;
|
||||
}
|
||||
}
|
||||
if (capa < len || capa > ARY_MAX_SIZE) {
|
||||
if (capa > ARY_MAX_SIZE) {
|
||||
ary_too_big(mrb);
|
||||
}
|
||||
|
||||
if (ARY_EMBED_P(a)) {
|
||||
mrb_value *ptr = ARY_EMBED_PTR(a);
|
||||
mrb_int len = ARY_EMBED_LEN(a);
|
||||
mrb_int slen = ARY_EMBED_LEN(a);
|
||||
mrb_value *expanded_ptr = (mrb_value*)mrb_malloc(mrb, sizeof(mrb_value)*capa);
|
||||
|
||||
ARY_UNSET_EMBED_FLAG(a);
|
||||
array_copy(expanded_ptr, ptr, len);
|
||||
a->as.heap.len = len;
|
||||
array_copy(expanded_ptr, ptr, slen);
|
||||
a->as.heap.len = slen;
|
||||
a->as.heap.aux.capa = capa;
|
||||
a->as.heap.ptr = expanded_ptr;
|
||||
}
|
||||
|
||||
+103
-95
@@ -17,23 +17,30 @@
|
||||
#include <mruby/internal.h>
|
||||
#include <mruby/presym.h>
|
||||
|
||||
struct backtrace_location {
|
||||
mrb_sym method_id;
|
||||
int32_t idx;
|
||||
const mrb_irep *irep;
|
||||
};
|
||||
|
||||
typedef void (*each_backtrace_func)(mrb_state*, const struct backtrace_location*, void*);
|
||||
|
||||
static const mrb_data_type bt_type = { "Backtrace", mrb_free };
|
||||
|
||||
static uint32_t
|
||||
each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, each_backtrace_func func, void *data)
|
||||
static void
|
||||
copy_backtrace(mrb_state *mrb,
|
||||
const struct mrb_backtrace_location *loc,
|
||||
struct mrb_backtrace_location *ptr,
|
||||
size_t n)
|
||||
{
|
||||
uint32_t n = 0;
|
||||
ptr[n] = *loc;
|
||||
if (loc->irep) {
|
||||
if (loc->irep->refcnt == UINT16_MAX) {
|
||||
ptr[n].irep = NULL;
|
||||
}
|
||||
else {
|
||||
mrb_irep_incref(mrb, (mrb_irep*)loc->irep);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static size_t
|
||||
pack_backtrace(mrb_state *mrb, ptrdiff_t ciidx, struct mrb_backtrace_location *ptr)
|
||||
{
|
||||
size_t n = 0;
|
||||
|
||||
for (ptrdiff_t i=ciidx; i >= 0; i--) {
|
||||
struct backtrace_location loc;
|
||||
struct mrb_backtrace_location loc;
|
||||
mrb_callinfo *ci;
|
||||
const mrb_code *pc;
|
||||
|
||||
@@ -75,59 +82,42 @@ each_backtrace(mrb_state *mrb, ptrdiff_t ciidx, each_backtrace_func func, void *
|
||||
}
|
||||
|
||||
loc.irep = irep;
|
||||
loc.idx = (uint32_t)(pc - loc.irep->iseq);
|
||||
loc.idx = (uint32_t)(pc - irep->iseq);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (func) func(mrb, &loc, data);
|
||||
copy_backtrace(mrb, &loc, ptr, n);
|
||||
n++;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
static void
|
||||
pack_backtrace_i(mrb_state *mrb,
|
||||
const struct backtrace_location *loc,
|
||||
void *data)
|
||||
{
|
||||
struct backtrace_location **pptr = (struct backtrace_location**)data;
|
||||
struct backtrace_location *ptr = *pptr;
|
||||
|
||||
*ptr = *loc;
|
||||
*pptr = ptr+1;
|
||||
}
|
||||
|
||||
static struct RObject*
|
||||
static struct RBasic*
|
||||
packed_backtrace(mrb_state *mrb)
|
||||
{
|
||||
struct RData *backtrace;
|
||||
struct RBacktrace *backtrace;
|
||||
ptrdiff_t ciidx = mrb->c->ci - mrb->c->cibase;
|
||||
|
||||
if (ciidx >= mrb->c->ciend - mrb->c->cibase)
|
||||
ciidx = mrb->c->ciend - mrb->c->cibase; /* ciidx is broken... */
|
||||
|
||||
/* count the number of backtraces */
|
||||
int len = each_backtrace(mrb, ciidx, NULL, NULL);
|
||||
backtrace = mrb_data_object_alloc(mrb, NULL, NULL, &bt_type);
|
||||
if (len > 0) {
|
||||
void *ptr = mrb_malloc(mrb, len * sizeof(struct backtrace_location));
|
||||
backtrace->data = ptr;
|
||||
backtrace->flags = len;
|
||||
each_backtrace(mrb, ciidx, pack_backtrace_i, &ptr);
|
||||
}
|
||||
else {
|
||||
backtrace->data = NULL;
|
||||
backtrace->flags = 0;
|
||||
}
|
||||
return (struct RObject*)backtrace;
|
||||
ptrdiff_t len = ciidx + 1;
|
||||
|
||||
backtrace = MRB_OBJ_ALLOC(mrb, MRB_TT_BACKTRACE, NULL);
|
||||
|
||||
void *ptr = mrb_malloc(mrb, len * sizeof(struct mrb_backtrace_location));
|
||||
backtrace->locations = (struct mrb_backtrace_location*)ptr;
|
||||
backtrace->len = pack_backtrace(mrb, ciidx, backtrace->locations);
|
||||
|
||||
return (struct RBasic*)backtrace;
|
||||
}
|
||||
|
||||
static void
|
||||
store_backtrace(mrb_state *mrb, mrb_value exc, struct RObject *backtrace)
|
||||
store_backtrace(mrb_state *mrb, mrb_value exc, struct RBasic *backtrace)
|
||||
{
|
||||
struct RException *e = mrb_exc_ptr(exc);
|
||||
e->backtrace = backtrace;
|
||||
mrb_field_write_barrier(mrb, (struct RBasic*)e, (struct RBasic*)backtrace);
|
||||
mrb_field_write_barrier(mrb, (struct RBasic*)e, backtrace);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -138,48 +128,52 @@ mrb_keep_backtrace(mrb_state *mrb, mrb_value exc)
|
||||
if (mrb->c->ci == NULL) return;
|
||||
if (mrb_exc_ptr(exc)->backtrace) return;
|
||||
ai = mrb_gc_arena_save(mrb);
|
||||
struct RObject *backtrace = packed_backtrace(mrb);
|
||||
struct RBasic *backtrace = packed_backtrace(mrb);
|
||||
store_backtrace(mrb, exc, backtrace);
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
|
||||
static struct RObject*
|
||||
mrb_unpack_backtrace(mrb_state *mrb, struct RObject *backtrace)
|
||||
static mrb_value
|
||||
decode_location(mrb_state *mrb, const struct mrb_backtrace_location *entry)
|
||||
{
|
||||
const struct backtrace_location *bt;
|
||||
mrb_int n, i;
|
||||
int ai;
|
||||
mrb_value btline;
|
||||
int32_t lineno;
|
||||
const char *filename;
|
||||
|
||||
if (!entry->irep || !mrb_debug_get_position(mrb, entry->irep, entry->idx, &lineno, &filename)) {
|
||||
btline = mrb_str_new_lit(mrb, "(unknown):0");
|
||||
}
|
||||
else if (lineno != -1) {//debug info was available
|
||||
btline = mrb_format(mrb, "%s:%d", filename, (int)lineno);
|
||||
}
|
||||
else { //all that was left was the stack frame
|
||||
btline = mrb_format(mrb, "%s:0", filename);
|
||||
}
|
||||
if (entry->method_id != 0) {
|
||||
mrb_str_cat_lit(mrb, btline, ":in ");
|
||||
mrb_str_cat_cstr(mrb, btline, mrb_sym_name(mrb, entry->method_id));
|
||||
}
|
||||
return btline;
|
||||
}
|
||||
|
||||
static struct RBasic*
|
||||
mrb_unpack_backtrace(mrb_state *mrb, struct RBasic *backtrace)
|
||||
{
|
||||
if (backtrace == NULL) {
|
||||
empty_backtrace:
|
||||
return mrb_obj_ptr(mrb_ary_new_capa(mrb, 0));
|
||||
return mrb_basic_ptr(mrb_ary_new_capa(mrb, 0));
|
||||
}
|
||||
if (backtrace->tt == MRB_TT_ARRAY) return backtrace;
|
||||
bt = (struct backtrace_location*)mrb_data_check_get_ptr(mrb, mrb_obj_value(backtrace), &bt_type);
|
||||
if (bt == NULL) goto empty_backtrace;
|
||||
n = (mrb_int)backtrace->flags;
|
||||
if (n == 0) goto empty_backtrace;
|
||||
backtrace = mrb_obj_ptr(mrb_ary_new_capa(mrb, n));
|
||||
ai = mrb_gc_arena_save(mrb);
|
||||
for (i = 0; i < n; i++) {
|
||||
const struct backtrace_location *entry = &bt[i];
|
||||
mrb_value btline;
|
||||
int32_t lineno;
|
||||
const char *filename;
|
||||
|
||||
if (!mrb_debug_get_position(mrb, entry->irep, entry->idx, &lineno, &filename)) {
|
||||
btline = mrb_str_new_lit(mrb, "(unknown):0");
|
||||
}
|
||||
else if (lineno != -1) {//debug info was available
|
||||
btline = mrb_format(mrb, "%s:%d", filename, (int)lineno);
|
||||
}
|
||||
else { //all that was left was the stack frame
|
||||
btline = mrb_format(mrb, "%s:0", filename);
|
||||
}
|
||||
if (entry->method_id != 0) {
|
||||
mrb_str_cat_lit(mrb, btline, ":in ");
|
||||
mrb_str_cat_cstr(mrb, btline, mrb_sym_name(mrb, entry->method_id));
|
||||
}
|
||||
mrb_assert(backtrace->tt == MRB_TT_BACKTRACE);
|
||||
|
||||
struct RBacktrace *bt = (struct RBacktrace*)backtrace;
|
||||
mrb_int n = bt ? (mrb_int)bt->len : 0;
|
||||
const struct mrb_backtrace_location *loc = bt->locations;
|
||||
|
||||
backtrace = mrb_basic_ptr(mrb_ary_new_capa(mrb, n));
|
||||
int ai = mrb_gc_arena_save(mrb);
|
||||
for (mrb_int i = 0; i < n; i++) {
|
||||
mrb_value btline = decode_location(mrb, &loc[i]);
|
||||
mrb_ary_push(mrb, mrb_obj_value(backtrace), btline);
|
||||
mrb_gc_arena_restore(mrb, ai);
|
||||
}
|
||||
@@ -190,7 +184,7 @@ mrb_unpack_backtrace(mrb_state *mrb, struct RObject *backtrace)
|
||||
mrb_value
|
||||
mrb_exc_backtrace(mrb_state *mrb, mrb_value exc)
|
||||
{
|
||||
struct RObject *backtrace = mrb_exc_ptr(exc)->backtrace;
|
||||
struct RBasic *backtrace = mrb_exc_ptr(exc)->backtrace;
|
||||
if (backtrace == NULL) {
|
||||
return mrb_nil_value();
|
||||
}
|
||||
@@ -212,25 +206,40 @@ mrb_get_backtrace(mrb_state *mrb)
|
||||
#ifndef MRB_NO_STDIO
|
||||
|
||||
static void
|
||||
print_backtrace(mrb_state *mrb, struct RObject *exc, struct RArray *backtrace)
|
||||
print_backtrace(mrb_state *mrb, struct RObject *exc, struct RBasic *ptr)
|
||||
{
|
||||
mrb_int i;
|
||||
mrb_int n = (backtrace ? ARY_LEN(backtrace) : 0);
|
||||
mrb_value *loc, mesg;
|
||||
struct RArray *ary = NULL;
|
||||
struct RBacktrace *bt = NULL;
|
||||
mrb_int n = 0;
|
||||
|
||||
if (ptr) {
|
||||
if (ptr->tt == MRB_TT_ARRAY) {
|
||||
ary = (struct RArray*)ptr;
|
||||
n = ARY_LEN(ary);
|
||||
}
|
||||
else {
|
||||
bt = (struct RBacktrace*)ptr;
|
||||
n = (mrb_int)bt->len;
|
||||
}
|
||||
}
|
||||
|
||||
if (n != 0) {
|
||||
if (n > 1) {
|
||||
fputs("trace (most recent call last):\n", stderr);
|
||||
}
|
||||
for (i=n-1,loc=&ARY_PTR(backtrace)[i]; i>0; i--,loc--) {
|
||||
if (mrb_string_p(*loc)) {
|
||||
mrb_value btline;
|
||||
|
||||
fputs("trace (most recent call last):\n", stderr);
|
||||
for (mrb_int i=n-1; i>0; i--) {
|
||||
if (ary) btline = ARY_PTR(ary)[i];
|
||||
else btline = decode_location(mrb, &bt->locations[i]);
|
||||
if (mrb_string_p(btline)) {
|
||||
fprintf(stderr, "\t[%d] ", (int)i);
|
||||
fwrite(RSTRING_PTR(*loc), (int)RSTRING_LEN(*loc), 1, stderr);
|
||||
fwrite(RSTRING_PTR(btline), (int)RSTRING_LEN(btline), 1, stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
}
|
||||
if (mrb_string_p(*loc)) {
|
||||
fwrite(RSTRING_PTR(*loc), (int)RSTRING_LEN(*loc), 1, stderr);
|
||||
if (ary) btline = ARY_PTR(ary)[0];
|
||||
else btline = decode_location(mrb, &bt->locations[0]);
|
||||
if (mrb_string_p(btline)) {
|
||||
fwrite(RSTRING_PTR(btline), (int)RSTRING_LEN(btline), 1, stderr);
|
||||
fputs(": ", stderr);
|
||||
}
|
||||
}
|
||||
@@ -243,7 +252,7 @@ print_backtrace(mrb_state *mrb, struct RObject *exc, struct RArray *backtrace)
|
||||
fwrite(nomem, sizeof(nomem)-1, 1, stderr);
|
||||
}
|
||||
else {
|
||||
mesg = mrb_exc_inspect(mrb, mrb_obj_value(exc));
|
||||
mrb_value mesg = mrb_exc_inspect(mrb, mrb_obj_value(exc));
|
||||
fwrite(RSTRING_PTR(mesg), RSTRING_LEN(mesg), 1, stderr);
|
||||
fputc('\n', stderr);
|
||||
}
|
||||
@@ -261,9 +270,8 @@ mrb_print_backtrace(mrb_state *mrb)
|
||||
return;
|
||||
}
|
||||
|
||||
struct RObject *backtrace = ((struct RException*)mrb->exc)->backtrace;
|
||||
if (backtrace && backtrace->tt != MRB_TT_ARRAY) backtrace = mrb_unpack_backtrace(mrb, backtrace);
|
||||
print_backtrace(mrb, mrb->exc, (struct RArray*)backtrace);
|
||||
struct RBasic *backtrace = ((struct RException*)mrb->exc)->backtrace;
|
||||
print_backtrace(mrb, mrb->exc, backtrace);
|
||||
}
|
||||
#else
|
||||
MRB_API void
|
||||
|
||||
+2
-2
@@ -24,7 +24,7 @@ mrb_exc_mesg_set(mrb_state *mrb, struct RException *exc, mrb_value mesg)
|
||||
if (!mrb_string_p(mesg)) {
|
||||
mesg = mrb_obj_as_string(mrb, mesg);
|
||||
}
|
||||
exc->mesg = mrb_obj_ptr(mesg);
|
||||
exc->mesg = mrb_basic_ptr(mesg);
|
||||
mrb_field_write_barrier_value(mrb, (struct RBasic*)exc, mesg);
|
||||
}
|
||||
|
||||
@@ -160,7 +160,7 @@ set_backtrace(mrb_state *mrb, mrb_value exc, mrb_value backtrace)
|
||||
p++;
|
||||
}
|
||||
}
|
||||
mrb_exc_ptr(exc)->backtrace = mrb_obj_ptr(backtrace);
|
||||
mrb_exc_ptr(exc)->backtrace = mrb_basic_ptr(backtrace);
|
||||
mrb_field_write_barrier_value(mrb, mrb_basic_ptr(exc), backtrace);
|
||||
}
|
||||
|
||||
|
||||
@@ -107,9 +107,11 @@
|
||||
|
||||
*/
|
||||
|
||||
typedef struct RVALUE RVALUE;
|
||||
|
||||
struct free_obj {
|
||||
MRB_OBJECT_HEADER;
|
||||
struct RBasic *next;
|
||||
RVALUE *next;
|
||||
};
|
||||
|
||||
struct RVALUE_initializer {
|
||||
@@ -117,7 +119,7 @@ struct RVALUE_initializer {
|
||||
char padding[sizeof(void*) * 4 - sizeof(uint32_t)];
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
struct RVALUE {
|
||||
union {
|
||||
struct RVALUE_initializer init; /* must be first member to ensure initialization */
|
||||
struct free_obj free;
|
||||
@@ -136,7 +138,7 @@ typedef struct {
|
||||
struct RException exc;
|
||||
struct RBreak brk;
|
||||
} as;
|
||||
} RVALUE;
|
||||
};
|
||||
|
||||
#ifdef GC_DEBUG
|
||||
#define DEBUG(x) (x)
|
||||
@@ -149,12 +151,11 @@ typedef struct {
|
||||
#endif
|
||||
|
||||
typedef struct mrb_heap_page {
|
||||
struct RBasic *freelist;
|
||||
RVALUE *freelist;
|
||||
struct mrb_heap_page *next;
|
||||
struct mrb_heap_page *free_next;
|
||||
mrb_bool old:1;
|
||||
/* Flexible array members are not C++ compatible */
|
||||
/* void* objects[]; */
|
||||
RVALUE objects[MRB_HEAP_PAGE_SIZE];
|
||||
} mrb_heap_page;
|
||||
|
||||
#define GC_STEP_SIZE 1024
|
||||
@@ -181,12 +182,6 @@ mrb_static_assert(MRB_GC_RED <= GC_COLOR_MASK);
|
||||
#define other_white_part(s) ((s)->current_white_part ^ GC_WHITES)
|
||||
#define is_dead(s, o) (((o)->color & other_white_part(s) & GC_WHITES) || (o)->tt == MRB_TT_FREE)
|
||||
|
||||
/* We have removed `objects[]` from `mrb_heap_page` since it was not C++
|
||||
* compatible. Using array index to get pointer after structure instead. */
|
||||
|
||||
/* #define objects(p) ((RVALUE*)p->objects) */
|
||||
#define objects(p) ((RVALUE*)&p[1])
|
||||
|
||||
mrb_noreturn void mrb_raise_nomemory(mrb_state *mrb);
|
||||
|
||||
MRB_API void*
|
||||
@@ -279,7 +274,7 @@ heap_p(mrb_gc *gc, struct RBasic *object)
|
||||
while (page) {
|
||||
RVALUE *p;
|
||||
|
||||
p = objects(page);
|
||||
p = page->objects;
|
||||
if (&p[0].as.basic <= object && object <= &p[MRB_HEAP_PAGE_SIZE - 1].as.basic) {
|
||||
return TRUE;
|
||||
}
|
||||
@@ -299,14 +294,14 @@ mrb_object_dead_p(mrb_state *mrb, struct RBasic *object)
|
||||
static void
|
||||
add_heap(mrb_state *mrb, mrb_gc *gc)
|
||||
{
|
||||
mrb_heap_page *page = (mrb_heap_page*)mrb_calloc(mrb, 1, sizeof(mrb_heap_page) + MRB_HEAP_PAGE_SIZE * sizeof(RVALUE));
|
||||
mrb_heap_page *page = (mrb_heap_page*)mrb_calloc(mrb, 1, sizeof(mrb_heap_page));
|
||||
RVALUE *p, *e;
|
||||
struct RBasic *prev = NULL;
|
||||
RVALUE *prev = NULL;
|
||||
|
||||
for (p = objects(page), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
|
||||
for (p = page->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
|
||||
p->as.free.tt = MRB_TT_FREE;
|
||||
p->as.free.next = prev;
|
||||
prev = &p->as.basic;
|
||||
prev = p;
|
||||
}
|
||||
page->freelist = prev;
|
||||
|
||||
@@ -345,7 +340,7 @@ mrb_gc_init(mrb_state *mrb, mrb_gc *gc)
|
||||
#endif
|
||||
}
|
||||
|
||||
static void obj_free(mrb_state *mrb, struct RBasic *obj, int end);
|
||||
static void obj_free(mrb_state *mrb, struct RBasic *obj, mrb_bool end);
|
||||
|
||||
static void
|
||||
free_heap(mrb_state *mrb, mrb_gc *gc)
|
||||
@@ -357,7 +352,7 @@ free_heap(mrb_state *mrb, mrb_gc *gc)
|
||||
while (page) {
|
||||
tmp = page;
|
||||
page = page->next;
|
||||
for (p = objects(tmp), e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
|
||||
for (p = tmp->objects, e=p+MRB_HEAP_PAGE_SIZE; p<e; p++) {
|
||||
if (p->as.free.tt != MRB_TT_FREE)
|
||||
obj_free(mrb, &p->as.basic, TRUE);
|
||||
}
|
||||
@@ -498,19 +493,19 @@ mrb_obj_alloc(mrb_state *mrb, enum mrb_vtype ttype, struct RClass *cls)
|
||||
add_heap(mrb, gc);
|
||||
}
|
||||
|
||||
struct RBasic *p = gc->free_heaps->freelist;
|
||||
gc->free_heaps->freelist = ((struct free_obj*)p)->next;
|
||||
RVALUE *p = gc->free_heaps->freelist;
|
||||
gc->free_heaps->freelist = p->as.free.next;
|
||||
if (gc->free_heaps->freelist == NULL) {
|
||||
gc->free_heaps = gc->free_heaps->free_next;
|
||||
}
|
||||
|
||||
gc->live++;
|
||||
gc_protect(mrb, gc, p);
|
||||
*(RVALUE*)p = RVALUE_zero;
|
||||
p->tt = ttype;
|
||||
p->c = cls;
|
||||
paint_partial_white(gc, p);
|
||||
return p;
|
||||
gc_protect(mrb, gc, &p->as.basic);
|
||||
*p = RVALUE_zero;
|
||||
p->as.basic.tt = ttype;
|
||||
p->as.basic.c = cls;
|
||||
paint_partial_white(gc, &p->as.basic);
|
||||
return &p->as.basic;
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -704,7 +699,7 @@ mrb_gc_mark(mrb_state *mrb, struct RBasic *obj)
|
||||
}
|
||||
|
||||
static void
|
||||
obj_free(mrb_state *mrb, struct RBasic *obj, int end)
|
||||
obj_free(mrb_state *mrb, struct RBasic *obj, mrb_bool end)
|
||||
{
|
||||
DEBUG(fprintf(stderr, "obj_free(%p,tt=%d)\n",obj,obj->tt));
|
||||
switch (obj->tt) {
|
||||
@@ -823,6 +818,17 @@ obj_free(mrb_state *mrb, struct RBasic *obj, int end)
|
||||
break;
|
||||
#endif
|
||||
|
||||
case MRB_TT_BACKTRACE:
|
||||
{
|
||||
struct RBacktrace *bt = (struct RBacktrace*)obj;
|
||||
for (size_t i = 0; i < bt->len; i++) {
|
||||
const mrb_irep *irep = bt->locations[i].irep;
|
||||
if (irep == NULL) continue;
|
||||
mrb_irep_decref(mrb, (mrb_irep*)irep);
|
||||
}
|
||||
mrb_free(mrb, bt->locations);
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -969,6 +975,10 @@ gc_gray_counts(mrb_state *mrb, mrb_gc *gc, struct RBasic *obj)
|
||||
}
|
||||
break;
|
||||
|
||||
case MRB_TT_BACKTRACE:
|
||||
children += ((struct RBacktrace*)obj)->len;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -1064,7 +1074,7 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
|
||||
size_t tried_sweep = 0;
|
||||
|
||||
while (page && (tried_sweep < limit)) {
|
||||
RVALUE *p = objects(page);
|
||||
RVALUE *p = page->objects;
|
||||
RVALUE *e = p + MRB_HEAP_PAGE_SIZE;
|
||||
size_t freed = 0;
|
||||
mrb_bool dead_slot = TRUE;
|
||||
@@ -1080,7 +1090,7 @@ incremental_sweep_phase(mrb_state *mrb, mrb_gc *gc, size_t limit)
|
||||
obj_free(mrb, &p->as.basic, FALSE);
|
||||
if (p->as.basic.tt == MRB_TT_FREE) {
|
||||
p->as.free.next = page->freelist;
|
||||
page->freelist = (struct RBasic*)p;
|
||||
page->freelist = p;
|
||||
freed++;
|
||||
}
|
||||
else {
|
||||
@@ -1524,7 +1534,7 @@ gc_each_objects(mrb_state *mrb, mrb_gc *gc, mrb_each_object_callback *callback,
|
||||
while (page != NULL) {
|
||||
RVALUE *p;
|
||||
|
||||
p = objects(page);
|
||||
p = page->objects;
|
||||
for (int i=0; i < MRB_HEAP_PAGE_SIZE; i++) {
|
||||
if ((*callback)(mrb, &p[i].as.basic, data) == MRB_EACH_OBJ_BREAK)
|
||||
return;
|
||||
|
||||
+13
-16
@@ -744,18 +744,14 @@ flo_lshift(mrb_state *mrb, mrb_value x)
|
||||
|
||||
/* 15.2.9.3.13 */
|
||||
/*
|
||||
* Document-method: Float#to_f
|
||||
*
|
||||
* call-seq:
|
||||
* flt.to_f -> self
|
||||
*
|
||||
* As <code>flt</code> is already a float, returns +self+.
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
flo_to_f(mrb_state *mrb, mrb_value num)
|
||||
{
|
||||
return num;
|
||||
}
|
||||
|
||||
/* 15.2.9.3.11 */
|
||||
/*
|
||||
* call-seq:
|
||||
@@ -1105,19 +1101,17 @@ flo_abs(mrb_state *mrb, mrb_value num)
|
||||
|
||||
/* 15.2.9.3.24 */
|
||||
/*
|
||||
* Document-method: Integer#to_i
|
||||
* Document-method: Integer#to_int
|
||||
*
|
||||
* call-seq:
|
||||
* int.to_i -> integer
|
||||
* int.to_int -> integer
|
||||
*
|
||||
* As <i>int</i> is already an <code>Integer</code>, all these
|
||||
* methods simply return the receiver.
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
int_to_i(mrb_state *mrb, mrb_value num)
|
||||
{
|
||||
return num;
|
||||
}
|
||||
|
||||
mrb_value
|
||||
mrb_int_mul(mrb_state *mrb, mrb_value x, mrb_value y)
|
||||
{
|
||||
@@ -1976,7 +1970,6 @@ MRB_API mrb_value
|
||||
mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
|
||||
{
|
||||
char buf[MRB_INT_BIT+1];
|
||||
mrb_int val = mrb_integer(x);
|
||||
|
||||
if (base < 2 || 36 < base) {
|
||||
mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid radix %i", base);
|
||||
@@ -1986,6 +1979,7 @@ mrb_integer_to_str(mrb_state *mrb, mrb_value x, mrb_int base)
|
||||
return mrb_bint_to_s(mrb, x, base);
|
||||
}
|
||||
#endif
|
||||
mrb_int val = mrb_integer(x);
|
||||
const char *p = mrb_int_to_cstr(buf, sizeof(buf), val, base);
|
||||
mrb_assert(p != NULL);
|
||||
mrb_value str = mrb_str_new_cstr(mrb, p);
|
||||
@@ -2031,6 +2025,9 @@ cmpnum(mrb_state *mrb, mrb_value v1, mrb_value v2)
|
||||
if (mrb_bigint_p(v1)) {
|
||||
return mrb_bint_cmp(mrb, v1, v2);
|
||||
}
|
||||
if (mrb_bigint_p(v2)) {
|
||||
return mrb_bint_cmp(mrb, mrb_bint_new_int(mrb, mrb_integer(v1)), v2);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef MRB_NO_FLOAT
|
||||
@@ -2237,8 +2234,8 @@ mrb_init_numeric(mrb_state *mrb)
|
||||
mrb_define_method_id(mrb, integer, MRB_OPSYM(gt), num_gt, MRB_ARGS_REQ(1));
|
||||
mrb_define_method_id(mrb, integer, MRB_OPSYM(ge), num_ge, MRB_ARGS_REQ(1));
|
||||
|
||||
mrb_define_method_id(mrb, integer, MRB_SYM(to_i), int_to_i, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
|
||||
mrb_define_method_id(mrb, integer, MRB_SYM(to_int), int_to_i, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, integer, MRB_SYM(to_i), mrb_obj_itself, MRB_ARGS_NONE()); /* 15.2.8.3.24 */
|
||||
mrb_define_method_id(mrb, integer, MRB_SYM(to_int), mrb_obj_itself, MRB_ARGS_NONE());
|
||||
|
||||
mrb_define_method_id(mrb, integer, MRB_OPSYM(add), int_add, MRB_ARGS_REQ(1)); /* 15.2.8.3.1 */
|
||||
mrb_define_method_id(mrb, integer, MRB_OPSYM(sub), int_sub, MRB_ARGS_REQ(1)); /* 15.2.8.3.2 */
|
||||
@@ -2301,7 +2298,7 @@ mrb_init_numeric(mrb_state *mrb)
|
||||
mrb_define_method_id(mrb, fl, MRB_SYM(floor), flo_floor, MRB_ARGS_OPT(1)); /* 15.2.9.3.10 */
|
||||
mrb_define_method_id(mrb, fl, MRB_SYM_Q(infinite),flo_infinite_p, MRB_ARGS_NONE()); /* 15.2.9.3.11 */
|
||||
mrb_define_method_id(mrb, fl, MRB_SYM(round), flo_round, MRB_ARGS_OPT(1)); /* 15.2.9.3.12 */
|
||||
mrb_define_method_id(mrb, fl, MRB_SYM(to_f), flo_to_f, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
|
||||
mrb_define_method_id(mrb, fl, MRB_SYM(to_f), mrb_obj_itself, MRB_ARGS_NONE()); /* 15.2.9.3.13 */
|
||||
mrb_define_method_id(mrb, fl, MRB_SYM(to_i), flo_to_i, MRB_ARGS_NONE()); /* 15.2.9.3.14 */
|
||||
mrb_define_method_id(mrb, fl, MRB_SYM(truncate), flo_truncate, MRB_ARGS_OPT(1)); /* 15.2.9.3.15 */
|
||||
mrb_define_method_id(mrb, fl, MRB_SYM(divmod), flo_divmod, MRB_ARGS_REQ(1));
|
||||
|
||||
@@ -649,3 +649,9 @@ mrb_eql(mrb_state *mrb, mrb_value obj1, mrb_value obj2)
|
||||
if (mrb_class(mrb, obj1) != mrb_class(mrb, obj2)) return FALSE;
|
||||
return mrb_test(mrb_funcall_argv(mrb, obj1, MRB_SYM_Q(eql), 1, &obj2));
|
||||
}
|
||||
|
||||
MRB_API mrb_value
|
||||
mrb_obj_itself(mrb_state *mrb, mrb_value self)
|
||||
{
|
||||
return self;
|
||||
}
|
||||
|
||||
@@ -161,6 +161,9 @@ mrb_irep_free(mrb_state *mrb, mrb_irep *irep)
|
||||
}
|
||||
mrb_free(mrb, (void*)irep->lv);
|
||||
mrb_debug_info_free(mrb, irep->debug_info);
|
||||
#ifdef MRB_DEBUG
|
||||
memset(irep, -1, sizeof(*irep));
|
||||
#endif
|
||||
mrb_free(mrb, irep);
|
||||
}
|
||||
|
||||
|
||||
+302
-147
@@ -263,7 +263,138 @@ mrb_gc_free_str(mrb_state *mrb, struct RString *str)
|
||||
mrb_free(mrb, str->as.heap.ptr);
|
||||
}
|
||||
|
||||
#if defined(__i386) || defined(__i386__) || defined(_M_IX86) || \
|
||||
defined(__x86_64) || defined(__x86_64__) || defined(_M_AMD64) || \
|
||||
defined(__powerpc64__) || defined(__POWERPC__) || defined(__aarch64__) || \
|
||||
defined(__mc68020__)
|
||||
# define ALIGNED_WORD_ACCESS 0
|
||||
#else
|
||||
# define ALIGNED_WORD_ACCESS 1
|
||||
#endif
|
||||
|
||||
#ifdef MRB_UTF8_STRING
|
||||
|
||||
#define NOASCII(c) ((c) & 0x80)
|
||||
|
||||
#ifdef SIMPLE_SEARCH_NONASCII
|
||||
/* the naive implementation. define SIMPLE_SEARCH_NONASCII, */
|
||||
/* if you need it for any constraint (e.g. code size). */
|
||||
static const char*
|
||||
search_nonascii(const char* p, const char *e)
|
||||
{
|
||||
for (; p < e; ++p) {
|
||||
if (NOASCII(*p)) return p;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#elif defined(__SSE2__)
|
||||
# include <emmintrin.h>
|
||||
|
||||
static inline const char *
|
||||
search_nonascii(const char *p, const char *e)
|
||||
{
|
||||
if (sizeof(__m128i) < (size_t)(e - p)) {
|
||||
if (!_mm_movemask_epi8(_mm_loadu_si128((__m128i const*)p))) {
|
||||
const intptr_t lowbits = sizeof(__m128i) - 1;
|
||||
const __m128i *s, *t;
|
||||
s = (const __m128i*)(~lowbits & ((intptr_t)p + lowbits));
|
||||
t = (const __m128i*)(~lowbits & (intptr_t)e);
|
||||
for (; s < t; ++s) {
|
||||
if (_mm_movemask_epi8(_mm_load_si128(s))) break;
|
||||
}
|
||||
p = (const char *)s;
|
||||
}
|
||||
}
|
||||
switch (e - p) {
|
||||
default:
|
||||
case 15: if (NOASCII(*p)) return p; ++p;
|
||||
case 14: if (NOASCII(*p)) return p; ++p;
|
||||
case 13: if (NOASCII(*p)) return p; ++p;
|
||||
case 12: if (NOASCII(*p)) return p; ++p;
|
||||
case 11: if (NOASCII(*p)) return p; ++p;
|
||||
case 10: if (NOASCII(*p)) return p; ++p;
|
||||
case 9: if (NOASCII(*p)) return p; ++p;
|
||||
case 8: if (NOASCII(*p)) return p; ++p;
|
||||
case 7: if (NOASCII(*p)) return p; ++p;
|
||||
case 6: if (NOASCII(*p)) return p; ++p;
|
||||
case 5: if (NOASCII(*p)) return p; ++p;
|
||||
case 4: if (NOASCII(*p)) return p; ++p;
|
||||
case 3: if (NOASCII(*p)) return p; ++p;
|
||||
case 2: if (NOASCII(*p)) return p; ++p;
|
||||
case 1: if (NOASCII(*p)) return p; ++p;
|
||||
if (NOASCII(*p)) return p;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
#ifdef MRB_64BIT
|
||||
# define NONASCII_MASK 0x8080808080808080ULL
|
||||
#else /* MRB_32BIT */
|
||||
# define NONASCII_MASK 0x80808080UL
|
||||
#endif
|
||||
|
||||
static const char*
|
||||
search_nonascii(const char *p, const char *e)
|
||||
{
|
||||
if (e - p >= sizeof(void*)) {
|
||||
#if ALIGNED_WORD_ACCESS
|
||||
if ((uintptr_t)p % sizeof(void*)) {
|
||||
int l = sizeof(void*) - (uintptr_t)p % sizeof(void*);
|
||||
p += l;
|
||||
switch (l) {
|
||||
#ifdef MRB_64BIT
|
||||
case 7: if (p[-7]&0x80) return p-7;
|
||||
case 6: if (p[-6]&0x80) return p-6;
|
||||
case 5: if (p[-5]&0x80) return p-5;
|
||||
case 4: if (p[-4]&0x80) return p-4;
|
||||
#endif
|
||||
case 3: if (p[-3]&0x80) return p-3;
|
||||
case 2: if (p[-2]&0x80) return p-2;
|
||||
case 1: if (p[-1]&0x80) return p-1;
|
||||
case 0: break;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
const uintptr_t *s = (uintptr_t*)p;
|
||||
const uintptr_t *t = (uintptr_t*)(e - (sizeof(void*)-1));
|
||||
|
||||
for (;s < t; s++) {
|
||||
if (*s & NONASCII_MASK) {
|
||||
p = (const char*)s;
|
||||
if (NOASCII(p[0])) return p+0;
|
||||
if (NOASCII(p[1])) return p+1;
|
||||
if (NOASCII(p[2])) return p+2;
|
||||
if (NOASCII(p[3])) return p+3;
|
||||
#ifdef MRB_64BIT
|
||||
if (NOASCII(p[4])) return p+4;
|
||||
if (NOASCII(p[5])) return p+5;
|
||||
if (NOASCII(p[6])) return p+6;
|
||||
if (NOASCII(p[7])) return p+7;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (e - p) {
|
||||
default:
|
||||
#ifdef MRB_64BIT
|
||||
case 7: if (e[-7]&0x80) return e-7;
|
||||
case 6: if (e[-6]&0x80) return e-6;
|
||||
case 5: if (e[-5]&0x80) return e-5;
|
||||
case 4: if (e[-4]&0x80) return e-4;
|
||||
#endif
|
||||
case 3: if (e[-3]&0x80) return e-3;
|
||||
case 2: if (e[-2]&0x80) return e-2;
|
||||
case 1: if (e[-1]&0x80) return e-1;
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
#endif /* SIMPLE_SEARCH_NONASCII */
|
||||
|
||||
#define utf8_islead(c) ((unsigned char)((c)&0xc0) != 0x80)
|
||||
|
||||
extern const char mrb_utf8len_table[];
|
||||
@@ -278,7 +409,7 @@ mrb_utf8len(const char* p, const char* e)
|
||||
mrb_int len = mrb_utf8len_table[(unsigned char)p[0] >> 3];
|
||||
if (len > e - p) return 1;
|
||||
switch (len) {
|
||||
case 1:
|
||||
case 0:
|
||||
return 1;
|
||||
case 4:
|
||||
if (utf8_islead(p[3])) return 1;
|
||||
@@ -309,12 +440,12 @@ utf8_strlen(mrb_value str)
|
||||
struct RString *s = mrb_str_ptr(str);
|
||||
mrb_int byte_len = RSTR_LEN(s);
|
||||
|
||||
if (RSTR_ASCII_P(s)) {
|
||||
if (RSTR_SINGLE_BYTE_P(s)) {
|
||||
return byte_len;
|
||||
}
|
||||
else {
|
||||
mrb_int utf8_len = mrb_utf8_strlen(RSTR_PTR(s), byte_len);
|
||||
if (byte_len == utf8_len) RSTR_SET_ASCII_FLAG(s);
|
||||
if (byte_len == utf8_len) RSTR_SET_SINGLE_BYTE_FLAG(s);
|
||||
return utf8_len;
|
||||
}
|
||||
}
|
||||
@@ -325,33 +456,62 @@ utf8_strlen(mrb_value str)
|
||||
static mrb_int
|
||||
chars2bytes(mrb_value s, mrb_int off, mrb_int idx)
|
||||
{
|
||||
if (RSTR_ASCII_P(mrb_str_ptr(s))) {
|
||||
if (RSTR_SINGLE_BYTE_P(mrb_str_ptr(s))) {
|
||||
return idx;
|
||||
}
|
||||
else {
|
||||
mrb_int i, b, n;
|
||||
const char *p = RSTRING_PTR(s) + off;
|
||||
const char *e = RSTRING_END(s);
|
||||
|
||||
for (b=i=0; p<e && i<idx; i++) {
|
||||
n = mrb_utf8len(p, e);
|
||||
b += n;
|
||||
p += n;
|
||||
const char *p0 = RSTRING_PTR(s) + off;
|
||||
const char *p = p0;
|
||||
const char *e = RSTRING_END(s);
|
||||
mrb_int i = 0;
|
||||
|
||||
while (p<e && i<idx) {
|
||||
if ((*p & 0x80) == 0) {
|
||||
const char *np = search_nonascii(p, e);
|
||||
ptrdiff_t alen = np - p;
|
||||
if (idx < i+alen) {
|
||||
p += idx-i;
|
||||
i=idx;
|
||||
}
|
||||
else {
|
||||
p = np;
|
||||
i += alen;
|
||||
}
|
||||
}
|
||||
else {
|
||||
p += mrb_utf8len(p, e);
|
||||
i++;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
mrb_int len = (mrb_int)(p-p0);
|
||||
if (i<idx) len++;
|
||||
return len;
|
||||
}
|
||||
|
||||
/* map byte offset to character index */
|
||||
static mrb_int
|
||||
bytes2chars(char *p, mrb_int len, mrb_int bi)
|
||||
bytes2chars(mrb_value s, mrb_int bi)
|
||||
{
|
||||
const char *e = p + (size_t)len;
|
||||
const char *pivot = p + bi;
|
||||
mrb_int i;
|
||||
if (RSTR_SINGLE_BYTE_P(mrb_str_ptr(s))) {
|
||||
return bi;
|
||||
}
|
||||
|
||||
for (i = 0; p < pivot; i++) {
|
||||
p += mrb_utf8len(p, e);
|
||||
const char *p = RSTRING_PTR(s);
|
||||
const char *pivot = p + bi;
|
||||
mrb_int i = 0;
|
||||
|
||||
if (RSTRING_END(s) < pivot) return -1;
|
||||
while (p < pivot) {
|
||||
if ((*p & 0x80) == 0) {
|
||||
const char *np = search_nonascii(p, pivot);
|
||||
i += np - p;
|
||||
p = np;
|
||||
}
|
||||
else {
|
||||
p += mrb_utf8len(p, pivot);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
if (p != pivot) return -1;
|
||||
return i;
|
||||
@@ -380,135 +540,135 @@ char_backtrack(const char *ptr, const char *end)
|
||||
}
|
||||
|
||||
static mrb_int
|
||||
str_index_str_by_char_search(mrb_state *mrb, const char *p, const char *pend, const char *s, const mrb_int slen, mrb_int off)
|
||||
str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
|
||||
{
|
||||
/* Based on Quick Search algorithm (Boyer-Moore-Horspool algorithm) */
|
||||
const char *ptr = RSTRING_PTR(sub);
|
||||
mrb_int len = RSTRING_LEN(sub);
|
||||
|
||||
ptrdiff_t qstable[1 << CHAR_BIT];
|
||||
if (pos > 0) {
|
||||
pos = chars2bytes(str, 0, pos);
|
||||
}
|
||||
|
||||
/* Preprocessing */
|
||||
{
|
||||
mrb_int i;
|
||||
pos = mrb_str_index(mrb, str, ptr, len, pos);
|
||||
|
||||
for (i = 0; i < 1 << CHAR_BIT; i++) {
|
||||
qstable[i] = slen;
|
||||
}
|
||||
for (i = 0; i < slen; i++) {
|
||||
qstable[(unsigned char)s[i]] = slen - (i + 1);
|
||||
if (pos > 0) {
|
||||
pos = bytes2chars(str, pos);
|
||||
}
|
||||
return pos;
|
||||
}
|
||||
|
||||
#else
|
||||
#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s)
|
||||
#define chars2bytes(s, off, ci) (ci)
|
||||
#define bytes2chars(s, bi) (bi)
|
||||
#define char_adjust(beg, end, ptr) (ptr)
|
||||
#define char_backtrack(ptr, end) ((end) - 1)
|
||||
#define str_index_str_by_char(mrb, str, sub, pos) str_index_str((mrb), (str), (sub), (pos))
|
||||
#endif
|
||||
|
||||
/* memsearch_swar (SWAR stands for SIMD within a register) */
|
||||
/* See https://en.wikipedia.org/wiki/SWAR */
|
||||
/* The function is taken from http://0x80.pl/articles/simd-strfind.html */
|
||||
/* The original source code is under 2-clause BSD license; see LEGAL file. */
|
||||
/* The modifications:
|
||||
* port from C++ to C
|
||||
* returns mrb_int
|
||||
* remove alignment issue
|
||||
* support bigendian CPU
|
||||
* fixed potential buffer overflow
|
||||
*/
|
||||
static inline mrb_int
|
||||
memsearch_swar(const char *xs, mrb_int m, const char *ys, mrb_int n)
|
||||
{
|
||||
#ifdef MRB_64BIT
|
||||
#define bitint uint64_t
|
||||
#define MASK1 0x0101010101010101ull
|
||||
#define MASK2 0x7f7f7f7f7f7f7f7full
|
||||
#define MASK3 0x8080808080808080ull
|
||||
#else
|
||||
#define bitint uint32_t
|
||||
#define MASK1 0x01010101ul
|
||||
#define MASK2 0x7f7f7f7ful
|
||||
#define MASK3 0x80808080ul
|
||||
#endif
|
||||
#if defined(MRB_ENDIAN_BIG)
|
||||
#ifdef MRB_64BIT
|
||||
#define MASK4 0x8000000000000000ull
|
||||
#else
|
||||
#define MASK4 0x80000000ul
|
||||
#endif
|
||||
#else
|
||||
#define MASK4 0x80
|
||||
#endif
|
||||
|
||||
const bitint first = MASK1 * (uint8_t)xs[0];
|
||||
const bitint last = MASK1 * (uint8_t)xs[m-1];
|
||||
|
||||
const char *s0 = ys;
|
||||
const char *s1 = ys+m-1;
|
||||
|
||||
const mrb_int lim = n - m - (mrb_int)sizeof(bitint);
|
||||
mrb_int i;
|
||||
|
||||
for (i=0; i < lim; i+=sizeof(bitint)) {
|
||||
bitint t0, t1;
|
||||
|
||||
memcpy(&t0, s0+i, sizeof(bitint));
|
||||
memcpy(&t1, s1+i, sizeof(bitint));
|
||||
|
||||
const bitint eq = (t0 ^ first) | (t1 ^ last);
|
||||
bitint zeros = ((~eq & MASK2) + MASK1) & (~eq & MASK3);
|
||||
|
||||
|
||||
for (size_t j = 0; zeros; j++) {
|
||||
if (zeros & MASK4) {
|
||||
const mrb_int idx = i + j;
|
||||
const char* p = s0 + idx + 1;
|
||||
if (memcmp(p, xs + 1, m - 2) == 0) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(MRB_ENDIAN_BIG)
|
||||
zeros <<= 8;
|
||||
#else
|
||||
zeros >>= 8;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
/* Searching */
|
||||
while (p < pend && pend - p >= slen) {
|
||||
const char *pivot;
|
||||
|
||||
if (memcmp(p, s, slen) == 0) {
|
||||
return off;
|
||||
if (i+m < n) {
|
||||
const char *p = s0;
|
||||
const char *e = ys + n;
|
||||
for (;p<e;) {
|
||||
size_t len = e - p;
|
||||
p = (const char*)memchr(p, *xs, len);
|
||||
if (p == NULL || (e - p) < m) break;
|
||||
if (memcmp(p+1, xs+1, m-1) == 0) return (mrb_int)(p - ys);
|
||||
p++;
|
||||
}
|
||||
|
||||
pivot = p + qstable[(unsigned char)p[slen - 1]];
|
||||
if (pivot >= pend || pivot < p /* overflowed */) { return -1; }
|
||||
|
||||
do {
|
||||
p += mrb_utf8len(p, pend);
|
||||
off++;
|
||||
} while (p < pivot);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static mrb_int
|
||||
str_index_str_by_char(mrb_state *mrb, mrb_value str, mrb_value sub, mrb_int pos)
|
||||
mrb_memsearch(const char *x, mrb_int m, const char *y, mrb_int n)
|
||||
{
|
||||
const char *p = RSTRING_PTR(str);
|
||||
const char *pend = p + RSTRING_LEN(str);
|
||||
const char *s = RSTRING_PTR(sub);
|
||||
const mrb_int slen = RSTRING_LEN(sub);
|
||||
mrb_int off = pos;
|
||||
|
||||
for (; pos > 0; pos --) {
|
||||
if (pend - p < 1) { return -1; }
|
||||
p += mrb_utf8len(p, pend);
|
||||
}
|
||||
|
||||
if (slen < 1) { return off; }
|
||||
|
||||
return str_index_str_by_char_search(mrb, p, pend, s, slen, off);
|
||||
}
|
||||
|
||||
#define BYTES_ALIGN_CHECK(pos) if (pos < 0) return mrb_nil_value();
|
||||
#else
|
||||
#define RSTRING_CHAR_LEN(s) RSTRING_LEN(s)
|
||||
#define chars2bytes(p, off, ci) (ci)
|
||||
#define bytes2chars(p, end, bi) (bi)
|
||||
#define char_adjust(beg, end, ptr) (ptr)
|
||||
#define char_backtrack(ptr, end) ((end) - 1)
|
||||
#define BYTES_ALIGN_CHECK(pos)
|
||||
#define str_index_str_by_char(mrb, str, sub, pos) str_index_str(mrb, str, sub, pos)
|
||||
#endif
|
||||
|
||||
#ifndef MRB_QS_SHORT_STRING_LENGTH
|
||||
#define MRB_QS_SHORT_STRING_LENGTH 2048
|
||||
#endif
|
||||
|
||||
static inline mrb_int
|
||||
mrb_memsearch_qs(const unsigned char *xs, mrb_int m, const unsigned char *ys, mrb_int n)
|
||||
{
|
||||
if (n + m < MRB_QS_SHORT_STRING_LENGTH) {
|
||||
const unsigned char *y = ys;
|
||||
const unsigned char *ye = ys+n-m+1;
|
||||
|
||||
for (;;) {
|
||||
y = (const unsigned char*)memchr(y, xs[0], (size_t)(ye-y));
|
||||
if (y == NULL) return -1;
|
||||
if (memcmp(xs, y, m) == 0) {
|
||||
return (mrb_int)(y - ys);
|
||||
}
|
||||
y++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
else {
|
||||
const unsigned char *x = xs, *xe = xs + m;
|
||||
const unsigned char *y = ys;
|
||||
ptrdiff_t qstable[256];
|
||||
|
||||
/* Preprocessing */
|
||||
for (int i = 0; i < 256; i++)
|
||||
qstable[i] = m + 1;
|
||||
for (; x < xe; x++)
|
||||
qstable[*x] = xe - x;
|
||||
/* Searching */
|
||||
for (; y + m <= ys + n; y += *(qstable + y[m])) {
|
||||
if (*xs == *y && memcmp(xs, y, m) == 0)
|
||||
return (mrb_int)(y - ys);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
static mrb_int
|
||||
mrb_memsearch(const void *x0, mrb_int m, const void *y0, mrb_int n)
|
||||
{
|
||||
const unsigned char *x = (const unsigned char*)x0, *y = (const unsigned char*)y0;
|
||||
|
||||
if (m > n) return -1;
|
||||
else if (m == n) {
|
||||
return memcmp(x0, y0, m) == 0 ? 0 : -1;
|
||||
return memcmp(x, y, m) == 0 ? 0 : -1;
|
||||
}
|
||||
else if (m < 1) {
|
||||
return 0;
|
||||
}
|
||||
else if (m == 1) {
|
||||
const unsigned char *ys = (const unsigned char*)memchr(y, *x, n);
|
||||
const char *p = (const char*)memchr(y, *x, n);
|
||||
|
||||
if (ys)
|
||||
return (mrb_int)(ys - y);
|
||||
else
|
||||
return -1;
|
||||
if (p) return (mrb_int)(p - y);
|
||||
return -1;
|
||||
}
|
||||
return mrb_memsearch_qs((const unsigned char*)x0, m, (const unsigned char*)y0, n);
|
||||
return memsearch_swar(x, m, y, n);
|
||||
}
|
||||
|
||||
static void
|
||||
@@ -551,21 +711,16 @@ mrb_str_byte_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
|
||||
s->as.heap.ptr += (mrb_ssize)beg;
|
||||
s->as.heap.len = (mrb_ssize)len;
|
||||
}
|
||||
RSTR_COPY_ASCII_FLAG(s, orig);
|
||||
RSTR_COPY_SINGLE_BYTE_FLAG(s, orig);
|
||||
return mrb_obj_value(s);
|
||||
}
|
||||
|
||||
static void
|
||||
str_range_to_bytes(mrb_value str, mrb_int *pos, mrb_int *len)
|
||||
{
|
||||
*pos = chars2bytes(str, 0, *pos);
|
||||
*len = chars2bytes(str, *pos, *len);
|
||||
}
|
||||
#ifdef MRB_UTF8_STRING
|
||||
static inline mrb_value
|
||||
str_subseq(mrb_state *mrb, mrb_value str, mrb_int beg, mrb_int len)
|
||||
{
|
||||
str_range_to_bytes(str, &beg, &len);
|
||||
beg = chars2bytes(str, 0, beg);
|
||||
len = chars2bytes(str, beg, len);
|
||||
return mrb_str_byte_subseq(mrb, str, beg, len);
|
||||
}
|
||||
#else
|
||||
@@ -639,7 +794,7 @@ str_replace(mrb_state *mrb, struct RString *s1, struct RString *s2)
|
||||
|
||||
mrb_check_frozen(mrb, s1);
|
||||
if (s1 == s2) return mrb_obj_value(s1);
|
||||
RSTR_COPY_ASCII_FLAG(s1, s2);
|
||||
RSTR_COPY_SINGLE_BYTE_FLAG(s1, s2);
|
||||
if (RSTR_SHARED_P(s1)) {
|
||||
str_decref(mrb, s1->as.heap.aux.shared);
|
||||
}
|
||||
@@ -765,7 +920,7 @@ MRB_API void
|
||||
mrb_str_modify(mrb_state *mrb, struct RString *s)
|
||||
{
|
||||
mrb_str_modify_keep_ascii(mrb, s);
|
||||
RSTR_UNSET_ASCII_FLAG(s);
|
||||
RSTR_UNSET_SINGLE_BYTE_FLAG(s);
|
||||
}
|
||||
|
||||
MRB_API mrb_value
|
||||
@@ -903,7 +1058,7 @@ mrb_str_times(mrb_state *mrb, mrb_value self)
|
||||
memcpy(p + n, p, len-n);
|
||||
}
|
||||
p[RSTR_LEN(str2)] = '\0';
|
||||
RSTR_COPY_ASCII_FLAG(str2, mrb_str_ptr(self));
|
||||
RSTR_COPY_SINGLE_BYTE_FLAG(str2, mrb_str_ptr(self));
|
||||
|
||||
return mrb_obj_value(str2);
|
||||
}
|
||||
@@ -1213,7 +1368,7 @@ str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect)
|
||||
char buf[4]; /* `\x??` or UTF-8 character */
|
||||
mrb_value result = mrb_str_new_lit(mrb, "\"");
|
||||
#ifdef MRB_UTF8_STRING
|
||||
uint32_t ascii_flag = MRB_STR_ASCII;
|
||||
uint32_t sb_flag = MRB_STR_SINGLE_BYTE;
|
||||
#endif
|
||||
|
||||
p = RSTRING_PTR(str); pend = RSTRING_END(str);
|
||||
@@ -1225,7 +1380,7 @@ str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect)
|
||||
if (clen > 1) {
|
||||
mrb_str_cat(mrb, result, p, clen);
|
||||
p += clen-1;
|
||||
ascii_flag = 0;
|
||||
sb_flag = 0;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
@@ -1267,11 +1422,11 @@ str_escape(mrb_state *mrb, mrb_value str, mrb_bool inspect)
|
||||
mrb_str_cat_lit(mrb, result, "\"");
|
||||
#ifdef MRB_UTF8_STRING
|
||||
if (inspect) {
|
||||
mrb_str_ptr(str)->flags |= ascii_flag;
|
||||
mrb_str_ptr(result)->flags |= ascii_flag;
|
||||
mrb_str_ptr(str)->flags |= sb_flag;
|
||||
mrb_str_ptr(result)->flags |= sb_flag;
|
||||
}
|
||||
else {
|
||||
RSTR_SET_ASCII_FLAG(mrb_str_ptr(result));
|
||||
RSTR_SET_SINGLE_BYTE_FLAG(mrb_str_ptr(result));
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -1297,7 +1452,8 @@ mrb_str_aset(mrb_state *mrb, mrb_value str, mrb_value indx, mrb_value alen, mrb_
|
||||
if (beg < 0 || beg > charlen) { str_out_of_index(mrb, indx); }
|
||||
/* fall through */
|
||||
case STR_CHAR_RANGE_CORRECTED:
|
||||
str_range_to_bytes(str, &beg, &len);
|
||||
beg = chars2bytes(str, 0, beg);
|
||||
len = chars2bytes(str, beg, len);
|
||||
/* fall through */
|
||||
case STR_BYTE_RANGE_CORRECTED:
|
||||
if (mrb_int_add_overflow(beg, len, &len)) {
|
||||
@@ -1791,7 +1947,7 @@ mrb_str_byteindex_m(mrb_state *mrb, mrb_value str)
|
||||
static mrb_value
|
||||
mrb_str_index_m(mrb_state *mrb, mrb_value str)
|
||||
{
|
||||
if (RSTR_ASCII_P(mrb_str_ptr(str))) {
|
||||
if (RSTR_SINGLE_BYTE_P(mrb_str_ptr(str))) {
|
||||
return mrb_str_byteindex_m(mrb, str);
|
||||
}
|
||||
|
||||
@@ -2062,7 +2218,7 @@ mrb_str_byterindex_m(mrb_state *mrb, mrb_value str)
|
||||
static mrb_value
|
||||
mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
|
||||
{
|
||||
if (RSTR_ASCII_P(mrb_str_ptr(str))) {
|
||||
if (RSTR_SINGLE_BYTE_P(mrb_str_ptr(str))) {
|
||||
return mrb_str_byterindex_m(mrb, str);
|
||||
}
|
||||
|
||||
@@ -2070,8 +2226,7 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
|
||||
mrb_int pos;
|
||||
|
||||
if (mrb_get_args(mrb, "S|i", &sub, &pos) == 1) {
|
||||
pos = RSTRING_CHAR_LEN(str);
|
||||
pos = chars2bytes(str, 0, pos);
|
||||
pos = RSTRING_LEN(str);
|
||||
}
|
||||
else if (pos >= 0) {
|
||||
pos = chars2bytes(str, 0, pos);
|
||||
@@ -2087,8 +2242,8 @@ mrb_str_rindex_m(mrb_state *mrb, mrb_value str)
|
||||
}
|
||||
pos = str_rindex(mrb, str, sub, pos);
|
||||
if (pos >= 0) {
|
||||
pos = bytes2chars(RSTRING_PTR(str), RSTRING_LEN(str), pos);
|
||||
BYTES_ALIGN_CHECK(pos);
|
||||
pos = bytes2chars(str, pos);
|
||||
if (pos < 0) return mrb_nil_value();
|
||||
return mrb_int_value(mrb, pos);
|
||||
}
|
||||
return mrb_nil_value();
|
||||
|
||||
+3
-7
@@ -441,6 +441,8 @@ sym_name(mrb_state *mrb, mrb_value vsym)
|
||||
|
||||
/* 15.2.11.3.4 */
|
||||
/*
|
||||
* Document-method: Symbol#to_sym
|
||||
*
|
||||
* call-seq:
|
||||
* sym.to_sym -> sym
|
||||
* sym.intern -> sym
|
||||
@@ -450,12 +452,6 @@ sym_name(mrb_state *mrb, mrb_value vsym)
|
||||
* in this case.
|
||||
*/
|
||||
|
||||
static mrb_value
|
||||
sym_to_sym(mrb_state *mrb, mrb_value sym)
|
||||
{
|
||||
return sym;
|
||||
}
|
||||
|
||||
/* 15.2.11.3.5(x) */
|
||||
/*
|
||||
* call-seq:
|
||||
@@ -696,7 +692,7 @@ mrb_init_symbol(mrb_state *mrb)
|
||||
|
||||
mrb_define_method_id(mrb, sym, MRB_SYM(to_s), sym_to_s, MRB_ARGS_NONE()); /* 15.2.11.3.3 */
|
||||
mrb_define_method_id(mrb, sym, MRB_SYM(name), sym_name, MRB_ARGS_NONE());
|
||||
mrb_define_method_id(mrb, sym, MRB_SYM(to_sym), sym_to_sym, MRB_ARGS_NONE()); /* 15.2.11.3.4 */
|
||||
mrb_define_method_id(mrb, sym, MRB_SYM(to_sym), mrb_obj_itself, MRB_ARGS_NONE()); /* 15.2.11.3.4 */
|
||||
mrb_define_method_id(mrb, sym, MRB_SYM(inspect), sym_inspect, MRB_ARGS_NONE()); /* 15.2.11.3.5(x) */
|
||||
mrb_define_method_id(mrb, sym, MRB_OPSYM(cmp), sym_cmp, MRB_ARGS_REQ(1));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user