/* An actor that sorts the elements of an array.
Copyright (c) 2003-2007 The Regents of the University of California.
All rights reserved.
Permission is hereby granted, without written agreement and without
license or royalty fees, to use, copy, modify, and distribute this
software and its documentation for any purpose, provided that the above
copyright notice and the following two paragraphs appear in all copies
of this software.
IN NO EVENT SHALL THE UNIVERSITY OF CALIFORNIA BE LIABLE TO ANY PARTY
FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES
ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF
THE UNIVERSITY OF CALIFORNIA HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGE.
THE UNIVERSITY OF CALIFORNIA SPECIFICALLY DISCLAIMS ANY WARRANTIES,
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE
PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE UNIVERSITY OF
CALIFORNIA HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
ENHANCEMENTS, OR MODIFICATIONS.
PT_COPYRIGHT_VERSION_2
COPYRIGHTENDKEY
*/
package ptolemy.actor.lib;
import java.util.ArrayList;
import ptolemy.data.ArrayToken;
import ptolemy.data.BooleanToken;
import ptolemy.data.Token;
import ptolemy.data.expr.Parameter;
import ptolemy.data.expr.UtilityFunctions;
import ptolemy.data.type.ArrayType;
import ptolemy.data.type.BaseType;
import ptolemy.data.type.Type;
import ptolemy.kernel.CompositeEntity;
import ptolemy.kernel.util.IllegalActionException;
import ptolemy.kernel.util.NameDuplicationException;
import ptolemy.kernel.util.Workspace;
//////////////////////////////////////////////////////////////////////////
//// ArraySort
/**
Sort the elements of an input array. This actor reads an array from the
<i>input</i> port and sends a sorted array to the <i>output</i> port.
The input array is required to contain either strings or non-complex
scalars, or a type error will occur. The output array will have the
same type as the input and can can be sorted in either ascending or
descending order. Duplicate entries can be optionally removed.
@author Mark Oliver, Edward A. Lee
@version $ID: ArraySort.java,v1.0 2003/07/09
@since Ptolemy II 4.0
@Pt.ProposedRating Red (cxh)
@Pt.AcceptedRating Red (cxh)
*/
public class ArraySort extends Transformer {
/** Construct an actor with the given container and name.
* @param container The container.
* @param name The name of this actor.
* @exception IllegalActionException If the actor cannot be contained
* by the proposed container.
* @exception NameDuplicationException If the container already has an
* actor with this name.
*/
public ArraySort(CompositeEntity container, String name)
throws NameDuplicationException, IllegalActionException {
super(container, name);
// Set Type Constraints.
input.setTypeAtLeast(ArrayType.ARRAY_BOTTOM);
output.setTypeAtLeast(input);
// FIXME: correct type constraint for length
output.setTypeAtLeast(ArrayType.ARRAY_UNSIZED_BOTTOM);
// NOTE: Consider constraining input element types.
// This is a bit complicated to do, however.
// Set Parameters.
allowDuplicates = new Parameter(this, "allowDuplicates");
allowDuplicates.setExpression("true");
allowDuplicates.setTypeEquals(BaseType.BOOLEAN);
ascending = new Parameter(this, "ascending");
ascending.setExpression("true");
ascending.setTypeEquals(BaseType.BOOLEAN);
}
///////////////////////////////////////////////////////////////////
//// ports and parameters ////
/** Tells the actor whether or not to remove duplicate elements.
* This is a boolean that defaults to true.
*/
public Parameter allowDuplicates;
/** The sort order attribute. This tells the actor whether to
* sort the elements in ascending or descending order. It is a
* boolean that defaults to true, which means ascending order.
*/
public Parameter ascending;
///////////////////////////////////////////////////////////////////
//// public methods ////
/** Override the base class to set type constraints.
* @param workspace The workspace for the new object.
* @return A new instance of ArrayElement.
* @exception CloneNotSupportedException If a derived class contains
* an attribute that cannot be cloned.
*/
public Object clone(Workspace workspace) throws CloneNotSupportedException {
ArraySort newObject = (ArraySort) super.clone(workspace);
newObject.input.setTypeAtLeast(ArrayType.ARRAY_BOTTOM);
newObject.output.setTypeAtLeast(newObject.input);
newObject.output.setTypeAtLeast(ArrayType.ARRAY_UNSIZED_BOTTOM);
return newObject;
}
/** Consume at most one array from the input port and produce
* a sorted array on the <i>output</i> port.
* If there is no token on the input, then no output is produced.
* If the input is an empty array, then the same empty array token
* is produced on the output.
* @exception IllegalActionException If there is no director, or
* if sorting is not supported for the input array.
*/
public void fire() throws IllegalActionException {
super.fire();
if (input.hasToken(0)) {
ArrayToken token = (ArrayToken) input.get(0);
Type inputElementType = token.getElementType();
if (token.length() == 0) {
output.send(0, token);
return;
}
boolean ascendingValue = ((BooleanToken) ascending.getToken())
.booleanValue();
ArrayToken result = null;
try {
if (ascendingValue) {
result = UtilityFunctions.sort(token);
} else {
result = UtilityFunctions.sortDescending(token);
}
} catch (ClassCastException ex) {
// The call to sort() above throws ClassCastException if
// sorting is not supported. This is not ideal, so we
// remap this to IllegalActionException.
throw new IllegalActionException(this, ex.getMessage());
}
boolean allowDuplicatesValue = ((BooleanToken) allowDuplicates
.getToken()).booleanValue();
if (!allowDuplicatesValue) {
// Strip out duplicates.
ArrayList list = new ArrayList();
Token previous = result.getElement(0);
list.add(previous);
for (int i = 1; i < result.length(); i++) {
Token next = result.getElement(i);
if (!next.isEqualTo(previous).booleanValue()) {
list.add(next);
previous = next;
}
}
// Dummy array to give the run-time type to toArray().
Token[] dummy = new Token[0];
result = new ArrayToken(inputElementType, (Token[]) list
.toArray(dummy));
}
output.send(0, result);
}
}
}