
com.tangosol.dev.compiler.java.DualSet Maven / Gradle / Ivy
/*
* Copyright (c) 2000, 2020, Oracle and/or its affiliates.
*
* Licensed under the Universal Permissive License v 1.0 as shown at
* http://oss.oracle.com/licenses/upl.
*/
package com.tangosol.dev.compiler.java;
import com.tangosol.util.DeltaSet;
import com.tangosol.util.NullImplementation;
import com.tangosol.util.NullImplementation;
import java.util.Collection;
import java.util.Iterator;
import java.util.Set;
import java.util.AbstractSet;
import java.util.HashSet;
import java.util.NoSuchElementException;
/**
* Implements a set which can be treated as two different sets or as a single
* set. This implementation is intended to be used for determination of
* definite assignment of variables in Java source code.
*
* From the Java Language Specification (16):
*
* In order to precisely specify all the cases of definite assignment, the
* rules in this section define two technical terms:
* - whether a local variable is definitely assigned before a statement
* or expression, and
* - whether a local variable is definitely assigned after a statement
* or expression.
* In order to specify boolean-valued expressions, the latter notion is
* refined into two cases:
* - whether a local variable is definitely assigned after the
* expression when true, and
* - whether a local variable is definitely assigned after the
* expression when false.
*
* The dual set implementation is typically used as a single set. However,
* when dealing with those language constructs requiring "when true" vs.
* "when false" functionality, the dual set maintains two separate sets
* internally. When the two sets are maintained, the dual set represents
* the union of the two sets; for example, if the dual set is used to track
* unassigned variables, then a variable is considered unassigned ("not
* definitely assigned") if it appears in either set.
*
* @version 1.00, 11/30/98
* @author Cameron Purdy
*/
public class DualSet extends AbstractSet
{
// ----- constructors ---------------------------------------------------
/**
* Construct this set based on an existing set.
*
* @param set the set to base this delta set on
*/
public DualSet(Set set)
{
dsetTrue = new DeltaSet(set);
}
// ----- DualSet accessors ---------------------------------------------
/**
* Determine if any items were added or removed.
*
* @return true if the set has been modified
*/
public boolean isModified()
{
return dsetTrue.isModified() || dsetFalse != null && dsetFalse.isModified();
}
/**
* Determine what items were added to the dual set.
*
* @return an immutable set of added items
*/
public Set getAdded()
{
DeltaSet dsetTrue = this.dsetTrue;
DeltaSet dsetFalse = this.dsetFalse;
if (dsetFalse == null)
{
return dsetTrue.getAdded();
}
// if one of the sets (when true/when false) is empty, then return
// the items added to the other
Set setAddedTrue = dsetTrue .getAdded();
Set setAddedFalse = dsetFalse.getAdded();
if (setAddedTrue.isEmpty())
{
return setAddedFalse;
}
if (setAddedFalse.isEmpty())
{
return setAddedTrue;
}
// determine what items have been added to either set (union)
HashSet setAdded = new HashSet(setAddedTrue);
setAdded.addAll(setAddedFalse);
return setAdded;
}
/**
* Determine what items were removed from the dual set.
*
* @return an immutable set of removed items
*/
public Set getRemoved()
{
DeltaSet dsetTrue = this.dsetTrue;
DeltaSet dsetFalse = this.dsetFalse;
if (dsetFalse == null)
{
return dsetTrue.getRemoved();
}
// if one of the sets (when true/when false) is empty, then no
// items have been removed from both
Set setRemovedTrue = dsetTrue .getRemoved();
Set setRemovedFalse = dsetFalse.getRemoved();
if (setRemovedTrue.isEmpty() || setRemovedFalse.isEmpty())
{
return EMPTY_SET;
}
// determine what items have been removed from both sets
// (intersection)
HashSet setRemoved = new HashSet(setRemovedTrue);
setRemoved.retainAll(setRemovedFalse);
return setRemoved;
}
/**
* Determine what items are in the "when true" set.
*
* @return the "when true" DeltaSet
*/
public DeltaSet getTrueSet()
{
if (dsetFalse == null)
{
dsetFalse = (DeltaSet) dsetTrue.clone();
}
return dsetTrue;
}
/**
* Determine what items are in the "when false" set.
*
* @return the "when false" DeltaSet
*/
public DeltaSet getFalseSet()
{
DeltaSet dset = dsetFalse;
if (dset == null)
{
dsetFalse = dset = (DeltaSet) dsetTrue.clone();
}
return dset;
}
/**
* Swap the "when true" and "when false" sets.
*/
public void negate()
{
if (dsetFalse != null)
{
DeltaSet dset = dsetFalse;
dsetFalse = dsetTrue;
dsetTrue = dset;
}
}
/**
* Determine if the dual set has not yet needed to be backed by two sets.
*
* @return true if the true and false sets are one and the same
*/
public boolean isSingle()
{
return dsetFalse == null;
}
/**
* Merge the information in the "when true" and "when false" sets.
*/
public void merge()
{
if (dsetFalse != null)
{
DeltaSet dsetTrue = this.dsetTrue;
DeltaSet dsetFalse = this.dsetFalse;
// any items added to dsetFalse must be added to dsetTrue
Set setAdded = dsetFalse.getAdded();
if (!setAdded.isEmpty())
{
dsetTrue.addAll(setAdded);
}
// any items removed from dsetTrue but not from dsetFalse must
// be un-removed from (added to) dsetTrue
Set setRemovedTrue = dsetTrue .getRemoved();
Set setRemovedFalse = dsetFalse.getRemoved();
if (!setRemovedTrue.equals(setRemovedFalse))
{
HashSet set = new HashSet(setRemovedTrue);
set.removeAll(setRemovedFalse);
dsetTrue.addAll(set);
}
// all changes are resolved; discard the second set
dsetFalse = null;
}
}
/**
* Apply the changes to the underlying set ("commit").
*/
public void resolve()
{
merge();
dsetTrue.resolve();
}
/**
* Discard the changes to the set.
*/
public void reset()
{
dsetTrue.reset();
dsetFalse = null;
}
// ----- Set interface --------------------------------------------------
/**
* Returns an Iterator over the elements contained in this Collection.
*
* @return an Iterator over the elements contained in this Collection
*/
public Iterator iterator()
{
if (dsetFalse == null)
{
return dsetTrue.iterator();
}
else
{
return new DualIterator();
}
}
/**
* Returns the number of elements in this Collection.
*
* @return the number of elements in this Collection
*/
public int size()
{
DeltaSet dsetTrue = this.dsetTrue;
DeltaSet dsetFalse = this.dsetFalse;
int c = dsetTrue.size();
if (dsetFalse == null)
{
return c;
}
Set setAddedFalse = dsetFalse.getAdded();
if (setAddedFalse.isEmpty())
{
return c;
}
// since both delta sets are based on the same underlying set,
// just check which items were added to the false set which were
// not already counted in the "when true" delta set
Set setAddedTrue = dsetTrue.getAdded();
for (Iterator iter = setAddedFalse.iterator(); iter.hasNext(); )
{
if (!setAddedTrue.contains(iter.next()))
{
++c;
}
}
return c;
}
/**
* Returns true if this Collection contains the specified element. More
* formally, returns true if and only if this Collection contains at least
* one element e
such that (o==null ? e==null :
* o.equals(e))
.
*
* @param o the object to search for in the set
*
* @return true if this set contains the specified object
*/
public boolean contains(Object o)
{
if (dsetFalse == null)
{
return dsetTrue.contains(o);
}
return dsetTrue.contains(o) || dsetFalse.contains(o);
}
/**
* Ensures that this Collection contains the specified element.
*
* @param o element whose presence in this Collection is to be ensured
*
* @return true if the Collection changed as a result of the call
*/
public boolean add(Object o)
{
boolean f = dsetTrue.add(o);
if (dsetFalse != null)
{
f &= dsetFalse.add(o);
}
return f;
}
/**
* Removes a single instance of the specified element from this Collection,
* if it is present (optional operation). More formally, removes an
* element e
such that (o==null ? e==null :
* o.equals(e))
, if the Collection contains one or more such
* elements. Returns true if the Collection contained the specified
* element (or equivalently, if the Collection changed as a result of the
* call).
*
* @param o element to be removed from this Collection, if present
*
* @return true if the Collection contained the specified element
*/
public boolean remove(Object o)
{
boolean f = dsetTrue.remove(o);
if (dsetFalse != null)
{
f &= dsetFalse.remove(o);
}
return f;
}
/**
* Removes all of the elements from this Collection.
*/
public void clear()
{
dsetTrue.clear();
dsetFalse = null;
}
/**
* Returns an array containing all of the elements in this Set.
* Obeys the general contract of Collection.toArray.
*
* @return an Object array containing all of the elements in this Set
*/
public Object[] toArray()
{
DeltaSet dsetTrue = this.dsetTrue;
DeltaSet dsetFalse = this.dsetFalse;
if (dsetFalse == null || dsetFalse.getAdded().isEmpty())
{
return dsetTrue.toArray();
}
int c = size();
Object[] ao = new Object[c];
// get the items from the "when true" set
c = dsetTrue.size();
if (c > 0)
{
dsetTrue.toArray(ao);
}
// add any missing items from the "when false" set
Set setAddedTrue = dsetTrue .getAdded();
Set setAddedFalse = dsetFalse.getAdded();
for (Iterator iter = setAddedFalse.iterator(); iter.hasNext(); )
{
Object o = iter.next();
if (!setAddedTrue.contains(o))
{
ao[c++] = o;
}
}
return ao;
}
// ----- inner classes --------------------------------------------------
/**
* Iterator for the contents of a dual set.
*/
protected class DualIterator implements Iterator
{
/**
* Construct an iterator for a dual set.
*/
protected DualIterator()
{
ao = toArray();
}
/**
* Returns true if the iteration has more elements.
*/
public boolean hasNext()
{
return i < ao.length;
}
/**
* Returns the next element in the interation.
*
* @exception NoSuchElementException iteration has no more elements.
*/
public Object next()
{
if (i < ao.length)
{
fRemovable = true;
return ao[i++];
}
throw new NoSuchElementException();
}
/**
* Removes from the underlying Collection the last element returned by the
* Iterator . This method can be called only once per call to next The
* behavior of an Iterator is unspecified if the underlying Collection is
* modified while the iteration is in progress in any way other than by
* calling this method. Optional operation.
*
* @exception IllegalStateException next has not yet been called,
* or remove has already been called after the last call
* to next.
*/
public void remove()
{
if (!fRemovable)
{
throw new IllegalStateException();
}
DualSet.this.remove(ao[i-1]);
fRemovable = false;
}
/**
* Array of objects to iterate.
*/
private Object[] ao;
/**
* The next object to return.
*/
private int i = 0;
/**
* True if last iterated item can be removed.
*/
private boolean fRemovable = false;
}
// ----- data members ---------------------------------------------------
/**
*
*/
private DeltaSet dsetTrue;
/**
*
*/
private DeltaSet dsetFalse;
/**
* An empty immutable set.
*/
private static final Set EMPTY_SET = NullImplementation.getSet();
/**
* An empty immutable iterator.
*/
private static final Iterator EMPTY_ITERATOR = NullImplementation.getIterator();
/**
* An empty immutable array.
*/
private static final Object[] EMPTY_ARRAY = new Object[0];
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy