2004/01/07 20:37:33
[org.ibex.core.git] / src / org / xwt / js / JSArray.java
index 2f5f04d..a5798bf 100644 (file)
@@ -2,14 +2,15 @@
 package org.xwt.js; 
 
 import org.xwt.util.*; 
-import java.io.*;
 import java.util.*;
 
 /** A JavaScript JSArray */
 public class JSArray extends JS {
-    private Vec vec = new Vec();
+    private static final Object NULL = new Object();
+    
     public JSArray() { }
-    public JSArray(int size) { vec.setSize(size); }
+    public JSArray(int size) { setSize(size); }
+    
     private static int intVal(Object o) {
         if (o instanceof Number) {
             int intVal = ((Number)o).intValue();
@@ -24,14 +25,16 @@ public class JSArray extends JS {
     
     public Object callMethod(Object method, Object a0, Object a1, Object a2, Object[] rest, int nargs) throws JSExn {
         //#switch(method)
-        case "pop": return vec.pop();
+        case "pop": {
+            int oldSize = size();
+            if(oldSize == 0) return null;
+            return removeElementAt(oldSize-1);
+        }
         case "reverse": return reverse();
         case "toString": return join(",");
         case "shift":
             if(length() == 0) return null;
-            Object o = vec.elementAt(0);
-            vec.removeElementAt(0);
-            return o;
+            return removeElementAt(0);
         case "join":
             return join(nargs == 0 ? "," : JS.toString(a0));
         case "sort":
@@ -40,12 +43,14 @@ public class JSArray extends JS {
             int start = toInt(nargs < 1 ? null : a0);
             int end = nargs < 2 ? length() : toInt(a1);
             return slice(start, end);
-        case "push":
-            for(int i=0; i<nargs; i++) vec.push(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
-            return N(vec.size());
+        case "push": {
+            int oldSize = size();
+            for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],oldSize+i);
+            return N(oldSize + nargs);
+        }
         case "unshift":
-            for(int i=0; i<nargs; i++) vec.insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3], i);
-            return N(vec.size());
+            for(int i=0; i<nargs; i++) insertElementAt(i==0?a0:i==1?a1:i==2?a2:rest[i-3],i);
+            return N(size());
         case "splice":
             JSArray array = new JSArray();
             for(int i=0; i<nargs; i++) array.addElement(i==0?a0:i==1?a1:i==2?a2:rest[i-3]);
@@ -55,14 +60,10 @@ public class JSArray extends JS {
     }
         
     public Object get(Object key) throws JSExn {
-        if (key instanceof Number) {
-            int i = intVal(key);
-            if (i == Integer.MIN_VALUE) return super.get(key);
-            try {
-                return vec.elementAt(i);
-            } catch (ArrayIndexOutOfBoundsException e) {
-                return null;
-            }
+        int i = intVal(key);
+        if (i != Integer.MIN_VALUE) {
+            if (i < 0 || i >= size()) return null;
+            return elementAt(i);
         }
         //#switch(key)
         case "pop": return METHOD;
@@ -75,42 +76,73 @@ public class JSArray extends JS {
         case "push": return METHOD;
         case "unshift": return METHOD;
         case "splice": return METHOD;
-        case "length": return N(vec.size());
+        case "length": return N(size());
         //#end
         return super.get(key);
     }
 
     public void put(Object key, Object val) throws JSExn {
-        if (key.equals("length")) vec.setSize(toNumber(val).intValue());
+        if (key.equals("length")) setSize(toInt(val));
         int i = intVal(key);
-        if (i == Integer.MIN_VALUE) super.put(key, val);
+        if (i == Integer.MIN_VALUE)
+            super.put(key, val);
         else {
-            if (i >= vec.size()) vec.setSize(i+1);
-            vec.setElementAt(val, i);
+            int oldSize = size();
+            if(i < oldSize) {
+                setElementAt(val,i);
+            } else {
+                if(i > oldSize) setSize(i);
+                insertElementAt(val,i);
+            }
         }
     }
 
     public Enumeration keys() {
         return new Enumeration() {
                 int cur = 0;
-                public boolean hasMoreElements() { return cur >= vec.size(); }
+                public boolean hasMoreElements() { return cur >= size(); }
                 public Object nextElement() {
-                    if (cur >= vec.size()) throw new NoSuchElementException();
+                    if (cur >= size()) throw new NoSuchElementException();
                     return new Integer(cur++);
                 }
             };
     }
 
-    public void setSize(int i) { vec.setSize(i); }
-    public int length() { return vec.size(); }
-    public Object elementAt(int i) { return vec.elementAt(i); }
-    public void addElement(Object o) { vec.addElement(o); }
-    public void setElementAt(Object o, int i) { vec.setElementAt(o, i); }
-    public int size() { return vec.size(); }
+    public final void setSize(int newSize) {
+        // FEATURE: This could be done a lot more efficiently in BalancedTree
+        int oldSize = size();
+        for(int i=oldSize;i<newSize;i++) insertElementAt(null,i);
+        for(int i=oldSize-1;i>=newSize;i--) removeElementAt(i);
+    }
+    
+    public final int length() { return size(); }
+    public final Object elementAt(int i) { 
+        if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
+        Object o = getNode(i);
+        return o == NULL ? null : o;
+    }
+    public final void addElement(Object o) { 
+        insertNode(size(),o==null ? NULL : o);
+    }
+    public final void setElementAt(Object o, int i) {
+        if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
+        replaceNode(i,o==null ? NULL : o);
+    }
+    public final void insertElementAt(Object o, int i) {
+        if(i < 0 || i > size()) throw new ArrayIndexOutOfBoundsException(i);
+        insertNode(i,o==null ? NULL : o);
+    }
+    public final Object removeElementAt(int i) {
+        if(i < 0 || i >= size()) throw new ArrayIndexOutOfBoundsException(i);
+        Object o = deleteNode(i);
+        return o == NULL ? null : o;
+    }
+    
+    public final int size() { return treeSize(); }
     public String typeName() { return "array"; }
         
     private Object join(String sep) {
-        int length = vec.size();
+        int length = size();
         if(length == 0) return "";
         StringBuffer sb = new StringBuffer(64);
         int i=0;
@@ -123,12 +155,13 @@ public class JSArray extends JS {
         return sb.toString();
     }
     
+    // FEATURE: Implement this more efficiently
     private Object reverse() {
-        Vec oldVec = vec;
-        int size = oldVec.size();
+        int size = size();
         if(size < 2) return this;
-        vec = new Vec(size);
-        for(int i=size-1;i>=0;i--) vec.addElement(oldVec.elementAt(i));
+        Vec vec = toVec();
+        clear();
+        for(int i=size-1,j=0;i>=0;i--,j++) insertElementAt(vec.elementAt(i),j);
         return this;
     }
     
@@ -152,6 +185,7 @@ public class JSArray extends JS {
         }
     };
     private Object sort(Object tmp) throws JSExn {
+        Vec vec = toVec();
         if(tmp instanceof JS) {
             final JSArray funcArgs = new JSArray(2);
             final JS jsFunc = (JS) tmp;
@@ -170,6 +204,7 @@ public class JSArray extends JS {
         } else {
             vec.sort(defaultSort);
         }
+        setFromVec(vec);
         return this;
     }
     
@@ -203,5 +238,25 @@ public class JSArray extends JS {
         return ret;
     }
     
-     public String coerceToString() { return JS.toString(join(",")); }
+    protected Vec toVec() {
+        int count = size();
+        Vec vec = new Vec();
+        vec.setSize(count);
+        for(int i=0;i<count;i++) {
+            Object o = getNode(i);
+            vec.setElementAt(o == NULL ? null : o,i);
+        }
+        return vec;
+    }
+    
+    protected void setFromVec(Vec vec) {
+        int count = vec.size();
+        clear();
+        for(int i=0;i<count;i++) {
+            Object o = vec.elementAt(i);
+            insertNode(i,o==null ? NULL : o);
+        }
+    }
+    
+    public String coerceToString() { return JS.toString(join(",")); }
 }