2000-05-01 13:42:38 +04:00
|
|
|
/**********************************************************************
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
range.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
created at: Thu Aug 19 17:46:47 JST 1993
|
|
|
|
|
* encoding.c: provide basic features for M17N.
* parse.y: encoding aware parsing.
* parse.y (pragma_encoding): encoding specification pragma.
* parse.y (rb_intern3): encoding specified symbols.
* string.c (rb_str_length): length based on characters.
for older behavior, bytesize method added.
* string.c (rb_str_index_m): index based on characters. rindex as
well.
* string.c (succ_char): encoding aware succeeding string.
* string.c (rb_str_reverse): reverse based on characters.
* string.c (rb_str_inspect): encoding aware string description.
* string.c (rb_str_upcase_bang): encoding aware case conversion.
downcase, capitalize, swapcase as well.
* string.c (rb_str_tr_bang): tr based on characters. delete,
squeeze, tr_s, count as well.
* string.c (rb_str_split_m): split based on characters.
* string.c (rb_str_each_line): encoding aware each_line.
* string.c (rb_str_each_char): added. iteration based on
characters.
* string.c (rb_str_strip_bang): encoding aware whitespace
stripping. lstrip, rstrip as well.
* string.c (rb_str_justify): encoding aware justifying (ljust,
rjust, center).
* string.c (str_encoding): get encoding attribute from a string.
* re.c (rb_reg_initialize): encoding aware regular expression
* sprintf.c (rb_str_format): formatting (i.e. length count) based
on characters.
* io.c (rb_io_getc): getc to return one-character string.
for older behavior, getbyte method added.
* ext/stringio/stringio.c (strio_getc): ditto.
* io.c (rb_io_ungetc): allow pushing arbitrary string at the
current reading point.
* ext/stringio/stringio.c (strio_ungetc): ditto.
* ext/strscan/strscan.c: encoding support.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13261 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-08-25 07:29:39 +04:00
|
|
|
Copyright (C) 1993-2007 Yukihiro Matsumoto
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2000-05-01 13:42:38 +04:00
|
|
|
**********************************************************************/
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2020-05-08 12:31:09 +03:00
|
|
|
#include "ruby/internal/config.h"
|
2019-12-04 11:16:30 +03:00
|
|
|
|
2019-01-06 03:46:36 +03:00
|
|
|
#include <assert.h>
|
2019-12-04 11:16:30 +03:00
|
|
|
#include <math.h>
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2012-11-14 19:53:50 +04:00
|
|
|
#ifdef HAVE_FLOAT_H
|
|
|
|
#include <float.h>
|
|
|
|
#endif
|
2019-12-04 11:16:30 +03:00
|
|
|
|
|
|
|
#include "id.h"
|
|
|
|
#include "internal.h"
|
|
|
|
#include "internal/array.h"
|
|
|
|
#include "internal/compar.h"
|
|
|
|
#include "internal/enum.h"
|
|
|
|
#include "internal/enumerator.h"
|
|
|
|
#include "internal/error.h"
|
|
|
|
#include "internal/numeric.h"
|
|
|
|
#include "internal/range.h"
|
2012-11-14 19:53:50 +04:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
VALUE rb_cRange;
|
2018-04-19 18:19:00 +03:00
|
|
|
static ID id_beg, id_end, id_excl;
|
2015-05-02 01:39:14 +03:00
|
|
|
#define id_cmp idCmp
|
|
|
|
#define id_succ idSucc
|
2020-07-04 20:12:02 +03:00
|
|
|
#define id_min idMin
|
|
|
|
#define id_max idMax
|
1999-08-13 09:45:20 +04:00
|
|
|
|
2015-05-15 12:05:57 +03:00
|
|
|
static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
|
|
|
|
|
2013-10-25 09:18:26 +04:00
|
|
|
#define RANGE_SET_BEG(r, v) (RSTRUCT_SET(r, 0, v))
|
|
|
|
#define RANGE_SET_END(r, v) (RSTRUCT_SET(r, 1, v))
|
|
|
|
#define RANGE_SET_EXCL(r, v) (RSTRUCT_SET(r, 2, v))
|
2013-10-25 10:57:20 +04:00
|
|
|
#define RBOOL(v) ((v) ? Qtrue : Qfalse)
|
2007-09-08 19:07:18 +04:00
|
|
|
|
|
|
|
#define EXCL(r) RTEST(RANGE_EXCL(r))
|
|
|
|
|
2000-02-29 11:05:32 +03:00
|
|
|
static void
|
2013-10-25 10:57:20 +04:00
|
|
|
range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2019-04-03 11:11:41 +03:00
|
|
|
if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) {
|
2005-08-14 19:39:39 +04:00
|
|
|
VALUE v;
|
|
|
|
|
2017-04-25 14:42:43 +03:00
|
|
|
v = rb_funcall(beg, id_cmp, 1, end);
|
2006-12-31 18:02:22 +03:00
|
|
|
if (NIL_P(v))
|
2017-04-25 14:42:43 +03:00
|
|
|
rb_raise(rb_eArgError, "bad value for range");
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2013-10-25 10:57:20 +04:00
|
|
|
RANGE_SET_EXCL(range, exclude_end);
|
2013-10-25 09:18:26 +04:00
|
|
|
RANGE_SET_BEG(range, beg);
|
2018-06-13 14:00:28 +03:00
|
|
|
RANGE_SET_END(range, end);
|
2020-09-25 12:05:55 +03:00
|
|
|
|
|
|
|
if (CLASS_OF(range) == rb_cRange) {
|
|
|
|
rb_obj_freeze(range);
|
|
|
|
}
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2018-06-13 14:00:28 +03:00
|
|
|
rb_range_new(VALUE beg, VALUE end, int exclude_end)
|
1999-08-13 09:45:20 +04:00
|
|
|
{
|
2002-06-11 11:02:23 +04:00
|
|
|
VALUE range = rb_obj_alloc(rb_cRange);
|
2000-02-29 11:05:32 +03:00
|
|
|
|
2018-06-13 14:00:28 +03:00
|
|
|
range_init(range, beg, end, RBOOL(exclude_end));
|
2002-06-11 11:02:23 +04:00
|
|
|
return range;
|
1999-08-13 09:45:20 +04:00
|
|
|
}
|
|
|
|
|
2013-10-26 14:08:02 +04:00
|
|
|
static void
|
|
|
|
range_modify(VALUE range)
|
|
|
|
{
|
2016-11-10 13:39:51 +03:00
|
|
|
rb_check_frozen(range);
|
2013-10-26 14:08:02 +04:00
|
|
|
/* Ranges are immutable, so that they should be initialized only once. */
|
|
|
|
if (RANGE_EXCL(range) != Qnil) {
|
2015-10-28 09:24:12 +03:00
|
|
|
rb_name_err_raise("`initialize' called twice", range, ID2SYM(idInitialize));
|
2013-10-26 14:08:02 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-24 07:29:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2011-12-06 03:36:53 +04:00
|
|
|
* Range.new(begin, end, exclude_end=false) -> rng
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Constructs a range using the given +begin+ and +end+. If the +exclude_end+
|
2018-07-08 22:30:19 +03:00
|
|
|
* parameter is omitted or is <code>false</code>, the range will include
|
2003-12-24 07:29:32 +03:00
|
|
|
* the end object; otherwise, it will be excluded.
|
|
|
|
*/
|
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_initialize(int argc, VALUE *argv, VALUE range)
|
1999-08-13 09:45:20 +04:00
|
|
|
{
|
2001-02-02 14:38:20 +03:00
|
|
|
VALUE beg, end, flags;
|
2009-02-22 17:23:33 +03:00
|
|
|
|
2001-02-02 14:38:20 +03:00
|
|
|
rb_scan_args(argc, argv, "21", &beg, &end, &flags);
|
2013-10-26 14:08:02 +04:00
|
|
|
range_modify(range);
|
2013-10-25 10:57:20 +04:00
|
|
|
range_init(range, beg, end, RBOOL(RTEST(flags)));
|
2000-02-29 11:05:32 +03:00
|
|
|
return Qnil;
|
1999-08-13 09:45:20 +04:00
|
|
|
}
|
|
|
|
|
2013-10-26 14:08:02 +04:00
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
range_initialize_copy(VALUE range, VALUE orig)
|
|
|
|
{
|
|
|
|
range_modify(range);
|
|
|
|
rb_struct_init_copy(range, orig);
|
|
|
|
return range;
|
|
|
|
}
|
2003-12-24 07:29:32 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.exclude_end? -> true or false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns <code>true</code> if the range excludes its end value.
|
|
|
|
*
|
|
|
|
* (1..5).exclude_end? #=> false
|
|
|
|
* (1...5).exclude_end? #=> true
|
2003-12-24 07:29:32 +03:00
|
|
|
*/
|
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_exclude_end_p(VALUE range)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2002-07-30 14:22:32 +04:00
|
|
|
return EXCL(range) ? Qtrue : Qfalse;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2009-09-20 06:14:02 +04:00
|
|
|
static VALUE
|
|
|
|
recursive_equal(VALUE range, VALUE obj, int recur)
|
|
|
|
{
|
|
|
|
if (recur) return Qtrue; /* Subtle! */
|
|
|
|
if (!rb_equal(RANGE_BEG(range), RANGE_BEG(obj)))
|
|
|
|
return Qfalse;
|
|
|
|
if (!rb_equal(RANGE_END(range), RANGE_END(obj)))
|
|
|
|
return Qfalse;
|
|
|
|
|
|
|
|
if (EXCL(range) != EXCL(obj))
|
|
|
|
return Qfalse;
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
2003-12-24 07:29:32 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng == obj -> true or false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns <code>true</code> only if +obj+ is a Range, has equivalent
|
|
|
|
* begin and end items (by comparing them with <code>==</code>), and has
|
|
|
|
* the same #exclude_end? setting as the range.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
* (0..2) == (0..2) #=> true
|
|
|
|
* (0..2) == Range.new(0,2) #=> true
|
|
|
|
* (0..2) == (0...2) #=> false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
*/
|
|
|
|
|
2000-11-27 12:23:38 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_eq(VALUE range, VALUE obj)
|
2000-11-27 12:23:38 +03:00
|
|
|
{
|
2006-12-31 18:02:22 +03:00
|
|
|
if (range == obj)
|
|
|
|
return Qtrue;
|
2009-08-05 09:01:12 +04:00
|
|
|
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
2002-09-03 09:20:14 +04:00
|
|
|
return Qfalse;
|
2000-11-27 12:23:38 +03:00
|
|
|
|
2009-09-20 06:14:02 +04:00
|
|
|
return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
|
2000-11-27 12:23:38 +03:00
|
|
|
}
|
|
|
|
|
2015-05-15 12:06:18 +03:00
|
|
|
/* compares _a_ and _b_ and returns:
|
|
|
|
* < 0: a < b
|
|
|
|
* = 0: a = b
|
2015-05-15 15:39:56 +03:00
|
|
|
* > 0: a > b or non-comparable
|
2015-05-15 12:06:18 +03:00
|
|
|
*/
|
2001-05-30 13:12:34 +04:00
|
|
|
static int
|
2015-05-15 12:06:18 +03:00
|
|
|
r_less(VALUE a, VALUE b)
|
2001-05-30 13:12:34 +04:00
|
|
|
{
|
|
|
|
VALUE r = rb_funcall(a, id_cmp, 1, b);
|
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
if (NIL_P(r))
|
2015-05-15 12:06:18 +03:00
|
|
|
return INT_MAX;
|
|
|
|
return rb_cmpint(r, a, b);
|
2001-05-30 13:12:34 +04:00
|
|
|
}
|
|
|
|
|
2009-09-20 06:14:02 +04:00
|
|
|
static VALUE
|
|
|
|
recursive_eql(VALUE range, VALUE obj, int recur)
|
|
|
|
{
|
|
|
|
if (recur) return Qtrue; /* Subtle! */
|
|
|
|
if (!rb_eql(RANGE_BEG(range), RANGE_BEG(obj)))
|
|
|
|
return Qfalse;
|
|
|
|
if (!rb_eql(RANGE_END(range), RANGE_END(obj)))
|
|
|
|
return Qfalse;
|
|
|
|
|
|
|
|
if (EXCL(range) != EXCL(obj))
|
|
|
|
return Qfalse;
|
|
|
|
return Qtrue;
|
|
|
|
}
|
|
|
|
|
2003-12-24 07:29:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.eql?(obj) -> true or false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns <code>true</code> only if +obj+ is a Range, has equivalent
|
|
|
|
* begin and end items (by comparing them with <code>eql?</code>),
|
|
|
|
* and has the same #exclude_end? setting as the range.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2009-05-07 08:58:54 +04:00
|
|
|
* (0..2).eql?(0..2) #=> true
|
|
|
|
* (0..2).eql?(Range.new(0,2)) #=> true
|
|
|
|
* (0..2).eql?(0...2) #=> false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
*/
|
|
|
|
|
2001-11-08 12:21:59 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_eql(VALUE range, VALUE obj)
|
2001-11-08 12:21:59 +03:00
|
|
|
{
|
2006-12-31 18:02:22 +03:00
|
|
|
if (range == obj)
|
|
|
|
return Qtrue;
|
2009-08-05 09:01:12 +04:00
|
|
|
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
2002-09-03 09:20:14 +04:00
|
|
|
return Qfalse;
|
2009-09-20 06:14:02 +04:00
|
|
|
return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
|
2001-11-08 12:21:59 +03:00
|
|
|
}
|
|
|
|
|
2009-07-17 13:28:46 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2016-09-08 07:57:49 +03:00
|
|
|
* rng.hash -> integer
|
2009-07-17 13:28:46 +04:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Compute a hash-code for this range. Two ranges with equal
|
|
|
|
* begin and end points (using <code>eql?</code>), and the same
|
|
|
|
* #exclude_end? value will generate the same hash-code.
|
2014-03-14 05:27:43 +04:00
|
|
|
*
|
|
|
|
* See also Object#hash.
|
2009-07-17 13:28:46 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_hash(VALUE range)
|
|
|
|
{
|
2013-12-03 17:18:30 +04:00
|
|
|
st_index_t hash = EXCL(range);
|
|
|
|
VALUE v;
|
|
|
|
|
|
|
|
hash = rb_hash_start(hash);
|
|
|
|
v = rb_hash(RANGE_BEG(range));
|
|
|
|
hash = rb_hash_uint(hash, NUM2LONG(v));
|
|
|
|
v = rb_hash(RANGE_END(range));
|
|
|
|
hash = rb_hash_uint(hash, NUM2LONG(v));
|
|
|
|
hash = rb_hash_uint(hash, EXCL(range) << 24);
|
|
|
|
hash = rb_hash_end(hash);
|
|
|
|
|
2019-04-08 06:26:29 +03:00
|
|
|
return ST2FIX(hash);
|
2009-07-17 13:28:46 +04:00
|
|
|
}
|
|
|
|
|
2002-05-30 10:12:29 +04:00
|
|
|
static void
|
2018-04-28 14:16:54 +03:00
|
|
|
range_each_func(VALUE range, int (*func)(VALUE, VALUE), VALUE arg)
|
2002-05-30 10:12:29 +04:00
|
|
|
{
|
2004-05-14 20:39:15 +04:00
|
|
|
int c;
|
2008-04-06 21:11:50 +04:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
VALUE e = RANGE_END(range);
|
2008-04-07 07:15:26 +04:00
|
|
|
VALUE v = b;
|
2004-05-14 20:39:15 +04:00
|
|
|
|
2002-05-30 10:12:29 +04:00
|
|
|
if (EXCL(range)) {
|
2015-05-15 12:06:18 +03:00
|
|
|
while (r_less(v, e) < 0) {
|
2018-04-28 14:16:54 +03:00
|
|
|
if ((*func)(v, arg)) break;
|
2015-02-16 07:08:52 +03:00
|
|
|
v = rb_funcallv(v, id_succ, 0, 0);
|
2002-05-30 10:12:29 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-05-15 12:06:18 +03:00
|
|
|
while ((c = r_less(v, e)) <= 0) {
|
2018-08-20 18:33:59 +03:00
|
|
|
if ((*func)(v, arg)) break;
|
2015-05-15 12:06:18 +03:00
|
|
|
if (!c) break;
|
2015-02-16 07:08:52 +03:00
|
|
|
v = rb_funcallv(v, id_succ, 0, 0);
|
2002-05-30 10:12:29 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-28 14:16:54 +03:00
|
|
|
static int
|
|
|
|
sym_step_i(VALUE i, VALUE arg)
|
2009-08-17 21:00:47 +04:00
|
|
|
{
|
2013-11-29 06:26:48 +04:00
|
|
|
VALUE *iter = (VALUE *)arg;
|
2009-08-17 21:00:47 +04:00
|
|
|
|
|
|
|
if (FIXNUM_P(iter[0])) {
|
|
|
|
iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
|
|
|
|
}
|
|
|
|
if (iter[0] == INT2FIX(0)) {
|
|
|
|
rb_yield(rb_str_intern(i));
|
|
|
|
iter[0] = iter[1];
|
|
|
|
}
|
2018-04-28 14:16:54 +03:00
|
|
|
return 0;
|
2009-08-17 21:00:47 +04:00
|
|
|
}
|
|
|
|
|
2018-04-28 14:16:54 +03:00
|
|
|
static int
|
|
|
|
step_i(VALUE i, VALUE arg)
|
2004-10-06 11:40:06 +04:00
|
|
|
{
|
2013-11-29 06:26:48 +04:00
|
|
|
VALUE *iter = (VALUE *)arg;
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
|
2007-12-05 09:15:23 +03:00
|
|
|
if (FIXNUM_P(iter[0])) {
|
|
|
|
iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
|
|
|
|
}
|
|
|
|
else {
|
2008-01-29 16:27:51 +03:00
|
|
|
iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
|
2007-12-05 09:15:23 +03:00
|
|
|
}
|
|
|
|
if (iter[0] == INT2FIX(0)) {
|
2004-10-06 11:40:06 +04:00
|
|
|
rb_yield(i);
|
|
|
|
iter[0] = iter[1];
|
|
|
|
}
|
2018-04-28 14:16:54 +03:00
|
|
|
return 0;
|
2004-10-06 11:40:06 +04:00
|
|
|
}
|
|
|
|
|
2009-09-30 12:32:43 +04:00
|
|
|
static int
|
2009-10-02 19:31:05 +04:00
|
|
|
discrete_object_p(VALUE obj)
|
2009-09-30 12:32:43 +04:00
|
|
|
{
|
2009-10-02 19:31:05 +04:00
|
|
|
if (rb_obj_is_kind_of(obj, rb_cTime)) return FALSE; /* until Time#succ removed */
|
|
|
|
return rb_respond_to(obj, id_succ);
|
2009-09-30 12:32:43 +04:00
|
|
|
}
|
|
|
|
|
2015-05-03 04:02:15 +03:00
|
|
|
static int
|
|
|
|
linear_object_p(VALUE obj)
|
|
|
|
{
|
|
|
|
if (FIXNUM_P(obj) || FLONUM_P(obj)) return TRUE;
|
|
|
|
if (SPECIAL_CONST_P(obj)) return FALSE;
|
|
|
|
switch (BUILTIN_TYPE(obj)) {
|
|
|
|
case T_FLOAT:
|
|
|
|
case T_BIGNUM:
|
|
|
|
return TRUE;
|
2020-04-08 09:13:37 +03:00
|
|
|
default:
|
|
|
|
break;
|
2015-05-03 04:02:15 +03:00
|
|
|
}
|
|
|
|
if (rb_obj_is_kind_of(obj, rb_cNumeric)) return TRUE;
|
|
|
|
if (rb_obj_is_kind_of(obj, rb_cTime)) return TRUE;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2012-11-06 21:15:00 +04:00
|
|
|
static VALUE
|
2016-07-25 15:33:15 +03:00
|
|
|
check_step_domain(VALUE step)
|
2012-11-06 21:15:00 +04:00
|
|
|
{
|
2016-07-25 15:33:15 +03:00
|
|
|
VALUE zero = INT2FIX(0);
|
|
|
|
int cmp;
|
|
|
|
if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
|
|
|
|
step = rb_to_int(step);
|
2012-11-06 21:15:00 +04:00
|
|
|
}
|
2016-07-25 15:33:15 +03:00
|
|
|
cmp = rb_cmpint(rb_funcallv(step, idCmp, 1, &zero), step, zero);
|
|
|
|
if (cmp < 0) {
|
2012-11-06 21:15:00 +04:00
|
|
|
rb_raise(rb_eArgError, "step can't be negative");
|
|
|
|
}
|
2016-07-25 15:33:15 +03:00
|
|
|
else if (cmp == 0) {
|
2012-11-06 21:15:00 +04:00
|
|
|
rb_raise(rb_eArgError, "step can't be 0");
|
|
|
|
}
|
2016-07-25 15:33:15 +03:00
|
|
|
return step;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_step_size(VALUE range, VALUE args, VALUE eobj)
|
|
|
|
{
|
|
|
|
VALUE b = RANGE_BEG(range), e = RANGE_END(range);
|
|
|
|
VALUE step = INT2FIX(1);
|
|
|
|
if (args) {
|
|
|
|
step = check_step_domain(RARRAY_AREF(args, 0));
|
|
|
|
}
|
2012-11-06 21:15:00 +04:00
|
|
|
|
|
|
|
if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
|
2013-03-06 10:30:03 +04:00
|
|
|
return ruby_num_interval_step_size(b, e, step, EXCL(range));
|
2012-11-06 21:15:00 +04:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
2009-09-30 12:32:43 +04:00
|
|
|
|
2003-12-24 07:29:32 +03:00
|
|
|
/*
|
2018-09-28 09:25:24 +03:00
|
|
|
* Document-method: Range#step
|
|
|
|
* Document-method: Range#%
|
2003-12-24 07:29:32 +03:00
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.step(n=1) {| obj | block } -> rng
|
|
|
|
* rng.step(n=1) -> an_enumerator
|
2018-09-12 11:51:34 +03:00
|
|
|
* rng.step(n=1) -> an_arithmetic_sequence
|
2018-09-28 09:25:24 +03:00
|
|
|
* rng % n -> an_enumerator
|
|
|
|
* rng % n -> an_arithmetic_sequence
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Iterates over the range, passing each <code>n</code>th element to the block.
|
|
|
|
* If begin and end are numeric, +n+ is added for each iteration.
|
2019-03-28 06:33:35 +03:00
|
|
|
* Otherwise #step invokes #succ to iterate through range elements.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2010-05-13 09:49:55 +04:00
|
|
|
* If no block is given, an enumerator is returned instead.
|
2018-09-12 11:51:34 +03:00
|
|
|
* Especially, the enumerator is an Enumerator::ArithmeticSequence
|
|
|
|
* if begin and end of the range are numeric.
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* range = Xs.new(1)..Xs.new(10)
|
|
|
|
* range.step(2) {|x| puts x}
|
|
|
|
* puts
|
|
|
|
* range.step(3) {|x| puts x}
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
* <em>produces:</em>
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* 1 x
|
|
|
|
* 3 xxx
|
|
|
|
* 5 xxxxx
|
|
|
|
* 7 xxxxxxx
|
|
|
|
* 9 xxxxxxxxx
|
|
|
|
*
|
|
|
|
* 1 x
|
|
|
|
* 4 xxxx
|
|
|
|
* 7 xxxxxxx
|
|
|
|
* 10 xxxxxxxxxx
|
|
|
|
*
|
|
|
|
* See Range for the definition of class Xs.
|
2003-12-24 07:29:32 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2001-08-14 12:13:31 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_step(int argc, VALUE *argv, VALUE range)
|
2001-08-14 12:13:31 +04:00
|
|
|
{
|
2008-04-07 07:15:26 +04:00
|
|
|
VALUE b, e, step, tmp;
|
2001-08-14 12:13:31 +04:00
|
|
|
|
2007-09-08 19:07:18 +04:00
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2018-12-06 10:49:24 +03:00
|
|
|
step = (!rb_check_arity(argc, 0, 1) ? INT2FIX(1) : argv[0]);
|
2008-04-06 21:11:50 +04:00
|
|
|
|
2018-08-06 12:08:28 +03:00
|
|
|
if (!rb_block_given_p()) {
|
2020-10-23 09:26:51 +03:00
|
|
|
if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
|
|
|
|
step = rb_to_int(step);
|
|
|
|
}
|
|
|
|
if (rb_equal(step, INT2FIX(0))) {
|
|
|
|
rb_raise(rb_eArgError, "step can't be 0");
|
|
|
|
}
|
|
|
|
|
2019-04-04 06:34:52 +03:00
|
|
|
const VALUE b_num_p = rb_obj_is_kind_of(b, rb_cNumeric);
|
|
|
|
const VALUE e_num_p = rb_obj_is_kind_of(e, rb_cNumeric);
|
|
|
|
if ((b_num_p && (NIL_P(e) || e_num_p)) || (NIL_P(b) && e_num_p)) {
|
2018-08-06 12:08:28 +03:00
|
|
|
return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
|
|
|
|
range_step_size, b, e, step, EXCL(range));
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
step = check_step_domain(step);
|
|
|
|
|
2018-04-19 18:18:50 +03:00
|
|
|
if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
|
|
|
|
long i = FIX2LONG(b), unit = FIX2LONG(step);
|
2018-04-20 03:10:46 +03:00
|
|
|
do {
|
2018-04-19 18:18:50 +03:00
|
|
|
rb_yield(LONG2FIX(i));
|
2018-04-20 03:10:46 +03:00
|
|
|
i += unit; /* FIXABLE+FIXABLE never overflow */
|
|
|
|
} while (FIXABLE(i));
|
2018-04-19 18:18:50 +03:00
|
|
|
b = LONG2NUM(i);
|
|
|
|
|
2018-04-20 03:23:01 +03:00
|
|
|
for (;; b = rb_big_plus(b, step))
|
2018-04-19 18:18:50 +03:00
|
|
|
rb_yield(b);
|
|
|
|
}
|
|
|
|
else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
|
2002-05-30 10:12:29 +04:00
|
|
|
long end = FIX2LONG(e);
|
2008-05-02 11:15:28 +04:00
|
|
|
long i, unit = FIX2LONG(step);
|
2002-05-30 10:12:29 +04:00
|
|
|
|
2006-12-31 18:02:22 +03:00
|
|
|
if (!EXCL(range))
|
|
|
|
end += 1;
|
2009-02-22 17:23:33 +03:00
|
|
|
i = FIX2LONG(b);
|
2007-09-09 20:11:28 +04:00
|
|
|
while (i < end) {
|
2002-08-21 19:47:54 +04:00
|
|
|
rb_yield(LONG2NUM(i));
|
2007-09-09 20:11:28 +04:00
|
|
|
if (i + unit < i) break;
|
|
|
|
i += unit;
|
2001-08-14 12:13:31 +04:00
|
|
|
}
|
2008-04-06 21:11:50 +04:00
|
|
|
|
|
|
|
}
|
2018-04-19 18:18:50 +03:00
|
|
|
else if (SYMBOL_P(b) && (NIL_P(e) || SYMBOL_P(e))) { /* symbols are special */
|
2018-04-28 14:16:54 +03:00
|
|
|
VALUE iter[2];
|
2009-08-17 21:00:47 +04:00
|
|
|
iter[0] = INT2FIX(1);
|
|
|
|
iter[1] = step;
|
2018-04-19 18:18:50 +03:00
|
|
|
|
2018-04-28 14:16:54 +03:00
|
|
|
b = rb_sym2str(b);
|
2018-04-19 18:18:50 +03:00
|
|
|
if (NIL_P(e)) {
|
2018-04-28 14:16:54 +03:00
|
|
|
rb_str_upto_endless_each(b, sym_step_i, (VALUE)iter);
|
2018-04-19 18:18:50 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-04-28 14:16:54 +03:00
|
|
|
rb_str_upto_each(b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
|
2018-04-19 18:18:50 +03:00
|
|
|
}
|
2009-08-17 21:00:47 +04:00
|
|
|
}
|
2018-04-19 18:18:50 +03:00
|
|
|
else if (ruby_float_step(b, e, step, EXCL(range), TRUE)) {
|
2009-01-04 05:58:45 +03:00
|
|
|
/* done */
|
|
|
|
}
|
2008-04-06 21:11:50 +04:00
|
|
|
else if (rb_obj_is_kind_of(b, rb_cNumeric) ||
|
|
|
|
!NIL_P(rb_check_to_integer(b, "to_int")) ||
|
|
|
|
!NIL_P(rb_check_to_integer(e, "to_int"))) {
|
2012-12-02 13:57:47 +04:00
|
|
|
ID op = EXCL(range) ? '<' : idLE;
|
2009-01-05 02:20:39 +03:00
|
|
|
VALUE v = b;
|
|
|
|
int i = 0;
|
2008-04-06 21:11:50 +04:00
|
|
|
|
2018-04-19 18:18:50 +03:00
|
|
|
while (NIL_P(e) || RTEST(rb_funcall(v, op, 1, e))) {
|
2009-01-05 02:20:39 +03:00
|
|
|
rb_yield(v);
|
|
|
|
i++;
|
|
|
|
v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
|
2008-04-06 21:11:50 +04:00
|
|
|
}
|
2001-08-14 12:13:31 +04:00
|
|
|
}
|
2002-05-30 10:12:29 +04:00
|
|
|
else {
|
2008-04-06 21:11:50 +04:00
|
|
|
tmp = rb_check_string_type(b);
|
2001-08-14 12:13:31 +04:00
|
|
|
|
2003-06-07 19:34:31 +04:00
|
|
|
if (!NIL_P(tmp)) {
|
2018-04-28 14:16:54 +03:00
|
|
|
VALUE iter[2];
|
2003-06-07 19:34:31 +04:00
|
|
|
|
|
|
|
b = tmp;
|
2007-12-05 09:15:23 +03:00
|
|
|
iter[0] = INT2FIX(1);
|
|
|
|
iter[1] = step;
|
2018-04-19 18:18:50 +03:00
|
|
|
|
|
|
|
if (NIL_P(e)) {
|
2018-04-28 14:16:54 +03:00
|
|
|
rb_str_upto_endless_each(b, step_i, (VALUE)iter);
|
2018-04-19 18:18:50 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-04-28 14:16:54 +03:00
|
|
|
rb_str_upto_each(b, e, EXCL(range), step_i, (VALUE)iter);
|
2018-04-19 18:18:50 +03:00
|
|
|
}
|
2003-06-07 19:34:31 +04:00
|
|
|
}
|
|
|
|
else {
|
2007-12-05 09:15:23 +03:00
|
|
|
VALUE args[2];
|
2003-06-07 19:34:31 +04:00
|
|
|
|
2009-09-30 12:32:43 +04:00
|
|
|
if (!discrete_object_p(b)) {
|
* array.c: replace rb_protect_inspect() and rb_inspecting_p() by
rb_exec_recursive() in eval.c.
* eval.c (rb_exec_recursive): new function.
* array.c (rb_ary_join): use rb_exec_recursive().
* array.c (rb_ary_inspect, rb_ary_hash): ditto.
* file.c (rb_file_join): ditto.
* hash.c (rb_hash_inspect, rb_hash_to_s, rb_hash_hash): ditto.
* io.c (rb_io_puts): ditto.
* object.c (rb_obj_inspect): ditto
* struct.c (rb_struct_inspect): ditto.
* lib/set.rb (SortedSet::setup): a hack to shut up warning.
[ruby-talk:132866]
* lib/time.rb (Time::strptime): add new function. inspired by
[ruby-talk:132815].
* lib/parsedate.rb (ParseDate::strptime): ditto.
* regparse.c: move st_*_strend() functions from st.c. fixed some
potential memory leaks.
* exception error messages updated. [ruby-core:04497]
* ext/socket/socket.c (Init_socket): add bunch of Socket
constants. Patch from Sam Roberts <sroberts@uniserve.com>.
[ruby-core:04409]
* array.c (rb_ary_s_create): no need for negative argc check.
[ruby-core:04463]
* array.c (rb_ary_unshift_m): ditto.
* lib/xmlrpc/parser.rb (XMLRPC::FaultException): make it subclass
of StandardError class, not Exception class. [ruby-core:04429]
* parse.y (fcall_gen): lvar(arg) will be evaluated as
lvar.call(arg) when lvar is a defined local variable. [new]
* object.c (rb_class_initialize): call inherited method before
calling initializing block.
* eval.c (rb_thread_start_1): initialize newly pushed frame.
* lib/open3.rb (Open3::popen3): $? should not be EXIT_FAILURE.
fixed: [ruby-core:04444]
* eval.c (is_defined): NODE_IASGN is an assignment.
* ext/readline/readline.c (Readline.readline): use rl_outstream
and rl_instream. [ruby-dev:25699]
* ext/etc/etc.c (Init_etc): sGroup needs HAVE_ST_GR_PASSWD check
[ruby-dev:25675]
* misc/ruby-mode.el: [ruby-core:04415]
* lib/rdoc/generators/html_generator.rb: [ruby-core:04412]
* lib/rdoc/generators/ri_generator.rb: ditto.
* struct.c (make_struct): fixed: [ruby-core:04402]
* ext/curses/curses.c (window_color_set): [ruby-core:04393]
* ext/socket/socket.c (Init_socket): SO_REUSEPORT added.
[ruby-talk:130092]
* object.c: [ruby-doc:818]
* parse.y (open_args): fix too verbose warnings for the space
before argument parentheses. [ruby-dev:25492]
* parse.y (parser_yylex): ditto.
* parse.y (parser_yylex): the first expression in the parentheses
should not be a command. [ruby-dev:25492]
* lib/irb/context.rb (IRB::Context::initialize): [ruby-core:04330]
* object.c (Init_Object): remove Object#type. [ruby-core:04335]
* st.c (st_foreach): report success/failure by return value.
[ruby-Bugs-1396]
* parse.y: forgot to initialize parser struct. [ruby-dev:25492]
* parse.y (parser_yylex): no tLABEL on EXPR_BEG.
[ruby-talk:127711]
* document updates - [ruby-core:04296], [ruby-core:04301],
[ruby-core:04302], [ruby-core:04307]
* dir.c (rb_push_glob): should work for NUL delimited patterns.
* dir.c (rb_glob2): should aware of offset in the pattern.
* string.c (rb_str_new4): should propagate taintedness.
* env.h: rename member names in struct FRAME; last_func -> callee,
orig_func -> this_func, last_class -> this_class.
* struct.c (rb_struct_set): use original method name, not callee
name, to retrieve member slot. [ruby-core:04268]
* time.c (time_strftime): protect from format modification from GC
finalizers.
* object.c (Init_Object): remove rb_obj_id_obsolete()
* eval.c (rb_mod_define_method): incomplete subclass check.
[ruby-dev:25464]
* gc.c (rb_data_object_alloc): klass may be NULL.
[ruby-list:40498]
* bignum.c (rb_big_rand): should return positive random number.
[ruby-dev:25401]
* bignum.c (rb_big_rand): do not use rb_big_modulo to generate
random bignums. [ruby-dev:25396]
* variable.c (rb_autoload): [ruby-dev:25373]
* eval.c (svalue_to_avalue): [ruby-dev:25366]
* string.c (rb_str_justify): [ruby-dev:25367]
* io.c (rb_f_select): [ruby-dev:25312]
* ext/socket/socket.c (sock_s_getservbyport): [ruby-talk:124072]
* struct.c (make_struct): [ruby-dev:25249]
* dir.c (dir_open_dir): new function. [ruby-dev:25242]
* io.c (rb_f_open): add type check for return value from to_open.
* lib/pstore.rb (PStore#transaction): Use the empty content when a
file is not found. [ruby-dev:24561]
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@8068 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-03-04 09:47:45 +03:00
|
|
|
rb_raise(rb_eTypeError, "can't iterate from %s",
|
2003-06-07 19:34:31 +04:00
|
|
|
rb_obj_classname(b));
|
|
|
|
}
|
2007-12-05 09:15:23 +03:00
|
|
|
args[0] = INT2FIX(1);
|
|
|
|
args[1] = step;
|
2013-11-29 06:26:48 +04:00
|
|
|
range_each_func(range, step_i, (VALUE)args);
|
2003-06-07 19:34:31 +04:00
|
|
|
}
|
2001-08-14 12:13:31 +04:00
|
|
|
}
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2018-09-28 05:18:58 +03:00
|
|
|
static VALUE
|
|
|
|
range_percent_step(VALUE range, VALUE step)
|
|
|
|
{
|
2018-09-28 12:23:35 +03:00
|
|
|
return range_step(1, &step, range);
|
2018-09-28 05:18:58 +03:00
|
|
|
}
|
|
|
|
|
2013-01-30 02:00:36 +04:00
|
|
|
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
|
|
|
|
union int64_double {
|
2013-01-30 10:20:26 +04:00
|
|
|
int64_t i;
|
|
|
|
double d;
|
2013-01-30 02:00:36 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
static VALUE
|
2013-01-30 10:20:26 +04:00
|
|
|
int64_as_double_to_num(int64_t i)
|
|
|
|
{
|
2013-01-30 02:00:36 +04:00
|
|
|
union int64_double convert;
|
|
|
|
if (i < 0) {
|
|
|
|
convert.i = -i;
|
|
|
|
return DBL2NUM(-convert.d);
|
2013-01-30 10:20:26 +04:00
|
|
|
}
|
|
|
|
else {
|
2013-01-30 02:00:36 +04:00
|
|
|
convert.i = i;
|
|
|
|
return DBL2NUM(convert.d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t
|
2013-01-30 10:20:26 +04:00
|
|
|
double_as_int64(double d)
|
|
|
|
{
|
2013-01-30 02:00:36 +04:00
|
|
|
union int64_double convert;
|
|
|
|
convert.d = fabs(d);
|
|
|
|
return d < 0 ? -convert.i : convert.i;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-30 09:46:48 +04:00
|
|
|
static int
|
2013-01-30 10:20:26 +04:00
|
|
|
is_integer_p(VALUE v)
|
|
|
|
{
|
2018-04-19 18:19:00 +03:00
|
|
|
ID id_integer_p;
|
|
|
|
VALUE is_int;
|
|
|
|
CONST_ID(id_integer_p, "integer?");
|
|
|
|
is_int = rb_check_funcall(v, id_integer_p, 0, 0);
|
2013-01-30 09:46:48 +04:00
|
|
|
return RTEST(is_int) && is_int != Qundef;
|
|
|
|
}
|
|
|
|
|
2018-04-19 18:18:57 +03:00
|
|
|
static VALUE
|
|
|
|
bsearch_integer_range(VALUE beg, VALUE end, int excl)
|
|
|
|
{
|
|
|
|
VALUE satisfied = Qnil;
|
|
|
|
int smaller;
|
|
|
|
|
|
|
|
#define BSEARCH_CHECK(expr) \
|
|
|
|
do { \
|
|
|
|
VALUE val = (expr); \
|
|
|
|
VALUE v = rb_yield(val); \
|
|
|
|
if (FIXNUM_P(v)) { \
|
|
|
|
if (v == INT2FIX(0)) return val; \
|
|
|
|
smaller = (SIGNED_VALUE)v < 0; \
|
|
|
|
} \
|
|
|
|
else if (v == Qtrue) { \
|
|
|
|
satisfied = val; \
|
|
|
|
smaller = 1; \
|
|
|
|
} \
|
|
|
|
else if (v == Qfalse || v == Qnil) { \
|
|
|
|
smaller = 0; \
|
|
|
|
} \
|
|
|
|
else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \
|
|
|
|
int cmp = rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)); \
|
|
|
|
if (!cmp) return val; \
|
|
|
|
smaller = cmp < 0; \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE \
|
|
|
|
" (must be numeric, true, false or nil)", \
|
|
|
|
rb_obj_class(v)); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
VALUE low = rb_to_int(beg);
|
|
|
|
VALUE high = rb_to_int(end);
|
|
|
|
VALUE mid, org_high;
|
2018-04-19 18:19:00 +03:00
|
|
|
ID id_div;
|
|
|
|
CONST_ID(id_div, "div");
|
|
|
|
|
2018-04-19 18:18:57 +03:00
|
|
|
if (excl) high = rb_funcall(high, '-', 1, INT2FIX(1));
|
|
|
|
org_high = high;
|
|
|
|
|
|
|
|
while (rb_cmpint(rb_funcall(low, id_cmp, 1, high), low, high) < 0) {
|
|
|
|
mid = rb_funcall(rb_funcall(high, '+', 1, low), id_div, 1, INT2FIX(2));
|
|
|
|
BSEARCH_CHECK(mid);
|
|
|
|
if (smaller) {
|
|
|
|
high = mid;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
low = rb_funcall(mid, '+', 1, INT2FIX(1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (rb_equal(low, org_high)) {
|
|
|
|
BSEARCH_CHECK(low);
|
|
|
|
if (!smaller) return Qnil;
|
|
|
|
}
|
|
|
|
return satisfied;
|
|
|
|
}
|
|
|
|
|
2012-11-14 19:53:50 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* rng.bsearch {|obj| block } -> value
|
|
|
|
*
|
|
|
|
* By using binary search, finds a value in range which meets the given
|
2013-06-02 07:05:26 +04:00
|
|
|
* condition in O(log n) where n is the size of the range.
|
2012-11-14 19:53:50 +04:00
|
|
|
*
|
|
|
|
* You can use this method in two use cases: a find-minimum mode and
|
2013-06-02 07:05:26 +04:00
|
|
|
* a find-any mode. In either case, the elements of the range must be
|
2012-11-14 19:53:50 +04:00
|
|
|
* monotone (or sorted) with respect to the block.
|
|
|
|
*
|
|
|
|
* In find-minimum mode (this is a good choice for typical use case),
|
|
|
|
* the block must return true or false, and there must be a value x
|
|
|
|
* so that:
|
|
|
|
*
|
|
|
|
* - the block returns false for any value which is less than x, and
|
|
|
|
* - the block returns true for any value which is greater than or
|
2014-02-15 04:39:25 +04:00
|
|
|
* equal to x.
|
2012-11-14 19:53:50 +04:00
|
|
|
*
|
2012-11-29 06:58:31 +04:00
|
|
|
* If x is within the range, this method returns the value x.
|
2012-11-14 19:53:50 +04:00
|
|
|
* Otherwise, it returns nil.
|
|
|
|
*
|
|
|
|
* ary = [0, 4, 7, 10, 12]
|
|
|
|
* (0...ary.size).bsearch {|i| ary[i] >= 4 } #=> 1
|
|
|
|
* (0...ary.size).bsearch {|i| ary[i] >= 6 } #=> 2
|
|
|
|
* (0...ary.size).bsearch {|i| ary[i] >= 8 } #=> 3
|
|
|
|
* (0...ary.size).bsearch {|i| ary[i] >= 100 } #=> nil
|
|
|
|
*
|
|
|
|
* (0.0...Float::INFINITY).bsearch {|x| Math.log(x) >= 0 } #=> 1.0
|
|
|
|
*
|
|
|
|
* In find-any mode (this behaves like libc's bsearch(3)), the block
|
|
|
|
* must return a number, and there must be two values x and y (x <= y)
|
|
|
|
* so that:
|
|
|
|
*
|
|
|
|
* - the block returns a positive number for v if v < x,
|
|
|
|
* - the block returns zero for v if x <= v < y, and
|
|
|
|
* - the block returns a negative number for v if y <= v.
|
|
|
|
*
|
|
|
|
* This method returns any value which is within the intersection of
|
|
|
|
* the given range and x...y (if any). If there is no value that
|
|
|
|
* satisfies the condition, it returns nil.
|
|
|
|
*
|
|
|
|
* ary = [0, 100, 100, 100, 200]
|
2012-11-15 17:50:55 +04:00
|
|
|
* (0..4).bsearch {|i| 100 - ary[i] } #=> 1, 2 or 3
|
|
|
|
* (0..4).bsearch {|i| 300 - ary[i] } #=> nil
|
|
|
|
* (0..4).bsearch {|i| 50 - ary[i] } #=> nil
|
2012-11-14 19:53:50 +04:00
|
|
|
*
|
|
|
|
* You must not mix the two modes at a time; the block must always
|
|
|
|
* return either true/false, or always return a number. It is
|
|
|
|
* undefined which value is actually picked up at each iteration.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_bsearch(VALUE range)
|
|
|
|
{
|
2015-01-13 06:51:35 +03:00
|
|
|
VALUE beg, end, satisfied = Qnil;
|
|
|
|
int smaller;
|
2012-11-14 19:53:50 +04:00
|
|
|
|
2013-01-30 02:00:36 +04:00
|
|
|
/* Implementation notes:
|
|
|
|
* Floats are handled by mapping them to 64 bits integers.
|
|
|
|
* Apart from sign issues, floats and their 64 bits integer have the
|
|
|
|
* same order, assuming they are represented as exponent followed
|
|
|
|
* by the mantissa. This is true with or without implicit bit.
|
|
|
|
*
|
|
|
|
* Finding the average of two ints needs to be careful about
|
|
|
|
* potential overflow (since float to long can use 64 bits)
|
|
|
|
* as well as the fact that -1/2 can be 0 or -1 in C89.
|
|
|
|
*
|
|
|
|
* Note that -0.0 is mapped to the same int as 0.0 as we don't want
|
|
|
|
* (-1...0.0).bsearch to yield -0.0.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#define BSEARCH(conv) \
|
|
|
|
do { \
|
2013-01-30 09:11:03 +04:00
|
|
|
RETURN_ENUMERATOR(range, 0, 0); \
|
2013-01-30 02:00:36 +04:00
|
|
|
if (EXCL(range)) high--; \
|
|
|
|
org_high = high; \
|
|
|
|
while (low < high) { \
|
|
|
|
mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
|
|
|
|
: (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
|
|
|
|
BSEARCH_CHECK(conv(mid)); \
|
|
|
|
if (smaller) { \
|
|
|
|
high = mid; \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
low = mid + 1; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
if (low == org_high) { \
|
|
|
|
BSEARCH_CHECK(conv(low)); \
|
|
|
|
if (!smaller) return Qnil; \
|
|
|
|
} \
|
2015-01-13 06:51:35 +03:00
|
|
|
return satisfied; \
|
2013-01-30 02:00:36 +04:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
2012-11-14 19:53:50 +04:00
|
|
|
beg = RANGE_BEG(range);
|
|
|
|
end = RANGE_END(range);
|
|
|
|
|
|
|
|
if (FIXNUM_P(beg) && FIXNUM_P(end)) {
|
|
|
|
long low = FIX2LONG(beg);
|
|
|
|
long high = FIX2LONG(end);
|
|
|
|
long mid, org_high;
|
2013-01-30 02:00:36 +04:00
|
|
|
BSEARCH(INT2FIX);
|
2012-11-14 19:53:50 +04:00
|
|
|
}
|
2013-01-30 02:00:36 +04:00
|
|
|
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
|
2012-12-29 16:22:01 +04:00
|
|
|
else if (RB_TYPE_P(beg, T_FLOAT) || RB_TYPE_P(end, T_FLOAT)) {
|
2019-04-03 11:11:41 +03:00
|
|
|
int64_t low = double_as_int64(NIL_P(beg) ? -HUGE_VAL : RFLOAT_VALUE(rb_Float(beg)));
|
|
|
|
int64_t high = double_as_int64(NIL_P(end) ? HUGE_VAL : RFLOAT_VALUE(rb_Float(end)));
|
2013-01-30 02:00:36 +04:00
|
|
|
int64_t mid, org_high;
|
|
|
|
BSEARCH(int64_as_double_to_num);
|
2012-11-14 19:53:50 +04:00
|
|
|
}
|
2013-01-30 02:00:36 +04:00
|
|
|
#endif
|
2013-01-30 09:46:48 +04:00
|
|
|
else if (is_integer_p(beg) && is_integer_p(end)) {
|
2013-01-30 09:11:03 +04:00
|
|
|
RETURN_ENUMERATOR(range, 0, 0);
|
2018-04-19 18:18:57 +03:00
|
|
|
return bsearch_integer_range(beg, end, EXCL(range));
|
|
|
|
}
|
|
|
|
else if (is_integer_p(beg) && NIL_P(end)) {
|
|
|
|
VALUE diff = LONG2FIX(1);
|
|
|
|
RETURN_ENUMERATOR(range, 0, 0);
|
|
|
|
while (1) {
|
2018-04-19 18:19:00 +03:00
|
|
|
VALUE mid = rb_funcall(beg, '+', 1, diff);
|
2012-11-14 19:53:50 +04:00
|
|
|
BSEARCH_CHECK(mid);
|
|
|
|
if (smaller) {
|
2018-04-19 18:18:57 +03:00
|
|
|
return bsearch_integer_range(beg, mid, 0);
|
2012-11-14 19:53:50 +04:00
|
|
|
}
|
2018-04-19 18:19:00 +03:00
|
|
|
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
|
2012-11-14 19:53:50 +04:00
|
|
|
}
|
|
|
|
}
|
2019-04-03 11:11:41 +03:00
|
|
|
else if (NIL_P(beg) && is_integer_p(end)) {
|
|
|
|
VALUE diff = LONG2FIX(-1);
|
|
|
|
RETURN_ENUMERATOR(range, 0, 0);
|
|
|
|
while (1) {
|
|
|
|
VALUE mid = rb_funcall(end, '+', 1, diff);
|
|
|
|
BSEARCH_CHECK(mid);
|
|
|
|
if (!smaller) {
|
|
|
|
return bsearch_integer_range(mid, end, 0);
|
|
|
|
}
|
|
|
|
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
|
|
|
|
}
|
|
|
|
}
|
2012-11-14 19:53:50 +04:00
|
|
|
else {
|
|
|
|
rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
|
|
|
|
}
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2018-04-28 14:16:54 +03:00
|
|
|
static int
|
|
|
|
each_i(VALUE v, VALUE arg)
|
2002-05-30 10:12:29 +04:00
|
|
|
{
|
2004-10-06 11:40:06 +04:00
|
|
|
rb_yield(v);
|
2018-04-28 14:16:54 +03:00
|
|
|
return 0;
|
2002-05-30 10:12:29 +04:00
|
|
|
}
|
|
|
|
|
2018-04-28 14:16:54 +03:00
|
|
|
static int
|
|
|
|
sym_each_i(VALUE v, VALUE arg)
|
2009-08-17 21:00:47 +04:00
|
|
|
{
|
|
|
|
rb_yield(rb_str_intern(v));
|
2018-04-28 14:16:54 +03:00
|
|
|
return 0;
|
2009-08-17 21:00:47 +04:00
|
|
|
}
|
|
|
|
|
2012-11-06 21:14:46 +04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* rng.size -> num
|
|
|
|
*
|
2014-01-10 01:23:45 +04:00
|
|
|
* Returns the number of elements in the range. Both the begin and the end of
|
|
|
|
* the Range must be Numeric, otherwise nil is returned.
|
2012-11-06 21:14:46 +04:00
|
|
|
*
|
|
|
|
* (10..20).size #=> 11
|
2014-01-10 01:23:45 +04:00
|
|
|
* ('a'..'z').size #=> nil
|
|
|
|
* (-Float::INFINITY..Float::INFINITY).size #=> Infinity
|
2012-11-06 21:14:46 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_size(VALUE range)
|
|
|
|
{
|
|
|
|
VALUE b = RANGE_BEG(range), e = RANGE_END(range);
|
2018-06-22 05:58:39 +03:00
|
|
|
if (rb_obj_is_kind_of(b, rb_cNumeric)) {
|
|
|
|
if (rb_obj_is_kind_of(e, rb_cNumeric)) {
|
|
|
|
return ruby_num_interval_step_size(b, e, INT2FIX(1), EXCL(range));
|
|
|
|
}
|
|
|
|
if (NIL_P(e)) {
|
|
|
|
return DBL2NUM(HUGE_VAL);
|
|
|
|
}
|
2012-11-06 21:14:46 +04:00
|
|
|
}
|
2019-04-03 11:11:41 +03:00
|
|
|
else if (NIL_P(b)) {
|
|
|
|
return DBL2NUM(HUGE_VAL);
|
|
|
|
}
|
2018-06-22 05:58:39 +03:00
|
|
|
|
2012-11-06 21:14:46 +04:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2018-06-22 05:58:37 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* rng.to_a -> array
|
|
|
|
* rng.entries -> array
|
|
|
|
*
|
2018-07-08 22:30:19 +03:00
|
|
|
* Returns an array containing the items in the range.
|
2018-06-22 05:58:37 +03:00
|
|
|
*
|
|
|
|
* (1..7).to_a #=> [1, 2, 3, 4, 5, 6, 7]
|
|
|
|
* (1..).to_a #=> RangeError: cannot convert endless range to an array
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_to_a(VALUE range)
|
|
|
|
{
|
|
|
|
if (NIL_P(RANGE_END(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot convert endless range to an array");
|
|
|
|
}
|
|
|
|
return rb_call_super(0, 0);
|
|
|
|
}
|
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
static VALUE
|
|
|
|
range_enum_size(VALUE range, VALUE args, VALUE eobj)
|
|
|
|
{
|
|
|
|
return range_size(range);
|
|
|
|
}
|
|
|
|
|
2020-06-16 08:31:11 +03:00
|
|
|
RBIMPL_ATTR_NORETURN()
|
|
|
|
static void
|
|
|
|
range_each_bignum_endless(VALUE beg)
|
|
|
|
{
|
|
|
|
for (;; beg = rb_big_plus(beg, INT2FIX(1))) {
|
|
|
|
rb_yield(beg);
|
|
|
|
}
|
2020-06-24 10:23:59 +03:00
|
|
|
UNREACHABLE;
|
2020-06-16 08:31:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
RBIMPL_ATTR_NORETURN()
|
|
|
|
static void
|
|
|
|
range_each_fixnum_endless(VALUE beg)
|
|
|
|
{
|
|
|
|
for (long i = FIX2LONG(beg); FIXABLE(i); i++) {
|
|
|
|
rb_yield(LONG2FIX(i));
|
|
|
|
}
|
|
|
|
|
|
|
|
range_each_bignum_endless(LONG2NUM(RUBY_FIXNUM_MAX + 1));
|
2020-06-24 10:23:59 +03:00
|
|
|
UNREACHABLE;
|
2020-06-16 08:31:11 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_each_fixnum_loop(VALUE beg, VALUE end, VALUE range)
|
|
|
|
{
|
|
|
|
long lim = FIX2LONG(end) + !EXCL(range);
|
|
|
|
for (long i = FIX2LONG(beg); i < lim; i++) {
|
|
|
|
rb_yield(LONG2FIX(i));
|
|
|
|
}
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2003-12-24 07:29:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.each {| i | block } -> rng
|
|
|
|
* rng.each -> an_enumerator
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Iterates over the elements of range, passing each in turn to the
|
|
|
|
* block.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* The +each+ method can only be used if the begin object of the range
|
|
|
|
* supports the +succ+ method. A TypeError is raised if the object
|
|
|
|
* does not have +succ+ method defined (like Float).
|
2010-05-13 09:49:55 +04:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* If no block is given, an enumerator is returned instead.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* (10..15).each {|n| print n, ' ' }
|
|
|
|
* # prints: 10 11 12 13 14 15
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* (2.5..5).each {|n| print n, ' ' }
|
|
|
|
* # raises: TypeError: can't iterate from Float
|
2003-12-24 07:29:32 +03:00
|
|
|
*/
|
|
|
|
|
2002-05-01 13:41:50 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_each(VALUE range)
|
2002-05-01 13:41:50 +04:00
|
|
|
{
|
2002-05-30 10:12:29 +04:00
|
|
|
VALUE beg, end;
|
2020-06-16 08:31:11 +03:00
|
|
|
long i;
|
2002-05-30 10:12:29 +04:00
|
|
|
|
2013-06-26 17:43:22 +04:00
|
|
|
RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
|
2005-08-30 18:49:51 +04:00
|
|
|
|
2007-09-08 19:07:18 +04:00
|
|
|
beg = RANGE_BEG(range);
|
|
|
|
end = RANGE_END(range);
|
2002-05-30 10:12:29 +04:00
|
|
|
|
2018-04-19 18:18:50 +03:00
|
|
|
if (FIXNUM_P(beg) && NIL_P(end)) {
|
2020-06-16 08:31:11 +03:00
|
|
|
range_each_fixnum_endless(beg);
|
2018-04-19 18:18:50 +03:00
|
|
|
}
|
|
|
|
else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
|
2020-06-16 08:31:11 +03:00
|
|
|
return range_each_fixnum_loop(beg, end, range);
|
2003-01-08 09:05:08 +03:00
|
|
|
}
|
2018-04-29 10:12:56 +03:00
|
|
|
else if (RB_INTEGER_TYPE_P(beg) && (NIL_P(end) || RB_INTEGER_TYPE_P(end))) {
|
|
|
|
if (SPECIAL_CONST_P(end) || RBIGNUM_POSITIVE_P(end)) { /* end >= FIXNUM_MIN */
|
|
|
|
if (!FIXNUM_P(beg)) {
|
|
|
|
if (RBIGNUM_NEGATIVE_P(beg)) {
|
|
|
|
do {
|
|
|
|
rb_yield(beg);
|
|
|
|
} while (!FIXNUM_P(beg = rb_big_plus(beg, INT2FIX(1))));
|
2020-06-16 08:31:11 +03:00
|
|
|
if (NIL_P(end)) range_each_fixnum_endless(beg);
|
|
|
|
if (FIXNUM_P(end)) return range_each_fixnum_loop(beg, end, range);
|
2018-04-29 10:12:56 +03:00
|
|
|
}
|
|
|
|
else {
|
2020-06-16 08:31:11 +03:00
|
|
|
if (NIL_P(end)) range_each_bignum_endless(beg);
|
2018-04-29 10:12:56 +03:00
|
|
|
if (FIXNUM_P(end)) return range;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (FIXNUM_P(beg)) {
|
|
|
|
i = FIX2LONG(beg);
|
|
|
|
do {
|
|
|
|
rb_yield(LONG2FIX(i));
|
|
|
|
} while (POSFIXABLE(++i));
|
|
|
|
beg = LONG2NUM(i);
|
|
|
|
}
|
|
|
|
ASSUME(!FIXNUM_P(beg));
|
|
|
|
ASSUME(!SPECIAL_CONST_P(end));
|
|
|
|
}
|
|
|
|
if (!FIXNUM_P(beg) && RBIGNUM_SIGN(beg) == RBIGNUM_SIGN(end)) {
|
|
|
|
if (EXCL(range)) {
|
|
|
|
while (rb_big_cmp(beg, end) == INT2FIX(-1)) {
|
|
|
|
rb_yield(beg);
|
|
|
|
beg = rb_big_plus(beg, INT2FIX(1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE c;
|
|
|
|
while ((c = rb_big_cmp(beg, end)) != INT2FIX(1)) {
|
|
|
|
rb_yield(beg);
|
|
|
|
if (c == INT2FIX(0)) break;
|
|
|
|
beg = rb_big_plus(beg, INT2FIX(1));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-29 02:31:32 +03:00
|
|
|
else if (SYMBOL_P(beg) && (NIL_P(end) || SYMBOL_P(end))) { /* symbols are special */
|
2018-04-28 14:16:54 +03:00
|
|
|
beg = rb_sym2str(beg);
|
2018-04-29 02:31:32 +03:00
|
|
|
if (NIL_P(end)) {
|
|
|
|
rb_str_upto_endless_each(beg, sym_each_i, 0);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
rb_str_upto_each(beg, rb_sym2str(end), EXCL(range), sym_each_i, 0);
|
|
|
|
}
|
2009-08-17 21:00:47 +04:00
|
|
|
}
|
2002-05-30 10:12:29 +04:00
|
|
|
else {
|
2009-08-17 20:41:00 +04:00
|
|
|
VALUE tmp = rb_check_string_type(beg);
|
|
|
|
|
|
|
|
if (!NIL_P(tmp)) {
|
2018-04-19 18:18:50 +03:00
|
|
|
if (!NIL_P(end)) {
|
2018-04-28 14:16:54 +03:00
|
|
|
rb_str_upto_each(tmp, end, EXCL(range), each_i, 0);
|
2018-04-19 18:18:50 +03:00
|
|
|
}
|
2018-04-28 10:31:32 +03:00
|
|
|
else {
|
2018-04-28 14:16:54 +03:00
|
|
|
rb_str_upto_endless_each(tmp, each_i, 0);
|
2018-04-19 18:18:50 +03:00
|
|
|
}
|
2009-08-17 20:41:00 +04:00
|
|
|
}
|
|
|
|
else {
|
2009-09-30 12:32:43 +04:00
|
|
|
if (!discrete_object_p(beg)) {
|
2009-08-17 20:41:00 +04:00
|
|
|
rb_raise(rb_eTypeError, "can't iterate from %s",
|
|
|
|
rb_obj_classname(beg));
|
|
|
|
}
|
2018-04-19 18:18:50 +03:00
|
|
|
if (!NIL_P(end))
|
|
|
|
range_each_func(range, each_i, 0);
|
|
|
|
else
|
2018-04-29 10:12:56 +03:00
|
|
|
for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
|
|
|
|
rb_yield(beg);
|
2009-02-23 18:46:02 +03:00
|
|
|
}
|
2002-05-30 10:12:29 +04:00
|
|
|
}
|
|
|
|
return range;
|
2002-05-01 13:41:50 +04:00
|
|
|
}
|
|
|
|
|
2003-12-24 07:29:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.begin -> obj
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns the object that defines the beginning of the range.
|
|
|
|
*
|
|
|
|
* (1..10).begin #=> 1
|
2003-12-24 07:29:32 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2007-10-18 10:58:35 +04:00
|
|
|
range_begin(VALUE range)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2007-09-08 19:07:18 +04:00
|
|
|
return RANGE_BEG(range);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2003-12-24 07:29:32 +03:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.end -> obj
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns the object that defines the end of the range.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
* (1..10).end #=> 10
|
|
|
|
* (1...10).end #=> 10
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
2007-10-18 10:58:35 +04:00
|
|
|
range_end(VALUE range)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2007-09-08 19:07:18 +04:00
|
|
|
return RANGE_END(range);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2007-10-18 10:58:35 +04:00
|
|
|
|
|
|
|
static VALUE
|
2013-11-29 11:59:14 +04:00
|
|
|
first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, cbarg))
|
2007-10-18 10:58:35 +04:00
|
|
|
{
|
2013-11-29 11:45:00 +04:00
|
|
|
VALUE *ary = (VALUE *)cbarg;
|
2007-10-18 10:58:35 +04:00
|
|
|
long n = NUM2LONG(ary[0]);
|
|
|
|
|
|
|
|
if (n <= 0) {
|
|
|
|
rb_iter_break();
|
|
|
|
}
|
|
|
|
rb_ary_push(ary[1], i);
|
|
|
|
n--;
|
2020-04-08 07:28:13 +03:00
|
|
|
ary[0] = LONG2NUM(n);
|
2007-10-18 10:58:35 +04:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.first -> obj
|
|
|
|
* rng.first(n) -> an_array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns the first object in the range, or an array of the first +n+
|
|
|
|
* elements.
|
|
|
|
*
|
|
|
|
* (10..20).first #=> 10
|
|
|
|
* (10..20).first(3) #=> [10, 11, 12]
|
2007-10-18 10:58:35 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_first(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
|
|
|
VALUE n, ary[2];
|
|
|
|
|
2019-04-30 17:18:44 +03:00
|
|
|
if (NIL_P(RANGE_BEG(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
|
|
|
|
}
|
2007-10-18 10:58:35 +04:00
|
|
|
if (argc == 0) return RANGE_BEG(range);
|
|
|
|
|
|
|
|
rb_scan_args(argc, argv, "1", &n);
|
|
|
|
ary[0] = n;
|
|
|
|
ary[1] = rb_ary_new2(NUM2LONG(n));
|
2012-12-02 13:57:47 +04:00
|
|
|
rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
|
2007-10-18 10:58:35 +04:00
|
|
|
|
|
|
|
return ary[1];
|
|
|
|
}
|
|
|
|
|
2019-01-06 03:46:36 +03:00
|
|
|
static VALUE
|
|
|
|
rb_int_range_last(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
|
|
|
static const VALUE ONE = INT2FIX(1);
|
|
|
|
|
|
|
|
VALUE b, e, len_1, len, nv, ary;
|
|
|
|
int x;
|
|
|
|
long n;
|
|
|
|
|
|
|
|
assert(argc > 0);
|
|
|
|
|
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
|
|
|
assert(RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e));
|
|
|
|
|
|
|
|
x = EXCL(range);
|
|
|
|
|
|
|
|
len_1 = rb_int_minus(e, b);
|
|
|
|
if (FIXNUM_ZERO_P(len_1) || rb_num_negative_p(len_1)) {
|
|
|
|
return rb_ary_new_capa(0);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (x) {
|
|
|
|
e = rb_int_minus(e, ONE);
|
|
|
|
len = len_1;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
len = rb_int_plus(len_1, ONE);
|
|
|
|
}
|
|
|
|
|
|
|
|
rb_scan_args(argc, argv, "1", &nv);
|
|
|
|
n = NUM2LONG(nv);
|
|
|
|
if (n < 0) {
|
|
|
|
rb_raise(rb_eArgError, "negative array size");
|
|
|
|
}
|
|
|
|
|
|
|
|
nv = LONG2NUM(n);
|
|
|
|
if (RTEST(rb_int_gt(nv, len))) {
|
|
|
|
nv = len;
|
|
|
|
n = NUM2LONG(nv);
|
|
|
|
}
|
|
|
|
|
|
|
|
ary = rb_ary_new_capa(n);
|
|
|
|
b = rb_int_minus(e, nv);
|
|
|
|
while (n) {
|
|
|
|
b = rb_int_plus(b, ONE);
|
|
|
|
rb_ary_push(ary, b);
|
|
|
|
--n;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ary;
|
|
|
|
}
|
2007-10-18 10:58:35 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.last -> obj
|
|
|
|
* rng.last(n) -> an_array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns the last object in the range,
|
|
|
|
* or an array of the last +n+ elements.
|
|
|
|
*
|
|
|
|
* Note that with no arguments +last+ will return the object that defines
|
|
|
|
* the end of the range even if #exclude_end? is +true+.
|
|
|
|
*
|
|
|
|
* (10..20).last #=> 20
|
|
|
|
* (10...20).last #=> 20
|
|
|
|
* (10..20).last(3) #=> [18, 19, 20]
|
|
|
|
* (10...20).last(3) #=> [17, 18, 19]
|
2007-10-18 10:58:35 +04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_last(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
2019-01-06 03:46:36 +03:00
|
|
|
VALUE b, e;
|
|
|
|
|
2018-06-22 05:58:40 +03:00
|
|
|
if (NIL_P(RANGE_END(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the last element of endless range");
|
|
|
|
}
|
2013-08-08 05:27:19 +04:00
|
|
|
if (argc == 0) return RANGE_END(range);
|
2019-01-06 03:46:36 +03:00
|
|
|
|
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2019-01-08 07:37:40 +03:00
|
|
|
if (RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e) &&
|
|
|
|
RB_LIKELY(rb_method_basic_definition_p(rb_cRange, idEach))) {
|
2019-01-06 03:46:36 +03:00
|
|
|
return rb_int_range_last(argc, argv, range);
|
|
|
|
}
|
2009-02-22 17:23:33 +03:00
|
|
|
return rb_ary_last(argc, argv, rb_Array(range));
|
2007-10-18 10:58:35 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-25 04:30:57 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2014-02-14 19:45:11 +04:00
|
|
|
* rng.min -> obj
|
|
|
|
* rng.min {| a,b | block } -> obj
|
|
|
|
* rng.min(n) -> array
|
|
|
|
* rng.min(n) {| a,b | block } -> array
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns the minimum value in the range. Returns +nil+ if the begin
|
2016-10-05 08:27:42 +03:00
|
|
|
* value of the range is larger than the end value. Returns +nil+ if
|
|
|
|
* the begin value of an exclusive range is equal to the end value.
|
2011-12-06 03:36:53 +04:00
|
|
|
*
|
|
|
|
* Can be given an optional block to override the default comparison
|
|
|
|
* method <code>a <=> b</code>.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* (10..20).min #=> 10
|
2005-11-25 04:30:57 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
static VALUE
|
2014-02-14 19:45:11 +04:00
|
|
|
range_min(int argc, VALUE *argv, VALUE range)
|
2005-11-25 04:30:57 +03:00
|
|
|
{
|
2019-12-25 07:35:22 +03:00
|
|
|
if (NIL_P(RANGE_BEG(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the minimum of beginless range");
|
|
|
|
}
|
|
|
|
|
2005-11-25 04:30:57 +03:00
|
|
|
if (rb_block_given_p()) {
|
2018-06-22 05:58:40 +03:00
|
|
|
if (NIL_P(RANGE_END(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the minimum of endless range with custom comparison method");
|
|
|
|
}
|
2014-02-14 19:45:11 +04:00
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
else if (argc != 0) {
|
|
|
|
return range_first(argc, argv, range);
|
2005-11-25 04:30:57 +03:00
|
|
|
}
|
|
|
|
else {
|
2017-05-30 05:57:33 +03:00
|
|
|
struct cmp_opt_data cmp_opt = { 0, 0 };
|
2007-09-08 19:07:18 +04:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
VALUE e = RANGE_END(range);
|
2018-04-19 18:18:53 +03:00
|
|
|
int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
|
2005-11-25 04:30:57 +03:00
|
|
|
|
2007-07-13 06:33:11 +04:00
|
|
|
if (c > 0 || (c == 0 && EXCL(range)))
|
2006-12-31 18:02:22 +03:00
|
|
|
return Qnil;
|
2005-11-25 04:30:57 +03:00
|
|
|
return b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2014-02-14 19:45:11 +04:00
|
|
|
* rng.max -> obj
|
|
|
|
* rng.max {| a,b | block } -> obj
|
|
|
|
* rng.max(n) -> obj
|
|
|
|
* rng.max(n) {| a,b | block } -> obj
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-09-01 19:58:45 +03:00
|
|
|
* Returns the maximum value in the range, or an array of maximum
|
|
|
|
* values in the range if given an \Integer argument.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2020-09-01 19:58:45 +03:00
|
|
|
* For inclusive ranges with an end, the maximum value of the range
|
|
|
|
* is the same as the end of the range.
|
|
|
|
*
|
|
|
|
* If an argument or block is given, or +self+ is an exclusive,
|
|
|
|
* non-numeric range, calls Enumerable#max (via +super+) with the
|
|
|
|
* argument and/or block to get the maximum values, unless +self+ is
|
|
|
|
* a beginless range, in which case it raises a RangeError.
|
|
|
|
*
|
|
|
|
* If +self+ is an exclusive, integer range (both start and end of the
|
|
|
|
* range are integers), and no arguments or block are provided, returns
|
|
|
|
* last value in the range (1 before the end). Otherwise, if +self+ is
|
|
|
|
* an exclusive, numeric range, raises a TypeError.
|
2020-09-02 06:44:28 +03:00
|
|
|
*
|
2020-09-01 19:58:45 +03:00
|
|
|
* Returns +nil+ if the begin value of the range larger than the
|
|
|
|
* end value. Returns +nil+ if the begin value of an exclusive
|
|
|
|
* range is equal to the end value. Raises a RangeError if called on
|
|
|
|
* an endless range.
|
2011-12-06 03:36:53 +04:00
|
|
|
*
|
2020-09-01 19:58:45 +03:00
|
|
|
* Examples:
|
|
|
|
* (10..20).max #=> 20
|
|
|
|
* (10..20).max(2) #=> [20, 19]
|
|
|
|
* (10...20).max #=> 19
|
|
|
|
* (10...20).max(2) #=> [19, 18]
|
|
|
|
* (10...20).max{|x, y| -x <=> -y } #=> 10
|
|
|
|
* (10...20).max(2){|x, y| -x <=> -y } #=> [10, 11]
|
2005-11-25 04:30:57 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2014-02-14 19:45:11 +04:00
|
|
|
range_max(int argc, VALUE *argv, VALUE range)
|
2005-11-25 04:30:57 +03:00
|
|
|
{
|
2007-09-08 19:07:18 +04:00
|
|
|
VALUE e = RANGE_END(range);
|
2009-01-05 01:32:40 +03:00
|
|
|
int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
|
2005-11-25 08:42:28 +03:00
|
|
|
|
2018-06-22 05:58:40 +03:00
|
|
|
if (NIL_P(RANGE_END(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the maximum of endless range");
|
|
|
|
}
|
2018-04-19 18:18:53 +03:00
|
|
|
|
2020-07-18 19:18:40 +03:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
|
2014-02-14 19:45:11 +04:00
|
|
|
if (rb_block_given_p() || (EXCL(range) && !nm) || argc) {
|
2020-07-18 19:18:40 +03:00
|
|
|
if (NIL_P(b)) {
|
2019-12-25 07:35:22 +03:00
|
|
|
rb_raise(rb_eRangeError, "cannot get the maximum of beginless range with custom comparison method");
|
|
|
|
}
|
2018-02-26 10:57:15 +03:00
|
|
|
return rb_call_super(argc, argv);
|
2005-11-25 04:30:57 +03:00
|
|
|
}
|
|
|
|
else {
|
2018-02-26 10:57:15 +03:00
|
|
|
struct cmp_opt_data cmp_opt = { 0, 0 };
|
2020-07-18 19:18:40 +03:00
|
|
|
int c = NIL_P(b) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
|
2018-02-26 10:57:15 +03:00
|
|
|
|
|
|
|
if (c > 0)
|
|
|
|
return Qnil;
|
|
|
|
if (EXCL(range)) {
|
|
|
|
if (!RB_INTEGER_TYPE_P(e)) {
|
|
|
|
rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
|
|
|
|
}
|
|
|
|
if (c == 0) return Qnil;
|
|
|
|
if (!RB_INTEGER_TYPE_P(b)) {
|
|
|
|
rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
|
|
|
|
}
|
|
|
|
if (FIXNUM_P(e)) {
|
|
|
|
return LONG2NUM(FIX2LONG(e) - 1);
|
|
|
|
}
|
|
|
|
return rb_funcall(e, '-', 1, INT2FIX(1));
|
|
|
|
}
|
|
|
|
return e;
|
2005-11-25 04:30:57 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-08 08:03:02 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* rng.minmax -> [obj, obj]
|
|
|
|
* rng.minmax {| a,b | block } -> [obj, obj]
|
|
|
|
*
|
|
|
|
* Returns a two element array which contains the minimum and the
|
|
|
|
* maximum value in the range.
|
|
|
|
*
|
|
|
|
* Can be given an optional block to override the default comparison
|
|
|
|
* method <code>a <=> b</code>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_minmax(VALUE range)
|
|
|
|
{
|
|
|
|
if (rb_block_given_p()) {
|
|
|
|
return rb_call_super(0, NULL);
|
|
|
|
}
|
Fix non-numeric exclusive Range#minmax bug
The implementation of Range#minmax added in d5c60214c45 causes the
following incorrect behaviour:
('a'...'c').minmax => ["a", ["a", "b"]]
instead of
('a'...'c').minmax => ["a", "b"]
This is because the C implementation of Range#minmax (range_minmax)
directly delegates to the C implementation of Range#min (range_min) and
Range#max (range_max), without changing the execution context.
Range#max's C implementation (range_max), when given a non-numeric
exclusive range, delegates to super, which is meant to call
Enumerable#max. However, because range_max is called directly by
range_minmax, super calls Enumerable#minmax instead, causing the
incorrect nesting.
Perhaps it is possible to change the execution context in an optimized
manner, but the simplest solution seems to be to just explicitly
delegate from Range#minmax to Range#min and Range#max.
2020-07-04 05:56:07 +03:00
|
|
|
return rb_assoc_new(
|
2020-07-04 20:12:02 +03:00
|
|
|
rb_funcall(range, id_min, 0),
|
|
|
|
rb_funcall(range, id_max, 0)
|
Fix non-numeric exclusive Range#minmax bug
The implementation of Range#minmax added in d5c60214c45 causes the
following incorrect behaviour:
('a'...'c').minmax => ["a", ["a", "b"]]
instead of
('a'...'c').minmax => ["a", "b"]
This is because the C implementation of Range#minmax (range_minmax)
directly delegates to the C implementation of Range#min (range_min) and
Range#max (range_max), without changing the execution context.
Range#max's C implementation (range_max), when given a non-numeric
exclusive range, delegates to super, which is meant to call
Enumerable#max. However, because range_max is called directly by
range_minmax, super calls Enumerable#minmax instead, causing the
incorrect nesting.
Perhaps it is possible to change the execution context in an optimized
manner, but the simplest solution seems to be to just explicitly
delegate from Range#minmax to Range#min and Range#max.
2020-07-04 05:56:07 +03:00
|
|
|
);
|
2019-06-08 08:03:02 +03:00
|
|
|
}
|
|
|
|
|
2009-07-16 10:52:29 +04:00
|
|
|
int
|
|
|
|
rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2005-08-04 08:31:33 +04:00
|
|
|
VALUE b, e;
|
2009-07-16 10:52:29 +04:00
|
|
|
int excl;
|
1998-01-16 15:13:05 +03:00
|
|
|
|
2005-08-04 08:31:33 +04:00
|
|
|
if (rb_obj_is_kind_of(range, rb_cRange)) {
|
2007-09-08 19:07:18 +04:00
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2005-08-04 15:29:51 +04:00
|
|
|
excl = EXCL(range);
|
2005-08-04 08:31:33 +04:00
|
|
|
}
|
2018-12-21 16:05:16 +03:00
|
|
|
else if (RTEST(rb_obj_is_kind_of(range, rb_cArithSeq))) {
|
|
|
|
return (int)Qfalse;
|
|
|
|
}
|
2005-08-04 08:31:33 +04:00
|
|
|
else {
|
2017-10-25 04:40:15 +03:00
|
|
|
VALUE x;
|
|
|
|
b = rb_check_funcall(range, id_beg, 0, 0);
|
|
|
|
if (b == Qundef) return (int)Qfalse;
|
|
|
|
e = rb_check_funcall(range, id_end, 0, 0);
|
|
|
|
if (e == Qundef) return (int)Qfalse;
|
|
|
|
x = rb_check_funcall(range, rb_intern("exclude_end?"), 0, 0);
|
|
|
|
if (x == Qundef) return (int)Qfalse;
|
|
|
|
excl = RTEST(x);
|
2005-08-04 08:31:33 +04:00
|
|
|
}
|
2009-07-16 10:52:29 +04:00
|
|
|
*begp = b;
|
|
|
|
*endp = e;
|
|
|
|
*exclp = excl;
|
2009-09-23 07:39:44 +04:00
|
|
|
return (int)Qtrue;
|
2009-07-16 10:52:29 +04:00
|
|
|
}
|
|
|
|
|
2020-10-20 20:40:18 +03:00
|
|
|
/* Extract the components of a Range.
|
|
|
|
*
|
|
|
|
* You can use +err+ to control the behavior of out-of-range and exception.
|
|
|
|
*
|
|
|
|
* When +err+ is 0 or 2, if the begin offset is greater than +len+,
|
|
|
|
* it is out-of-range. The +RangeError+ is raised only if +err+ is 2,
|
|
|
|
* in this case. If +err+ is 0, +Qnil+ will be returned.
|
|
|
|
*
|
|
|
|
* When +err+ is 1, the begin and end offsets won't be adjusted even if they
|
|
|
|
* are greater than +len+. It allows +rb_ary_aset+ extends arrays.
|
|
|
|
*
|
|
|
|
* If the begin component of the given range is negative and is too-large
|
|
|
|
* abstract value, the +RangeError+ is raised only +err+ is 1 or 2.
|
|
|
|
*
|
|
|
|
* The case of <code>err = 0</code> is used in item accessing methods such as
|
|
|
|
* +rb_ary_aref+, +rb_ary_slice_bang+, and +rb_str_aref+.
|
|
|
|
*
|
|
|
|
* The case of <code>err = 1</code> is used in Array's methods such as
|
|
|
|
* +rb_ary_aset+ and +rb_ary_fill+.
|
|
|
|
*
|
|
|
|
* The case of <code>err = 2</code> is used in +rb_str_aset+.
|
|
|
|
*/
|
2009-07-16 10:52:29 +04:00
|
|
|
VALUE
|
2020-10-20 20:40:18 +03:00
|
|
|
rb_range_component_beg_len(VALUE b, VALUE e, int excl,
|
|
|
|
long *begp, long *lenp, long len, int err)
|
2009-07-16 10:52:29 +04:00
|
|
|
{
|
2020-10-20 10:00:35 +03:00
|
|
|
long beg, end;
|
2009-07-16 10:52:29 +04:00
|
|
|
|
2019-04-03 11:11:41 +03:00
|
|
|
beg = NIL_P(b) ? 0 : NUM2LONG(b);
|
2018-04-19 18:18:50 +03:00
|
|
|
end = NIL_P(e) ? -1 : NUM2LONG(e);
|
|
|
|
if (NIL_P(e)) excl = 0;
|
1999-08-13 09:45:20 +04:00
|
|
|
if (beg < 0) {
|
2020-10-20 20:40:18 +03:00
|
|
|
beg += len;
|
|
|
|
if (beg < 0)
|
|
|
|
goto out_of_range;
|
1999-08-13 09:45:20 +04:00
|
|
|
}
|
2012-11-21 08:23:56 +04:00
|
|
|
if (end < 0)
|
2020-10-20 20:40:18 +03:00
|
|
|
end += len;
|
2012-11-21 08:23:56 +04:00
|
|
|
if (!excl)
|
2020-10-20 20:40:18 +03:00
|
|
|
end++; /* include end point */
|
1999-08-13 09:45:20 +04:00
|
|
|
if (err == 0 || err == 2) {
|
2020-10-20 20:40:18 +03:00
|
|
|
if (beg > len)
|
|
|
|
goto out_of_range;
|
|
|
|
if (end > len)
|
|
|
|
end = len;
|
1999-08-13 09:45:20 +04:00
|
|
|
}
|
|
|
|
len = end - beg;
|
2006-12-31 18:02:22 +03:00
|
|
|
if (len < 0)
|
2020-10-20 20:40:18 +03:00
|
|
|
len = 0;
|
1999-08-13 09:45:20 +04:00
|
|
|
|
|
|
|
*begp = beg;
|
|
|
|
*lenp = len;
|
1999-01-20 07:59:39 +03:00
|
|
|
return Qtrue;
|
1999-08-13 09:45:20 +04:00
|
|
|
|
|
|
|
out_of_range:
|
|
|
|
return Qnil;
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2020-10-20 20:40:18 +03:00
|
|
|
VALUE
|
|
|
|
rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err)
|
|
|
|
{
|
|
|
|
VALUE b, e;
|
|
|
|
int excl;
|
|
|
|
|
|
|
|
if (!rb_range_values(range, &b, &e, &excl))
|
|
|
|
return Qfalse;
|
|
|
|
|
|
|
|
VALUE res = rb_range_component_beg_len(b, e, excl, begp, lenp, len, err);
|
|
|
|
if (NIL_P(res) && err) {
|
|
|
|
rb_raise(rb_eRangeError, "%+"PRIsVALUE" out of range", range);
|
|
|
|
}
|
|
|
|
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2003-12-30 19:38:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.to_s -> string
|
2003-12-30 19:38:32 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Convert this range object to a printable form (using #to_s to convert the
|
|
|
|
* begin and end objects).
|
2003-12-30 19:38:32 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_to_s(VALUE range)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
|
|
|
VALUE str, str2;
|
|
|
|
|
2007-09-08 19:07:18 +04:00
|
|
|
str = rb_obj_as_string(RANGE_BEG(range));
|
|
|
|
str2 = rb_obj_as_string(RANGE_END(range));
|
2000-04-10 09:48:43 +04:00
|
|
|
str = rb_str_dup(str);
|
2006-12-31 18:02:22 +03:00
|
|
|
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
|
2000-04-10 09:48:43 +04:00
|
|
|
rb_str_append(str, str2);
|
1998-01-16 15:13:05 +03:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2008-09-25 19:42:23 +04:00
|
|
|
static VALUE
|
|
|
|
inspect_range(VALUE range, VALUE dummy, int recur)
|
|
|
|
{
|
2018-04-19 18:18:50 +03:00
|
|
|
VALUE str, str2 = Qundef;
|
2008-09-25 19:42:23 +04:00
|
|
|
|
|
|
|
if (recur) {
|
|
|
|
return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)");
|
|
|
|
}
|
2019-05-22 18:45:30 +03:00
|
|
|
if (!NIL_P(RANGE_BEG(range)) || NIL_P(RANGE_END(range))) {
|
|
|
|
str = rb_str_dup(rb_inspect(RANGE_BEG(range)));
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
str = rb_str_new(0, 0);
|
|
|
|
}
|
2008-09-25 19:42:23 +04:00
|
|
|
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
|
2019-05-22 18:45:30 +03:00
|
|
|
if (NIL_P(RANGE_BEG(range)) || !NIL_P(RANGE_END(range))) {
|
|
|
|
str2 = rb_inspect(RANGE_END(range));
|
|
|
|
}
|
2018-04-19 18:18:50 +03:00
|
|
|
if (str2 != Qundef) rb_str_append(str, str2);
|
2008-09-25 19:42:23 +04:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2003-12-30 19:38:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng.inspect -> string
|
2003-12-30 19:38:32 +03:00
|
|
|
*
|
2019-03-28 06:33:35 +03:00
|
|
|
* Convert this range object to a printable form (using #inspect to
|
|
|
|
* convert the begin and end objects).
|
2003-12-30 19:38:32 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_inspect(VALUE range)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2008-09-25 19:42:23 +04:00
|
|
|
return rb_exec_recursive(inspect_range, range, 0);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|
|
|
|
|
2019-07-30 02:22:00 +03:00
|
|
|
static VALUE range_include_internal(VALUE range, VALUE val, int string_use_cover);
|
2018-05-17 13:46:21 +03:00
|
|
|
|
2003-12-24 07:29:32 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-18 01:07:33 +04:00
|
|
|
* rng === obj -> true or false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2019-12-21 23:58:14 +03:00
|
|
|
* Returns <code>true</code> if +obj+ is between begin and end of range,
|
|
|
|
* <code>false</code> otherwise (same as #cover?). Conveniently,
|
|
|
|
* <code>===</code> is the comparison operator used by <code>case</code>
|
|
|
|
* statements.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
* case 79
|
2019-12-21 23:58:14 +03:00
|
|
|
* when 1..50 then puts "low"
|
|
|
|
* when 51..75 then puts "medium"
|
|
|
|
* when 76..100 then puts "high"
|
2003-12-24 07:29:32 +03:00
|
|
|
* end
|
2019-12-21 23:58:14 +03:00
|
|
|
* # Prints "high"
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2019-12-21 23:58:14 +03:00
|
|
|
* case "2.6.5"
|
|
|
|
* when ..."2.4" then puts "EOL"
|
|
|
|
* when "2.4"..."2.5" then puts "maintenance"
|
|
|
|
* when "2.5"..."2.7" then puts "stable"
|
|
|
|
* when "2.7".. then puts "upcoming"
|
|
|
|
* end
|
|
|
|
* # Prints "stable"
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
*/
|
|
|
|
|
2007-07-26 17:37:13 +04:00
|
|
|
static VALUE
|
|
|
|
range_eqq(VALUE range, VALUE val)
|
|
|
|
{
|
2019-07-30 02:22:00 +03:00
|
|
|
VALUE ret = range_include_internal(range, val, 1);
|
2018-05-17 13:46:21 +03:00
|
|
|
if (ret != Qundef) return ret;
|
|
|
|
return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
|
2007-07-26 17:37:13 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2011-12-06 03:36:53 +04:00
|
|
|
* rng.member?(obj) -> true or false
|
|
|
|
* rng.include?(obj) -> true or false
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* Returns <code>true</code> if +obj+ is an element of
|
2019-12-21 23:58:14 +03:00
|
|
|
* the range, <code>false</code> otherwise.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* ("a".."z").include?("g") #=> true
|
|
|
|
* ("a".."z").include?("A") #=> false
|
|
|
|
* ("a".."z").include?("cc") #=> false
|
2019-12-21 23:58:14 +03:00
|
|
|
*
|
|
|
|
* If you need to ensure +obj+ is between +begin+ and +end+, use #cover?
|
|
|
|
*
|
|
|
|
* ("a".."z").cover?("cc") #=> true
|
|
|
|
*
|
|
|
|
* If begin and end are numeric, #include? behaves like #cover?
|
|
|
|
*
|
|
|
|
* (1..3).include?(1.5) # => true
|
2007-07-26 17:37:13 +04:00
|
|
|
*/
|
|
|
|
|
2002-06-11 11:02:23 +04:00
|
|
|
static VALUE
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
range_include(VALUE range, VALUE val)
|
2018-05-17 13:46:21 +03:00
|
|
|
{
|
2019-07-30 02:22:00 +03:00
|
|
|
VALUE ret = range_include_internal(range, val, 0);
|
2018-05-17 13:46:21 +03:00
|
|
|
if (ret != Qundef) return ret;
|
|
|
|
return rb_call_super(1, &val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2019-07-30 02:22:00 +03:00
|
|
|
range_include_internal(VALUE range, VALUE val, int string_use_cover)
|
2002-06-11 11:02:23 +04:00
|
|
|
{
|
2007-09-08 19:07:18 +04:00
|
|
|
VALUE beg = RANGE_BEG(range);
|
|
|
|
VALUE end = RANGE_END(range);
|
2005-12-07 11:41:59 +03:00
|
|
|
int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
|
2015-05-03 04:02:15 +03:00
|
|
|
linear_object_p(beg) || linear_object_p(end);
|
2005-12-07 11:41:59 +03:00
|
|
|
|
2005-12-09 17:17:09 +03:00
|
|
|
if (nv ||
|
|
|
|
!NIL_P(rb_check_to_integer(beg, "to_int")) ||
|
|
|
|
!NIL_P(rb_check_to_integer(end, "to_int"))) {
|
2015-05-15 12:05:57 +03:00
|
|
|
return r_cover_p(range, beg, end, val);
|
2002-06-11 11:02:23 +04:00
|
|
|
}
|
2019-07-30 02:22:00 +03:00
|
|
|
else if (RB_TYPE_P(beg, T_STRING) || RB_TYPE_P(end, T_STRING)) {
|
|
|
|
if (RB_TYPE_P(beg, T_STRING) && RB_TYPE_P(end, T_STRING)) {
|
|
|
|
if (string_use_cover) {
|
|
|
|
return r_cover_p(range, beg, end, val);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
VALUE rb_str_include_range_p(VALUE beg, VALUE end, VALUE val, VALUE exclusive);
|
|
|
|
return rb_str_include_range_p(beg, end, val, RANGE_EXCL(range));
|
|
|
|
}
|
|
|
|
}
|
2019-04-03 11:11:41 +03:00
|
|
|
else if (NIL_P(beg)) {
|
|
|
|
VALUE r = rb_funcall(val, id_cmp, 1, end);
|
|
|
|
if (NIL_P(r)) return Qfalse;
|
|
|
|
if (rb_cmpint(r, val, end) <= 0) return Qtrue;
|
|
|
|
return Qfalse;
|
|
|
|
}
|
2018-04-19 18:18:53 +03:00
|
|
|
else if (NIL_P(end)) {
|
|
|
|
VALUE r = rb_funcall(beg, id_cmp, 1, val);
|
|
|
|
if (NIL_P(r)) return Qfalse;
|
|
|
|
if (rb_cmpint(r, beg, val) <= 0) return Qtrue;
|
|
|
|
return Qfalse;
|
|
|
|
}
|
2008-02-11 20:46:52 +03:00
|
|
|
}
|
2018-05-17 13:46:21 +03:00
|
|
|
return Qundef;
|
2002-06-11 11:02:23 +04:00
|
|
|
}
|
|
|
|
|
2018-09-05 22:06:08 +03:00
|
|
|
static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
|
2003-12-24 07:29:32 +03:00
|
|
|
|
2005-12-12 04:01:29 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-09-05 22:06:08 +03:00
|
|
|
* rng.cover?(obj) -> true or false
|
|
|
|
* rng.cover?(range) -> true or false
|
2011-12-06 03:36:53 +04:00
|
|
|
*
|
|
|
|
* Returns <code>true</code> if +obj+ is between the begin and end of
|
|
|
|
* the range.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+
|
|
|
|
* and <code>begin <= obj < end</code> when #exclude_end? is +true+.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2018-10-13 00:11:54 +03:00
|
|
|
* If called with a Range argument, returns <code>true</code> when the
|
|
|
|
* given range is covered by the receiver,
|
2018-09-05 22:06:08 +03:00
|
|
|
* by comparing the begin and end values. If the argument can be treated as
|
|
|
|
* a sequence, this method treats it that way. In the specific case of
|
|
|
|
* <code>(a..b).cover?(c...d)</code> with <code>a <= c && b < d</code>,
|
2018-10-13 00:11:54 +03:00
|
|
|
* the end of the sequence must be calculated, which may exhibit poor
|
|
|
|
* performance if <code>c</code> is non-numeric.
|
|
|
|
* Returns <code>false</code> if the begin value of the
|
2019-07-24 20:30:56 +03:00
|
|
|
* range is larger than the end value. Also returns +false+ if one of the
|
|
|
|
* internal calls to <code><=></code> returns +nil+ (indicating the objects
|
|
|
|
* are not comparable).
|
2018-09-05 22:06:08 +03:00
|
|
|
*
|
|
|
|
* ("a".."z").cover?("c") #=> true
|
|
|
|
* ("a".."z").cover?("5") #=> false
|
|
|
|
* ("a".."z").cover?("cc") #=> true
|
2019-07-24 20:30:56 +03:00
|
|
|
* ("a".."z").cover?(1) #=> false
|
2018-09-05 22:06:08 +03:00
|
|
|
* (1..5).cover?(2..3) #=> true
|
|
|
|
* (1..5).cover?(0..6) #=> false
|
|
|
|
* (1..5).cover?(1...6) #=> true
|
2005-12-12 04:01:29 +03:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
* sprintf.c (rb_str_format): allow %c to print one character
string (e.g. ?x).
* lib/tempfile.rb (Tempfile::make_tmpname): put dot between
basename and pid. [ruby-talk:196272]
* parse.y (do_block): remove -> style block.
* parse.y (parser_yylex): remove tLAMBDA_ARG.
* eval.c (rb_call0): binding for the return event hook should have
consistent scope. [ruby-core:07928]
* eval.c (proc_invoke): return behavior should depend whether it
is surrounded by a lambda or a mere block.
* eval.c (formal_assign): handles post splat arguments.
* eval.c (rb_call0): ditto.
* st.c (strhash): use FNV-1a hash.
* parse.y (parser_yylex): removed experimental ';;' terminator.
* eval.c (rb_node_arity): should be aware of post splat arguments.
* eval.c (rb_proc_arity): ditto.
* parse.y (f_args): syntax rule enhanced to support arguments
after the splat.
* parse.y (block_param): ditto for block parameters.
* parse.y (f_post_arg): mandatory formal arguments after the splat
argument.
* parse.y (new_args_gen): generate nodes for mandatory formal
arguments after the splat argument.
* eval.c (rb_eval): dispatch mandatory formal arguments after the
splat argument.
* parse.y (args): allow more than one splat in the argument list.
* parse.y (method_call): allow aref [] to accept all kind of
method argument, including assocs, splat, and block argument.
* eval.c (SETUP_ARGS0): prepare block argument as well.
* lib/mathn.rb (Integer): remove Integer#gcd2. [ruby-core:07931]
* eval.c (error_line): print receivers true/false/nil specially.
* eval.c (rb_proc_yield): handles parameters in yield semantics.
* eval.c (nil_yield): gives LocalJumpError to denote no block
error.
* io.c (rb_io_getc): now takes one-character string.
* string.c (rb_str_hash): use FNV-1a hash from Fowler/Noll/Vo
hashing algorithm.
* string.c (rb_str_aref): str[0] now returns 1 character string,
instead of a fixnum. [Ruby2]
* parse.y (parser_yylex): ?c now returns 1 character string,
instead of a fixnum. [Ruby2]
* string.c (rb_str_aset): no longer support fixnum insertion.
* eval.c (umethod_bind): should not update original class.
[ruby-dev:28636]
* eval.c (ev_const_get): should support constant access from
within instance_eval(). [ruby-dev:28327]
* time.c (time_timeval): should round for usec floating
number. [ruby-core:07896]
* time.c (time_add): ditto.
* dir.c (sys_warning): should not call a vararg function
rb_sys_warning() indirectly. [ruby-core:07886]
* numeric.c (flo_divmod): the first element of Float#divmod should
be an integer. [ruby-dev:28589]
* test/ruby/test_float.rb: add tests for divmod, div, modulo and remainder.
* re.c (rb_reg_initialize): should not allow modifying literal
regexps. frozen check moved from rb_reg_initialize_m as well.
* re.c (rb_reg_initialize): should not modify untainted objects in
safe levels higher than 3.
* re.c (rb_memcmp): type change from char* to const void*.
* dir.c (dir_close): should not close untainted dir stream.
* dir.c (GetDIR): add tainted/frozen check for each dir operation.
* lib/rdoc/parsers/parse_rb.rb (RDoc::RubyParser::parse_symbol_arg):
typo fixed. a patch from Florian Gross <florg at florg.net>.
* eval.c (EXEC_EVENT_HOOK): trace_func may remove itself from
event_hooks. no guarantee for arbitrary hook deletion.
[ruby-dev:28632]
* util.c (ruby_strtod): differ addition to minimize error.
[ruby-dev:28619]
* util.c (ruby_strtod): should not raise ERANGE when the input
string does not have any digits. [ruby-dev:28629]
* eval.c (proc_invoke): should restore old ruby_frame->block.
thanks to ts <decoux at moulon.inra.fr>. [ruby-core:07833]
also fix [ruby-dev:28614] as well.
* signal.c (trap): sig should be less then NSIG. Coverity found
this bug. a patch from Kevin Tew <tewk at tewk.com>.
[ruby-core:07823]
* math.c (math_log2): add new method inspired by
[ruby-talk:191237].
* math.c (math_log): add optional base argument to Math::log().
[ruby-talk:191308]
* ext/syck/emitter.c (syck_scan_scalar): avoid accessing
uninitialized array element. a patch from Pat Eyler
<rubypate at gmail.com>. [ruby-core:07809]
* array.c (rb_ary_fill): initialize local variables first. a
patch from Pat Eyler <rubypate at gmail.com>. [ruby-core:07810]
* ext/syck/yaml2byte.c (syck_yaml2byte_handler): need to free
type_tag. a patch from Pat Eyler <rubypate at gmail.com>.
[ruby-core:07808]
* ext/socket/socket.c (make_hostent_internal): accept ai_family
check from Sam Roberts <sroberts at uniserve.com>.
[ruby-core:07691]
* util.c (ruby_strtod): should not cut off 18 digits for no
reason. [ruby-core:07796]
* array.c (rb_ary_fill): internalize local variable "beg" to
pacify Coverity. [ruby-core:07770]
* pack.c (pack_unpack): now supports CRLF newlines. a patch from
<tommy at tmtm.org>. [ruby-dev:28601]
* applied code clean-up patch from Stefan Huehner
<stefan at huehner.org>. [ruby-core:07764]
* lib/jcode.rb (String::tr_s): should have translated non
squeezing character sequence (i.e. a character) as well. thanks
to Hiroshi Ichikawa <gimite at gimite.ddo.jp> [ruby-list:42090]
* ext/socket/socket.c: document update patch from Sam Roberts
<sroberts at uniserve.com>. [ruby-core:07701]
* lib/mathn.rb (Integer): need not to remove gcd2. a patch from
NARUSE, Yui <naruse at airemix.com>. [ruby-dev:28570]
* parse.y (arg): too much NEW_LIST()
* eval.c (SETUP_ARGS0): remove unnecessary access to nd_alen.
* eval.c (rb_eval): use ARGSCAT for NODE_OP_ASGN1.
[ruby-dev:28585]
* parse.y (arg): use NODE_ARGSCAT for placeholder.
* lib/getoptlong.rb (GetoptLong::get): RDoc update patch from
mathew <meta at pobox.com>. [ruby-core:07738]
* variable.c (rb_const_set): raise error when no target klass is
supplied. [ruby-dev:28582]
* prec.c (prec_prec_f): documentation patch from
<gerardo.santana at gmail.com>. [ruby-core:07689]
* bignum.c (rb_big_pow): second operand may be too big even if
it's a Fixnum. [ruby-talk:187984]
* README.EXT: update symbol description. [ruby-talk:188104]
* COPYING: explicitly note GPLv2. [ruby-talk:187922]
* parse.y: remove some obsolete syntax rules (unparenthesized
method calls in argument list).
* eval.c (rb_call0): insecure calling should be checked for non
NODE_SCOPE method invocations too.
* eval.c (rb_alias): should preserve the current safe level as
well as method definition.
* process.c (rb_f_sleep): remove RDoc description about SIGALRM
which is not valid on the current implementation. [ruby-dev:28464]
Thu Mar 23 21:40:47 2006 K.Kosako <sndgk393 AT ybb.ne.jp>
* eval.c (method_missing): should support argument splat in
super. a bug in combination of super, splat and
method_missing. [ruby-talk:185438]
* configure.in: Solaris SunPro compiler -rapth patch from
<kuwa at labs.fujitsu.com>. [ruby-dev:28443]
* configure.in: remove enable_rpath=no for Solaris.
[ruby-dev:28440]
* ext/win32ole/win32ole.c (ole_val2olevariantdata): change behavior
of converting OLE Variant object with VT_ARRAY|VT_UI1 and Ruby
String object.
* ruby.1: a clarification patch from David Lutterkort
<dlutter at redhat.com>. [ruby-core:7508]
* lib/rdoc/ri/ri_paths.rb (RI::Paths): adding paths from rubygems
directories. a patch from Eric Hodel <drbrain at segment7.net>.
[ruby-core:07423]
* eval.c (rb_clear_cache_by_class): clearing wrong cache.
* ext/extmk.rb: use :remove_destination to install extension libraries
to avoid SEGV. [ruby-dev:28417]
* eval.c (rb_thread_fd_writable): should not re-schedule output
from KILLED thread (must be error printing).
* array.c (rb_ary_flatten_bang): allow specifying recursion
level. [ruby-talk:182170]
* array.c (rb_ary_flatten): ditto.
* gc.c (add_heap): a heap_slots may overflow. a patch from Stefan
Weil <weil at mail.berlios.de>.
* eval.c (rb_call): use separate cache for fcall/vcall
invocation.
* eval.c (rb_eval): NODE_FCALL, NODE_VCALL can call local
functions.
* eval.c (rb_mod_local): a new method to specify newly added
visibility "local".
* eval.c (search_method): search for local methods which are
visible only from the current class.
* class.c (rb_class_local_methods): a method to list local methods.
* object.c (Init_Object): add BasicObject class as a top level
BlankSlate class.
* ruby.h (SYM2ID): should not cast to signed long.
[ruby-core:07414]
* class.c (rb_include_module): allow module duplication.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@10235 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2006-06-10 01:20:17 +04:00
|
|
|
range_cover(VALUE range, VALUE val)
|
2005-12-12 04:01:29 +03:00
|
|
|
{
|
|
|
|
VALUE beg, end;
|
|
|
|
|
2007-09-08 19:07:18 +04:00
|
|
|
beg = RANGE_BEG(range);
|
|
|
|
end = RANGE_END(range);
|
2018-09-05 22:06:08 +03:00
|
|
|
|
|
|
|
if (rb_obj_is_kind_of(val, rb_cRange)) {
|
|
|
|
return RBOOL(r_cover_range_p(range, beg, end, val));
|
|
|
|
}
|
2015-05-15 12:05:57 +03:00
|
|
|
return r_cover_p(range, beg, end, val);
|
|
|
|
}
|
|
|
|
|
2018-09-05 22:06:08 +03:00
|
|
|
static VALUE
|
|
|
|
r_call_max(VALUE r)
|
|
|
|
{
|
|
|
|
return rb_funcallv(r, rb_intern("max"), 0, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val)
|
|
|
|
{
|
|
|
|
VALUE val_beg, val_end, val_max;
|
|
|
|
int cmp_end;
|
|
|
|
|
|
|
|
val_beg = RANGE_BEG(val);
|
|
|
|
val_end = RANGE_END(val);
|
|
|
|
|
|
|
|
if (!NIL_P(end) && NIL_P(val_end)) return FALSE;
|
2019-04-03 11:35:57 +03:00
|
|
|
if (!NIL_P(beg) && NIL_P(val_beg)) return FALSE;
|
2020-04-08 07:28:13 +03:00
|
|
|
if (!NIL_P(val_beg) && !NIL_P(val_end) && r_less(val_beg, val_end) > (EXCL(val) ? -1 : 0)) return FALSE;
|
2019-04-03 11:35:57 +03:00
|
|
|
if (!NIL_P(val_beg) && !r_cover_p(range, beg, end, val_beg)) return FALSE;
|
2018-09-05 22:06:08 +03:00
|
|
|
|
|
|
|
cmp_end = r_less(end, val_end);
|
|
|
|
|
|
|
|
if (EXCL(range) == EXCL(val)) {
|
|
|
|
return cmp_end >= 0;
|
2019-01-09 16:58:49 +03:00
|
|
|
}
|
|
|
|
else if (EXCL(range)) {
|
2018-09-05 22:06:08 +03:00
|
|
|
return cmp_end > 0;
|
2019-01-09 16:58:49 +03:00
|
|
|
}
|
|
|
|
else if (cmp_end >= 0) {
|
2018-09-05 22:06:08 +03:00
|
|
|
return TRUE;
|
|
|
|
}
|
2020-09-01 19:19:03 +03:00
|
|
|
|
|
|
|
val_max = rb_rescue2(r_call_max, val, 0, Qnil, rb_eTypeError, (VALUE)0);
|
|
|
|
if (val_max == Qnil) return FALSE;
|
2018-09-05 22:06:08 +03:00
|
|
|
|
|
|
|
return r_less(end, val_max) >= 0;
|
|
|
|
}
|
|
|
|
|
2015-05-15 12:05:57 +03:00
|
|
|
static VALUE
|
|
|
|
r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val)
|
|
|
|
{
|
2019-04-03 11:11:41 +03:00
|
|
|
if (NIL_P(beg) || r_less(beg, val) <= 0) {
|
2015-05-15 12:06:18 +03:00
|
|
|
int excl = EXCL(range);
|
2018-04-19 18:18:53 +03:00
|
|
|
if (NIL_P(end) || r_less(val, end) <= -excl)
|
2015-05-15 12:06:18 +03:00
|
|
|
return Qtrue;
|
2005-12-12 04:01:29 +03:00
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2007-09-08 19:07:18 +04:00
|
|
|
static VALUE
|
|
|
|
range_dumper(VALUE range)
|
|
|
|
{
|
2020-10-29 02:58:17 +03:00
|
|
|
VALUE v = rb_obj_alloc(rb_cObject);
|
2007-09-08 19:07:18 +04:00
|
|
|
|
2007-09-10 10:50:22 +04:00
|
|
|
rb_ivar_set(v, id_excl, RANGE_EXCL(range));
|
2007-09-08 19:07:18 +04:00
|
|
|
rb_ivar_set(v, id_beg, RANGE_BEG(range));
|
2018-06-13 14:00:28 +03:00
|
|
|
rb_ivar_set(v, id_end, RANGE_END(range));
|
2007-09-08 19:07:18 +04:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_loader(VALUE range, VALUE obj)
|
|
|
|
{
|
2016-11-11 14:52:03 +03:00
|
|
|
VALUE beg, end, excl;
|
|
|
|
|
2011-09-29 15:07:45 +04:00
|
|
|
if (!RB_TYPE_P(obj, T_OBJECT) || RBASIC(obj)->klass != rb_cObject) {
|
2007-09-08 19:07:18 +04:00
|
|
|
rb_raise(rb_eTypeError, "not a dumped range object");
|
|
|
|
}
|
|
|
|
|
2013-10-26 14:08:02 +04:00
|
|
|
range_modify(range);
|
2016-11-11 14:52:03 +03:00
|
|
|
beg = rb_ivar_get(obj, id_beg);
|
2018-06-13 14:00:28 +03:00
|
|
|
end = rb_ivar_get(obj, id_end);
|
2016-11-11 14:52:03 +03:00
|
|
|
excl = rb_ivar_get(obj, id_excl);
|
|
|
|
if (!NIL_P(excl)) {
|
|
|
|
range_init(range, beg, end, RBOOL(RTEST(excl)));
|
|
|
|
}
|
2007-09-08 19:07:18 +04:00
|
|
|
return range;
|
|
|
|
}
|
2005-12-12 04:01:29 +03:00
|
|
|
|
2007-11-23 10:00:50 +03:00
|
|
|
static VALUE
|
|
|
|
range_alloc(VALUE klass)
|
|
|
|
{
|
2016-11-10 03:49:16 +03:00
|
|
|
/* rb_struct_alloc_noinit itself should not be used because
|
|
|
|
* rb_marshal_define_compat uses equality of allocation function */
|
2007-11-23 10:00:50 +03:00
|
|
|
return rb_struct_alloc_noinit(klass);
|
|
|
|
}
|
|
|
|
|
2019-12-04 09:31:51 +03:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* range.count -> int
|
|
|
|
* range.count(item) -> int
|
|
|
|
* range.count { |obj| block } -> int
|
|
|
|
*
|
|
|
|
* Identical to Enumerable#count, except it returns Infinity for endless
|
|
|
|
* ranges.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
range_count(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
|
|
|
if (argc != 0) {
|
2019-12-20 03:19:39 +03:00
|
|
|
/* It is odd for instance (1...).count(0) to return Infinity. Just let
|
2019-12-04 09:31:51 +03:00
|
|
|
* it loop. */
|
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
else if (rb_block_given_p()) {
|
2019-12-20 03:19:39 +03:00
|
|
|
/* Likewise it is odd for instance (1...).count {|x| x == 0 } to return
|
2019-12-04 09:31:51 +03:00
|
|
|
* Infinity. Just let it loop. */
|
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
else if (NIL_P(RANGE_END(range))) {
|
|
|
|
/* We are confident that the answer is Infinity. */
|
|
|
|
return DBL2NUM(HUGE_VAL);
|
|
|
|
}
|
|
|
|
else if (NIL_P(RANGE_BEG(range))) {
|
|
|
|
/* We are confident that the answer is Infinity. */
|
|
|
|
return DBL2NUM(HUGE_VAL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-28 06:33:35 +03:00
|
|
|
/* A Range represents an interval---a set of values with a
|
2011-12-06 03:36:53 +04:00
|
|
|
* beginning and an end. Ranges may be constructed using the
|
2003-12-24 07:29:32 +03:00
|
|
|
* <em>s</em><code>..</code><em>e</em> and
|
|
|
|
* <em>s</em><code>...</code><em>e</em> literals, or with
|
2011-12-06 03:36:53 +04:00
|
|
|
* Range::new. Ranges constructed using <code>..</code>
|
|
|
|
* run from the beginning to the end inclusively. Those created using
|
2003-12-24 07:29:32 +03:00
|
|
|
* <code>...</code> exclude the end value. When used as an iterator,
|
|
|
|
* ranges return each value in the sequence.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
* (-1..-5).to_a #=> []
|
|
|
|
* (-5..-1).to_a #=> [-5, -4, -3, -2, -1]
|
|
|
|
* ('a'..'e').to_a #=> ["a", "b", "c", "d", "e"]
|
|
|
|
* ('a'...'e').to_a #=> ["a", "b", "c", "d"]
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2019-04-03 11:11:41 +03:00
|
|
|
* == Beginless/Endless Ranges
|
|
|
|
*
|
|
|
|
* A "beginless range" and "endless range" represents a semi-infinite
|
|
|
|
* range. Literal notation for a beginless range is:
|
|
|
|
*
|
|
|
|
* (..1)
|
|
|
|
* # or
|
|
|
|
* (...1)
|
2018-12-12 22:49:22 +03:00
|
|
|
*
|
|
|
|
* Literal notation for an endless range is:
|
|
|
|
*
|
|
|
|
* (1..)
|
|
|
|
* # or similarly
|
|
|
|
* (1...)
|
|
|
|
*
|
|
|
|
* Which is equivalent to
|
|
|
|
*
|
|
|
|
* (1..nil) # or similarly (1...nil)
|
|
|
|
* Range.new(1, nil) # or Range.new(1, nil, true)
|
|
|
|
*
|
2019-04-03 11:11:41 +03:00
|
|
|
* Beginless/endless ranges are useful, for example, for idiomatic
|
|
|
|
* slicing of arrays:
|
2018-12-12 22:49:22 +03:00
|
|
|
*
|
2019-04-03 11:11:41 +03:00
|
|
|
* [1, 2, 3, 4, 5][...2] # => [1, 2]
|
2018-12-12 22:49:22 +03:00
|
|
|
* [1, 2, 3, 4, 5][2...] # => [3, 4, 5]
|
|
|
|
*
|
|
|
|
* Some implementation details:
|
|
|
|
*
|
2019-04-03 11:11:41 +03:00
|
|
|
* * +begin+ of beginless range and +end+ of endless range are +nil+;
|
|
|
|
* * +each+ of beginless range raises an exception;
|
2018-12-12 22:49:22 +03:00
|
|
|
* * +each+ of endless range enumerates infinite sequence (may be
|
|
|
|
* useful in combination with Enumerable#take_while or similar
|
|
|
|
* methods);
|
|
|
|
* * <code>(1..)</code> and <code>(1...)</code> are not equal,
|
|
|
|
* although technically representing the same sequence.
|
|
|
|
*
|
2011-12-06 03:36:53 +04:00
|
|
|
* == Custom Objects in Ranges
|
|
|
|
*
|
|
|
|
* Ranges can be constructed using any objects that can be compared
|
|
|
|
* using the <code><=></code> operator.
|
|
|
|
* Methods that treat the range as a sequence (#each and methods inherited
|
|
|
|
* from Enumerable) expect the begin object to implement a
|
|
|
|
* <code>succ</code> method to return the next object in sequence.
|
|
|
|
* The #step and #include? methods require the begin
|
|
|
|
* object to implement <code>succ</code> or to be numeric.
|
|
|
|
*
|
|
|
|
* In the <code>Xs</code> class below both <code><=></code> and
|
|
|
|
* <code>succ</code> are implemented so <code>Xs</code> can be used
|
|
|
|
* to construct ranges. Note that the Comparable module is included
|
|
|
|
* so the <code>==</code> method is defined in terms of <code><=></code>.
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
* class Xs # represent a string of 'x's
|
|
|
|
* include Comparable
|
|
|
|
* attr :length
|
|
|
|
* def initialize(n)
|
|
|
|
* @length = n
|
|
|
|
* end
|
|
|
|
* def succ
|
|
|
|
* Xs.new(@length + 1)
|
|
|
|
* end
|
|
|
|
* def <=>(other)
|
|
|
|
* @length <=> other.length
|
|
|
|
* end
|
|
|
|
* def to_s
|
|
|
|
* sprintf "%2d #{inspect}", @length
|
|
|
|
* end
|
|
|
|
* def inspect
|
|
|
|
* 'x' * @length
|
|
|
|
* end
|
|
|
|
* end
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2012-03-03 07:29:01 +04:00
|
|
|
* An example of using <code>Xs</code> to construct a range:
|
2011-12-06 03:36:53 +04:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
* r = Xs.new(3)..Xs.new(6) #=> xxx..xxxxxx
|
|
|
|
* r.to_a #=> [xxx, xxxx, xxxxx, xxxxxx]
|
|
|
|
* r.member?(Xs.new(5)) #=> true
|
2009-02-22 17:23:33 +03:00
|
|
|
*
|
2003-12-24 07:29:32 +03:00
|
|
|
*/
|
|
|
|
|
1998-01-16 15:13:05 +03:00
|
|
|
void
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 14:44:21 +04:00
|
|
|
Init_Range(void)
|
1998-01-16 15:13:05 +03:00
|
|
|
{
|
2020-09-25 20:56:30 +03:00
|
|
|
id_beg = rb_intern_const("begin");
|
|
|
|
id_end = rb_intern_const("end");
|
|
|
|
id_excl = rb_intern_const("excl");
|
2007-09-08 19:07:18 +04:00
|
|
|
|
2007-11-23 10:00:50 +03:00
|
|
|
rb_cRange = rb_struct_define_without_accessor(
|
|
|
|
"Range", rb_cObject, range_alloc,
|
2007-11-23 07:35:53 +03:00
|
|
|
"begin", "end", "excl", NULL);
|
2007-09-08 19:07:18 +04:00
|
|
|
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_include_module(rb_cRange, rb_mEnumerable);
|
2007-09-08 19:07:18 +04:00
|
|
|
rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader);
|
2000-02-29 11:05:32 +03:00
|
|
|
rb_define_method(rb_cRange, "initialize", range_initialize, -1);
|
2008-08-21 01:02:54 +04:00
|
|
|
rb_define_method(rb_cRange, "initialize_copy", range_initialize_copy, 1);
|
2000-11-27 12:23:38 +03:00
|
|
|
rb_define_method(rb_cRange, "==", range_eq, 1);
|
2007-07-26 17:37:13 +04:00
|
|
|
rb_define_method(rb_cRange, "===", range_eqq, 1);
|
2001-11-08 12:21:59 +03:00
|
|
|
rb_define_method(rb_cRange, "eql?", range_eql, 1);
|
|
|
|
rb_define_method(rb_cRange, "hash", range_hash, 0);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cRange, "each", range_each, 0);
|
2001-08-14 12:13:31 +04:00
|
|
|
rb_define_method(rb_cRange, "step", range_step, -1);
|
2018-09-28 05:18:58 +03:00
|
|
|
rb_define_method(rb_cRange, "%", range_percent_step, 1);
|
2012-11-14 19:53:50 +04:00
|
|
|
rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
|
2007-10-18 10:58:35 +04:00
|
|
|
rb_define_method(rb_cRange, "begin", range_begin, 0);
|
2007-10-18 12:14:21 +04:00
|
|
|
rb_define_method(rb_cRange, "end", range_end, 0);
|
2007-10-18 10:58:35 +04:00
|
|
|
rb_define_method(rb_cRange, "first", range_first, -1);
|
|
|
|
rb_define_method(rb_cRange, "last", range_last, -1);
|
2014-02-14 19:45:11 +04:00
|
|
|
rb_define_method(rb_cRange, "min", range_min, -1);
|
|
|
|
rb_define_method(rb_cRange, "max", range_max, -1);
|
2019-06-08 08:03:02 +03:00
|
|
|
rb_define_method(rb_cRange, "minmax", range_minmax, 0);
|
2012-11-06 21:14:46 +04:00
|
|
|
rb_define_method(rb_cRange, "size", range_size, 0);
|
2018-06-22 05:58:37 +03:00
|
|
|
rb_define_method(rb_cRange, "to_a", range_to_a, 0);
|
|
|
|
rb_define_method(rb_cRange, "entries", range_to_a, 0);
|
1999-01-20 07:59:39 +03:00
|
|
|
rb_define_method(rb_cRange, "to_s", range_to_s, 0);
|
|
|
|
rb_define_method(rb_cRange, "inspect", range_inspect, 0);
|
|
|
|
|
1999-08-13 09:45:20 +04:00
|
|
|
rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
|
|
|
|
|
2004-10-19 14:25:23 +04:00
|
|
|
rb_define_method(rb_cRange, "member?", range_include, 1);
|
2002-06-11 11:02:23 +04:00
|
|
|
rb_define_method(rb_cRange, "include?", range_include, 1);
|
2005-12-12 04:01:29 +03:00
|
|
|
rb_define_method(rb_cRange, "cover?", range_cover, 1);
|
2019-12-04 09:31:51 +03:00
|
|
|
rb_define_method(rb_cRange, "count", range_count, -1);
|
1998-01-16 15:13:05 +03:00
|
|
|
}
|