Feature #16812: Allow slicing arrays with ArithmeticSequence (#3241)

* Support ArithmeticSequence in Array#slice

* Extract rb_range_component_beg_len

* Use rb_range_values to check Range object

* Fix ary_make_partial_step

* Fix for negative step cases

* range.c: Describe the role of err argument in rb_range_component_beg_len

* Raise a RangeError when an arithmetic sequence refers the outside of an array

[Feature #16812]
This commit is contained in:
Kenta Murata 2020-10-21 02:40:18 +09:00 committed by GitHub
parent 081cc4eb28
commit a6a8576e87
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
Notes: git 2020-10-21 02:40:53 +09:00
Merged-By: mrkn <mrkn@ruby-lang.org>
6 changed files with 216 additions and 31 deletions

View file

@ -3410,17 +3410,53 @@ rb_arithmetic_sequence_extract(VALUE obj, rb_arithmetic_sequence_components_t *c
component->exclude_end = arith_seq_exclude_end_p(obj);
return 1;
}
else if (rb_obj_is_kind_of(obj, rb_cRange)) {
component->begin = RANGE_BEG(obj);
component->end = RANGE_END(obj);
else if (rb_range_values(obj, &component->begin, &component->end, &component->exclude_end)) {
component->step = INT2FIX(1);
component->exclude_end = RTEST(RANGE_EXCL(obj));
return 1;
}
return 0;
}
VALUE
rb_arithmetic_sequence_beg_len_step(VALUE obj, long *begp, long *lenp, long *stepp, long len, int err)
{
RUBY_ASSERT(begp != NULL);
RUBY_ASSERT(lenp != NULL);
RUBY_ASSERT(stepp != NULL);
rb_arithmetic_sequence_components_t aseq;
if (!rb_arithmetic_sequence_extract(obj, &aseq)) {
return Qfalse;
}
long step = NIL_P(aseq.step) ? 1 : NUM2LONG(aseq.step);
*stepp = step;
if (step < 0) {
VALUE tmp = aseq.begin;
aseq.begin = aseq.end;
aseq.end = tmp;
}
if (err == 0 && (step < -1 || step > 1)) {
if (rb_range_component_beg_len(aseq.begin, aseq.end, aseq.exclude_end, begp, lenp, len, 1) == Qtrue) {
if (*begp > len)
goto out_of_range;
if (*lenp > len)
goto out_of_range;
return Qtrue;
}
}
else {
return rb_range_component_beg_len(aseq.begin, aseq.end, aseq.exclude_end, begp, lenp, len, err);
}
out_of_range:
rb_raise(rb_eRangeError, "%+"PRIsVALUE" out of range", obj);
return Qnil;
}
/*
* call-seq:
* aseq.first -> num or nil