From: <pj...@us...> - 2008-10-25 21:51:54
|
Revision: 5506 http://jython.svn.sourceforge.net/jython/?rev=5506&view=rev Author: pjenvey Date: 2008-10-25 21:47:49 +0000 (Sat, 25 Oct 2008) Log Message: ----------- o back set with ConcurrentHashSet (just wraps ConcurrentHashMap) to make it thread safe o make frozenset immutable from the Java side's Set interface methods -- avoid unmodifiableSet because that complicates BaseSet Modified Paths: -------------- trunk/jython/src/org/python/core/BaseSet.java trunk/jython/src/org/python/core/PyFrozenSet.java trunk/jython/src/org/python/core/PyFrozenSetDerived.java trunk/jython/src/org/python/core/PySet.java trunk/jython/src/org/python/core/PySetIterator.java trunk/jython/src/templates/frozenset.derived Added Paths: ----------- trunk/jython/src/org/python/core/util/ConcurrentHashSet.java Modified: trunk/jython/src/org/python/core/BaseSet.java =================================================================== --- trunk/jython/src/org/python/core/BaseSet.java 2008-10-24 00:48:16 UTC (rev 5505) +++ trunk/jython/src/org/python/core/BaseSet.java 2008-10-25 21:47:49 UTC (rev 5506) @@ -8,51 +8,46 @@ public abstract class BaseSet extends PyObject implements Set { - /** - * The underlying container. HashSet is used rather than Set because - * clone is protected on Object and I didn't want to cast. - */ - protected HashSet _set; + /** The underlying Set. */ + protected Set _set; /** - * Create a new, empty set instance. - */ - public BaseSet() { - super(); - _set = new HashSet(); - } - - /** - * Create a new set instance from the values of the iterable object. + * Create a new Python set instance from the specified Set object. * - * @param data An iterable instance. + * @param set An Set object. */ - public BaseSet(PyObject data) { - super(); - _set = new HashSet(); - _update(data); + protected BaseSet(Set set) { + _set = set; } - public BaseSet(PyType type) { + protected BaseSet(PyType type, Set set) { super(type); - _set = new HashSet(); + _set = set; } + protected void _update(PyObject data) throws PyIgnoreMethodTag { + update(_set, data); + } + /** * Update the underlying set with the contents of the iterable. * * @param data An iterable instance. * @throws PyIgnoreMethodTag Ignore. */ - protected void _update(PyObject data) throws PyIgnoreMethodTag { + protected static Set update(Set set, PyObject data) throws PyIgnoreMethodTag { + if (data == null) { + return set; + } if (data instanceof BaseSet) { // Skip the iteration if both are sets - _set.addAll(((BaseSet)data)._set); - return; + set.addAll(((BaseSet)data)._set); + return set; } for (PyObject item : data.asIterable()) { - _set.add(item); + set.add(item); } + return set; } /** @@ -458,17 +453,15 @@ protected static BaseSet makeNewSet(PyType type, PyObject iterable) { BaseSet so; if (type == PySet.TYPE) { - so = new PySet(); + so = new PySet(iterable); } else if (type == PyFrozenSet.TYPE) { - so = new PyFrozenSet(); + so = new PyFrozenSet(iterable); } else if (Py.isSubClass(type, PySet.TYPE)) { so = new PySetDerived(type); + so._update(iterable); } else { - so = new PyFrozenSetDerived(type); + so = new PyFrozenSetDerived(type, iterable); } - if (iterable != null) { - so._update(iterable); - } return so; } Modified: trunk/jython/src/org/python/core/PyFrozenSet.java =================================================================== --- trunk/jython/src/org/python/core/PyFrozenSet.java 2008-10-24 00:48:16 UTC (rev 5505) +++ trunk/jython/src/org/python/core/PyFrozenSet.java 2008-10-25 21:47:49 UTC (rev 5506) @@ -1,5 +1,9 @@ package org.python.core; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; + import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; @@ -11,15 +15,15 @@ public static final PyType TYPE = PyType.fromClass(PyFrozenSet.class); public PyFrozenSet() { - super(); + super(new HashSet<PyObject>()); } - public PyFrozenSet(PyType type) { - super(type); + public PyFrozenSet(PyObject data) { + super(update(new HashSet<PyObject>(), data)); } - public PyFrozenSet(PyObject data) { - super(data); + public PyFrozenSet(PyType type, PyObject data) { + super(type, update(new HashSet<PyObject>(), data)); } @ExposedNew @@ -32,7 +36,7 @@ if (new_.for_type == subtype) { if (iterable == null) { fset = Py.EmptyFrozenSet; - } else if (iterable.getClass() == PyFrozenSet.class) { + } else if (iterable.getType() == TYPE) { fset = (PyFrozenSet)iterable; } else { fset = new PyFrozenSet(iterable); @@ -41,10 +45,7 @@ } } } else { - fset = new PyFrozenSetDerived(subtype); - if (iterable != null) { - fset._update(iterable); - } + fset = new PyFrozenSetDerived(subtype, iterable); } return fset; @@ -177,4 +178,44 @@ public int hashCode() { return frozenset___hash__(); } + + public void clear() { + throw new UnsupportedOperationException(); + } + + public boolean add(Object o) { + throw new UnsupportedOperationException(); + } + + public boolean remove(Object o) { + throw new UnsupportedOperationException(); + } + + public boolean addAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException(); + } + + public Iterator iterator() { + return new Iterator() { + Iterator i = _set.iterator(); + + public boolean hasNext() { + return i.hasNext(); + } + public Object next() { + return i.next(); + } + public void remove() { + throw new UnsupportedOperationException(); + } + }; + } } Modified: trunk/jython/src/org/python/core/PyFrozenSetDerived.java =================================================================== --- trunk/jython/src/org/python/core/PyFrozenSetDerived.java 2008-10-24 00:48:16 UTC (rev 5505) +++ trunk/jython/src/org/python/core/PyFrozenSetDerived.java 2008-10-25 21:47:49 UTC (rev 5506) @@ -36,8 +36,8 @@ dict=new PyStringMap(); } - public PyFrozenSetDerived(PyType subtype) { - super(subtype); + public PyFrozenSetDerived(PyType subtype,PyObject data) { + super(subtype,data); slots=new PyObject[subtype.getNumSlots()]; dict=subtype.instDict(); } Modified: trunk/jython/src/org/python/core/PySet.java =================================================================== --- trunk/jython/src/org/python/core/PySet.java 2008-10-24 00:48:16 UTC (rev 5505) +++ trunk/jython/src/org/python/core/PySet.java 2008-10-25 21:47:49 UTC (rev 5506) @@ -3,6 +3,7 @@ import java.util.Iterator; import java.util.NoSuchElementException; +import org.python.core.util.ConcurrentHashSet; import org.python.expose.ExposedMethod; import org.python.expose.ExposedNew; import org.python.expose.ExposedType; @@ -14,15 +15,15 @@ public static final PyType TYPE = PyType.fromClass(PySet.class); public PySet() { - super(); + super(new ConcurrentHashSet<PyObject>()); } public PySet(PyType type) { - super(type); + super(type, new ConcurrentHashSet<PyObject>()); } public PySet(PyObject data) { - super(data); + super(update(new ConcurrentHashSet<PyObject>(), data)); } @ExposedNew @@ -37,8 +38,7 @@ } _set.clear(); - PyObject o = args[0]; - _update(o); + _update(args[0]); } @ExposedMethod(type = MethodType.BINARY) @@ -245,11 +245,11 @@ final PyObject set_pop() { Iterator iterator = _set.iterator(); try { - Object first = iterator.next(); + Object first = iterator.next(); _set.remove(first); - return (PyObject) first; + return (PyObject)first; } catch (NoSuchElementException e) { - throw new PyException(Py.KeyError, "pop from an empty set"); + throw new PyException(Py.KeyError, "pop from an empty set"); } } Modified: trunk/jython/src/org/python/core/PySetIterator.java =================================================================== --- trunk/jython/src/org/python/core/PySetIterator.java 2008-10-24 00:48:16 UTC (rev 5505) +++ trunk/jython/src/org/python/core/PySetIterator.java 2008-10-25 21:47:49 UTC (rev 5506) @@ -2,18 +2,20 @@ import java.util.Iterator; import java.util.Set; -import java.util.ConcurrentModificationException; public class PySetIterator extends PyObject { - private Set _set; - private int _count; - private Iterator _iterator; + private Set set; + + private int size; + + private Iterator<PyObject> iterator; + public PySetIterator(Set set) { super(); - this._set = set; - this._count = 0; - this._iterator = set.iterator(); + this.set = set; + size = set.size(); + iterator = set.iterator(); } public PyObject __iter__() { @@ -22,24 +24,12 @@ /** * Returns the next item in the iteration or raises a StopIteration. - * <p/> - * <p/> - * This differs from the core Jython Set iterator in that it checks if - * the underlying Set changes in size during the course and upon completion - * of the iteration. A RuntimeError is raised if the Set ever changes size - * or is concurrently modified. - * </p> * * @return the next item in the iteration */ public PyObject next() { PyObject o = this.__iternext__(); if (o == null) { - if (this._count != this._set.size()) { - // CPython throws an exception even if you have iterated through the - // entire set, this is not true for Java, so check by hand - throw Py.RuntimeError("dictionary changed size during iteration"); - } throw Py.StopIteration(""); } return o; @@ -48,18 +38,15 @@ /** * Returns the next item in the iteration. * - * @return the next item in the iteration - * or null to signal the end of the iteration + * @return the next item in the iteration or null to signal the end of the iteration */ public PyObject __iternext__() { - if (this._iterator.hasNext()) { - this._count++; - try { - return Py.java2py(this._iterator.next()); - } catch (ConcurrentModificationException e) { - throw Py.RuntimeError("dictionary changed size during iteration"); - } + if (set.size() != size) { + throw Py.RuntimeError("set changed size during iteration"); } + if (iterator.hasNext()) { + return iterator.next(); + } return null; } } Added: trunk/jython/src/org/python/core/util/ConcurrentHashSet.java =================================================================== --- trunk/jython/src/org/python/core/util/ConcurrentHashSet.java (rev 0) +++ trunk/jython/src/org/python/core/util/ConcurrentHashSet.java 2008-10-25 21:47:49 UTC (rev 5506) @@ -0,0 +1,90 @@ +/* Copyright (c) Jython Developers */ +package org.python.core.util; + +import java.util.AbstractSet; +import java.util.Collection; +import java.util.Iterator; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; + +/** + * A Set backed by ConcurrentHashMap. + */ +public class ConcurrentHashSet<E> extends AbstractSet<E> { + + /** The backing Map. */ + private ConcurrentHashMap<E, Object> map; + + /** Backing's KeySet. */ + private transient Set<E> keySet; + + /** Dummy value to associate with the key in the backing map. */ + private static final Object PRESENT = new Object(); + + public ConcurrentHashSet() { + map = new ConcurrentHashMap<E, Object>(); + keySet = map.keySet(); + } + + public ConcurrentHashSet(int initialCapacity) { + map = new ConcurrentHashMap<E, Object>(initialCapacity); + keySet = map.keySet(); + } + + public ConcurrentHashSet(int initialCapacity, float loadFactor, int concurrencyLevel) { + map = new ConcurrentHashMap<E, Object>(initialCapacity, loadFactor, concurrencyLevel); + keySet = map.keySet(); + } + + public int size() { + return map.size(); + } + + public boolean isEmpty() { + return map.isEmpty(); + } + + public boolean contains(Object o) { + return map.containsKey(o); + } + + public Iterator<E> iterator() { + return keySet.iterator(); + } + + public Object[] toArray() { + return keySet.toArray(); + } + + public <T> T[] toArray(T[] a) { + return keySet.toArray(a); + } + + public boolean add(E e) { + return map.put(e, PRESENT) == null; + } + + public boolean remove(Object o) { + return map.remove(o) != null; + } + + public boolean removeAll(Collection<?> c) { + return keySet.removeAll(c); + } + + public boolean retainAll(Collection<?> c) { + return keySet.retainAll(c); + } + + public void clear() { + map.clear(); + } + + public boolean equals(Object o) { + return keySet.equals(o); + } + + public int hashCode() { + return keySet.hashCode(); + } +} Modified: trunk/jython/src/templates/frozenset.derived =================================================================== --- trunk/jython/src/templates/frozenset.derived 2008-10-24 00:48:16 UTC (rev 5505) +++ trunk/jython/src/templates/frozenset.derived 2008-10-25 21:47:49 UTC (rev 5506) @@ -1,4 +1,4 @@ base_class: PyFrozenSet want_dict: true -ctr: +ctr: PyObject data incl: object This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |