/*
* 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.ObjectOutputStream;
import java.io.ObjectStreamException;
import java.io.ObjectStreamField;
import java.io.Serializable;
/**
* <p>
* An unsynchronised, immutable variation of the {@link SimpleScalar} class to
* handle boolean values. This avoids the need for synchronization, since we no
* longer have any situations where the underlying value changes. This means
* that <code>FastBoolean</code> should be significantly faster in some cases.
* </p>
*
* <p>
* As of 1.8, this class also implements the {@link TemplateNumberModel}
* interface, in order to simplify casting of boolean literals to numbers.
* </p>
*
* <p>
* <b>Note:</b><br />
* Unlike the other Fast classes, <code>FastBoolean</code> uses a factory method
* to create instances. This can dramatically reduce the amount of garbage
* generated by reusing the same objects when possible.
* </p>
*
* @version $Id: FastBoolean.java 1080 2005-08-28 10:18:09Z run2000 $
* @see FastHash
* @see FastList
* @see FastScalar
* @see FastNumber
* @since 1.7.5
*/
public final class FastBoolean implements TemplateScalarModel, TemplateNumberModel, TemplateObjectModel, Serializable {
/** Represents a true boolean expression. */
public static final FastBoolean TRUE = new FastBoolean(true);
/** Represents a false boolean expression. */
public static final FastBoolean FALSE = new FastBoolean(false);
private boolean isEmpty;
private short numberValue;
private String stringValue;
/** Serialization id, for future compatibility. */
private static final long serialVersionUID = 3879422004795437198L;
/**
* Serialize as a single boolean value, for compactness.
*
* @serialField
* booleanValue boolean the boolean value that this
* <code>FastBoolean</code> represents
*/
private static final ObjectStreamField[] serialPersistentFields = { new ObjectStreamField("booleanValue", Boolean.TYPE) };
/**
* Constructs an instance of this object with an initial value.
*
* @param value
* the value of the boolean expression
*/
private FastBoolean(boolean value) {
isEmpty = !value;
if (value) {
stringValue = "true";
numberValue = 1;
} else {
stringValue = null;
numberValue = 0;
}
}
/**
* Returns the boolean value as a <code>String</code>.
*
* @return the <code>String</code> value of this scalar.
*/
public String getAsString() throws TemplateModelException {
return stringValue;
}
/**
* Returns the boolean value as a <code>long</code>.
*
* @return the <code>long</code> value of this scalar.
* @since 1.8
*/
public long getAsNumber() throws TemplateModelException {
return numberValue;
}
/**
* Is the model empty?
*
* @return <code>true</code> if this object is empty, otherwise
* <code>false</code>
*/
public boolean isEmpty() throws TemplateModelException {
return isEmpty;
}
/**
* Return the model as a Boolean object. This is for the benefit of the
* reflection library.
*
* @return <code>Boolean.TRUE</code> if this object is true, otherwise
* <code>Boolean.FALSE</code>
*/
public Object getAsObject() throws TemplateModelException {
return isEmpty ? Boolean.FALSE : Boolean.TRUE;
}
/**
* Factory method for retrieving instances of a <code>FastBoolean</code>.
*
* @param isTrue
* <code>true</code> if we want a True instance, otherwise
* <code>false</code> to retrieve a False instance
* @return a True instance if <code>isTrue</code> is set, otherwise a False
* instance
*/
public static FastBoolean getInstance(boolean isTrue) {
return isTrue ? TRUE : FALSE;
}
/**
* Returns true if the passed object is the TRUE instance.
*
* @param value
* the value to compare against the TRUE instance
* @return <code>true</code> if this is the TRUE instance, otherwise
* <code>false</code>
*/
public static boolean getBoolean(Object value) {
return value == TRUE;
}
/**
* For serialization purposes, always resolve a de-serialized object back to
* the singleton instance. This ensures that any strict equality tests
* remain valid after serialization.
*/
private Object readResolve() throws ObjectStreamException {
if (isEmpty) {
return FALSE;
} else {
return TRUE;
}
}
/**
* For serialization, read this object as a single boolean value.
*
* @param stream
* the input stream to read serialized objects from
*/
private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException {
ObjectInputStream.GetField fields = stream.readFields();
boolean value = fields.get("booleanValue", false);
// Recreate the original fields
isEmpty = !value;
if (value) {
stringValue = "true";
numberValue = 1;
} else {
stringValue = null;
numberValue = 0;
}
}
/**
* For serialization, write this object as a single boolean value.
*
* @param stream
* the output stream to write this object to
*/
private void writeObject(ObjectOutputStream stream) throws IOException {
ObjectOutputStream.PutField fields = stream.putFields();
// Synthesize for compactness
fields.put("booleanValue", !isEmpty);
stream.writeFields();
}
/**
* Retrieve the value of this object as a <code>String</code>.
*/
public String toString() {
return isEmpty ? "false" : "true";
}
}