[Jython-checkins] jython: Unified PyDictionary and Py StringMap under a common abstract class

stefan.richthofer jython-checkins at python.org
Thu Oct 22 01:01:46 CEST 2015


https://hg.python.org/jython/rev/02e8f41510f3
changeset:   7762:02e8f41510f3
user:        Stefan Richthofer <stefan.richthofer at gmx.de>
date:        Thu Oct 22 01:01:24 2015 +0200
summary:
  Unified PyDictionary and Py StringMap under a common abstract class AbstractDict. This simplifies some JyNI-code and generally improves Jython's class structre and reduces need for case-distinctions. Also made the merge-function family public, adding the override-flag in the public API. This makes this API-part more consistent with CPython-API, also makin JyNI's dict-support more convenient.

files:
  src/org/python/core/AbstractDict.java |  33 +++++
  src/org/python/core/PyDictionary.java |  90 ++++++++++++++-
  src/org/python/core/PyStringMap.java  |  90 ++++++++++++++-
  3 files changed, 211 insertions(+), 2 deletions(-)


diff --git a/src/org/python/core/AbstractDict.java b/src/org/python/core/AbstractDict.java
new file mode 100644
--- /dev/null
+++ b/src/org/python/core/AbstractDict.java
@@ -0,0 +1,33 @@
+package org.python.core;
+
+import java.util.concurrent.ConcurrentMap;
+import java.util.Collection;
+
+public abstract class AbstractDict extends PyObject {
+
+    public AbstractDict(PyType type) {
+        super(type);
+    }
+
+    public abstract void clear();
+    public abstract AbstractDict copy();
+    public abstract PyObject get(PyObject key);
+    public abstract PyObject get(PyObject key, PyObject defaultObj);
+    public abstract ConcurrentMap<? extends Object, PyObject> getMap();
+    public abstract boolean has_key(PyObject key);
+    public abstract PyList items();
+    public abstract PyObject iteritems();
+    public abstract PyObject iterkeys();
+    public abstract PyObject itervalues();
+    public abstract PyList keys();
+    public abstract void merge(PyObject other, boolean override);
+    public abstract void mergeFromKeys(PyObject other, PyObject keys, boolean override);
+    public abstract void mergeFromSeq(PyObject other, boolean override);
+    public abstract PyObject pop(PyObject key);
+    public abstract PyObject pop(PyObject key, PyObject defaultValue);
+    public abstract PyObject popitem();
+    public abstract PyObject setdefault(PyObject key);
+    public abstract PyObject setdefault(PyObject key, PyObject failobj);
+    public abstract void update(PyObject other);
+    public abstract Collection<? extends Object> values();
+}
diff --git a/src/org/python/core/PyDictionary.java b/src/org/python/core/PyDictionary.java
--- a/src/org/python/core/PyDictionary.java
+++ b/src/org/python/core/PyDictionary.java
@@ -27,7 +27,7 @@
  * A builtin python dictionary.
  */
 @ExposedType(name = "dict", doc = BuiltinDocs.dict_doc)
-public class PyDictionary extends PyObject implements ConcurrentMap, Traverseproc {
+public class PyDictionary extends AbstractDict implements ConcurrentMap, Traverseproc {
 
     public static final PyType TYPE = PyType.fromClass(PyDictionary.class);
     {
@@ -520,6 +520,35 @@
     }
 
     /**
+     * Merge another PyObject that supports keys() with this
+     * dict.
+     *
+     * @param other a PyObject with a keys() method
+     * @param override if true, the value from other is used on key-collision
+     */
+    public void merge(PyObject other, boolean override) {
+        synchronized(internalMap) {
+            if (override) {
+                merge(other);
+            } else {
+                if (other instanceof PyDictionary) {
+                    Set<Map.Entry<PyObject, PyObject>> entrySet =
+                            ((PyDictionary)other).internalMap.entrySet();
+                    for (Map.Entry<PyObject, PyObject> ent: entrySet) {
+                        if (!internalMap.containsKey(ent.getKey())) {
+                            internalMap.put(ent.getKey(), ent.getValue());
+                        }
+                    }
+                } else if (other instanceof PyStringMap) {
+                    mergeFromKeys(other, ((PyStringMap)other).keys(), override);
+                } else {
+                    mergeFromKeys(other, other.invoke("keys"), override);
+                }
+            }
+        }
+    }
+
+    /**
      * Merge another PyObject via its keys() method
      *
      * @param other a PyObject with a keys() method
@@ -532,6 +561,27 @@
     }
 
     /**
+     * Merge another PyObject via its keys() method
+     *
+     * @param other a PyObject with a keys() method
+     * @param keys the result of other's keys() method
+     * @param override if true, the value from other is used on key-collision
+     */
+    public void mergeFromKeys(PyObject other, PyObject keys, boolean override) {
+        synchronized(internalMap) {
+            if (override) {
+                mergeFromKeys(other, keys);
+            } else {
+                for (PyObject key : keys.asIterable()) {
+                    if (!dict___contains__(key)) {
+                        dict___setitem__(key, other.__getitem__(key));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Merge any iterable object producing iterable objects of length
      * 2 into this dict.
      *
@@ -561,6 +611,44 @@
     }
 
     /**
+     * Merge any iterable object producing iterable objects of length
+     * 2 into this dict.
+     *
+     * @param other another PyObject
+     * @param override if true, the value from other is used on key-collision
+     */
+    public void mergeFromSeq(PyObject other, boolean override) {
+        synchronized(internalMap) {
+            if (override) {
+                mergeFromSeq(other);
+            } else {
+                PyObject pairs = other.__iter__();
+                PyObject pair;
+        
+                for (int i = 0; (pair = pairs.__iternext__()) != null; i++) {
+                    try {
+                        pair = PySequence.fastSequence(pair, "");
+                    } catch(PyException pye) {
+                        if (pye.match(Py.TypeError)) {
+                            throw Py.TypeError(String.format("cannot convert dictionary update sequence "
+                                                             + "element #%d to a sequence", i));
+                        }
+                        throw pye;
+                    }
+                    int n;
+                    if ((n = pair.__len__()) != 2) {
+                        throw Py.ValueError(String.format("dictionary update sequence element #%d "
+                                                          + "has length %d; 2 is required", i, n));
+                    }
+                    if (!dict___contains__(pair.__getitem__(0))) {
+                        dict___setitem__(pair.__getitem__(0), pair.__getitem__(1));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Return this[key] if the key exist, otherwise insert key with
      * a None value and return None.
      *
diff --git a/src/org/python/core/PyStringMap.java b/src/org/python/core/PyStringMap.java
--- a/src/org/python/core/PyStringMap.java
+++ b/src/org/python/core/PyStringMap.java
@@ -24,7 +24,7 @@
  * to PyObject unlike PyDictionary.
  */
 @ExposedType(name = "stringmap", isBaseType = false)
-public class PyStringMap extends PyObject implements Traverseproc {
+public class PyStringMap extends AbstractDict implements Traverseproc {
 
     /**
      * TYPE computed lazily, PyStringMap is used early in the bootstrap process and
@@ -410,6 +410,35 @@
     }
 
     /**
+     * Merge another PyObject that supports keys() with this
+     * dict.
+     *
+     * @param other a PyObject with a keys() method
+     * @param override if true, the value from other is used on key-collision
+     */
+    public void merge(PyObject other, boolean override) {
+        synchronized(table) {
+            if (override) {
+                merge(other);
+            } else {
+                if (other instanceof PyStringMap) {
+                    Set<Map.Entry<Object, PyObject>> entrySet =
+                            ((PyStringMap)other).table.entrySet();
+                    for (Map.Entry<Object, PyObject> ent: entrySet) {
+                        if (!table.containsKey(ent.getKey())) {
+                            table.put(ent.getKey(), ent.getValue());
+                        }
+                    }
+                } else if (other instanceof PyDictionary) {
+                    mergeFromKeys(other, ((PyDictionary)other).keys(), override);
+                } else {
+                    mergeFromKeys(other, other.invoke("keys"), override);
+                }
+            }
+        }
+    }
+
+    /**
      * Merge another PyObject via its keys() method
      *
      * @param other a PyObject with a keys() method
@@ -422,6 +451,27 @@
     }
 
     /**
+     * Merge another PyObject via its keys() method
+     *
+     * @param other a PyObject with a keys() method
+     * @param keys the result of other's keys() method
+     * @param override if true, the value from other is used on key-collision
+     */
+    public void mergeFromKeys(PyObject other, PyObject keys, boolean override) {
+        synchronized(table) {
+            if (override) {
+                mergeFromKeys(other, keys);
+            } else {
+                for (PyObject key : keys.asIterable()) {
+                    if (!__contains__(key)) {
+                        __setitem__(key, other.__getitem__(key));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Merge any iterable object producing iterable objects of length
      * 2 into this dict.
      *
@@ -451,6 +501,44 @@
     }
 
     /**
+     * Merge any iterable object producing iterable objects of length
+     * 2 into this dict.
+     *
+     * @param other another PyObject
+     * @param override if true, the value from other is used on key-collision
+     */
+    public void mergeFromSeq(PyObject other, boolean override) {
+        synchronized(table) {
+            if (override) {
+                mergeFromSeq(other);
+            } else {
+                PyObject pairs = other.__iter__();
+                PyObject pair;
+        
+                for (int i = 0; (pair = pairs.__iternext__()) != null; i++) {
+                    try {
+                        pair = PySequence.fastSequence(pair, "");
+                    } catch(PyException pye) {
+                        if (pye.match(Py.TypeError)) {
+                            throw Py.TypeError(String.format("cannot convert dictionary update sequence "
+                                                             + "element #%d to a sequence", i));
+                        }
+                        throw pye;
+                    }
+                    int n;
+                    if ((n = pair.__len__()) != 2) {
+                        throw Py.ValueError(String.format("dictionary update sequence element #%d "
+                                                          + "has length %d; 2 is required", i, n));
+                    }
+                    if (!__contains__(pair.__getitem__(0))) {
+                        __setitem__(pair.__getitem__(0), pair.__getitem__(1));
+                    }
+                }
+            }
+        }
+    }
+
+    /**
      * Return this[key] if the key exist, otherwise insert key with a None value and return None.
      *
      * @param key

-- 
Repository URL: https://hg.python.org/jython


More information about the Jython-checkins mailing list