/*
* FreeMarker: a tool that allows Java programs to generate HTML
* output using templates.
* Copyright (C) 1998-2004 Benjamin Geer
* Email: beroul@users.sourceforge.net
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/
package freemarker.template;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
/**
* A simple list model that represents a range of values. For memory
* conservation, we store the from and to values only. For a range that iterates
* backwards, set the <code>toValue</code> to be lower than the
* <code>fromValue</code>.
*
* @version $Id: FastListRange.java 1051 2004-10-24 09:14:44Z run2000 $
* @since 1.8
*/
public final class FastListRange implements TemplateListModel2, TemplateIndexedModel, Serializable {
/** The beginning of the list range. */
private final long fromValue;
/**
* The end of the list range, inclusive. Can be lower than the
* <code>fromValue</code> field, to indicate that the list should be stepped
* through backwards. This also implies that the list cannot be empty.
*/
private final long toValue;
/** Whether we step forwards or backwards in the list. */
private transient int step;
/**
* The difference between the <code>fromValue</code> and
* <code>toValue</code> values.
*/
private transient long range;
/** Serialization id, for future compatibility. */
static final long serialVersionUID = -3029960574903790084L;
/**
* Constructor that takes from and to values to represent the indexModel of
* values. Both from and to values are inclusive.
*
* @param fromValue
* the start of the range
* @param toValue
* the end of the range
*/
public FastListRange(long fromValue, long toValue) {
this.fromValue = fromValue;
this.toValue = toValue;
step = (fromValue > toValue) ? -1 : 1;
range = Math.abs(toValue - fromValue);
}
/**
* Is the range empty?
*
* @return <code>false</code>, because there is always at least one value in
* the range
*/
public boolean isEmpty() {
return false;
}
/**
* Get the value at the specified index.
*
* @param index
* the index of the item we're after
* @return a new <code>FastNumber</code> containing the value at the given
* index
* @throws freemarker.template.TemplateModelException
* the index was out of bounds
*/
public TemplateModel getAtIndex(long index) throws TemplateModelException {
if ((index < 0) || (index > range)) {
throw new TemplateModelException("Index out of bounds for given indexModel");
}
return new FastNumber(fromValue + (index * step));
}
/**
* Get a new iterator for this template model.
*
* @return an iterator to use over the values in this range
*/
public TemplateIteratorModel templateIterator() {
return new FastIndexedIterator(this, 0, range);
}
/**
* Reclaim the iterator. In this case we don't do anything, since we don't
* pool iterators in this implementation.
*
* @param iterator
* the iterator to be reclaimed
*/
public void releaseIterator(TemplateIteratorModel iterator) {
// Do nothing
}
/**
* Serialized form consists of only the from and to values. Make sure
* transient fields are repopulated when we deserialize this object.
*
* @param stream
* the stream from which to deserialize
* @throws IOException
* there was an IO problem with the stream
* @throws ClassNotFoundException
* the classes being deserialized could not be found
*/
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
stream.defaultReadObject();
step = (fromValue > toValue) ? -1 : 1;
range = Math.abs(toValue - fromValue);
}
/**
* <p>
* Return the string value of this list range. The values typically look
* like this:
* </p>
*
* <pre>
* [ {fromValue} .. {toValue} ]
* </pre>
*
* @return a <code>String</code> representing this range
*/
public String toString() {
StringBuffer buffer = new StringBuffer(16);
buffer.append("[ ");
buffer.append(fromValue);
buffer.append(" .. ");
buffer.append(toValue);
buffer.append(" ]");
return buffer.toString();
}
/**
* Tests this object for equality with the given object.
*
* @param o
* the object to be compared with
* @return <code>true</code> if the objects are equal, otherwise
* <code>false</code>
*/
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (!(o instanceof FastListRange)) {
return false;
}
final FastListRange fastListRange = (FastListRange) o;
if (fromValue != fastListRange.fromValue) {
return false;
}
return (toValue == fastListRange.toValue);
}
/**
* Return the hash value for this object.
*
* @return a hash code corresponding to the object's value
*/
public int hashCode() {
int result;
result = (int) (fromValue ^ (fromValue >>> 32));
result = 29 * result + (int) (toValue ^ (toValue >>> 32));
return result;
}
}