001: package org.python.modules.sets;
002:
003: import org.python.core.Py;
004: import org.python.core.PyException;
005: import org.python.core.PyIgnoreMethodTag;
006: import org.python.core.PyList;
007: import org.python.core.PyObject;
008: import org.python.core.PyTuple;
009: import org.python.core.__builtin__;
010: import org.python.core.PyType;
011:
012: import java.util.Collection;
013: import java.util.Collections;
014: import java.util.HashSet;
015: import java.util.Iterator;
016: import java.util.Set;
017:
018: public abstract class BaseSet extends PyObject /*implements Set*/{
019:
020: /**
021: * The underlying container. HashSet is used rather than Set because
022: * clone is protected on Object and I didn't want to cast.
023: */
024: protected HashSet _set;
025:
026: /**
027: * Create a new, empty set instance.
028: */
029: public BaseSet() {
030: super ();
031: this ._set = new HashSet();
032: }
033:
034: /**
035: * Create a new set instance from the values of the iterable object.
036: *
037: * @param data An iterable instance.
038: */
039: public BaseSet(PyObject data) {
040: super ();
041: this ._set = new HashSet();
042: this ._update(data);
043: }
044:
045: public BaseSet(PyType type) {
046: super (type);
047: this ._set = new HashSet();
048: }
049:
050: /**
051: * Update the underlying set with the contents of the iterable.
052: *
053: * @param data An iterable instance.
054: * @throws PyIgnoreMethodTag Ignore.
055: */
056: protected void _update(PyObject data) throws PyIgnoreMethodTag {
057:
058: if (data instanceof BaseSet) {
059: // Skip the iteration if both are sets
060: this ._set.addAll(((BaseSet) data)._set);
061: return;
062: }
063:
064: PyObject value = null;
065: if (data.__findattr__("__iter__") != null) {
066: PyObject iter = data.__iter__();
067: while ((value = iter.__iternext__()) != null) {
068: try {
069: this ._set.add(value);
070: } catch (PyException e) {
071: PyObject immutable = this .asImmutable(e, value);
072: this ._set.add(immutable);
073: }
074: }
075: } else {
076: int i = 0;
077: while (true) {
078: try {
079: value = data.__finditem__(i++);
080: if (value == null) {
081: break;
082: }
083: } catch (PyException e) {
084: if (Py.matchException(e, Py.AttributeError)) {
085: throw Py.TypeError("object not iterable");
086: }
087: throw e;
088: }
089: try {
090: this ._set.add(value);
091: } catch (PyException e) {
092: PyObject immutable = this .asImmutable(e, value);
093: this ._set.add(immutable);
094: }
095: }
096: }
097: }
098:
099: /**
100: * The union of <code>this</code> with <code>other</code>.
101: * <p/>
102: * <br/>
103: * (I.e. all elements that are in either set)
104: *
105: * @param other A <code>BaseSet</code> instance.
106: * @return The union of the two sets as a new set.
107: */
108: public PyObject __or__(PyObject other) {
109: return baseset___or__(other);
110: }
111:
112: final PyObject baseset___or__(PyObject other) {
113: if (!(other instanceof BaseSet)) {
114: throw Py.TypeError("Not Implemented");
115: }
116: return baseset_union(other);
117: }
118:
119: /**
120: * The intersection of the <code>this</code> with <code>other</code>.
121: * <p/>
122: * <br/>
123: * (I.e. all elements that are in both sets)
124: *
125: * @param other A <code>BaseSet</code> instance.
126: * @return The intersection of the two sets as a new set.
127: */
128: public PyObject __and__(PyObject other) {
129: return baseset___and__(other);
130: }
131:
132: final PyObject baseset___and__(PyObject other) {
133: if (!(other instanceof BaseSet)) {
134: throw Py.TypeError("Not Implemented");
135: }
136: return baseset_intersection(other);
137: }
138:
139: /**
140: * The difference of the <code>this</code> with <code>other</code>.
141: * <p/>
142: * <br/>
143: * (I.e. all elements that are in this set and not in the other)
144: *
145: * @param other A <code>BaseSet</code> instance.
146: * @return The difference of the two sets as a new set.
147: */
148: public PyObject __sub__(PyObject other) {
149: return baseset___sub__(other);
150: }
151:
152: final PyObject baseset___sub__(PyObject other) {
153: if (!(other instanceof BaseSet)) {
154: throw Py.TypeError("Not Implemented");
155: }
156: return difference(other);
157: }
158:
159: public PyObject difference(PyObject other) {
160: return baseset_difference(other);
161: }
162:
163: final PyObject baseset_difference(PyObject other) {
164: BaseSet iterable = (other instanceof BaseSet) ? (BaseSet) other
165: : new PySet(other);
166: Set set = iterable._set;
167: BaseSet o = (BaseSet) this .getType().__call__();
168: for (Iterator i = this ._set.iterator(); i.hasNext();) {
169: Object p = i.next();
170: if (!set.contains(p)) {
171: o._set.add(p);
172: }
173: }
174:
175: return o;
176: }
177:
178: /**
179: * The symmetric difference of the <code>this</code> with <code>other</code>.
180: * <p/>
181: * <br/>
182: * (I.e. all elements that are in exactly one of the sets)
183: *
184: * @param other A <code>BaseSet</code> instance.
185: * @return The symmetric difference of the two sets as a new set.
186: */
187: public PyObject __xor__(PyObject other) {
188: return baseset___xor__(other);
189: }
190:
191: final PyObject baseset___xor__(PyObject other) {
192: if (!(other instanceof BaseSet)) {
193: throw Py.TypeError("Not Implemented");
194: }
195: return symmetric_difference(other);
196: }
197:
198: public PyObject symmetric_difference(PyObject other) {
199: return baseset_symmetric_difference(other);
200: }
201:
202: public PyObject baseset_symmetric_difference(PyObject other) {
203: BaseSet iterable = (other instanceof BaseSet) ? (BaseSet) other
204: : new PySet(other);
205: BaseSet o = (BaseSet) this .getType().__call__();
206: for (Iterator i = this ._set.iterator(); i.hasNext();) {
207: Object p = i.next();
208: if (!iterable._set.contains(p)) {
209: o._set.add(p);
210: }
211: }
212: for (Iterator i = iterable._set.iterator(); i.hasNext();) {
213: Object p = i.next();
214: if (!this ._set.contains(p)) {
215: o._set.add(p);
216: }
217: }
218: return o;
219: }
220:
221: /**
222: * The hashCode of the set. Only immutable instances can be hashed.
223: *
224: * @return The hashCode of the set.
225: */
226: public abstract int hashCode();
227:
228: /**
229: * The length of the set.
230: *
231: * @return The length of the set.
232: */
233: public int __len__() {
234: return baseset___len__();
235: }
236:
237: final int baseset___len__() {
238: return this ._set.size();
239: }
240:
241: /**
242: * Determines if the instance is considered <code>true</code> by Python.
243: * This implementation returns true if the set is not empty.
244: *
245: * @return <code>true</code> if the set is not empty, <code>false</code> otherwise
246: */
247: public boolean __nonzero__() {
248: return baseset___nonzero__();
249: }
250:
251: final boolean baseset___nonzero__() {
252: return !this ._set.isEmpty();
253: }
254:
255: /**
256: * Produce an iterable object.
257: *
258: * @return An iteration of the set.
259: */
260: public PyObject __iter__() {
261: return new PySetIterator(this ._set);
262: }
263:
264: public boolean __contains__(PyObject other) {
265: return baseset___contains__(other);
266: }
267:
268: final boolean baseset___contains__(PyObject other) {
269: return this ._set.contains(other);
270: }
271:
272: public PyObject __eq__(PyObject other) {
273: return baseset___eq__(other);
274: }
275:
276: final PyObject baseset___eq__(PyObject other) {
277: if (other instanceof BaseSet) {
278: BaseSet bs = this ._binary_sanity_check(other);
279: return Py.newBoolean(this ._set.equals(bs._set));
280: }
281: return Py.Zero;
282: }
283:
284: public PyObject __ne__(PyObject other) {
285: return baseset___ne__(other);
286: }
287:
288: final PyObject baseset___ne__(PyObject other) {
289: if (other instanceof BaseSet) {
290: BaseSet bs = this ._binary_sanity_check(other);
291: return Py.newBoolean(!this ._set.equals(bs._set));
292: }
293: return Py.One;
294: }
295:
296: public PyObject __le__(PyObject other) {
297: return baseset___le__(other);
298: }
299:
300: final PyObject baseset___le__(PyObject other) {
301: return this .baseset_issubset(other);
302: }
303:
304: public PyObject __ge__(PyObject other) {
305: return baseset___ge__(other);
306: }
307:
308: final PyObject baseset___ge__(PyObject other) {
309: return this .baseset_issuper set(other);
310: }
311:
312: public PyObject __lt__(PyObject other) {
313: return baseset___lt__(other);
314: }
315:
316: final PyObject baseset___lt__(PyObject other) {
317: BaseSet bs = this ._binary_sanity_check(other);
318: return Py.newBoolean(this .__len__() < bs.__len__()
319: && this .baseset_issubset(other).__nonzero__());
320: }
321:
322: public PyObject __gt__(PyObject other) {
323: return baseset___gt__(other);
324: }
325:
326: public PyObject baseset___gt__(PyObject other) {
327: BaseSet bs = this ._binary_sanity_check(other);
328: return Py.newBoolean(this .__len__() > bs.__len__()
329: && this .baseset_issuper set(other).__nonzero__());
330: }
331:
332: /**
333: * Used for pickling. Uses the module <code>setsfactory</sets> to
334: * export safe constructors.
335: *
336: * @return a tuple of (constructor, (elements))
337: */
338: public PyObject __reduce__() {
339: return baseset___reduce__();
340: }
341:
342: final PyObject baseset___reduce__() {
343: String name = getType().getFullName();
344: PyObject factory = __builtin__.__import__("setsfactory");
345: PyObject func = factory.__getattr__(name);
346: return new PyTuple(
347: new PyObject[] {
348: func,
349: new PyTuple(new PyObject[] { new PyList(
350: (PyObject) this ) }) });
351: }
352:
353: public PyObject __deepcopy__(PyObject memo) {
354: return baseset___deepcopy__(memo);
355: }
356:
357: final PyObject baseset___deepcopy__(PyObject memo) {
358: PyObject copy = __builtin__.__import__("copy");
359: PyObject deepcopy = copy.__getattr__("deepcopy");
360: BaseSet result = (BaseSet) this .getType().__call__();
361: memo.__setitem__(Py.newInteger(Py.id(this )), result);
362: for (Iterator iterator = this ._set.iterator(); iterator
363: .hasNext();) {
364: result._set.add(deepcopy.__call__(Py.java2py(iterator
365: .next()), memo));
366: }
367: return result;
368: }
369:
370: /**
371: * Return this instance as a Java object. Only coerces to Collection and subinterfaces.
372: *
373: * @param c The Class to coerce to.
374: * @return the underlying HashSet (not a copy)
375: */
376: public Object __tojava__(Class c) {
377: if (Collection.class.isAssignableFrom(c)) {
378: return Collections.unmodifiableSet(this ._set);
379: }
380: return super .__tojava__(c);
381: }
382:
383: public PyObject baseset_union(PyObject other) {
384: BaseSet result = (BaseSet) this .getType().__call__(this );
385: result._update(other);
386: return result;
387: }
388:
389: public PyObject baseset_intersection(PyObject other) {
390:
391: PyObject little, big;
392: if (!(other instanceof BaseSet)) {
393: other = new PySet(other);
394: }
395:
396: if (this .__len__() <= __builtin__.len(other)) {
397: little = this ;
398: big = other;
399: } else {
400: little = other;
401: big = this ;
402: }
403:
404: PyObject common = __builtin__.filter(big
405: .__getattr__("__contains__"), little);
406: return other.getType().__call__(common);
407: }
408:
409: public PyObject baseset_copy() {
410: BaseSet copy = (BaseSet) this .getType().__call__();
411: copy._set = (HashSet) this ._set.clone();
412: return copy;
413: }
414:
415: public PyObject baseset_issubset(PyObject other) {
416: BaseSet bs = this ._binary_sanity_check(other);
417: if (this .__len__() > bs.__len__()) {
418: return Py.Zero;
419: }
420: for (Iterator iterator = this ._set.iterator(); iterator
421: .hasNext();) {
422: if (!bs._set.contains(iterator.next())) {
423: return Py.Zero;
424: }
425: }
426: return Py.One;
427: }
428:
429: public PyObject baseset_issuper set(PyObject other) {
430: BaseSet bs = this ._binary_sanity_check(other);
431: if (this .__len__() < bs.__len__()) {
432: return Py.Zero;
433: }
434: for (Iterator iterator = bs._set.iterator(); iterator.hasNext();) {
435: if (!this ._set.contains(iterator.next())) {
436: return Py.Zero;
437: }
438: }
439: return Py.One;
440: }
441:
442: final String baseset_toString() {
443: return toString();
444: }
445:
446: public String toString() {
447: String name = getType().getFullName();
448: StringBuffer buf = new StringBuffer(name).append("([");
449: for (Iterator i = this ._set.iterator(); i.hasNext();) {
450: buf.append(((PyObject) i.next()).__repr__().toString());
451: if (i.hasNext()) {
452: buf.append(", ");
453: }
454: }
455: buf.append("])");
456: return buf.toString();
457: }
458:
459: protected final BaseSet _binary_sanity_check(PyObject other)
460: throws PyIgnoreMethodTag {
461: try {
462: return (BaseSet) other;
463: } catch (ClassCastException e) {
464: throw Py
465: .TypeError("Binary operation only permitted between sets");
466: }
467: }
468:
469: /**
470: * If the exception <code>e</code> is a <code>TypeError</code>, attempt to convert
471: * the object <code>value</code> into an ImmutableSet.
472: *
473: * @param e The exception thrown from a hashable operation.
474: * @param value The object which was unhashable.
475: * @return An ImmutableSet if available, a <code>TypeError</code> is thrown otherwise.
476: */
477: protected final PyObject asImmutable(PyException e, PyObject value) {
478: if (Py.matchException(e, Py.TypeError)) {
479: PyObject transform = value.__findattr__("_as_immutable");
480: if (transform != null) {
481: return transform.__call__();
482: }
483: }
484: throw e;
485: }
486:
487: // public int size() {
488: // return this._set.size();
489: // }
490: //
491: // public void clear() {
492: // this._set.clear();
493: // }
494: //
495: // public boolean isEmpty() {
496: // return this._set.isEmpty();
497: // }
498: //
499: // public Object[] toArray() {
500: // return this._set.toArray();
501: // }
502: //
503: // public boolean add(Object o) {
504: // return this._set.add(o);
505: // }
506: //
507: // public boolean contains(Object o) {
508: // return this._set.contains(o);
509: // }
510: //
511: // public boolean remove(Object o) {
512: // return this._set.remove(o);
513: // }
514: //
515: // public boolean addAll(Collection c) {
516: // return this._set.addAll(c);
517: // }
518: //
519: // public boolean containsAll(Collection c) {
520: // return this._set.containsAll(c);
521: // }
522: //
523: // public boolean removeAll(Collection c) {
524: // return this._set.removeAll(c);
525: // }
526: //
527: // public boolean retainAll(Collection c) {
528: // return this._set.retainAll(c);
529: // }
530: //
531: // public Iterator iterator() {
532: // return this._set.iterator();
533: // }
534: //
535: // public Object[] toArray(Object a[]) {
536: // return this._set.toArray(a);
537: // }
538: }
|