/*
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
*
* Copyright @ 2015 Atlassian Pty Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.java.sip.communicator.impl.protocol.irc.collection;
import java.util.*;
/**
* Dynamic difference set.
*
* A custom implementation that constructs a (dynamic) difference set from 2
* input instances. The first input instance is the 'source' which is used as
* the base data set. The second input is the 'removals', which are then removed
* from the source set. The dynamic set is computed each time a method call is
* executed.
*
* This set is immutable. That is, the modifier methods are unsupported. Changes
* that do happen are derived from changes in the 'source' set or the 'removals'
* set.
*
* Keep in mind that any operation on this dynamic returns a result that is only
* valid in the moment. Even calling two subsequent methods can result in
* difference or conflicting results.
*
* @author Danny van Heumen
*
* @param <E> The type of element that is stored in the set.
*/
public class DynamicDifferenceSet<E>
implements Set<E>
{
/**
* SYNCHRONIZED The source or base data set. This set is the basis and contains all the
* elements that can possibly be in the dynamic set.
*/
private final Set<E> source;
/**
* SYNCHRONIZED The removals set contains elements that are removed during the
* calculation of the difference set at the moment.
*/
private final Set<E> removals;
/**
* Constructor for creating a difference set instance.
*
* @param source The source data set.
* @param removals The removals data set which will be used to create the
* difference.
*/
public DynamicDifferenceSet(final Set<E> source,
final Set<E> removals)
{
if (source == null)
{
throw new IllegalArgumentException("source cannot be null");
}
this.source = source;
if (removals == null)
{
throw new IllegalArgumentException("removals cannot be null");
}
this.removals = removals;
}
/**
* Calculate the difference set based on the current state of the data.
*
* @return Returns the current difference set that is calculated on the fly.
*/
private Set<E> calculate()
{
final TreeSet<E> current;
synchronized (source)
{
current = new TreeSet<E>(source);
}
synchronized (removals)
{
current.removeAll(removals);
}
return current;
}
/**
* Get the size of the difference set. (Keep in mind that these numbers are
* only momentary and may be obsolete as soon as they are calculated.)
*/
@Override
public int size()
{
return calculate().size();
}
/**
* Check if the difference set of the moment is empty. (Keep in mind that
* the result may be obsolete as soon as it is calculated.)
*/
@Override
public boolean isEmpty()
{
return calculate().isEmpty();
}
/**
* Check if an element is contained in the difference set.
*/
@Override
public boolean contains(Object o)
{
return this.source.contains(o) && !this.removals.contains(o);
}
/**
* Get an iterator for the difference set of the moment.
*/
@Override
public Iterator<E> iterator()
{
return calculate().iterator();
}
/**
* Get an array of the current difference set.
*/
@Override
public Object[] toArray()
{
return calculate().toArray();
}
/**
* Get an array of the current difference set.
*/
@Override
public <T> T[] toArray(T[] a)
{
return calculate().toArray(a);
}
/**
* Adding elements to a difference set is unsupported.
*/
@Override
public boolean add(E e)
{
throw new UnsupportedOperationException();
}
/**
* Removing elements from a difference set is unsupported.
*/
@Override
public boolean remove(Object o)
{
throw new UnsupportedOperationException();
}
/**
* Check if all provided elements are contained in the difference set of the
* moment.
*/
@Override
public boolean containsAll(Collection<?> c)
{
return calculate().containsAll(c);
}
/**
* Adding elements to a difference set is unsupported.
*/
@Override
public boolean addAll(Collection<? extends E> c)
{
throw new UnsupportedOperationException();
}
/**
* Removing elements from a difference set is unsupported.
*/
@Override
public boolean removeAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
/**
* Modifying a difference set is unsupported.
*/
@Override
public boolean retainAll(Collection<?> c)
{
throw new UnsupportedOperationException();
}
/**
* Modifying a difference set is unsupported.
*/
@Override
public void clear()
{
throw new UnsupportedOperationException();
}
}