2000-05-01 09:42:38 +00:00
|
|
|
/**********************************************************************
|
1998-01-16 12:13:05 +00:00
|
|
|
|
|
|
|
range.c -
|
|
|
|
|
|
|
|
$Author$
|
|
|
|
created at: Thu Aug 19 17:46:47 JST 1993
|
|
|
|
|
* encoding.c: provide basic features for M17N.
* parse.y: encoding aware parsing.
* parse.y (pragma_encoding): encoding specification pragma.
* parse.y (rb_intern3): encoding specified symbols.
* string.c (rb_str_length): length based on characters.
for older behavior, bytesize method added.
* string.c (rb_str_index_m): index based on characters. rindex as
well.
* string.c (succ_char): encoding aware succeeding string.
* string.c (rb_str_reverse): reverse based on characters.
* string.c (rb_str_inspect): encoding aware string description.
* string.c (rb_str_upcase_bang): encoding aware case conversion.
downcase, capitalize, swapcase as well.
* string.c (rb_str_tr_bang): tr based on characters. delete,
squeeze, tr_s, count as well.
* string.c (rb_str_split_m): split based on characters.
* string.c (rb_str_each_line): encoding aware each_line.
* string.c (rb_str_each_char): added. iteration based on
characters.
* string.c (rb_str_strip_bang): encoding aware whitespace
stripping. lstrip, rstrip as well.
* string.c (rb_str_justify): encoding aware justifying (ljust,
rjust, center).
* string.c (str_encoding): get encoding attribute from a string.
* re.c (rb_reg_initialize): encoding aware regular expression
* sprintf.c (rb_str_format): formatting (i.e. length count) based
on characters.
* io.c (rb_io_getc): getc to return one-character string.
for older behavior, getbyte method added.
* ext/stringio/stringio.c (strio_getc): ditto.
* io.c (rb_io_ungetc): allow pushing arbitrary string at the
current reading point.
* ext/stringio/stringio.c (strio_ungetc): ditto.
* ext/strscan/strscan.c: encoding support.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@13261 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2007-08-25 03:29:39 +00:00
|
|
|
Copyright (C) 1993-2007 Yukihiro Matsumoto
|
1998-01-16 12:13:05 +00:00
|
|
|
|
2000-05-01 09:42:38 +00:00
|
|
|
**********************************************************************/
|
1998-01-16 12:13:05 +00:00
|
|
|
|
2020-05-08 18:31:09 +09:00
|
|
|
#include "ruby/internal/config.h"
|
2019-12-04 17:16:30 +09:00
|
|
|
|
2019-01-06 00:46:36 +00:00
|
|
|
#include <assert.h>
|
2019-12-04 17:16:30 +09:00
|
|
|
#include <math.h>
|
1998-01-16 12:13:05 +00:00
|
|
|
|
2012-11-14 15:53:50 +00:00
|
|
|
#ifdef HAVE_FLOAT_H
|
|
|
|
#include <float.h>
|
|
|
|
#endif
|
2019-12-04 17:16:30 +09: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 15:53:50 +00:00
|
|
|
|
1999-01-20 04:59:39 +00:00
|
|
|
VALUE rb_cRange;
|
2018-04-19 15:19:00 +00:00
|
|
|
static ID id_beg, id_end, id_excl;
|
2015-05-01 22:39:14 +00:00
|
|
|
#define id_cmp idCmp
|
|
|
|
#define id_succ idSucc
|
2020-07-04 10:12:02 -07:00
|
|
|
#define id_min idMin
|
|
|
|
#define id_max idMax
|
1999-08-13 05:45:20 +00:00
|
|
|
|
2015-05-15 09:05:57 +00:00
|
|
|
static VALUE r_cover_p(VALUE, VALUE, VALUE, VALUE);
|
|
|
|
|
2013-10-25 05:18:26 +00: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 15:07:18 +00:00
|
|
|
|
|
|
|
#define EXCL(r) RTEST(RANGE_EXCL(r))
|
|
|
|
|
2000-02-29 08:05:32 +00:00
|
|
|
static void
|
2013-10-25 06:57:20 +00:00
|
|
|
range_init(VALUE range, VALUE beg, VALUE end, VALUE exclude_end)
|
1998-01-16 12:13:05 +00:00
|
|
|
{
|
2019-04-03 08:11:41 +00:00
|
|
|
if ((!FIXNUM_P(beg) || !FIXNUM_P(end)) && !NIL_P(beg) && !NIL_P(end)) {
|
2005-08-14 15:39:39 +00:00
|
|
|
VALUE v;
|
|
|
|
|
2017-04-25 11:42:43 +00:00
|
|
|
v = rb_funcall(beg, id_cmp, 1, end);
|
2006-12-31 15:02:22 +00:00
|
|
|
if (NIL_P(v))
|
2017-04-25 11:42:43 +00:00
|
|
|
rb_raise(rb_eArgError, "bad value for range");
|
1998-01-16 12:13:05 +00:00
|
|
|
}
|
|
|
|
|
2013-10-25 06:57:20 +00:00
|
|
|
RANGE_SET_EXCL(range, exclude_end);
|
2013-10-25 05:18:26 +00:00
|
|
|
RANGE_SET_BEG(range, beg);
|
2018-06-13 11:00:28 +00:00
|
|
|
RANGE_SET_END(range, end);
|
2020-09-25 18:05:55 +09:00
|
|
|
|
|
|
|
if (CLASS_OF(range) == rb_cRange) {
|
|
|
|
rb_obj_freeze(range);
|
|
|
|
}
|
1998-01-16 12:13:05 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
VALUE
|
2018-06-13 11:00:28 +00:00
|
|
|
rb_range_new(VALUE beg, VALUE end, int exclude_end)
|
1999-08-13 05:45:20 +00:00
|
|
|
{
|
2002-06-11 07:02:23 +00:00
|
|
|
VALUE range = rb_obj_alloc(rb_cRange);
|
2000-02-29 08:05:32 +00:00
|
|
|
|
2018-06-13 11:00:28 +00:00
|
|
|
range_init(range, beg, end, RBOOL(exclude_end));
|
2002-06-11 07:02:23 +00:00
|
|
|
return range;
|
1999-08-13 05:45:20 +00:00
|
|
|
}
|
|
|
|
|
2013-10-26 10:08:02 +00:00
|
|
|
static void
|
|
|
|
range_modify(VALUE range)
|
|
|
|
{
|
2016-11-10 10:39:51 +00:00
|
|
|
rb_check_frozen(range);
|
2013-10-26 10:08:02 +00:00
|
|
|
/* Ranges are immutable, so that they should be initialized only once. */
|
|
|
|
if (RANGE_EXCL(range) != Qnil) {
|
2015-10-28 06:24:12 +00:00
|
|
|
rb_name_err_raise("`initialize' called twice", range, ID2SYM(idInitialize));
|
2013-10-26 10:08:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2003-12-24 04:29:32 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 14:00:39 -05: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 14:23:33 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
1999-08-13 05:45:20 +00: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 10:44:21 +00:00
|
|
|
range_initialize(int argc, VALUE *argv, VALUE range)
|
1999-08-13 05:45:20 +00:00
|
|
|
{
|
2001-02-02 11:38:20 +00:00
|
|
|
VALUE beg, end, flags;
|
2009-02-22 14:23:33 +00:00
|
|
|
|
2001-02-02 11:38:20 +00:00
|
|
|
rb_scan_args(argc, argv, "21", &beg, &end, &flags);
|
2013-10-26 10:08:02 +00:00
|
|
|
range_modify(range);
|
2013-10-25 06:57:20 +00:00
|
|
|
range_init(range, beg, end, RBOOL(RTEST(flags)));
|
2000-02-29 08:05:32 +00:00
|
|
|
return Qnil;
|
1999-08-13 05:45:20 +00:00
|
|
|
}
|
|
|
|
|
2013-10-26 10:08:02 +00:00
|
|
|
/* :nodoc: */
|
|
|
|
static VALUE
|
|
|
|
range_initialize_copy(VALUE range, VALUE orig)
|
|
|
|
{
|
|
|
|
range_modify(range);
|
|
|
|
rb_struct_init_copy(range, orig);
|
|
|
|
return range;
|
|
|
|
}
|
2003-12-24 04:29:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 14:00:39 -05:00
|
|
|
* exclude_end? -> true or false
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05:00
|
|
|
* Returns +true+ if +self+ excludes its end value; +false+ otherwise:
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05: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-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
1999-08-13 05:45:20 +00: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 10:44:21 +00:00
|
|
|
range_exclude_end_p(VALUE range)
|
1998-01-16 12:13:05 +00:00
|
|
|
{
|
2021-08-02 12:06:44 +09:00
|
|
|
return RBOOL(EXCL(range));
|
1998-01-16 12:13:05 +00:00
|
|
|
}
|
|
|
|
|
2009-09-20 02:14:02 +00: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-02 12:06:44 +09:00
|
|
|
return RBOOL(EXCL(range) == EXCL(obj));
|
2009-09-20 02:14:02 +00:00
|
|
|
}
|
|
|
|
|
2003-12-24 04:29:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 14:00:39 -05: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>.
|
|
|
|
* - <tt>other.exclude_end? == self.include_end?</tt>.
|
|
|
|
*
|
|
|
|
* 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 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05:00
|
|
|
* Note that even with the same argument, the return values of #== and #eql? can differ:
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05:00
|
|
|
* (1..2) == (1..2.0) # => true
|
|
|
|
* (1..2).eql? (1..2.0) # => false
|
|
|
|
*
|
|
|
|
* Related: Range#eql?.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
2000-11-27 09:23:38 +00: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 10:44:21 +00:00
|
|
|
range_eq(VALUE range, VALUE obj)
|
2000-11-27 09:23:38 +00:00
|
|
|
{
|
2006-12-31 15:02:22 +00:00
|
|
|
if (range == obj)
|
|
|
|
return Qtrue;
|
2009-08-05 05:01:12 +00:00
|
|
|
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
2002-09-03 05:20:14 +00:00
|
|
|
return Qfalse;
|
2000-11-27 09:23:38 +00:00
|
|
|
|
2009-09-20 02:14:02 +00:00
|
|
|
return rb_exec_recursive_paired(recursive_equal, range, obj, obj);
|
2000-11-27 09:23:38 +00:00
|
|
|
}
|
|
|
|
|
2015-05-15 09:06:18 +00:00
|
|
|
/* compares _a_ and _b_ and returns:
|
|
|
|
* < 0: a < b
|
|
|
|
* = 0: a = b
|
2015-05-15 12:39:56 +00:00
|
|
|
* > 0: a > b or non-comparable
|
2015-05-15 09:06:18 +00:00
|
|
|
*/
|
2001-05-30 09:12:34 +00:00
|
|
|
static int
|
2015-05-15 09:06:18 +00:00
|
|
|
r_less(VALUE a, VALUE b)
|
2001-05-30 09:12:34 +00:00
|
|
|
{
|
|
|
|
VALUE r = rb_funcall(a, id_cmp, 1, b);
|
|
|
|
|
2006-12-31 15:02:22 +00:00
|
|
|
if (NIL_P(r))
|
2015-05-15 09:06:18 +00:00
|
|
|
return INT_MAX;
|
|
|
|
return rb_cmpint(r, a, b);
|
2001-05-30 09:12:34 +00:00
|
|
|
}
|
|
|
|
|
2009-09-20 02:14:02 +00: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-02 12:06:44 +09:00
|
|
|
return RBOOL(EXCL(range) == EXCL(obj));
|
2009-09-20 02:14:02 +00:00
|
|
|
}
|
|
|
|
|
2003-12-24 04:29:32 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 14:00:39 -05: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>.
|
|
|
|
* - <tt>other.exclude_end? == self.include_end?</tt>.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05:00
|
|
|
* Otherwise returns +false+.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05: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 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05: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-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
2001-11-08 09:21:59 +00: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 10:44:21 +00:00
|
|
|
range_eql(VALUE range, VALUE obj)
|
2001-11-08 09:21:59 +00:00
|
|
|
{
|
2006-12-31 15:02:22 +00:00
|
|
|
if (range == obj)
|
|
|
|
return Qtrue;
|
2009-08-05 05:01:12 +00:00
|
|
|
if (!rb_obj_is_kind_of(obj, rb_cRange))
|
2002-09-03 05:20:14 +00:00
|
|
|
return Qfalse;
|
2009-09-20 02:14:02 +00:00
|
|
|
return rb_exec_recursive_paired(recursive_eql, range, obj, obj);
|
2001-11-08 09:21:59 +00:00
|
|
|
}
|
|
|
|
|
2009-07-17 09:28:46 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 14:00:39 -05:00
|
|
|
* hash -> integer
|
2009-07-17 09:28:46 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05: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-14 01:27:43 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05:00
|
|
|
* Related: Range#eql?, Object#hash.
|
2009-07-17 09:28:46 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_hash(VALUE range)
|
|
|
|
{
|
2013-12-03 13:18:30 +00:00
|
|
|
st_index_t hash = EXCL(range);
|
|
|
|
VALUE v;
|
|
|
|
|
|
|
|
hash = rb_hash_start(hash);
|
|
|
|
v = rb_hash(RANGE_BEG(range));
|
|
|
|
hash = rb_hash_uint(hash, NUM2LONG(v));
|
|
|
|
v = rb_hash(RANGE_END(range));
|
|
|
|
hash = rb_hash_uint(hash, NUM2LONG(v));
|
|
|
|
hash = rb_hash_uint(hash, EXCL(range) << 24);
|
|
|
|
hash = rb_hash_end(hash);
|
|
|
|
|
2019-04-08 03:26:29 +00:00
|
|
|
return ST2FIX(hash);
|
2009-07-17 09:28:46 +00:00
|
|
|
}
|
|
|
|
|
2002-05-30 06:12:29 +00:00
|
|
|
static void
|
2018-04-28 11:16:54 +00:00
|
|
|
range_each_func(VALUE range, int (*func)(VALUE, VALUE), VALUE arg)
|
2002-05-30 06:12:29 +00:00
|
|
|
{
|
2004-05-14 16:39:15 +00:00
|
|
|
int c;
|
2008-04-06 17:11:50 +00:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
VALUE e = RANGE_END(range);
|
2008-04-07 03:15:26 +00:00
|
|
|
VALUE v = b;
|
2004-05-14 16:39:15 +00:00
|
|
|
|
2002-05-30 06:12:29 +00:00
|
|
|
if (EXCL(range)) {
|
2015-05-15 09:06:18 +00:00
|
|
|
while (r_less(v, e) < 0) {
|
2018-04-28 11:16:54 +00:00
|
|
|
if ((*func)(v, arg)) break;
|
2015-02-16 04:08:52 +00:00
|
|
|
v = rb_funcallv(v, id_succ, 0, 0);
|
2002-05-30 06:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else {
|
2015-05-15 09:06:18 +00:00
|
|
|
while ((c = r_less(v, e)) <= 0) {
|
2018-08-20 15:33:59 +00:00
|
|
|
if ((*func)(v, arg)) break;
|
2015-05-15 09:06:18 +00:00
|
|
|
if (!c) break;
|
2015-02-16 04:08:52 +00:00
|
|
|
v = rb_funcallv(v, id_succ, 0, 0);
|
2002-05-30 06:12:29 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-28 11:16:54 +00:00
|
|
|
static int
|
|
|
|
sym_step_i(VALUE i, VALUE arg)
|
2009-08-17 17:00:47 +00:00
|
|
|
{
|
2013-11-29 02:26:48 +00:00
|
|
|
VALUE *iter = (VALUE *)arg;
|
2009-08-17 17:00:47 +00:00
|
|
|
|
|
|
|
if (FIXNUM_P(iter[0])) {
|
|
|
|
iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
|
|
|
|
}
|
|
|
|
if (iter[0] == INT2FIX(0)) {
|
|
|
|
rb_yield(rb_str_intern(i));
|
|
|
|
iter[0] = iter[1];
|
|
|
|
}
|
2018-04-28 11:16:54 +00:00
|
|
|
return 0;
|
2009-08-17 17:00:47 +00:00
|
|
|
}
|
|
|
|
|
2018-04-28 11:16:54 +00:00
|
|
|
static int
|
|
|
|
step_i(VALUE i, VALUE arg)
|
2004-10-06 07:40:06 +00:00
|
|
|
{
|
2013-11-29 02:26:48 +00:00
|
|
|
VALUE *iter = (VALUE *)arg;
|
* array.c: moved to ANSI function style from K&R function style.
(used protoize on windows, so still K&R remains on #ifdef part of
other platforms. And `foo _((boo))' stuff is still there)
[ruby-dev:26975]
* bignum.c, class.c, compar.c, dir.c, dln.c, dmyext.c, enum.c,
enumerator.c, error.c, eval.c, file.c, gc.c, hash.c, inits.c,
io.c, main.c, marshal.c, math.c, numeric.c, object.c, pack.c,
prec.c, process.c, random.c, range.c, re.c, regcomp.c, regenc.c,
regerror.c, regexec.c, regparse.c, regparse.h, ruby.c, signal.c,
sprintf.c, st.c, string.c, struct.c, time.c, util.h, variable.c,
version.c: ditto.
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@9126 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2005-09-12 10:44:21 +00:00
|
|
|
|
2007-12-05 06:15:23 +00:00
|
|
|
if (FIXNUM_P(iter[0])) {
|
|
|
|
iter[0] -= INT2FIX(1) & ~FIXNUM_FLAG;
|
|
|
|
}
|
|
|
|
else {
|
2008-01-29 13:27:51 +00:00
|
|
|
iter[0] = rb_funcall(iter[0], '-', 1, INT2FIX(1));
|
2007-12-05 06:15:23 +00:00
|
|
|
}
|
|
|
|
if (iter[0] == INT2FIX(0)) {
|
2004-10-06 07:40:06 +00:00
|
|
|
rb_yield(i);
|
|
|
|
iter[0] = iter[1];
|
|
|
|
}
|
2018-04-28 11:16:54 +00:00
|
|
|
return 0;
|
2004-10-06 07:40:06 +00:00
|
|
|
}
|
|
|
|
|
2009-09-30 08:32:43 +00:00
|
|
|
static int
|
2009-10-02 15:31:05 +00:00
|
|
|
discrete_object_p(VALUE obj)
|
2009-09-30 08:32:43 +00:00
|
|
|
{
|
2009-10-02 15:31:05 +00:00
|
|
|
if (rb_obj_is_kind_of(obj, rb_cTime)) return FALSE; /* until Time#succ removed */
|
|
|
|
return rb_respond_to(obj, id_succ);
|
2009-09-30 08:32:43 +00:00
|
|
|
}
|
|
|
|
|
2015-05-03 01:02:15 +00: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 15:13:37 +09:00
|
|
|
default:
|
|
|
|
break;
|
2015-05-03 01:02:15 +00: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 17:15:00 +00:00
|
|
|
static VALUE
|
2016-07-25 12:33:15 +00:00
|
|
|
check_step_domain(VALUE step)
|
2012-11-06 17:15:00 +00:00
|
|
|
{
|
2016-07-25 12:33:15 +00:00
|
|
|
VALUE zero = INT2FIX(0);
|
|
|
|
int cmp;
|
|
|
|
if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
|
|
|
|
step = rb_to_int(step);
|
2012-11-06 17:15:00 +00:00
|
|
|
}
|
2016-07-25 12:33:15 +00:00
|
|
|
cmp = rb_cmpint(rb_funcallv(step, idCmp, 1, &zero), step, zero);
|
|
|
|
if (cmp < 0) {
|
2012-11-06 17:15:00 +00:00
|
|
|
rb_raise(rb_eArgError, "step can't be negative");
|
|
|
|
}
|
2016-07-25 12:33:15 +00:00
|
|
|
else if (cmp == 0) {
|
2012-11-06 17:15:00 +00:00
|
|
|
rb_raise(rb_eArgError, "step can't be 0");
|
|
|
|
}
|
2016-07-25 12:33:15 +00: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 17:15:00 +00:00
|
|
|
|
|
|
|
if (rb_obj_is_kind_of(b, rb_cNumeric) && rb_obj_is_kind_of(e, rb_cNumeric)) {
|
2013-03-06 06:30:03 +00:00
|
|
|
return ruby_num_interval_step_size(b, e, step, EXCL(range));
|
2012-11-06 17:15:00 +00:00
|
|
|
}
|
|
|
|
return Qnil;
|
|
|
|
}
|
2009-09-30 08:32:43 +00:00
|
|
|
|
2003-12-24 04:29:32 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-13 14:00:39 -05:00
|
|
|
* step(n = 1) {|element| ... } -> self
|
|
|
|
* step(n = 1) -> enumerator
|
|
|
|
*
|
|
|
|
* Iterates over the elements of +self+.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05:00
|
|
|
* With a block given and no argument,
|
|
|
|
* calls the block each element of the range; returns +self+:
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05: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 05:49:55 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05: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 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05: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 14:23:33 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05: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 23:36:53 +00:00
|
|
|
*
|
2021-09-13 14:00:39 -05:00
|
|
|
* e = (1..5).step(2) # => ((1..5).step(2))
|
|
|
|
* e.class # => Enumerator::ArithmeticSequence
|
|
|
|
* ('a'..'e').step # => #<Enumerator: ...>
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
2001-08-14 08:13:31 +00: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 10:44:21 +00:00
|
|
|
range_step(int argc, VALUE *argv, VALUE range)
|
2001-08-14 08:13:31 +00:00
|
|
|
{
|
2008-04-07 03:15:26 +00:00
|
|
|
VALUE b, e, step, tmp;
|
2001-08-14 08:13:31 +00:00
|
|
|
|
2007-09-08 15:07:18 +00:00
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2018-12-06 07:49:24 +00:00
|
|
|
step = (!rb_check_arity(argc, 0, 1) ? INT2FIX(1) : argv[0]);
|
2008-04-06 17:11:50 +00:00
|
|
|
|
2018-08-06 09:08:28 +00:00
|
|
|
if (!rb_block_given_p()) {
|
2020-10-23 15:26:51 +09:00
|
|
|
if (!rb_obj_is_kind_of(step, rb_cNumeric)) {
|
|
|
|
step = rb_to_int(step);
|
|
|
|
}
|
|
|
|
if (rb_equal(step, INT2FIX(0))) {
|
|
|
|
rb_raise(rb_eArgError, "step can't be 0");
|
|
|
|
}
|
|
|
|
|
2019-04-04 03:34:52 +00: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 09:08:28 +00:00
|
|
|
return rb_arith_seq_new(range, ID2SYM(rb_frame_this_func()), argc, argv,
|
|
|
|
range_step_size, b, e, step, EXCL(range));
|
|
|
|
}
|
|
|
|
|
|
|
|
RETURN_SIZED_ENUMERATOR(range, argc, argv, range_step_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
step = check_step_domain(step);
|
|
|
|
|
2018-04-19 15:18:50 +00:00
|
|
|
if (FIXNUM_P(b) && NIL_P(e) && FIXNUM_P(step)) {
|
|
|
|
long i = FIX2LONG(b), unit = FIX2LONG(step);
|
2018-04-20 00:10:46 +00:00
|
|
|
do {
|
2018-04-19 15:18:50 +00:00
|
|
|
rb_yield(LONG2FIX(i));
|
2018-04-20 00:10:46 +00:00
|
|
|
i += unit; /* FIXABLE+FIXABLE never overflow */
|
|
|
|
} while (FIXABLE(i));
|
2018-04-19 15:18:50 +00:00
|
|
|
b = LONG2NUM(i);
|
|
|
|
|
2018-04-20 00:23:01 +00:00
|
|
|
for (;; b = rb_big_plus(b, step))
|
2018-04-19 15:18:50 +00:00
|
|
|
rb_yield(b);
|
|
|
|
}
|
|
|
|
else if (FIXNUM_P(b) && FIXNUM_P(e) && FIXNUM_P(step)) { /* fixnums are special */
|
2002-05-30 06:12:29 +00:00
|
|
|
long end = FIX2LONG(e);
|
2008-05-02 07:15:28 +00:00
|
|
|
long i, unit = FIX2LONG(step);
|
2002-05-30 06:12:29 +00:00
|
|
|
|
2006-12-31 15:02:22 +00:00
|
|
|
if (!EXCL(range))
|
|
|
|
end += 1;
|
2009-02-22 14:23:33 +00:00
|
|
|
i = FIX2LONG(b);
|
2007-09-09 16:11:28 +00:00
|
|
|
while (i < end) {
|
2002-08-21 15:47:54 +00:00
|
|
|
rb_yield(LONG2NUM(i));
|
2007-09-09 16:11:28 +00:00
|
|
|
if (i + unit < i) break;
|
|
|
|
i += unit;
|
2001-08-14 08:13:31 +00:00
|
|
|
}
|
2008-04-06 17:11:50 +00:00
|
|
|
|
|
|
|
}
|
2018-04-19 15:18:50 +00:00
|
|
|
else if (SYMBOL_P(b) && (NIL_P(e) || SYMBOL_P(e))) { /* symbols are special */
|
2018-04-28 11:16:54 +00:00
|
|
|
VALUE iter[2];
|
2009-08-17 17:00:47 +00:00
|
|
|
iter[0] = INT2FIX(1);
|
|
|
|
iter[1] = step;
|
2018-04-19 15:18:50 +00:00
|
|
|
|
2018-04-28 11:16:54 +00:00
|
|
|
b = rb_sym2str(b);
|
2018-04-19 15:18:50 +00:00
|
|
|
if (NIL_P(e)) {
|
2018-04-28 11:16:54 +00:00
|
|
|
rb_str_upto_endless_each(b, sym_step_i, (VALUE)iter);
|
2018-04-19 15:18:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2018-04-28 11:16:54 +00:00
|
|
|
rb_str_upto_each(b, rb_sym2str(e), EXCL(range), sym_step_i, (VALUE)iter);
|
2018-04-19 15:18:50 +00:00
|
|
|
}
|
2009-08-17 17:00:47 +00:00
|
|
|
}
|
2018-04-19 15:18:50 +00:00
|
|
|
else if (ruby_float_step(b, e, step, EXCL(range), TRUE)) {
|
2009-01-04 02:58:45 +00:00
|
|
|
/* done */
|
|
|
|
}
|
2008-04-06 17:11:50 +00: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 09:57:47 +00:00
|
|
|
ID op = EXCL(range) ? '<' : idLE;
|
2009-01-04 23:20:39 +00:00
|
|
|
VALUE v = b;
|
|
|
|
int i = 0;
|
2008-04-06 17:11:50 +00:00
|
|
|
|
2018-04-19 15:18:50 +00:00
|
|
|
while (NIL_P(e) || RTEST(rb_funcall(v, op, 1, e))) {
|
2009-01-04 23:20:39 +00:00
|
|
|
rb_yield(v);
|
|
|
|
i++;
|
|
|
|
v = rb_funcall(b, '+', 1, rb_funcall(INT2NUM(i), '*', 1, step));
|
2008-04-06 17:11:50 +00:00
|
|
|
}
|
2001-08-14 08:13:31 +00:00
|
|
|
}
|
2002-05-30 06:12:29 +00:00
|
|
|
else {
|
2008-04-06 17:11:50 +00:00
|
|
|
tmp = rb_check_string_type(b);
|
2001-08-14 08:13:31 +00:00
|
|
|
|
2003-06-07 15:34:31 +00:00
|
|
|
if (!NIL_P(tmp)) {
|
2018-04-28 11:16:54 +00:00
|
|
|
VALUE iter[2];
|
2003-06-07 15:34:31 +00:00
|
|
|
|
|
|
|
b = tmp;
|
2007-12-05 06:15:23 +00:00
|
|
|
iter[0] = INT2FIX(1);
|
|
|
|
iter[1] = step;
|
2018-04-19 15:18:50 +00:00
|
|
|
|
|
|
|
if (NIL_P(e)) {
|
2018-04-28 11:16:54 +00:00
|
|
|
rb_str_upto_endless_each(b, step_i, (VALUE)iter);
|
2018-04-19 15:18:50 +00:00
|
|
|
}
|
|
|
|
else {
|
2018-04-28 11:16:54 +00:00
|
|
|
rb_str_upto_each(b, e, EXCL(range), step_i, (VALUE)iter);
|
2018-04-19 15:18:50 +00:00
|
|
|
}
|
2003-06-07 15:34:31 +00:00
|
|
|
}
|
|
|
|
else {
|
2007-12-05 06:15:23 +00:00
|
|
|
VALUE args[2];
|
2003-06-07 15:34:31 +00:00
|
|
|
|
2009-09-30 08:32:43 +00: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 06:47:45 +00:00
|
|
|
rb_raise(rb_eTypeError, "can't iterate from %s",
|
2003-06-07 15:34:31 +00:00
|
|
|
rb_obj_classname(b));
|
|
|
|
}
|
2007-12-05 06:15:23 +00:00
|
|
|
args[0] = INT2FIX(1);
|
|
|
|
args[1] = step;
|
2013-11-29 02:26:48 +00:00
|
|
|
range_each_func(range, step_i, (VALUE)args);
|
2003-06-07 15:34:31 +00:00
|
|
|
}
|
2001-08-14 08:13:31 +00:00
|
|
|
}
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2018-09-28 02:18:58 +00:00
|
|
|
static VALUE
|
|
|
|
range_percent_step(VALUE range, VALUE step)
|
|
|
|
{
|
2018-09-28 09:23:35 +00:00
|
|
|
return range_step(1, &step, range);
|
2018-09-28 02:18:58 +00:00
|
|
|
}
|
|
|
|
|
2013-01-29 22:00:36 +00:00
|
|
|
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
|
|
|
|
union int64_double {
|
2013-01-30 06:20:26 +00:00
|
|
|
int64_t i;
|
|
|
|
double d;
|
2013-01-29 22:00:36 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
static VALUE
|
2013-01-30 06:20:26 +00:00
|
|
|
int64_as_double_to_num(int64_t i)
|
|
|
|
{
|
2013-01-29 22:00:36 +00:00
|
|
|
union int64_double convert;
|
|
|
|
if (i < 0) {
|
|
|
|
convert.i = -i;
|
|
|
|
return DBL2NUM(-convert.d);
|
2013-01-30 06:20:26 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-01-29 22:00:36 +00:00
|
|
|
convert.i = i;
|
|
|
|
return DBL2NUM(convert.d);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static int64_t
|
2013-01-30 06:20:26 +00:00
|
|
|
double_as_int64(double d)
|
|
|
|
{
|
2013-01-29 22:00:36 +00:00
|
|
|
union int64_double convert;
|
|
|
|
convert.d = fabs(d);
|
|
|
|
return d < 0 ? -convert.i : convert.i;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
2013-01-30 05:46:48 +00:00
|
|
|
static int
|
2013-01-30 06:20:26 +00:00
|
|
|
is_integer_p(VALUE v)
|
|
|
|
{
|
2018-04-19 15:19:00 +00: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 05:46:48 +00:00
|
|
|
return RTEST(is_int) && is_int != Qundef;
|
|
|
|
}
|
|
|
|
|
2018-04-19 15:18:57 +00:00
|
|
|
static VALUE
|
|
|
|
bsearch_integer_range(VALUE beg, VALUE end, int excl)
|
|
|
|
{
|
|
|
|
VALUE satisfied = Qnil;
|
|
|
|
int smaller;
|
|
|
|
|
|
|
|
#define BSEARCH_CHECK(expr) \
|
|
|
|
do { \
|
|
|
|
VALUE val = (expr); \
|
|
|
|
VALUE v = rb_yield(val); \
|
|
|
|
if (FIXNUM_P(v)) { \
|
|
|
|
if (v == INT2FIX(0)) return val; \
|
|
|
|
smaller = (SIGNED_VALUE)v < 0; \
|
|
|
|
} \
|
|
|
|
else if (v == Qtrue) { \
|
|
|
|
satisfied = val; \
|
|
|
|
smaller = 1; \
|
|
|
|
} \
|
|
|
|
else if (v == Qfalse || v == Qnil) { \
|
|
|
|
smaller = 0; \
|
|
|
|
} \
|
|
|
|
else if (rb_obj_is_kind_of(v, rb_cNumeric)) { \
|
|
|
|
int cmp = rb_cmpint(rb_funcall(v, id_cmp, 1, INT2FIX(0)), v, INT2FIX(0)); \
|
|
|
|
if (!cmp) return val; \
|
|
|
|
smaller = cmp < 0; \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
rb_raise(rb_eTypeError, "wrong argument type %"PRIsVALUE \
|
|
|
|
" (must be numeric, true, false or nil)", \
|
|
|
|
rb_obj_class(v)); \
|
|
|
|
} \
|
|
|
|
} while (0)
|
|
|
|
|
|
|
|
VALUE low = rb_to_int(beg);
|
|
|
|
VALUE high = rb_to_int(end);
|
|
|
|
VALUE mid, org_high;
|
2018-04-19 15:19:00 +00:00
|
|
|
ID id_div;
|
|
|
|
CONST_ID(id_div, "div");
|
|
|
|
|
2018-04-19 15:18:57 +00: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 15:53:50 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 17:51:31 -05:00
|
|
|
* bsearch {|obj| block } -> value
|
2012-11-14 15:53:50 +00:00
|
|
|
*
|
2021-09-14 16:08:21 -05:00
|
|
|
* Returns an element from +self+ selected by a binary search.
|
2012-11-14 15:53:50 +00:00
|
|
|
*
|
2021-09-15 09:39:43 +09:00
|
|
|
* See {Binary Searching}[rdoc-ref:bsearch.rdoc].
|
2012-11-14 15:53:50 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_bsearch(VALUE range)
|
|
|
|
{
|
2015-01-13 03:51:35 +00:00
|
|
|
VALUE beg, end, satisfied = Qnil;
|
|
|
|
int smaller;
|
2012-11-14 15:53:50 +00:00
|
|
|
|
2013-01-29 22:00:36 +00: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 05:11:03 +00:00
|
|
|
RETURN_ENUMERATOR(range, 0, 0); \
|
2013-01-29 22:00:36 +00:00
|
|
|
if (EXCL(range)) high--; \
|
|
|
|
org_high = high; \
|
|
|
|
while (low < high) { \
|
|
|
|
mid = ((high < 0) == (low < 0)) ? low + ((high - low) / 2) \
|
|
|
|
: (low < -high) ? -((-1 - low - high)/2 + 1) : (low + high) / 2; \
|
|
|
|
BSEARCH_CHECK(conv(mid)); \
|
|
|
|
if (smaller) { \
|
|
|
|
high = mid; \
|
|
|
|
} \
|
|
|
|
else { \
|
|
|
|
low = mid + 1; \
|
|
|
|
} \
|
|
|
|
} \
|
|
|
|
if (low == org_high) { \
|
|
|
|
BSEARCH_CHECK(conv(low)); \
|
|
|
|
if (!smaller) return Qnil; \
|
|
|
|
} \
|
2015-01-13 03:51:35 +00:00
|
|
|
return satisfied; \
|
2013-01-29 22:00:36 +00:00
|
|
|
} while (0)
|
|
|
|
|
|
|
|
|
2012-11-14 15:53:50 +00: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 22:00:36 +00:00
|
|
|
BSEARCH(INT2FIX);
|
2012-11-14 15:53:50 +00:00
|
|
|
}
|
2013-01-29 22:00:36 +00:00
|
|
|
#if SIZEOF_DOUBLE == 8 && defined(HAVE_INT64_T)
|
2021-09-11 09:56:59 +09:00
|
|
|
else if (RB_FLOAT_TYPE_P(beg) || RB_FLOAT_TYPE_P(end)) {
|
2019-04-03 08:11:41 +00: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 22:00:36 +00:00
|
|
|
int64_t mid, org_high;
|
|
|
|
BSEARCH(int64_as_double_to_num);
|
2012-11-14 15:53:50 +00:00
|
|
|
}
|
2013-01-29 22:00:36 +00:00
|
|
|
#endif
|
2013-01-30 05:46:48 +00:00
|
|
|
else if (is_integer_p(beg) && is_integer_p(end)) {
|
2013-01-30 05:11:03 +00:00
|
|
|
RETURN_ENUMERATOR(range, 0, 0);
|
2018-04-19 15:18:57 +00: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 15:19:00 +00:00
|
|
|
VALUE mid = rb_funcall(beg, '+', 1, diff);
|
2012-11-14 15:53:50 +00:00
|
|
|
BSEARCH_CHECK(mid);
|
|
|
|
if (smaller) {
|
2018-04-19 15:18:57 +00:00
|
|
|
return bsearch_integer_range(beg, mid, 0);
|
2012-11-14 15:53:50 +00:00
|
|
|
}
|
2018-04-19 15:19:00 +00:00
|
|
|
diff = rb_funcall(diff, '*', 1, LONG2FIX(2));
|
2012-11-14 15:53:50 +00:00
|
|
|
}
|
|
|
|
}
|
2019-04-03 08:11:41 +00: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 15:53:50 +00:00
|
|
|
else {
|
|
|
|
rb_raise(rb_eTypeError, "can't do binary search for %s", rb_obj_classname(beg));
|
|
|
|
}
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2018-04-28 11:16:54 +00:00
|
|
|
static int
|
|
|
|
each_i(VALUE v, VALUE arg)
|
2002-05-30 06:12:29 +00:00
|
|
|
{
|
2004-10-06 07:40:06 +00:00
|
|
|
rb_yield(v);
|
2018-04-28 11:16:54 +00:00
|
|
|
return 0;
|
2002-05-30 06:12:29 +00:00
|
|
|
}
|
|
|
|
|
2018-04-28 11:16:54 +00:00
|
|
|
static int
|
|
|
|
sym_each_i(VALUE v, VALUE arg)
|
2009-08-17 17:00:47 +00:00
|
|
|
{
|
2021-07-11 13:56:03 +09:00
|
|
|
return each_i(rb_str_intern(v), arg);
|
2009-08-17 17:00:47 +00:00
|
|
|
}
|
|
|
|
|
2012-11-06 17:14:46 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 17:51:31 -05:00
|
|
|
* size -> non_negative_integer or Infinity or nil
|
2012-11-06 17:14:46 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* Returns the count of elements in +self+
|
|
|
|
* if both begin and end values are numeric;
|
|
|
|
* otherwise, returns +nil+:
|
2012-11-06 17:14:46 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* (1..4).size # => 4
|
|
|
|
* (1...4).size # => 3
|
|
|
|
* (1..).size # => Infinity
|
2014-01-09 21:23:45 +00:00
|
|
|
* ('a'..'z').size #=> nil
|
2012-11-06 17:14:46 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_size(VALUE range)
|
|
|
|
{
|
|
|
|
VALUE b = RANGE_BEG(range), e = RANGE_END(range);
|
2018-06-22 02:58:39 +00: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 17:14:46 +00:00
|
|
|
}
|
2019-04-03 08:11:41 +00:00
|
|
|
else if (NIL_P(b)) {
|
|
|
|
return DBL2NUM(HUGE_VAL);
|
|
|
|
}
|
2018-06-22 02:58:39 +00:00
|
|
|
|
2012-11-06 17:14:46 +00:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
2018-06-22 02:58:37 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 17:51:31 -05:00
|
|
|
* to_a -> array
|
2018-06-22 02:58:37 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* Returns an array containing the elements in +self+, if a finite collection;
|
|
|
|
* raises an exception otherwise.
|
2018-06-22 02:58:37 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05: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-22 02:58:37 +00: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 13:43:22 +00:00
|
|
|
static VALUE
|
|
|
|
range_enum_size(VALUE range, VALUE args, VALUE eobj)
|
|
|
|
{
|
|
|
|
return range_size(range);
|
|
|
|
}
|
|
|
|
|
2020-06-16 14:31:11 +09: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 16:23:59 +09:00
|
|
|
UNREACHABLE;
|
2020-06-16 14:31:11 +09: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 16:23:59 +09:00
|
|
|
UNREACHABLE;
|
2020-06-16 14:31:11 +09:00
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_each_fixnum_loop(VALUE beg, VALUE end, VALUE range)
|
|
|
|
{
|
|
|
|
long lim = FIX2LONG(end) + !EXCL(range);
|
|
|
|
for (long i = FIX2LONG(beg); i < lim; i++) {
|
|
|
|
rb_yield(LONG2FIX(i));
|
|
|
|
}
|
|
|
|
return range;
|
|
|
|
}
|
|
|
|
|
2003-12-24 04:29:32 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 17:51:31 -05:00
|
|
|
* each {|element| ... } -> self
|
|
|
|
* each -> an_enumerator
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* With a block given, passes each element of +self+ to the block:
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* a = []
|
|
|
|
* (1..4).each {|element| a.push(element) } # => 1..4
|
|
|
|
* a # => [1, 2, 3, 4]
|
2010-05-13 05:49:55 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* Raises an exception unless <tt>self.first.respond_to?(:succ)</tt>.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* With no block given, returns an enumerator.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
2002-05-01 09:41:50 +00: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 10:44:21 +00:00
|
|
|
range_each(VALUE range)
|
2002-05-01 09:41:50 +00:00
|
|
|
{
|
2002-05-30 06:12:29 +00:00
|
|
|
VALUE beg, end;
|
2020-06-16 14:31:11 +09:00
|
|
|
long i;
|
2002-05-30 06:12:29 +00:00
|
|
|
|
2013-06-26 13:43:22 +00:00
|
|
|
RETURN_SIZED_ENUMERATOR(range, 0, 0, range_enum_size);
|
2005-08-30 14:49:51 +00:00
|
|
|
|
2007-09-08 15:07:18 +00:00
|
|
|
beg = RANGE_BEG(range);
|
|
|
|
end = RANGE_END(range);
|
2002-05-30 06:12:29 +00:00
|
|
|
|
2018-04-19 15:18:50 +00:00
|
|
|
if (FIXNUM_P(beg) && NIL_P(end)) {
|
2020-06-16 14:31:11 +09:00
|
|
|
range_each_fixnum_endless(beg);
|
2018-04-19 15:18:50 +00:00
|
|
|
}
|
|
|
|
else if (FIXNUM_P(beg) && FIXNUM_P(end)) { /* fixnums are special */
|
2020-06-16 14:31:11 +09:00
|
|
|
return range_each_fixnum_loop(beg, end, range);
|
2003-01-08 06:05:08 +00:00
|
|
|
}
|
2018-04-29 07:12:56 +00: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 14:31:11 +09: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 07:12:56 +00:00
|
|
|
}
|
|
|
|
else {
|
2020-06-16 14:31:11 +09:00
|
|
|
if (NIL_P(end)) range_each_bignum_endless(beg);
|
2018-04-29 07:12:56 +00: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 23:31:32 +00:00
|
|
|
else if (SYMBOL_P(beg) && (NIL_P(end) || SYMBOL_P(end))) { /* symbols are special */
|
2018-04-28 11:16:54 +00:00
|
|
|
beg = rb_sym2str(beg);
|
2018-04-28 23:31:32 +00: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 17:00:47 +00:00
|
|
|
}
|
2002-05-30 06:12:29 +00:00
|
|
|
else {
|
2009-08-17 16:41:00 +00:00
|
|
|
VALUE tmp = rb_check_string_type(beg);
|
|
|
|
|
|
|
|
if (!NIL_P(tmp)) {
|
2018-04-19 15:18:50 +00:00
|
|
|
if (!NIL_P(end)) {
|
2018-04-28 11:16:54 +00:00
|
|
|
rb_str_upto_each(tmp, end, EXCL(range), each_i, 0);
|
2018-04-19 15:18:50 +00:00
|
|
|
}
|
2018-04-28 07:31:32 +00:00
|
|
|
else {
|
2018-04-28 11:16:54 +00:00
|
|
|
rb_str_upto_endless_each(tmp, each_i, 0);
|
2018-04-19 15:18:50 +00:00
|
|
|
}
|
2009-08-17 16:41:00 +00:00
|
|
|
}
|
|
|
|
else {
|
2009-09-30 08:32:43 +00:00
|
|
|
if (!discrete_object_p(beg)) {
|
2009-08-17 16:41:00 +00:00
|
|
|
rb_raise(rb_eTypeError, "can't iterate from %s",
|
|
|
|
rb_obj_classname(beg));
|
|
|
|
}
|
2018-04-19 15:18:50 +00:00
|
|
|
if (!NIL_P(end))
|
|
|
|
range_each_func(range, each_i, 0);
|
|
|
|
else
|
2018-04-29 07:12:56 +00:00
|
|
|
for (;; beg = rb_funcallv(beg, id_succ, 0, 0))
|
|
|
|
rb_yield(beg);
|
2009-02-23 15:46:02 +00:00
|
|
|
}
|
2002-05-30 06:12:29 +00:00
|
|
|
}
|
|
|
|
return range;
|
2002-05-01 09:41:50 +00:00
|
|
|
}
|
|
|
|
|
2003-12-24 04:29:32 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 17:51:31 -05:00
|
|
|
* self.begin -> object
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* Returns the object that defines the beginning of +self+.
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* (1..4).begin # => 1
|
|
|
|
* (..2).begin # => nil
|
|
|
|
*
|
|
|
|
* Related: Range#first, Range#end.
|
2003-12-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
1998-01-16 12:13:05 +00:00
|
|
|
static VALUE
|
2007-10-18 06:58:35 +00:00
|
|
|
range_begin(VALUE range)
|
1998-01-16 12:13:05 +00:00
|
|
|
{
|
2007-09-08 15:07:18 +00:00
|
|
|
return RANGE_BEG(range);
|
1998-01-16 12:13:05 +00:00
|
|
|
}
|
|
|
|
|
2003-12-24 04:29:32 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 17:51:31 -05:00
|
|
|
* self.end -> object
|
|
|
|
*
|
|
|
|
* Returns the object that defines the end of +self+.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* (1..4).end # => 4
|
|
|
|
* (1...4).end # => 4
|
|
|
|
* (1..).end # => nil
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* Related: Range#begin, Range#last.
|
2003-12-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
1998-01-16 12:13:05 +00:00
|
|
|
static VALUE
|
2007-10-18 06:58:35 +00:00
|
|
|
range_end(VALUE range)
|
1998-01-16 12:13:05 +00:00
|
|
|
{
|
2007-09-08 15:07:18 +00:00
|
|
|
return RANGE_END(range);
|
1998-01-16 12:13:05 +00:00
|
|
|
}
|
|
|
|
|
2007-10-18 06:58:35 +00:00
|
|
|
|
|
|
|
static VALUE
|
2013-11-29 07:59:14 +00:00
|
|
|
first_i(RB_BLOCK_CALL_FUNC_ARGLIST(i, cbarg))
|
2007-10-18 06:58:35 +00:00
|
|
|
{
|
2013-11-29 07:45:00 +00:00
|
|
|
VALUE *ary = (VALUE *)cbarg;
|
2007-10-18 06:58:35 +00:00
|
|
|
long n = NUM2LONG(ary[0]);
|
|
|
|
|
|
|
|
if (n <= 0) {
|
|
|
|
rb_iter_break();
|
|
|
|
}
|
|
|
|
rb_ary_push(ary[1], i);
|
|
|
|
n--;
|
2020-04-08 13:28:13 +09:00
|
|
|
ary[0] = LONG2NUM(n);
|
2007-10-18 06:58:35 +00:00
|
|
|
return Qnil;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 17:51:31 -05: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 14:23:33 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* Raises an exception if there is no first element:
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* (..4).first # Raises RangeError
|
2007-10-18 06:58:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_first(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
|
|
|
VALUE n, ary[2];
|
|
|
|
|
2019-04-30 23:18:44 +09:00
|
|
|
if (NIL_P(RANGE_BEG(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the first element of beginless range");
|
|
|
|
}
|
2007-10-18 06:58:35 +00: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 09:57:47 +00:00
|
|
|
rb_block_call(range, idEach, 0, 0, first_i, (VALUE)ary);
|
2007-10-18 06:58:35 +00:00
|
|
|
|
|
|
|
return ary[1];
|
|
|
|
}
|
|
|
|
|
2019-01-06 00:46:36 +00: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 06:58:35 +00:00
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-14 17:51:31 -05: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 14:23:33 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* Raises an exception if there is no last element:
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2021-09-14 17:51:31 -05:00
|
|
|
* (1..).last # Raises RangeError
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2007-10-18 06:58:35 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_last(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
2019-01-06 00:46:36 +00:00
|
|
|
VALUE b, e;
|
|
|
|
|
2018-06-22 02:58:40 +00:00
|
|
|
if (NIL_P(RANGE_END(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the last element of endless range");
|
|
|
|
}
|
2013-08-08 01:27:19 +00:00
|
|
|
if (argc == 0) return RANGE_END(range);
|
2019-01-06 00:46:36 +00:00
|
|
|
|
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2019-01-08 04:37:40 +00:00
|
|
|
if (RB_INTEGER_TYPE_P(b) && RB_INTEGER_TYPE_P(e) &&
|
|
|
|
RB_LIKELY(rb_method_basic_definition_p(rb_cRange, idEach))) {
|
2019-01-06 00:46:36 +00:00
|
|
|
return rb_int_range_last(argc, argv, range);
|
|
|
|
}
|
2009-02-22 14:23:33 +00:00
|
|
|
return rb_ary_last(argc, argv, rb_Array(range));
|
2007-10-18 06:58:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2005-11-25 01:30:57 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2021-09-15 13:37:34 -05:00
|
|
|
* min -> object
|
|
|
|
* min(n) -> array
|
|
|
|
* min {|a, b| ... } -> object
|
|
|
|
* min(n) {|a, b| ... } -> array
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-15 13:37:34 -05:00
|
|
|
* Returns the minimum value in +self+,
|
|
|
|
* using method <tt><=></tt> or a given block for comparison.
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2021-09-15 13:37:34 -05:00
|
|
|
* With no argument and no block given,
|
|
|
|
* returns the minimum-valued element of +self+.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2021-09-15 13:37:34 -05: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]
|
|
|
|
* (1..4).min(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 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-25 01:30:57 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
static VALUE
|
2014-02-14 15:45:11 +00:00
|
|
|
range_min(int argc, VALUE *argv, VALUE range)
|
2005-11-25 01:30:57 +00:00
|
|
|
{
|
2019-12-25 13:35:22 +09:00
|
|
|
if (NIL_P(RANGE_BEG(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the minimum of beginless range");
|
|
|
|
}
|
|
|
|
|
2005-11-25 01:30:57 +00:00
|
|
|
if (rb_block_given_p()) {
|
2018-06-22 02:58:40 +00: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 15:45:11 +00:00
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
else if (argc != 0) {
|
|
|
|
return range_first(argc, argv, range);
|
2005-11-25 01:30:57 +00:00
|
|
|
}
|
|
|
|
else {
|
2017-05-30 02:57:33 +00:00
|
|
|
struct cmp_opt_data cmp_opt = { 0, 0 };
|
2007-09-08 15:07:18 +00:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
VALUE e = RANGE_END(range);
|
2018-04-19 15:18:53 +00:00
|
|
|
int c = NIL_P(e) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
|
2005-11-25 01:30:57 +00:00
|
|
|
|
2007-07-13 02:33:11 +00:00
|
|
|
if (c > 0 || (c == 0 && EXCL(range)))
|
2006-12-31 15:02:22 +00:00
|
|
|
return Qnil;
|
2005-11-25 01:30:57 +00:00
|
|
|
return b;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2014-02-14 15:45:11 +00:00
|
|
|
* rng.max -> obj
|
|
|
|
* rng.max {| a,b | block } -> obj
|
|
|
|
* rng.max(n) -> obj
|
|
|
|
* rng.max(n) {| a,b | block } -> obj
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2020-09-01 09:58:45 -07:00
|
|
|
* Returns the maximum value in the range, or an array of maximum
|
|
|
|
* values in the range if given an \Integer argument.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2020-09-01 09:58:45 -07:00
|
|
|
* For inclusive ranges with an end, the maximum value of the range
|
|
|
|
* is the same as the end of the range.
|
|
|
|
*
|
|
|
|
* If an argument or block is given, or +self+ is an exclusive,
|
|
|
|
* non-numeric range, calls Enumerable#max (via +super+) with the
|
|
|
|
* argument and/or block to get the maximum values, unless +self+ is
|
|
|
|
* a beginless range, in which case it raises a RangeError.
|
|
|
|
*
|
|
|
|
* If +self+ is an exclusive, integer range (both start and end of the
|
|
|
|
* range are integers), and no arguments or block are provided, returns
|
|
|
|
* last value in the range (1 before the end). Otherwise, if +self+ is
|
|
|
|
* an exclusive, numeric range, raises a TypeError.
|
2020-09-02 12:44:28 +09:00
|
|
|
*
|
2020-09-01 09:58:45 -07:00
|
|
|
* Returns +nil+ if the begin value of the range larger than the
|
|
|
|
* end value. Returns +nil+ if the begin value of an exclusive
|
|
|
|
* range is equal to the end value. Raises a RangeError if called on
|
|
|
|
* an endless range.
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2020-09-01 09:58:45 -07:00
|
|
|
* Examples:
|
|
|
|
* (10..20).max #=> 20
|
|
|
|
* (10..20).max(2) #=> [20, 19]
|
|
|
|
* (10...20).max #=> 19
|
|
|
|
* (10...20).max(2) #=> [19, 18]
|
|
|
|
* (10...20).max{|x, y| -x <=> -y } #=> 10
|
|
|
|
* (10...20).max(2){|x, y| -x <=> -y } #=> [10, 11]
|
2005-11-25 01:30:57 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
2014-02-14 15:45:11 +00:00
|
|
|
range_max(int argc, VALUE *argv, VALUE range)
|
2005-11-25 01:30:57 +00:00
|
|
|
{
|
2007-09-08 15:07:18 +00:00
|
|
|
VALUE e = RANGE_END(range);
|
2009-01-04 22:32:40 +00:00
|
|
|
int nm = FIXNUM_P(e) || rb_obj_is_kind_of(e, rb_cNumeric);
|
2005-11-25 05:42:28 +00:00
|
|
|
|
2018-06-22 02:58:40 +00:00
|
|
|
if (NIL_P(RANGE_END(range))) {
|
|
|
|
rb_raise(rb_eRangeError, "cannot get the maximum of endless range");
|
|
|
|
}
|
2018-04-19 15:18:53 +00:00
|
|
|
|
2020-07-18 23:18:40 +07:00
|
|
|
VALUE b = RANGE_BEG(range);
|
|
|
|
|
2014-02-14 15:45:11 +00:00
|
|
|
if (rb_block_given_p() || (EXCL(range) && !nm) || argc) {
|
2020-07-18 23:18:40 +07:00
|
|
|
if (NIL_P(b)) {
|
2019-12-25 13:35:22 +09:00
|
|
|
rb_raise(rb_eRangeError, "cannot get the maximum of beginless range with custom comparison method");
|
|
|
|
}
|
2018-02-26 07:57:15 +00:00
|
|
|
return rb_call_super(argc, argv);
|
2005-11-25 01:30:57 +00:00
|
|
|
}
|
|
|
|
else {
|
2018-02-26 07:57:15 +00:00
|
|
|
struct cmp_opt_data cmp_opt = { 0, 0 };
|
2020-07-18 23:18:40 +07:00
|
|
|
int c = NIL_P(b) ? -1 : OPTIMIZED_CMP(b, e, cmp_opt);
|
2018-02-26 07:57:15 +00:00
|
|
|
|
|
|
|
if (c > 0)
|
|
|
|
return Qnil;
|
|
|
|
if (EXCL(range)) {
|
|
|
|
if (!RB_INTEGER_TYPE_P(e)) {
|
|
|
|
rb_raise(rb_eTypeError, "cannot exclude non Integer end value");
|
|
|
|
}
|
|
|
|
if (c == 0) return Qnil;
|
|
|
|
if (!RB_INTEGER_TYPE_P(b)) {
|
|
|
|
rb_raise(rb_eTypeError, "cannot exclude end value with non Integer begin value");
|
|
|
|
}
|
|
|
|
if (FIXNUM_P(e)) {
|
|
|
|
return LONG2NUM(FIX2LONG(e) - 1);
|
|
|
|
}
|
|
|
|
return rb_funcall(e, '-', 1, INT2FIX(1));
|
|
|
|
}
|
|
|
|
return e;
|
2005-11-25 01:30:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-07 22:03:02 -07:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* rng.minmax -> [obj, obj]
|
|
|
|
* rng.minmax {| a,b | block } -> [obj, obj]
|
|
|
|
*
|
|
|
|
* Returns a two element array which contains the minimum and the
|
|
|
|
* maximum value in the range.
|
|
|
|
*
|
|
|
|
* Can be given an optional block to override the default comparison
|
|
|
|
* method <code>a <=> b</code>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_minmax(VALUE range)
|
|
|
|
{
|
|
|
|
if (rb_block_given_p()) {
|
|
|
|
return rb_call_super(0, NULL);
|
|
|
|
}
|
Fix non-numeric exclusive Range#minmax bug
The implementation of Range#minmax added in d5c60214c45 causes the
following incorrect behaviour:
('a'...'c').minmax => ["a", ["a", "b"]]
instead of
('a'...'c').minmax => ["a", "b"]
This is because the C implementation of Range#minmax (range_minmax)
directly delegates to the C implementation of Range#min (range_min) and
Range#max (range_max), without changing the execution context.
Range#max's C implementation (range_max), when given a non-numeric
exclusive range, delegates to super, which is meant to call
Enumerable#max. However, because range_max is called directly by
range_minmax, super calls Enumerable#minmax instead, causing the
incorrect nesting.
Perhaps it is possible to change the execution context in an optimized
manner, but the simplest solution seems to be to just explicitly
delegate from Range#minmax to Range#min and Range#max.
2020-07-03 22:56:07 -04:00
|
|
|
return rb_assoc_new(
|
2020-07-04 10:12:02 -07: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-07 22:03:02 -07:00
|
|
|
}
|
|
|
|
|
2009-07-16 06:52:29 +00:00
|
|
|
int
|
|
|
|
rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp)
|
1998-01-16 12:13:05 +00:00
|
|
|
{
|
2005-08-04 04:31:33 +00:00
|
|
|
VALUE b, e;
|
2009-07-16 06:52:29 +00:00
|
|
|
int excl;
|
1998-01-16 12:13:05 +00:00
|
|
|
|
2005-08-04 04:31:33 +00:00
|
|
|
if (rb_obj_is_kind_of(range, rb_cRange)) {
|
2007-09-08 15:07:18 +00:00
|
|
|
b = RANGE_BEG(range);
|
|
|
|
e = RANGE_END(range);
|
2005-08-04 11:29:51 +00:00
|
|
|
excl = EXCL(range);
|
2005-08-04 04:31:33 +00:00
|
|
|
}
|
2018-12-21 13:05:16 +00:00
|
|
|
else if (RTEST(rb_obj_is_kind_of(range, rb_cArithSeq))) {
|
|
|
|
return (int)Qfalse;
|
|
|
|
}
|
2005-08-04 04:31:33 +00:00
|
|
|
else {
|
2017-10-25 01:40:15 +00: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 04:31:33 +00:00
|
|
|
}
|
2009-07-16 06:52:29 +00:00
|
|
|
*begp = b;
|
|
|
|
*endp = e;
|
|
|
|
*exclp = excl;
|
2009-09-23 03:39:44 +00:00
|
|
|
return (int)Qtrue;
|
2009-07-16 06:52:29 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 02:40:18 +09: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 06:52:29 +00:00
|
|
|
VALUE
|
2020-10-21 02:40:18 +09:00
|
|
|
rb_range_component_beg_len(VALUE b, VALUE e, int excl,
|
|
|
|
long *begp, long *lenp, long len, int err)
|
2009-07-16 06:52:29 +00:00
|
|
|
{
|
2020-10-20 16:00:35 +09:00
|
|
|
long beg, end;
|
2009-07-16 06:52:29 +00:00
|
|
|
|
2019-04-03 08:11:41 +00:00
|
|
|
beg = NIL_P(b) ? 0 : NUM2LONG(b);
|
2018-04-19 15:18:50 +00:00
|
|
|
end = NIL_P(e) ? -1 : NUM2LONG(e);
|
|
|
|
if (NIL_P(e)) excl = 0;
|
1999-08-13 05:45:20 +00:00
|
|
|
if (beg < 0) {
|
2020-10-21 02:40:18 +09:00
|
|
|
beg += len;
|
|
|
|
if (beg < 0)
|
|
|
|
goto out_of_range;
|
1999-08-13 05:45:20 +00:00
|
|
|
}
|
2012-11-21 04:23:56 +00:00
|
|
|
if (end < 0)
|
2020-10-21 02:40:18 +09:00
|
|
|
end += len;
|
2012-11-21 04:23:56 +00:00
|
|
|
if (!excl)
|
2020-10-21 02:40:18 +09:00
|
|
|
end++; /* include end point */
|
1999-08-13 05:45:20 +00:00
|
|
|
if (err == 0 || err == 2) {
|
2020-10-21 02:40:18 +09:00
|
|
|
if (beg > len)
|
|
|
|
goto out_of_range;
|
|
|
|
if (end > len)
|
|
|
|
end = len;
|
1999-08-13 05:45:20 +00:00
|
|
|
}
|
|
|
|
len = end - beg;
|
2006-12-31 15:02:22 +00:00
|
|
|
if (len < 0)
|
2020-10-21 02:40:18 +09:00
|
|
|
len = 0;
|
1999-08-13 05:45:20 +00:00
|
|
|
|
|
|
|
*begp = beg;
|
|
|
|
*lenp = len;
|
1999-01-20 04:59:39 +00:00
|
|
|
return Qtrue;
|
1999-08-13 05:45:20 +00:00
|
|
|
|
|
|
|
out_of_range:
|
|
|
|
return Qnil;
|
1998-01-16 12:13:05 +00:00
|
|
|
}
|
|
|
|
|
2020-10-21 02:40:18 +09: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 16:38:32 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-17 21:07:33 +00:00
|
|
|
* rng.to_s -> string
|
2003-12-30 16:38:32 +00:00
|
|
|
*
|
2011-12-05 23:36:53 +00:00
|
|
|
* Convert this range object to a printable form (using #to_s to convert the
|
|
|
|
* begin and end objects).
|
2003-12-30 16:38:32 +00:00
|
|
|
*/
|
|
|
|
|
1998-01-16 12:13:05 +00: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 10:44:21 +00:00
|
|
|
range_to_s(VALUE range)
|
1998-01-16 12:13:05 +00:00
|
|
|
{
|
|
|
|
VALUE str, str2;
|
|
|
|
|
2007-09-08 15:07:18 +00:00
|
|
|
str = rb_obj_as_string(RANGE_BEG(range));
|
|
|
|
str2 = rb_obj_as_string(RANGE_END(range));
|
2000-04-10 05:48:43 +00:00
|
|
|
str = rb_str_dup(str);
|
2006-12-31 15:02:22 +00:00
|
|
|
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
|
2000-04-10 05:48:43 +00:00
|
|
|
rb_str_append(str, str2);
|
1998-01-16 12:13:05 +00:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2008-09-25 15:42:23 +00:00
|
|
|
static VALUE
|
|
|
|
inspect_range(VALUE range, VALUE dummy, int recur)
|
|
|
|
{
|
2018-04-19 15:18:50 +00:00
|
|
|
VALUE str, str2 = Qundef;
|
2008-09-25 15:42:23 +00:00
|
|
|
|
|
|
|
if (recur) {
|
|
|
|
return rb_str_new2(EXCL(range) ? "(... ... ...)" : "(... .. ...)");
|
|
|
|
}
|
2019-05-23 00:45:30 +09: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 15:42:23 +00:00
|
|
|
rb_str_cat(str, "...", EXCL(range) ? 3 : 2);
|
2019-05-23 00:45:30 +09:00
|
|
|
if (NIL_P(RANGE_BEG(range)) || !NIL_P(RANGE_END(range))) {
|
|
|
|
str2 = rb_inspect(RANGE_END(range));
|
|
|
|
}
|
2018-04-19 15:18:50 +00:00
|
|
|
if (str2 != Qundef) rb_str_append(str, str2);
|
2008-09-25 15:42:23 +00:00
|
|
|
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2003-12-30 16:38:32 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-17 21:07:33 +00:00
|
|
|
* rng.inspect -> string
|
2003-12-30 16:38:32 +00:00
|
|
|
*
|
2019-03-28 03:33:35 +00:00
|
|
|
* Convert this range object to a printable form (using #inspect to
|
|
|
|
* convert the begin and end objects).
|
2003-12-30 16:38:32 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
1998-01-16 12:13:05 +00: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 10:44:21 +00:00
|
|
|
range_inspect(VALUE range)
|
1998-01-16 12:13:05 +00:00
|
|
|
{
|
2008-09-25 15:42:23 +00:00
|
|
|
return rb_exec_recursive(inspect_range, range, 0);
|
1998-01-16 12:13:05 +00:00
|
|
|
}
|
|
|
|
|
2019-07-29 16:22:00 -07:00
|
|
|
static VALUE range_include_internal(VALUE range, VALUE val, int string_use_cover);
|
2018-05-17 10:46:21 +00:00
|
|
|
|
2003-12-24 04:29:32 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2010-05-17 21:07:33 +00:00
|
|
|
* rng === obj -> true or false
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2019-12-21 22:58:14 +02:00
|
|
|
* Returns <code>true</code> if +obj+ is between begin and end of range,
|
|
|
|
* <code>false</code> otherwise (same as #cover?). Conveniently,
|
|
|
|
* <code>===</code> is the comparison operator used by <code>case</code>
|
|
|
|
* statements.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
* case 79
|
2019-12-21 22:58:14 +02:00
|
|
|
* when 1..50 then puts "low"
|
|
|
|
* when 51..75 then puts "medium"
|
|
|
|
* when 76..100 then puts "high"
|
2003-12-24 04:29:32 +00:00
|
|
|
* end
|
2019-12-21 22:58:14 +02:00
|
|
|
* # Prints "high"
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2019-12-21 22:58:14 +02:00
|
|
|
* case "2.6.5"
|
|
|
|
* when ..."2.4" then puts "EOL"
|
|
|
|
* when "2.4"..."2.5" then puts "maintenance"
|
|
|
|
* when "2.5"..."2.7" then puts "stable"
|
|
|
|
* when "2.7".. then puts "upcoming"
|
|
|
|
* end
|
|
|
|
* # Prints "stable"
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
2007-07-26 13:37:13 +00:00
|
|
|
static VALUE
|
|
|
|
range_eqq(VALUE range, VALUE val)
|
|
|
|
{
|
2019-07-29 16:22:00 -07:00
|
|
|
VALUE ret = range_include_internal(range, val, 1);
|
2018-05-17 10:46:21 +00:00
|
|
|
if (ret != Qundef) return ret;
|
|
|
|
return r_cover_p(range, RANGE_BEG(range), RANGE_END(range), val);
|
2007-07-26 13:37:13 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
* call-seq:
|
2011-12-05 23:36:53 +00:00
|
|
|
* rng.member?(obj) -> true or false
|
|
|
|
* rng.include?(obj) -> true or false
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2011-12-05 23:36:53 +00:00
|
|
|
* Returns <code>true</code> if +obj+ is an element of
|
2019-12-21 22:58:14 +02:00
|
|
|
* the range, <code>false</code> otherwise.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2011-12-05 23:36:53 +00:00
|
|
|
* ("a".."z").include?("g") #=> true
|
|
|
|
* ("a".."z").include?("A") #=> false
|
|
|
|
* ("a".."z").include?("cc") #=> false
|
2019-12-21 22:58:14 +02:00
|
|
|
*
|
|
|
|
* If you need to ensure +obj+ is between +begin+ and +end+, use #cover?
|
|
|
|
*
|
|
|
|
* ("a".."z").cover?("cc") #=> true
|
|
|
|
*
|
|
|
|
* If begin and end are numeric, #include? behaves like #cover?
|
|
|
|
*
|
|
|
|
* (1..3).include?(1.5) # => true
|
2007-07-26 13:37:13 +00:00
|
|
|
*/
|
|
|
|
|
2002-06-11 07:02:23 +00: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 10:44:21 +00:00
|
|
|
range_include(VALUE range, VALUE val)
|
2018-05-17 10:46:21 +00:00
|
|
|
{
|
2019-07-29 16:22:00 -07:00
|
|
|
VALUE ret = range_include_internal(range, val, 0);
|
2018-05-17 10:46:21 +00:00
|
|
|
if (ret != Qundef) return ret;
|
|
|
|
return rb_call_super(1, &val);
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
2019-07-29 16:22:00 -07:00
|
|
|
range_include_internal(VALUE range, VALUE val, int string_use_cover)
|
2002-06-11 07:02:23 +00:00
|
|
|
{
|
2007-09-08 15:07:18 +00:00
|
|
|
VALUE beg = RANGE_BEG(range);
|
|
|
|
VALUE end = RANGE_END(range);
|
2005-12-07 08:41:59 +00:00
|
|
|
int nv = FIXNUM_P(beg) || FIXNUM_P(end) ||
|
2015-05-03 01:02:15 +00:00
|
|
|
linear_object_p(beg) || linear_object_p(end);
|
2005-12-07 08:41:59 +00:00
|
|
|
|
2005-12-09 14:17:09 +00:00
|
|
|
if (nv ||
|
|
|
|
!NIL_P(rb_check_to_integer(beg, "to_int")) ||
|
|
|
|
!NIL_P(rb_check_to_integer(end, "to_int"))) {
|
2015-05-15 09:05:57 +00:00
|
|
|
return r_cover_p(range, beg, end, val);
|
2002-06-11 07:02:23 +00:00
|
|
|
}
|
2019-07-29 16:22:00 -07: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 08:11:41 +00: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 15:18:53 +00: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 17:46:52 +00:00
|
|
|
}
|
2018-05-17 10:46:21 +00:00
|
|
|
return Qundef;
|
2002-06-11 07:02:23 +00:00
|
|
|
}
|
|
|
|
|
2018-09-05 19:06:08 +00:00
|
|
|
static int r_cover_range_p(VALUE range, VALUE beg, VALUE end, VALUE val);
|
2003-12-24 04:29:32 +00:00
|
|
|
|
2005-12-12 01:01:29 +00:00
|
|
|
/*
|
|
|
|
* call-seq:
|
2018-09-05 19:06:08 +00:00
|
|
|
* rng.cover?(obj) -> true or false
|
|
|
|
* rng.cover?(range) -> true or false
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
|
|
|
* Returns <code>true</code> if +obj+ is between the begin and end of
|
|
|
|
* the range.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2011-12-05 23:36:53 +00:00
|
|
|
* This tests <code>begin <= obj <= end</code> when #exclude_end? is +false+
|
|
|
|
* and <code>begin <= obj < end</code> when #exclude_end? is +true+.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2018-10-12 21:11:54 +00:00
|
|
|
* If called with a Range argument, returns <code>true</code> when the
|
|
|
|
* given range is covered by the receiver,
|
2018-09-05 19:06:08 +00:00
|
|
|
* by comparing the begin and end values. If the argument can be treated as
|
|
|
|
* a sequence, this method treats it that way. In the specific case of
|
|
|
|
* <code>(a..b).cover?(c...d)</code> with <code>a <= c && b < d</code>,
|
2018-10-12 21:11:54 +00:00
|
|
|
* the end of the sequence must be calculated, which may exhibit poor
|
|
|
|
* performance if <code>c</code> is non-numeric.
|
|
|
|
* Returns <code>false</code> if the begin value of the
|
2019-07-24 10:30:56 -07:00
|
|
|
* range is larger than the end value. Also returns +false+ if one of the
|
|
|
|
* internal calls to <code><=></code> returns +nil+ (indicating the objects
|
|
|
|
* are not comparable).
|
2018-09-05 19:06:08 +00:00
|
|
|
*
|
|
|
|
* ("a".."z").cover?("c") #=> true
|
|
|
|
* ("a".."z").cover?("5") #=> false
|
|
|
|
* ("a".."z").cover?("cc") #=> true
|
2019-07-24 10:30:56 -07:00
|
|
|
* ("a".."z").cover?(1) #=> false
|
2018-09-05 19:06:08 +00:00
|
|
|
* (1..5).cover?(2..3) #=> true
|
|
|
|
* (1..5).cover?(0..6) #=> false
|
|
|
|
* (1..5).cover?(1...6) #=> true
|
2005-12-12 01:01:29 +00: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 21:20:17 +00:00
|
|
|
range_cover(VALUE range, VALUE val)
|
2005-12-12 01:01:29 +00:00
|
|
|
{
|
|
|
|
VALUE beg, end;
|
|
|
|
|
2007-09-08 15:07:18 +00:00
|
|
|
beg = RANGE_BEG(range);
|
|
|
|
end = RANGE_END(range);
|
2018-09-05 19:06:08 +00:00
|
|
|
|
|
|
|
if (rb_obj_is_kind_of(val, rb_cRange)) {
|
|
|
|
return RBOOL(r_cover_range_p(range, beg, end, val));
|
|
|
|
}
|
2015-05-15 09:05:57 +00:00
|
|
|
return r_cover_p(range, beg, end, val);
|
|
|
|
}
|
|
|
|
|
2018-09-05 19:06:08 +00: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 08:35:57 +00:00
|
|
|
if (!NIL_P(beg) && NIL_P(val_beg)) return FALSE;
|
2020-04-08 13:28:13 +09: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 08:35:57 +00:00
|
|
|
if (!NIL_P(val_beg) && !r_cover_p(range, beg, end, val_beg)) return FALSE;
|
2018-09-05 19:06:08 +00:00
|
|
|
|
|
|
|
cmp_end = r_less(end, val_end);
|
|
|
|
|
|
|
|
if (EXCL(range) == EXCL(val)) {
|
|
|
|
return cmp_end >= 0;
|
2019-01-09 13:58:49 +00:00
|
|
|
}
|
|
|
|
else if (EXCL(range)) {
|
2018-09-05 19:06:08 +00:00
|
|
|
return cmp_end > 0;
|
2019-01-09 13:58:49 +00:00
|
|
|
}
|
|
|
|
else if (cmp_end >= 0) {
|
2018-09-05 19:06:08 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
2020-09-01 09:19:03 -07:00
|
|
|
|
|
|
|
val_max = rb_rescue2(r_call_max, val, 0, Qnil, rb_eTypeError, (VALUE)0);
|
|
|
|
if (val_max == Qnil) return FALSE;
|
2018-09-05 19:06:08 +00:00
|
|
|
|
|
|
|
return r_less(end, val_max) >= 0;
|
|
|
|
}
|
|
|
|
|
2015-05-15 09:05:57 +00:00
|
|
|
static VALUE
|
|
|
|
r_cover_p(VALUE range, VALUE beg, VALUE end, VALUE val)
|
|
|
|
{
|
2019-04-03 08:11:41 +00:00
|
|
|
if (NIL_P(beg) || r_less(beg, val) <= 0) {
|
2015-05-15 09:06:18 +00:00
|
|
|
int excl = EXCL(range);
|
2018-04-19 15:18:53 +00:00
|
|
|
if (NIL_P(end) || r_less(val, end) <= -excl)
|
2015-05-15 09:06:18 +00:00
|
|
|
return Qtrue;
|
2005-12-12 01:01:29 +00:00
|
|
|
}
|
|
|
|
return Qfalse;
|
|
|
|
}
|
|
|
|
|
2007-09-08 15:07:18 +00:00
|
|
|
static VALUE
|
|
|
|
range_dumper(VALUE range)
|
|
|
|
{
|
2020-10-28 16:58:17 -07:00
|
|
|
VALUE v = rb_obj_alloc(rb_cObject);
|
2007-09-08 15:07:18 +00:00
|
|
|
|
2007-09-10 06:50:22 +00:00
|
|
|
rb_ivar_set(v, id_excl, RANGE_EXCL(range));
|
2007-09-08 15:07:18 +00:00
|
|
|
rb_ivar_set(v, id_beg, RANGE_BEG(range));
|
2018-06-13 11:00:28 +00:00
|
|
|
rb_ivar_set(v, id_end, RANGE_END(range));
|
2007-09-08 15:07:18 +00:00
|
|
|
return v;
|
|
|
|
}
|
|
|
|
|
|
|
|
static VALUE
|
|
|
|
range_loader(VALUE range, VALUE obj)
|
|
|
|
{
|
2016-11-11 11:52:03 +00:00
|
|
|
VALUE beg, end, excl;
|
|
|
|
|
2011-09-29 11:07:45 +00:00
|
|
|
if (!RB_TYPE_P(obj, T_OBJECT) || RBASIC(obj)->klass != rb_cObject) {
|
2007-09-08 15:07:18 +00:00
|
|
|
rb_raise(rb_eTypeError, "not a dumped range object");
|
|
|
|
}
|
|
|
|
|
2013-10-26 10:08:02 +00:00
|
|
|
range_modify(range);
|
2016-11-11 11:52:03 +00:00
|
|
|
beg = rb_ivar_get(obj, id_beg);
|
2018-06-13 11:00:28 +00:00
|
|
|
end = rb_ivar_get(obj, id_end);
|
2016-11-11 11:52:03 +00:00
|
|
|
excl = rb_ivar_get(obj, id_excl);
|
|
|
|
if (!NIL_P(excl)) {
|
|
|
|
range_init(range, beg, end, RBOOL(RTEST(excl)));
|
|
|
|
}
|
2007-09-08 15:07:18 +00:00
|
|
|
return range;
|
|
|
|
}
|
2005-12-12 01:01:29 +00:00
|
|
|
|
2007-11-23 07:00:50 +00:00
|
|
|
static VALUE
|
|
|
|
range_alloc(VALUE klass)
|
|
|
|
{
|
2016-11-10 00:49:16 +00:00
|
|
|
/* rb_struct_alloc_noinit itself should not be used because
|
|
|
|
* rb_marshal_define_compat uses equality of allocation function */
|
2007-11-23 07:00:50 +00:00
|
|
|
return rb_struct_alloc_noinit(klass);
|
|
|
|
}
|
|
|
|
|
2019-12-04 15:31:51 +09:00
|
|
|
/*
|
|
|
|
* call-seq:
|
|
|
|
* range.count -> int
|
|
|
|
* range.count(item) -> int
|
|
|
|
* range.count { |obj| block } -> int
|
|
|
|
*
|
|
|
|
* Identical to Enumerable#count, except it returns Infinity for endless
|
|
|
|
* ranges.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
static VALUE
|
|
|
|
range_count(int argc, VALUE *argv, VALUE range)
|
|
|
|
{
|
|
|
|
if (argc != 0) {
|
2019-12-20 09:19:39 +09:00
|
|
|
/* It is odd for instance (1...).count(0) to return Infinity. Just let
|
2019-12-04 15:31:51 +09:00
|
|
|
* it loop. */
|
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
else if (rb_block_given_p()) {
|
2019-12-20 09:19:39 +09:00
|
|
|
/* Likewise it is odd for instance (1...).count {|x| x == 0 } to return
|
2019-12-04 15:31:51 +09:00
|
|
|
* Infinity. Just let it loop. */
|
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
else if (NIL_P(RANGE_END(range))) {
|
|
|
|
/* We are confident that the answer is Infinity. */
|
|
|
|
return DBL2NUM(HUGE_VAL);
|
|
|
|
}
|
|
|
|
else if (NIL_P(RANGE_BEG(range))) {
|
|
|
|
/* We are confident that the answer is Infinity. */
|
|
|
|
return DBL2NUM(HUGE_VAL);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return rb_call_super(argc, argv);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-28 03:33:35 +00:00
|
|
|
/* A Range represents an interval---a set of values with a
|
2011-12-05 23:36:53 +00:00
|
|
|
* beginning and an end. Ranges may be constructed using the
|
2003-12-24 04:29:32 +00:00
|
|
|
* <em>s</em><code>..</code><em>e</em> and
|
|
|
|
* <em>s</em><code>...</code><em>e</em> literals, or with
|
2011-12-05 23:36:53 +00:00
|
|
|
* Range::new. Ranges constructed using <code>..</code>
|
|
|
|
* run from the beginning to the end inclusively. Those created using
|
2003-12-24 04:29:32 +00:00
|
|
|
* <code>...</code> exclude the end value. When used as an iterator,
|
|
|
|
* ranges return each value in the sequence.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
* (-1..-5).to_a #=> []
|
|
|
|
* (-5..-1).to_a #=> [-5, -4, -3, -2, -1]
|
|
|
|
* ('a'..'e').to_a #=> ["a", "b", "c", "d", "e"]
|
|
|
|
* ('a'...'e').to_a #=> ["a", "b", "c", "d"]
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2019-04-03 08:11:41 +00:00
|
|
|
* == Beginless/Endless Ranges
|
|
|
|
*
|
|
|
|
* A "beginless range" and "endless range" represents a semi-infinite
|
|
|
|
* range. Literal notation for a beginless range is:
|
|
|
|
*
|
|
|
|
* (..1)
|
|
|
|
* # or
|
|
|
|
* (...1)
|
2018-12-12 19:49:22 +00:00
|
|
|
*
|
|
|
|
* Literal notation for an endless range is:
|
|
|
|
*
|
|
|
|
* (1..)
|
|
|
|
* # or similarly
|
|
|
|
* (1...)
|
|
|
|
*
|
|
|
|
* Which is equivalent to
|
|
|
|
*
|
|
|
|
* (1..nil) # or similarly (1...nil)
|
|
|
|
* Range.new(1, nil) # or Range.new(1, nil, true)
|
|
|
|
*
|
2019-04-03 08:11:41 +00:00
|
|
|
* Beginless/endless ranges are useful, for example, for idiomatic
|
|
|
|
* slicing of arrays:
|
2018-12-12 19:49:22 +00:00
|
|
|
*
|
2019-04-03 08:11:41 +00:00
|
|
|
* [1, 2, 3, 4, 5][...2] # => [1, 2]
|
2018-12-12 19:49:22 +00:00
|
|
|
* [1, 2, 3, 4, 5][2...] # => [3, 4, 5]
|
|
|
|
*
|
|
|
|
* Some implementation details:
|
|
|
|
*
|
2019-04-03 08:11:41 +00:00
|
|
|
* * +begin+ of beginless range and +end+ of endless range are +nil+;
|
|
|
|
* * +each+ of beginless range raises an exception;
|
2018-12-12 19:49:22 +00:00
|
|
|
* * +each+ of endless range enumerates infinite sequence (may be
|
|
|
|
* useful in combination with Enumerable#take_while or similar
|
|
|
|
* methods);
|
|
|
|
* * <code>(1..)</code> and <code>(1...)</code> are not equal,
|
|
|
|
* although technically representing the same sequence.
|
|
|
|
*
|
2011-12-05 23:36:53 +00:00
|
|
|
* == Custom Objects in Ranges
|
|
|
|
*
|
|
|
|
* Ranges can be constructed using any objects that can be compared
|
|
|
|
* using the <code><=></code> operator.
|
|
|
|
* Methods that treat the range as a sequence (#each and methods inherited
|
|
|
|
* from Enumerable) expect the begin object to implement a
|
|
|
|
* <code>succ</code> method to return the next object in sequence.
|
|
|
|
* The #step and #include? methods require the begin
|
|
|
|
* object to implement <code>succ</code> or to be numeric.
|
|
|
|
*
|
|
|
|
* In the <code>Xs</code> class below both <code><=></code> and
|
|
|
|
* <code>succ</code> are implemented so <code>Xs</code> can be used
|
|
|
|
* to construct ranges. Note that the Comparable module is included
|
|
|
|
* so the <code>==</code> method is defined in terms of <code><=></code>.
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
* class Xs # represent a string of 'x's
|
|
|
|
* include Comparable
|
|
|
|
* attr :length
|
|
|
|
* def initialize(n)
|
|
|
|
* @length = n
|
|
|
|
* end
|
|
|
|
* def succ
|
|
|
|
* Xs.new(@length + 1)
|
|
|
|
* end
|
|
|
|
* def <=>(other)
|
|
|
|
* @length <=> other.length
|
|
|
|
* end
|
|
|
|
* def to_s
|
|
|
|
* sprintf "%2d #{inspect}", @length
|
|
|
|
* end
|
|
|
|
* def inspect
|
|
|
|
* 'x' * @length
|
|
|
|
* end
|
|
|
|
* end
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2012-03-03 03:29:01 +00:00
|
|
|
* An example of using <code>Xs</code> to construct a range:
|
2011-12-05 23:36:53 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
* r = Xs.new(3)..Xs.new(6) #=> xxx..xxxxxx
|
|
|
|
* r.to_a #=> [xxx, xxxx, xxxxx, xxxxxx]
|
|
|
|
* r.member?(Xs.new(5)) #=> true
|
2009-02-22 14:23:33 +00:00
|
|
|
*
|
2003-12-24 04:29:32 +00:00
|
|
|
*/
|
|
|
|
|
1998-01-16 12:13:05 +00: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 10:44:21 +00:00
|
|
|
Init_Range(void)
|
1998-01-16 12:13:05 +00:00
|
|
|
{
|
2020-09-25 19:56:30 +02:00
|
|
|
id_beg = rb_intern_const("begin");
|
|
|
|
id_end = rb_intern_const("end");
|
|
|
|
id_excl = rb_intern_const("excl");
|
2007-09-08 15:07:18 +00:00
|
|
|
|
2007-11-23 07:00:50 +00:00
|
|
|
rb_cRange = rb_struct_define_without_accessor(
|
|
|
|
"Range", rb_cObject, range_alloc,
|
2007-11-23 04:35:53 +00:00
|
|
|
"begin", "end", "excl", NULL);
|
2007-09-08 15:07:18 +00:00
|
|
|
|
1999-01-20 04:59:39 +00:00
|
|
|
rb_include_module(rb_cRange, rb_mEnumerable);
|
2007-09-08 15:07:18 +00:00
|
|
|
rb_marshal_define_compat(rb_cRange, rb_cObject, range_dumper, range_loader);
|
2000-02-29 08:05:32 +00:00
|
|
|
rb_define_method(rb_cRange, "initialize", range_initialize, -1);
|
2008-08-20 21:02:54 +00:00
|
|
|
rb_define_method(rb_cRange, "initialize_copy", range_initialize_copy, 1);
|
2000-11-27 09:23:38 +00:00
|
|
|
rb_define_method(rb_cRange, "==", range_eq, 1);
|
2007-07-26 13:37:13 +00:00
|
|
|
rb_define_method(rb_cRange, "===", range_eqq, 1);
|
2001-11-08 09:21:59 +00:00
|
|
|
rb_define_method(rb_cRange, "eql?", range_eql, 1);
|
|
|
|
rb_define_method(rb_cRange, "hash", range_hash, 0);
|
1999-01-20 04:59:39 +00:00
|
|
|
rb_define_method(rb_cRange, "each", range_each, 0);
|
2001-08-14 08:13:31 +00:00
|
|
|
rb_define_method(rb_cRange, "step", range_step, -1);
|
2018-09-28 02:18:58 +00:00
|
|
|
rb_define_method(rb_cRange, "%", range_percent_step, 1);
|
2012-11-14 15:53:50 +00:00
|
|
|
rb_define_method(rb_cRange, "bsearch", range_bsearch, 0);
|
2007-10-18 06:58:35 +00:00
|
|
|
rb_define_method(rb_cRange, "begin", range_begin, 0);
|
2007-10-18 08:14:21 +00:00
|
|
|
rb_define_method(rb_cRange, "end", range_end, 0);
|
2007-10-18 06:58:35 +00:00
|
|
|
rb_define_method(rb_cRange, "first", range_first, -1);
|
|
|
|
rb_define_method(rb_cRange, "last", range_last, -1);
|
2014-02-14 15:45:11 +00:00
|
|
|
rb_define_method(rb_cRange, "min", range_min, -1);
|
|
|
|
rb_define_method(rb_cRange, "max", range_max, -1);
|
2019-06-07 22:03:02 -07:00
|
|
|
rb_define_method(rb_cRange, "minmax", range_minmax, 0);
|
2012-11-06 17:14:46 +00:00
|
|
|
rb_define_method(rb_cRange, "size", range_size, 0);
|
2018-06-22 02:58:37 +00:00
|
|
|
rb_define_method(rb_cRange, "to_a", range_to_a, 0);
|
|
|
|
rb_define_method(rb_cRange, "entries", range_to_a, 0);
|
1999-01-20 04:59:39 +00:00
|
|
|
rb_define_method(rb_cRange, "to_s", range_to_s, 0);
|
|
|
|
rb_define_method(rb_cRange, "inspect", range_inspect, 0);
|
|
|
|
|
1999-08-13 05:45:20 +00:00
|
|
|
rb_define_method(rb_cRange, "exclude_end?", range_exclude_end_p, 0);
|
|
|
|
|
2004-10-19 10:25:23 +00:00
|
|
|
rb_define_method(rb_cRange, "member?", range_include, 1);
|
2002-06-11 07:02:23 +00:00
|
|
|
rb_define_method(rb_cRange, "include?", range_include, 1);
|
2005-12-12 01:01:29 +00:00
|
|
|
rb_define_method(rb_cRange, "cover?", range_cover, 1);
|
2019-12-04 15:31:51 +09:00
|
|
|
rb_define_method(rb_cRange, "count", range_count, -1);
|
1998-01-16 12:13:05 +00:00
|
|
|
}
|