purged JS.Obj <-> Basket.Hash incest
[org.ibex.js.git] / src / org / ibex / js / JS.java
index 2c0baee..e2fe3e3 100644 (file)
@@ -161,20 +161,10 @@ public interface JS extends Pausable {
         public String coerceToString() { return clonee.coerceToString(); }
     }
 
-    public static class Obj extends Basket.Hash implements JS {
+    public static class Obj extends Basket.HashMap implements JS {
         private static final String[] emptystr = new String[0];
         private static final Placeholder holder = new Placeholder();
 
-        // HACK: this is hideously, disgustingly ugly.... we need N-ary Hash classes
-        /** entries[index + 0] // key
-         *  entries[index + 1] // value
-         *  entries[index + 2] // trap
-         */
-
-        protected void entryAdded(int p) {}
-        protected void entryUpdated(int p) {}
-        protected void entryRemoved(int p) {}
-
         public Obj() { super(3, 4, 0.75F); }
 
         public JS unclone() { return this; }
@@ -192,43 +182,29 @@ public interface JS extends Pausable {
         public String[] getFormalArgs() { return emptystr; }
 
         public Enumeration keys() throws JSExn {
+            final Object[] keys = super.dumpkeys();
             return new Enumeration(null) {
-                private int dest = -1, next = -1;
-                public boolean _hasNext() {
-                    for (int i = Math.max(0, dest); i < usedslots; i++)
-                        if (i > 0 ? entries[i * indexmultiple] != null : true &&
-                            entries[i * indexmultiple] != this) { next = i; return true; }
-                    return false;
-                }
-                public JS _next() throws JSExn {
-                    if (next < 0 && !hasNext()) throw new NoSuchElementException();
-                    int index = next; dest = next; next = -1;
-                    return (JS)entries[index * indexmultiple];
-                }
-            };
+                    private int cur = 0;
+                    public boolean _hasNext() { return cur < keys.length; }
+                    public JS _next() throws JSExn {
+                        if (cur >= keys.length) throw new NoSuchElementException();
+                        return (JS)keys[cur++];
+                    }
+                };
         }
-        public JS get(JS key) throws JSExn { int i = indexOf(key);
-            return i < 0 ? null : entries[i + 1] instanceof Placeholder ?  null : (JS)entries[i + 1]; }
-        public void put(JS key, JS val) throws JSExn {
-            // NOTE: only way value can be stored as null is using declare()
-            int dest = put(indexOf(key), key);
-            if (val == null) entries[dest + 1] = holder;
-            else entries[dest + 1] = val; }
+
+        public JS get(JS key) throws JSExn { return (JS)super.get(key, 0); }
+        public void put(JS key, JS val) throws JSExn { super.put(key, val, 0); }
 
         /*public boolean hasValue(JS key, JS value) {
             int i = indexOf(key); return i >= 0 && entries[i + 1] != null; }
         public boolean hasTrap(JS key, JS trap) {
             int i = indexOf(key); return i >= 0 && entries[i + 2] != null; }*/
 
-        public void declare(JS key) throws JSExn { entries[put(indexOf(key), key) + 1] = null; }
-        public void undeclare(JS key) throws JSExn { remove(indexOf(key)); }
-
         public JS putAndTriggerTraps(JS key, JS val) throws JSExn {
-            Trap t = null; int i = indexOf(key);
-            if (i >= 0) t = (Trap)entries[i + 2];
-            if (t != null && (t = t.write()) != null) {
+            Trap t = (Trap)super.get(key, 1);
+            if (t != null && (t = t.write()) != null)
                 val = (JS)new Interpreter(t, val, false).run(null);
-            }
             put(key, val); // HACK: necessary for subclasses overriding put()
             /*if (i < 0) i = put(i, key);
             if (val == null) entries[i + 1] = holder;
@@ -236,14 +212,11 @@ public interface JS extends Pausable {
             return val;
         }
         public JS getAndTriggerTraps(JS key) throws JSExn {
-            Trap t = null; int i = indexOf(key);
-            if (i < 0) return get(key); // HACK: necessary for subclasses overriding get()
-            t = (Trap)entries[i + 2];
-            return t == null ? (JS)entries[i + 1] : (JS)new Interpreter(t, null, false).run(null);
+            Trap t = (Trap)super.get(key, 1);
+            return t == null ? (JS)super.get(key) : (JS)new Interpreter(t, null, false).run(null);
         }
         public JS justTriggerTraps(JS key, JS val) throws JSExn {
-            Trap t = null; int i = indexOf(key);
-            if (i >= 0) t = (Trap)entries[i + 2];
+            Trap t = (Trap)super.get(key, 1);
             if (t == null || (t = t.write()) == null) return val;
             return (JS)new Interpreter(t, val, true).run(null);
         }
@@ -251,23 +224,20 @@ public interface JS extends Pausable {
         public void addTrap(JS key, JS f) throws JSExn {
             if (f.getFormalArgs() == null || f.getFormalArgs().length > 1) throw new JSExn(
                 "traps must take either one argument (write) or no arguments (read)");
-            int i = indexOf(key); if (i < 0) i = put(i, key);
-            for (Trap t = (Trap)entries[i + 2]; t != null; t = t.next())
+            for (Trap t = (Trap)super.get(key, 1); t != null; t = t.next())
                 if (t.function().equals(f)) return;
-            entries[i + 2] = new TrapHolder(this, key, f, (Trap)entries[i + 2]);
+            super.put(key, new TrapHolder(this, key, f, (Trap)super.get(key, 1)), 1);
         }
 
         public void delTrap(JS key, JS f) throws JSExn {
-            int i = indexOf(key); if (i < 0) return;
-            Trap t = (Trap)entries[i + 2];
-            if (t.function().equals(f)) { entries[i + 2] = t.next(); return; }
+            Trap t = (Trap)super.get(key, 1);
+            if (t==null) return;
+            if (t.function().equals(f)) { super.put(key, t.next(), 2); return; }
             for (; t.next() != null; t = t.next())
                 if (t.next().function().equals(f)) { ((TrapHolder)t).next = t.next().next(); return; }
         }
 
-        public Trap getTrap(JS key) throws JSExn {
-            int i = indexOf(key); return i < 0 ? null : (Trap)entries[i + 2];
-        }
+        public Trap getTrap(JS key) throws JSExn { return (Trap)super.get(key, 1); }
 
         public String coerceToString() { return "object"; }
 
@@ -327,7 +297,7 @@ public interface JS extends Pausable {
         protected abstract JS _next() throws JSExn;
 
         public final boolean hasNext() {
-            return _hasNext() || parent != null ? parent.hasNext() : false; }
+            return _hasNext() || (parent != null ? parent.hasNext() : false); }
         public final JS next() throws JSExn {
             if (_hasNext()) return _next();
             if (parent == null) throw new NoSuchElementException("reached end of set");