1 #include <string.h>
2 #include <stdlib.h>
3 #include <stdio.h>
4 #include "codegen.h"
5 #include "symboltable.h"
6 #include "stringbuffer.h"
7
8 extern void yyerror(char* msg);
9
10 static stringBuffer* staticVariableBuffer;
11 static stringBuffer* classInitBuffer;
12 static stringBuffer* currentMethodBuffer;
13 static stringBuffer* finishedMethodsBuffer;
14 static stringBuffer* mainBuffer;
15
16 static int currentMethodBufferIndex;
17 static int currentMethodStackSize;
18 static int currentMethodStackSizeMax;
19 static int currentMethodNumberOfLocals;
20
21 static int classInitBufferIndex;
22 static int classInitStackSize;
23 static int classInitStackSizeMax;
24
25 static int labelCounter = 0;
26 static int global = 1;
27
28 char tempString[MAX_LENGTH_OF_COMMAND];
29
30 extern char* className; /* from minako-syntax.y */
31
32 /* forward declarations */
33 static void increaseStackby(int stackdiff);
34 char convertType(int type);
35
codegenInit()36 void codegenInit() {
37 staticVariableBuffer = newStringBuffer();
38 classInitBuffer = newStringBuffer();
39 currentMethodBuffer = 0;
40 finishedMethodsBuffer = newStringBuffer();
41 mainBuffer = newStringBuffer();
42
43 stringBufferAppend(mainBuffer, "; ------- Header --------------------------------------------");
44 sprintf(tempString, ".class public synchronized %s", className);
45 stringBufferAppend(mainBuffer, tempString);
46 stringBufferAppend(mainBuffer, ".super java/lang/Object");
47 stringBufferAppend(mainBuffer, "; -----------------------------------------------------------");
48 stringBufferAppend(mainBuffer, "");
49
50 stringBufferAppend(finishedMethodsBuffer, "; ------- Constructor ---------------------------------------");
51 stringBufferAppend(finishedMethodsBuffer, ".method public <init>()V");
52 stringBufferAppend(finishedMethodsBuffer, "\t.limit stack 1");
53 stringBufferAppend(finishedMethodsBuffer, "\t.limit locals 1");
54 stringBufferAppend(finishedMethodsBuffer, "\taload_0");
55 stringBufferAppend(finishedMethodsBuffer, "\tinvokenonvirtual java/lang/Object/<init>()V");
56 stringBufferAppend(finishedMethodsBuffer, "\treturn");
57 stringBufferAppend(finishedMethodsBuffer, ".end method");
58 stringBufferAppend(finishedMethodsBuffer, "; -----------------------------------------------------------");
59 stringBufferAppend(finishedMethodsBuffer, "");
60
61 stringBufferAppend(staticVariableBuffer, "; ------- Class Variables -----------------------------------");
62
63 stringBufferAppend(classInitBuffer, "; ------- Class Initializer ---------------------------------");
64 stringBufferAppend(classInitBuffer, ".method static <clinit>()V");
65 classInitBufferIndex = classInitBuffer->numberOfNextElement;
66 stringBufferAppend(classInitBuffer, "\t.limit locals 0");
67
68 }
69
codegenAppendCommand(char * cmd,int stackdiff)70 void codegenAppendCommand(char* cmd, int stackdiff) {
71 char tempString[MAX_LENGTH_OF_COMMAND];
72 sprintf(tempString, "\t%s", cmd);
73 if (global) stringBufferAppend(classInitBuffer, tempString);
74 else stringBufferAppend(currentMethodBuffer, tempString);
75 increaseStackby(stackdiff);
76 }
77
codegenInsertCommand(int address,char * cmd,int stackdiff)78 void codegenInsertCommand(int address, char* cmd, int stackdiff) {
79 char tempString[MAX_LENGTH_OF_COMMAND];
80 sprintf(tempString, "\t%s", cmd);
81 if (global) stringBufferInsert(classInitBuffer, address, tempString);
82 else stringBufferInsert(currentMethodBuffer, address, tempString);
83 increaseStackby(stackdiff);
84 }
85
codegenAppendLabel(int label)86 void codegenAppendLabel(int label) {
87 char tempString[MAX_LENGTH_OF_COMMAND];
88 sprintf(tempString, "Label%d:", label);
89 if (global) stringBufferAppend(classInitBuffer, tempString);
90 else stringBufferAppend(currentMethodBuffer, tempString);
91 }
92
codegenAddVariable(char * name,int type)93 void codegenAddVariable(char* name, int type) {
94 /*fprintf(stderr, "add variable %s(%d) global=%d ", name, convertType(type), global);*/
95 if (global) {
96 if (type == TYPE_INT) sprintf(tempString, ".field static %s %c", name, 'I');
97 else if (type == TYPE_FLOAT) sprintf(tempString, ".field static %s %c", name, 'F');
98 else if (type == TYPE_BOOLEAN) sprintf(tempString, ".field static %s %c", name, 'Z');
99 else yyerror("compiler-intern error in codegenAddGlobalVariable().\n");
100 stringBufferAppend(staticVariableBuffer, tempString);
101 }
102 else {
103 currentMethodNumberOfLocals++;
104 }
105 }
106
codegenGetNextLabel()107 int codegenGetNextLabel() {
108 return labelCounter++;
109 }
110
codegenGetCurrentAddress()111 int codegenGetCurrentAddress() {
112 if (global) return classInitBuffer->numberOfNextElement;
113 else return currentMethodBuffer->numberOfNextElement;
114 }
115
codegenEnterFunction(symtabEntry * entry)116 void codegenEnterFunction(symtabEntry* entry) {
117 currentMethodBuffer = newStringBuffer();
118 currentMethodStackSize = 0;
119 currentMethodStackSizeMax = 0;
120 labelCounter = 1;
121 global = 0;
122
123 if (strcmp(entry->name, "main") == 0) {
124 if (entry->idtype != TYPE_VOID) yyerror("main has to be void.\n");
125 currentMethodNumberOfLocals = 1;
126 symtabInsert(strdup("#main-param#"), TYPE_VOID, CLASS_FUNC);
127 stringBufferAppend(currentMethodBuffer, "; ------- Methode ---- void main() --------------------------");
128 stringBufferAppend(currentMethodBuffer, ".method public static main([Ljava/lang/String;)V");
129 }
130 else {
131 int i;
132 currentMethodNumberOfLocals = entry->paramIndex;
133 stringBufferAppend(currentMethodBuffer, "; ------- Methode -------------------------------------------");
134 sprintf(tempString, ".method public static %s(", entry->name);
135 for (i=entry->paramIndex-1; i>=0; i--) {
136 int type = entry->params[i]->idtype;
137 tempString[strlen(tempString)+1] = 0;
138 tempString[strlen(tempString)] = convertType(type);
139 }
140 tempString[strlen(tempString)+2] = 0;
141 tempString[strlen(tempString)+1] = convertType(entry->idtype);
142 tempString[strlen(tempString)] = ')';
143 stringBufferAppend(currentMethodBuffer, tempString);
144 }
145 currentMethodBufferIndex = currentMethodBuffer->numberOfNextElement;
146 }
147
codegenLeaveFunction()148 void codegenLeaveFunction() {
149 global = 1;
150 sprintf(tempString, "\t.limit locals %d", currentMethodNumberOfLocals);
151 stringBufferInsert(currentMethodBuffer, currentMethodBufferIndex, tempString);
152 sprintf(tempString, "\t.limit stack %d", currentMethodStackSizeMax);
153 stringBufferInsert(currentMethodBuffer, currentMethodBufferIndex, tempString);
154 stringBufferAppend(currentMethodBuffer, "\treturn");
155 stringBufferAppend(currentMethodBuffer, ".end method");
156 stringBufferAppend(currentMethodBuffer, "; -----------------------------------------------------------");
157 stringBufferAppend(currentMethodBuffer, "");
158
159 stringBufferConcatenate(finishedMethodsBuffer, currentMethodBuffer);
160 }
161
162
163
codegenFinishCode()164 void codegenFinishCode() {
165 stringBufferAppend(staticVariableBuffer, "; -----------------------------------------------------------");
166 stringBufferAppend(staticVariableBuffer, "");
167
168 sprintf(tempString, "\t.limit stack %d", classInitStackSizeMax);
169 stringBufferInsert(classInitBuffer, classInitBufferIndex, tempString);
170 stringBufferAppend(classInitBuffer, "\treturn");
171 stringBufferAppend(classInitBuffer, ".end method");
172 stringBufferAppend(classInitBuffer, "; -----------------------------------------------------------");
173
174 stringBufferConcatenate(mainBuffer, staticVariableBuffer);
175 stringBufferConcatenate(mainBuffer, finishedMethodsBuffer);
176 stringBufferConcatenate(mainBuffer, classInitBuffer);
177
178 stringBufferPrint(mainBuffer);
179 }
180
increaseStackby(int stackdiff)181 static void increaseStackby(int stackdiff) {
182 if (global) {
183 classInitStackSize += stackdiff;
184 if (classInitStackSize > classInitStackSizeMax) classInitStackSizeMax = classInitStackSize;
185 }
186 else {
187 currentMethodStackSize += stackdiff;
188 if (currentMethodStackSize > currentMethodStackSizeMax) currentMethodStackSizeMax = currentMethodStackSize;
189 }
190 }
191
convertType(int type)192 char convertType(int type) {
193 switch(type) {
194 case TYPE_VOID: return 'V';
195 case TYPE_INT: return 'I';
196 case TYPE_FLOAT: return 'F';
197 case TYPE_BOOLEAN: return 'Z';
198 default : yyerror("compiler-intern error in convertType().\n");
199 }
200 return 0; /* to avoid compiler-warning */
201 }
202
203
204 //#include <stdlib.h>
205 //#include <stdio.h>
206
main()207 int main() {
208 int a = 12, b = 44;
209 while (a != b) {
210 if (a > b)
211 a -= b;
212 else
213 b -= a;
214 }
215 printf("%d\n%d", a, 0X0);\
216 }
217
218
219 /**********************************************************************
220
221 array.c -
222
223 $Author: murphy $
224 $Date: 2005-11-05 04:33:55 +0100 (Sa, 05 Nov 2005) $
225 created at: Fri Aug 6 09:46:12 JST 1993
226
227 Copyright (C) 1993-2003 Yukihiro Matsumoto
228 Copyright (C) 2000 Network Applied Communication Laboratory, Inc.
229 Copyright (C) 2000 Information-technology Promotion Agency, Japan
230
231 **********************************************************************/
232
233 #include "ruby.h"
234 #include "util.h"
235 #include "st.h"
236 #include "node.h"
237
238 VALUE rb_cArray, rb_cValues;
239
240 static ID id_cmp;
241
242 #define ARY_DEFAULT_SIZE 16
243
244
245 void
rb_mem_clear(mem,size)246 rb_mem_clear(mem, size)
247 register VALUE *mem;
248 register long size;
249 {
250 while (size--) {
251 *mem++ = Qnil;
252 }
253 }
254
255 static inline void
memfill(mem,size,val)256 memfill(mem, size, val)
257 register VALUE *mem;
258 register long size;
259 register VALUE val;
260 {
261 while (size--) {
262 *mem++ = val;
263 }
264 }
265
266 #define ARY_TMPLOCK FL_USER1
267
268 static inline void
rb_ary_modify_check(ary)269 rb_ary_modify_check(ary)
270 VALUE ary;
271 {
272 if (OBJ_FROZEN(ary)) rb_error_frozen("array");
273 if (FL_TEST(ary, ARY_TMPLOCK))
274 rb_raise(rb_eRuntimeError, "can't modify array during iteration");
275 if (!OBJ_TAINTED(ary) && rb_safe_level() >= 4)
276 rb_raise(rb_eSecurityError, "Insecure: can't modify array");
277 }
278
279 static void
rb_ary_modify(ary)280 rb_ary_modify(ary)
281 VALUE ary;
282 {
283 VALUE *ptr;
284
285 rb_ary_modify_check(ary);
286 if (FL_TEST(ary, ELTS_SHARED)) {
287 ptr = ALLOC_N(VALUE, RARRAY(ary)->len);
288 FL_UNSET(ary, ELTS_SHARED);
289 RARRAY(ary)->aux.capa = RARRAY(ary)->len;
290 MEMCPY(ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
291 RARRAY(ary)->ptr = ptr;
292 }
293 }
294
295 VALUE
rb_ary_freeze(ary)296 rb_ary_freeze(ary)
297 VALUE ary;
298 {
299 return rb_obj_freeze(ary);
300 }
301
302 /*
303 * call-seq:
304 * array.frozen? -> true or false
305 *
306 * Return <code>true</code> if this array is frozen (or temporarily frozen
307 * while being sorted).
308 */
309
310 static VALUE
rb_ary_frozen_p(ary)311 rb_ary_frozen_p(ary)
312 VALUE ary;
313 {
314 if (OBJ_FROZEN(ary)) return Qtrue;
315 if (FL_TEST(ary, ARY_TMPLOCK)) return Qtrue;
316 return Qfalse;
317 }
318
319 static VALUE ary_alloc(VALUE);
320 static VALUE
ary_alloc(klass)321 ary_alloc(klass)
322 VALUE klass;
323 {
324 NEWOBJ(ary, struct RArray);
325 OBJSETUP(ary, klass, T_ARRAY);
326
327 ary->len = 0;
328 ary->ptr = 0;
329 ary->aux.capa = 0;
330
331 return (VALUE)ary;
332 }
333
334 static VALUE
ary_new(klass,len)335 ary_new(klass, len)
336 VALUE klass;
337 long len;
338 {
339 VALUE ary;
340
341 if (len < 0) {
342 rb_raise(rb_eArgError, "negative array size (or size too big)");
343 }
344 if (len > 0 && len * sizeof(VALUE) <= len) {
345 rb_raise(rb_eArgError, "array size too big");
346 }
347 if (len == 0) len++;
348
349 ary = ary_alloc(klass);
350 RARRAY(ary)->ptr = ALLOC_N(VALUE, len);
351 RARRAY(ary)->aux.capa = len;
352
353 return ary;
354 }
355
356 VALUE
rb_ary_new2(len)357 rb_ary_new2(len)
358 long len;
359 {
360 return ary_new(rb_cArray, len);
361 }
362
363
364 VALUE
rb_ary_new()365 rb_ary_new()
366 {
367 return rb_ary_new2(ARY_DEFAULT_SIZE);
368 }
369
370 #ifdef HAVE_STDARG_PROTOTYPES
371 #include <stdarg.h>
372 #define va_init_list(a,b) va_start(a,b)
373 #else
374 #include <varargs.h>
375 #define va_init_list(a,b) va_start(a)
376 #endif
377
378 VALUE
379 #ifdef HAVE_STDARG_PROTOTYPES
rb_ary_new3(long n,...)380 rb_ary_new3(long n, ...)
381 #else
382 rb_ary_new3(n, va_alist)
383 long n;
384 va_dcl
385 #endif
386 {
387 va_list ar;
388 VALUE ary;
389 long i;
390
391 ary = rb_ary_new2(n);
392
393 va_init_list(ar, n);
394 for (i=0; i<n; i++) {
395 RARRAY(ary)->ptr[i] = va_arg(ar, VALUE);
396 }
397 va_end(ar);
398
399 RARRAY(ary)->len = n;
400 return ary;
401 }
402
403 VALUE
rb_ary_new4(n,elts)404 rb_ary_new4(n, elts)
405 long n;
406 const VALUE *elts;
407 {
408 VALUE ary;
409
410 ary = rb_ary_new2(n);
411 if (n > 0 && elts) {
412 MEMCPY(RARRAY(ary)->ptr, elts, VALUE, n);
413 }
414 RARRAY(ary)->len = n;
415
416 return ary;
417 }
418
419 VALUE
420 #ifdef HAVE_STDARG_PROTOTYPES
rb_values_new(long n,...)421 rb_values_new(long n, ...)
422 #else
423 rb_values_new(n, va_alist)
424 long n;
425 va_dcl
426 #endif
427 {
428 va_list ar;
429 VALUE val;
430 long i;
431
432 val = ary_new(rb_cValues, n);
433 va_init_list(ar, n);
434 for (i=0; i<n; i++) {
435 RARRAY(val)->ptr[i] = va_arg(ar, VALUE);
436 }
437 va_end(ar);
438 RARRAY(val)->len = n;
439
440 return val;
441 }
442
443 VALUE
rb_values_new2(n,elts)444 rb_values_new2(n, elts)
445 long n;
446 const VALUE *elts;
447 {
448 VALUE val;
449
450 val = ary_new(rb_cValues, n);
451 if (n > 0 && elts) {
452 RARRAY(val)->len = n;
453 MEMCPY(RARRAY(val)->ptr, elts, VALUE, n);
454 }
455
456 return val;
457 }
458
459 static VALUE
ary_make_shared(ary)460 ary_make_shared(ary)
461 VALUE ary;
462 {
463 if (!FL_TEST(ary, ELTS_SHARED)) {
464 NEWOBJ(shared, struct RArray);
465 OBJSETUP(shared, rb_cArray, T_ARRAY);
466
467 shared->len = RARRAY(ary)->len;
468 shared->ptr = RARRAY(ary)->ptr;
469 shared->aux.capa = RARRAY(ary)->aux.capa;
470 RARRAY(ary)->aux.shared = (VALUE)shared;
471 FL_SET(ary, ELTS_SHARED);
472 OBJ_FREEZE(shared);
473 return (VALUE)shared;
474 }
475 else {
476 return RARRAY(ary)->aux.shared;
477 }
478 }
479
480 static VALUE
ary_shared_array(klass,ary)481 ary_shared_array(klass, ary)
482 VALUE klass, ary;
483 {
484 VALUE val = ary_alloc(klass);
485
486 ary_make_shared(ary);
487 RARRAY(val)->ptr = RARRAY(ary)->ptr;
488 RARRAY(val)->len = RARRAY(ary)->len;
489 RARRAY(val)->aux.shared = RARRAY(ary)->aux.shared;
490 FL_SET(val, ELTS_SHARED);
491 return val;
492 }
493
494 VALUE
rb_values_from_ary(ary)495 rb_values_from_ary(ary)
496 VALUE ary;
497 {
498 return ary_shared_array(rb_cValues, ary);
499 }
500
501 VALUE
rb_ary_from_values(val)502 rb_ary_from_values(val)
503 VALUE val;
504 {
505 return ary_shared_array(rb_cArray, val);
506 }
507
508 VALUE
rb_assoc_new(car,cdr)509 rb_assoc_new(car, cdr)
510 VALUE car, cdr;
511 {
512 return rb_values_new(2, car, cdr);
513 }
514
515 static VALUE
to_ary(ary)516 to_ary(ary)
517 VALUE ary;
518 {
519 return rb_convert_type(ary, T_ARRAY, "Array", "to_ary");
520 }
521
522 static VALUE
to_a(ary)523 to_a(ary)
524 VALUE ary;
525 {
526 return rb_convert_type(ary, T_ARRAY, "Array", "to_a");
527 }
528
529 VALUE
rb_check_array_type(ary)530 rb_check_array_type(ary)
531 VALUE ary;
532 {
533 return rb_check_convert_type(ary, T_ARRAY, "Array", "to_ary");
534 }
535
536 static VALUE rb_ary_replace _((VALUE, VALUE));
537
538 /*
539 * call-seq:
540 * Array.new(size=0, obj=nil)
541 * Array.new(array)
542 * Array.new(size) {|index| block }
543 *
544 * Returns a new array. In the first form, the new array is
545 * empty. In the second it is created with _size_ copies of _obj_
546 * (that is, _size_ references to the same
547 * _obj_). The third form creates a copy of the array
548 * passed as a parameter (the array is generated by calling
549 * to_ary on the parameter). In the last form, an array
550 * of the given size is created. Each element in this array is
551 * calculated by passing the element's index to the given block and
552 * storing the return value.
553 *
554 * Array.new
555 * Array.new(2)
556 * Array.new(5, "A")
557 *
558 * # only one copy of the object is created
559 * a = Array.new(2, Hash.new)
560 * a[0]['cat'] = 'feline'
561 * a
562 * a[1]['cat'] = 'Felix'
563 * a
564 *
565 * # here multiple copies are created
566 * a = Array.new(2) { Hash.new }
567 * a[0]['cat'] = 'feline'
568 * a
569 *
570 * squares = Array.new(5) {|i| i*i}
571 * squares
572 *
573 * copy = Array.new(squares)
574 */
575
576 static VALUE
rb_ary_initialize(argc,argv,ary)577 rb_ary_initialize(argc, argv, ary)
578 int argc;
579 VALUE *argv;
580 VALUE ary;
581 {
582 long len;
583 VALUE size, val;
584
585 if (rb_scan_args(argc, argv, "02", &size, &val) == 0) {
586 RARRAY(ary)->len = 0;
587 if (rb_block_given_p()) {
588 rb_warning("given block not used");
589 }
590 return ary;
591 }
592
593 if (argc == 1 && !FIXNUM_P(size)) {
594 val = rb_check_array_type(size);
595 if (!NIL_P(val)) {
596 rb_ary_replace(ary, val);
597 return ary;
598 }
599 }
600
601 len = NUM2LONG(size);
602 if (len < 0) {
603 rb_raise(rb_eArgError, "negative array size");
604 }
605 if (len > 0 && len * (long)sizeof(VALUE) <= len) {
606 rb_raise(rb_eArgError, "array size too big");
607 }
608 rb_ary_modify(ary);
609 if (len > RARRAY(ary)->aux.capa) {
610 REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
611 RARRAY(ary)->aux.capa = len;
612 }
613 if (rb_block_given_p()) {
614 long i;
615
616 if (argc == 2) {
617 rb_warn("block supersedes default value argument");
618 }
619 for (i=0; i<len; i++) {
620 rb_ary_store(ary, i, rb_yield(LONG2NUM(i)));
621 RARRAY(ary)->len = i + 1;
622 }
623 }
624 else {
625 memfill(RARRAY(ary)->ptr, len, val);
626 RARRAY(ary)->len = len;
627 }
628
629 return ary;
630 }
631
632
633 /*
634 * Returns a new array populated with the given objects.
635 *
636 * Array.[]( 1, 'a', /^A/ )
637 * Array[ 1, 'a', /^A/ ]
638 * [ 1, 'a', /^A/ ]
639 */
640
641 static VALUE
rb_ary_s_create(argc,argv,klass)642 rb_ary_s_create(argc, argv, klass)
643 int argc;
644 VALUE *argv;
645 VALUE klass;
646 {
647 VALUE ary = ary_alloc(klass);
648
649 if (argc > 0) {
650 RARRAY(ary)->ptr = ALLOC_N(VALUE, argc);
651 MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
652 }
653 RARRAY(ary)->len = RARRAY(ary)->aux.capa = argc;
654
655 return ary;
656 }
657
658 void
rb_ary_store(ary,idx,val)659 rb_ary_store(ary, idx, val)
660 VALUE ary;
661 long idx;
662 VALUE val;
663 {
664 if (idx < 0) {
665 idx += RARRAY(ary)->len;
666 if (idx < 0) {
667 rb_raise(rb_eIndexError, "index %ld out of array",
668 idx - RARRAY(ary)->len);
669 }
670 }
671
672 rb_ary_modify(ary);
673 if (idx >= RARRAY(ary)->aux.capa) {
674 long new_capa = RARRAY(ary)->aux.capa / 2;
675
676 if (new_capa < ARY_DEFAULT_SIZE) {
677 new_capa = ARY_DEFAULT_SIZE;
678 }
679 new_capa += idx;
680 if (new_capa * (long)sizeof(VALUE) <= new_capa) {
681 rb_raise(rb_eArgError, "index too big");
682 }
683 REALLOC_N(RARRAY(ary)->ptr, VALUE, new_capa);
684 RARRAY(ary)->aux.capa = new_capa;
685 }
686 if (idx > RARRAY(ary)->len) {
687 rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len,
688 idx-RARRAY(ary)->len + 1);
689 }
690
691 if (idx >= RARRAY(ary)->len) {
692 RARRAY(ary)->len = idx + 1;
693 }
694 RARRAY(ary)->ptr[idx] = val;
695 }
696
697 static VALUE
ary_shared_first(argc,argv,ary)698 ary_shared_first(argc, argv, ary)
699 int argc;
700 VALUE *argv;
701 VALUE ary;
702 {
703 VALUE nv, result;
704 long n;
705
706 rb_scan_args(argc, argv, "1", &nv);
707 n = NUM2LONG(nv);
708 if (n > RARRAY(ary)->len) {
709 n = RARRAY(ary)->len;
710 }
711 else if (n < 0) {
712 rb_raise(rb_eArgError, "negative array size");
713 }
714 result = ary_shared_array(rb_cArray, ary);
715 RARRAY(result)->len = n;
716 return result;
717 }
718
719 static VALUE
ary_shared_last(argc,argv,ary)720 ary_shared_last(argc, argv, ary)
721 int argc;
722 VALUE *argv;
723 VALUE ary;
724 {
725 VALUE result = ary_shared_first(argc, argv, ary);
726
727 RARRAY(result)->ptr += RARRAY(ary)->len - RARRAY(result)->len;
728 return result;
729 }
730
731 /*
732 * call-seq:
733 * array << obj -> array
734 *
735 * Append---Pushes the given object on to the end of this array. This
736 * expression returns the array itself, so several appends
737 * may be chained together.
738 *
739 * [ 1, 2 ] << "c" << "d" << [ 3, 4 ]
740 * #=> [ 1, 2, "c", "d", [ 3, 4 ] ]
741 *
742 */
743
744 VALUE
rb_ary_push(ary,item)745 rb_ary_push(ary, item)
746 VALUE ary;
747 VALUE item;
748 {
749 rb_ary_store(ary, RARRAY(ary)->len, item);
750 return ary;
751 }
752
753 /*
754 * call-seq:
755 * array.push(obj, ... ) -> array
756 *
757 * Append---Pushes the given object(s) on to the end of this array. This
758 * expression returns the array itself, so several appends
759 * may be chained together.
760 *
761 * a = [ "a", "b", "c" ]
762 * a.push("d", "e", "f")
763 * #=> ["a", "b", "c", "d", "e", "f"]
764 */
765
766 static VALUE
rb_ary_push_m(argc,argv,ary)767 rb_ary_push_m(argc, argv, ary)
768 int argc;
769 VALUE *argv;
770 VALUE ary;
771 {
772 while (argc--) {
773 rb_ary_push(ary, *argv++);
774 }
775 return ary;
776 }
777
778 VALUE
rb_ary_pop(ary)779 rb_ary_pop(ary)
780 VALUE ary;
781 {
782 rb_ary_modify_check(ary);
783 if (RARRAY(ary)->len == 0) return Qnil;
784 if (!FL_TEST(ary, ELTS_SHARED) &&
785 RARRAY(ary)->len * 2 < RARRAY(ary)->aux.capa &&
786 RARRAY(ary)->aux.capa > ARY_DEFAULT_SIZE) {
787 RARRAY(ary)->aux.capa = RARRAY(ary)->len * 2;
788 REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
789 }
790 return RARRAY(ary)->ptr[--RARRAY(ary)->len];
791 }
792
793 /*
794 * call-seq:
795 * array.pop -> obj or nil
796 *
797 * Removes the last element from <i>self</i> and returns it, or
798 * <code>nil</code> if the array is empty.
799 *
800 * a = [ "a", "b", "c", "d" ]
801 * a.pop #=> "d"
802 * a.pop(2) #=> ["b", "c"]
803 * a #=> ["a"]
804 */
805
806 static VALUE
rb_ary_pop_m(argc,argv,ary)807 rb_ary_pop_m(argc, argv, ary)
808 int argc;
809 VALUE *argv;
810 VALUE ary;
811 {
812 VALUE result;
813
814 if (argc == 0) {
815 return rb_ary_pop(ary);
816 }
817
818 rb_ary_modify_check(ary);
819
820 result = ary_shared_last(argc, argv, ary);
821 RARRAY(ary)->len -= RARRAY(result)->len;
822 return result;
823 }
824
825 VALUE
rb_ary_shift(ary)826 rb_ary_shift(ary)
827 VALUE ary;
828 {
829 VALUE top;
830
831 rb_ary_modify_check(ary);
832 if (RARRAY(ary)->len == 0) return Qnil;
833 top = RARRAY(ary)->ptr[0];
834 ary_make_shared(ary);
835 RARRAY(ary)->ptr++; /* shift ptr */
836 RARRAY(ary)->len--;
837
838 return top;
839 }
840
841 /*
842 * call-seq:
843 * array.shift -> obj or nil
844 *
845 * Returns the first element of <i>self</i> and removes it (shifting all
846 * other elements down by one). Returns <code>nil</code> if the array
847 * is empty.
848 *
849 * args = [ "-m", "-q", "filename" ]
850 * args.shift #=> "-m"
851 * args #=> ["-q", "filename"]
852 *
853 * args = [ "-m", "-q", "filename" ]
854 * args.shift(2) #=> ["-m", "-q"]
855 * args #=> ["filename"]
856 */
857
858 static VALUE
rb_ary_shift_m(argc,argv,ary)859 rb_ary_shift_m(argc, argv, ary)
860 int argc;
861 VALUE *argv;
862 VALUE ary;
863 {
864 VALUE result;
865 long n;
866
867 if (argc == 0) {
868 return rb_ary_shift(ary);
869 }
870
871 rb_ary_modify_check(ary);
872
873 result = ary_shared_first(argc, argv, ary);
874 n = RARRAY(result)->len;
875 RARRAY(ary)->ptr += n;
876 RARRAY(ary)->len -= n;
877
878 return result;
879 }
880
881 VALUE
rb_ary_unshift(ary,item)882 rb_ary_unshift(ary, item)
883 VALUE ary, item;
884 {
885 rb_ary_modify(ary);
886 if (RARRAY(ary)->len == RARRAY(ary)->aux.capa) {
887 long capa_inc = RARRAY(ary)->aux.capa / 2;
888 if (capa_inc < ARY_DEFAULT_SIZE) {
889 capa_inc = ARY_DEFAULT_SIZE;
890 }
891 RARRAY(ary)->aux.capa += capa_inc;
892 REALLOC_N(RARRAY(ary)->ptr, VALUE, RARRAY(ary)->aux.capa);
893 }
894
895 /* sliding items */
896 MEMMOVE(RARRAY(ary)->ptr + 1, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
897
898 RARRAY(ary)->len++;
899 RARRAY(ary)->ptr[0] = item;
900
901 return ary;
902 }
903
904 /*
905 * call-seq:
906 * array.unshift(obj, ...) -> array
907 *
908 * Prepends objects to the front of <i>array</i>.
909 * other elements up one.
910 *
911 * a = [ "b", "c", "d" ]
912 * a.unshift("a") #=> ["a", "b", "c", "d"]
913 * a.unshift(1, 2) #=> [ 1, 2, "a", "b", "c", "d"]
914 */
915
916 static VALUE
rb_ary_unshift_m(argc,argv,ary)917 rb_ary_unshift_m(argc, argv, ary)
918 int argc;
919 VALUE *argv;
920 VALUE ary;
921 {
922 long len = RARRAY(ary)->len;
923
924 if (argc == 0) return ary;
925
926 /* make rooms by setting the last item */
927 rb_ary_store(ary, len + argc - 1, Qnil);
928
929 /* sliding items */
930 MEMMOVE(RARRAY(ary)->ptr + argc, RARRAY(ary)->ptr, VALUE, len);
931 MEMCPY(RARRAY(ary)->ptr, argv, VALUE, argc);
932
933 return ary;
934 }
935
936 /* faster version - use this if you don't need to treat negative offset */
937 static inline VALUE
rb_ary_elt(ary,offset)938 rb_ary_elt(ary, offset)
939 VALUE ary;
940 long offset;
941 {
942 if (RARRAY(ary)->len == 0) return Qnil;
943 if (offset < 0 || RARRAY(ary)->len <= offset) {
944 return Qnil;
945 }
946 return RARRAY(ary)->ptr[offset];
947 }
948
949 VALUE
rb_ary_entry(ary,offset)950 rb_ary_entry(ary, offset)
951 VALUE ary;
952 long offset;
953 {
954 if (offset < 0) {
955 offset += RARRAY(ary)->len;
956 }
957 return rb_ary_elt(ary, offset);
958 }
959
960 static VALUE
rb_ary_subseq(ary,beg,len)961 rb_ary_subseq(ary, beg, len)
962 VALUE ary;
963 long beg, len;
964 {
965 VALUE klass, ary2, shared;
966 VALUE *ptr;
967
968 if (beg > RARRAY(ary)->len) return Qnil;
969 if (beg < 0 || len < 0) return Qnil;
970
971 if (beg + len > RARRAY(ary)->len) {
972 len = RARRAY(ary)->len - beg;
973 if (len < 0)
974 len = 0;
975 }
976 klass = rb_obj_class(ary);
977 if (len == 0) return ary_new(klass, 0);
978
979 shared = ary_make_shared(ary);
980 ptr = RARRAY(ary)->ptr;
981 ary2 = ary_alloc(klass);
982 RARRAY(ary2)->ptr = ptr + beg;
983 RARRAY(ary2)->len = len;
984 RARRAY(ary2)->aux.shared = shared;
985 FL_SET(ary2, ELTS_SHARED);
986
987 return ary2;
988 }
989
990 /*
991 * call-seq:
992 * array[index] -> obj or nil
993 * array[start, length] -> an_array or nil
994 * array[range] -> an_array or nil
995 * array.slice(index) -> obj or nil
996 * array.slice(start, length) -> an_array or nil
997 * array.slice(range) -> an_array or nil
998 *
999 * Element Reference---Returns the element at _index_,
1000 * or returns a subarray starting at _start_ and
1001 * continuing for _length_ elements, or returns a subarray
1002 * specified by _range_.
1003 * Negative indices count backward from the end of the
1004 * array (-1 is the last element). Returns nil if the index
1005 * (or starting index) are out of range.
1006 *
1007 * a = [ "a", "b", "c", "d", "e" ]
1008 * a[2] + a[0] + a[1] #=> "cab"
1009 * a[6] #=> nil
1010 * a[1, 2] #=> [ "b", "c" ]
1011 * a[1..3] #=> [ "b", "c", "d" ]
1012 * a[4..7] #=> [ "e" ]
1013 * a[6..10] #=> nil
1014 * a[-3, 3] #=> [ "c", "d", "e" ]
1015 * # special cases
1016 * a[5] #=> nil
1017 * a[5, 1] #=> []
1018 * a[5..10] #=> []
1019 *
1020 */
1021
1022 VALUE
rb_ary_aref(argc,argv,ary)1023 rb_ary_aref(argc, argv, ary)
1024 int argc;
1025 VALUE *argv;
1026 VALUE ary;
1027 {
1028 VALUE arg;
1029 long beg, len;
1030
1031 if (argc == 2) {
1032 beg = NUM2LONG(argv[0]);
1033 len = NUM2LONG(argv[1]);
1034 if (beg < 0) {
1035 beg += RARRAY(ary)->len;
1036 }
1037 return rb_ary_subseq(ary, beg, len);
1038 }
1039 if (argc != 1) {
1040 rb_scan_args(argc, argv, "11", 0, 0);
1041 }
1042 arg = argv[0];
1043 /* special case - speeding up */
1044 if (FIXNUM_P(arg)) {
1045 return rb_ary_entry(ary, FIX2LONG(arg));
1046 }
1047 /* check if idx is Range */
1048 switch (rb_range_beg_len(arg, &beg, &len, RARRAY(ary)->len, 0)) {
1049 case Qfalse:
1050 break;
1051 case Qnil:
1052 return Qnil;
1053 default:
1054 return rb_ary_subseq(ary, beg, len);
1055 }
1056 return rb_ary_entry(ary, NUM2LONG(arg));
1057 }
1058
1059 /*
1060 * call-seq:
1061 * array.at(index) -> obj or nil
1062 *
1063 * Returns the element at _index_. A
1064 * negative index counts from the end of _self_. Returns +nil+
1065 * if the index is out of range. See also <code>Array#[]</code>.
1066 * (<code>Array#at</code> is slightly faster than <code>Array#[]</code>,
1067 * as it does not accept ranges and so on.)
1068 *
1069 * a = [ "a", "b", "c", "d", "e" ]
1070 * a.at(0) #=> "a"
1071 * a.at(-1) #=> "e"
1072 */
1073
1074 static VALUE
rb_ary_at(ary,pos)1075 rb_ary_at(ary, pos)
1076 VALUE ary, pos;
1077 {
1078 return rb_ary_entry(ary, NUM2LONG(pos));
1079 }
1080
1081 /*
1082 * call-seq:
1083 * array.first -> obj or nil
1084 * array.first(n) -> an_array
1085 *
1086 * Returns the first element of the array. If the array is empty,
1087 * returns <code>nil</code>.
1088 *
1089 * a = [ "q", "r", "s", "t" ]
1090 * a.first #=> "q"
1091 * a.first(2) #=> ["q", "r"]
1092 */
1093
1094 static VALUE
rb_ary_first(argc,argv,ary)1095 rb_ary_first(argc, argv, ary)
1096 int argc;
1097 VALUE *argv;
1098 VALUE ary;
1099 {
1100 if (argc == 0) {
1101 if (RARRAY(ary)->len == 0) return Qnil;
1102 return RARRAY(ary)->ptr[0];
1103 }
1104 else {
1105 return ary_shared_first(argc, argv, ary);
1106 }
1107 }
1108
1109 /*
1110 * call-seq:
1111 * array.last -> obj or nil
1112 * array.last(n) -> an_array
1113 *
1114 * Returns the last element(s) of <i>self</i>. If the array is empty,
1115 * the first form returns <code>nil</code>.
1116 *
1117 * a = [ "w", "x", "y", "z" ]
1118 * a.last #=> "z"
1119 * a.last(2) #=> ["y", "z"]
1120 */
1121
1122 static VALUE
rb_ary_last(argc,argv,ary)1123 rb_ary_last(argc, argv, ary)
1124 int argc;
1125 VALUE *argv;
1126 VALUE ary;
1127 {
1128 if (argc == 0) {
1129 if (RARRAY(ary)->len == 0) return Qnil;
1130 return RARRAY(ary)->ptr[RARRAY(ary)->len-1];
1131 }
1132 else {
1133 return ary_shared_last(argc, argv, ary);
1134 }
1135 }
1136
1137 /*
1138 * call-seq:
1139 * array.fetch(index) -> obj
1140 * array.fetch(index, default ) -> obj
1141 * array.fetch(index) {|index| block } -> obj
1142 *
1143 * Tries to return the element at position <i>index</i>. If the index
1144 * lies outside the array, the first form throws an
1145 * <code>IndexError</code> exception, the second form returns
1146 * <i>default</i>, and the third form returns the value of invoking
1147 * the block, passing in the index. Negative values of <i>index</i>
1148 * count from the end of the array.
1149 *
1150 * a = [ 11, 22, 33, 44 ]
1151 * a.fetch(1) #=> 22
1152 * a.fetch(-1) #=> 44
1153 * a.fetch(4, 'cat') #=> "cat"
1154 * a.fetch(4) { |i| i*i } #=> 16
1155 */
1156
1157 static VALUE
rb_ary_fetch(argc,argv,ary)1158 rb_ary_fetch(argc, argv, ary)
1159 int argc;
1160 VALUE *argv;
1161 VALUE ary;
1162 {
1163 VALUE pos, ifnone;
1164 long block_given;
1165 long idx;
1166
1167 rb_scan_args(argc, argv, "11", &pos, &ifnone);
1168 block_given = rb_block_given_p();
1169 if (block_given && argc == 2) {
1170 rb_warn("block supersedes default value argument");
1171 }
1172 idx = NUM2LONG(pos);
1173
1174 if (idx < 0) {
1175 idx += RARRAY(ary)->len;
1176 }
1177 if (idx < 0 || RARRAY(ary)->len <= idx) {
1178 if (block_given) return rb_yield(pos);
1179 if (argc == 1) {
1180 rb_raise(rb_eIndexError, "index %ld out of array", idx);
1181 }
1182 return ifnone;
1183 }
1184 return RARRAY(ary)->ptr[idx];
1185 }
1186
1187 /*
1188 * call-seq:
1189 * array.index(obj) -> int or nil
1190 * array.index {|item| block} -> int or nil
1191 *
1192 * Returns the index of the first object in <i>self</i> such that is
1193 * <code>==</code> to <i>obj</i>. If a block is given instead of an
1194 * argument, returns first object for which <em>block</em> is true.
1195 * Returns <code>nil</code> if no match is found.
1196 *
1197 * a = [ "a", "b", "c" ]
1198 * a.index("b") #=> 1
1199 * a.index("z") #=> nil
1200 * a.index{|x|x=="b"} #=> 1
1201 */
1202
1203 static VALUE
rb_ary_index(argc,argv,ary)1204 rb_ary_index(argc, argv, ary)
1205 int argc;
1206 VALUE *argv;
1207 VALUE ary;
1208 {
1209 VALUE val;
1210 long i;
1211
1212 if (rb_scan_args(argc, argv, "01", &val) == 0) {
1213 for (i=0; i<RARRAY(ary)->len; i++) {
1214 if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) {
1215 return LONG2NUM(i);
1216 }
1217 }
1218 }
1219 else {
1220 for (i=0; i<RARRAY(ary)->len; i++) {
1221 if (rb_equal(RARRAY(ary)->ptr[i], val))
1222 return LONG2NUM(i);
1223 }
1224 }
1225 return Qnil;
1226 }
1227
1228 /*
1229 * call-seq:
1230 * array.rindex(obj) -> int or nil
1231 *
1232 * Returns the index of the last object in <i>array</i>
1233 * <code>==</code> to <i>obj</i>. If a block is given instead of an
1234 * argument, returns first object for which <em>block</em> is
1235 * true. Returns <code>nil</code> if no match is found.
1236 *
1237 * a = [ "a", "b", "b", "b", "c" ]
1238 * a.rindex("b") #=> 3
1239 * a.rindex("z") #=> nil
1240 * a.rindex{|x|x=="b"} #=> 3
1241 */
1242
1243 static VALUE
rb_ary_rindex(argc,argv,ary)1244 rb_ary_rindex(argc, argv, ary)
1245 int argc;
1246 VALUE *argv;
1247 VALUE ary;
1248 {
1249 VALUE val;
1250 long i = RARRAY(ary)->len;
1251
1252 if (rb_scan_args(argc, argv, "01", &val) == 0) {
1253 while (i--) {
1254 if (RTEST(rb_yield(RARRAY(ary)->ptr[i])))
1255 return LONG2NUM(i);
1256 if (i > RARRAY(ary)->len) {
1257 i = RARRAY(ary)->len;
1258 }
1259 }
1260 }
1261 else {
1262 while (i--) {
1263 if (rb_equal(RARRAY(ary)->ptr[i], val))
1264 return LONG2NUM(i);
1265 if (i > RARRAY(ary)->len) {
1266 i = RARRAY(ary)->len;
1267 }
1268 }
1269 }
1270 return Qnil;
1271 }
1272
1273 VALUE
rb_ary_to_ary(obj)1274 rb_ary_to_ary(obj)
1275 VALUE obj;
1276 {
1277 if (TYPE(obj) == T_ARRAY) {
1278 return obj;
1279 }
1280 if (rb_respond_to(obj, rb_intern("to_ary"))) {
1281 return to_ary(obj);
1282 }
1283 return rb_ary_new3(1, obj);
1284 }
1285
1286 static void
rb_ary_splice(ary,beg,len,rpl)1287 rb_ary_splice(ary, beg, len, rpl)
1288 VALUE ary;
1289 long beg, len;
1290 VALUE rpl;
1291 {
1292 long rlen;
1293
1294 if (len < 0) rb_raise(rb_eIndexError, "negative length (%ld)", len);
1295 if (beg < 0) {
1296 beg += RARRAY(ary)->len;
1297 if (beg < 0) {
1298 beg -= RARRAY(ary)->len;
1299 rb_raise(rb_eIndexError, "index %ld out of array", beg);
1300 }
1301 }
1302 if (beg + len > RARRAY(ary)->len) {
1303 len = RARRAY(ary)->len - beg;
1304 }
1305
1306 if (rpl == Qundef) {
1307 rlen = 0;
1308 }
1309 else {
1310 rpl = rb_ary_to_ary(rpl);
1311 rlen = RARRAY(rpl)->len;
1312 }
1313 rb_ary_modify(ary);
1314
1315 if (beg >= RARRAY(ary)->len) {
1316 len = beg + rlen;
1317 if (len >= RARRAY(ary)->aux.capa) {
1318 REALLOC_N(RARRAY(ary)->ptr, VALUE, len);
1319 RARRAY(ary)->aux.capa = len;
1320 }
1321 rb_mem_clear(RARRAY(ary)->ptr + RARRAY(ary)->len, beg - RARRAY(ary)->len);
1322 if (rlen > 0) {
1323 MEMCPY(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
1324 }
1325 RARRAY(ary)->len = len;
1326 }
1327 else {
1328 long alen;
1329
1330 if (beg + len > RARRAY(ary)->len) {
1331 len = RARRAY(ary)->len - beg;
1332 }
1333
1334 alen = RARRAY(ary)->len + rlen - len;
1335 if (alen >= RARRAY(ary)->aux.capa) {
1336 REALLOC_N(RARRAY(ary)->ptr, VALUE, alen);
1337 RARRAY(ary)->aux.capa = alen;
1338 }
1339
1340 if (len != rlen) {
1341 MEMMOVE(RARRAY(ary)->ptr + beg + rlen, RARRAY(ary)->ptr + beg + len,
1342 VALUE, RARRAY(ary)->len - (beg + len));
1343 RARRAY(ary)->len = alen;
1344 }
1345 if (rlen > 0) {
1346 MEMMOVE(RARRAY(ary)->ptr + beg, RARRAY(rpl)->ptr, VALUE, rlen);
1347 }
1348 }
1349 }
1350
1351 /*
1352 * call-seq:
1353 * array[index] = obj -> obj
1354 * array[start, length] = obj or an_array or nil -> obj or an_array or nil
1355 * array[range] = obj or an_array or nil -> obj or an_array or nil
1356 *
1357 * Element Assignment---Sets the element at _index_,
1358 * or replaces a subarray starting at _start_ and
1359 * continuing for _length_ elements, or replaces a subarray
1360 * specified by _range_. If indices are greater than
1361 * the current capacity of the array, the array grows
1362 * automatically. A negative indices will count backward
1363 * from the end of the array. Inserts elements if _length_ is
1364 * zero. An +IndexError+ is raised if a negative index points
1365 * past the beginning of the array. See also
1366 * <code>Array#push</code>, and <code>Array#unshift</code>.
1367 *
1368 * a = Array.new
1369 * a[4] = "4"; #=> [nil, nil, nil, nil, "4"]
1370 * a[0, 3] = [ 'a', 'b', 'c' ] #=> ["a", "b", "c", nil, "4"]
1371 * a[1..2] = [ 1, 2 ] #=> ["a", 1, 2, nil, "4"]
1372 * a[0, 2] = "?" #=> ["?", 2, nil, "4"]
1373 * a[0..2] = "A" #=> ["A", "4"]
1374 * a[-1] = "Z" #=> ["A", "Z"]
1375 * a[1..-1] = nil #=> ["A", nil]
1376 * a[1..-1] = [] #=> ["A"]
1377 */
1378
1379 static VALUE
rb_ary_aset(argc,argv,ary)1380 rb_ary_aset(argc, argv, ary)
1381 int argc;
1382 VALUE *argv;
1383 VALUE ary;
1384 {
1385 long offset, beg, len;
1386
1387 if (argc == 3) {
1388 rb_ary_splice(ary, NUM2LONG(argv[0]), NUM2LONG(argv[1]), argv[2]);
1389 return argv[2];
1390 }
1391 if (argc != 2) {
1392 rb_raise(rb_eArgError, "wrong number of arguments (%d for 2)", argc);
1393 }
1394 if (FIXNUM_P(argv[0])) {
1395 offset = FIX2LONG(argv[0]);
1396 goto fixnum;
1397 }
1398 if (rb_range_beg_len(argv[0], &beg, &len, RARRAY(ary)->len, 1)) {
1399 /* check if idx is Range */
1400 rb_ary_splice(ary, beg, len, argv[1]);
1401 return argv[1];
1402 }
1403
1404 offset = NUM2LONG(argv[0]);
1405 fixnum:
1406 rb_ary_store(ary, offset, argv[1]);
1407 return argv[1];
1408 }
1409
1410 /*
1411 * call-seq:
1412 * array.insert(index, obj...) -> array
1413 *
1414 * Inserts the given values before the element with the given index
1415 * (which may be negative).
1416 *
1417 * a = %w{ a b c d }
1418 * a.insert(2, 99) #=> ["a", "b", 99, "c", "d"]
1419 * a.insert(-2, 1, 2, 3) #=> ["a", "b", 99, "c", 1, 2, 3, "d"]
1420 */
1421
1422 static VALUE
rb_ary_insert(argc,argv,ary)1423 rb_ary_insert(argc, argv, ary)
1424 int argc;
1425 VALUE *argv;
1426 VALUE ary;
1427 {
1428 long pos;
1429
1430 if (argc < 1) {
1431 rb_raise(rb_eArgError, "wrong number of arguments (at least 1)");
1432 }
1433 pos = NUM2LONG(argv[0]);
1434 if (pos == -1) {
1435 pos = RARRAY(ary)->len;
1436 }
1437 else if (pos < 0) {
1438 pos++;
1439 }
1440
1441 if (argc == 1) return ary;
1442 rb_ary_splice(ary, pos, 0, rb_ary_new4(argc - 1, argv + 1));
1443 return ary;
1444 }
1445
1446 /*
1447 * call-seq:
1448 * array.each {|item| block } -> array
1449 *
1450 * Calls <i>block</i> once for each element in <i>self</i>, passing that
1451 * element as a parameter.
1452 *
1453 * a = [ "a", "b", "c" ]
1454 * a.each {|x| print x, " -- " }
1455 *
1456 * produces:
1457 *
1458 * a -- b -- c --
1459 */
1460
1461 VALUE
rb_ary_each(ary)1462 rb_ary_each(ary)
1463 VALUE ary;
1464 {
1465 long i;
1466
1467 for (i=0; i<RARRAY(ary)->len; i++) {
1468 rb_yield(RARRAY(ary)->ptr[i]);
1469 }
1470 return ary;
1471 }
1472
1473 /*
1474 * call-seq:
1475 * array.each_index {|index| block } -> array
1476 *
1477 * Same as <code>Array#each</code>, but passes the index of the element
1478 * instead of the element itself.
1479 *
1480 * a = [ "a", "b", "c" ]
1481 * a.each_index {|x| print x, " -- " }
1482 *
1483 * produces:
1484 *
1485 * 0 -- 1 -- 2 --
1486 */
1487
1488 static VALUE
rb_ary_each_index(ary)1489 rb_ary_each_index(ary)
1490 VALUE ary;
1491 {
1492 long i;
1493
1494 for (i=0; i<RARRAY(ary)->len; i++) {
1495 rb_yield(LONG2NUM(i));
1496 }
1497 return ary;
1498 }
1499
1500 /*
1501 * call-seq:
1502 * array.reverse_each {|item| block }
1503 *
1504 * Same as <code>Array#each</code>, but traverses <i>self</i> in reverse
1505 * order.
1506 *
1507 * a = [ "a", "b", "c" ]
1508 * a.reverse_each {|x| print x, " " }
1509 *
1510 * produces:
1511 *
1512 * c b a
1513 */
1514
1515 static VALUE
rb_ary_reverse_each(ary)1516 rb_ary_reverse_each(ary)
1517 VALUE ary;
1518 {
1519 long len = RARRAY(ary)->len;
1520
1521 while (len--) {
1522 rb_yield(RARRAY(ary)->ptr[len]);
1523 if (RARRAY(ary)->len < len) {
1524 len = RARRAY(ary)->len;
1525 }
1526 }
1527 return ary;
1528 }
1529
1530 /*
1531 * call-seq:
1532 * array.length -> int
1533 *
1534 * Returns the number of elements in <i>self</i>. May be zero.
1535 *
1536 * [ 1, 2, 3, 4, 5 ].length #=> 5
1537 */
1538
1539 static VALUE
rb_ary_length(ary)1540 rb_ary_length(ary)
1541 VALUE ary;
1542 {
1543 return LONG2NUM(RARRAY(ary)->len);
1544 }
1545
1546 /*
1547 * call-seq:
1548 * array.empty? -> true or false
1549 *
1550 * Returns <code>true</code> if <i>self</i> array contains no elements.
1551 *
1552 * [].empty? #=> true
1553 */
1554
1555 static VALUE
rb_ary_empty_p(ary)1556 rb_ary_empty_p(ary)
1557 VALUE ary;
1558 {
1559 if (RARRAY(ary)->len == 0)
1560 return Qtrue;
1561 return Qfalse;
1562 }
1563
1564 VALUE
rb_ary_dup(ary)1565 rb_ary_dup(ary)
1566 VALUE ary;
1567 {
1568 VALUE dup = rb_ary_new2(RARRAY(ary)->len);
1569
1570 DUPSETUP(dup, ary);
1571 MEMCPY(RARRAY(dup)->ptr, RARRAY(ary)->ptr, VALUE, RARRAY(ary)->len);
1572 RARRAY(dup)->len = RARRAY(ary)->len;
1573 return dup;
1574 }
1575
1576 extern VALUE rb_output_fs;
1577
1578 static VALUE
recursive_join(ary,arg,recur)1579 recursive_join(ary, arg, recur)
1580 VALUE ary;
1581 VALUE *arg;
1582 int recur;
1583 {
1584 if (recur) {
1585 return rb_str_new2("[...]");
1586 }
1587 return rb_ary_join(arg[0], arg[1]);
1588 }
1589
1590 VALUE
rb_ary_join(ary,sep)1591 rb_ary_join(ary, sep)
1592 VALUE ary, sep;
1593 {
1594 long len = 1, i;
1595 int taint = Qfalse;
1596 VALUE result, tmp;
1597
1598 if (RARRAY(ary)->len == 0) return rb_str_new(0, 0);
1599 if (OBJ_TAINTED(ary) || OBJ_TAINTED(sep)) taint = Qtrue;
1600
1601 for (i=0; i<RARRAY(ary)->len; i++) {
1602 tmp = rb_check_string_type(RARRAY(ary)->ptr[i]);
1603 len += NIL_P(tmp) ? 10 : RSTRING(tmp)->len;
1604 }
1605 if (!NIL_P(sep)) {
1606 StringValue(sep);
1607 len += RSTRING(sep)->len * (RARRAY(ary)->len - 1);
1608 }
1609 result = rb_str_buf_new(len);
1610 for (i=0; i<RARRAY(ary)->len; i++) {
1611 tmp = RARRAY(ary)->ptr[i];
1612 switch (TYPE(tmp)) {
1613 case T_STRING:
1614 break;
1615 case T_ARRAY:
1616 {
1617 VALUE args[2];
1618
1619 args[0] = tmp;
1620 args[1] = sep;
1621 tmp = rb_exec_recursive(recursive_join, ary, (VALUE)args);
1622 }
1623 break;
1624 default:
1625 tmp = rb_obj_as_string(tmp);
1626 }
1627 if (i > 0 && !NIL_P(sep))
1628 rb_str_buf_append(result, sep);
1629 rb_str_buf_append(result, tmp);
1630 if (OBJ_TAINTED(tmp)) taint = Qtrue;
1631 }
1632
1633 if (taint) OBJ_TAINT(result);
1634 return result;
1635 }
1636
1637 /*
1638 * call-seq:
1639 * array.join(sep=$,) -> str
1640 *
1641 * Returns a string created by converting each element of the array to
1642 * a string, separated by <i>sep</i>.
1643 *
1644 * [ "a", "b", "c" ].join #=> "abc"
1645 * [ "a", "b", "c" ].join("-") #=> "a-b-c"
1646 */
1647
1648 static VALUE
rb_ary_join_m(argc,argv,ary)1649 rb_ary_join_m(argc, argv, ary)
1650 int argc;
1651 VALUE *argv;
1652 VALUE ary;
1653 {
1654 VALUE sep;
1655
1656 rb_scan_args(argc, argv, "01", &sep);
1657 if (NIL_P(sep)) sep = rb_output_fs;
1658
1659 return rb_ary_join(ary, sep);
1660 }
1661
1662 /*
1663 * call-seq:
1664 * array.to_s -> string
1665 *
1666 * Returns _self_<code>.join</code>.
1667 *
1668 * [ "a", "e", "i", "o" ].to_s #=> "aeio"
1669 *
1670 */
1671
1672 VALUE
rb_ary_to_s(ary)1673 rb_ary_to_s(ary)
1674 VALUE ary;
1675 {
1676 if (RARRAY(ary)->len == 0) return rb_str_new(0, 0);
1677
1678 return rb_ary_join(ary, rb_output_fs);
1679 }
1680
1681 static VALUE
inspect_ary(ary,dummy,recur)1682 inspect_ary(ary, dummy, recur)
1683 VALUE ary;
1684 VALUE dummy;
1685 int recur;
1686 {
1687 int tainted = OBJ_TAINTED(ary);
1688 long i;
1689 VALUE s, str;
1690
1691 if (recur) return rb_tainted_str_new2("[...]");
1692 str = rb_str_buf_new2("[");
1693 for (i=0; i<RARRAY(ary)->len; i++) {
1694 s = rb_inspect(RARRAY(ary)->ptr[i]);
1695 if (OBJ_TAINTED(s)) tainted = Qtrue;
1696 if (i > 0) rb_str_buf_cat2(str, ", ");
1697 rb_str_buf_append(str, s);
1698 }
1699 rb_str_buf_cat2(str, "]");
1700 if (tainted) OBJ_TAINT(str);
1701 return str;
1702 }
1703
1704 /*
1705 * call-seq:
1706 * array.inspect -> string
1707 *
1708 * Create a printable version of <i>array</i>.
1709 */
1710
1711 static VALUE
rb_ary_inspect(ary)1712 rb_ary_inspect(ary)
1713 VALUE ary;
1714 {
1715 if (RARRAY(ary)->len == 0) return rb_str_new2("[]");
1716 return rb_exec_recursive(inspect_ary, ary, 0);
1717 }
1718
1719 /*
1720 * call-seq:
1721 * array.to_a -> array
1722 *
1723 * Returns _self_. If called on a subclass of Array, converts
1724 * the receiver to an Array object.
1725 */
1726
1727 static VALUE
rb_ary_to_a(ary)1728 rb_ary_to_a(ary)
1729 VALUE ary;
1730 {
1731 if (rb_obj_class(ary) != rb_cArray) {
1732 VALUE dup = rb_ary_new2(RARRAY(ary)->len);
1733 rb_ary_replace(dup, ary);
1734 return dup;
1735 }
1736 return ary;
1737 }
1738
1739 /*
1740 * call-seq:
1741 * array.to_ary -> array
1742 *
1743 * Returns _self_.
1744 */
1745
1746 static VALUE
rb_ary_to_ary_m(ary)1747 rb_ary_to_ary_m(ary)
1748 VALUE ary;
1749 {
1750 return ary;
1751 }
1752
1753 VALUE
rb_ary_reverse(ary)1754 rb_ary_reverse(ary)
1755 VALUE ary;
1756 {
1757 VALUE *p1, *p2;
1758 VALUE tmp;
1759
1760 rb_ary_modify(ary);
1761 if (RARRAY(ary)->len > 1) {
1762 p1 = RARRAY(ary)->ptr;
1763 p2 = p1 + RARRAY(ary)->len - 1; /* points last item */
1764
1765 while (p1 < p2) {
1766 tmp = *p1;
1767 *p1++ = *p2;
1768 *p2-- = tmp;
1769 }
1770 }
1771 return ary;
1772 }
1773
1774 /*
1775 * call-seq:
1776 * array.reverse! -> array
1777 *
1778 * Reverses _self_ in place.
1779 *
1780 * a = [ "a", "b", "c" ]
1781 * a.reverse! #=> ["c", "b", "a"]
1782 * a #=> ["c", "b", "a"]
1783 */
1784
1785 static VALUE
rb_ary_reverse_bang(ary)1786 rb_ary_reverse_bang(ary)
1787 VALUE ary;
1788 {
1789 return rb_ary_reverse(ary);
1790 }
1791
1792 /*
1793 * call-seq:
1794 * array.reverse -> an_array
1795 *
1796 * Returns a new array containing <i>self</i>'s elements in reverse order.
1797 *
1798 * [ "a", "b", "c" ].reverse #=> ["c", "b", "a"]
1799 * [ 1 ].reverse #=> [1]
1800 */
1801
1802 static VALUE
rb_ary_reverse_m(ary)1803 rb_ary_reverse_m(ary)
1804 VALUE ary;
1805 {
1806 return rb_ary_reverse(rb_ary_dup(ary));
1807 }
1808
1809 struct ary_sort_data {
1810 VALUE ary;
1811 VALUE *ptr;
1812 long len;
1813 };
1814
1815 static void
ary_sort_check(data)1816 ary_sort_check(data)
1817 struct ary_sort_data *data;
1818 {
1819 if (RARRAY(data->ary)->ptr != data->ptr || RARRAY(data->ary)->len != data->len) {
1820 rb_raise(rb_eRuntimeError, "array modified during sort");
1821 }
1822 }
1823
1824 static int
sort_1(a,b,data)1825 sort_1(a, b, data)
1826 VALUE *a, *b;
1827 struct ary_sort_data *data;
1828 {
1829 VALUE retval = rb_yield_values(2, *a, *b);
1830 int n;
1831
1832 n = rb_cmpint(retval, *a, *b);
1833 ary_sort_check(data);
1834 return n;
1835 }
1836
1837 static int
sort_2(ap,bp,data)1838 sort_2(ap, bp, data)
1839 VALUE *ap, *bp;
1840 struct ary_sort_data *data;
1841 {
1842 VALUE retval;
1843 VALUE a = *ap, b = *bp;
1844 int n;
1845
1846 if (FIXNUM_P(a) && FIXNUM_P(b)) {
1847 if ((long)a > (long)b) return 1;
1848 if ((long)a < (long)b) return -1;
1849 return 0;
1850 }
1851 if (TYPE(a) == T_STRING && TYPE(b) == T_STRING) {
1852 return rb_str_cmp(a, b);
1853 }
1854
1855 retval = rb_funcall(a, id_cmp, 1, b);
1856 n = rb_cmpint(retval, a, b);
1857 ary_sort_check(data);
1858
1859 return n;
1860 }
1861
1862 static VALUE
sort_internal(ary)1863 sort_internal(ary)
1864 VALUE ary;
1865 {
1866 struct ary_sort_data data;
1867
1868 data.ary = ary;
1869 data.ptr = RARRAY(ary)->ptr; data.len = RARRAY(ary)->len;
1870 qsort(RARRAY(ary)->ptr, RARRAY(ary)->len, sizeof(VALUE),
1871 rb_block_given_p()?sort_1:sort_2, &data);
1872 return ary;
1873 }
1874
1875 static VALUE
sort_unlock(ary)1876 sort_unlock(ary)
1877 VALUE ary;
1878 {
1879 FL_UNSET(ary, ARY_TMPLOCK);
1880 return ary;
1881 }
1882
1883 /*
1884 * call-seq:
1885 * array.sort! -> array
1886 * array.sort! {| a,b | block } -> array
1887 *
1888 * Sorts _self_. Comparisons for
1889 * the sort will be done using the <code><=></code> operator or using
1890 * an optional code block. The block implements a comparison between
1891 * <i>a</i> and <i>b</i>, returning -1, 0, or +1. See also
1892 * <code>Enumerable#sort_by</code>.
1893 *
1894 * a = [ "d", "a", "e", "c", "b" ]
1895 * a.sort #=> ["a", "b", "c", "d", "e"]
1896 * a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
1897 */
1898
1899 VALUE
rb_ary_sort_bang(ary)1900 rb_ary_sort_bang(ary)
1901 VALUE ary;
1902 {
1903 rb_ary_modify(ary);
1904 if (RARRAY(ary)->len > 1) {
1905 FL_SET(ary, ARY_TMPLOCK); /* prohibit modification during sort */
1906 rb_ensure(sort_internal, ary, sort_unlock, ary);
1907 }
1908 return ary;
1909 }
1910
1911 /*
1912 * call-seq:
1913 * array.sort -> an_array
1914 * array.sort {| a,b | block } -> an_array
1915 *
1916 * Returns a new array created by sorting <i>self</i>. Comparisons for
1917 * the sort will be done using the <code><=></code> operator or using
1918 * an optional code block. The block implements a comparison between
1919 * <i>a</i> and <i>b</i>, returning -1, 0, or +1. See also
1920 * <code>Enumerable#sort_by</code>.
1921 *
1922 * a = [ "d", "a", "e", "c", "b" ]
1923 * a.sort #=> ["a", "b", "c", "d", "e"]
1924 * a.sort {|x,y| y <=> x } #=> ["e", "d", "c", "b", "a"]
1925 */
1926
1927 VALUE
rb_ary_sort(ary)1928 rb_ary_sort(ary)
1929 VALUE ary;
1930 {
1931 ary = rb_ary_dup(ary);
1932 rb_ary_sort_bang(ary);
1933 return ary;
1934 }
1935
1936 /*
1937 * call-seq:
1938 * array.collect {|item| block } -> an_array
1939 * array.map {|item| block } -> an_array
1940 *
1941 * Invokes <i>block</i> once for each element of <i>self</i>. Creates a
1942 * new array containing the values returned by the block.
1943 * See also <code>Enumerable#collect</code>.
1944 *
1945 * a = [ "a", "b", "c", "d" ]
1946 * a.collect {|x| x + "!" } #=> ["a!", "b!", "c!", "d!"]
1947 * a #=> ["a", "b", "c", "d"]
1948 */
1949
1950 static VALUE
rb_ary_collect(ary)1951 rb_ary_collect(ary)
1952 VALUE ary;
1953 {
1954 long i;
1955 VALUE collect;
1956
1957 if (!rb_block_given_p()) {
1958 return rb_ary_new4(RARRAY(ary)->len, RARRAY(ary)->ptr);
1959 }
1960
1961 collect = rb_ary_new2(RARRAY(ary)->len);
1962 for (i = 0; i < RARRAY(ary)->len; i++) {
1963 rb_ary_push(collect, rb_yield(RARRAY(ary)->ptr[i]));
1964 }
1965 return collect;
1966 }
1967
1968 /*
1969 * call-seq:
1970 * array.collect! {|item| block } -> array
1971 * array.map! {|item| block } -> array
1972 *
1973 * Invokes the block once for each element of _self_, replacing the
1974 * element with the value returned by _block_.
1975 * See also <code>Enumerable#collect</code>.
1976 *
1977 * a = [ "a", "b", "c", "d" ]
1978 * a.collect! {|x| x + "!" }
1979 * a #=> [ "a!", "b!", "c!", "d!" ]
1980 */
1981
1982 static VALUE
rb_ary_collect_bang(ary)1983 rb_ary_collect_bang(ary)
1984 VALUE ary;
1985 {
1986 long i;
1987
1988 rb_ary_modify(ary);
1989 for (i = 0; i < RARRAY(ary)->len; i++) {
1990 rb_ary_store(ary, i, rb_yield(RARRAY(ary)->ptr[i]));
1991 }
1992 return ary;
1993 }
1994
1995 VALUE
rb_get_values_at(obj,olen,argc,argv,func)1996 rb_get_values_at(obj, olen, argc, argv, func)
1997 VALUE obj;
1998 long olen;
1999 int argc;
2000 VALUE *argv;
2001 VALUE (*func) _((VALUE,long));
2002 {
2003 VALUE result = rb_ary_new2(argc);
2004 long beg, len, i, j;
2005
2006 for (i=0; i<argc; i++) {
2007 if (FIXNUM_P(argv[i])) {
2008 rb_ary_push(result, (*func)(obj, FIX2LONG(argv[i])));
2009 continue;
2010 }
2011 /* check if idx is Range */
2012 switch (rb_range_beg_len(argv[i], &beg, &len, olen, 0)) {
2013 case Qfalse:
2014 break;
2015 case Qnil:
2016 continue;
2017 default:
2018 for (j=0; j<len; j++) {
2019 rb_ary_push(result, (*func)(obj, j+beg));
2020 }
2021 continue;
2022 }
2023 rb_ary_push(result, (*func)(obj, NUM2LONG(argv[i])));
2024 }
2025 return result;
2026 }
2027
2028 /*
2029 * call-seq:
2030 * array.values_at(selector,... ) -> an_array
2031 *
2032 * Returns an array containing the elements in
2033 * _self_ corresponding to the given selector(s). The selectors
2034 * may be either integer indices or ranges.
2035 * See also <code>Array#select</code>.
2036 *
2037 * a = %w{ a b c d e f }
2038 * a.values_at(1, 3, 5)
2039 * a.values_at(1, 3, 5, 7)
2040 * a.values_at(-1, -3, -5, -7)
2041 * a.values_at(1..3, 2...5)
2042 */
2043
2044 static VALUE
rb_ary_values_at(argc,argv,ary)2045 rb_ary_values_at(argc, argv, ary)
2046 int argc;
2047 VALUE *argv;
2048 VALUE ary;
2049 {
2050 return rb_get_values_at(ary, RARRAY(ary)->len, argc, argv, rb_ary_entry);
2051 }
2052
2053 /*
2054 * call-seq:
2055 * array.select {|item| block } -> an_array
2056 *
2057 * Invokes the block passing in successive elements from <i>array</i>,
2058 * returning an array containing those elements for which the block
2059 * returns a true value (equivalent to <code>Enumerable#select</code>).
2060 *
2061 * a = %w{ a b c d e f }
2062 * a.select {|v| v =~ /[aeiou]/} #=> ["a", "e"]
2063 */
2064
2065 static VALUE
rb_ary_select(ary)2066 rb_ary_select(ary)
2067 VALUE ary;
2068 {
2069 VALUE result;
2070 long i;
2071
2072 result = rb_ary_new2(RARRAY(ary)->len);
2073 for (i = 0; i < RARRAY(ary)->len; i++) {
2074 if (RTEST(rb_yield(RARRAY(ary)->ptr[i]))) {
2075 rb_ary_push(result, rb_ary_elt(ary, i));
2076 }
2077 }
2078 return result;
2079 }
2080
2081