/*
|
* %CopyrightBegin%
|
*
|
* Copyright Ericsson AB 2000-2013. All Rights Reserved.
|
*
|
* 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.
|
*
|
* %CopyrightEnd%
|
*/
|
package com.ericsson.otp.erlang;
|
|
/**
|
* Provides a Java representation of Erlang tuples. Tuples are created from one
|
* or more arbitrary Erlang terms.
|
* <p>
|
* <p>
|
* The arity of the tuple is the number of elements it contains. Elements are
|
* indexed from 0 to (arity-1) and can be retrieved individually by using the
|
* appropriate index.
|
*/
|
public class OtpErlangTuple extends OtpErlangObject {
|
// don't change this!
|
private static final long serialVersionUID = 9163498658004915935L;
|
private static final OtpErlangObject[] NO_ELEMENTS = new OtpErlangObject[0];
|
private OtpErlangObject[] elems = NO_ELEMENTS;
|
|
/**
|
* Create a unary tuple containing the given element.
|
*
|
* @param elem the element to create the tuple from.
|
* @throws java.lang.IllegalArgumentException if the element is null.
|
*/
|
public OtpErlangTuple(final OtpErlangObject elem) {
|
if (elem == null) {
|
throw new java.lang.IllegalArgumentException(
|
"Tuple element cannot be null");
|
}
|
elems = new OtpErlangObject[]{elem};
|
}
|
|
/**
|
* Create a tuple from an array of terms.
|
*
|
* @param elems the array of terms to create the tuple from.
|
* @throws java.lang.IllegalArgumentException if the array is empty (null) or contains null elements.
|
*/
|
public OtpErlangTuple(final OtpErlangObject[] elems) {
|
this(elems, 0, elems.length);
|
}
|
|
/**
|
* Create a tuple from an array of terms.
|
*
|
* @param elems the array of terms to create the tuple from.
|
* @param start the offset of the first term to insert.
|
* @param count the number of terms to insert.
|
* @throws java.lang.IllegalArgumentException if the array is empty (null) or contains null elements.
|
*/
|
public OtpErlangTuple(final OtpErlangObject[] elems, final int start,
|
final int count) {
|
if (elems == null) {
|
throw new java.lang.IllegalArgumentException(
|
"Tuple content can't be null");
|
} else if (count < 1) {
|
this.elems = NO_ELEMENTS;
|
} else {
|
this.elems = new OtpErlangObject[count];
|
for (int i = 0; i < count; i++) {
|
if (elems[start + i] != null) {
|
this.elems[i] = elems[start + i];
|
} else {
|
throw new java.lang.IllegalArgumentException(
|
"Tuple element cannot be null (element"
|
+ (start + i) + ")");
|
}
|
}
|
}
|
}
|
|
/**
|
* Create a tuple from a stream containing an tuple encoded in Erlang
|
* external format.
|
*
|
* @param buf the stream containing the encoded tuple.
|
* @throws OtpErlangDecodeException if the buffer does not contain a valid external
|
* representation of an Erlang tuple.
|
*/
|
public OtpErlangTuple(final OtpInputStream buf)
|
throws OtpErlangDecodeException {
|
final int arity = buf.read_tuple_head();
|
if (arity > 0) {
|
elems = new OtpErlangObject[arity];
|
for (int i = 0; i < arity; i++) {
|
elems[i] = buf.read_any();
|
}
|
} else {
|
elems = NO_ELEMENTS;
|
}
|
}
|
|
/**
|
* Get the arity of the tuple.
|
*
|
* @return the number of elements contained in the tuple.
|
*/
|
public int arity() {
|
return elems.length;
|
}
|
|
/**
|
* Get the specified element from the tuple.
|
*
|
* @param i the index of the requested element. Tuple elements are
|
* numbered as array elements, starting at 0.
|
* @return the requested element, of null if i is not a valid element index.
|
*/
|
public OtpErlangObject elementAt(final int i) {
|
if (i >= arity() || i < 0) {
|
return null;
|
}
|
return elems[i];
|
}
|
|
/**
|
* Get all the elements from the tuple as an array.
|
*
|
* @return an array containing all of the tuple's elements.
|
*/
|
public OtpErlangObject[] elements() {
|
final OtpErlangObject[] res = new OtpErlangObject[arity()];
|
System.arraycopy(elems, 0, res, 0, res.length);
|
return res;
|
}
|
|
/**
|
* Get the string representation of the tuple.
|
*
|
* @return the string representation of the tuple.
|
*/
|
public String toString() {
|
int i;
|
final StringBuffer s = new StringBuffer();
|
final int arity = elems.length;
|
s.append("{");
|
for (i = 0; i < arity; i++) {
|
if (i > 0) {
|
s.append(",");
|
}
|
s.append(elems[i].toString());
|
}
|
s.append("}");
|
return s.toString();
|
}
|
|
/**
|
* Convert this tuple to the equivalent Erlang external representation.
|
*
|
* @param buf an output stream to which the encoded tuple should be written.
|
*/
|
public void encode(final OtpOutputStream buf) {
|
final int arity = elems.length;
|
buf.write_tuple_head(arity);
|
for (int i = 0; i < arity; i++) {
|
buf.write_any(elems[i]);
|
}
|
}
|
|
/**
|
* Determine if two tuples are equal. Tuples are equal if they have the same
|
* arity and all of the elements are equal.
|
*
|
* @param o the tuple to compare to.
|
* @return true if the tuples have the same arity and all the elements are
|
* equal.
|
*/
|
public boolean equals(final Object o) {
|
if (!(o instanceof OtpErlangTuple)) {
|
return false;
|
}
|
final OtpErlangTuple t = (OtpErlangTuple) o;
|
final int a = arity();
|
if (a != t.arity()) {
|
return false;
|
}
|
for (int i = 0; i < a; i++) {
|
if (!elems[i].equals(t.elems[i])) {
|
return false; // early exit
|
}
|
}
|
return true;
|
}
|
|
public <T> boolean match(final OtpErlangObject term, final T bindings) {
|
if (!(term instanceof OtpErlangTuple)) {
|
return false;
|
}
|
final OtpErlangTuple t = (OtpErlangTuple) term;
|
final int a = elems.length;
|
if (a != t.elems.length) {
|
return false;
|
}
|
for (int i = 0; i < a; i++) {
|
if (!elems[i].match(t.elems[i], bindings)) {
|
return false;
|
}
|
}
|
return true;
|
}
|
|
public <T> OtpErlangObject bind(final T binds) throws OtpErlangException {
|
final OtpErlangTuple tuple = (OtpErlangTuple) this.clone();
|
final int a = tuple.elems.length;
|
for (int i = 0; i < a; i++) {
|
final OtpErlangObject e = tuple.elems[i];
|
tuple.elems[i] = e.bind(binds);
|
}
|
return tuple;
|
}
|
|
protected int doHashCode() {
|
final OtpErlangObject.Hash hash = new OtpErlangObject.Hash(9);
|
final int a = arity();
|
hash.combine(a);
|
for (int i = 0; i < a; i++) {
|
hash.combine(elems[i].hashCode());
|
}
|
return hash.valueOf();
|
}
|
|
public Object clone() {
|
final OtpErlangTuple newTuple = (OtpErlangTuple) super.clone();
|
newTuple.elems = elems.clone();
|
return newTuple;
|
}
|
}
|