Commit 44dc05f1 authored by take_cheeze's avatar take_cheeze

Implement Struct#values_at and Array#values_at .

Add API `mrb_get_values_at()` to mruby/range.h .
parent d91c9a9e
...@@ -27,6 +27,7 @@ struct RRange { ...@@ -27,6 +27,7 @@ struct RRange {
mrb_value mrb_range_new(mrb_state*, mrb_value, mrb_value, mrb_bool); mrb_value mrb_range_new(mrb_state*, mrb_value, mrb_value, mrb_bool);
mrb_bool mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len); mrb_bool mrb_range_beg_len(mrb_state *mrb, mrb_value range, mrb_int *begp, mrb_int *lenp, mrb_int len);
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));
#if defined(__cplusplus) #if defined(__cplusplus)
} /* extern "C" { */ } /* extern "C" { */
......
#include "mruby.h" #include "mruby.h"
#include "mruby/value.h" #include "mruby/value.h"
#include "mruby/array.h" #include "mruby/array.h"
#include "mruby/range.h"
/* /*
* call-seq: * call-seq:
...@@ -122,6 +123,17 @@ mrb_ary_at(mrb_state *mrb, mrb_value ary) ...@@ -122,6 +123,17 @@ mrb_ary_at(mrb_state *mrb, mrb_value ary)
return mrb_ary_entry(ary, pos); return mrb_ary_entry(ary, pos);
} }
static mrb_value
mrb_ary_values_at(mrb_state *mrb, mrb_value self)
{
mrb_int argc;
mrb_value *argv;
mrb_get_args(mrb, "*", &argv, &argc);
return mrb_get_values_at(mrb, self, MRB_INT_MAX, argc, argv, mrb_ary_ref);
}
void void
mrb_mruby_array_ext_gem_init(mrb_state* mrb) mrb_mruby_array_ext_gem_init(mrb_state* mrb)
{ {
...@@ -132,6 +144,7 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb) ...@@ -132,6 +144,7 @@ mrb_mruby_array_ext_gem_init(mrb_state* mrb)
mrb_define_method(mrb, a, "assoc", mrb_ary_assoc, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "assoc", mrb_ary_assoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1)); mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
} }
void void
......
...@@ -280,3 +280,13 @@ assert("Array#select!") do ...@@ -280,3 +280,13 @@ assert("Array#select!") do
assert_equal [4, 5], a.select! { |val| val > 3 } assert_equal [4, 5], a.select! { |val| val > 3 }
assert_equal [4, 5], a assert_equal [4, 5], a
end end
assert('Array#values_at') do
a = %w{red green purple white none}
assert_equal %w{red purple none}, a.values_at(0, 2, 4)
assert_equal ['green', 'white', nil, nil], a.values_at(1, 3, 5, 7)
assert_equal ['none', 'white', 'white', nil], a.values_at(-1, -2, -2, -7)
assert_equal ['none', nil, nil, 'red', 'green', 'purple'], a.values_at(4..6, 0...3)
assert_raise(TypeError) { a.values_at 'tt' }
end
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include "mruby/class.h" #include "mruby/class.h"
#include "mruby/variable.h" #include "mruby/variable.h"
#include "mruby/hash.h" #include "mruby/hash.h"
#include "mruby/range.h"
#define RSTRUCT_LEN(st) RARRAY_LEN(st) #define RSTRUCT_LEN(st) RARRAY_LEN(st)
#define RSTRUCT_PTR(st) RARRAY_PTR(st) #define RSTRUCT_PTR(st) RARRAY_PTR(st)
...@@ -828,6 +829,23 @@ mrb_struct_to_h(mrb_state *mrb, mrb_value self) ...@@ -828,6 +829,23 @@ mrb_struct_to_h(mrb_state *mrb, mrb_value self)
return ret; return ret;
} }
static mrb_value
struct_values_at_getter(mrb_state *mrb, mrb_value self, mrb_int idx)
{
return mrb_struct_aref_n(mrb, self, mrb_fixnum_value(idx));
}
static mrb_value
mrb_struct_values_at(mrb_state *mrb, mrb_value self)
{
mrb_int argc;
mrb_value *argv;
mrb_get_args(mrb, "*", &argv, &argc);
return mrb_get_values_at(mrb, self, MRB_INT_MAX, argc, argv, struct_values_at_getter);
}
/* /*
* A <code>Struct</code> is a convenient way to bundle a number of * A <code>Struct</code> is a convenient way to bundle a number of
* attributes together, using accessor methods, without having to write * attributes together, using accessor methods, without having to write
...@@ -866,6 +884,7 @@ mrb_mruby_struct_gem_init(mrb_state* mrb) ...@@ -866,6 +884,7 @@ mrb_mruby_struct_gem_init(mrb_state* mrb)
mrb_define_method(mrb, st, "to_a", mrb_struct_to_a, MRB_ARGS_NONE()); mrb_define_method(mrb, st, "to_a", mrb_struct_to_a, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "values", mrb_struct_to_a, MRB_ARGS_NONE()); mrb_define_method(mrb, st, "values", mrb_struct_to_a, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "to_h", mrb_struct_to_h, MRB_ARGS_NONE()); mrb_define_method(mrb, st, "to_h", mrb_struct_to_h, MRB_ARGS_NONE());
mrb_define_method(mrb, st, "values_at", mrb_struct_values_at, MRB_ARGS_NONE());
} }
void void
......
...@@ -123,3 +123,10 @@ assert('Struct#to_h') do ...@@ -123,3 +123,10 @@ assert('Struct#to_h') do
s = Struct.new(:white, :red, :green).new('ruuko', 'yuzuki', 'hitoe') s = Struct.new(:white, :red, :green).new('ruuko', 'yuzuki', 'hitoe')
assert_equal(:white => 'ruuko', :red => 'yuzuki', :green => 'hitoe') { s.to_h } assert_equal(:white => 'ruuko', :red => 'yuzuki', :green => 'hitoe') { s.to_h }
end end
assert('Struct#values_at') do
a = Struct.new(:blue, :purple).new('aki', 'io')
assert_equal ['aki'], a.values_at(0)
assert_equal ['io', 'aki'], a.values_at(1, 0)
assert_raise(IndexError) { a.values_at 2 }
end
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "mruby/class.h" #include "mruby/class.h"
#include "mruby/range.h" #include "mruby/range.h"
#include "mruby/string.h" #include "mruby/string.h"
#include "mruby/array.h"
#define RANGE_CLASS (mrb_class_get(mrb, "Range")) #define RANGE_CLASS (mrb_class_get(mrb, "Range"))
...@@ -395,6 +396,33 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy) ...@@ -395,6 +396,33 @@ range_initialize_copy(mrb_state *mrb, mrb_value copy)
return copy; return copy;
} }
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);
for (i = 0; i < argc; ++i) {
if (mrb_fixnum_p(argv[i])) {
mrb_ary_push(mrb, result, func(mrb, obj, mrb_fixnum(argv[i])));
} else if (mrb_range_beg_len(mrb, argv[i], &beg, &len, olen)) {
mrb_int const end = RARRAY_LEN(obj) < beg + len ? RARRAY_LEN(obj) : beg + len;
for (j = beg; j < end; ++j) {
mrb_ary_push(mrb, result, func(mrb, obj, j));
}
for (; j < beg + len; ++j) {
mrb_ary_push(mrb, result, mrb_nil_value());
}
} else {
mrb_raisef(mrb, E_ARGUMENT_ERROR, "invalid values selector: %S", argv[i]);
}
}
return result;
}
void void
mrb_init_range(mrb_state *mrb) mrb_init_range(mrb_state *mrb)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment