summaryrefslogtreecommitdiff
path: root/src/range.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/range.c')
-rw-r--r--src/range.c173
1 files changed, 115 insertions, 58 deletions
diff --git a/src/range.c b/src/range.c
index 5473227..0ff506b 100644
--- a/src/range.c
+++ b/src/range.c
@@ -10,7 +10,7 @@
#include <mruby/string.h>
#include <mruby/array.h>
#include <mruby/numeric.h>
-#include <mruby/presym.h>
+#include <mruby/internal.h>
#define RANGE_INITIALIZED_FLAG 1
#define RANGE_INITIALIZED(p) ((p)->flags |= RANGE_INITIALIZED_FLAG)
@@ -19,12 +19,9 @@
static void
r_check(mrb_state *mrb, mrb_value a, mrb_value b)
{
- enum mrb_vtype ta;
- enum mrb_vtype tb;
- mrb_int n;
+ enum mrb_vtype ta = mrb_type(a);
+ enum mrb_vtype tb = mrb_type(b);
- ta = mrb_type(a);
- tb = mrb_type(b);
#ifdef MRB_NO_FLOAT
if (ta == MRB_TT_INTEGER && tb == MRB_TT_INTEGER ) return;
#else
@@ -36,7 +33,7 @@ r_check(mrb_state *mrb, mrb_value a, mrb_value b)
if (mrb_nil_p(a) || mrb_nil_p(b)) return;
- n = mrb_cmp(mrb, a, b);
+ mrb_int n = mrb_cmp(mrb, a, b);
if (n == -2) { /* can not be compared */
mrb_raise(mrb, E_ARGUMENT_ERROR, "bad value for range");
}
@@ -113,7 +110,7 @@ range_ptr_replace(mrb_state *mrb, struct RRange *r, mrb_value beg, mrb_value end
* rng.first => obj
* rng.begin => obj
*
- * Returns the first object in <i>rng</i>.
+ * Returns the first object in `rng`.
*/
static mrb_value
range_beg(mrb_state *mrb, mrb_value range)
@@ -126,7 +123,7 @@ range_beg(mrb_state *mrb, mrb_value range)
* rng.end => obj
* rng.last => obj
*
- * Returns the object that defines the end of <i>rng</i>.
+ * Returns the object that defines the end of `rng`.
*
* (1..10).end #=> 10
* (1...10).end #=> 10
@@ -141,7 +138,7 @@ range_end(mrb_state *mrb, mrb_value range)
* call-seq:
* range.exclude_end? => true or false
*
- * Returns <code>true</code> if <i>range</i> excludes its end value.
+ * Returns `true` if `range` excludes its end value.
*/
static mrb_value
range_excl(mrb_state *mrb, mrb_value range)
@@ -153,8 +150,8 @@ range_excl(mrb_state *mrb, mrb_value range)
* call-seq:
* Range.new(start, end, exclusive=false) => range
*
- * Constructs a range using the given <i>start</i> and <i>end</i>. If the third
- * parameter is omitted or is <code>false</code>, the <i>range</i> will include
+ * Constructs a range using the given `start` and `end`. If the third
+ * parameter is omitted or is `false`, the `range` will include
* the end object; otherwise, it will be excluded.
*/
static mrb_value
@@ -173,10 +170,10 @@ range_initialize(mrb_state *mrb, mrb_value range)
* call-seq:
* range == obj => true or false
*
- * Returns <code>true</code> only if
- * 1) <i>obj</i> is a Range,
- * 2) <i>obj</i> has equivalent beginning and end items (by comparing them with <code>==</code>),
- * 3) <i>obj</i> has the same #exclude_end? setting as <i>rng</t>.
+ * Returns `true` only if
+ * 1) `obj` is a Range,
+ * 2) `obj` has equivalent beginning and end items (by comparing them with `==`),
+ * 3) `obj` has the same #exclude_end? setting as `rng`.
*
* (0..2) == (0..2) #=> true
* (0..2) == Range.new(0,2) #=> true
@@ -266,7 +263,7 @@ range_to_s(mrb_state *mrb, mrb_value range)
* rng.inspect -> string
*
* Convert this range object to a printable form (using
- * <code>inspect</code> to convert the start and end
+ * `inspect` to convert the start and end
* objects).
*/
static mrb_value
@@ -296,9 +293,9 @@ range_inspect(mrb_state *mrb, mrb_value range)
* call-seq:
* rng.eql?(obj) -> true or false
*
- * Returns <code>true</code> only if <i>obj</i> is a Range, has equivalent
+ * Returns `true` only if `obj` is a Range, has equivalent
* beginning and end items (by comparing them with #eql?), and has the same
- * #exclude_end? setting as <i>rng</i>.
+ * #exclude_end? setting as `rng`.
*
* (0..2).eql?(0..2) #=> true
* (0..2).eql?(Range.new(0,2)) #=> true
@@ -348,7 +345,6 @@ range_num_to_a(mrb_state *mrb, mrb_value range)
struct RRange *r = mrb_range_ptr(mrb, range);
mrb_value beg = RANGE_BEG(r);
mrb_value end = RANGE_END(r);
- mrb_value ary;
mrb->c->ci->mid = 0;
if (mrb_nil_p(end)) {
@@ -372,7 +368,7 @@ range_num_to_a(mrb_state *mrb, mrb_value range)
if (len == MRB_INT_MAX) goto too_long;
len++;
}
- ary = mrb_ary_new_capa(mrb, len);
+ mrb_value ary = mrb_ary_new_capa(mrb, len);
mrb_value *ptr = RARRAY_PTR(ary);
for (mrb_int i=0; i<len; i++) {
ptr[i] = mrb_int_value(mrb, a+i);
@@ -388,48 +384,61 @@ range_num_to_a(mrb_state *mrb, mrb_value range)
if (a > b) {
return mrb_ary_new_capa(mrb, 0);
}
- mrb_int alen = (mrb_int)(b - a) + 1;
- ary = mrb_ary_new_capa(mrb, alen);
+ mrb_int alen = (mrb_int)(b - a) + RANGE_EXCL(r);
+ mrb_value ary = mrb_ary_new_capa(mrb, alen);
mrb_value *ptr = RARRAY_PTR(ary);
- if (RANGE_EXCL(r)) {
- for (mrb_int i=0; a<b; a++) {
- ptr[i++] = mrb_int_value(mrb, a);
- ARY_SET_LEN(RARRAY(ary), i);
- }
- }
- else {
- for (mrb_int i=0; a<=b; a++) {
- ptr[i++] = mrb_int_value(mrb, a);
- ARY_SET_LEN(RARRAY(ary), i);
- }
+ for (mrb_int i=0; i<alen; i++) {
+ ptr[i] = mrb_int_value(mrb, a+i);
+ ARY_SET_LEN(RARRAY(ary), i);
}
return ary;
}
#endif
}
+#ifdef MRB_USE_BIGINT
+ if (mrb_bigint_p(beg)) {
+ end = mrb_as_bint(mrb, end);
+ switch (mrb_bint_cmp(mrb, end, beg)) {
+ case 0: case -1:
+ return mrb_ary_new_capa(mrb, 0);
+ case -2:
+ return mrb_nil_value();
+ default:
+ break;
+ }
+ mrb_value lenv = mrb_bint_sub(mrb, end, beg);
+ if (!mrb_fixnum_p(lenv)) {
+ mrb_raise(mrb, E_RANGE_ERROR, "integer range too long");
+ }
+ mrb_int len = mrb_integer(lenv);
+ if (!RANGE_EXCL(r)) len++;
+ mrb_value ary = mrb_ary_new_capa(mrb, len);
+ for (mrb_int i=0; i<len; i++) {
+ RARRAY_PTR(ary)[i] = mrb_bint_add(mrb, beg, mrb_int_value(mrb, i));
+ ARY_SET_LEN(RARRAY(ary), i+1);
+ }
+ return ary;
+ }
+#endif
return mrb_nil_value();
}
mrb_value
mrb_get_values_at(mrb_state *mrb, mrb_value obj, mrb_int olen, mrb_int argc, const mrb_value *argv, mrb_value (*func)(mrb_state*, mrb_value, mrb_int))
{
- mrb_int i, j, beg, len;
- mrb_value result;
- result = mrb_ary_new(mrb);
+ mrb_int beg, len;
+ mrb_value result = mrb_ary_new(mrb);
- for (i = 0; i < argc; i++) {
+ for (mrb_int i = 0; i < argc; i++) {
mrb_value v = argv[i];
- if (mrb_integer_p(v)
-#ifdef MRB_USE_BIGINT
- || mrb_bigint_p(v)
-#endif
- ) {
+ if (mrb_integer_p(v) || mrb_bigint_p(v)) {
mrb_int i = mrb_as_int(mrb, v);
mrb_ary_push(mrb, result, func(mrb, obj, i));
}
else if (mrb_range_beg_len(mrb, v, &beg, &len, olen, FALSE) == MRB_RANGE_OK) {
mrb_int const end = olen < beg + len ? olen : beg + len;
+ mrb_int j;
for (j = beg; j < end; j++) {
mrb_ary_push(mrb, result, func(mrb, obj, j));
}
@@ -455,6 +464,17 @@ mrb_gc_mark_range(mrb_state *mrb, struct RRange *r)
return 2;
}
+/**
+ * Retrieves a pointer to the internal RRange structure from a Range object.
+ *
+ * This function ensures that the given Range object is properly initialized
+ * before returning a pointer to its data. If the Range is not initialized,
+ * it raises an E_ARGUMENT_ERROR.
+ *
+ * @param mrb The mruby state.
+ * @param range The Range object (mrb_value) from which to get the pointer.
+ * @return A pointer to the struct RRange.
+ */
MRB_API struct RRange*
mrb_range_ptr(mrb_state *mrb, mrb_value range)
{
@@ -467,6 +487,18 @@ mrb_range_ptr(mrb_state *mrb, mrb_value range)
return r;
}
+/**
+ * Creates a new Range object.
+ *
+ * This function allocates and initializes a new Range object with the given
+ * beginning and end values, and an exclude_end flag.
+ *
+ * @param mrb The mruby state.
+ * @param beg The beginning value of the range.
+ * @param end The end value of the range.
+ * @param excl A boolean flag indicating whether the end value is excluded (true) or included (false).
+ * @return The new Range object (mrb_value).
+ */
MRB_API mrb_value
mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
{
@@ -474,6 +506,26 @@ mrb_range_new(mrb_state *mrb, mrb_value beg, mrb_value end, mrb_bool excl)
return mrb_range_value(r);
}
+/**
+ * Calculates the beginning position and length of a range.
+ *
+ * This function is typically used to get array offsets.
+ * It interprets the range as a sequence of integers.
+ * - If the beginning of the range is nil, it's treated as 0.
+ * - If the end of the range is nil, it's treated as -1 (or the last element).
+ *
+ * The function handles negative indices, out-of-bounds conditions,
+ * and truncation based on the provided length and trunc flag.
+ *
+ * @param mrb The mruby state.
+ * @param range The Range object (mrb_value).
+ * @param[out] begp Pointer to store the calculated beginning position.
+ * @param[out] lenp Pointer to store the calculated length.
+ * @param len The length of the sequence the range is being applied to.
+ * @param trunc If true, truncate the range to fit within the given length.
+ * @return An enum mrb_range_beg_len indicating success (MRB_RANGE_OK),
+ * type mismatch (MRB_RANGE_TYPE_MISMATCH), or out of bounds (MRB_RANGE_OUT).
+ */
MRB_API enum mrb_range_beg_len
mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len, mrb_bool trunc)
{
@@ -508,6 +560,25 @@ mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp,
return MRB_RANGE_OK;
}
+/* ---------------------------*/
+static const mrb_mt_entry range_rom_entries[] = {
+ MRB_MT_ENTRY(range_beg, MRB_SYM(begin), MRB_ARGS_NONE()), /* 15.2.14.4.3 */
+ MRB_MT_ENTRY(range_end, MRB_SYM(end), MRB_ARGS_NONE()), /* 15.2.14.4.5 */
+ MRB_MT_ENTRY(range_eq, MRB_OPSYM(eq), MRB_ARGS_REQ(1)), /* 15.2.14.4.1 */
+ MRB_MT_ENTRY(range_include, MRB_OPSYM(eqq), MRB_ARGS_REQ(1)), /* 15.2.14.4.2 */
+ MRB_MT_ENTRY(range_excl, MRB_SYM_Q(exclude_end), MRB_ARGS_NONE()), /* 15.2.14.4.6 */
+ MRB_MT_ENTRY(range_beg, MRB_SYM(first), MRB_ARGS_NONE()), /* 15.2.14.4.7 */
+ MRB_MT_ENTRY(range_include, MRB_SYM_Q(include), MRB_ARGS_REQ(1)), /* 15.2.14.4.8 */
+ MRB_MT_ENTRY(range_initialize, MRB_SYM(initialize), MRB_ARGS_ANY() | MRB_MT_PRIVATE), /* 15.2.14.4.9 */
+ MRB_MT_ENTRY(range_end, MRB_SYM(last), MRB_ARGS_NONE()), /* 15.2.14.4.10 */
+ MRB_MT_ENTRY(range_include, MRB_SYM_Q(member), MRB_ARGS_REQ(1)), /* 15.2.14.4.11 */
+ MRB_MT_ENTRY(range_to_s, MRB_SYM(to_s), MRB_ARGS_NONE()), /* 15.2.14.4.12(x) */
+ MRB_MT_ENTRY(range_inspect, MRB_SYM(inspect), MRB_ARGS_NONE()), /* 15.2.14.4.13(x) */
+ MRB_MT_ENTRY(range_eql, MRB_SYM_Q(eql), MRB_ARGS_REQ(1)), /* 15.2.14.4.14(x) */
+ MRB_MT_ENTRY(range_initialize_copy, MRB_SYM(initialize_copy), MRB_ARGS_REQ(1) | MRB_MT_PRIVATE), /* 15.2.14.4.15(x) */
+ MRB_MT_ENTRY(range_num_to_a, MRB_SYM(__num_to_a), MRB_ARGS_NONE()),
+};
+
void
mrb_init_range(mrb_state *mrb)
{
@@ -517,19 +588,5 @@ mrb_init_range(mrb_state *mrb)
mrb->range_class = r;
MRB_SET_INSTANCE_TT(r, MRB_TT_RANGE);
- mrb_define_method_id(mrb, r, MRB_SYM(begin), range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.3 */
- mrb_define_method_id(mrb, r, MRB_SYM(end), range_end, MRB_ARGS_NONE()); /* 15.2.14.4.5 */
- mrb_define_method_id(mrb, r, MRB_OPSYM(eq), range_eq, MRB_ARGS_REQ(1)); /* 15.2.14.4.1 */
- mrb_define_method_id(mrb, r, MRB_OPSYM(eqq), range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.2 */
- mrb_define_method_id(mrb, r, MRB_SYM_Q(exclude_end), range_excl, MRB_ARGS_NONE()); /* 15.2.14.4.6 */
- mrb_define_method_id(mrb, r, MRB_SYM(first), range_beg, MRB_ARGS_NONE()); /* 15.2.14.4.7 */
- mrb_define_method_id(mrb, r, MRB_SYM_Q(include), range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.8 */
- mrb_define_method_id(mrb, r, MRB_SYM(initialize), range_initialize, MRB_ARGS_ANY()); /* 15.2.14.4.9 */
- mrb_define_method_id(mrb, r, MRB_SYM(last), range_end, MRB_ARGS_NONE()); /* 15.2.14.4.10 */
- mrb_define_method_id(mrb, r, MRB_SYM_Q(member), range_include, MRB_ARGS_REQ(1)); /* 15.2.14.4.11 */
- mrb_define_method_id(mrb, r, MRB_SYM(to_s), range_to_s, MRB_ARGS_NONE()); /* 15.2.14.4.12(x) */
- mrb_define_method_id(mrb, r, MRB_SYM(inspect), range_inspect, MRB_ARGS_NONE()); /* 15.2.14.4.13(x) */
- mrb_define_method_id(mrb, r, MRB_SYM_Q(eql), range_eql, MRB_ARGS_REQ(1)); /* 15.2.14.4.14(x) */
- mrb_define_method_id(mrb, r, MRB_SYM(initialize_copy), range_initialize_copy, MRB_ARGS_REQ(1)); /* 15.2.14.4.15(x) */
- mrb_define_method_id(mrb, r, MRB_SYM(__num_to_a), range_num_to_a, MRB_ARGS_NONE());
+ MRB_MT_INIT_ROM(mrb, r, range_rom_entries);
}