mbed I/F binding for mruby
Dependents: mruby_mbed_web mirb_mbed
mbed-mruby
How to use
Class
src/array.c@0:158c61bb030f, 2015-03-25 (annotated)
- Committer:
- mzta
- Date:
- Wed Mar 25 17:36:16 2015 +0000
- Revision:
- 0:158c61bb030f
mirb_mbed initial commit;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
mzta | 0:158c61bb030f | 1 | /* |
mzta | 0:158c61bb030f | 2 | ** array.c - Array class |
mzta | 0:158c61bb030f | 3 | ** |
mzta | 0:158c61bb030f | 4 | ** See Copyright Notice in mruby.h |
mzta | 0:158c61bb030f | 5 | */ |
mzta | 0:158c61bb030f | 6 | |
mzta | 0:158c61bb030f | 7 | #include "mruby.h" |
mzta | 0:158c61bb030f | 8 | #include "mruby/array.h" |
mzta | 0:158c61bb030f | 9 | #include "mruby/class.h" |
mzta | 0:158c61bb030f | 10 | #include "mruby/string.h" |
mzta | 0:158c61bb030f | 11 | #include "mruby/range.h" |
mzta | 0:158c61bb030f | 12 | #include "value_array.h" |
mzta | 0:158c61bb030f | 13 | |
mzta | 0:158c61bb030f | 14 | #define ARY_DEFAULT_LEN 4 |
mzta | 0:158c61bb030f | 15 | #define ARY_SHRINK_RATIO 5 /* must be larger than 2 */ |
mzta | 0:158c61bb030f | 16 | #define ARY_C_MAX_SIZE (SIZE_MAX / sizeof(mrb_value)) |
mzta | 0:158c61bb030f | 17 | #define ARY_MAX_SIZE ((ARY_C_MAX_SIZE < (size_t)MRB_INT_MAX) ? (mrb_int)ARY_C_MAX_SIZE : MRB_INT_MAX-1) |
mzta | 0:158c61bb030f | 18 | |
mzta | 0:158c61bb030f | 19 | static inline mrb_value |
mzta | 0:158c61bb030f | 20 | ary_elt(mrb_value ary, mrb_int offset) |
mzta | 0:158c61bb030f | 21 | { |
mzta | 0:158c61bb030f | 22 | if (RARRAY_LEN(ary) == 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 23 | if (offset < 0 || RARRAY_LEN(ary) <= offset) { |
mzta | 0:158c61bb030f | 24 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 25 | } |
mzta | 0:158c61bb030f | 26 | return RARRAY_PTR(ary)[offset]; |
mzta | 0:158c61bb030f | 27 | } |
mzta | 0:158c61bb030f | 28 | |
mzta | 0:158c61bb030f | 29 | static struct RArray* |
mzta | 0:158c61bb030f | 30 | ary_new_capa(mrb_state *mrb, mrb_int capa) |
mzta | 0:158c61bb030f | 31 | { |
mzta | 0:158c61bb030f | 32 | struct RArray *a; |
mzta | 0:158c61bb030f | 33 | mrb_int blen; |
mzta | 0:158c61bb030f | 34 | |
mzta | 0:158c61bb030f | 35 | if (capa > ARY_MAX_SIZE) { |
mzta | 0:158c61bb030f | 36 | mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); |
mzta | 0:158c61bb030f | 37 | } |
mzta | 0:158c61bb030f | 38 | blen = capa * sizeof(mrb_value); |
mzta | 0:158c61bb030f | 39 | if (blen < capa) { |
mzta | 0:158c61bb030f | 40 | mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); |
mzta | 0:158c61bb030f | 41 | } |
mzta | 0:158c61bb030f | 42 | |
mzta | 0:158c61bb030f | 43 | a = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class); |
mzta | 0:158c61bb030f | 44 | a->ptr = (mrb_value *)mrb_malloc(mrb, blen); |
mzta | 0:158c61bb030f | 45 | a->aux.capa = capa; |
mzta | 0:158c61bb030f | 46 | a->len = 0; |
mzta | 0:158c61bb030f | 47 | |
mzta | 0:158c61bb030f | 48 | return a; |
mzta | 0:158c61bb030f | 49 | } |
mzta | 0:158c61bb030f | 50 | |
mzta | 0:158c61bb030f | 51 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 52 | mrb_ary_new_capa(mrb_state *mrb, mrb_int capa) |
mzta | 0:158c61bb030f | 53 | { |
mzta | 0:158c61bb030f | 54 | struct RArray *a = ary_new_capa(mrb, capa); |
mzta | 0:158c61bb030f | 55 | return mrb_obj_value(a); |
mzta | 0:158c61bb030f | 56 | } |
mzta | 0:158c61bb030f | 57 | |
mzta | 0:158c61bb030f | 58 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 59 | mrb_ary_new(mrb_state *mrb) |
mzta | 0:158c61bb030f | 60 | { |
mzta | 0:158c61bb030f | 61 | return mrb_ary_new_capa(mrb, 0); |
mzta | 0:158c61bb030f | 62 | } |
mzta | 0:158c61bb030f | 63 | |
mzta | 0:158c61bb030f | 64 | /* |
mzta | 0:158c61bb030f | 65 | * to copy array, use this instead of memcpy because of portability |
mzta | 0:158c61bb030f | 66 | * * gcc on ARM may fail optimization of memcpy |
mzta | 0:158c61bb030f | 67 | * http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.faqs/ka3934.html |
mzta | 0:158c61bb030f | 68 | * * gcc on MIPS also fail |
mzta | 0:158c61bb030f | 69 | * http://gcc.gnu.org/bugzilla/show_bug.cgi?id=39755 |
mzta | 0:158c61bb030f | 70 | * * memcpy doesn't exist on freestanding environment |
mzta | 0:158c61bb030f | 71 | * |
mzta | 0:158c61bb030f | 72 | * If you optimize for binary size, use memcpy instead of this at your own risk |
mzta | 0:158c61bb030f | 73 | * of above portability issue. |
mzta | 0:158c61bb030f | 74 | * |
mzta | 0:158c61bb030f | 75 | * see also http://togetter.com/li/462898 |
mzta | 0:158c61bb030f | 76 | * |
mzta | 0:158c61bb030f | 77 | */ |
mzta | 0:158c61bb030f | 78 | static inline void |
mzta | 0:158c61bb030f | 79 | array_copy(mrb_value *dst, const mrb_value *src, mrb_int size) |
mzta | 0:158c61bb030f | 80 | { |
mzta | 0:158c61bb030f | 81 | mrb_int i; |
mzta | 0:158c61bb030f | 82 | |
mzta | 0:158c61bb030f | 83 | for (i = 0; i < size; i++) { |
mzta | 0:158c61bb030f | 84 | dst[i] = src[i]; |
mzta | 0:158c61bb030f | 85 | } |
mzta | 0:158c61bb030f | 86 | } |
mzta | 0:158c61bb030f | 87 | |
mzta | 0:158c61bb030f | 88 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 89 | mrb_ary_new_from_values(mrb_state *mrb, mrb_int size, const mrb_value *vals) |
mzta | 0:158c61bb030f | 90 | { |
mzta | 0:158c61bb030f | 91 | mrb_value ary; |
mzta | 0:158c61bb030f | 92 | struct RArray *a; |
mzta | 0:158c61bb030f | 93 | |
mzta | 0:158c61bb030f | 94 | ary = mrb_ary_new_capa(mrb, size); |
mzta | 0:158c61bb030f | 95 | a = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 96 | array_copy(a->ptr, vals, size); |
mzta | 0:158c61bb030f | 97 | a->len = size; |
mzta | 0:158c61bb030f | 98 | |
mzta | 0:158c61bb030f | 99 | return ary; |
mzta | 0:158c61bb030f | 100 | } |
mzta | 0:158c61bb030f | 101 | |
mzta | 0:158c61bb030f | 102 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 103 | mrb_assoc_new(mrb_state *mrb, mrb_value car, mrb_value cdr) |
mzta | 0:158c61bb030f | 104 | { |
mzta | 0:158c61bb030f | 105 | struct RArray *a; |
mzta | 0:158c61bb030f | 106 | |
mzta | 0:158c61bb030f | 107 | a = ary_new_capa(mrb, 2); |
mzta | 0:158c61bb030f | 108 | a->ptr[0] = car; |
mzta | 0:158c61bb030f | 109 | a->ptr[1] = cdr; |
mzta | 0:158c61bb030f | 110 | a->len = 2; |
mzta | 0:158c61bb030f | 111 | return mrb_obj_value(a); |
mzta | 0:158c61bb030f | 112 | } |
mzta | 0:158c61bb030f | 113 | |
mzta | 0:158c61bb030f | 114 | static void |
mzta | 0:158c61bb030f | 115 | ary_fill_with_nil(mrb_value *ptr, mrb_int size) |
mzta | 0:158c61bb030f | 116 | { |
mzta | 0:158c61bb030f | 117 | mrb_value nil = mrb_nil_value(); |
mzta | 0:158c61bb030f | 118 | |
mzta | 0:158c61bb030f | 119 | while (size--) { |
mzta | 0:158c61bb030f | 120 | *ptr++ = nil; |
mzta | 0:158c61bb030f | 121 | } |
mzta | 0:158c61bb030f | 122 | } |
mzta | 0:158c61bb030f | 123 | |
mzta | 0:158c61bb030f | 124 | static void |
mzta | 0:158c61bb030f | 125 | ary_modify(mrb_state *mrb, struct RArray *a) |
mzta | 0:158c61bb030f | 126 | { |
mzta | 0:158c61bb030f | 127 | if (ARY_SHARED_P(a)) { |
mzta | 0:158c61bb030f | 128 | mrb_shared_array *shared = a->aux.shared; |
mzta | 0:158c61bb030f | 129 | |
mzta | 0:158c61bb030f | 130 | if (shared->refcnt == 1 && a->ptr == shared->ptr) { |
mzta | 0:158c61bb030f | 131 | a->ptr = shared->ptr; |
mzta | 0:158c61bb030f | 132 | a->aux.capa = a->len; |
mzta | 0:158c61bb030f | 133 | mrb_free(mrb, shared); |
mzta | 0:158c61bb030f | 134 | } |
mzta | 0:158c61bb030f | 135 | else { |
mzta | 0:158c61bb030f | 136 | mrb_value *ptr, *p; |
mzta | 0:158c61bb030f | 137 | mrb_int len; |
mzta | 0:158c61bb030f | 138 | |
mzta | 0:158c61bb030f | 139 | p = a->ptr; |
mzta | 0:158c61bb030f | 140 | len = a->len * sizeof(mrb_value); |
mzta | 0:158c61bb030f | 141 | ptr = (mrb_value *)mrb_malloc(mrb, len); |
mzta | 0:158c61bb030f | 142 | if (p) { |
mzta | 0:158c61bb030f | 143 | array_copy(ptr, p, a->len); |
mzta | 0:158c61bb030f | 144 | } |
mzta | 0:158c61bb030f | 145 | a->ptr = ptr; |
mzta | 0:158c61bb030f | 146 | a->aux.capa = a->len; |
mzta | 0:158c61bb030f | 147 | mrb_ary_decref(mrb, shared); |
mzta | 0:158c61bb030f | 148 | } |
mzta | 0:158c61bb030f | 149 | ARY_UNSET_SHARED_FLAG(a); |
mzta | 0:158c61bb030f | 150 | } |
mzta | 0:158c61bb030f | 151 | } |
mzta | 0:158c61bb030f | 152 | |
mzta | 0:158c61bb030f | 153 | MRB_API void |
mzta | 0:158c61bb030f | 154 | mrb_ary_modify(mrb_state *mrb, struct RArray* a) |
mzta | 0:158c61bb030f | 155 | { |
mzta | 0:158c61bb030f | 156 | mrb_write_barrier(mrb, (struct RBasic*)a); |
mzta | 0:158c61bb030f | 157 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 158 | } |
mzta | 0:158c61bb030f | 159 | |
mzta | 0:158c61bb030f | 160 | static void |
mzta | 0:158c61bb030f | 161 | ary_make_shared(mrb_state *mrb, struct RArray *a) |
mzta | 0:158c61bb030f | 162 | { |
mzta | 0:158c61bb030f | 163 | if (!ARY_SHARED_P(a)) { |
mzta | 0:158c61bb030f | 164 | mrb_shared_array *shared = (mrb_shared_array *)mrb_malloc(mrb, sizeof(mrb_shared_array)); |
mzta | 0:158c61bb030f | 165 | |
mzta | 0:158c61bb030f | 166 | shared->refcnt = 1; |
mzta | 0:158c61bb030f | 167 | if (a->aux.capa > a->len) { |
mzta | 0:158c61bb030f | 168 | a->ptr = shared->ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*a->len+1); |
mzta | 0:158c61bb030f | 169 | } |
mzta | 0:158c61bb030f | 170 | else { |
mzta | 0:158c61bb030f | 171 | shared->ptr = a->ptr; |
mzta | 0:158c61bb030f | 172 | } |
mzta | 0:158c61bb030f | 173 | shared->len = a->len; |
mzta | 0:158c61bb030f | 174 | a->aux.shared = shared; |
mzta | 0:158c61bb030f | 175 | ARY_SET_SHARED_FLAG(a); |
mzta | 0:158c61bb030f | 176 | } |
mzta | 0:158c61bb030f | 177 | } |
mzta | 0:158c61bb030f | 178 | |
mzta | 0:158c61bb030f | 179 | static void |
mzta | 0:158c61bb030f | 180 | ary_expand_capa(mrb_state *mrb, struct RArray *a, mrb_int len) |
mzta | 0:158c61bb030f | 181 | { |
mzta | 0:158c61bb030f | 182 | mrb_int capa = a->aux.capa; |
mzta | 0:158c61bb030f | 183 | |
mzta | 0:158c61bb030f | 184 | if (len > ARY_MAX_SIZE) { |
mzta | 0:158c61bb030f | 185 | mrb_raise(mrb, E_ARGUMENT_ERROR, "array size too big"); |
mzta | 0:158c61bb030f | 186 | } |
mzta | 0:158c61bb030f | 187 | |
mzta | 0:158c61bb030f | 188 | if (capa == 0) { |
mzta | 0:158c61bb030f | 189 | capa = ARY_DEFAULT_LEN; |
mzta | 0:158c61bb030f | 190 | } |
mzta | 0:158c61bb030f | 191 | while (capa < len) { |
mzta | 0:158c61bb030f | 192 | capa *= 2; |
mzta | 0:158c61bb030f | 193 | } |
mzta | 0:158c61bb030f | 194 | |
mzta | 0:158c61bb030f | 195 | if (capa > ARY_MAX_SIZE) capa = ARY_MAX_SIZE; /* len <= capa <= ARY_MAX_SIZE */ |
mzta | 0:158c61bb030f | 196 | |
mzta | 0:158c61bb030f | 197 | if (capa > a->aux.capa) { |
mzta | 0:158c61bb030f | 198 | mrb_value *expanded_ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa); |
mzta | 0:158c61bb030f | 199 | |
mzta | 0:158c61bb030f | 200 | a->aux.capa = capa; |
mzta | 0:158c61bb030f | 201 | a->ptr = expanded_ptr; |
mzta | 0:158c61bb030f | 202 | } |
mzta | 0:158c61bb030f | 203 | } |
mzta | 0:158c61bb030f | 204 | |
mzta | 0:158c61bb030f | 205 | static void |
mzta | 0:158c61bb030f | 206 | ary_shrink_capa(mrb_state *mrb, struct RArray *a) |
mzta | 0:158c61bb030f | 207 | { |
mzta | 0:158c61bb030f | 208 | mrb_int capa = a->aux.capa; |
mzta | 0:158c61bb030f | 209 | |
mzta | 0:158c61bb030f | 210 | if (capa < ARY_DEFAULT_LEN * 2) return; |
mzta | 0:158c61bb030f | 211 | if (capa <= a->len * ARY_SHRINK_RATIO) return; |
mzta | 0:158c61bb030f | 212 | |
mzta | 0:158c61bb030f | 213 | do { |
mzta | 0:158c61bb030f | 214 | capa /= 2; |
mzta | 0:158c61bb030f | 215 | if (capa < ARY_DEFAULT_LEN) { |
mzta | 0:158c61bb030f | 216 | capa = ARY_DEFAULT_LEN; |
mzta | 0:158c61bb030f | 217 | break; |
mzta | 0:158c61bb030f | 218 | } |
mzta | 0:158c61bb030f | 219 | } while (capa > a->len * ARY_SHRINK_RATIO); |
mzta | 0:158c61bb030f | 220 | |
mzta | 0:158c61bb030f | 221 | if (capa > a->len && capa < a->aux.capa) { |
mzta | 0:158c61bb030f | 222 | a->aux.capa = capa; |
mzta | 0:158c61bb030f | 223 | a->ptr = (mrb_value *)mrb_realloc(mrb, a->ptr, sizeof(mrb_value)*capa); |
mzta | 0:158c61bb030f | 224 | } |
mzta | 0:158c61bb030f | 225 | } |
mzta | 0:158c61bb030f | 226 | |
mzta | 0:158c61bb030f | 227 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 228 | mrb_ary_resize(mrb_state *mrb, mrb_value ary, mrb_int new_len) |
mzta | 0:158c61bb030f | 229 | { |
mzta | 0:158c61bb030f | 230 | mrb_int old_len; |
mzta | 0:158c61bb030f | 231 | struct RArray *a = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 232 | |
mzta | 0:158c61bb030f | 233 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 234 | old_len = RARRAY_LEN(ary); |
mzta | 0:158c61bb030f | 235 | if (old_len != new_len) { |
mzta | 0:158c61bb030f | 236 | a->len = new_len; |
mzta | 0:158c61bb030f | 237 | if (new_len < old_len) { |
mzta | 0:158c61bb030f | 238 | ary_shrink_capa(mrb, a); |
mzta | 0:158c61bb030f | 239 | } |
mzta | 0:158c61bb030f | 240 | else { |
mzta | 0:158c61bb030f | 241 | ary_expand_capa(mrb, a, new_len); |
mzta | 0:158c61bb030f | 242 | ary_fill_with_nil(a->ptr + old_len, new_len - old_len); |
mzta | 0:158c61bb030f | 243 | } |
mzta | 0:158c61bb030f | 244 | } |
mzta | 0:158c61bb030f | 245 | |
mzta | 0:158c61bb030f | 246 | return ary; |
mzta | 0:158c61bb030f | 247 | } |
mzta | 0:158c61bb030f | 248 | |
mzta | 0:158c61bb030f | 249 | static mrb_value |
mzta | 0:158c61bb030f | 250 | mrb_ary_s_create(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 251 | { |
mzta | 0:158c61bb030f | 252 | mrb_value *vals; |
mzta | 0:158c61bb030f | 253 | mrb_int len; |
mzta | 0:158c61bb030f | 254 | |
mzta | 0:158c61bb030f | 255 | mrb_get_args(mrb, "*", &vals, &len); |
mzta | 0:158c61bb030f | 256 | |
mzta | 0:158c61bb030f | 257 | return mrb_ary_new_from_values(mrb, len, vals); |
mzta | 0:158c61bb030f | 258 | } |
mzta | 0:158c61bb030f | 259 | |
mzta | 0:158c61bb030f | 260 | static void |
mzta | 0:158c61bb030f | 261 | ary_concat(mrb_state *mrb, struct RArray *a, mrb_value *ptr, mrb_int blen) |
mzta | 0:158c61bb030f | 262 | { |
mzta | 0:158c61bb030f | 263 | mrb_int len = a->len + blen; |
mzta | 0:158c61bb030f | 264 | |
mzta | 0:158c61bb030f | 265 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 266 | if (a->aux.capa < len) ary_expand_capa(mrb, a, len); |
mzta | 0:158c61bb030f | 267 | array_copy(a->ptr+a->len, ptr, blen); |
mzta | 0:158c61bb030f | 268 | mrb_write_barrier(mrb, (struct RBasic*)a); |
mzta | 0:158c61bb030f | 269 | a->len = len; |
mzta | 0:158c61bb030f | 270 | } |
mzta | 0:158c61bb030f | 271 | |
mzta | 0:158c61bb030f | 272 | MRB_API void |
mzta | 0:158c61bb030f | 273 | mrb_ary_concat(mrb_state *mrb, mrb_value self, mrb_value other) |
mzta | 0:158c61bb030f | 274 | { |
mzta | 0:158c61bb030f | 275 | struct RArray *a2 = mrb_ary_ptr(other); |
mzta | 0:158c61bb030f | 276 | |
mzta | 0:158c61bb030f | 277 | ary_concat(mrb, mrb_ary_ptr(self), a2->ptr, a2->len); |
mzta | 0:158c61bb030f | 278 | } |
mzta | 0:158c61bb030f | 279 | |
mzta | 0:158c61bb030f | 280 | static mrb_value |
mzta | 0:158c61bb030f | 281 | mrb_ary_concat_m(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 282 | { |
mzta | 0:158c61bb030f | 283 | mrb_value *ptr; |
mzta | 0:158c61bb030f | 284 | mrb_int blen; |
mzta | 0:158c61bb030f | 285 | |
mzta | 0:158c61bb030f | 286 | mrb_get_args(mrb, "a", &ptr, &blen); |
mzta | 0:158c61bb030f | 287 | ary_concat(mrb, mrb_ary_ptr(self), ptr, blen); |
mzta | 0:158c61bb030f | 288 | return self; |
mzta | 0:158c61bb030f | 289 | } |
mzta | 0:158c61bb030f | 290 | |
mzta | 0:158c61bb030f | 291 | static mrb_value |
mzta | 0:158c61bb030f | 292 | mrb_ary_plus(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 293 | { |
mzta | 0:158c61bb030f | 294 | struct RArray *a1 = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 295 | struct RArray *a2; |
mzta | 0:158c61bb030f | 296 | mrb_value ary; |
mzta | 0:158c61bb030f | 297 | mrb_value *ptr; |
mzta | 0:158c61bb030f | 298 | mrb_int blen; |
mzta | 0:158c61bb030f | 299 | |
mzta | 0:158c61bb030f | 300 | mrb_get_args(mrb, "a", &ptr, &blen); |
mzta | 0:158c61bb030f | 301 | ary = mrb_ary_new_capa(mrb, a1->len + blen); |
mzta | 0:158c61bb030f | 302 | a2 = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 303 | array_copy(a2->ptr, a1->ptr, a1->len); |
mzta | 0:158c61bb030f | 304 | array_copy(a2->ptr + a1->len, ptr, blen); |
mzta | 0:158c61bb030f | 305 | a2->len = a1->len + blen; |
mzta | 0:158c61bb030f | 306 | |
mzta | 0:158c61bb030f | 307 | return ary; |
mzta | 0:158c61bb030f | 308 | } |
mzta | 0:158c61bb030f | 309 | |
mzta | 0:158c61bb030f | 310 | static void |
mzta | 0:158c61bb030f | 311 | ary_replace(mrb_state *mrb, struct RArray *a, mrb_value *argv, mrb_int len) |
mzta | 0:158c61bb030f | 312 | { |
mzta | 0:158c61bb030f | 313 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 314 | if (a->aux.capa < len) |
mzta | 0:158c61bb030f | 315 | ary_expand_capa(mrb, a, len); |
mzta | 0:158c61bb030f | 316 | array_copy(a->ptr, argv, len); |
mzta | 0:158c61bb030f | 317 | mrb_write_barrier(mrb, (struct RBasic*)a); |
mzta | 0:158c61bb030f | 318 | a->len = len; |
mzta | 0:158c61bb030f | 319 | } |
mzta | 0:158c61bb030f | 320 | |
mzta | 0:158c61bb030f | 321 | MRB_API void |
mzta | 0:158c61bb030f | 322 | mrb_ary_replace(mrb_state *mrb, mrb_value self, mrb_value other) |
mzta | 0:158c61bb030f | 323 | { |
mzta | 0:158c61bb030f | 324 | struct RArray *a2 = mrb_ary_ptr(other); |
mzta | 0:158c61bb030f | 325 | |
mzta | 0:158c61bb030f | 326 | ary_replace(mrb, mrb_ary_ptr(self), a2->ptr, a2->len); |
mzta | 0:158c61bb030f | 327 | } |
mzta | 0:158c61bb030f | 328 | |
mzta | 0:158c61bb030f | 329 | static mrb_value |
mzta | 0:158c61bb030f | 330 | mrb_ary_replace_m(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 331 | { |
mzta | 0:158c61bb030f | 332 | mrb_value other; |
mzta | 0:158c61bb030f | 333 | |
mzta | 0:158c61bb030f | 334 | mrb_get_args(mrb, "A", &other); |
mzta | 0:158c61bb030f | 335 | mrb_ary_replace(mrb, self, other); |
mzta | 0:158c61bb030f | 336 | |
mzta | 0:158c61bb030f | 337 | return self; |
mzta | 0:158c61bb030f | 338 | } |
mzta | 0:158c61bb030f | 339 | |
mzta | 0:158c61bb030f | 340 | static mrb_value |
mzta | 0:158c61bb030f | 341 | mrb_ary_times(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 342 | { |
mzta | 0:158c61bb030f | 343 | struct RArray *a1 = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 344 | struct RArray *a2; |
mzta | 0:158c61bb030f | 345 | mrb_value ary; |
mzta | 0:158c61bb030f | 346 | mrb_value *ptr; |
mzta | 0:158c61bb030f | 347 | mrb_int times; |
mzta | 0:158c61bb030f | 348 | |
mzta | 0:158c61bb030f | 349 | mrb_get_args(mrb, "i", ×); |
mzta | 0:158c61bb030f | 350 | if (times < 0) { |
mzta | 0:158c61bb030f | 351 | mrb_raise(mrb, E_ARGUMENT_ERROR, "negative argument"); |
mzta | 0:158c61bb030f | 352 | } |
mzta | 0:158c61bb030f | 353 | if (times == 0) return mrb_ary_new(mrb); |
mzta | 0:158c61bb030f | 354 | |
mzta | 0:158c61bb030f | 355 | ary = mrb_ary_new_capa(mrb, a1->len * times); |
mzta | 0:158c61bb030f | 356 | a2 = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 357 | ptr = a2->ptr; |
mzta | 0:158c61bb030f | 358 | while (times--) { |
mzta | 0:158c61bb030f | 359 | array_copy(ptr, a1->ptr, a1->len); |
mzta | 0:158c61bb030f | 360 | ptr += a1->len; |
mzta | 0:158c61bb030f | 361 | a2->len += a1->len; |
mzta | 0:158c61bb030f | 362 | } |
mzta | 0:158c61bb030f | 363 | |
mzta | 0:158c61bb030f | 364 | return ary; |
mzta | 0:158c61bb030f | 365 | } |
mzta | 0:158c61bb030f | 366 | |
mzta | 0:158c61bb030f | 367 | static mrb_value |
mzta | 0:158c61bb030f | 368 | mrb_ary_reverse_bang(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 369 | { |
mzta | 0:158c61bb030f | 370 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 371 | |
mzta | 0:158c61bb030f | 372 | if (a->len > 1) { |
mzta | 0:158c61bb030f | 373 | mrb_value *p1, *p2; |
mzta | 0:158c61bb030f | 374 | |
mzta | 0:158c61bb030f | 375 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 376 | p1 = a->ptr; |
mzta | 0:158c61bb030f | 377 | p2 = a->ptr + a->len - 1; |
mzta | 0:158c61bb030f | 378 | |
mzta | 0:158c61bb030f | 379 | while (p1 < p2) { |
mzta | 0:158c61bb030f | 380 | mrb_value tmp = *p1; |
mzta | 0:158c61bb030f | 381 | *p1++ = *p2; |
mzta | 0:158c61bb030f | 382 | *p2-- = tmp; |
mzta | 0:158c61bb030f | 383 | } |
mzta | 0:158c61bb030f | 384 | } |
mzta | 0:158c61bb030f | 385 | return self; |
mzta | 0:158c61bb030f | 386 | } |
mzta | 0:158c61bb030f | 387 | |
mzta | 0:158c61bb030f | 388 | static mrb_value |
mzta | 0:158c61bb030f | 389 | mrb_ary_reverse(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 390 | { |
mzta | 0:158c61bb030f | 391 | struct RArray *a = mrb_ary_ptr(self), *b; |
mzta | 0:158c61bb030f | 392 | mrb_value ary; |
mzta | 0:158c61bb030f | 393 | |
mzta | 0:158c61bb030f | 394 | ary = mrb_ary_new_capa(mrb, a->len); |
mzta | 0:158c61bb030f | 395 | b = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 396 | if (a->len > 0) { |
mzta | 0:158c61bb030f | 397 | mrb_value *p1, *p2, *e; |
mzta | 0:158c61bb030f | 398 | |
mzta | 0:158c61bb030f | 399 | p1 = a->ptr; |
mzta | 0:158c61bb030f | 400 | e = p1 + a->len; |
mzta | 0:158c61bb030f | 401 | p2 = b->ptr + a->len - 1; |
mzta | 0:158c61bb030f | 402 | while (p1 < e) { |
mzta | 0:158c61bb030f | 403 | *p2-- = *p1++; |
mzta | 0:158c61bb030f | 404 | } |
mzta | 0:158c61bb030f | 405 | b->len = a->len; |
mzta | 0:158c61bb030f | 406 | } |
mzta | 0:158c61bb030f | 407 | return ary; |
mzta | 0:158c61bb030f | 408 | } |
mzta | 0:158c61bb030f | 409 | |
mzta | 0:158c61bb030f | 410 | MRB_API void |
mzta | 0:158c61bb030f | 411 | mrb_ary_push(mrb_state *mrb, mrb_value ary, mrb_value elem) |
mzta | 0:158c61bb030f | 412 | { |
mzta | 0:158c61bb030f | 413 | struct RArray *a = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 414 | |
mzta | 0:158c61bb030f | 415 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 416 | if (a->len == a->aux.capa) |
mzta | 0:158c61bb030f | 417 | ary_expand_capa(mrb, a, a->len + 1); |
mzta | 0:158c61bb030f | 418 | a->ptr[a->len++] = elem; |
mzta | 0:158c61bb030f | 419 | mrb_field_write_barrier_value(mrb, (struct RBasic*)a, elem); |
mzta | 0:158c61bb030f | 420 | } |
mzta | 0:158c61bb030f | 421 | |
mzta | 0:158c61bb030f | 422 | static mrb_value |
mzta | 0:158c61bb030f | 423 | mrb_ary_push_m(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 424 | { |
mzta | 0:158c61bb030f | 425 | mrb_value *argv; |
mzta | 0:158c61bb030f | 426 | mrb_int len; |
mzta | 0:158c61bb030f | 427 | |
mzta | 0:158c61bb030f | 428 | mrb_get_args(mrb, "*", &argv, &len); |
mzta | 0:158c61bb030f | 429 | while (len--) { |
mzta | 0:158c61bb030f | 430 | mrb_ary_push(mrb, self, *argv++); |
mzta | 0:158c61bb030f | 431 | } |
mzta | 0:158c61bb030f | 432 | |
mzta | 0:158c61bb030f | 433 | return self; |
mzta | 0:158c61bb030f | 434 | } |
mzta | 0:158c61bb030f | 435 | |
mzta | 0:158c61bb030f | 436 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 437 | mrb_ary_pop(mrb_state *mrb, mrb_value ary) |
mzta | 0:158c61bb030f | 438 | { |
mzta | 0:158c61bb030f | 439 | struct RArray *a = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 440 | |
mzta | 0:158c61bb030f | 441 | if (a->len == 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 442 | return a->ptr[--a->len]; |
mzta | 0:158c61bb030f | 443 | } |
mzta | 0:158c61bb030f | 444 | |
mzta | 0:158c61bb030f | 445 | #define ARY_SHIFT_SHARED_MIN 10 |
mzta | 0:158c61bb030f | 446 | |
mzta | 0:158c61bb030f | 447 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 448 | mrb_ary_shift(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 449 | { |
mzta | 0:158c61bb030f | 450 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 451 | mrb_value val; |
mzta | 0:158c61bb030f | 452 | |
mzta | 0:158c61bb030f | 453 | if (a->len == 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 454 | if (ARY_SHARED_P(a)) { |
mzta | 0:158c61bb030f | 455 | L_SHIFT: |
mzta | 0:158c61bb030f | 456 | val = a->ptr[0]; |
mzta | 0:158c61bb030f | 457 | a->ptr++; |
mzta | 0:158c61bb030f | 458 | a->len--; |
mzta | 0:158c61bb030f | 459 | return val; |
mzta | 0:158c61bb030f | 460 | } |
mzta | 0:158c61bb030f | 461 | if (a->len > ARY_SHIFT_SHARED_MIN) { |
mzta | 0:158c61bb030f | 462 | ary_make_shared(mrb, a); |
mzta | 0:158c61bb030f | 463 | goto L_SHIFT; |
mzta | 0:158c61bb030f | 464 | } |
mzta | 0:158c61bb030f | 465 | else { |
mzta | 0:158c61bb030f | 466 | mrb_value *ptr = a->ptr; |
mzta | 0:158c61bb030f | 467 | mrb_int size = a->len; |
mzta | 0:158c61bb030f | 468 | |
mzta | 0:158c61bb030f | 469 | val = *ptr; |
mzta | 0:158c61bb030f | 470 | while (--size) { |
mzta | 0:158c61bb030f | 471 | *ptr = *(ptr+1); |
mzta | 0:158c61bb030f | 472 | ++ptr; |
mzta | 0:158c61bb030f | 473 | } |
mzta | 0:158c61bb030f | 474 | --a->len; |
mzta | 0:158c61bb030f | 475 | } |
mzta | 0:158c61bb030f | 476 | return val; |
mzta | 0:158c61bb030f | 477 | } |
mzta | 0:158c61bb030f | 478 | |
mzta | 0:158c61bb030f | 479 | /* self = [1,2,3] |
mzta | 0:158c61bb030f | 480 | item = 0 |
mzta | 0:158c61bb030f | 481 | self.unshift item |
mzta | 0:158c61bb030f | 482 | p self #=> [0, 1, 2, 3] */ |
mzta | 0:158c61bb030f | 483 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 484 | mrb_ary_unshift(mrb_state *mrb, mrb_value self, mrb_value item) |
mzta | 0:158c61bb030f | 485 | { |
mzta | 0:158c61bb030f | 486 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 487 | |
mzta | 0:158c61bb030f | 488 | if (ARY_SHARED_P(a) |
mzta | 0:158c61bb030f | 489 | && a->aux.shared->refcnt == 1 /* shared only referenced from this array */ |
mzta | 0:158c61bb030f | 490 | && a->ptr - a->aux.shared->ptr >= 1) /* there's room for unshifted item */ { |
mzta | 0:158c61bb030f | 491 | a->ptr--; |
mzta | 0:158c61bb030f | 492 | a->ptr[0] = item; |
mzta | 0:158c61bb030f | 493 | } |
mzta | 0:158c61bb030f | 494 | else { |
mzta | 0:158c61bb030f | 495 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 496 | if (a->aux.capa < a->len + 1) |
mzta | 0:158c61bb030f | 497 | ary_expand_capa(mrb, a, a->len + 1); |
mzta | 0:158c61bb030f | 498 | value_move(a->ptr + 1, a->ptr, a->len); |
mzta | 0:158c61bb030f | 499 | a->ptr[0] = item; |
mzta | 0:158c61bb030f | 500 | } |
mzta | 0:158c61bb030f | 501 | a->len++; |
mzta | 0:158c61bb030f | 502 | mrb_field_write_barrier_value(mrb, (struct RBasic*)a, item); |
mzta | 0:158c61bb030f | 503 | |
mzta | 0:158c61bb030f | 504 | return self; |
mzta | 0:158c61bb030f | 505 | } |
mzta | 0:158c61bb030f | 506 | |
mzta | 0:158c61bb030f | 507 | static mrb_value |
mzta | 0:158c61bb030f | 508 | mrb_ary_unshift_m(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 509 | { |
mzta | 0:158c61bb030f | 510 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 511 | mrb_value *vals; |
mzta | 0:158c61bb030f | 512 | mrb_int len; |
mzta | 0:158c61bb030f | 513 | |
mzta | 0:158c61bb030f | 514 | mrb_get_args(mrb, "*", &vals, &len); |
mzta | 0:158c61bb030f | 515 | if (ARY_SHARED_P(a) |
mzta | 0:158c61bb030f | 516 | && a->aux.shared->refcnt == 1 /* shared only referenced from this array */ |
mzta | 0:158c61bb030f | 517 | && a->ptr - a->aux.shared->ptr >= len) /* there's room for unshifted item */ { |
mzta | 0:158c61bb030f | 518 | a->ptr -= len; |
mzta | 0:158c61bb030f | 519 | } |
mzta | 0:158c61bb030f | 520 | else { |
mzta | 0:158c61bb030f | 521 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 522 | if (len == 0) return self; |
mzta | 0:158c61bb030f | 523 | if (a->aux.capa < a->len + len) |
mzta | 0:158c61bb030f | 524 | ary_expand_capa(mrb, a, a->len + len); |
mzta | 0:158c61bb030f | 525 | value_move(a->ptr + len, a->ptr, a->len); |
mzta | 0:158c61bb030f | 526 | } |
mzta | 0:158c61bb030f | 527 | array_copy(a->ptr, vals, len); |
mzta | 0:158c61bb030f | 528 | a->len += len; |
mzta | 0:158c61bb030f | 529 | while (len--) { |
mzta | 0:158c61bb030f | 530 | mrb_field_write_barrier_value(mrb, (struct RBasic*)a, vals[len]); |
mzta | 0:158c61bb030f | 531 | } |
mzta | 0:158c61bb030f | 532 | |
mzta | 0:158c61bb030f | 533 | return self; |
mzta | 0:158c61bb030f | 534 | } |
mzta | 0:158c61bb030f | 535 | |
mzta | 0:158c61bb030f | 536 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 537 | mrb_ary_ref(mrb_state *mrb, mrb_value ary, mrb_int n) |
mzta | 0:158c61bb030f | 538 | { |
mzta | 0:158c61bb030f | 539 | struct RArray *a = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 540 | |
mzta | 0:158c61bb030f | 541 | /* range check */ |
mzta | 0:158c61bb030f | 542 | if (n < 0) n += a->len; |
mzta | 0:158c61bb030f | 543 | if (n < 0 || a->len <= n) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 544 | |
mzta | 0:158c61bb030f | 545 | return a->ptr[n]; |
mzta | 0:158c61bb030f | 546 | } |
mzta | 0:158c61bb030f | 547 | |
mzta | 0:158c61bb030f | 548 | MRB_API void |
mzta | 0:158c61bb030f | 549 | mrb_ary_set(mrb_state *mrb, mrb_value ary, mrb_int n, mrb_value val) |
mzta | 0:158c61bb030f | 550 | { |
mzta | 0:158c61bb030f | 551 | struct RArray *a = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 552 | |
mzta | 0:158c61bb030f | 553 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 554 | /* range check */ |
mzta | 0:158c61bb030f | 555 | if (n < 0) { |
mzta | 0:158c61bb030f | 556 | n += a->len; |
mzta | 0:158c61bb030f | 557 | if (n < 0) { |
mzta | 0:158c61bb030f | 558 | mrb_raisef(mrb, E_INDEX_ERROR, "index %S out of array", mrb_fixnum_value(n - a->len)); |
mzta | 0:158c61bb030f | 559 | } |
mzta | 0:158c61bb030f | 560 | } |
mzta | 0:158c61bb030f | 561 | if (a->len <= n) { |
mzta | 0:158c61bb030f | 562 | if (a->aux.capa <= n) |
mzta | 0:158c61bb030f | 563 | ary_expand_capa(mrb, a, n + 1); |
mzta | 0:158c61bb030f | 564 | ary_fill_with_nil(a->ptr + a->len, n + 1 - a->len); |
mzta | 0:158c61bb030f | 565 | a->len = n + 1; |
mzta | 0:158c61bb030f | 566 | } |
mzta | 0:158c61bb030f | 567 | |
mzta | 0:158c61bb030f | 568 | a->ptr[n] = val; |
mzta | 0:158c61bb030f | 569 | mrb_field_write_barrier_value(mrb, (struct RBasic*)a, val); |
mzta | 0:158c61bb030f | 570 | } |
mzta | 0:158c61bb030f | 571 | |
mzta | 0:158c61bb030f | 572 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 573 | mrb_ary_splice(mrb_state *mrb, mrb_value ary, mrb_int head, mrb_int len, mrb_value rpl) |
mzta | 0:158c61bb030f | 574 | { |
mzta | 0:158c61bb030f | 575 | struct RArray *a = mrb_ary_ptr(ary); |
mzta | 0:158c61bb030f | 576 | mrb_int tail, size; |
mzta | 0:158c61bb030f | 577 | const mrb_value *argv; |
mzta | 0:158c61bb030f | 578 | mrb_int i, argc; |
mzta | 0:158c61bb030f | 579 | |
mzta | 0:158c61bb030f | 580 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 581 | |
mzta | 0:158c61bb030f | 582 | /* len check */ |
mzta | 0:158c61bb030f | 583 | if (len < 0) mrb_raisef(mrb, E_INDEX_ERROR, "negative length (%S)", mrb_fixnum_value(len)); |
mzta | 0:158c61bb030f | 584 | |
mzta | 0:158c61bb030f | 585 | /* range check */ |
mzta | 0:158c61bb030f | 586 | if (head < 0) { |
mzta | 0:158c61bb030f | 587 | head += a->len; |
mzta | 0:158c61bb030f | 588 | if (head < 0) { |
mzta | 0:158c61bb030f | 589 | mrb_raise(mrb, E_INDEX_ERROR, "index is out of array"); |
mzta | 0:158c61bb030f | 590 | } |
mzta | 0:158c61bb030f | 591 | } |
mzta | 0:158c61bb030f | 592 | if (a->len < len || a->len < head + len) { |
mzta | 0:158c61bb030f | 593 | len = a->len - head; |
mzta | 0:158c61bb030f | 594 | } |
mzta | 0:158c61bb030f | 595 | tail = head + len; |
mzta | 0:158c61bb030f | 596 | |
mzta | 0:158c61bb030f | 597 | /* size check */ |
mzta | 0:158c61bb030f | 598 | if (mrb_array_p(rpl)) { |
mzta | 0:158c61bb030f | 599 | argc = RARRAY_LEN(rpl); |
mzta | 0:158c61bb030f | 600 | argv = RARRAY_PTR(rpl); |
mzta | 0:158c61bb030f | 601 | } |
mzta | 0:158c61bb030f | 602 | else { |
mzta | 0:158c61bb030f | 603 | argc = 1; |
mzta | 0:158c61bb030f | 604 | argv = &rpl; |
mzta | 0:158c61bb030f | 605 | } |
mzta | 0:158c61bb030f | 606 | size = head + argc; |
mzta | 0:158c61bb030f | 607 | |
mzta | 0:158c61bb030f | 608 | if (tail < a->len) size += a->len - tail; |
mzta | 0:158c61bb030f | 609 | if (size > a->aux.capa) |
mzta | 0:158c61bb030f | 610 | ary_expand_capa(mrb, a, size); |
mzta | 0:158c61bb030f | 611 | |
mzta | 0:158c61bb030f | 612 | if (head > a->len) { |
mzta | 0:158c61bb030f | 613 | ary_fill_with_nil(a->ptr + a->len, head - a->len); |
mzta | 0:158c61bb030f | 614 | } |
mzta | 0:158c61bb030f | 615 | else if (head < a->len) { |
mzta | 0:158c61bb030f | 616 | value_move(a->ptr + head + argc, a->ptr + tail, a->len - tail); |
mzta | 0:158c61bb030f | 617 | } |
mzta | 0:158c61bb030f | 618 | |
mzta | 0:158c61bb030f | 619 | for (i = 0; i < argc; i++) { |
mzta | 0:158c61bb030f | 620 | *(a->ptr + head + i) = *(argv + i); |
mzta | 0:158c61bb030f | 621 | mrb_field_write_barrier_value(mrb, (struct RBasic*)a, argv[i]); |
mzta | 0:158c61bb030f | 622 | } |
mzta | 0:158c61bb030f | 623 | |
mzta | 0:158c61bb030f | 624 | a->len = size; |
mzta | 0:158c61bb030f | 625 | |
mzta | 0:158c61bb030f | 626 | return ary; |
mzta | 0:158c61bb030f | 627 | } |
mzta | 0:158c61bb030f | 628 | |
mzta | 0:158c61bb030f | 629 | void |
mzta | 0:158c61bb030f | 630 | mrb_ary_decref(mrb_state *mrb, mrb_shared_array *shared) |
mzta | 0:158c61bb030f | 631 | { |
mzta | 0:158c61bb030f | 632 | shared->refcnt--; |
mzta | 0:158c61bb030f | 633 | if (shared->refcnt == 0) { |
mzta | 0:158c61bb030f | 634 | mrb_free(mrb, shared->ptr); |
mzta | 0:158c61bb030f | 635 | mrb_free(mrb, shared); |
mzta | 0:158c61bb030f | 636 | } |
mzta | 0:158c61bb030f | 637 | } |
mzta | 0:158c61bb030f | 638 | |
mzta | 0:158c61bb030f | 639 | static mrb_value |
mzta | 0:158c61bb030f | 640 | ary_subseq(mrb_state *mrb, struct RArray *a, mrb_int beg, mrb_int len) |
mzta | 0:158c61bb030f | 641 | { |
mzta | 0:158c61bb030f | 642 | struct RArray *b; |
mzta | 0:158c61bb030f | 643 | |
mzta | 0:158c61bb030f | 644 | ary_make_shared(mrb, a); |
mzta | 0:158c61bb030f | 645 | b = (struct RArray*)mrb_obj_alloc(mrb, MRB_TT_ARRAY, mrb->array_class); |
mzta | 0:158c61bb030f | 646 | b->ptr = a->ptr + beg; |
mzta | 0:158c61bb030f | 647 | b->len = len; |
mzta | 0:158c61bb030f | 648 | b->aux.shared = a->aux.shared; |
mzta | 0:158c61bb030f | 649 | b->aux.shared->refcnt++; |
mzta | 0:158c61bb030f | 650 | ARY_SET_SHARED_FLAG(b); |
mzta | 0:158c61bb030f | 651 | |
mzta | 0:158c61bb030f | 652 | return mrb_obj_value(b); |
mzta | 0:158c61bb030f | 653 | } |
mzta | 0:158c61bb030f | 654 | |
mzta | 0:158c61bb030f | 655 | static mrb_int |
mzta | 0:158c61bb030f | 656 | aget_index(mrb_state *mrb, mrb_value index) |
mzta | 0:158c61bb030f | 657 | { |
mzta | 0:158c61bb030f | 658 | if (mrb_fixnum_p(index)) { |
mzta | 0:158c61bb030f | 659 | return mrb_fixnum(index); |
mzta | 0:158c61bb030f | 660 | } |
mzta | 0:158c61bb030f | 661 | else if (mrb_float_p(index)) { |
mzta | 0:158c61bb030f | 662 | return (mrb_int)mrb_float(index); |
mzta | 0:158c61bb030f | 663 | } |
mzta | 0:158c61bb030f | 664 | else { |
mzta | 0:158c61bb030f | 665 | mrb_int i, argc; |
mzta | 0:158c61bb030f | 666 | mrb_value *argv; |
mzta | 0:158c61bb030f | 667 | |
mzta | 0:158c61bb030f | 668 | mrb_get_args(mrb, "i*", &i, &argv, &argc); |
mzta | 0:158c61bb030f | 669 | return i; |
mzta | 0:158c61bb030f | 670 | } |
mzta | 0:158c61bb030f | 671 | } |
mzta | 0:158c61bb030f | 672 | |
mzta | 0:158c61bb030f | 673 | /* |
mzta | 0:158c61bb030f | 674 | * call-seq: |
mzta | 0:158c61bb030f | 675 | * ary[index] -> obj or nil |
mzta | 0:158c61bb030f | 676 | * ary[start, length] -> new_ary or nil |
mzta | 0:158c61bb030f | 677 | * ary[range] -> new_ary or nil |
mzta | 0:158c61bb030f | 678 | * ary.slice(index) -> obj or nil |
mzta | 0:158c61bb030f | 679 | * ary.slice(start, length) -> new_ary or nil |
mzta | 0:158c61bb030f | 680 | * ary.slice(range) -> new_ary or nil |
mzta | 0:158c61bb030f | 681 | * |
mzta | 0:158c61bb030f | 682 | * Element Reference --- Returns the element at +index+, or returns a |
mzta | 0:158c61bb030f | 683 | * subarray starting at the +start+ index and continuing for +length+ |
mzta | 0:158c61bb030f | 684 | * elements, or returns a subarray specified by +range+ of indices. |
mzta | 0:158c61bb030f | 685 | * |
mzta | 0:158c61bb030f | 686 | * Negative indices count backward from the end of the array (-1 is the last |
mzta | 0:158c61bb030f | 687 | * element). For +start+ and +range+ cases the starting index is just before |
mzta | 0:158c61bb030f | 688 | * an element. Additionally, an empty array is returned when the starting |
mzta | 0:158c61bb030f | 689 | * index for an element range is at the end of the array. |
mzta | 0:158c61bb030f | 690 | * |
mzta | 0:158c61bb030f | 691 | * Returns +nil+ if the index (or starting index) are out of range. |
mzta | 0:158c61bb030f | 692 | * |
mzta | 0:158c61bb030f | 693 | * a = [ "a", "b", "c", "d", "e" ] |
mzta | 0:158c61bb030f | 694 | * a[1] => "b" |
mzta | 0:158c61bb030f | 695 | * a[1,2] => ["b", "c"] |
mzta | 0:158c61bb030f | 696 | * a[1..-2] => ["b", "c", "d"] |
mzta | 0:158c61bb030f | 697 | * |
mzta | 0:158c61bb030f | 698 | */ |
mzta | 0:158c61bb030f | 699 | |
mzta | 0:158c61bb030f | 700 | static mrb_value |
mzta | 0:158c61bb030f | 701 | mrb_ary_aget(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 702 | { |
mzta | 0:158c61bb030f | 703 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 704 | mrb_int i, len; |
mzta | 0:158c61bb030f | 705 | mrb_value index; |
mzta | 0:158c61bb030f | 706 | |
mzta | 0:158c61bb030f | 707 | if (mrb_get_args(mrb, "o|i", &index, &len) == 1) { |
mzta | 0:158c61bb030f | 708 | switch (mrb_type(index)) { |
mzta | 0:158c61bb030f | 709 | /* a[n..m] */ |
mzta | 0:158c61bb030f | 710 | case MRB_TT_RANGE: |
mzta | 0:158c61bb030f | 711 | if (mrb_range_beg_len(mrb, index, &i, &len, a->len)) { |
mzta | 0:158c61bb030f | 712 | return ary_subseq(mrb, a, i, len); |
mzta | 0:158c61bb030f | 713 | } |
mzta | 0:158c61bb030f | 714 | else { |
mzta | 0:158c61bb030f | 715 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 716 | } |
mzta | 0:158c61bb030f | 717 | case MRB_TT_FIXNUM: |
mzta | 0:158c61bb030f | 718 | return mrb_ary_ref(mrb, self, mrb_fixnum(index)); |
mzta | 0:158c61bb030f | 719 | default: |
mzta | 0:158c61bb030f | 720 | return mrb_ary_ref(mrb, self, aget_index(mrb, index)); |
mzta | 0:158c61bb030f | 721 | } |
mzta | 0:158c61bb030f | 722 | } |
mzta | 0:158c61bb030f | 723 | |
mzta | 0:158c61bb030f | 724 | i = aget_index(mrb, index); |
mzta | 0:158c61bb030f | 725 | if (i < 0) i += a->len; |
mzta | 0:158c61bb030f | 726 | if (i < 0 || a->len < i) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 727 | if (len < 0) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 728 | if (a->len == i) return mrb_ary_new(mrb); |
mzta | 0:158c61bb030f | 729 | if (len > a->len - i) len = a->len - i; |
mzta | 0:158c61bb030f | 730 | |
mzta | 0:158c61bb030f | 731 | return ary_subseq(mrb, a, i, len); |
mzta | 0:158c61bb030f | 732 | } |
mzta | 0:158c61bb030f | 733 | |
mzta | 0:158c61bb030f | 734 | /* |
mzta | 0:158c61bb030f | 735 | * call-seq: |
mzta | 0:158c61bb030f | 736 | * ary[index] = obj -> obj |
mzta | 0:158c61bb030f | 737 | * ary[start, length] = obj or other_ary or nil -> obj or other_ary or nil |
mzta | 0:158c61bb030f | 738 | * ary[range] = obj or other_ary or nil -> obj or other_ary or nil |
mzta | 0:158c61bb030f | 739 | * |
mzta | 0:158c61bb030f | 740 | * Element Assignment --- Sets the element at +index+, or replaces a subarray |
mzta | 0:158c61bb030f | 741 | * from the +start+ index for +length+ elements, or replaces a subarray |
mzta | 0:158c61bb030f | 742 | * specified by the +range+ of indices. |
mzta | 0:158c61bb030f | 743 | * |
mzta | 0:158c61bb030f | 744 | * If indices are greater than the current capacity of the array, the array |
mzta | 0:158c61bb030f | 745 | * grows automatically. Elements are inserted into the array at +start+ if |
mzta | 0:158c61bb030f | 746 | * +length+ is zero. |
mzta | 0:158c61bb030f | 747 | * |
mzta | 0:158c61bb030f | 748 | * Negative indices will count backward from the end of the array. For |
mzta | 0:158c61bb030f | 749 | * +start+ and +range+ cases the starting index is just before an element. |
mzta | 0:158c61bb030f | 750 | * |
mzta | 0:158c61bb030f | 751 | * An IndexError is raised if a negative index points past the beginning of |
mzta | 0:158c61bb030f | 752 | * the array. |
mzta | 0:158c61bb030f | 753 | * |
mzta | 0:158c61bb030f | 754 | * See also Array#push, and Array#unshift. |
mzta | 0:158c61bb030f | 755 | * |
mzta | 0:158c61bb030f | 756 | * a = Array.new |
mzta | 0:158c61bb030f | 757 | * a[4] = "4"; #=> [nil, nil, nil, nil, "4"] |
mzta | 0:158c61bb030f | 758 | * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"] |
mzta | 0:158c61bb030f | 759 | * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"] |
mzta | 0:158c61bb030f | 760 | * a[0, 2] = "?" #=> ["?", 2, nil, "4"] |
mzta | 0:158c61bb030f | 761 | * a[0..2] = "A" #=> ["A", "4"] |
mzta | 0:158c61bb030f | 762 | * a[-1] = "Z" #=> ["A", "Z"] |
mzta | 0:158c61bb030f | 763 | * a[1..-1] = nil #=> ["A", nil] |
mzta | 0:158c61bb030f | 764 | * a[1..-1] = [] #=> ["A"] |
mzta | 0:158c61bb030f | 765 | * a[0, 0] = [ 1, 2 ] #=> [1, 2, "A"] |
mzta | 0:158c61bb030f | 766 | * a[3, 0] = "B" #=> [1, 2, "A", "B"] |
mzta | 0:158c61bb030f | 767 | */ |
mzta | 0:158c61bb030f | 768 | |
mzta | 0:158c61bb030f | 769 | static mrb_value |
mzta | 0:158c61bb030f | 770 | mrb_ary_aset(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 771 | { |
mzta | 0:158c61bb030f | 772 | mrb_value v1, v2, v3; |
mzta | 0:158c61bb030f | 773 | mrb_int i, len; |
mzta | 0:158c61bb030f | 774 | |
mzta | 0:158c61bb030f | 775 | if (mrb_get_args(mrb, "oo|o", &v1, &v2, &v3) == 2) { |
mzta | 0:158c61bb030f | 776 | switch (mrb_type(v1)) { |
mzta | 0:158c61bb030f | 777 | /* a[n..m] = v */ |
mzta | 0:158c61bb030f | 778 | case MRB_TT_RANGE: |
mzta | 0:158c61bb030f | 779 | if (mrb_range_beg_len(mrb, v1, &i, &len, RARRAY_LEN(self))) { |
mzta | 0:158c61bb030f | 780 | mrb_ary_splice(mrb, self, i, len, v2); |
mzta | 0:158c61bb030f | 781 | } |
mzta | 0:158c61bb030f | 782 | break; |
mzta | 0:158c61bb030f | 783 | /* a[n] = v */ |
mzta | 0:158c61bb030f | 784 | case MRB_TT_FIXNUM: |
mzta | 0:158c61bb030f | 785 | mrb_ary_set(mrb, self, mrb_fixnum(v1), v2); |
mzta | 0:158c61bb030f | 786 | break; |
mzta | 0:158c61bb030f | 787 | default: |
mzta | 0:158c61bb030f | 788 | mrb_ary_set(mrb, self, aget_index(mrb, v1), v2); |
mzta | 0:158c61bb030f | 789 | break; |
mzta | 0:158c61bb030f | 790 | } |
mzta | 0:158c61bb030f | 791 | return v2; |
mzta | 0:158c61bb030f | 792 | } |
mzta | 0:158c61bb030f | 793 | |
mzta | 0:158c61bb030f | 794 | /* a[n,m] = v */ |
mzta | 0:158c61bb030f | 795 | mrb_ary_splice(mrb, self, aget_index(mrb, v1), aget_index(mrb, v2), v3); |
mzta | 0:158c61bb030f | 796 | return v3; |
mzta | 0:158c61bb030f | 797 | } |
mzta | 0:158c61bb030f | 798 | |
mzta | 0:158c61bb030f | 799 | static mrb_value |
mzta | 0:158c61bb030f | 800 | mrb_ary_delete_at(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 801 | { |
mzta | 0:158c61bb030f | 802 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 803 | mrb_int index; |
mzta | 0:158c61bb030f | 804 | mrb_value val; |
mzta | 0:158c61bb030f | 805 | mrb_value *ptr; |
mzta | 0:158c61bb030f | 806 | mrb_int len; |
mzta | 0:158c61bb030f | 807 | |
mzta | 0:158c61bb030f | 808 | mrb_get_args(mrb, "i", &index); |
mzta | 0:158c61bb030f | 809 | if (index < 0) index += a->len; |
mzta | 0:158c61bb030f | 810 | if (index < 0 || a->len <= index) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 811 | |
mzta | 0:158c61bb030f | 812 | ary_modify(mrb, a); |
mzta | 0:158c61bb030f | 813 | val = a->ptr[index]; |
mzta | 0:158c61bb030f | 814 | |
mzta | 0:158c61bb030f | 815 | ptr = a->ptr + index; |
mzta | 0:158c61bb030f | 816 | len = a->len - index; |
mzta | 0:158c61bb030f | 817 | while (--len) { |
mzta | 0:158c61bb030f | 818 | *ptr = *(ptr+1); |
mzta | 0:158c61bb030f | 819 | ++ptr; |
mzta | 0:158c61bb030f | 820 | } |
mzta | 0:158c61bb030f | 821 | --a->len; |
mzta | 0:158c61bb030f | 822 | |
mzta | 0:158c61bb030f | 823 | ary_shrink_capa(mrb, a); |
mzta | 0:158c61bb030f | 824 | |
mzta | 0:158c61bb030f | 825 | return val; |
mzta | 0:158c61bb030f | 826 | } |
mzta | 0:158c61bb030f | 827 | |
mzta | 0:158c61bb030f | 828 | static mrb_value |
mzta | 0:158c61bb030f | 829 | mrb_ary_first(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 830 | { |
mzta | 0:158c61bb030f | 831 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 832 | mrb_int size; |
mzta | 0:158c61bb030f | 833 | |
mzta | 0:158c61bb030f | 834 | if (mrb_get_args(mrb, "|i", &size) == 0) { |
mzta | 0:158c61bb030f | 835 | return (a->len > 0)? a->ptr[0]: mrb_nil_value(); |
mzta | 0:158c61bb030f | 836 | } |
mzta | 0:158c61bb030f | 837 | if (size < 0) { |
mzta | 0:158c61bb030f | 838 | mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); |
mzta | 0:158c61bb030f | 839 | } |
mzta | 0:158c61bb030f | 840 | |
mzta | 0:158c61bb030f | 841 | if (size > a->len) size = a->len; |
mzta | 0:158c61bb030f | 842 | if (ARY_SHARED_P(a)) { |
mzta | 0:158c61bb030f | 843 | return ary_subseq(mrb, a, 0, size); |
mzta | 0:158c61bb030f | 844 | } |
mzta | 0:158c61bb030f | 845 | return mrb_ary_new_from_values(mrb, size, a->ptr); |
mzta | 0:158c61bb030f | 846 | } |
mzta | 0:158c61bb030f | 847 | |
mzta | 0:158c61bb030f | 848 | static mrb_value |
mzta | 0:158c61bb030f | 849 | mrb_ary_last(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 850 | { |
mzta | 0:158c61bb030f | 851 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 852 | mrb_int size; |
mzta | 0:158c61bb030f | 853 | |
mzta | 0:158c61bb030f | 854 | if (mrb_get_args(mrb, "|i", &size) == 0) |
mzta | 0:158c61bb030f | 855 | return (a->len > 0)? a->ptr[a->len - 1]: mrb_nil_value(); |
mzta | 0:158c61bb030f | 856 | |
mzta | 0:158c61bb030f | 857 | if (size < 0) { |
mzta | 0:158c61bb030f | 858 | mrb_raise(mrb, E_ARGUMENT_ERROR, "negative array size"); |
mzta | 0:158c61bb030f | 859 | } |
mzta | 0:158c61bb030f | 860 | if (size > a->len) size = a->len; |
mzta | 0:158c61bb030f | 861 | if (ARY_SHARED_P(a) || size > ARY_DEFAULT_LEN) { |
mzta | 0:158c61bb030f | 862 | return ary_subseq(mrb, a, a->len - size, size); |
mzta | 0:158c61bb030f | 863 | } |
mzta | 0:158c61bb030f | 864 | return mrb_ary_new_from_values(mrb, size, a->ptr + a->len - size); |
mzta | 0:158c61bb030f | 865 | } |
mzta | 0:158c61bb030f | 866 | |
mzta | 0:158c61bb030f | 867 | static mrb_value |
mzta | 0:158c61bb030f | 868 | mrb_ary_index_m(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 869 | { |
mzta | 0:158c61bb030f | 870 | mrb_value obj; |
mzta | 0:158c61bb030f | 871 | mrb_int i; |
mzta | 0:158c61bb030f | 872 | |
mzta | 0:158c61bb030f | 873 | mrb_get_args(mrb, "o", &obj); |
mzta | 0:158c61bb030f | 874 | for (i = 0; i < RARRAY_LEN(self); i++) { |
mzta | 0:158c61bb030f | 875 | if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { |
mzta | 0:158c61bb030f | 876 | return mrb_fixnum_value(i); |
mzta | 0:158c61bb030f | 877 | } |
mzta | 0:158c61bb030f | 878 | } |
mzta | 0:158c61bb030f | 879 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 880 | } |
mzta | 0:158c61bb030f | 881 | |
mzta | 0:158c61bb030f | 882 | static mrb_value |
mzta | 0:158c61bb030f | 883 | mrb_ary_rindex_m(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 884 | { |
mzta | 0:158c61bb030f | 885 | mrb_value obj; |
mzta | 0:158c61bb030f | 886 | mrb_int i; |
mzta | 0:158c61bb030f | 887 | |
mzta | 0:158c61bb030f | 888 | mrb_get_args(mrb, "o", &obj); |
mzta | 0:158c61bb030f | 889 | for (i = RARRAY_LEN(self) - 1; i >= 0; i--) { |
mzta | 0:158c61bb030f | 890 | if (mrb_equal(mrb, RARRAY_PTR(self)[i], obj)) { |
mzta | 0:158c61bb030f | 891 | return mrb_fixnum_value(i); |
mzta | 0:158c61bb030f | 892 | } |
mzta | 0:158c61bb030f | 893 | } |
mzta | 0:158c61bb030f | 894 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 895 | } |
mzta | 0:158c61bb030f | 896 | |
mzta | 0:158c61bb030f | 897 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 898 | mrb_ary_splat(mrb_state *mrb, mrb_value v) |
mzta | 0:158c61bb030f | 899 | { |
mzta | 0:158c61bb030f | 900 | if (mrb_array_p(v)) { |
mzta | 0:158c61bb030f | 901 | return v; |
mzta | 0:158c61bb030f | 902 | } |
mzta | 0:158c61bb030f | 903 | if (mrb_respond_to(mrb, v, mrb_intern_lit(mrb, "to_a"))) { |
mzta | 0:158c61bb030f | 904 | return mrb_funcall(mrb, v, "to_a", 0); |
mzta | 0:158c61bb030f | 905 | } |
mzta | 0:158c61bb030f | 906 | else { |
mzta | 0:158c61bb030f | 907 | return mrb_ary_new_from_values(mrb, 1, &v); |
mzta | 0:158c61bb030f | 908 | } |
mzta | 0:158c61bb030f | 909 | } |
mzta | 0:158c61bb030f | 910 | |
mzta | 0:158c61bb030f | 911 | static mrb_value |
mzta | 0:158c61bb030f | 912 | mrb_ary_size(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 913 | { |
mzta | 0:158c61bb030f | 914 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 915 | |
mzta | 0:158c61bb030f | 916 | return mrb_fixnum_value(a->len); |
mzta | 0:158c61bb030f | 917 | } |
mzta | 0:158c61bb030f | 918 | |
mzta | 0:158c61bb030f | 919 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 920 | mrb_ary_clear(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 921 | { |
mzta | 0:158c61bb030f | 922 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 923 | |
mzta | 0:158c61bb030f | 924 | if (ARY_SHARED_P(a)) { |
mzta | 0:158c61bb030f | 925 | mrb_ary_decref(mrb, a->aux.shared); |
mzta | 0:158c61bb030f | 926 | ARY_UNSET_SHARED_FLAG(a); |
mzta | 0:158c61bb030f | 927 | } |
mzta | 0:158c61bb030f | 928 | else { |
mzta | 0:158c61bb030f | 929 | mrb_free(mrb, a->ptr); |
mzta | 0:158c61bb030f | 930 | } |
mzta | 0:158c61bb030f | 931 | a->len = 0; |
mzta | 0:158c61bb030f | 932 | a->aux.capa = 0; |
mzta | 0:158c61bb030f | 933 | a->ptr = 0; |
mzta | 0:158c61bb030f | 934 | |
mzta | 0:158c61bb030f | 935 | return self; |
mzta | 0:158c61bb030f | 936 | } |
mzta | 0:158c61bb030f | 937 | |
mzta | 0:158c61bb030f | 938 | static mrb_value |
mzta | 0:158c61bb030f | 939 | mrb_ary_empty_p(mrb_state *mrb, mrb_value self) |
mzta | 0:158c61bb030f | 940 | { |
mzta | 0:158c61bb030f | 941 | struct RArray *a = mrb_ary_ptr(self); |
mzta | 0:158c61bb030f | 942 | |
mzta | 0:158c61bb030f | 943 | return mrb_bool_value(a->len == 0); |
mzta | 0:158c61bb030f | 944 | } |
mzta | 0:158c61bb030f | 945 | |
mzta | 0:158c61bb030f | 946 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 947 | mrb_check_array_type(mrb_state *mrb, mrb_value ary) |
mzta | 0:158c61bb030f | 948 | { |
mzta | 0:158c61bb030f | 949 | return mrb_check_convert_type(mrb, ary, MRB_TT_ARRAY, "Array", "to_ary"); |
mzta | 0:158c61bb030f | 950 | } |
mzta | 0:158c61bb030f | 951 | |
mzta | 0:158c61bb030f | 952 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 953 | mrb_ary_entry(mrb_value ary, mrb_int offset) |
mzta | 0:158c61bb030f | 954 | { |
mzta | 0:158c61bb030f | 955 | if (offset < 0) { |
mzta | 0:158c61bb030f | 956 | offset += RARRAY_LEN(ary); |
mzta | 0:158c61bb030f | 957 | } |
mzta | 0:158c61bb030f | 958 | return ary_elt(ary, offset); |
mzta | 0:158c61bb030f | 959 | } |
mzta | 0:158c61bb030f | 960 | |
mzta | 0:158c61bb030f | 961 | static mrb_value |
mzta | 0:158c61bb030f | 962 | join_ary(mrb_state *mrb, mrb_value ary, mrb_value sep, mrb_value list) |
mzta | 0:158c61bb030f | 963 | { |
mzta | 0:158c61bb030f | 964 | mrb_int i; |
mzta | 0:158c61bb030f | 965 | mrb_value result, val, tmp; |
mzta | 0:158c61bb030f | 966 | |
mzta | 0:158c61bb030f | 967 | /* check recursive */ |
mzta | 0:158c61bb030f | 968 | for (i=0; i<RARRAY_LEN(list); i++) { |
mzta | 0:158c61bb030f | 969 | if (mrb_obj_equal(mrb, ary, RARRAY_PTR(list)[i])) { |
mzta | 0:158c61bb030f | 970 | mrb_raise(mrb, E_ARGUMENT_ERROR, "recursive array join"); |
mzta | 0:158c61bb030f | 971 | } |
mzta | 0:158c61bb030f | 972 | } |
mzta | 0:158c61bb030f | 973 | |
mzta | 0:158c61bb030f | 974 | mrb_ary_push(mrb, list, ary); |
mzta | 0:158c61bb030f | 975 | |
mzta | 0:158c61bb030f | 976 | result = mrb_str_buf_new(mrb, 64); |
mzta | 0:158c61bb030f | 977 | |
mzta | 0:158c61bb030f | 978 | for (i=0; i<RARRAY_LEN(ary); i++) { |
mzta | 0:158c61bb030f | 979 | if (i > 0 && !mrb_nil_p(sep)) { |
mzta | 0:158c61bb030f | 980 | mrb_str_cat_str(mrb, result, sep); |
mzta | 0:158c61bb030f | 981 | } |
mzta | 0:158c61bb030f | 982 | |
mzta | 0:158c61bb030f | 983 | val = RARRAY_PTR(ary)[i]; |
mzta | 0:158c61bb030f | 984 | switch (mrb_type(val)) { |
mzta | 0:158c61bb030f | 985 | case MRB_TT_ARRAY: |
mzta | 0:158c61bb030f | 986 | ary_join: |
mzta | 0:158c61bb030f | 987 | val = join_ary(mrb, val, sep, list); |
mzta | 0:158c61bb030f | 988 | /* fall through */ |
mzta | 0:158c61bb030f | 989 | |
mzta | 0:158c61bb030f | 990 | case MRB_TT_STRING: |
mzta | 0:158c61bb030f | 991 | str_join: |
mzta | 0:158c61bb030f | 992 | mrb_str_cat_str(mrb, result, val); |
mzta | 0:158c61bb030f | 993 | break; |
mzta | 0:158c61bb030f | 994 | |
mzta | 0:158c61bb030f | 995 | default: |
mzta | 0:158c61bb030f | 996 | tmp = mrb_check_string_type(mrb, val); |
mzta | 0:158c61bb030f | 997 | if (!mrb_nil_p(tmp)) { |
mzta | 0:158c61bb030f | 998 | val = tmp; |
mzta | 0:158c61bb030f | 999 | goto str_join; |
mzta | 0:158c61bb030f | 1000 | } |
mzta | 0:158c61bb030f | 1001 | tmp = mrb_check_convert_type(mrb, val, MRB_TT_ARRAY, "Array", "to_ary"); |
mzta | 0:158c61bb030f | 1002 | if (!mrb_nil_p(tmp)) { |
mzta | 0:158c61bb030f | 1003 | val = tmp; |
mzta | 0:158c61bb030f | 1004 | goto ary_join; |
mzta | 0:158c61bb030f | 1005 | } |
mzta | 0:158c61bb030f | 1006 | val = mrb_obj_as_string(mrb, val); |
mzta | 0:158c61bb030f | 1007 | goto str_join; |
mzta | 0:158c61bb030f | 1008 | } |
mzta | 0:158c61bb030f | 1009 | } |
mzta | 0:158c61bb030f | 1010 | |
mzta | 0:158c61bb030f | 1011 | mrb_ary_pop(mrb, list); |
mzta | 0:158c61bb030f | 1012 | |
mzta | 0:158c61bb030f | 1013 | return result; |
mzta | 0:158c61bb030f | 1014 | } |
mzta | 0:158c61bb030f | 1015 | |
mzta | 0:158c61bb030f | 1016 | MRB_API mrb_value |
mzta | 0:158c61bb030f | 1017 | mrb_ary_join(mrb_state *mrb, mrb_value ary, mrb_value sep) |
mzta | 0:158c61bb030f | 1018 | { |
mzta | 0:158c61bb030f | 1019 | sep = mrb_obj_as_string(mrb, sep); |
mzta | 0:158c61bb030f | 1020 | return join_ary(mrb, ary, sep, mrb_ary_new(mrb)); |
mzta | 0:158c61bb030f | 1021 | } |
mzta | 0:158c61bb030f | 1022 | |
mzta | 0:158c61bb030f | 1023 | /* |
mzta | 0:158c61bb030f | 1024 | * call-seq: |
mzta | 0:158c61bb030f | 1025 | * ary.join(sep="") -> str |
mzta | 0:158c61bb030f | 1026 | * |
mzta | 0:158c61bb030f | 1027 | * Returns a string created by converting each element of the array to |
mzta | 0:158c61bb030f | 1028 | * a string, separated by <i>sep</i>. |
mzta | 0:158c61bb030f | 1029 | * |
mzta | 0:158c61bb030f | 1030 | * [ "a", "b", "c" ].join #=> "abc" |
mzta | 0:158c61bb030f | 1031 | * [ "a", "b", "c" ].join("-") #=> "a-b-c" |
mzta | 0:158c61bb030f | 1032 | */ |
mzta | 0:158c61bb030f | 1033 | |
mzta | 0:158c61bb030f | 1034 | static mrb_value |
mzta | 0:158c61bb030f | 1035 | mrb_ary_join_m(mrb_state *mrb, mrb_value ary) |
mzta | 0:158c61bb030f | 1036 | { |
mzta | 0:158c61bb030f | 1037 | mrb_value sep = mrb_nil_value(); |
mzta | 0:158c61bb030f | 1038 | |
mzta | 0:158c61bb030f | 1039 | mrb_get_args(mrb, "|S", &sep); |
mzta | 0:158c61bb030f | 1040 | return mrb_ary_join(mrb, ary, sep); |
mzta | 0:158c61bb030f | 1041 | } |
mzta | 0:158c61bb030f | 1042 | |
mzta | 0:158c61bb030f | 1043 | static mrb_value |
mzta | 0:158c61bb030f | 1044 | mrb_ary_eq(mrb_state *mrb, mrb_value ary1) |
mzta | 0:158c61bb030f | 1045 | { |
mzta | 0:158c61bb030f | 1046 | mrb_value ary2; |
mzta | 0:158c61bb030f | 1047 | |
mzta | 0:158c61bb030f | 1048 | mrb_get_args(mrb, "o", &ary2); |
mzta | 0:158c61bb030f | 1049 | if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_true_value(); |
mzta | 0:158c61bb030f | 1050 | if (mrb_immediate_p(ary2)) return mrb_false_value(); |
mzta | 0:158c61bb030f | 1051 | if (!mrb_array_p(ary2)) { |
mzta | 0:158c61bb030f | 1052 | return mrb_false_value(); |
mzta | 0:158c61bb030f | 1053 | } |
mzta | 0:158c61bb030f | 1054 | if (RARRAY_LEN(ary1) != RARRAY_LEN(ary2)) return mrb_false_value(); |
mzta | 0:158c61bb030f | 1055 | |
mzta | 0:158c61bb030f | 1056 | return ary2; |
mzta | 0:158c61bb030f | 1057 | } |
mzta | 0:158c61bb030f | 1058 | |
mzta | 0:158c61bb030f | 1059 | static mrb_value |
mzta | 0:158c61bb030f | 1060 | mrb_ary_cmp(mrb_state *mrb, mrb_value ary1) |
mzta | 0:158c61bb030f | 1061 | { |
mzta | 0:158c61bb030f | 1062 | mrb_value ary2; |
mzta | 0:158c61bb030f | 1063 | |
mzta | 0:158c61bb030f | 1064 | mrb_get_args(mrb, "o", &ary2); |
mzta | 0:158c61bb030f | 1065 | if (mrb_obj_equal(mrb, ary1, ary2)) return mrb_fixnum_value(0); |
mzta | 0:158c61bb030f | 1066 | if (mrb_immediate_p(ary2)) return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1067 | if (!mrb_array_p(ary2)) { |
mzta | 0:158c61bb030f | 1068 | return mrb_nil_value(); |
mzta | 0:158c61bb030f | 1069 | } |
mzta | 0:158c61bb030f | 1070 | |
mzta | 0:158c61bb030f | 1071 | return ary2; |
mzta | 0:158c61bb030f | 1072 | } |
mzta | 0:158c61bb030f | 1073 | |
mzta | 0:158c61bb030f | 1074 | void |
mzta | 0:158c61bb030f | 1075 | mrb_init_array(mrb_state *mrb) |
mzta | 0:158c61bb030f | 1076 | { |
mzta | 0:158c61bb030f | 1077 | struct RClass *a; |
mzta | 0:158c61bb030f | 1078 | |
mzta | 0:158c61bb030f | 1079 | a = mrb->array_class = mrb_define_class(mrb, "Array", mrb->object_class); /* 15.2.12 */ |
mzta | 0:158c61bb030f | 1080 | MRB_SET_INSTANCE_TT(a, MRB_TT_ARRAY); |
mzta | 0:158c61bb030f | 1081 | |
mzta | 0:158c61bb030f | 1082 | mrb_define_class_method(mrb, a, "[]", mrb_ary_s_create, MRB_ARGS_ANY()); /* 15.2.12.4.1 */ |
mzta | 0:158c61bb030f | 1083 | |
mzta | 0:158c61bb030f | 1084 | mrb_define_method(mrb, a, "+", mrb_ary_plus, MRB_ARGS_REQ(1)); /* 15.2.12.5.1 */ |
mzta | 0:158c61bb030f | 1085 | mrb_define_method(mrb, a, "*", mrb_ary_times, MRB_ARGS_REQ(1)); /* 15.2.12.5.2 */ |
mzta | 0:158c61bb030f | 1086 | mrb_define_method(mrb, a, "<<", mrb_ary_push_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.3 */ |
mzta | 0:158c61bb030f | 1087 | mrb_define_method(mrb, a, "[]", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.4 */ |
mzta | 0:158c61bb030f | 1088 | mrb_define_method(mrb, a, "[]=", mrb_ary_aset, MRB_ARGS_ANY()); /* 15.2.12.5.5 */ |
mzta | 0:158c61bb030f | 1089 | mrb_define_method(mrb, a, "clear", mrb_ary_clear, MRB_ARGS_NONE()); /* 15.2.12.5.6 */ |
mzta | 0:158c61bb030f | 1090 | mrb_define_method(mrb, a, "concat", mrb_ary_concat_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.8 */ |
mzta | 0:158c61bb030f | 1091 | mrb_define_method(mrb, a, "delete_at", mrb_ary_delete_at, MRB_ARGS_REQ(1)); /* 15.2.12.5.9 */ |
mzta | 0:158c61bb030f | 1092 | mrb_define_method(mrb, a, "empty?", mrb_ary_empty_p, MRB_ARGS_NONE()); /* 15.2.12.5.12 */ |
mzta | 0:158c61bb030f | 1093 | mrb_define_method(mrb, a, "first", mrb_ary_first, MRB_ARGS_OPT(1)); /* 15.2.12.5.13 */ |
mzta | 0:158c61bb030f | 1094 | mrb_define_method(mrb, a, "index", mrb_ary_index_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.14 */ |
mzta | 0:158c61bb030f | 1095 | mrb_define_method(mrb, a, "initialize_copy", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.16 */ |
mzta | 0:158c61bb030f | 1096 | mrb_define_method(mrb, a, "join", mrb_ary_join_m, MRB_ARGS_ANY()); /* 15.2.12.5.17 */ |
mzta | 0:158c61bb030f | 1097 | mrb_define_method(mrb, a, "last", mrb_ary_last, MRB_ARGS_ANY()); /* 15.2.12.5.18 */ |
mzta | 0:158c61bb030f | 1098 | mrb_define_method(mrb, a, "length", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.19 */ |
mzta | 0:158c61bb030f | 1099 | mrb_define_method(mrb, a, "pop", mrb_ary_pop, MRB_ARGS_NONE()); /* 15.2.12.5.21 */ |
mzta | 0:158c61bb030f | 1100 | mrb_define_method(mrb, a, "push", mrb_ary_push_m, MRB_ARGS_ANY()); /* 15.2.12.5.22 */ |
mzta | 0:158c61bb030f | 1101 | mrb_define_method(mrb, a, "replace", mrb_ary_replace_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.23 */ |
mzta | 0:158c61bb030f | 1102 | mrb_define_method(mrb, a, "reverse", mrb_ary_reverse, MRB_ARGS_NONE()); /* 15.2.12.5.24 */ |
mzta | 0:158c61bb030f | 1103 | mrb_define_method(mrb, a, "reverse!", mrb_ary_reverse_bang, MRB_ARGS_NONE()); /* 15.2.12.5.25 */ |
mzta | 0:158c61bb030f | 1104 | mrb_define_method(mrb, a, "rindex", mrb_ary_rindex_m, MRB_ARGS_REQ(1)); /* 15.2.12.5.26 */ |
mzta | 0:158c61bb030f | 1105 | mrb_define_method(mrb, a, "shift", mrb_ary_shift, MRB_ARGS_NONE()); /* 15.2.12.5.27 */ |
mzta | 0:158c61bb030f | 1106 | mrb_define_method(mrb, a, "size", mrb_ary_size, MRB_ARGS_NONE()); /* 15.2.12.5.28 */ |
mzta | 0:158c61bb030f | 1107 | mrb_define_method(mrb, a, "slice", mrb_ary_aget, MRB_ARGS_ANY()); /* 15.2.12.5.29 */ |
mzta | 0:158c61bb030f | 1108 | mrb_define_method(mrb, a, "unshift", mrb_ary_unshift_m, MRB_ARGS_ANY()); /* 15.2.12.5.30 */ |
mzta | 0:158c61bb030f | 1109 | |
mzta | 0:158c61bb030f | 1110 | mrb_define_method(mrb, a, "__ary_eq", mrb_ary_eq, MRB_ARGS_REQ(1)); |
mzta | 0:158c61bb030f | 1111 | mrb_define_method(mrb, a, "__ary_cmp", mrb_ary_cmp, MRB_ARGS_REQ(1)); |
mzta | 0:158c61bb030f | 1112 | } |
mzta | 0:158c61bb030f | 1113 |