com.tangosol.util.DeltaSet Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of coherence Show documentation
Show all versions of coherence Show documentation
Oracle Coherence Community Edition
/*
* 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.util;
import java.io.Serializable;
import java.util.AbstractSet;
import java.util.HashSet;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Set;
/**
* Implements a set which is based on another set, which is assumed to be
* immutable.
*
* @version 1.00, 11/30/98
* @author Cameron Purdy
*/
public class DeltaSet
extends AbstractSet
implements Cloneable, Serializable
{
// ----- constructors ---------------------------------------------------
/**
* Construct this set based on an existing set.
*
* @param set the set to base this delta set on
*/
public DeltaSet(Set set)
{
m_setOrig = set;
reset();
}
// ----- DeltaSet accessors ---------------------------------------------
/**
* Determine what items were in the original set.
*
* @return the set used to construct this DeltaSet
*/
public Set getOriginal()
{
return m_setOrig;
}
/**
* Determine if any items were added or removed.
*
* @return true if the set has been modified
*/
public boolean isModified()
{
return m_setAdded != null || m_setRemoved != null;
}
/**
* Determine what items were added to the delta set.
*
* @return an immutable set of added items
*/
public Set getAdded()
{
Set set = m_setAdded;
return set == null ? EMPTY_SET : set;
}
/**
* Determine what items were removed from the delta set.
*
* @return an immutable set of removed items
*/
public Set getRemoved()
{
Set set = m_setRemoved;
return set == null ? EMPTY_SET : set;
}
/**
* Get a mutable set of items that were added to the delta set.
*
* @return a mutable set of added items
*/
protected Set ensureAdded()
{
HashSet set = m_setAdded;
if (set == null)
{
m_setAdded = set = new HashSet();
}
return set;
}
/**
* Get a mutable set of items that were removed from the delta set.
*
* @return a mutable set of removed items
*/
protected Set ensureRemoved()
{
HashSet set = m_setRemoved;
if (set == null)
{
m_setRemoved = set = new HashSet();
}
return set;
}
/**
* Apply the changes to the underlying set ("commit").
*/
public void resolve()
{
Set setAdded = getAdded();
if (!setAdded.isEmpty())
{
m_setOrig.addAll(setAdded);
}
Set setRemoved = getRemoved();
if (!setRemoved.isEmpty())
{
m_setOrig.removeAll(setRemoved);
}
reset();
}
/**
* Discard the changes to the set ("rollback").
*/
public void reset()
{
m_setAdded = null;
m_setRemoved = 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()
{
return isEmpty() ? EMPTY_ITERATOR : new DeltaIterator();
}
/**
* Returns the number of elements in this Collection.
*
* @return the number of elements in this Collection
*/
public int size()
{
return m_setOrig.size() + getAdded().size() - getRemoved().size();
}
/**
* 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)
{
return getAdded().contains(o) || (!getRemoved().contains(o) && m_setOrig.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)
{
if (getRemoved().contains(o))
{
ensureRemoved().remove(o);
return true;
}
if (getAdded().contains(o) || m_setOrig.contains(o))
{
return false;
}
ensureAdded().add(o);
return true;
}
/**
* 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)
{
if (getRemoved().contains(o))
{
return false;
}
if (getAdded().contains(o))
{
ensureAdded().remove(o);
return true;
}
if (m_setOrig.contains(o))
{
ensureRemoved().add(o);
return true;
}
return false;
}
/**
* Removes all of the elements from this Collection.
*/
public void clear()
{
reset();
ensureRemoved().addAll(m_setOrig);
}
/**
* 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()
{
int c = size();
if (c == 0)
{
return EMPTY_ARRAY;
}
Object[] ao = new Object[c];
Set setAdded = getAdded();
c = setAdded.size();
if (c > 0)
{
setAdded.toArray(ao);
}
Set setRemoved = getRemoved();
for (Iterator iter = m_setOrig.iterator(); iter.hasNext(); )
{
Object o = iter.next();
if (!setRemoved.contains(o))
{
ao[c++] = o;
}
}
return ao;
}
// ----- Object methods -------------------------------------------------
/**
* Clone the delta set.
*
* @return a clone of this delta set
*/
public Object clone()
{
DeltaSet dset;
try
{
dset = (DeltaSet) super.clone();
}
catch (CloneNotSupportedException e)
{
throw new IllegalStateException();
}
HashSet setAdded = dset.m_setAdded;
if (setAdded != null)
{
dset.m_setAdded = (HashSet) setAdded.clone();
}
HashSet setRemoved = dset.m_setRemoved;
if (setRemoved != null)
{
dset.m_setRemoved = (HashSet) setRemoved.clone();
}
return dset;
}
// ----- inner classes --------------------------------------------------
/**
* Iterator for the contents of a delta set.
*/
protected class DeltaIterator implements Iterator
{
// ----- constructors -------------------------------------
/**
* Construct an iterator for a delta set.
*/
protected DeltaIterator()
{
m_aObject = DeltaSet.this.toArray();
}
// ----- Iterator interface -----------------------------------------
/**
* Returns true if the iteration has more elements.
*/
public boolean hasNext()
{
return m_index < m_aObject.length;
}
/**
* Returns the next element in the interation.
*
* @exception NoSuchElementException iteration has no more elements.
*/
public Object next()
{
if (m_index < m_aObject.length)
{
m_fRemovable = true;
return m_aObject[m_index++];
}
m_fRemovable = false;
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 (!m_fRemovable)
{
throw new IllegalStateException();
}
m_fRemovable = false;
DeltaSet.this.remove(m_aObject[m_index-1]);
}
// ----- data members -------------------------------------
/**
* Array of objects to iterate.
*/
private Object[] m_aObject;
/**
* The next object to return.
*/
private int m_index = 0;
/**
* True if last iterated item can be removed.
*/
private boolean m_fRemovable = false;
}
// ----- constants ------------------------------------------------------
/**
* 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];
// ----- data members ---------------------------------------------------
/**
* The underlying set (assumed immutable).
*/
private Set m_setOrig;
/**
* The added items.
*/
private HashSet m_setAdded;
/**
* The removed items.
*/
private HashSet m_setRemoved;
}