aboutsummaryrefslogtreecommitdiffstats
path: root/range.c
diff options
context:
space:
mode:
authorKenta Murata <mrkn@users.noreply.github.com>2020-10-21 02:40:18 +0900
committerGitHub <noreply@github.com>2020-10-21 02:40:18 +0900
commita6a8576e877b02b83cabd0e712ecd377e7bc156b (patch)
tree3802e57e38cb467462d19dd266dc4e848d428cc6 /range.c
parent081cc4eb283cb01ddffb364397e5175dbfacab66 (diff)
downloadruby-a6a8576e877b02b83cabd0e712ecd377e7bc156b.tar.gz
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]
Diffstat (limited to 'range.c')
-rw-r--r--range.c69
1 files changed, 51 insertions, 18 deletions
diff --git a/range.c b/range.c
index c019fcf2e0..a82763ca76 100644
--- a/range.c
+++ b/range.c
@@ -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