Author: Stephan <[email protected]>
Branch: 
Changeset: r138:6fcde575af3d
Date: 2011-10-25 13:00 +0200
http://bitbucket.org/pypy/lang-js/changeset/6fcde575af3d/

Log:    replaced W_PrimitiveObject.propdict with object map

diff --git a/js/interpreter.py b/js/interpreter.py
--- a/js/interpreter.py
+++ b/js/interpreter.py
@@ -302,7 +302,7 @@
     def Call(self, ctx, args=[], this=None):
         if len(args) >= 1:
             propname = args[0].ToString(ctx)
-            if propname in this.propdict:
+            if propname in self._get_property_keys():
                 return newbool(True)
         return newbool(False)
 
@@ -321,7 +321,7 @@
     def Call(self, ctx, args=[], this=None):
         if len(args) >= 1:
             propname = args[0].ToString(ctx)
-            if propname in this.propdict and not this.propdict[propname].flags 
& DONT_ENUM:
+            if self._has_property(propname) and not 
self._get_property_flags(propname) & DONT_ENUM:
                 return newbool(True)
         return newbool(False)
 
@@ -728,8 +728,7 @@
 
         w_ObjPrototype = W_Object(Prototype=None, Class='Object')
 
-        w_Function = W_Function(ctx, Class='Function',
-                              Prototype=w_ObjPrototype)
+        w_Function = W_Function(ctx, Class='Function', 
Prototype=w_ObjPrototype)
         w_FncPrototype = W_Function(ctx, Class='Function', 
Prototype=w_ObjPrototype)#W_Object(Prototype=None, Class='Function')
 
         w_Function.Put(ctx, 'length', W_IntNumber(1), flags = allon)
diff --git a/js/jsobj.py b/js/jsobj.py
--- a/js/jsobj.py
+++ b/js/jsobj.py
@@ -15,6 +15,12 @@
 READ_ONLY = RO = 4 # ReadOnly
 INTERNAL = IT = 8 # Internal
 
+from js.object_map import MapRoot
+ROOT_MAP = MapRoot()
+
+def _get_root_map():
+    return ROOT_MAP
+
 class SeePage(NotImplementedError):
     pass
 
@@ -147,8 +153,9 @@
 
 class W_PrimitiveObject(W_Root):
     def __init__(self, ctx=None, Prototype=None, Class='Object', 
Value=w_Undefined, callfunc=None):
-        self._propdict = {}
         self.Prototype = Prototype
+        self.property_map = _get_root_map()
+        self.property_values = []
         if Prototype is None:
             Prototype = w_Undefined
         self._set_property('prototype', Prototype, DONT_ENUM | DONT_DELETE)
@@ -161,44 +168,56 @@
         self.Value = Value
 
     def _set_property(self, name, value, flags):
-        p = self._propdict.get(name, None)
-        if p is None:
-            p = Property(name, value, flags)
-            self._propdict[name] = p
-        else:
-            p.value = value
-            p.falgs = flags
+        if self.property_map.lookup(name) == self.property_map.NOT_FOUND:
+            self.property_map = self.property_map.add(name, flags)
+        self._set_property_value(name, value)
+        self._set_property_flags(name, flags)
 
     def _set_property_value(self, name, value):
-        self._get_property(name).value = value
+        idx = self.property_map.lookup(name)
+        l = len(self.property_values)
+
+        if l <= idx:
+            self.property_values = self.property_values + ([None] * (idx - l + 
1))
+
+        self.property_values[idx] = value
 
     def _set_property_flags(self, name, flags):
-        self._get_property(name).flags = flags
+        self.property_map = self.property_map.set_flags(name, flags)
 
     def _get_property_value(self, name):
-        p = self._get_property(name)
-        if p is None:
+        idx = self.property_map.lookup(name)
+        if idx == self.property_map.NOT_FOUND:
             raise KeyError
-        return p.value
-
+        return self.property_values[idx]
 
     def _get_property_flags(self, name):
-        p = self._get_property(name)
-        if p is None:
+        flag = self.property_map.lookup_flag(name)
+        if flag == self.property_map.NOT_FOUND:
             raise KeyError
-        return p.flags
-
-    def _get_property(self, name):
-        return self._propdict.get(name, None)
+        return flag
 
     def _has_property(self, name):
-        return name in self._propdict
+        return self.property_map.lookup(name) != self.property_map.NOT_FOUND
 
     def _delete_property(self, name):
-        del self._propdict[name]
+        idx = self.property_map.lookup(name)
+        old_map = self.property_map
+        new_map = self.property_map.delete(name)
+        new_keys = new_map.keys()
+        new_values = [None] * len(new_keys)
+        old_values = self.property_values
+
+        for key in new_keys:
+            old_index = old_map.lookup(key)
+            new_index = new_map.lookup(key)
+            new_values[new_index] = old_values[old_index]
+
+        self.property_values = new_values
+        self.property_map = new_map
 
     def _get_property_keys(self):
-        return self._propdict.keys()
+        return self.property_map.keys()
 
     #@jit.unroll_safe
     def Call(self, ctx, args=[], this=None):
@@ -331,18 +350,15 @@
     return W_String(this.ToString(ctx))
 
 class W_Object(W_PrimitiveObject):
-    def __init__(self, ctx=None, Prototype=None, Class='Object',
-                 Value=w_Undefined, callfunc=None):
-        W_PrimitiveObject.__init__(self, ctx, Prototype,
-                                   Class, Value, callfunc)
+    def __init__(self, ctx=None, Prototype=None, Class='Object', 
Value=w_Undefined, callfunc=None):
+        W_PrimitiveObject.__init__(self, ctx, Prototype, Class, Value, 
callfunc)
 
     def ToNumber(self, ctx):
         return self.Get(ctx, 'valueOf').Call(ctx, args=[], 
this=self).ToNumber(ctx)
 
 class W_NewBuiltin(W_PrimitiveObject):
     length = -1
-    def __init__(self, ctx, Prototype=None, Class='function',
-                 Value=w_Undefined, callfunc=None):
+    def __init__(self, ctx, Prototype=None, Class='function', 
Value=w_Undefined, callfunc=None):
         if Prototype is None:
             proto = ctx.get_global().Get(ctx, 'Function').Get(ctx, 'prototype')
             Prototype = proto
@@ -402,7 +418,7 @@
         self._delete_property('prototype')
 
     def __repr__(self):
-        return str(self.propdict)
+        return str(self.property_map)
 
 class W_Array(W_ListObject):
     def __init__(self, ctx=None, Prototype=None, Class='Array', 
Value=w_Undefined, callfunc=None):
@@ -660,8 +676,7 @@
 
 def create_object(ctx, prototypename, callfunc=None, Value=w_Undefined):
     proto = ctx.get_global().Get(ctx, prototypename).Get(ctx, 'prototype')
-    obj = W_Object(ctx, callfunc = callfunc,Prototype=proto,
-                    Class = proto.Class, Value = Value)
+    obj = W_Object(ctx, callfunc = callfunc,Prototype=proto, Class = 
proto.Class, Value = Value)
     obj.Put(ctx, '__proto__', proto, DONT_ENUM | DONT_DELETE | READ_ONLY)
     return obj
 
diff --git a/js/object_map.py b/js/object_map.py
new file mode 100644
--- /dev/null
+++ b/js/object_map.py
@@ -0,0 +1,99 @@
+from pypy.rlib import jit
+
+class Map(object):
+    NOT_FOUND = -1
+    _immutable_fields_ = ['index', 'back', 'name', 'flags']
+    def __init__(self):
+        self.index = self.NOT_FOUND
+        self.forward_pointers = {}
+        self.back = None
+        self.name = None
+        self.flags = 0
+
+    def __repr__(self):
+        return "%s : %s:%d -> %s" % (object.__repr__(self), self.name, 
self.flags, repr(self.back) )
+
+    def lookup(self, name):
+        jit.promote(self)
+        node = self._find_node_with_name(name)
+        if node is not None:
+            return node.index
+        return self.NOT_FOUND
+
+    def lookup_flag(self, name):
+        jit.promote(self)
+        node = self._find_node_with_name(name)
+        if node is not None:
+            return node.flags
+        return self.NOT_FOUND
+
+    def _find_node_with_name(self, name):
+        if self.name == name:
+            return self
+        if self.back is not None:
+            return self.back._find_node_with_name(name)
+
+    def _find_node_with_name_and_flags(self, name, flags):
+        if self.name == name and self.flags == flags:
+            return self
+        node = None
+        if self.back is not None:
+            node = self.back._find_node_with_name_and_flags(name, flags)
+        if node is None:
+            return self.forward_pointers.get((name, flags), None)
+
+    def _key(self):
+        return (self.name, self.flags)
+
+    @jit.elidable
+    def add(self, name, flags=0):
+        assert self.lookup(name) == self.NOT_FOUND
+        node = self.forward_pointers.get((name, flags), None)
+        if node is None:
+            node = MapNode(self, name, flags)
+            self.forward_pointers[node._key()] = node
+        return node
+
+    def keys(self):
+        if self.name is None:
+            return []
+
+        k = [self.name]
+        if self.back is not None:
+            return self.back.keys() + k
+
+        return k
+
+    def set_flags(self, name, flags):
+        return self
+
+    def delete(self, key):
+        return self
+
+class MapRoot(Map):
+    pass
+
+class MapNode(Map):
+    def __init__(self, back, name, flags = 0):
+        Map.__init__(self)
+        self.back = back
+        self.name = name
+        self.index = back.index + 1
+        self.flags = flags
+
+    def delete(self, name):
+        if self.name == name:
+            return self.back
+        else:
+            n = self.back.delete(name)
+            return n.add(self.name, self.flags)
+
+    def set_flags(self, name, flags):
+        if self.name == name:
+            if self.flags == flags:
+                return self
+            else:
+                return self.back.add(name, flags)
+        else:
+            n = self.back.set_flags(name, flags)
+            return n.add(self.name, self.flags)
diff --git a/js/test/test_object_map.py b/js/test/test_object_map.py
new file mode 100644
--- /dev/null
+++ b/js/test/test_object_map.py
@@ -0,0 +1,175 @@
+import py
+
+from js.object_map import Map, MapRoot, MapNode
+
+class TestMap(object):
+    def setup_class(cls):
+        pass
+
+    def setup_method(cls, func):
+        pass
+
+    def test_root(self):
+        m = MapRoot()
+        assert m.index == Map.NOT_FOUND
+
+    def test_lookup_empty_root(self):
+        m = MapRoot()
+        assert m.lookup('foo') == Map.NOT_FOUND
+
+    def test_lookup(self):
+        a = MapRoot()
+        b = MapNode(a, 'foo')
+        c = MapNode(b, 'bar')
+        d = MapNode(b, 'baz')
+        e = MapNode(a, 'bar')
+
+        assert a.lookup('foo') == Map.NOT_FOUND
+        assert a.lookup('bar') == Map.NOT_FOUND
+        assert a.lookup('baz') == Map.NOT_FOUND
+        assert b.lookup('foo') == 0
+        assert b.lookup('bar') == Map.NOT_FOUND
+        assert b.lookup('baz') == Map.NOT_FOUND
+        assert c.lookup('foo') == 0
+        assert c.lookup('bar') == 1
+        assert c.lookup('baz') == Map.NOT_FOUND
+        assert d.lookup('foo') == 0
+        assert d.lookup('bar') == Map.NOT_FOUND
+        assert d.lookup('baz') == 1
+        assert e.lookup('bar') == 0
+
+    def test_add_node(self):
+        a = MapRoot()
+        b = a.add('foo')
+        assert b._key() in a.forward_pointers
+        assert a.forward_pointers[b._key()] == b
+        assert b.index == 0
+        assert b.back == a
+
+        c = b.add('bar')
+        assert c.lookup('bar') == 1
+
+        d = b.add('baz')
+        assert d.lookup('baz') == 1
+        assert c.lookup('baz') == Map.NOT_FOUND
+
+        py.test.raises(AssertionError, c.add, 'bar')
+
+    def test_add_duplicate(self):
+        r = MapRoot()
+        a = r.add('foo')
+        b = r.add('foo')
+        assert a == b
+
+        a = a.add('bar')
+        b = b.add('bar')
+
+        assert a == b
+
+    def test_keys(self):
+        m = MapRoot()
+        a = m.add('foo')
+        a = a.add('bar')
+        a = a.add('baz')
+
+        b = m.add('baz')
+        b = b.add('bar')
+
+        assert a.keys() == ['foo', 'bar', 'baz']
+        assert b.keys() == ['baz', 'bar']
+
+    def test_delete(self):
+        m = MapRoot()
+        m = m.add('foo')
+        m = m.add('bar')
+        m = m.add('baz')
+
+        b = m.delete('foo')
+        c = m.delete('bar')
+
+        assert b.lookup('foo') == Map.NOT_FOUND
+        assert b.lookup('bar') == 0
+        assert b.lookup('baz') == 1
+        assert b.keys() == ['bar', 'baz']
+
+        assert m.lookup('foo') == 0
+        assert m.lookup('bar') == 1
+        assert m.lookup('baz') == 2
+        assert m.keys() == ['foo', 'bar', 'baz']
+
+        assert c.lookup('foo') == 0
+        assert c.lookup('bar') == Map.NOT_FOUND
+        assert c.lookup('baz') == 1
+        assert c.keys() == ['foo', 'baz']
+
+    def test_delete_add(self):
+        m = MapRoot()
+        m = m.add('foo')
+        m = m.add('bar')
+        m = m.add('baz')
+
+        b = m.delete('foo')
+        b = b.add('foo')
+
+        assert b.lookup('foo') == 2
+        assert b.lookup('bar') == 0
+        assert b.lookup('baz') == 1
+        assert b.keys() == ['bar', 'baz', 'foo']
+
+    def test_delete_duplicate(self):
+        r = MapRoot()
+        a = r.add('bar')
+        a = a.add('baz')
+
+        b = r.add('foo')
+        b = b.add('bar')
+        b = b.add('baz')
+        b = b.delete('foo')
+
+        assert b.lookup('foo') == Map.NOT_FOUND
+        assert b.lookup('bar') == 0
+        assert b.lookup('baz') == 1
+
+        assert a.lookup('bar') == 0
+        assert a.lookup('baz') == 1
+
+        assert a == b
+
+    def test_add_with_flags(self):
+        r = MapRoot()
+        a = r.add('foo', 23)
+        a = a.add('bar')
+        b = r.add('foo', 42)
+        b = b.add('bar')
+
+        assert a.lookup('foo') == 0
+        assert a.lookup('bar') == 1
+
+        assert b.lookup('foo') == 0
+        assert b.lookup('bar') == 1
+
+        assert a.lookup_flag('foo') == 23
+        assert a.lookup_flag('bar') == 0
+        assert b.lookup_flag('foo') == 42
+        assert b.lookup_flag('bar') == 0
+
+    def test_set_flags(self):
+        r = MapRoot()
+        a = r.add('foo', 23)
+        a = a.add('bar')
+        a = a.add('baz')
+        b = r.add('foo', 42)
+        b = b.add('bar')
+        b = b.add('baz')
+
+
+        c = a.set_flags('bar', 42)
+        d = b.set_flags('bar', 23)
+
+        assert a.lookup_flag('bar') == 0
+        assert b.lookup_flag('bar') == 0
+        assert c.lookup_flag('bar') == 42
+        assert d.lookup_flag('bar') == 23
+
+        assert a.back.back == c.back.back
+        assert b.back.back == d.back.back
_______________________________________________
pypy-commit mailing list
[email protected]
http://mail.python.org/mailman/listinfo/pypy-commit

Reply via email to