Apply PIE to nghttpx
[platform/upstream/nghttp2.git] / third-party / mruby / mrbgems / mruby-array-ext / src / array.c
1 #include <mruby.h>
2 #include <mruby/value.h>
3 #include <mruby/array.h>
4 #include <mruby/range.h>
5 #include <mruby/hash.h>
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 /*
111  *  call-seq:
112  *     ary.slice!(index)         -> obj or nil
113  *     ary.slice!(start, length) -> new_ary or nil
114  *     ary.slice!(range)         -> new_ary or nil
115  *
116  *  Deletes the element(s) given by an +index+ (optionally up to +length+
117  *  elements) or by a +range+.
118  *
119  *  Returns the deleted object (or objects), or +nil+ if the +index+ is out of
120  *  range.
121  *
122  *     a = [ "a", "b", "c" ]
123  *     a.slice!(1)     #=> "b"
124  *     a               #=> ["a", "c"]
125  *     a.slice!(-1)    #=> "c"
126  *     a               #=> ["a"]
127  *     a.slice!(100)   #=> nil
128  *     a               #=> ["a"]
129  */
130
131 static mrb_value
132 mrb_ary_slice_bang(mrb_state *mrb, mrb_value self)
133 {
134   struct RArray *a = mrb_ary_ptr(self);
135   mrb_int i, j, k, len, alen;
136   mrb_value val;
137   mrb_value *ptr;
138   mrb_value ary;
139
140   mrb_ary_modify(mrb, a);
141
142   if (mrb_get_argc(mrb) == 1) {
143     mrb_value index;
144
145     mrb_get_args(mrb, "o|i", &index, &len);
146     switch (mrb_type(index)) {
147     case MRB_TT_RANGE:
148       if (mrb_range_beg_len(mrb, index, &i, &len, ARY_LEN(a), TRUE) == 1) {
149         goto delete_pos_len;
150       }
151       else {
152         return mrb_nil_value();
153       }
154     case MRB_TT_FIXNUM:
155       val = mrb_funcall(mrb, self, "delete_at", 1, index);
156       return val;
157     default:
158       val = mrb_funcall(mrb, self, "delete_at", 1, index);
159       return val;
160     }
161   }
162
163   mrb_get_args(mrb, "ii", &i, &len);
164  delete_pos_len:
165   alen = ARY_LEN(a);
166   if (i < 0) i += alen;
167   if (i < 0 || alen < i) return mrb_nil_value();
168   if (len < 0) return mrb_nil_value();
169   if (alen == i) return mrb_ary_new(mrb);
170   if (len > alen - i) len = alen - i;
171
172   ary = mrb_ary_new_capa(mrb, len);
173   ptr = ARY_PTR(a);
174   for (j = i, k = 0; k < len; ++j, ++k) {
175     mrb_ary_push(mrb, ary, ptr[j]);
176   }
177
178   ptr += i;
179   for (j = i; j < alen - len; ++j) {
180     *ptr = *(ptr+len);
181     ++ptr;
182   }
183
184   mrb_ary_resize(mrb, self, alen - len);
185   return ary;
186 }
187
188 void
189 mrb_mruby_array_ext_gem_init(mrb_state* mrb)
190 {
191   struct RClass * a = mrb->array_class;
192
193   mrb_define_method(mrb, a, "assoc",  mrb_ary_assoc,  MRB_ARGS_REQ(1));
194   mrb_define_method(mrb, a, "at",     mrb_ary_at,     MRB_ARGS_REQ(1));
195   mrb_define_method(mrb, a, "rassoc", mrb_ary_rassoc, MRB_ARGS_REQ(1));
196   mrb_define_method(mrb, a, "values_at", mrb_ary_values_at, MRB_ARGS_ANY());
197   mrb_define_method(mrb, a, "slice!", mrb_ary_slice_bang,   MRB_ARGS_ANY());
198 }
199
200 void
201 mrb_mruby_array_ext_gem_final(mrb_state* mrb)
202 {
203 }