diff options
author | Kenta Murata <mrkn@users.noreply.github.com> | 2020-10-21 02:40:18 +0900 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-10-21 02:40:18 +0900 |
commit | a6a8576e877b02b83cabd0e712ecd377e7bc156b (patch) | |
tree | 3802e57e38cb467462d19dd266dc4e848d428cc6 /range.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 <mrkn@ruby-lang.org>
Diffstat (limited to 'range.c')
-rw-r--r-- | range.c | 69 |
1 files changed, 51 insertions, 18 deletions
@@ -1329,48 +1329,81 @@ rb_range_values(VALUE range, VALUE *begp, VALUE *endp, int *exclp) return (int)Qtrue; } +/* 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+. + */ VALUE -rb_range_beg_len(VALUE range, long *begp, long *lenp, long len, int err) +rb_range_component_beg_len(VALUE b, VALUE e, int excl, + long *begp, long *lenp, long len, int err) { long beg, end; - VALUE b, e; - int excl; - if (!rb_range_values(range, &b, &e, &excl)) - return Qfalse; beg = NIL_P(b) ? 0 : NUM2LONG(b); end = NIL_P(e) ? -1 : NUM2LONG(e); if (NIL_P(e)) excl = 0; if (beg < 0) { - beg += len; - if (beg < 0) - goto out_of_range; + beg += len; + if (beg < 0) + goto out_of_range; } if (end < 0) - end += len; + end += len; if (!excl) - end++; /* include end point */ + end++; /* include end point */ if (err == 0 || err == 2) { - if (beg > len) - goto out_of_range; - if (end > len) - end = len; + if (beg > len) + goto out_of_range; + if (end > len) + end = len; } len = end - beg; if (len < 0) - len = 0; + len = 0; *begp = beg; *lenp = len; return Qtrue; out_of_range: - if (err) { - rb_raise(rb_eRangeError, "%+"PRIsVALUE" out of range", range); - } return Qnil; } +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; +} + /* * call-seq: * rng.to_s -> string |