[331] | 1 | #include <mruby.h>
|
---|
| 2 | #include <mruby/value.h>
|
---|
| 3 | #include <mruby/array.h>
|
---|
| 4 | #include <mruby/range.h>
|
---|
| 5 | #include <mruby/hash.h>
|
---|
[270] | 6 |
|
---|
| 7 | /*
|
---|
| 8 | * call-seq:
|
---|
| 9 | * ary.assoc(obj) -> new_ary or nil
|
---|
| 10 | *
|
---|
| 11 | * Searches through an array whose elements are also arrays
|
---|
| 12 | * comparing _obj_ with the first element of each contained array
|
---|
| 13 | * using obj.==.
|
---|
| 14 | * Returns the first contained array that matches (that
|
---|
| 15 | * is, the first associated array),
|
---|
| 16 | * or +nil+ if no match is found.
|
---|
| 17 | * See also <code>Array#rassoc</code>.
|
---|
| 18 | *
|
---|
| 19 | * s1 = [ "colors", "red", "blue", "green" ]
|
---|
| 20 | * s2 = [ "letters", "a", "b", "c" ]
|
---|
| 21 | * s3 = "foo"
|
---|
| 22 | * a = [ s1, s2, s3 ]
|
---|
| 23 | * a.assoc("letters") #=> [ "letters", "a", "b", "c" ]
|
---|
| 24 | * a.assoc("foo") #=> nil
|
---|
| 25 | */
|
---|
| 26 |
|
---|
| 27 | static mrb_value
|
---|
| 28 | mrb_ary_assoc(mrb_state *mrb, mrb_value ary)
|
---|
| 29 | {
|
---|
| 30 | mrb_int i;
|
---|
| 31 | mrb_value v, k;
|
---|
| 32 |
|
---|
| 33 | mrb_get_args(mrb, "o", &k);
|
---|
| 34 |
|
---|
| 35 | for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
---|
| 36 | v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
|
---|
| 37 | if (!mrb_nil_p(v) && RARRAY_LEN(v) > 0 &&
|
---|
| 38 | mrb_equal(mrb, RARRAY_PTR(v)[0], k))
|
---|
| 39 | return v;
|
---|
| 40 | }
|
---|
| 41 | return mrb_nil_value();
|
---|
| 42 | }
|
---|
| 43 |
|
---|
| 44 | /*
|
---|
| 45 | * call-seq:
|
---|
| 46 | * ary.rassoc(obj) -> new_ary or nil
|
---|
| 47 | *
|
---|
| 48 | * Searches through the array whose elements are also arrays. Compares
|
---|
| 49 | * _obj_ with the second element of each contained array using
|
---|
| 50 | * <code>==</code>. Returns the first contained array that matches. See
|
---|
| 51 | * also <code>Array#assoc</code>.
|
---|
| 52 | *
|
---|
| 53 | * a = [ [ 1, "one"], [2, "two"], [3, "three"], ["ii", "two"] ]
|
---|
| 54 | * a.rassoc("two") #=> [2, "two"]
|
---|
| 55 | * a.rassoc("four") #=> nil
|
---|
| 56 | */
|
---|
| 57 |
|
---|
| 58 | static mrb_value
|
---|
| 59 | mrb_ary_rassoc(mrb_state *mrb, mrb_value ary)
|
---|
| 60 | {
|
---|
| 61 | mrb_int i;
|
---|
| 62 | mrb_value v, value;
|
---|
| 63 |
|
---|
| 64 | mrb_get_args(mrb, "o", &value);
|
---|
| 65 |
|
---|
| 66 | for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
---|
| 67 | v = RARRAY_PTR(ary)[i];
|
---|
| 68 | if (mrb_type(v) == MRB_TT_ARRAY &&
|
---|
| 69 | RARRAY_LEN(v) > 1 &&
|
---|
| 70 | mrb_equal(mrb, RARRAY_PTR(v)[1], value))
|
---|
| 71 | return v;
|
---|
| 72 | }
|
---|
| 73 | return mrb_nil_value();
|
---|
| 74 | }
|
---|
| 75 |
|
---|
| 76 | /*
|
---|
| 77 | * call-seq:
|
---|
| 78 | * ary.at(index) -> obj or nil
|
---|
| 79 | *
|
---|
| 80 | * Returns the element at _index_. A
|
---|
| 81 | * negative index counts from the end of +self+. Returns +nil+
|
---|
| 82 | * if the index is out of range. See also <code>Array#[]</code>.
|
---|
| 83 | *
|
---|
| 84 | * a = [ "a", "b", "c", "d", "e" ]
|
---|
| 85 | * a.at(0) #=> "a"
|
---|
| 86 | * a.at(-1) #=> "e"
|
---|
| 87 | */
|
---|
| 88 |
|
---|
| 89 | static mrb_value
|
---|
| 90 | mrb_ary_at(mrb_state *mrb, mrb_value ary)
|
---|
| 91 | {
|
---|
| 92 | mrb_int pos;
|
---|
| 93 | mrb_get_args(mrb, "i", &pos);
|
---|
| 94 |
|
---|
| 95 | return mrb_ary_entry(ary, pos);
|
---|
| 96 | }
|
---|
| 97 |
|
---|
| 98 | static mrb_value
|
---|
| 99 | mrb_ary_values_at(mrb_state *mrb, mrb_value self)
|
---|
| 100 | {
|
---|
| 101 | mrb_int argc;
|
---|
| 102 | mrb_value *argv;
|
---|
| 103 |
|
---|
| 104 | mrb_get_args(mrb, "*", &argv, &argc);
|
---|
| 105 |
|
---|
| 106 | return mrb_get_values_at(mrb, self, RARRAY_LEN(self), argc, argv, mrb_ary_ref);
|
---|
| 107 | }
|
---|
| 108 |
|
---|
| 109 | /*
|
---|
| 110 | * call-seq:
|
---|
| 111 | * ary.to_h -> Hash
|
---|
| 112 | *
|
---|
| 113 | * Returns the result of interpreting <i>aray</i> as an array of
|
---|
| 114 | * <tt>[key, value]</tt> paris.
|
---|
| 115 | *
|
---|
| 116 | * [[:foo, :bar], [1, 2]].to_h
|
---|
| 117 | * # => {:foo => :bar, 1 => 2}
|
---|
| 118 | *
|
---|
| 119 | */
|
---|
| 120 |
|
---|
| 121 | static mrb_value
|
---|
| 122 | mrb_ary_to_h(mrb_state *mrb, mrb_value ary)
|
---|
| 123 | {
|
---|
| 124 | mrb_int i;
|
---|
| 125 | mrb_value v, hash;
|
---|
| 126 |
|
---|
| 127 | hash = mrb_hash_new_capa(mrb, 0);
|
---|
| 128 |
|
---|
| 129 | for (i = 0; i < RARRAY_LEN(ary); ++i) {
|
---|
| 130 | v = mrb_check_array_type(mrb, RARRAY_PTR(ary)[i]);
|
---|
| 131 |
|
---|
| 132 | if (mrb_nil_p(v)) {
|
---|
| 133 | mrb_raisef(mrb, E_TYPE_ERROR, "wrong element type %S at %S (expected array)",
|
---|
[331] | 134 | mrb_str_new_cstr(mrb, mrb_obj_classname(mrb, ary_elt(ary, i))),
|
---|
[270] | 135 | mrb_fixnum_value(i)
|
---|
| 136 | );
|
---|
| 137 | }
|
---|
| 138 |
|
---|
| 139 | if (RARRAY_LEN(v) != 2) {
|
---|
| 140 | mrb_raisef(mrb, E_ARGUMENT_ERROR, "wrong array length at %S (expected 2, was %S)",
|
---|
| 141 | mrb_fixnum_value(i),
|
---|
| 142 | mrb_fixnum_value(RARRAY_LEN(v))
|
---|
| 143 | );
|
---|
| 144 | }
|
---|
| 145 |
|
---|
| 146 | mrb_hash_set(mrb, hash, RARRAY_PTR(v)[0], RARRAY_PTR(v)[1]);
|
---|
| 147 | }
|
---|
| 148 |
|
---|
| 149 | return hash;
|
---|
| 150 | }
|
---|
| 151 |
|
---|
[331] | 152 | /*
|
---|
| 153 | * call-seq:
|
---|
| 154 | * ary.slice!(index) -> obj or nil
|
---|
| 155 | * ary.slice!(start, length) -> new_ary or nil
|
---|
| 156 | * ary.slice!(range) -> new_ary or nil
|
---|
| 157 | *
|
---|
| 158 | * Deletes the element(s) given by an +index+ (optionally up to +length+
|
---|
| 159 | * elements) or by a +range+.
|
---|
| 160 | *
|
---|
| 161 | * Returns the deleted object (or objects), or +nil+ if the +index+ is out of
|
---|
| 162 | * range.
|
---|
| 163 | *
|
---|
| 164 | * a = [ "a", "b", "c" ]
|
---|
| 165 | * a.slice!(1) #=> "b"
|
---|
| 166 | * a #=> ["a", "c"]
|
---|
| 167 | * a.slice!(-1) #=> "c"
|
---|
| 168 | * a #=> ["a"]
|
---|
| 169 | * a.slice!(100) #=> nil
|
---|
| 170 | * a #=> ["a"]
|
---|
| 171 | */
|
---|
| 172 |
|
---|
| 173 | static mrb_value
|
---|
| 174 | mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
|
---|
| 175 | {
|
---|
| 176 | struct RArray *a = mrb_ary_ptr(self);
|
---|
| 177 | mrb_int i, j, k, len;
|
---|
| 178 | mrb_value index;
|
---|
| 179 | mrb_value val;
|
---|
| 180 | mrb_value *ptr;
|
---|
| 181 | mrb_value ary;
|
---|
| 182 |
|
---|
| 183 | mrb_ary_modify(mrb, a);
|
---|
| 184 |
|
---|
| 185 | if (mrb_get_args(mrb, "o|i", &index, &len) == 1) {
|
---|
| 186 | switch (mrb_type(index)) {
|
---|
| 187 | case MRB_TT_RANGE:
|
---|
| 188 | if (mrb_range_beg_len(mrb, index, &i, &len, a->len, TRUE) == 1) {
|
---|
| 189 | goto delete_pos_len;
|
---|
| 190 | }
|
---|
| 191 | else {
|
---|
| 192 | return mrb_nil_value();
|
---|
| 193 | }
|
---|
| 194 | case MRB_TT_FIXNUM:
|
---|
| 195 | val = mrb_funcall(mrb, self, "delete_at", 1, index);
|
---|
| 196 | return val;
|
---|
| 197 | default:
|
---|
| 198 | val = mrb_funcall(mrb, self, "delete_at", 1, index);
|
---|
| 199 | return val;
|
---|
| 200 | }
|
---|
| 201 | }
|
---|
| 202 |
|
---|
| 203 | i = mrb_fixnum(index);
|
---|
| 204 | delete_pos_len:
|
---|
| 205 | if (i < 0) i += a->len;
|
---|
| 206 | if (i < 0 || a->len < i) return mrb_nil_value();
|
---|
| 207 | if (len < 0) return mrb_nil_value();
|
---|
| 208 | if (a->len == i) return mrb_ary_new(mrb);
|
---|
| 209 | if (len > a->len - i) len = a->len - i;
|
---|
| 210 |
|
---|
| 211 | ary = mrb_ary_new_capa(mrb, len);
|
---|
| 212 |
|
---|
| 213 | for (j = i, k = 0; k < len; ++j, ++k) {
|
---|
| 214 | mrb_ary_push(mrb, ary, a->ptr[j]);
|
---|
| 215 | }
|
---|
| 216 |
|
---|
| 217 | ptr = a->ptr + i;
|
---|
| 218 | for (j = i; j < a->len - len; ++j) {
|
---|
| 219 | *ptr = *(ptr+len);
|
---|
| 220 | ++ptr;
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | mrb_ary_resize(mrb, self, a->len - len);
|
---|
| 224 | return ary;
|
---|
| 225 | }
|
---|
| 226 |
|
---|
[270] | 227 | void
|
---|
| 228 | mrb_mruby_array_ext_gem_init(mrb_state* mrb)
|
---|
| 229 | {
|
---|
| 230 | struct RClass * a = mrb->array_class;
|
---|
| 231 |
|
---|
| 232 | mrb_define_method(mrb, a, "assoc", mrb_ary_assoc, MRB_ARGS_REQ(1));
|
---|
| 233 | mrb_define_method(mrb, a, "at", mrb_ary_at, MRB_ARGS_REQ(1));
|
---|
| 234 | mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
|
---|
| 235 | mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
|
---|
| 236 | mrb_define_method(mrb, a, "to_h", mrb_ary_to_h, MRB_ARGS_REQ(0));
|
---|
[331] | 237 | mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang, MRB_ARGS_ANY());
|
---|
[270] | 238 | }
|
---|
| 239 |
|
---|
| 240 | void
|
---|
| 241 | mrb_mruby_array_ext_gem_final(mrb_state* mrb)
|
---|
| 242 | {
|
---|
| 243 | }
|
---|