[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