2000-05-01 05:42:38 -04:00
|
|
|
/**********************************************************************
|
1998-01-16 07:13:05 -05: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-24 23:29:39 -04:00
|
|
|
Copyright (C) 1993-2007 Yukihiro Matsumoto
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2000-05-01 05:42:38 -04:00
|
|
|
**********************************************************************/
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2020-05-08 05:31:09 -04:00
|
|
|
#include "ruby/internal/config.h"
|
2019-12-04 03:16:30 -05:00
|
|
|
|
2019-01-05 19:46:36 -05:00
|
|
|
#include <assert.h>
|
2019-12-04 03:16:30 -05:00
|
|
|
#include <math.h>
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2012-11-14 10:53:50 -05:00
|
|
|
#ifdef HAVE_FLOAT_H
|
|
|
|
#include <float.h>
|
|
|
|
#endif
|
2019-12-04 03:16:30 -05: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 10:53:50 -05:00
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
VALUE rb_cRange;
|
2018-04-19 11:19:00 -04:00
|
|
|
static ID id_beg, id_end, id_excl;
|
2015-05-01 18:39:14 -04:00
|
|
|
#define id_cmp idCmp
|
|
|
|
#define id_succ idSucc
|
2020-07-04 13:12:02 -04:00
|
|
|
#define id_min idMin
|
|
|
|
#define id_max idMax
|
1999-08-13 01:45:20 -04:00
|
|
|
|
2015-05-15 05:05:57 -04:00
|
|
|
static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
|
|
|
|
|
2013-10-25 01: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))
|
2007-09-08 11:07:18 -04:00
|
|
|
|
|
|
|
#define EXCL(r) RTEST(RANGE_EXCL(r))
|
|
|
|
|
2000-02-29 03:05:32 -05:00
|
|
|
static void
|
2013-10-25 02:57:20 -04:00
|
|
|
range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
2019-04-03 04:11:41 -04:00
|
|
|
if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) {
|
2005-08-14 11:39:39 -04:00
|
|
|
VALUE v;
|
|
|
|
|
2017-04-25 07:42:43 -04:00
|
|
|
v = rb_funcall(beg, id_cmp, 1, end);
|
2006-12-31 10:02:22 -05:00
|
|
|
if (NIL_P(v))
|
2017-04-25 07:42:43 -04:00
|
|
|
rb_raise(rb_eArgError, "bad value for range");
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
2013-10-25 02:57:20 -04:00
|
|
|
RANGE_SET_EXCL(range, exclude_end);
|
2013-10-25 01:18:26 -04:00
|
|
|
RANGE_SET_BEG(range, beg);
|
2018-06-13 07:00:28 -04:00
|
|
|
RANGE_SET_END(range, end);
|
2020-09-25 05:05:55 -04:00
|
|
|
|
|
|
|
if (CLASS_OF(range) == rb_cRange) {
|
|
|
|
rb_obj_freeze(range);
|
|
|
|
}
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2018-06-13 07:00:28 -04:00
|
|
|
rb_range_new(VALUE beg, VALUE end, int exclude_end)
|
1999-08-13 01:45:20 -04:00
|
|
|
{
|
2002-06-11 03:02:23 -04:00
|
|
|
VALUE range = rb_obj_alloc(rb_cRange);
|
2000-02-29 03:05:32 -05:00
|
|
|
|
2018-06-13 07:00:28 -04:00
|
|
|
range_init(range, beg, end, RBOOL(exclude_end));
|
2002-06-11 03:02:23 -04:00
|
|
|
return range;
|
1999-08-13 01:45:20 -04:00
|
|
|
}
|
|
|
|
|
2013-10-26 06:08:02 -04:00
|
|
|
static void
|
|
|
|
range_modify(VALUE range)
|
|
|
|
{
|
2016-11-10 05:39:51 -05:00
|
|
|
rb_check_frozen(range);
|
2013-10-26 06:08:02 -04:00
|
|
|
/* Ranges are immutable, so that they should be initialized only once. */
|
|
|
|
if (RANGE_EXCL(range) != Qnil) {
|
2015-10-28 02:24:12 -04:00
|
|
|
rb_name_err_raise("`initialize' called twice", range, ID2SYM(idInitialize));
|
2013-10-26 06:08:02 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-23 23:29:32 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 15:00:39 -04:00
|
|
|
* Range.new(begin, end, exclude_end = false) -> new_range
|
|
|
|
*
|
|
|
|
* Returns a new range based on the given objects +begin+ and +end+.
|
|
|
|
* Optional argument +exclude_end+ determines whether object +end+
|
|
|
|
* is included as the last object in the range:
|
|
|
|
*
|
|
|
|
* Range.new(2, 5).to_a # => [2, 3, 4, 5]
|
|
|
|
* Range.new(2, 5, true).to_a # => [2, 3, 4]
|
|
|
|
* Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
|
|
|
|
* Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
1999-08-13 01: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 06:44:21 -04:00
|
|
|
range_initialize(int argc, VALUE *argv, VALUE range)
|
1999-08-13 01:45:20 -04:00
|
|
|
{
|
2001-02-02 06:38:20 -05:00
|
|
|
VALUE beg, end, flags;
|
2009-02-22 09:23:33 -05:00
|
|
|
|
2001-02-02 06:38:20 -05:00
|
|
|
rb_scan_args(argc, argv, "21", &beg, &end, &flags);
|
2013-10-26 06:08:02 -04:00
|
|
|
range_modify(range);
|
2013-10-25 02:57:20 -04:00
|
|
|
range_init(range, beg, end, RBOOL(RTEST(flags)));
|
2000-02-29 03:05:32 -05:00
|
|
|
return Qnil;
|
1999-08-13 01:45:20 -04:00
|
|
|
}
|
|
|
|
|
2013-10-26 06: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-23 23:29:32 -05:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 15:00:39 -04:00
|
|
|
* exclude_end? -> true or false
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* Returns +true+ if +self+ excludes its end value; +false+ otherwise:
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* Range.new(2, 5).exclude_end? # => false
|
|
|
|
* Range.new(2, 5, true).exclude_end? # => true
|
|
|
|
* (2..5).exclude_end? # => false
|
|
|
|
* (2...5).exclude_end? # => true
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
1999-08-13 01: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 06:44:21 -04:00
|
|
|
range_exclude_end_p(VALUE range)
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
2021-08-01 23:06:44 -04:00
|
|
|
return RBOOL(EXCL(range));
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
2009-09-19 22: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;
|
|
|
|
|
2021-08-01 23:06:44 -04:00
|
|
|
return RBOOL(EXCL(range) == EXCL(obj));
|
2009-09-19 22:14:02 -04:00
|
|
|
}
|
|
|
|
|
2003-12-23 23:29:32 -05:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 15:00:39 -04:00
|
|
|
* self == other -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if and only if:
|
|
|
|
*
|
|
|
|
* - +other+ is a range.
|
|
|
|
* - <tt>other.begin == self.begin</tt>.
|
|
|
|
* - <tt>other.end == self.end</tt>.
|
2021-09-23 19:08:49 -04:00
|
|
|
* - <tt>other.exclude_end? == self.exclude_end?</tt>.
|
2021-09-13 15:00:39 -04:00
|
|
|
*
|
|
|
|
* Otherwise returns +false+.
|
|
|
|
*
|
|
|
|
* r = (1..5)
|
|
|
|
* r == (1..5) # => true
|
|
|
|
* r = Range.new(1, 5)
|
|
|
|
* r == 'foo' # => false
|
|
|
|
* r == (2..5) # => false
|
|
|
|
* r == (1..4) # => false
|
|
|
|
* r == (1...5) # => false
|
|
|
|
* r == Range.new(1, 5, true) # => false
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* Note that even with the same argument, the return values of #== and #eql? can differ:
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* (1..2) == (1..2.0) # => true
|
|
|
|
* (1..2).eql? (1..2.0) # => false
|
|
|
|
*
|
|
|
|
* Related: Range#eql?.
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
2000-11-27 04:23:38 -05: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 06:44:21 -04:00
|
|
|
range_eq(VALUE range, VALUE obj)
|
2000-11-27 04:23:38 -05:00
|
|
|
{
|
2006-12-31 10:02:22 -05:00
|
|
|
if (range == obj)
|
|
|
|
return Qtrue;
|
2009-08-05 01:01:12 -04:00
|
|
|
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
2002-09-03 01:20:14 -04:00
|
|
|
return Qfalse;
|
2000-11-27 04:23:38 -05:00
|
|
|
|
2009-09-19 22:14:02 -04:00
|
|
|
return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
|
2000-11-27 04:23:38 -05:00
|
|
|
}
|
|
|
|
|
2015-05-15 05:06:18 -04:00
|
|
|
/* compares _a_ and _b_ and returns:
|
|
|
|
* < 0: a < b
|
|
|
|
* = 0: a = b
|
2015-05-15 08:39:56 -04:00
|
|
|
* > 0: a > b or non-comparable
|
2015-05-15 05:06:18 -04:00
|
|
|
*/
|
2001-05-30 05:12:34 -04:00
|
|
|
static int
|
2015-05-15 05:06:18 -04:00
|
|
|
r_less(VALUE a, VALUE b)
|
2001-05-30 05:12:34 -04:00
|
|
|
{
|
|
|
|
VALUE r = rb_funcall(a, id_cmp, 1, b);
|
|
|
|
|
2006-12-31 10:02:22 -05:00
|
|
|
if (NIL_P(r))
|
2015-05-15 05:06:18 -04:00
|
|
|
return INT_MAX;
|
|
|
|
return rb_cmpint(r, a, b);
|
2001-05-30 05:12:34 -04:00
|
|
|
}
|
|
|
|
|
2009-09-19 22: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;
|
|
|
|
|
2021-08-01 23:06:44 -04:00
|
|
|
return RBOOL(EXCL(range) == EXCL(obj));
|
2009-09-19 22:14:02 -04:00
|
|
|
}
|
|
|
|
|
2003-12-23 23:29:32 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 15:00:39 -04:00
|
|
|
* eql?(other) -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if and only if:
|
|
|
|
*
|
|
|
|
* - +other+ is a range.
|
|
|
|
* - <tt>other.begin eql? self.begin</tt>.
|
|
|
|
* - <tt>other.end eql? self.end</tt>.
|
2021-09-23 19:08:49 -04:00
|
|
|
* - <tt>other.exclude_end? == self.exclude_end?</tt>.
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* Otherwise returns +false+.
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* r = (1..5)
|
|
|
|
* r.eql?(1..5) # => true
|
|
|
|
* r = Range.new(1, 5)
|
|
|
|
* r.eql?('foo') # => false
|
|
|
|
* r.eql?(2..5) # => false
|
|
|
|
* r.eql?(1..4) # => false
|
|
|
|
* r.eql?(1...5) # => false
|
|
|
|
* r.eql?(Range.new(1, 5, true)) # => false
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* Note that even with the same argument, the return values of #== and #eql? can differ:
|
|
|
|
*
|
|
|
|
* (1..2) == (1..2.0) # => true
|
|
|
|
* (1..2).eql? (1..2.0) # => false
|
|
|
|
*
|
|
|
|
* Related: Range#==.
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
2001-11-08 04:21:59 -05: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 06:44:21 -04:00
|
|
|
range_eql(VALUE range, VALUE obj)
|
2001-11-08 04:21:59 -05:00
|
|
|
{
|
2006-12-31 10:02:22 -05:00
|
|
|
if (range == obj)
|
|
|
|
return Qtrue;
|
2009-08-05 01:01:12 -04:00
|
|
|
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
2002-09-03 01:20:14 -04:00
|
|
|
return Qfalse;
|
2009-09-19 22:14:02 -04:00
|
|
|
return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
|
2001-11-08 04:21:59 -05:00
|
|
|
}
|
|
|
|
|
2009-07-17 05:28:46 -04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 15:00:39 -04:00
|
|
|
* hash -> integer
|
2009-07-17 05:28:46 -04:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* Returns the integer hash value for +self+.
|
|
|
|
* Two range objects +r0+ and +r1+ have the same hash value
|
|
|
|
* if and only if <tt>r0.eql?(r1)</tt>.
|
2014-03-13 21:27:43 -04:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* Related: Range#eql?, Object#hash.
|
2009-07-17 05:28:46 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_hash(VALUE range)
|
|
|
|
{
|
2013-12-03 08:18:30 -05: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-07 23:26:29 -04:00
|
|
|
return ST2FIX(hash);
|
2009-07-17 05:28:46 -04:00
|
|
|
}
|
|
|
|
|
2002-05-30 02:12:29 -04:00
|
|
|
static void
|
2018-04-28 07:16:54 -04:00
|
|
|
range_each_func(VALUE range, int (*func)(VALUE, VALUE), VALUE arg)
|
2002-05-30 02:12:29 -04:00
|
|
|
{
|
2004-05-14 12:39:15 -04:00
|
|
|
int c;
|
2008-04-06 13:11:50 -04:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
VALUE e = RANGE_END(range);
|
2008-04-06 23:15:26 -04:00
|
|
|
VALUE v = b;
|
2004-05-14 12:39:15 -04:00
|
|
|
|
2002-05-30 02:12:29 -04:00
|
|
|
if (EXCL(range)) {
|
2015-05-15 05:06:18 -04:00
|
|
|
while (r_less(v, e) < 0) {
|
2018-04-28 07:16:54 -04:00
|
|
|
if ((*func)(v, arg)) break;
|
2015-02-15 23:08:52 -05:00
|
|
|
v = rb_funcallv(v, id_succ, 0, 0);
|
2002-05-30 02:12:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-05-15 05:06:18 -04:00
|
|
|
while ((c = r_less(v, e)) <= 0) {
|
2018-08-20 11:33:59 -04:00
|
|
|
if ((*func)(v, arg)) break;
|
2015-05-15 05:06:18 -04:00
|
|
|
if (!c) break;
|
2015-02-15 23:08:52 -05:00
|
|
|
v = rb_funcallv(v, id_succ, 0, 0);
|
2002-05-30 02:12:29 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-09 22:41:26 -04:00
|
|
|
static bool
|
2021-10-09 22:40:04 -04:00
|
|
|
step_i_iter(VALUE arg)
|
2009-08-17 13:00:47 -04:00
|
|
|
{
|
2013-11-28 21:26:48 -05:00
|
|
|
VALUE *iter = (VALUE *)arg;
|
2009-08-17 13: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));
|
|
|
|
}
|
2021-10-09 22:41:26 -04:00
|
|
|
if (iter[0] != INT2FIX(0)) return false;
|
|
|
|
iter[0] = iter[1];
|
|
|
|
return true;
|
2021-10-09 22:40:04 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
sym_step_i(VALUE i, VALUE arg)
|
|
|
|
{
|
2021-10-09 22:41:26 -04:00
|
|
|
if (step_i_iter(arg)) {
|
2009-08-17 13:00:47 -04:00
|
|
|
rb_yield(rb_str_intern(i));
|
|
|
|
}
|
2018-04-28 07:16:54 -04:00
|
|
|
return 0;
|
2009-08-17 13:00:47 -04:00
|
|
|
}
|
|
|
|
|
2018-04-28 07:16:54 -04:00
|
|
|
static int
|
|
|
|
step_i(VALUE i, VALUE arg)
|
2004-10-06 03:40:06 -04:00
|
|
|
{
|
2021-10-09 22:41:26 -04:00
|
|
|
if (step_i_iter(arg)) {
|
2004-10-06 03:40:06 -04:00
|
|
|
rb_yield(i);
|
|
|
|
}
|
2018-04-28 07:16:54 -04:00
|
|
|
return 0;
|
2004-10-06 03:40:06 -04:00
|
|
|
}
|
|
|
|
|
2009-09-30 04:32:43 -04:00
|
|
|
static int
|
2009-10-02 11:31:05 -04:00
|
|
|
discrete_object_p(VALUE obj)
|
2009-09-30 04:32:43 -04:00
|
|
|
{
|
2009-10-02 11:31:05 -04:00
|
|
|
return rb_respond_to(obj, id_succ);
|
2009-09-30 04:32:43 -04:00
|
|
|
}
|
|
|
|
|
2015-05-02 21:02:15 -04: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 02:13:37 -04:00
|
|
|
default:
|
|
|
|
break;
|
2015-05-02 21:02:15 -04: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 12:15:00 -05:00
|
|
|
static VALUE
|
2016-07-25 08:33:15 -04:00
|
|
|
check_step_domain(VALUE step)
|
2012-11-06 12:15:00 -05:00
|
|
|
{
|
2016-07-25 08:33:15 -04:00
|
|
|
VALUE zero = INT2FIX(0);
|
|
|
|
int cmp;
|
|
|
|
if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
|
|
|
|
step = rb_to_int(step);
|
2012-11-06 12:15:00 -05:00
|
|
|
}
|
2016-07-25 08:33:15 -04:00
|
|
|
cmp = rb_cmpint(rb_funcallv(step, idCmp, 1, &zero), step, zero);
|
|
|
|
if (cmp < 0) {
|
2012-11-06 12:15:00 -05:00
|
|
|
rb_raise(rb_eArgError, "step can't be negative");
|
|
|
|
}
|
2016-07-25 08:33:15 -04:00
|
|
|
else if (cmp == 0) {
|
2012-11-06 12:15:00 -05:00
|
|
|
rb_raise(rb_eArgError, "step can't be 0");
|
|
|
|
}
|
2016-07-25 08:33:15 -04: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 12:15:00 -05:00
|
|
|
|
|
|
|
if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
|
2013-03-06 01:30:03 -05:00
|
|
|
return ruby_num_interval_step_size(b, e, step, EXCL(range));
|
2012-11-06 12:15:00 -05:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
2009-09-30 04:32:43 -04:00
|
|
|
|
2003-12-23 23:29:32 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 15:00:39 -04:00
|
|
|
* step(n = 1) {|element| ... } -> self
|
|
|
|
* step(n = 1) -> enumerator
|
|
|
|
*
|
|
|
|
* Iterates over the elements of +self+.
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* With a block given and no argument,
|
|
|
|
* calls the block each element of the range; returns +self+:
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* a = []
|
|
|
|
* (1..5).step {|element| a.push(element) } # => 1..5
|
|
|
|
* a # => [1, 2, 3, 4, 5]
|
|
|
|
* a = []
|
|
|
|
* ('a'..'e').step {|element| a.push(element) } # => "a".."e"
|
|
|
|
* a # => ["a", "b", "c", "d", "e"]
|
2010-05-13 01:49:55 -04:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* With a block given and a positive integer argument +n+ given,
|
|
|
|
* calls the block with element +0+, element +n+, element <tt>2n</tt>, and so on:
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* a = []
|
|
|
|
* (1..5).step(2) {|element| a.push(element) } # => 1..5
|
|
|
|
* a # => [1, 3, 5]
|
|
|
|
* a = []
|
|
|
|
* ('a'..'e').step(2) {|element| a.push(element) } # => "a".."e"
|
|
|
|
* a # => ["a", "c", "e"]
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* With no block given, returns an enumerator,
|
|
|
|
* which will be of class Enumerator::ArithmeticSequence if +self+ is numeric;
|
|
|
|
* otherwise of class Enumerator:
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2021-09-13 15:00:39 -04:00
|
|
|
* e = (1..5).step(2) # => ((1..5).step(2))
|
|
|
|
* e.class # => Enumerator::ArithmeticSequence
|
|
|
|
* ('a'..'e').step # => #<Enumerator: ...>
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2021-09-22 15:51:11 -04:00
|
|
|
* Related: Range#%.
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
2001-08-14 04: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 06:44:21 -04:00
|
|
|
range_step(int argc, VALUE *argv, VALUE range)
|
2001-08-14 04:13:31 -04:00
|
|
|
{
|
2008-04-06 23:15:26 -04:00
|
|
|
VALUE b, e, step, tmp;
|
2001-08-14 04:13:31 -04:00
|
|
|
|
2007-09-08 11:07:18 -04:00
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2018-12-06 02:49:24 -05:00
|
|
|
step = (!rb_check_arity(argc, 0, 1) ? INT2FIX(1) : argv[0]);
|
2008-04-06 13:11:50 -04:00
|
|
|
|
2018-08-06 05:08:28 -04:00
|
|
|
if (!rb_block_given_p()) {
|
2020-10-23 02:26:51 -04: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-03 23:34:52 -04: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 05:08:28 -04: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);
|
2021-10-09 22:45:50 -04:00
|
|
|
VALUE iter[2] = {INT2FIX(1), step};
|
2018-08-06 05:08:28 -04:00
|
|
|
|
2018-04-19 11:18:50 -04:00
|
|
|
if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
|
|
|
|
long i = FIX2LONG(b), unit = FIX2LONG(step);
|
2018-04-19 20:10:46 -04:00
|
|
|
do {
|
2018-04-19 11:18:50 -04:00
|
|
|
rb_yield(LONG2FIX(i));
|
2018-04-19 20:10:46 -04:00
|
|
|
i += unit; /* FIXABLE+FIXABLE never overflow */
|
|
|
|
} while (FIXABLE(i));
|
2018-04-19 11:18:50 -04:00
|
|
|
b = LONG2NUM(i);
|
|
|
|
|
2018-04-19 20:23:01 -04:00
|
|
|
for (;; b = rb_big_plus(b, step))
|
2018-04-19 11:18:50 -04:00
|
|
|
rb_yield(b);
|
|
|
|
}
|
|
|
|
else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
|
2002-05-30 02:12:29 -04:00
|
|
|
long end = FIX2LONG(e);
|
2008-05-02 03:15:28 -04:00
|
|
|
long i, unit = FIX2LONG(step);
|
2002-05-30 02:12:29 -04:00
|
|
|
|
2006-12-31 10:02:22 -05:00
|
|
|
if (!EXCL(range))
|
|
|
|
end += 1;
|
2009-02-22 09:23:33 -05:00
|
|
|
i = FIX2LONG(b);
|
2007-09-09 12:11:28 -04:00
|
|
|
while (i < end) {
|
2002-08-21 11:47:54 -04:00
|
|
|
rb_yield(LONG2NUM(i));
|
2007-09-09 12:11:28 -04:00
|
|
|
if (i + unit < i) break;
|
|
|
|
i += unit;
|
2001-08-14 04:13:31 -04:00
|
|
|
}
|
2008-04-06 13:11:50 -04:00
|
|
|
|
|
|
|
}
|
2018-04-19 11:18:50 -04:00
|
|
|
else if (SYMBOL_P(b) && (NIL_P(e) || SYMBOL_P(e))) { /* symbols are special */
|
2018-04-28 07:16:54 -04:00
|
|
|
b = rb_sym2str(b);
|
2018-04-19 11:18:50 -04:00
|
|
|
if (NIL_P(e)) {
|
2018-04-28 07:16:54 -04:00
|
|
|
rb_str_upto_endless_each(b, sym_step_i, (VALUE)iter);
|
2018-04-19 11:18:50 -04:00
|
|
|
}
|
|
|
|
else {
|
2018-04-28 07:16:54 -04:00
|
|
|
rb_str_upto_each(b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
|
2018-04-19 11:18:50 -04:00
|
|
|
}
|
2009-08-17 13:00:47 -04:00
|
|
|
}
|
2018-04-19 11:18:50 -04:00
|
|
|
else if (ruby_float_step(b, e, step, EXCL(range), TRUE)) {
|
2009-01-03 21:58:45 -05:00
|
|
|
/* done */
|
|
|
|
}
|
2008-04-06 13: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 04:57:47 -05:00
|
|
|
ID op = EXCL(range) ? '<' : idLE;
|
2009-01-04 18:20:39 -05:00
|
|
|
VALUE v = b;
|
|
|
|
int i = 0;
|
2008-04-06 13:11:50 -04:00
|
|
|
|
2018-04-19 11:18:50 -04:00
|
|
|
while (NIL_P(e) || RTEST(rb_funcall(v, op, 1, e))) {
|
2009-01-04 18:20:39 -05:00
|
|
|
rb_yield(v);
|
|
|
|
i++;
|
|
|
|
v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
|
2008-04-06 13:11:50 -04:00
|
|
|
}
|
2001-08-14 04:13:31 -04:00
|
|
|
}
|
2002-05-30 02:12:29 -04:00
|
|
|
else {
|
2008-04-06 13:11:50 -04:00
|
|
|
tmp = rb_check_string_type(b);
|
2001-08-14 04:13:31 -04:00
|
|
|
|
2003-06-07 11:34:31 -04:00
|
|
|
if (!NIL_P(tmp)) {
|
|
|
|
b = tmp;
|
2018-04-19 11:18:50 -04:00
|
|
|
if (NIL_P(e)) {
|
2018-04-28 07:16:54 -04:00
|
|
|
rb_str_upto_endless_each(b, step_i, (VALUE)iter);
|
2018-04-19 11:18:50 -04:00
|
|
|
}
|
|
|
|
else {
|
2018-04-28 07:16:54 -04:00
|
|
|
rb_str_upto_each(b, e, EXCL(range), step_i, (VALUE)iter);
|
2018-04-19 11:18:50 -04:00
|
|
|
}
|
2003-06-07 11:34:31 -04:00
|
|
|
}
|
|
|
|
else {
|
2009-09-30 04: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 01:47:45 -05:00
|
|
|
rb_raise(rb_eTypeError, "can't iterate from %s",
|
2003-06-07 11:34:31 -04:00
|
|
|
rb_obj_classname(b));
|
|
|
|
}
|
2021-10-09 22:45:50 -04:00
|
|
|
range_each_func(range, step_i, (VALUE)iter);
|
2003-06-07 11:34:31 -04:00
|
|
|
}
|
2001-08-14 04:13:31 -04:00
|
|
|
}
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2021-09-22 15:51:11 -04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* %(n) {|element| ... } -> self
|
|
|
|
* %(n) -> enumerator
|
|
|
|
*
|
|
|
|
* Iterates over the elements of +self+.
|
|
|
|
*
|
|
|
|
* With a block given, calls the block with selected elements of the range;
|
|
|
|
* returns +self+:
|
|
|
|
*
|
|
|
|
* a = []
|
|
|
|
* (1..5).%(2) {|element| a.push(element) } # => 1..5
|
|
|
|
* a # => [1, 3, 5]
|
|
|
|
* a = []
|
|
|
|
* ('a'..'e').%(2) {|element| a.push(element) } # => "a".."e"
|
|
|
|
* a # => ["a", "c", "e"]
|
|
|
|
*
|
|
|
|
* With no block given, returns an enumerator,
|
|
|
|
* which will be of class Enumerator::ArithmeticSequence if +self+ is numeric;
|
|
|
|
* otherwise of class Enumerator:
|
|
|
|
*
|
|
|
|
* e = (1..5) % 2 # => ((1..5).%(2))
|
|
|
|
* e.class # => Enumerator::ArithmeticSequence
|
|
|
|
* ('a'..'e') % 2 # => #<Enumerator: ...>
|
|
|
|
*
|
|
|
|
* Related: Range#step.
|
|
|
|
*/
|
2018-09-27 22:18:58 -04:00
|
|
|
static VALUE
|
|
|
|
range_percent_step(VALUE range, VALUE step)
|
|
|
|
{
|
2018-09-28 05:23:35 -04:00
|
|
|
return range_step(1, &step, range);
|
2018-09-27 22:18:58 -04:00
|
|
|
}
|
|
|
|
|
2013-01-29 17:00:36 -05:00
|
|
|
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
|
|
|
|
union int64_double {
|
2013-01-30 01:20:26 -05:00
|
|
|
int64_t i;
|
|
|
|
double d;
|
2013-01-29 17:00:36 -05:00
|
|
|
};
|
|
|
|
|
|
|
|
static VALUE
|
2013-01-30 01:20:26 -05:00
|
|
|
int64_as_double_to_num(int64_t i)
|
|
|
|
{
|
2013-01-29 17:00:36 -05:00
|
|
|
union int64_double convert;
|
|
|
|
if (i < 0) {
|
|
|
|
convert.i = -i;
|
|
|
|
return DBL2NUM(-convert.d);
|
2013-01-30 01:20:26 -05:00
|
|
|
}
|
|
|
|
else {
|
2013-01-29 17:00:36 -05:00
|
|
|
convert.i = i;
|
|
|
|
return DBL2NUM(convert.d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t
|
2013-01-30 01:20:26 -05:00
|
|
|
double_as_int64(double d)
|
|
|
|
{
|
2013-01-29 17:00:36 -05:00
|
|
|
union int64_double convert;
|
|
|
|
convert.d = fabs(d);
|
|
|
|
return d < 0 ? -convert.i : convert.i;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-30 00:46:48 -05:00
|
|
|
static int
|
2013-01-30 01:20:26 -05:00
|
|
|
is_integer_p(VALUE v)
|
|
|
|
{
|
2018-04-19 11:19:00 -04: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 00:46:48 -05:00
|
|
|
return RTEST(is_int) && is_int != Qundef;
|
|
|
|
}
|
|
|
|
|
2018-04-19 11:18:57 -04: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; \
|
|
|
|
} \
|
2021-10-03 09:34:45 -04:00
|
|
|
else if (!RTEST(v)) { \
|
2018-04-19 11:18:57 -04:00
|
|
|
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 11:19:00 -04:00
|
|
|
ID id_div;
|
|
|
|
CONST_ID(id_div, "div");
|
|
|
|
|
2018-04-19 11:18:57 -04: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 10:53:50 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 18:51:31 -04:00
|
|
|
* bsearch {|obj| block } -> value
|
2012-11-14 10:53:50 -05:00
|
|
|
*
|
2021-09-14 17:08:21 -04:00
|
|
|
* Returns an element from +self+ selected by a binary search.
|
2012-11-14 10:53:50 -05:00
|
|
|
*
|
2021-09-14 20:39:43 -04:00
|
|
|
* See {Binary Searching}[rdoc-ref:bsearch.rdoc].
|
2012-11-14 10:53:50 -05:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_bsearch(VALUE range)
|
|
|
|
{
|
2015-01-12 22:51:35 -05:00
|
|
|
VALUE beg, end, satisfied = Qnil;
|
|
|
|
int smaller;
|
2012-11-14 10:53:50 -05:00
|
|
|
|
2013-01-29 17:00:36 -05: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 00:11:03 -05:00
|
|
|
RETURN_ENUMERATOR(range, 0, 0); \
|
2013-01-29 17:00:36 -05: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-12 22:51:35 -05:00
|
|
|
return satisfied; \
|
2013-01-29 17:00:36 -05:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
2012-11-14 10:53:50 -05: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-29 17:00:36 -05:00
|
|
|
BSEARCH(INT2FIX);
|
2012-11-14 10:53:50 -05:00
|
|
|
}
|
2013-01-29 17:00:36 -05:00
|
|
|
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
|
2021-09-10 20:56:59 -04:00
|
|
|
else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
|
2019-04-03 04:11:41 -04: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-29 17:00:36 -05:00
|
|
|
int64_t mid, org_high;
|
|
|
|
BSEARCH(int64_as_double_to_num);
|
2012-11-14 10:53:50 -05:00
|
|
|
}
|
2013-01-29 17:00:36 -05:00
|
|
|
#endif
|
2013-01-30 00:46:48 -05:00
|
|
|
else if (is_integer_p(beg) && is_integer_p(end)) {
|
2013-01-30 00:11:03 -05:00
|
|
|
RETURN_ENUMERATOR(range, 0, 0);
|
2018-04-19 11:18:57 -04: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 11:19:00 -04:00
|
|
|
VALUE mid = rb_funcall(beg, '+', 1, diff);
|
2012-11-14 10:53:50 -05:00
|
|
|
BSEARCH_CHECK(mid);
|
|
|
|
if (smaller) {
|
2018-04-19 11:18:57 -04:00
|
|
|
return bsearch_integer_range(beg, mid, 0);
|
2012-11-14 10:53:50 -05:00
|
|
|
}
|
2018-04-19 11:19:00 -04:00
|
|
|
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
|
2012-11-14 10:53:50 -05:00
|
|
|
}
|
|
|
|
}
|
2019-04-03 04:11:41 -04: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 10:53:50 -05:00
|
|
|
else {
|
|
|
|
rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
|
|
|
|
}
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2018-04-28 07:16:54 -04:00
|
|
|
static int
|
|
|
|
each_i(VALUE v, VALUE arg)
|
2002-05-30 02:12:29 -04:00
|
|
|
{
|
2004-10-06 03:40:06 -04:00
|
|
|
rb_yield(v);
|
2018-04-28 07:16:54 -04:00
|
|
|
return 0;
|
2002-05-30 02:12:29 -04:00
|
|
|
}
|
|
|
|
|
2018-04-28 07:16:54 -04:00
|
|
|
static int
|
|
|
|
sym_each_i(VALUE v, VALUE arg)
|
2009-08-17 13:00:47 -04:00
|
|
|
{
|
2021-07-11 00:56:03 -04:00
|
|
|
return each_i(rb_str_intern(v), arg);
|
2009-08-17 13:00:47 -04:00
|
|
|
}
|
|
|
|
|
2012-11-06 12:14:46 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 18:51:31 -04:00
|
|
|
* size -> non_negative_integer or Infinity or nil
|
2012-11-06 12:14:46 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* Returns the count of elements in +self+
|
|
|
|
* if both begin and end values are numeric;
|
|
|
|
* otherwise, returns +nil+:
|
2012-11-06 12:14:46 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* (1..4).size # => 4
|
|
|
|
* (1...4).size # => 3
|
|
|
|
* (1..).size # => Infinity
|
2014-01-09 16:23:45 -05:00
|
|
|
* ('a'..'z').size #=> nil
|
2021-09-18 08:27:02 -04:00
|
|
|
*
|
|
|
|
* Related: Range#count.
|
2012-11-06 12:14:46 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_size(VALUE range)
|
|
|
|
{
|
|
|
|
VALUE b = RANGE_BEG(range), e = RANGE_END(range);
|
2018-06-21 22:58:39 -04: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 12:14:46 -05:00
|
|
|
}
|
2019-04-03 04:11:41 -04:00
|
|
|
else if (NIL_P(b)) {
|
|
|
|
return DBL2NUM(HUGE_VAL);
|
|
|
|
}
|
2018-06-21 22:58:39 -04:00
|
|
|
|
2012-11-06 12:14:46 -05:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2018-06-21 22:58:37 -04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 18:51:31 -04:00
|
|
|
* to_a -> array
|
2018-06-21 22:58:37 -04:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* Returns an array containing the elements in +self+, if a finite collection;
|
|
|
|
* raises an exception otherwise.
|
2018-06-21 22:58:37 -04:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* (1..4).to_a # => [1, 2, 3, 4]
|
|
|
|
* (1...4).to_a # => [1, 2, 3]
|
|
|
|
* ('a'..'d').to_a # => ["a", "b", "c", "d"]
|
|
|
|
*
|
|
|
|
* Range#entries is an alias for Range#to_a.
|
2018-06-21 22:58:37 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
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 09:43:22 -04:00
|
|
|
static VALUE
|
|
|
|
range_enum_size(VALUE range, VALUE args, VALUE eobj)
|
|
|
|
{
|
|
|
|
return range_size(range);
|
|
|
|
}
|
|
|
|
|
2020-06-16 01:31:11 -04: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 03:23:59 -04:00
|
|
|
UNREACHABLE;
|
2020-06-16 01:31:11 -04: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 03:23:59 -04:00
|
|
|
UNREACHABLE;
|
2020-06-16 01:31:11 -04: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-23 23:29:32 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 18:51:31 -04:00
|
|
|
* each {|element| ... } -> self
|
|
|
|
* each -> an_enumerator
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* With a block given, passes each element of +self+ to the block:
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* a = []
|
|
|
|
* (1..4).each {|element| a.push(element) } # => 1..4
|
|
|
|
* a # => [1, 2, 3, 4]
|
2010-05-13 01:49:55 -04:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* Raises an exception unless <tt>self.first.respond_to?(:succ)</tt>.
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* With no block given, returns an enumerator.
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
2002-05-01 05: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 06:44:21 -04:00
|
|
|
range_each(VALUE range)
|
2002-05-01 05:41:50 -04:00
|
|
|
{
|
2002-05-30 02:12:29 -04:00
|
|
|
VALUE beg, end;
|
2020-06-16 01:31:11 -04:00
|
|
|
long i;
|
2002-05-30 02:12:29 -04:00
|
|
|
|
2013-06-26 09:43:22 -04:00
|
|
|
RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
|
2005-08-30 10:49:51 -04:00
|
|
|
|
2007-09-08 11:07:18 -04:00
|
|
|
beg = RANGE_BEG(range);
|
|
|
|
end = RANGE_END(range);
|
2002-05-30 02:12:29 -04:00
|
|
|
|
2018-04-19 11:18:50 -04:00
|
|
|
if (FIXNUM_P(beg) && NIL_P(end)) {
|
2020-06-16 01:31:11 -04:00
|
|
|
range_each_fixnum_endless(beg);
|
2018-04-19 11:18:50 -04:00
|
|
|
}
|
|
|
|
else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
|
2020-06-16 01:31:11 -04:00
|
|
|
return range_each_fixnum_loop(beg, end, range);
|
2003-01-08 01:05:08 -05:00
|
|
|
}
|
2018-04-29 03:12:56 -04: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 01:31:11 -04: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 03:12:56 -04:00
|
|
|
}
|
|
|
|
else {
|
2020-06-16 01:31:11 -04:00
|
|
|
if (NIL_P(end)) range_each_bignum_endless(beg);
|
2018-04-29 03:12:56 -04: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-28 19:31:32 -04:00
|
|
|
else if (SYMBOL_P(beg) && (NIL_P(end) || SYMBOL_P(end))) { /* symbols are special */
|
2018-04-28 07:16:54 -04:00
|
|
|
beg = rb_sym2str(beg);
|
2018-04-28 19:31:32 -04: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 13:00:47 -04:00
|
|
|
}
|
2002-05-30 02:12:29 -04:00
|
|
|
else {
|
2009-08-17 12:41:00 -04:00
|
|
|
VALUE tmp = rb_check_string_type(beg);
|
|
|
|
|
|
|
|
if (!NIL_P(tmp)) {
|
2018-04-19 11:18:50 -04:00
|
|
|
if (!NIL_P(end)) {
|
2018-04-28 07:16:54 -04:00
|
|
|
rb_str_upto_each(tmp, end, EXCL(range), each_i, 0);
|
2018-04-19 11:18:50 -04:00
|
|
|
}
|
2018-04-28 03:31:32 -04:00
|
|
|
else {
|
2018-04-28 07:16:54 -04:00
|
|
|
rb_str_upto_endless_each(tmp, each_i, 0);
|
2018-04-19 11:18:50 -04:00
|
|
|
}
|
2009-08-17 12:41:00 -04:00
|
|
|
}
|
|
|
|
else {
|
2009-09-30 04:32:43 -04:00
|
|
|
if (!discrete_object_p(beg)) {
|
2009-08-17 12:41:00 -04:00
|
|
|
rb_raise(rb_eTypeError, "can't iterate from %s",
|
|
|
|
rb_obj_classname(beg));
|
|
|
|
}
|
2018-04-19 11:18:50 -04:00
|
|
|
if (!NIL_P(end))
|
|
|
|
range_each_func(range, each_i, 0);
|
|
|
|
else
|
2018-04-29 03:12:56 -04:00
|
|
|
for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
|
|
|
|
rb_yield(beg);
|
2009-02-23 10:46:02 -05:00
|
|
|
}
|
2002-05-30 02:12:29 -04:00
|
|
|
}
|
|
|
|
return range;
|
2002-05-01 05:41:50 -04:00
|
|
|
}
|
|
|
|
|
2003-12-23 23:29:32 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 18:51:31 -04:00
|
|
|
* self.begin -> object
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* Returns the object that defines the beginning of +self+.
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* (1..4).begin # => 1
|
|
|
|
* (..2).begin # => nil
|
|
|
|
*
|
|
|
|
* Related: Range#first, Range#end.
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
static VALUE
|
2007-10-18 02:58:35 -04:00
|
|
|
range_begin(VALUE range)
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
2007-09-08 11:07:18 -04:00
|
|
|
return RANGE_BEG(range);
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
2003-12-23 23:29:32 -05:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 18:51:31 -04:00
|
|
|
* self.end -> object
|
|
|
|
*
|
|
|
|
* Returns the object that defines the end of +self+.
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* (1..4).end # => 4
|
|
|
|
* (1...4).end # => 4
|
|
|
|
* (1..).end # => nil
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* Related: Range#begin, Range#last.
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
1998-01-16 07:13:05 -05:00
|
|
|
static VALUE
|
2007-10-18 02:58:35 -04:00
|
|
|
range_end(VALUE range)
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
2007-09-08 11:07:18 -04:00
|
|
|
return RANGE_END(range);
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
2007-10-18 02:58:35 -04:00
|
|
|
|
|
|
|
static VALUE
|
2013-11-29 02:59:14 -05:00
|
|
|
first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, cbarg))
|
2007-10-18 02:58:35 -04:00
|
|
|
{
|
2013-11-29 02:45:00 -05:00
|
|
|
VALUE *ary = (VALUE *)cbarg;
|
2007-10-18 02: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 00:28:13 -04:00
|
|
|
ary[0] = LONG2NUM(n);
|
2007-10-18 02:58:35 -04:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 18:51:31 -04:00
|
|
|
* first -> object
|
|
|
|
* first(n) -> array
|
|
|
|
*
|
|
|
|
* With no argument, returns the first element of +self+, if it exists:
|
|
|
|
*
|
|
|
|
* (1..4).first # => 1
|
|
|
|
* ('a'..'d').first # => "a"
|
|
|
|
*
|
|
|
|
* With non-negative integer argument +n+ given,
|
|
|
|
* returns the first +n+ elements in an array:
|
|
|
|
*
|
|
|
|
* (1..10).first(3) # => [1, 2, 3]
|
|
|
|
* (1..10).first(0) # => []
|
|
|
|
* (1..4).first(50) # => [1, 2, 3, 4]
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* Raises an exception if there is no first element:
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* (..4).first # Raises RangeError
|
2007-10-18 02:58:35 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_first(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
|
|
|
VALUE n, ary[2];
|
|
|
|
|
2019-04-30 10:18:44 -04:00
|
|
|
if (NIL_P(RANGE_BEG(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
|
|
|
|
}
|
2007-10-18 02: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 04:57:47 -05:00
|
|
|
rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
|
2007-10-18 02:58:35 -04:00
|
|
|
|
|
|
|
return ary[1];
|
|
|
|
}
|
|
|
|
|
2019-01-05 19:46:36 -05: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 02:58:35 -04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 18:51:31 -04:00
|
|
|
* last -> object
|
|
|
|
* last(n) -> array
|
|
|
|
*
|
|
|
|
* With no argument, returns the last element of +self+, if it exists:
|
|
|
|
*
|
|
|
|
* (1..4).last # => 4
|
|
|
|
* ('a'..'d').last # => "d"
|
|
|
|
*
|
|
|
|
* Note that +last+ with no argument returns the end element of +self+
|
|
|
|
* even if #exclude_end? is +true+:
|
|
|
|
*
|
|
|
|
* (1...4).last # => 4
|
|
|
|
* ('a'...'d').last # => "d"
|
|
|
|
*
|
|
|
|
* With non-negative integer argument +n+ given,
|
|
|
|
* returns the last +n+ elements in an array:
|
|
|
|
*
|
|
|
|
* (1..10).last(3) # => [8, 9, 10]
|
|
|
|
* (1..10).last(0) # => []
|
|
|
|
* (1..4).last(50) # => [1, 2, 3, 4]
|
|
|
|
*
|
|
|
|
* Note that +last+ with argument does not return the end element of +self+
|
|
|
|
* if #exclude_end? it +true+:
|
|
|
|
*
|
|
|
|
* (1...4).last(3) # => [1, 2, 3]
|
|
|
|
* ('a'...'d').last(3) # => ["a", "b", "c"]
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* Raises an exception if there is no last element:
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2021-09-14 18:51:31 -04:00
|
|
|
* (1..).last # Raises RangeError
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2007-10-18 02:58:35 -04:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_last(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
2019-01-05 19:46:36 -05:00
|
|
|
VALUE b, e;
|
|
|
|
|
2018-06-21 22:58:40 -04:00
|
|
|
if (NIL_P(RANGE_END(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the last element of endless range");
|
|
|
|
}
|
2013-08-07 21:27:19 -04:00
|
|
|
if (argc == 0) return RANGE_END(range);
|
2019-01-05 19:46:36 -05:00
|
|
|
|
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2019-01-07 23:37:40 -05:00
|
|
|
if (RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e) &&
|
|
|
|
RB_LIKELY(rb_method_basic_definition_p(rb_cRange, idEach))) {
|
2019-01-05 19:46:36 -05:00
|
|
|
return rb_int_range_last(argc, argv, range);
|
|
|
|
}
|
2009-02-22 09:23:33 -05:00
|
|
|
return rb_ary_last(argc, argv, rb_Array(range));
|
2007-10-18 02:58:35 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-24 20:30:57 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-15 14:37:34 -04:00
|
|
|
* min -> object
|
|
|
|
* min(n) -> array
|
|
|
|
* min {|a, b| ... } -> object
|
|
|
|
* min(n) {|a, b| ... } -> array
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-15 14:37:34 -04:00
|
|
|
* Returns the minimum value in +self+,
|
|
|
|
* using method <tt><=></tt> or a given block for comparison.
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2021-09-15 14:37:34 -04:00
|
|
|
* With no argument and no block given,
|
|
|
|
* returns the minimum-valued element of +self+.
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-15 14:37:34 -04:00
|
|
|
* (1..4).min # => 1
|
|
|
|
* ('a'..'d').min # => "a"
|
|
|
|
* (-4..-1).min # => -4
|
|
|
|
*
|
|
|
|
* With non-negative integer argument +n+ given, and no block given,
|
|
|
|
* returns the +n+ minimum-valued elements of +self+ in an array:
|
|
|
|
*
|
|
|
|
* (1..4).min(2) # => [1, 2]
|
|
|
|
* ('a'..'d').min(2) # => ["a", "b"]
|
|
|
|
* (-4..-1).min(2) # => [-4, -3]
|
2021-09-15 15:48:47 -04:00
|
|
|
* (1..4).min(50) # => [1, 2, 3, 4]
|
2021-09-15 14:37:34 -04:00
|
|
|
*
|
|
|
|
* If a block is given, it is called:
|
|
|
|
*
|
|
|
|
* - First, with the first two element of +self+.
|
|
|
|
* - Then, sequentially, with the so-far minimum value and the next element of +self+.
|
|
|
|
*
|
|
|
|
* To illustrate:
|
|
|
|
*
|
|
|
|
* (1..4).min {|a, b| p [a, b]; a <=> b } # => 1
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
*
|
|
|
|
* [2, 1]
|
|
|
|
* [3, 1]
|
|
|
|
* [4, 1]
|
|
|
|
*
|
|
|
|
* With no argument and a block given,
|
|
|
|
* returns the return value of the last call to the block:
|
|
|
|
*
|
|
|
|
* (1..4).min {|a, b| -(a <=> b) } # => 4
|
|
|
|
*
|
|
|
|
* With non-negative integer argument +n+ given, and a block given,
|
|
|
|
* returns the return values of the last +n+ calls to the block in an array:
|
|
|
|
*
|
|
|
|
* (1..4).min(2) {|a, b| -(a <=> b) } # => [4, 3]
|
|
|
|
* (1..4).min(50) {|a, b| -(a <=> b) } # => [4, 3, 2, 1]
|
|
|
|
*
|
|
|
|
* Returns an empty array if +n+ is zero:
|
|
|
|
*
|
|
|
|
* (1..4).min(0) # => []
|
|
|
|
* (1..4).min(0) {|a, b| -(a <=> b) } # => []
|
|
|
|
*
|
|
|
|
* Returns +nil+ or an empty array if:
|
|
|
|
*
|
|
|
|
* - The begin value of the range is larger than the end value:
|
|
|
|
*
|
|
|
|
* (4..1).min # => nil
|
|
|
|
* (4..1).min(2) # => []
|
|
|
|
* (4..1).min {|a, b| -(a <=> b) } # => nil
|
|
|
|
* (4..1).min(2) {|a, b| -(a <=> b) } # => []
|
|
|
|
*
|
|
|
|
* - The begin value of an exclusive range is equal to the end value:
|
|
|
|
*
|
|
|
|
* (1...1).min # => nil
|
|
|
|
* (1...1).min(2) # => []
|
|
|
|
* (1...1).min {|a, b| -(a <=> b) } # => nil
|
|
|
|
* (1...1).min(2) {|a, b| -(a <=> b) } # => []
|
|
|
|
*
|
|
|
|
* Raises an exception if either:
|
|
|
|
*
|
|
|
|
* - +self+ is a beginless range: <tt>(..4)</tt>.
|
|
|
|
* - A block is given and +self+ is an endless range.
|
|
|
|
*
|
|
|
|
* Related: Range#max, Range#minmax.
|
2005-11-24 20:30:57 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
static VALUE
|
2014-02-14 10:45:11 -05:00
|
|
|
range_min(int argc, VALUE *argv, VALUE range)
|
2005-11-24 20:30:57 -05:00
|
|
|
{
|
2019-12-24 23:35:22 -05:00
|
|
|
if (NIL_P(RANGE_BEG(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the minimum of beginless range");
|
|
|
|
}
|
|
|
|
|
2005-11-24 20:30:57 -05:00
|
|
|
if (rb_block_given_p()) {
|
2018-06-21 22:58:40 -04: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 10:45:11 -05:00
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
else if (argc != 0) {
|
|
|
|
return range_first(argc, argv, range);
|
2005-11-24 20:30:57 -05:00
|
|
|
}
|
|
|
|
else {
|
2017-05-29 22:57:33 -04:00
|
|
|
struct cmp_opt_data cmp_opt = { 0, 0 };
|
2007-09-08 11:07:18 -04:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
VALUE e = RANGE_END(range);
|
2018-04-19 11:18:53 -04:00
|
|
|
int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
|
2005-11-24 20:30:57 -05:00
|
|
|
|
2007-07-12 22:33:11 -04:00
|
|
|
if (c > 0 || (c == 0 && EXCL(range)))
|
2006-12-31 10:02:22 -05:00
|
|
|
return Qnil;
|
2005-11-24 20:30:57 -05:00
|
|
|
return b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-15 15:48:47 -04:00
|
|
|
* max -> object
|
|
|
|
* max(n) -> array
|
|
|
|
* max {|a, b| ... } -> object
|
|
|
|
* max(n) {|a, b| ... } -> array
|
|
|
|
*
|
|
|
|
* Returns the maximum value in +self+,
|
|
|
|
* using method <tt><=></tt> or a given block for comparison.
|
|
|
|
*
|
|
|
|
* With no argument and no block given,
|
|
|
|
* returns the maximum-valued element of +self+.
|
|
|
|
*
|
|
|
|
* (1..4).max # => 4
|
|
|
|
* ('a'..'d').max # => "d"
|
|
|
|
* (-4..-1).max # => -1
|
|
|
|
*
|
|
|
|
* With non-negative integer argument +n+ given, and no block given,
|
|
|
|
* returns the +n+ maximum-valued elements of +self+ in an array:
|
|
|
|
*
|
|
|
|
* (1..4).max(2) # => [4, 3]
|
|
|
|
* ('a'..'d').max(2) # => ["d", "c"]
|
|
|
|
* (-4..-1).max(2) # => [-1, -2]
|
|
|
|
* (1..4).max(50) # => [4, 3, 2, 1]
|
|
|
|
*
|
|
|
|
* If a block is given, it is called:
|
|
|
|
*
|
|
|
|
* - First, with the first two element of +self+.
|
|
|
|
* - Then, sequentially, with the so-far maximum value and the next element of +self+.
|
|
|
|
*
|
|
|
|
* To illustrate:
|
|
|
|
*
|
|
|
|
* (1..4).max {|a, b| p [a, b]; a <=> b } # => 4
|
|
|
|
*
|
|
|
|
* Output:
|
|
|
|
*
|
|
|
|
* [2, 1]
|
|
|
|
* [3, 2]
|
|
|
|
* [4, 3]
|
|
|
|
*
|
|
|
|
* With no argument and a block given,
|
|
|
|
* returns the return value of the last call to the block:
|
|
|
|
*
|
|
|
|
* (1..4).max {|a, b| -(a <=> b) } # => 1
|
|
|
|
*
|
|
|
|
* With non-negative integer argument +n+ given, and a block given,
|
|
|
|
* returns the return values of the last +n+ calls to the block in an array:
|
|
|
|
*
|
|
|
|
* (1..4).max(2) {|a, b| -(a <=> b) } # => [1, 2]
|
|
|
|
* (1..4).max(50) {|a, b| -(a <=> b) } # => [1, 2, 3, 4]
|
|
|
|
*
|
|
|
|
* Returns an empty array if +n+ is zero:
|
|
|
|
*
|
|
|
|
* (1..4).max(0) # => []
|
|
|
|
* (1..4).max(0) {|a, b| -(a <=> b) } # => []
|
|
|
|
*
|
|
|
|
* Returns +nil+ or an empty array if:
|
|
|
|
*
|
|
|
|
* - The begin value of the range is larger than the end value:
|
|
|
|
*
|
|
|
|
* (4..1).max # => nil
|
|
|
|
* (4..1).max(2) # => []
|
|
|
|
* (4..1).max {|a, b| -(a <=> b) } # => nil
|
|
|
|
* (4..1).max(2) {|a, b| -(a <=> b) } # => []
|
|
|
|
*
|
|
|
|
* - The begin value of an exclusive range is equal to the end value:
|
|
|
|
*
|
|
|
|
* (1...1).max # => nil
|
|
|
|
* (1...1).max(2) # => []
|
|
|
|
* (1...1).max {|a, b| -(a <=> b) } # => nil
|
|
|
|
* (1...1).max(2) {|a, b| -(a <=> b) } # => []
|
|
|
|
*
|
|
|
|
* Raises an exception if either:
|
|
|
|
*
|
|
|
|
* - +self+ is a endless range: <tt>(1..)</tt>.
|
|
|
|
* - A block is given and +self+ is a beginless range.
|
|
|
|
*
|
|
|
|
* Related: Range#min, Range#minmax.
|
|
|
|
*
|
2005-11-24 20:30:57 -05:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2014-02-14 10:45:11 -05:00
|
|
|
range_max(int argc, VALUE *argv, VALUE range)
|
2005-11-24 20:30:57 -05:00
|
|
|
{
|
2007-09-08 11:07:18 -04:00
|
|
|
VALUE e = RANGE_END(range);
|
2009-01-04 17:32:40 -05:00
|
|
|
int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
|
2005-11-25 00:42:28 -05:00
|
|
|
|
2018-06-21 22:58:40 -04:00
|
|
|
if (NIL_P(RANGE_END(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the maximum of endless range");
|
|
|
|
}
|
2018-04-19 11:18:53 -04:00
|
|
|
|
2020-07-18 12:18:40 -04:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
|
2014-02-14 10:45:11 -05:00
|
|
|
if (rb_block_given_p() || (EXCL(range) && !nm) || argc) {
|
2020-07-18 12:18:40 -04:00
|
|
|
if (NIL_P(b)) {
|
2019-12-24 23:35:22 -05:00
|
|
|
rb_raise(rb_eRangeError, "cannot get the maximum of beginless range with custom comparison method");
|
|
|
|
}
|
2018-02-26 02:57:15 -05:00
|
|
|
return rb_call_super(argc, argv);
|
2005-11-24 20:30:57 -05:00
|
|
|
}
|
|
|
|
else {
|
2018-02-26 02:57:15 -05:00
|
|
|
struct cmp_opt_data cmp_opt = { 0, 0 };
|
2020-07-18 12:18:40 -04:00
|
|
|
int c = NIL_P(b) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
|
2018-02-26 02:57:15 -05: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-24 20:30:57 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-08 01:03:02 -04:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-15 16:51:54 -04:00
|
|
|
* minmax -> [object, object]
|
|
|
|
* minmax {|a, b| ... } -> [object, object]
|
2019-06-08 01:03:02 -04:00
|
|
|
*
|
2021-09-15 16:51:54 -04:00
|
|
|
* Returns a 2-element array containing the minimum and maximum value in +self+,
|
|
|
|
* either according to comparison method <tt><=></tt> or a given block.
|
|
|
|
*
|
|
|
|
* With no block given, returns the minimum and maximum values,
|
|
|
|
* using <tt><=></tt> for comparison:
|
|
|
|
*
|
|
|
|
* (1..4).minmax # => [1, 4]
|
|
|
|
* (1...4).minmax # => [1, 3]
|
|
|
|
* ('a'..'d').minmax # => ["a", "d"]
|
|
|
|
* (-4..-1).minmax # => [-4, -1]
|
|
|
|
*
|
|
|
|
* With a block given, the block must return an integer:
|
|
|
|
*
|
|
|
|
* - Negative if +a+ is smaller than +b+.
|
|
|
|
* - Zero if +a+ and +b+ are equal.
|
|
|
|
* - Positive if +a+ is larger than +b+.
|
|
|
|
*
|
|
|
|
* The block is called <tt>self.size</tt> times to compare elements;
|
|
|
|
* returns a 2-element Array containing the minimum and maximum values from +self+,
|
|
|
|
* per the block:
|
|
|
|
*
|
|
|
|
* (1..4).minmax {|a, b| -(a <=> b) } # => [4, 1]
|
|
|
|
*
|
|
|
|
* Returns <tt>[nil, nil]</tt> if:
|
|
|
|
*
|
|
|
|
* - The begin value of the range is larger than the end value:
|
|
|
|
*
|
|
|
|
* (4..1).minmax # => [nil, nil]
|
|
|
|
* (4..1).minmax {|a, b| -(a <=> b) } # => [nil, nil]
|
|
|
|
*
|
|
|
|
* - The begin value of an exclusive range is equal to the end value:
|
|
|
|
*
|
|
|
|
* (1...1).minmax # => [nil, nil]
|
|
|
|
* (1...1).minmax {|a, b| -(a <=> b) } # => [nil, nil]
|
|
|
|
*
|
|
|
|
* Raises an exception if +self+ is a beginless or an endless range.
|
|
|
|
*
|
|
|
|
* Related: Range#min, Range#max.
|
2019-06-08 01:03:02 -04:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
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-03 22:56:07 -04:00
|
|
|
return rb_assoc_new(
|
2020-07-04 13:12:02 -04: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-03 22:56:07 -04:00
|
|
|
);
|
2019-06-08 01:03:02 -04:00
|
|
|
}
|
|
|
|
|
2009-07-16 02:52:29 -04:00
|
|
|
int
|
|
|
|
rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
2005-08-04 00:31:33 -04:00
|
|
|
VALUE b, e;
|
2009-07-16 02:52:29 -04:00
|
|
|
int excl;
|
1998-01-16 07:13:05 -05:00
|
|
|
|
2005-08-04 00:31:33 -04:00
|
|
|
if (rb_obj_is_kind_of(range, rb_cRange)) {
|
2007-09-08 11:07:18 -04:00
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2005-08-04 07:29:51 -04:00
|
|
|
excl = EXCL(range);
|
2005-08-04 00:31:33 -04:00
|
|
|
}
|
2018-12-21 08:05:16 -05:00
|
|
|
else if (RTEST(rb_obj_is_kind_of(range, rb_cArithSeq))) {
|
|
|
|
return (int)Qfalse;
|
|
|
|
}
|
2005-08-04 00:31:33 -04:00
|
|
|
else {
|
2017-10-24 21:40:15 -04: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 00:31:33 -04:00
|
|
|
}
|
2009-07-16 02:52:29 -04:00
|
|
|
*begp = b;
|
|
|
|
*endp = e;
|
|
|
|
*exclp = excl;
|
2009-09-22 23:39:44 -04:00
|
|
|
return (int)Qtrue;
|
2009-07-16 02:52:29 -04:00
|
|
|
}
|
|
|
|
|
2020-10-20 13:40:18 -04: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 02:52:29 -04:00
|
|
|
VALUE
|
2020-10-20 13:40:18 -04:00
|
|
|
rb_range_component_beg_len(VALUE b, VALUE e, int excl,
|
|
|
|
long *begp, long *lenp, long len, int err)
|
2009-07-16 02:52:29 -04:00
|
|
|
{
|
2020-10-20 03:00:35 -04:00
|
|
|
long beg, end;
|
2009-07-16 02:52:29 -04:00
|
|
|
|
2019-04-03 04:11:41 -04:00
|
|
|
beg = NIL_P(b) ? 0 : NUM2LONG(b);
|
2018-04-19 11:18:50 -04:00
|
|
|
end = NIL_P(e) ? -1 : NUM2LONG(e);
|
|
|
|
if (NIL_P(e)) excl = 0;
|
1999-08-13 01:45:20 -04:00
|
|
|
if (beg < 0) {
|
2020-10-20 13:40:18 -04:00
|
|
|
beg += len;
|
|
|
|
if (beg < 0)
|
|
|
|
goto out_of_range;
|
1999-08-13 01:45:20 -04:00
|
|
|
}
|
2012-11-20 23:23:56 -05:00
|
|
|
if (end < 0)
|
2020-10-20 13:40:18 -04:00
|
|
|
end += len;
|
2012-11-20 23:23:56 -05:00
|
|
|
if (!excl)
|
2020-10-20 13:40:18 -04:00
|
|
|
end++; /* include end point */
|
1999-08-13 01:45:20 -04:00
|
|
|
if (err == 0 || err == 2) {
|
2020-10-20 13:40:18 -04:00
|
|
|
if (beg > len)
|
|
|
|
goto out_of_range;
|
|
|
|
if (end > len)
|
|
|
|
end = len;
|
1999-08-13 01:45:20 -04:00
|
|
|
}
|
|
|
|
len = end - beg;
|
2006-12-31 10:02:22 -05:00
|
|
|
if (len < 0)
|
2020-10-20 13:40:18 -04:00
|
|
|
len = 0;
|
1999-08-13 01:45:20 -04:00
|
|
|
|
|
|
|
*begp = beg;
|
|
|
|
*lenp = len;
|
1999-01-19 23:59:39 -05:00
|
|
|
return Qtrue;
|
1999-08-13 01:45:20 -04:00
|
|
|
|
|
|
|
out_of_range:
|
|
|
|
return Qnil;
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
2020-10-20 13:40:18 -04: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 11:38:32 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-18 08:27:02 -04:00
|
|
|
* to_s -> string
|
|
|
|
*
|
|
|
|
* Returns a string representation of +self+,
|
|
|
|
* including <tt>begin.to_s</tt> and <tt>end.to_s</tt>:
|
|
|
|
*
|
|
|
|
* (1..4).to_s # => "1..4"
|
|
|
|
* (1...4).to_s # => "1...4"
|
|
|
|
* (1..).to_s # => "1.."
|
|
|
|
* (..4).to_s # => "..4"
|
|
|
|
*
|
|
|
|
* Note that returns from #to_s and #inspect may differ:
|
|
|
|
*
|
|
|
|
* ('a'..'d').to_s # => "a..d"
|
|
|
|
* ('a'..'d').inspect # => "\"a\"..\"d\""
|
|
|
|
*
|
|
|
|
* Related: Range#inspect.
|
2003-12-30 11:38:32 -05:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
1998-01-16 07:13:05 -05: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 06:44:21 -04:00
|
|
|
range_to_s(VALUE range)
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
|
|
|
VALUE str, str2;
|
|
|
|
|
2007-09-08 11:07:18 -04:00
|
|
|
str = rb_obj_as_string(RANGE_BEG(range));
|
|
|
|
str2 = rb_obj_as_string(RANGE_END(range));
|
2000-04-10 01:48:43 -04:00
|
|
|
str = rb_str_dup(str);
|
2006-12-31 10:02:22 -05:00
|
|
|
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
|
2000-04-10 01:48:43 -04:00
|
|
|
rb_str_append(str, str2);
|
1998-01-16 07:13:05 -05:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2008-09-25 11:42:23 -04:00
|
|
|
static VALUE
|
|
|
|
inspect_range(VALUE range, VALUE dummy, int recur)
|
|
|
|
{
|
2018-04-19 11:18:50 -04:00
|
|
|
VALUE str, str2 = Qundef;
|
2008-09-25 11:42:23 -04:00
|
|
|
|
|
|
|
if (recur) {
|
|
|
|
return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)");
|
|
|
|
}
|
2019-05-22 11:45:30 -04: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 11:42:23 -04:00
|
|
|
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
|
2019-05-22 11:45:30 -04:00
|
|
|
if (NIL_P(RANGE_BEG(range)) || !NIL_P(RANGE_END(range))) {
|
|
|
|
str2 = rb_inspect(RANGE_END(range));
|
|
|
|
}
|
2018-04-19 11:18:50 -04:00
|
|
|
if (str2 != Qundef) rb_str_append(str, str2);
|
2008-09-25 11:42:23 -04:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2003-12-30 11:38:32 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-18 08:27:02 -04:00
|
|
|
* inspect -> string
|
|
|
|
*
|
|
|
|
* Returns a string representation of +self+,
|
|
|
|
* including <tt>begin.inspect</tt> and <tt>end.inspect</tt>:
|
|
|
|
*
|
|
|
|
* (1..4).inspect # => "1..4"
|
|
|
|
* (1...4).inspect # => "1...4"
|
|
|
|
* (1..).inspect # => "1.."
|
|
|
|
* (..4).inspect # => "..4"
|
|
|
|
*
|
|
|
|
* Note that returns from #to_s and #inspect may differ:
|
|
|
|
*
|
|
|
|
* ('a'..'d').to_s # => "a..d"
|
|
|
|
* ('a'..'d').inspect # => "\"a\"..\"d\""
|
|
|
|
*
|
|
|
|
* Related: Range#to_s.
|
2003-12-30 11:38:32 -05:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
1998-01-16 07:13:05 -05: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 06:44:21 -04:00
|
|
|
range_inspect(VALUE range)
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
2008-09-25 11:42:23 -04:00
|
|
|
return rb_exec_recursive(inspect_range, range, 0);
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|
|
|
|
|
2019-07-29 19:22:00 -04:00
|
|
|
static VALUE range_include_internal(VALUE range, VALUE val, int string_use_cover);
|
2018-05-17 06:46:21 -04:00
|
|
|
|
2003-12-23 23:29:32 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-22 15:51:11 -04:00
|
|
|
* self === object -> true or false
|
2021-09-18 08:27:02 -04:00
|
|
|
*
|
|
|
|
* Returns +true+ if +object+ is between <tt>self.begin</tt> and <tt>self.end</tt>.
|
|
|
|
* +false+ otherwise:
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* (1..4) === 2 # => true
|
|
|
|
* (1..4) === 5 # => false
|
|
|
|
* (1..4) === 'a' # => false
|
|
|
|
* (1..4) === 4 # => true
|
|
|
|
* (1...4) === 4 # => false
|
|
|
|
* ('a'..'d') === 'c' # => true
|
|
|
|
* ('a'..'d') === 'e' # => false
|
|
|
|
*
|
|
|
|
* A case statement uses method <tt>===</tt>, and so:
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2003-12-23 23:29:32 -05:00
|
|
|
* case 79
|
2021-09-18 08:27:02 -04:00
|
|
|
* when (1..50)
|
|
|
|
* "low"
|
|
|
|
* when (51..75)
|
|
|
|
* "medium"
|
|
|
|
* when (76..100)
|
|
|
|
* "high"
|
|
|
|
* end # => "high"
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2019-12-21 15:58:14 -05:00
|
|
|
* case "2.6.5"
|
2021-09-18 08:27:02 -04:00
|
|
|
* when ..."2.4"
|
|
|
|
* "EOL"
|
|
|
|
* when "2.4"..."2.5"
|
|
|
|
* "maintenance"
|
|
|
|
* when "2.5"..."3.0"
|
|
|
|
* "stable"
|
|
|
|
* when "3.1"..
|
|
|
|
* "upcoming"
|
|
|
|
* end # => "stable"
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
2007-07-26 09:37:13 -04:00
|
|
|
static VALUE
|
|
|
|
range_eqq(VALUE range, VALUE val)
|
|
|
|
{
|
2019-07-29 19:22:00 -04:00
|
|
|
VALUE ret = range_include_internal(range, val, 1);
|
2018-05-17 06:46:21 -04:00
|
|
|
if (ret != Qundef) return ret;
|
|
|
|
return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
|
2007-07-26 09:37:13 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-18 08:27:02 -04:00
|
|
|
* include?(object) -> true or false
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* Returns +true+ if +object+ is an element of +self+, +false+ otherwise:
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* (1..4).include?(2) # => true
|
|
|
|
* (1..4).include?(5) # => false
|
|
|
|
* (1..4).include?(4) # => true
|
|
|
|
* (1...4).include?(4) # => false
|
|
|
|
* ('a'..'d').include?('b') # => true
|
|
|
|
* ('a'..'d').include?('e') # => false
|
|
|
|
* ('a'..'d').include?('B') # => false
|
|
|
|
* ('a'..'d').include?('d') # => true
|
|
|
|
* ('a'...'d').include?('d') # => false
|
2019-12-21 15:58:14 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* If begin and end are numeric, #include? behaves like #cover?
|
2019-12-21 15:58:14 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* (1..3).include?(1.5) # => true
|
|
|
|
* (1..3).cover?(1.5) # => true
|
2019-12-21 15:58:14 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* But when not numeric, the two methods may differ:
|
2019-12-21 15:58:14 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* ('a'..'d').include?('cc') # => false
|
|
|
|
* ('a'..'d').cover?('cc') # => true
|
|
|
|
*
|
|
|
|
* Related: Range#cover?.
|
|
|
|
*
|
|
|
|
* Range#member? is an alias for Range#include?.
|
2007-07-26 09:37:13 -04:00
|
|
|
*/
|
|
|
|
|
2002-06-11 03: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 06:44:21 -04:00
|
|
|
range_include(VALUE range, VALUE val)
|
2018-05-17 06:46:21 -04:00
|
|
|
{
|
2019-07-29 19:22:00 -04:00
|
|
|
VALUE ret = range_include_internal(range, val, 0);
|
2018-05-17 06:46:21 -04:00
|
|
|
if (ret != Qundef) return ret;
|
|
|
|
return rb_call_super(1, &val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2019-07-29 19:22:00 -04:00
|
|
|
range_include_internal(VALUE range, VALUE val, int string_use_cover)
|
2002-06-11 03:02:23 -04:00
|
|
|
{
|
2007-09-08 11:07:18 -04:00
|
|
|
VALUE beg = RANGE_BEG(range);
|
|
|
|
VALUE end = RANGE_END(range);
|
2005-12-07 03:41:59 -05:00
|
|
|
int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
|
2015-05-02 21:02:15 -04:00
|
|
|
linear_object_p(beg) || linear_object_p(end);
|
2005-12-07 03:41:59 -05:00
|
|
|
|
2005-12-09 09:17:09 -05:00
|
|
|
if (nv ||
|
|
|
|
!NIL_P(rb_check_to_integer(beg, "to_int")) ||
|
|
|
|
!NIL_P(rb_check_to_integer(end, "to_int"))) {
|
2015-05-15 05:05:57 -04:00
|
|
|
return r_cover_p(range, beg, end, val);
|
2002-06-11 03:02:23 -04:00
|
|
|
}
|
2019-07-29 19:22:00 -04: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 04:11:41 -04: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 11:18:53 -04: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 12:46:52 -05:00
|
|
|
}
|
2018-05-17 06:46:21 -04:00
|
|
|
return Qundef;
|
2002-06-11 03:02:23 -04:00
|
|
|
}
|
|
|
|
|
2018-09-05 15:06:08 -04:00
|
|
|
static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
|
2003-12-23 23:29:32 -05:00
|
|
|
|
2005-12-11 20:01:29 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-18 08:27:02 -04:00
|
|
|
* cover?(object) -> true or false
|
|
|
|
* cover?(range) -> true or false
|
|
|
|
*
|
|
|
|
* Returns +true+ if the given argument is within +self+, +false+ otherwise.
|
|
|
|
*
|
|
|
|
* With non-range argument +object+, evaluates with <tt><=</tt> and <tt><</tt>.
|
|
|
|
*
|
|
|
|
* For range +self+ with included end value (<tt>#exclude_end? == false</tt>),
|
|
|
|
* evaluates thus:
|
|
|
|
*
|
|
|
|
* self.begin <= object <= self.end
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* r = (1..4)
|
|
|
|
* r.cover?(1) # => true
|
|
|
|
* r.cover?(4) # => true
|
|
|
|
* r.cover?(0) # => false
|
|
|
|
* r.cover?(5) # => false
|
|
|
|
* r.cover?('foo') # => false
|
|
|
|
|
|
|
|
* r = ('a'..'d')
|
|
|
|
* r.cover?('a') # => true
|
|
|
|
* r.cover?('d') # => true
|
|
|
|
* r.cover?(' ') # => false
|
|
|
|
* r.cover?('e') # => false
|
|
|
|
* r.cover?(0) # => false
|
|
|
|
*
|
|
|
|
* For range +r+ with excluded end value (<tt>#exclude_end? == true</tt>),
|
|
|
|
* evaluates thus:
|
|
|
|
*
|
|
|
|
* r.begin <= object < r.end
|
|
|
|
*
|
|
|
|
* Examples:
|
|
|
|
*
|
|
|
|
* r = (1...4)
|
|
|
|
* r.cover?(1) # => true
|
|
|
|
* r.cover?(3) # => true
|
|
|
|
* r.cover?(0) # => false
|
|
|
|
* r.cover?(4) # => false
|
|
|
|
* r.cover?('foo') # => false
|
|
|
|
|
|
|
|
* r = ('a'...'d')
|
|
|
|
* r.cover?('a') # => true
|
|
|
|
* r.cover?('c') # => true
|
|
|
|
* r.cover?(' ') # => false
|
|
|
|
* r.cover?('d') # => false
|
|
|
|
* r.cover?(0) # => false
|
|
|
|
*
|
|
|
|
* With range argument +range+, compares the first and last
|
|
|
|
* elements of +self+ and +range+:
|
|
|
|
*
|
|
|
|
* r = (1..4)
|
|
|
|
* r.cover?(1..4) # => true
|
|
|
|
* r.cover?(0..4) # => false
|
|
|
|
* r.cover?(1..5) # => false
|
|
|
|
* r.cover?('a'..'d') # => false
|
|
|
|
|
|
|
|
* r = (1...4)
|
|
|
|
* r.cover?(1..3) # => true
|
|
|
|
* r.cover?(1..4) # => false
|
|
|
|
*
|
|
|
|
* If begin and end are numeric, #cover? behaves like #include?
|
|
|
|
*
|
|
|
|
* (1..3).cover?(1.5) # => true
|
|
|
|
* (1..3).include?(1.5) # => true
|
|
|
|
*
|
|
|
|
* But when not numeric, the two methods may differ:
|
|
|
|
*
|
|
|
|
* ('a'..'d').cover?('cc') # => true
|
|
|
|
* ('a'..'d').include?('cc') # => false
|
|
|
|
*
|
|
|
|
* Returns +false+ if either:
|
|
|
|
*
|
|
|
|
* - The begin value of +self+ is larger than its end value.
|
|
|
|
* - An internal call to <tt><=></tt> returns +nil+;
|
|
|
|
* that is, the operands are not comparable.
|
|
|
|
*
|
|
|
|
* Related: Range#include?.
|
|
|
|
*
|
2005-12-11 20:01:29 -05: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-09 17:20:17 -04:00
|
|
|
range_cover(VALUE range, VALUE val)
|
2005-12-11 20:01:29 -05:00
|
|
|
{
|
|
|
|
VALUE beg, end;
|
|
|
|
|
2007-09-08 11:07:18 -04:00
|
|
|
beg = RANGE_BEG(range);
|
|
|
|
end = RANGE_END(range);
|
2018-09-05 15:06:08 -04:00
|
|
|
|
|
|
|
if (rb_obj_is_kind_of(val, rb_cRange)) {
|
|
|
|
return RBOOL(r_cover_range_p(range, beg, end, val));
|
|
|
|
}
|
2015-05-15 05:05:57 -04:00
|
|
|
return r_cover_p(range, beg, end, val);
|
|
|
|
}
|
|
|
|
|
2018-09-05 15:06:08 -04: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 04:35:57 -04:00
|
|
|
if (!NIL_P(beg) && NIL_P(val_beg)) return FALSE;
|
2020-04-08 00:28:13 -04: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 04:35:57 -04:00
|
|
|
if (!NIL_P(val_beg) && !r_cover_p(range, beg, end, val_beg)) return FALSE;
|
2018-09-05 15:06:08 -04:00
|
|
|
|
|
|
|
cmp_end = r_less(end, val_end);
|
|
|
|
|
|
|
|
if (EXCL(range) == EXCL(val)) {
|
|
|
|
return cmp_end >= 0;
|
2019-01-09 08:58:49 -05:00
|
|
|
}
|
|
|
|
else if (EXCL(range)) {
|
2018-09-05 15:06:08 -04:00
|
|
|
return cmp_end > 0;
|
2019-01-09 08:58:49 -05:00
|
|
|
}
|
|
|
|
else if (cmp_end >= 0) {
|
2018-09-05 15:06:08 -04:00
|
|
|
return TRUE;
|
|
|
|
}
|
2020-09-01 12:19:03 -04:00
|
|
|
|
|
|
|
val_max = rb_rescue2(r_call_max, val, 0, Qnil, rb_eTypeError, (VALUE)0);
|
2021-10-03 09:34:45 -04:00
|
|
|
if (NIL_P(val_max)) return FALSE;
|
2018-09-05 15:06:08 -04:00
|
|
|
|
|
|
|
return r_less(end, val_max) >= 0;
|
|
|
|
}
|
|
|
|
|
2015-05-15 05:05:57 -04:00
|
|
|
static VALUE
|
|
|
|
r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val)
|
|
|
|
{
|
2019-04-03 04:11:41 -04:00
|
|
|
if (NIL_P(beg) || r_less(beg, val) <= 0) {
|
2015-05-15 05:06:18 -04:00
|
|
|
int excl = EXCL(range);
|
2018-04-19 11:18:53 -04:00
|
|
|
if (NIL_P(end) || r_less(val, end) <= -excl)
|
2015-05-15 05:06:18 -04:00
|
|
|
return Qtrue;
|
2005-12-11 20:01:29 -05:00
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2007-09-08 11:07:18 -04:00
|
|
|
static VALUE
|
|
|
|
range_dumper(VALUE range)
|
|
|
|
{
|
2020-10-28 19:58:17 -04:00
|
|
|
VALUE v = rb_obj_alloc(rb_cObject);
|
2007-09-08 11:07:18 -04:00
|
|
|
|
2007-09-10 02:50:22 -04:00
|
|
|
rb_ivar_set(v, id_excl, RANGE_EXCL(range));
|
2007-09-08 11:07:18 -04:00
|
|
|
rb_ivar_set(v, id_beg, RANGE_BEG(range));
|
2018-06-13 07:00:28 -04:00
|
|
|
rb_ivar_set(v, id_end, RANGE_END(range));
|
2007-09-08 11:07:18 -04:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_loader(VALUE range, VALUE obj)
|
|
|
|
{
|
2016-11-11 06:52:03 -05:00
|
|
|
VALUE beg, end, excl;
|
|
|
|
|
2011-09-29 07:07:45 -04:00
|
|
|
if (!RB_TYPE_P(obj, T_OBJECT) || RBASIC(obj)->klass != rb_cObject) {
|
2007-09-08 11:07:18 -04:00
|
|
|
rb_raise(rb_eTypeError, "not a dumped range object");
|
|
|
|
}
|
|
|
|
|
2013-10-26 06:08:02 -04:00
|
|
|
range_modify(range);
|
2016-11-11 06:52:03 -05:00
|
|
|
beg = rb_ivar_get(obj, id_beg);
|
2018-06-13 07:00:28 -04:00
|
|
|
end = rb_ivar_get(obj, id_end);
|
2016-11-11 06:52:03 -05:00
|
|
|
excl = rb_ivar_get(obj, id_excl);
|
|
|
|
if (!NIL_P(excl)) {
|
|
|
|
range_init(range, beg, end, RBOOL(RTEST(excl)));
|
|
|
|
}
|
2007-09-08 11:07:18 -04:00
|
|
|
return range;
|
|
|
|
}
|
2005-12-11 20:01:29 -05:00
|
|
|
|
2007-11-23 02:00:50 -05:00
|
|
|
static VALUE
|
|
|
|
range_alloc(VALUE klass)
|
|
|
|
{
|
2016-11-09 19:49:16 -05:00
|
|
|
/* rb_struct_alloc_noinit itself should not be used because
|
|
|
|
* rb_marshal_define_compat uses equality of allocation function */
|
2007-11-23 02:00:50 -05:00
|
|
|
return rb_struct_alloc_noinit(klass);
|
|
|
|
}
|
|
|
|
|
2019-12-04 01:31:51 -05:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-22 15:51:11 -04:00
|
|
|
* count -> integer
|
2021-09-18 08:27:02 -04:00
|
|
|
* count(object) -> integer
|
|
|
|
* count {|element| ... } -> integer
|
|
|
|
*
|
|
|
|
* Returns the count of elements, based on an argument or block criterion, if given.
|
|
|
|
*
|
|
|
|
* With no argument and no block given, returns the number of elements:
|
|
|
|
*
|
|
|
|
* (1..4).count # => 4
|
|
|
|
* (1...4).count # => 3
|
|
|
|
* ('a'..'d').count # => 4
|
|
|
|
* ('a'...'d').count # => 3
|
|
|
|
* (1..).count # => Infinity
|
|
|
|
* (..4).count # => Infinity
|
|
|
|
*
|
|
|
|
* With argument +object+, returns the number of +object+ found in +self+,
|
|
|
|
* which will usually be zero or one:
|
|
|
|
*
|
|
|
|
* (1..4).count(2) # => 1
|
|
|
|
* (1..4).count(5) # => 0
|
|
|
|
* (1..4).count('a') # => 0
|
|
|
|
*
|
|
|
|
* With a block given, calls the block with each element;
|
|
|
|
* returns the number of elements for which the block returns a truthy value:
|
2019-12-04 01:31:51 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* (1..4).count {|element| element < 3 } # => 2
|
2019-12-04 01:31:51 -05:00
|
|
|
*
|
2021-09-18 08:27:02 -04:00
|
|
|
* Related: Range#size.
|
2019-12-04 01:31:51 -05:00
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
range_count(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
|
|
|
if (argc != 0) {
|
2019-12-19 19:19:39 -05:00
|
|
|
/* It is odd for instance (1...).count(0) to return Infinity. Just let
|
2019-12-04 01:31:51 -05:00
|
|
|
* it loop. */
|
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
else if (rb_block_given_p()) {
|
2019-12-19 19:19:39 -05:00
|
|
|
/* Likewise it is odd for instance (1...).count {|x| x == 0 } to return
|
2019-12-04 01:31:51 -05: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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-09-20 14:41:55 -04:00
|
|
|
/* A \Range object represents a collection of values
|
|
|
|
* that are between given begin and end values.
|
|
|
|
*
|
|
|
|
* A range may be created using a literal:
|
|
|
|
*
|
|
|
|
* # Ranges that use '..' to include the given end value.
|
|
|
|
* (1..4).to_a # => [1, 2, 3, 4]
|
|
|
|
* ('a'..'d').to_a # => ["a", "b", "c", "d"]
|
|
|
|
* # Ranges that use '...' to exclude the given end value.
|
|
|
|
* (1...4).to_a # => [1, 2, 3]
|
|
|
|
* ('a'...'d').to_a # => ["a", "b", "c"]
|
|
|
|
*
|
|
|
|
* A range may be created using method Range.new:
|
|
|
|
*
|
|
|
|
* # Ranges that by default include the given end value.
|
|
|
|
* Range.new(1, 4).to_a # => [1, 2, 3, 4]
|
|
|
|
* Range.new('a', 'd').to_a # => ["a", "b", "c", "d"]
|
|
|
|
* # Ranges that use third argument +exclude_end+ to exclude the given end value.
|
|
|
|
* Range.new(1, 4, true).to_a # => [1, 2, 3]
|
|
|
|
* Range.new('a', 'd', true).to_a # => ["a", "b", "c"]
|
|
|
|
*
|
|
|
|
* == Beginless Ranges
|
|
|
|
*
|
|
|
|
* A _beginless_ _range_ has a definite end value, but a +nil+ begin value.
|
|
|
|
* Such a range includes all values up to the end value.
|
|
|
|
*
|
|
|
|
* r = (..4) # => nil..4
|
|
|
|
* r.begin # => nil
|
|
|
|
* r.include?(-50) # => true
|
|
|
|
* r.include?(4) # => true
|
|
|
|
*
|
|
|
|
* r = (...4) # => nil...4
|
|
|
|
* r.include?(4) # => false
|
|
|
|
*
|
|
|
|
* Range.new(nil, 4) # => nil..4
|
|
|
|
* Range.new(nil, 4, true) # => nil...4
|
|
|
|
*
|
|
|
|
* A beginless range may be used to slice an array:
|
|
|
|
*
|
|
|
|
* a = [1, 2, 3, 4]
|
|
|
|
* r = (..2) # => nil...2
|
|
|
|
* a[r] # => [1, 2]
|
|
|
|
*
|
|
|
|
* \Method +each+ for a beginless range raises an exception.
|
|
|
|
*
|
|
|
|
* == Endless Ranges
|
|
|
|
*
|
|
|
|
* An _endless_ _range_ has a definite begin value, but a +nil+ end value.
|
|
|
|
* Such a range includes all values from the begin value.
|
|
|
|
*
|
|
|
|
* r = (1..) # => 1..
|
|
|
|
* r.end # => nil
|
|
|
|
* r.include?(50) # => true
|
|
|
|
*
|
|
|
|
* Range.new(1, nil) # => 1..
|
|
|
|
*
|
|
|
|
* The literal for an endless range may be written with either two dots
|
|
|
|
* or three.
|
|
|
|
* The range has the same elements, either way.
|
|
|
|
* But note that the two are not equal:
|
|
|
|
*
|
|
|
|
* r0 = (1..) # => 1..
|
|
|
|
* r1 = (1...) # => 1...
|
|
|
|
* r0.begin == r1.begin # => true
|
|
|
|
* r0.end == r1.end # => true
|
|
|
|
* r0 == r1 # => false
|
|
|
|
*
|
|
|
|
* An endless range may be used to slice an array:
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-20 14:41:55 -04:00
|
|
|
* a = [1, 2, 3, 4]
|
|
|
|
* r = (2..) # => 2..
|
|
|
|
* a[r] # => [3, 4]
|
|
|
|
*
|
|
|
|
* \Method +each+ for an endless range calls the given block indefinitely:
|
|
|
|
*
|
|
|
|
* a = []
|
|
|
|
* r = (1..)
|
|
|
|
* r.each do |i|
|
|
|
|
* a.push(i) if i.even?
|
|
|
|
* break if i > 10
|
|
|
|
* end
|
|
|
|
* a # => [2, 4, 6, 8, 10]
|
|
|
|
*
|
|
|
|
* == Ranges and Other Classes
|
|
|
|
*
|
|
|
|
* An object may be put into a range if its class implements
|
|
|
|
* instance method <tt><=></tt>.
|
|
|
|
* Ruby core classes that do so include Array, Complex, File::Stat,
|
|
|
|
* Float, Integer, Kernel, Module, Numeric, Rational, String, Symbol, and Time.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* t0 = Time.now # => 2021-09-19 09:22:48.4854986 -0500
|
|
|
|
* t1 = Time.now # => 2021-09-19 09:22:56.0365079 -0500
|
|
|
|
* t2 = Time.now # => 2021-09-19 09:23:08.5263283 -0500
|
|
|
|
* (t0..t2).include?(t1) # => true
|
|
|
|
* (t0..t1).include?(t2) # => false
|
|
|
|
*
|
|
|
|
* A range can be iterated over only if its elements
|
|
|
|
* implement instance method +succ+.
|
|
|
|
* Ruby core classes that do so include Integer, String, and Symbol
|
|
|
|
* (but not the other classes mentioned above).
|
|
|
|
*
|
|
|
|
* Iterator methods include:
|
|
|
|
*
|
|
|
|
* - In \Range itself: #each, #step, and #%
|
|
|
|
* - Included from module Enumerable: #each_entry, #each_with_index,
|
|
|
|
* #each_with_object, #each_slice, #each_cons, and #reverse_each.
|
|
|
|
*
|
|
|
|
* Example:
|
|
|
|
*
|
|
|
|
* a = []
|
|
|
|
* (1..4).each {|i| a.push(i) }
|
|
|
|
* a # => [1, 2, 3, 4]
|
|
|
|
*
|
|
|
|
* == Ranges and User-Defined Classes
|
|
|
|
*
|
|
|
|
* A user-defined class that is to be used in a range
|
|
|
|
* must implement instance <tt><=></tt>;
|
|
|
|
* see {Integer#<=>}[Integer.html#label-method-i-3C-3D-3E].
|
|
|
|
* To make iteration available, it must also implement
|
|
|
|
* instance method +succ+; see Integer#succ.
|
|
|
|
*
|
|
|
|
* The class below implements both <tt><=></tt> and +succ+,
|
|
|
|
* and so can be used both to construct ranges and to iterate over them.
|
|
|
|
* Note that the Comparable module is included
|
|
|
|
* so the <tt>==</tt> method is defined in terms of <tt><=></tt>.
|
|
|
|
*
|
|
|
|
* # Represent a string of 'X' characters.
|
|
|
|
* class Xs
|
|
|
|
* include Comparable
|
|
|
|
* attr_accessor :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
|
2011-12-05 18:36:53 -05:00
|
|
|
*
|
2021-09-20 14:41:55 -04:00
|
|
|
* r = Xs.new(3)..Xs.new(6) #=> XXX..XXXXXX
|
|
|
|
* r.to_a #=> [XXX, XXXX, XXXXX, XXXXXX]
|
|
|
|
* r.include?(Xs.new(5)) #=> true
|
|
|
|
* r.include?(Xs.new(7)) #=> false
|
2009-02-22 09:23:33 -05:00
|
|
|
*
|
2021-09-22 15:51:11 -04:00
|
|
|
* == What's Here
|
|
|
|
*
|
|
|
|
* First, what's elsewhere. \Class \Range:
|
|
|
|
*
|
|
|
|
* - Inherits from {class Object}[Object.html#class-Object-label-What-27s+Here].
|
|
|
|
* - Includes {module Enumerable}[Enumerable.html#module-Enumerable-label-What-27s+Here],
|
|
|
|
* which provides dozens of additional methods.
|
|
|
|
*
|
|
|
|
* Here, class \Range provides methods that are useful for:
|
|
|
|
*
|
|
|
|
* - {Creating a Range}[#class-Range-label-Methods+for+Creating+a+Range]
|
|
|
|
* - {Querying}[#class-Range-label-Methods+for+Querying]
|
|
|
|
* - {Comparing}[#class-Range-label-Methods+for+Comparing]
|
|
|
|
* - {Iterating}[#class-Range-label-Methods+for+Iterating]
|
|
|
|
* - {Converting}[#class-Range-label-Methods+for+Converting]
|
|
|
|
*
|
|
|
|
* === Methods for Creating a \Range
|
|
|
|
*
|
|
|
|
* - ::new:: Returns a new range.
|
|
|
|
*
|
|
|
|
* === Methods for Querying
|
|
|
|
*
|
|
|
|
* - #begin:: Returns the begin value given for +self+.
|
|
|
|
* - #bsearch:: Returns an element from +self+ selected by a binary search.
|
|
|
|
* - #count:: Returns a count of elements in +self+.
|
|
|
|
* - #end:: Returns the end value given for +self+.
|
|
|
|
* - #exclude_end?:: Returns whether the end object is excluded.
|
|
|
|
* - #first:: Returns the first elements of +self+.
|
|
|
|
* - #hash:: Returns the integer hash code.
|
|
|
|
* - #last:: Returns the last elements of +self+.
|
|
|
|
* - #max:: Returns the maximum values in +self+.
|
|
|
|
* - #min:: Returns the minimum values in +self+.
|
|
|
|
* - #minmax:: Returns the minimum and maximum values in +self+.
|
|
|
|
* - #size:: Returns the count of elements in +self+.
|
|
|
|
*
|
|
|
|
* === Methods for Comparing
|
|
|
|
*
|
|
|
|
* - {#==}[#method-i-3D-3D]:: Returns whether a given object is equal to +self+
|
|
|
|
* (uses #==).
|
|
|
|
* - #===:: Returns whether the given object is between the begin and end values.
|
|
|
|
* - #cover?:: Returns whether a given object is within +self+.
|
|
|
|
* - #eql?:: Returns whether a given object is equal to +self+ (uses #eql?).
|
|
|
|
* - #include? (aliased as #member?):: Returns whether a given object
|
|
|
|
* is an element of +self+.
|
|
|
|
*
|
|
|
|
* === Methods for Iterating
|
|
|
|
*
|
|
|
|
* - #%:: Requires argument +n+; calls the block with each +n+th element of +self+.
|
|
|
|
* - #each:: Calls the block with each element of +self+.
|
|
|
|
* - #step:: Takes optional argument +n+ (defaults to 1);
|
|
|
|
calls the block with each +n+th element of +self+.
|
|
|
|
*
|
|
|
|
* === Methods for Converting
|
|
|
|
*
|
|
|
|
* - #inspect:: Returns a string representation of +self+ (uses #inspect).
|
|
|
|
* - #to_a (aliased as #entries):: Returns elements of +self+ in an array.
|
|
|
|
* - #to_s:: Returns a string representation of +self+ (uses #to_s).
|
|
|
|
*
|
2003-12-23 23:29:32 -05:00
|
|
|
*/
|
|
|
|
|
1998-01-16 07:13:05 -05: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 06:44:21 -04:00
|
|
|
Init_Range(void)
|
1998-01-16 07:13:05 -05:00
|
|
|
{
|
2020-09-25 13:56:30 -04:00
|
|
|
id_beg = rb_intern_const("begin");
|
|
|
|
id_end = rb_intern_const("end");
|
|
|
|
id_excl = rb_intern_const("excl");
|
2007-09-08 11:07:18 -04:00
|
|
|
|
2007-11-23 02:00:50 -05:00
|
|
|
rb_cRange = rb_struct_define_without_accessor(
|
|
|
|
"Range", rb_cObject, range_alloc,
|
2007-11-22 23:35:53 -05:00
|
|
|
"begin", "end", "excl", NULL);
|
2007-09-08 11:07:18 -04:00
|
|
|
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_include_module(rb_cRange, rb_mEnumerable);
|
2007-09-08 11:07:18 -04:00
|
|
|
rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader);
|
2000-02-29 03:05:32 -05:00
|
|
|
rb_define_method(rb_cRange, "initialize", range_initialize, -1);
|
2008-08-20 17:02:54 -04:00
|
|
|
rb_define_method(rb_cRange, "initialize_copy", range_initialize_copy, 1);
|
2000-11-27 04:23:38 -05:00
|
|
|
rb_define_method(rb_cRange, "==", range_eq, 1);
|
2007-07-26 09:37:13 -04:00
|
|
|
rb_define_method(rb_cRange, "===", range_eqq, 1);
|
2001-11-08 04:21:59 -05:00
|
|
|
rb_define_method(rb_cRange, "eql?", range_eql, 1);
|
|
|
|
rb_define_method(rb_cRange, "hash", range_hash, 0);
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_define_method(rb_cRange, "each", range_each, 0);
|
2001-08-14 04:13:31 -04:00
|
|
|
rb_define_method(rb_cRange, "step", range_step, -1);
|
2018-09-27 22:18:58 -04:00
|
|
|
rb_define_method(rb_cRange, "%", range_percent_step, 1);
|
2012-11-14 10:53:50 -05:00
|
|
|
rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
|
2007-10-18 02:58:35 -04:00
|
|
|
rb_define_method(rb_cRange, "begin", range_begin, 0);
|
2007-10-18 04:14:21 -04:00
|
|
|
rb_define_method(rb_cRange, "end", range_end, 0);
|
2007-10-18 02: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 10:45:11 -05:00
|
|
|
rb_define_method(rb_cRange, "min", range_min, -1);
|
|
|
|
rb_define_method(rb_cRange, "max", range_max, -1);
|
2019-06-08 01:03:02 -04:00
|
|
|
rb_define_method(rb_cRange, "minmax", range_minmax, 0);
|
2012-11-06 12:14:46 -05:00
|
|
|
rb_define_method(rb_cRange, "size", range_size, 0);
|
2018-06-21 22:58:37 -04:00
|
|
|
rb_define_method(rb_cRange, "to_a", range_to_a, 0);
|
|
|
|
rb_define_method(rb_cRange, "entries", range_to_a, 0);
|
1999-01-19 23:59:39 -05:00
|
|
|
rb_define_method(rb_cRange, "to_s", range_to_s, 0);
|
|
|
|
rb_define_method(rb_cRange, "inspect", range_inspect, 0);
|
|
|
|
|
1999-08-13 01:45:20 -04:00
|
|
|
rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
|
|
|
|
|
2004-10-19 06:25:23 -04:00
|
|
|
rb_define_method(rb_cRange, "member?", range_include, 1);
|
2002-06-11 03:02:23 -04:00
|
|
|
rb_define_method(rb_cRange, "include?", range_include, 1);
|
2005-12-11 20:01:29 -05:00
|
|
|
rb_define_method(rb_cRange, "cover?", range_cover, 1);
|
2019-12-04 01:31:51 -05:00
|
|
|
rb_define_method(rb_cRange, "count", range_count, -1);
|
1998-01-16 07:13:05 -05:00
|
|
|
}
|