KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > es > NativeArray


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  * Free SoftwareFoundation, Inc.
23  * 59 Temple Place, Suite 330
24  * Boston, MA 02111-1307 USA
25  *
26  * @author Scott Ferguson
27  */

28
29 package com.caucho.es;
30
31 /**
32  * JavaScript object
33  */

34 class NativeArray extends Native {
35   static ESId LENGTH = ESId.intern("length");
36   static final int NEW = 1;
37   static final int JOIN = NEW + 1;
38   static final int TO_STRING = JOIN + 1;
39   static final int REVERSE = TO_STRING + 1;
40   static final int SORT = REVERSE + 1;
41
42   // js1.2
43
static final int CONCAT = SORT + 1;
44   static final int POP = CONCAT + 1;
45   static final int PUSH = POP + 1;
46   static final int SHIFT = PUSH + 1;
47   static final int UNSHIFT = SHIFT + 1;
48   static final int SLICE = UNSHIFT + 1;
49   static final int SPLICE = SLICE + 1;
50
51   /**
52    * Create a new object based on a prototype
53    */

54   private NativeArray(String JavaDoc name, int n, int len)
55   {
56     super(name, len);
57
58     this.n = n;
59   }
60
61   /**
62    * Creates the native Array object
63    */

64   static ESObject create(Global resin)
65   {
66     Native nativeArray = new NativeArray("Array", NEW, 1);
67     ESArray proto = new ESArray();
68     proto.prototype = resin.objProto;
69     NativeWrapper array = new NativeWrapper(resin, nativeArray,
70                                             proto, ESThunk.ARRAY_THUNK);
71     resin.arrayProto = proto;
72
73     put(proto, "join", JOIN, 1);
74     put(proto, "toString", TO_STRING, 0);
75     put(proto, "reverse", REVERSE, 0);
76     put(proto, "sort", SORT, 0);
77
78     // js1.2
79
put(proto, "concat", CONCAT, 0);
80     put(proto, "pop", POP, 0);
81     put(proto, "push", PUSH, 0);
82     put(proto, "shift", SHIFT, 0);
83     put(proto, "unshift", UNSHIFT, 0);
84     put(proto, "slice", SLICE, 2);
85     put(proto, "splice", SPLICE, 0);
86
87     proto.setClean();
88     array.setClean();
89
90     return array;
91   }
92
93   private static void put(ESObject obj, String JavaDoc name, int n, int len)
94   {
95     ESId id = ESId.intern(name);
96
97     obj.put(id, new NativeArray(name, n, len), DONT_ENUM);
98   }
99
100
101   public ESBase call(Call eval, int length) throws Throwable JavaDoc
102   {
103     switch (n) {
104     case NEW:
105       return create(eval, length);
106
107     case JOIN:
108       if (length == 0)
109         return toString(eval, length);
110       else
111         return join(eval, length);
112
113     case TO_STRING:
114       return toString(eval, length);
115
116     case REVERSE:
117       return reverse(eval, length);
118
119     case SORT:
120       return sort(eval, length);
121
122     case CONCAT:
123       return concat(eval, length);
124
125     case POP:
126       return pop(eval, length);
127
128     case PUSH:
129       return push(eval, length);
130
131     case SHIFT:
132       return shift(eval, length);
133
134     case UNSHIFT:
135       return unshift(eval, length);
136
137     case SLICE:
138       return slice(eval, length);
139
140     case SPLICE:
141       return splice(eval, length);
142
143     default:
144       throw new ESException("Unknown object function");
145     }
146   }
147
148   ESBase create(Call eval, int length) throws Throwable JavaDoc
149   {
150     ESObject obj = Global.getGlobalProto().createArray();
151
152     if (length == 0)
153       return obj;
154     if (length == 1) {
155       ESBase arg = eval.getArg(0);
156
157       if (arg instanceof ESNumber)
158         obj.setProperty(LENGTH, ESNumber.create(arg.toInt32()));
159       else
160         obj.setProperty(0, arg);
161
162       return obj;
163     }
164
165     for (int i = 0; i < length; i++)
166       obj.setProperty(i, eval.getArg(i));
167
168     return obj;
169   }
170
171   static ESBase join(ESObject array, String JavaDoc separator) throws Throwable JavaDoc
172   {
173     if (array.mark != 0) {
174       return ESString.create("...");
175     }
176     array.mark = -1;
177
178     try {
179       int len = array.getProperty(LENGTH).toInt32();
180       StringBuffer JavaDoc sbuf = new StringBuffer JavaDoc();
181
182       for (int i = 0; i < len; i++) {
183         if (i != 0)
184           sbuf.append(separator);
185
186         ESBase value = array.hasProperty(i);
187
188         if (value != null && value != esNull && value != esUndefined)
189           sbuf.append(value.toString());
190       }
191
192       return ESString.create(sbuf.toString());
193     } finally {
194       array.mark = 0;
195     }
196   }
197
198   ESBase join(Call eval, int length) throws Throwable JavaDoc
199   {
200     String JavaDoc separator = length == 0 ? "," : eval.getArg(0).toString();
201
202     ESObject array = eval.getArg(-1).toObject();
203
204     return join(array, separator);
205   }
206
207   static ESBase toString(ESObject array) throws Throwable JavaDoc
208   {
209     return join(array, ",");
210   }
211
212   // XXX: different for non-js1.2
213
ESBase toString(Call eval, int length) throws Throwable JavaDoc
214   {
215     ESObject array = eval.getArg(-1).toObject();
216
217     return toString(array);
218   }
219
220   ESBase reverse(Call eval, int length) throws Throwable JavaDoc
221   {
222     ESObject array = eval.getArg(-1).toObject();
223
224     int len = (int) array.getProperty(LENGTH).toInt32();
225     for (int k = 0; k < len / 2; k++) {
226       int firstIndex = k;
227       int secondIndex = len - k - 1;
228
229       ESBase first = array.hasProperty(firstIndex);
230       ESBase second = array.hasProperty(secondIndex);
231
232       if (first == null)
233         array.delete(secondIndex);
234       else
235         array.setProperty(secondIndex, first);
236
237       if (second == null)
238         array.delete(firstIndex);
239       else
240         array.setProperty(firstIndex, second);
241     }
242
243     return array;
244   }
245
246   ESBase sort(Call eval, int length) throws Throwable JavaDoc
247   {
248     ESObject array = eval.getArg(-1).toObject();
249
250     ESBase cmp = length == 0 ? null : eval.getArg(0);
251
252     int len = (int) array.getProperty(LENGTH).toInt32();
253     ESBase []values = new ESBase[len];
254
255     for (int i = 0; i < len; i++)
256       values[i] = array.getProperty("" + i);
257
258     qsort(values, 0, len, cmp);
259
260     for (int i = 0; i < len; i++) {
261       if (values[i] == esUndefined)
262         array.delete("" + i);
263       else
264         array.setProperty("" + i, values[i]);
265     }
266
267     return array;
268   }
269
270   private void qsort(ESBase []array, int offset, int length, ESBase cmp)
271     throws Throwable JavaDoc
272   {
273     if (length == 2) {
274       if (compare(cmp, array[offset], array[offset + 1]) > 0) {
275         ESBase temp = array[offset];
276         array[offset] = array[offset + 1];
277         array[offset + 1] = temp;
278       }
279     } else if (length > 2) {
280       int keyIndex = offset + length / 2;
281       ESBase key = array[keyIndex];
282       int keys = 0;
283       int tail = 0;
284       int val;
285
286       if ((val = compare(cmp, array[offset], key)) > 0) {
287         key = array[offset];
288         array[offset] = array[keyIndex];
289         array[keyIndex] = key;
290       } else if (val == 0)
291         keys++;
292
293       if ((val = compare(cmp, key, array[offset + length - 1])) > 0) {
294         key = array[offset + length - 1];
295         array[offset + length - 1] = array[keyIndex];
296         array[keyIndex] = key;
297         keys = 0;
298         tail = 1;
299
300         if ((val = compare(cmp, array[offset], key)) > 0) {
301           key = array[offset];
302           array[offset] = array[keyIndex];
303           array[keyIndex] = key;
304         } else if (val == 0)
305           keys++;
306       } else if (val < 0)
307         tail = 1;
308
309       int i;
310       if (keyIndex == offset + 1) {
311         i = 2 + tail;
312         keys++;
313       }
314       else
315         i = 1 + tail;
316
317       for (; i < length; i++) {
318         int index = offset + i - tail;
319
320         if (array[index] == key) {
321           keys++;
322           continue;
323         }
324
325         int cmpResult = compare(cmp, key, array[index]);
326         if (cmpResult > 0 && keys != 0) {
327           ESBase temp = array[index];
328           array[index] = array[index - keys];
329           array[index - keys] = temp;
330         } else if (cmpResult < 0) {
331           ESBase temp = array[offset + length - tail - 1];
332           array[offset + length - tail - 1] = array[index];
333           array[index] = temp;
334           tail += 1;
335         } else if (cmpResult == 0)
336           keys++;
337       }
338
339       if (length - tail - keys > 1)
340         qsort(array, offset, length - tail - keys, cmp);
341       if (tail > 1)
342         qsort(array, offset + length - tail, tail, cmp);
343     }
344   }
345
346   private int compare(ESBase cmp, ESBase a, ESBase b)
347     throws Throwable JavaDoc
348   {
349     if (a == b)
350       return 0;
351     else if (a == esUndefined)
352       return 1;
353     else if (b == esUndefined)
354       return -1;
355     else if (a == esNull)
356       return 1;
357     else if (b == esNull)
358       return -1;
359     else if (cmp != null) {
360       // Call eval = new Call(ESGlobal.getGlobalProto(), false);
361
Global resin = Global.getGlobalProto();
362       Call eval = resin.getCall();
363
364       eval.stack[0] = esNull;
365       eval.stack[1] = a;
366       eval.stack[2] = b;
367       eval.top = 1;
368
369       int result = cmp.call(eval, 2).toInt32();
370
371       resin.freeCall(eval);
372
373       return result;
374     }
375     else {
376       String JavaDoc sa = a.toString();
377       String JavaDoc sb = b.toString();
378
379       return sa.compareTo(sb);
380     }
381   }
382
383   ESBase concat(Call eval, int length) throws Throwable JavaDoc
384   {
385     ESArray array = Global.getGlobalProto().createArray();
386
387     int k = 0;
388     for (int i = -1; i < length; i++) {
389       ESBase arg = eval.getArg(i);
390
391       if (arg == esNull || arg == esUndefined || arg == esEmpty)
392         continue;
393
394       ESBase arglen = arg.hasProperty(LENGTH);
395
396       if (arglen == null) {
397         array.setProperty(k++, arg);
398         continue;
399       }
400
401       int len = (int) arglen.toInt32();
402
403       if (len < 0) {
404         array.setProperty(k++, arg);
405         continue;
406       }
407
408       for (int j = 0; j < len; j++) {
409         ESBase obj = arg.hasProperty(j);
410
411         if (obj != null)
412           array.setProperty(k, obj);
413         k++;
414       }
415     }
416     array.setProperty(LENGTH, ESNumber.create(k));
417
418     return array;
419   }
420
421   ESBase pop(Call eval, int length) throws Throwable JavaDoc
422   {
423     ESObject obj = eval.getArg(-1).toObject();
424
425     ESBase lenObj = obj.hasProperty(LENGTH);
426     int len;
427     if (lenObj == null || (len = lenObj.toInt32()) <= 0)
428       return esUndefined;
429
430     ESBase value = obj.getProperty(len - 1);
431
432     obj.setProperty(LENGTH, ESNumber.create(len - 1));
433
434     return value;
435   }
436
437   ESBase push(Call eval, int length) throws Throwable JavaDoc
438   {
439     ESObject obj = eval.getArg(-1).toObject();
440
441     ESBase lenObj = obj.getProperty(LENGTH);
442     int len = lenObj.toInt32();
443     if (len < 0)
444       len = 0;
445
446     for (int i = 0; i < length; i++)
447       obj.setProperty(len + i, eval.getArg(i));
448
449     ESNumber newLen = ESNumber.create(len + length);
450     obj.setProperty(LENGTH, newLen);
451
452     return newLen;
453   }
454
455   ESBase shift(Call eval, int length) throws Throwable JavaDoc
456   {
457     ESObject obj = eval.getArg(-1).toObject();
458
459     ESBase lenObj = obj.hasProperty(LENGTH);
460     int len;
461     if (lenObj == null || (len = (int) lenObj.toInt32()) <= 0)
462       return esUndefined;
463
464     ESBase value = obj.getProperty(0);
465
466     for (int i = 1; i < len; i++) {
467       ESBase temp = obj.hasProperty(i);
468       if (temp == null)
469         obj.delete(ESString.create(i - 1));
470       else
471         obj.setProperty(i - 1, temp);
472     }
473
474     obj.setProperty(LENGTH, ESNumber.create(len - 1));
475
476     return value;
477   }
478
479   ESBase unshift(Call eval, int length) throws Throwable JavaDoc
480   {
481     ESObject obj = eval.getArg(-1).toObject();
482
483     ESBase lenObj = obj.getProperty(LENGTH);
484     int len = lenObj.toInt32();
485     if (len < 0)
486       len = 0;
487
488     if (length == 0)
489       return ESNumber.create(0);
490
491     for (int i = len - 1; i >= 0; i--) {
492       ESBase value = obj.getProperty(i);
493
494       if (value == null)
495         obj.delete(ESString.create(length + i));
496       else
497         obj.setProperty(length + i, value);
498     }
499
500     for (int i = 0; i < length; i++) {
501       ESBase value = eval.getArg(i);
502
503       if (value == null)
504         obj.delete(ESString.create(i));
505       else
506         obj.setProperty(i, value);
507     }
508
509     ESNumber numLen = ESNumber.create(len + length);
510     obj.setProperty(LENGTH, numLen);
511
512     return numLen;
513   }
514
515   ESBase slice(Call eval, int length) throws Throwable JavaDoc
516   {
517     ESObject obj = eval.getArg(-1).toObject();
518
519     ESBase lenObj = obj.getProperty(LENGTH);
520     int len = lenObj.toInt32();
521
522     ESArray array = Global.getGlobalProto().createArray();
523     if (len <= 0)
524       return array;
525
526     int start = 0;
527     if (length > 0)
528       start = eval.getArg(0).toInt32();
529     if (start < 0)
530       start += len;
531     if (start < 0)
532       start = 0;
533     if (start > len)
534       return array;
535
536     int end = len;
537     if (length > 1)
538       end = eval.getArg(1).toInt32();
539     if (end < 0)
540       end += len;
541     if (end < 0)
542       return array;
543     if (end > len)
544       end = len;
545
546     if (start >= end)
547       return array;
548
549     for (int i = 0; i < end - start; i++) {
550       ESBase value = obj.hasProperty(start + i);
551
552       if (value != null)
553         array.setProperty(i, value);
554     }
555
556     array.setProperty(LENGTH, ESNumber.create(end - start));
557
558     return array;
559   }
560
561   ESBase splice(Call eval, int length) throws Throwable JavaDoc
562   {
563     if (length < 2)
564       return esUndefined;
565
566     ESObject obj = eval.getArg(-1).toObject();
567
568     int index = eval.getArg(0).toInt32();
569     int count = eval.getArg(1).toInt32();
570     boolean single = count == 1;
571
572     ESBase lenObj = obj.getProperty(LENGTH);
573     int len = lenObj.toInt32();
574
575     if (index < 0)
576       index += len;
577     if (index < 0)
578       index = 0;
579
580     if (count < 0)
581       count = 0;
582     if (index + count > len)
583       count = len - index;
584
585     ESBase value;
586
587     if (count < 1)
588       value = esUndefined;
589     else {
590       value = Global.getGlobalProto().createArray();
591
592       for (int i = 0; i < count; i++)
593         value.setProperty(i, obj.getProperty(index + i));
594     }
595
596     int delta = length - 2 - count;
597     if (delta < 0) {
598       for (int i = 0; i < len - count; i++) {
599         ESBase temp = obj.getProperty(i + index + count);
600         if (temp == null)
601           obj.delete(ESString.create(i + index + count + delta));
602         else
603           obj.setProperty(i + index + count + delta, temp);
604       }
605     } else if (delta > 0) {
606       for (int i = len - count - 1; i >= 0; i--) {
607         ESBase temp = obj.getProperty(i + index + count);
608         if (temp == null)
609           obj.delete(ESString.create(i + index + count + delta));
610         else
611           obj.setProperty(i + index + count + delta, temp);
612       }
613     }
614
615     for (int i = 0; i < length - 2; i++)
616       obj.setProperty(i + index, eval.getArg(i + 2));
617
618     obj.setProperty(LENGTH, ESNumber.create(len - count + length - 2));
619
620     return value;
621   }
622
623 }
624
Popular Tags