diff options
author | Kenta Murata <[email protected]> | 2020-10-21 02:40:18 +0900 |
---|---|---|
committer | GitHub <[email protected]> | 2020-10-21 02:40:18 +0900 |
commit | a6a8576e877b02b83cabd0e712ecd377e7bc156b (patch) | |
tree | 3802e57e38cb467462d19dd266dc4e848d428cc6 /enumerator.c | |
parent | 081cc4eb283cb01ddffb364397e5175dbfacab66 (diff) |
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]
Notes
Notes:
Merged-By: mrkn <[email protected]>
Diffstat (limited to 'enumerator.c')
-rw-r--r-- | enumerator.c | 44 |
1 files changed, 40 insertions, 4 deletions
diff --git a/enumerator.c b/enumerator.c index 3ea308a7cd..6e88c5db4a 100644 --- a/enumerator.c +++ b/enumerator.c @@ -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 |