1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15: #include "ruby/ruby.h"
16: #include "ruby/util.h"
17: #include "ruby/st.h"
18:
19: VALUE rb_cArray;
20:
21: static ID id_cmp;
22:
23: #define ARY_DEFAULT_SIZE 16
24:
25: void
26: rb_mem_clear(register VALUE *mem, register long size)
27: {
28: while (size--) {
29: *mem++ = Qnil;
30: }
31: }
32:
33: static inline void
34: memfill(register VALUE *mem, register long size, register VALUE val)
35: {
36: while (size--) {
37: *mem++ = val;
38: }
39: }
40:
41: #define ARY_ITERLOCK FL_USER1
42: static void
43: ary_iter_check(VALUE ary)
44: {
45: if (FL_TEST(ary, ARY_ITERLOCK)) {
46: rb_raise(rb_eRuntimeError, "can't modify array during iteration");
47: }
48: }
49: #define ARY_SORTLOCK FL_USER3
50: #define ARY_SHARED_P(a) FL_TEST(a, ELTS_SHARED)
51:
52: #define ARY_SET_LEN(ary, n) do { \
53: RARRAY(ary)->len = (n);\
54: } while (0)
55:
56: #define ARY_CAPA(ary) RARRAY(ary)->aux.capa
57: #define RESIZE_CAPA(ary,capacity) do {\
58: REALLOC_N(RARRAY(ary)->ptr, VALUE, (capacity));\
59: RARRAY(ary)->aux.capa = (capacity);\
60: } while (0)
61:
62: #define ITERATE(func, ary) do { \
63: FL_SET(ary, ARY_ITERLOCK); \
64: return rb_ensure(func, (ary), each_unlock, (ary));\
65: } while (0)
66:
67: static inline void
68: rb_ary_modify_check(VALUE ary)
69: {
70: if (OBJ_FROZEN(ary)) rb_error_frozen("array");
71: if (FL_TEST(ary, ARY_SORTLOCK))
72: rb_raise(rb_eRuntimeError, "can't modify array during sort");
73: if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4)
74: rb_raise(rb_eSecurityError, "Insecure: can't modify array");
75: }
76:
77: static void
78: rb_ary_modify(VALUE ary)
79: {
80: VALUE *ptr;
81:
82: rb_ary_modify_check(ary);
83: if (ARY_SHARED_P(ary)) {
84: ptr = ALLOC_N(VALUE, RARRAY_LEN(ary));
85: FL_UNSET(ary, ELTS_SHARED);
86: RARRAY(ary)->aux.capa = RARRAY_LEN(ary);
87: MEMCPY(ptr, RARRAY_PTR(ary), VALUE, RARRAY_LEN(ary));
88: RARRAY(ary)->ptr = ptr;
89: }
90: }
91:
92: VALUE
93: rb_ary_freeze(VALUE ary)
94: {
95: return rb_obj_freeze(ary);
96: }
97:
98:
99:
100:
101:
102:
103:
104:
105:
106: static VALUE
107: rb_ary_frozen_p(VALUE ary)
108: {
109: if (OBJ_FROZEN(ary)) return Qtrue;
110: if (FL_TEST(ary, ARY_SORTLOCK)) return Qtrue;
111: return Qfalse;
112: }
113:
114: static VALUE
115: ary_alloc(VALUE klass)
116: {
117: NEWOBJ(ary, struct RArray);
118: OBJSETUP(ary, klass, T_ARRAY);
119:
120: ary->len = 0;
121: ary->ptr = 0;
122: ary->aux.capa = 0;
123:
124: return (VALUE)ary;
125: }
126:
127: static VALUE
128: ary_new(VALUE klass, long len)
129: {
130: VALUE ary;
131:
132: if (len < 0) {
133: rb_raise(rb_eArgError, "negative array size (or size too big)");
134: }
135: if (len > 0 && len * sizeof(VALUE) <= len) {
136: rb_raise(rb_eArgError, "array size too big");
137: }
138: ary = ary_alloc(klass);
139: if (len == 0) len++;
140: RARRAY(ary)->ptr = ALLOC_N(VALUE, len);
141: RARRAY(ary)->aux.capa = len;
142:
143: return ary;
144: }
145:
146: VALUE
147: rb_ary_new2(long len)
148: {
149: return ary_new(rb_cArray, len);
150: }
151:
152:
153: VALUE
154: rb_ary_new(void)
155: {
156: return rb_ary_new2(ARY_DEFAULT_SIZE);
157: }
158:
159: #include <stdarg.h>
160:
161: VALUE
162: rb_ary_new3(long n, ...)
163: {
164: va_list ar;
165: VALUE ary;
166: long i;
167:
168: ary = rb_ary_new2(n);
169:
170: va_start(ar, n);
171: for (i=0; i<n; i++) {
172: RARRAY_PTR(ary)[i] = va_arg(ar, VALUE);
173: }
174: va_end(ar);
175:
176: RARRAY(ary)->len = n;
177: return ary;
178: }
179:
180: VALUE
181: rb_ary_new4(long n, const VALUE *elts)
182: {
183: VALUE ary;
184:
185: ary = rb_ary_new2(n);
186: if (n > 0 && elts) {
187: MEMCPY(RARRAY_PTR(ary), elts, VALUE, n);
188: RARRAY(ary)->len = n;
189: }
190:
191: return ary;
192: }
193:
194: void
195: rb_ary_free(VALUE ary)
196: {
197: if (!ARY_SHARED_P(ary)) {
198: xfree(RARRAY(ary)->ptr);
199: }
200: }
201:
202: static VALUE
203: ary_make_shared(VALUE ary)
204: {
205: if (ARY_SHARED_P(ary)) {
206: return RARRAY(ary)->aux.shared;
207: }
208: else {
209: NEWOBJ(shared, struct RArray);
210: OBJSETUP(shared, 0, T_ARRAY);
211:
212: shared->len = RARRAY(ary)->len;
213: shared->ptr = RARRAY(ary)->ptr;
214: shared->aux.capa = RARRAY(ary)->aux.capa;
215: RARRAY(ary)->aux.shared = (VALUE)shared;
216: FL_SET(ary, ELTS_SHARED);
217: OBJ_FREEZE(shared);
218: return (VALUE)shared;
219: }
220: }
221:
222: VALUE
223: rb_assoc_new(VALUE car, VALUE cdr)
224: {
225: return rb_ary_new3(2, car, cdr);
226: }
227:
228: static VALUE
229: to_ary(VALUE ary)
230: {
231: return rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
232: }
233:
234: VALUE
235: rb_check_array_type(VALUE ary)
236: {
237: return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
238: }
239:
240:
241:
242:
243:
244:
245:
246:
247:
248:
249:
250:
251:
252:
253:
254:
255:
256:
257:
258:
259:
260: static VALUE
261: rb_ary_s_try_convert(VALUE dummy, VALUE ary)
262: {
263: return rb_check_array_type(ary);
264: }
265:
266:
267:
268:
269:
270:
271:
272:
273:
274:
275:
276:
277:
278:
279:
280:
281:
282:
283:
284:
285:
286:
287:
288:
289:
290:
291:
292:
293:
294:
295:
296:
297:
298:
299:
300:
301:
302:
303:
304: static VALUE
305: rb_ary_initialize(int argc, VALUE *argv, VALUE ary)
306: {
307: long len;
308: VALUE size, val;
309:
310: rb_ary_modify(ary);
311: ary_iter_check(ary);
312: if (rb_scan_args(argc, argv, "02", &size, &val) == 0) {
313: if (RARRAY_PTR(ary) && !ARY_SHARED_P(ary)) {
314: free(RARRAY(ary)->ptr);
315: }
316: RARRAY(ary)->len = 0;
317: if (rb_block_given_p()) {
318: rb_warning("given block not used");
319: }
320: return ary;
321: }
322:
323: if (argc == 1 && !FIXNUM_P(size)) {
324: val = rb_check_array_type(size);
325: if (!NIL_P(val)) {
326: rb_ary_replace(ary, val);
327: return ary;
328: }
329: }
330:
331: len = NUM2LONG(size);
332: if (len < 0) {
333: rb_raise(rb_eArgError, "negative array size");
334: }
335: if (len > 0 && len * (long)sizeof(VALUE) <= len) {
336: rb_raise(rb_eArgError, "array size too big");
337: }
338: rb_ary_modify(ary);
339: RESIZE_CAPA(ary, len);
340: if (rb_block_given_p()) {
341: long i;
342:
343: if (argc == 2) {
344: rb_warn("block supersedes default value argument");
345: }
346: for (i=0; i<len; i++) {
347: rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
348: RARRAY(ary)->len = i + 1;
349: }
350: }
351: else {
352: memfill(RARRAY_PTR(ary), len, val);
353: RARRAY(ary)->len = len;
354: }
355: return ary;
356: }
357:
358:
359:
360:
361:
362:
363:
364:
365:
366:
367: static VALUE
368: rb_ary_s_create(int argc, VALUE *argv, VALUE klass)
369: {
370: VALUE ary = ary_alloc(klass);
371:
372: if (argc < 0) {
373: rb_raise(rb_eArgError, "negative array size");
374: }
375: RARRAY(ary)->ptr = ALLOC_N(VALUE, argc);
376: RARRAY(ary)->aux.capa = argc;
377: MEMCPY(RARRAY_PTR(ary), argv, VALUE, argc);
378: RARRAY(ary)->len = argc;
379:
380: return ary;
381: }
382:
383: void
384: rb_ary_store(VALUE ary, long idx, VALUE val)
385: {
386: if (idx < 0) {
387: idx += RARRAY_LEN(ary);
388: if (idx < 0) {
389: rb_raise(rb_eIndexError, "index %ld out of array",
390: idx - RARRAY_LEN(ary));
391: }
392: }
393:
394: rb_ary_modify(ary);
395: if (idx >= ARY_CAPA(ary)) {
396: long new_capa = ARY_CAPA(ary) / 2;
397:
398: if (new_capa < ARY_DEFAULT_SIZE) {
399: new_capa = ARY_DEFAULT_SIZE;
400: }
401: if (new_capa + idx < new_capa) {
402: rb_raise(rb_eArgError, "index too big");
403: }
404: new_capa += idx;
405: if (new_capa * (long)sizeof(VALUE) <= new_capa) {
406: rb_raise(rb_eArgError, "index too big");
407: }
408: RESIZE_CAPA(ary, new_capa);
409: }
410: if (idx > RARRAY_LEN(ary)) {
411: rb_mem_clear(RARRAY_PTR(ary) + RARRAY_LEN(ary),
412: idx-RARRAY_LEN(ary) + 1);
413: }
414:
415: if (idx >= RARRAY_LEN(ary)) {
416: RARRAY(ary)->len = idx + 1;
417: }
418: RARRAY_PTR(ary)[idx] = val;
419: }
420:
421: static VALUE
422: ary_shared_array(VALUE klass, VALUE ary)
423: {
424: VALUE val = ary_alloc(klass);
425:
426: ary_make_shared(ary);
427: RARRAY(val)->ptr = RARRAY(ary)->ptr;
428: RARRAY(val)->len = RARRAY(ary)->len;
429: RARRAY(val)->aux.shared = RARRAY(ary)->aux.shared;
430: FL_SET(val, ELTS_SHARED);
431: return val;
432: }
433:
434: static VALUE
435: ary_shared_first(int argc, VALUE *argv, VALUE ary, int last)
436: {
437: VALUE nv, result;
438: long n;
439: long offset = 0;
440:
441: rb_scan_args(argc, argv, "1", &nv);
442: n = NUM2LONG(nv);
443: if (n > RARRAY_LEN(ary)) {
444: n = RARRAY_LEN(ary);
445: }
446: else if (n < 0) {
447: rb_raise(rb_eArgError, "negative array size");
448: }
449: if (last) {
450: offset = RARRAY_LEN(ary) - n;
451: }
452: result = ary_shared_array(rb_cArray, ary);
453: RARRAY(result)->ptr += offset;
454: RARRAY(result)->len = n;
455:
456: return result;
457: }
458:
459:
460:
461:
462:
463:
464:
465:
466:
467:
468:
469:
470:
471:
472: VALUE
473: rb_ary_push(VALUE ary, VALUE item)
474: {
475: rb_ary_store(ary, RARRAY_LEN(ary), item);
476: return ary;
477: }
478:
479:
480:
481:
482:
483:
484:
485:
486:
487:
488:
489:
490:
491:
492: static VALUE
493: rb_ary_push_m(int argc, VALUE *argv, VALUE ary)
494: {
495: while (argc--) {
496: rb_ary_push(ary, *argv++);
497: }
498: return ary;
499: }
500:
501: VALUE
502: rb_ary_pop(VALUE ary)
503: {
504: long n;
505: rb_ary_modify_check(ary);
506: if (RARRAY_LEN(ary) == 0) return Qnil;
507: if (!ARY_SHARED_P(ary) &&
508: RARRAY_LEN(ary) * 3 < ARY_CAPA(ary) &&
509: ARY_CAPA(ary) > ARY_DEFAULT_SIZE)
510: {
511: RESIZE_CAPA(ary, RARRAY_LEN(ary) * 2);
512: }
513: n = RARRAY_LEN(ary)-1;
514: RARRAY(ary)->len = n;
515: return RARRAY_PTR(ary)[n];
516: }
517:
518:
519:
520:
521:
522:
523:
524:
525:
526:
527:
528:
529:
530:
531: static VALUE
532: rb_ary_pop_m(int argc, VALUE *argv, VALUE ary)
533: {
534: VALUE result;
535:
536: if (argc == 0) {
537: return rb_ary_pop(ary);
538: }
539:
540: rb_ary_modify_check(ary);
541: result = ary_shared_first(argc, argv, ary, Qtrue);
542: RARRAY(ary)->len -= RARRAY_LEN(result);
543: return result;
544: }
545:
546: VALUE
547: rb_ary_shift(VALUE ary)
548: {
549: VALUE top;
550:
551: rb_ary_modify_check(ary);
552: ary_iter_check(ary);
553: if (RARRAY_LEN(ary) == 0) return Qnil;
554: top = RARRAY_PTR(ary)[0];
555: if (!ARY_SHARED_P(ary)) {
556: if (RARRAY_LEN(ary) < ARY_DEFAULT_SIZE) {
557: MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+1, VALUE, RARRAY_LEN(ary)-1);
558: RARRAY(ary)->len--;
559: return top;
560: }
561: RARRAY_PTR(ary)[0] = Qnil;
562: ary_make_shared(ary);
563: }
564: RARRAY(ary)->ptr++;
565: RARRAY(ary)->len--;
566:
567: return top;
568: }
569:
570:
571:
572:
573:
574:
575:
576:
577:
578:
579:
580:
581:
582:
583:
584:
585:
586:
587: static VALUE
588: rb_ary_shift_m(int argc, VALUE *argv, VALUE ary)
589: {
590: VALUE result;
591: long n;
592:
593: if (argc == 0) {
594: return rb_ary_shift(ary);
595: }
596:
597: rb_ary_modify_check(ary);
598: ary_iter_check(ary);
599: result = ary_shared_first(argc, argv, ary, Qfalse);
600: n = RARRAY_LEN(result);
601: if (ARY_SHARED_P(ary)) {
602: RARRAY(ary)->ptr += n;
603: RARRAY(ary)->len -= n;
604: }
605: else {
606: MEMMOVE(RARRAY_PTR(ary), RARRAY_PTR(ary)+n, VALUE, RARRAY_LEN(ary)-n);
607: RARRAY(ary)->len -= n;
608: }
609:
610: return result;
611: }
612:
613:
614:
615:
616:
617:
618:
619:
620:
621:
622:
623:
624:
625: static VALUE
626: rb_ary_unshift_m(int argc, VALUE *argv, VALUE ary)
627: {
628: long len = RARRAY(ary)->len;
629:
630: if (argc == 0) return ary;
631: rb_ary_modify(ary);
632: ary_iter_check(ary);
633: if (RARRAY(ary)->aux.capa <= RARRAY_LEN(ary)+argc) {
634: RESIZE_CAPA(ary, RARRAY(ary)->aux.capa + ARY_DEFAULT_SIZE);
635: }
636:
637:
638: MEMMOVE(RARRAY(ary)->ptr + argc, RARRAY(ary)->ptr, VALUE, len);
639: MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
640: RARRAY(ary)->len += argc;
641:
642: return ary;
643: }
644:
645: