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