diff options
author | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
---|---|---|
committer | Erlang/OTP <[email protected]> | 2009-11-20 14:54:40 +0000 |
commit | 84adefa331c4159d432d22840663c38f155cd4c1 (patch) | |
tree | bff9a9c66adda4df2106dfd0e5c053ab182a12bd /lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangList.java | |
download | otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.gz otp-84adefa331c4159d432d22840663c38f155cd4c1.tar.bz2 otp-84adefa331c4159d432d22840663c38f155cd4c1.zip |
The R13B03 release.OTP_R13B03
Diffstat (limited to 'lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangList.java')
-rw-r--r-- | lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangList.java | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangList.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangList.java new file mode 100644 index 0000000000..3456fd7412 --- /dev/null +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangList.java @@ -0,0 +1,505 @@ +/* + * %CopyrightBegin% + * + * Copyright Ericsson AB 2000-2009. All Rights Reserved. + * + * The contents of this file are subject to the Erlang Public License, + * Version 1.1, (the "License"); you may not use this file except in + * compliance with the License. You should have received a copy of the + * Erlang Public License along with this software. If not, it can be + * retrieved online at http://www.erlang.org/. + * + * Software distributed under the License is distributed on an "AS IS" + * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See + * the License for the specific language governing rights and limitations + * under the License. + * + * %CopyrightEnd% + */ +package com.ericsson.otp.erlang; + +import java.io.Serializable; +import java.util.Iterator; +import java.util.NoSuchElementException; + +/** + * Provides a Java representation of Erlang lists. Lists are created from zero + * or more arbitrary Erlang terms. + * + * <p> + * The arity of the list is the number of elements it contains. + */ +public class OtpErlangList extends OtpErlangObject implements + Iterable<OtpErlangObject>, Serializable, Cloneable { + // don't change this! + static final long serialVersionUID = 5999112769036676548L; + + private static final OtpErlangObject[] NO_ELEMENTS = new OtpErlangObject[0]; + + final private OtpErlangObject[] elems; + + private OtpErlangObject lastTail = null; + + /** + * Create an empty list. + */ + public OtpErlangList() { + elems = NO_ELEMENTS; + } + + /** + * Create a list of Erlang integers representing Unicode codePoints. + * This method does not check if the string contains valid code points. + * + * @param str + * the characters from which to create the list. + */ + public OtpErlangList(final String str) { + if (str == null || str.length() == 0) { + elems = NO_ELEMENTS; + } else { + final int[] codePoints = OtpErlangString.stringToCodePoints(str); + elems = new OtpErlangObject[codePoints.length]; + for (int i = 0; i < elems.length; i++) { + elems[i] = new OtpErlangInt(codePoints[i]); + } + } + } + + /** + * Create a list containing one element. + * + * @param elem + * the elememet to make the list from. + */ + public OtpErlangList(final OtpErlangObject elem) { + elems = new OtpErlangObject[] { elem }; + } + + /** + * Create a list from an array of arbitrary Erlang terms. + * + * @param elems + * the array of terms from which to create the list. + */ + public OtpErlangList(final OtpErlangObject[] elems) { + this(elems, 0, elems.length); + } + + /** + * Create a list from an array of arbitrary Erlang terms. Tail can be + * specified, if not null, the list will not be proper. + * + * @param elems + * array of terms from which to create the list + * @param lastTail + * @throws OtpErlangException + */ + public OtpErlangList(final OtpErlangObject[] elems, + final OtpErlangObject lastTail) throws OtpErlangException { + this(elems, 0, elems.length); + if (elems.length == 0 && lastTail != null) { + throw new OtpErlangException("Bad list, empty head, non-empty tail"); + } + this.lastTail = lastTail; + } + + /** + * Create a list from an array of arbitrary Erlang terms. + * + * @param elems + * the array of terms from which to create the list. + * @param start + * the offset of the first term to insert. + * @param count + * the number of terms to insert. + */ + public OtpErlangList(final OtpErlangObject[] elems, final int start, + final int count) { + if (elems != null && count > 0) { + this.elems = new OtpErlangObject[count]; + System.arraycopy(elems, start, this.elems, 0, count); + } else { + this.elems = NO_ELEMENTS; + } + } + + /** + * Create a list from a stream containing an list encoded in Erlang external + * format. + * + * @param buf + * the stream containing the encoded list. + * + * @exception OtpErlangDecodeException + * if the buffer does not contain a valid external + * representation of an Erlang list. + */ + public OtpErlangList(final OtpInputStream buf) + throws OtpErlangDecodeException { + final int arity = buf.read_list_head(); + if (arity > 0) { + elems = new OtpErlangObject[arity]; + for (int i = 0; i < arity; i++) { + elems[i] = buf.read_any(); + } + /* discard the terminating nil (empty list) or read tail */ + if (buf.peek1() == OtpExternal.nilTag) { + buf.read_nil(); + } else { + lastTail = buf.read_any(); + } + } else { + elems = NO_ELEMENTS; + } + } + + /** + * Get the arity of the list. + * + * @return the number of elements contained in the list. + */ + public int arity() { + return elems.length; + } + + /** + * Get the specified element from the list. + * + * @param i + * the index of the requested element. List 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 list as an array. + * + * @return an array containing all of the list's elements. + */ + public OtpErlangObject[] elements() { + if (arity() == 0) { + return NO_ELEMENTS; + } else { + final OtpErlangObject[] res = new OtpErlangObject[arity()]; + System.arraycopy(elems, 0, res, 0, res.length); + return res; + } + } + + /** + * Get the string representation of the list. + * + * @return the string representation of the list. + */ + + @Override + public String toString() { + return toString(0); + } + + protected String toString(final int start) { + final StringBuffer s = new StringBuffer(); + s.append("["); + + for (int i = start; i < arity(); i++) { + if (i > start) { + s.append(","); + } + s.append(elems[i].toString()); + } + if (lastTail != null) { + s.append("|").append(lastTail.toString()); + } + s.append("]"); + + return s.toString(); + } + + /** + * Convert this list to the equivalent Erlang external representation. Note + * that this method never encodes lists as strings, even when it is possible + * to do so. + * + * @param buf + * An output stream to which the encoded list should be written. + * + */ + + @Override + public void encode(final OtpOutputStream buf) { + encode(buf, 0); + } + + protected void encode(final OtpOutputStream buf, final int start) { + final int arity = arity() - start; + + if (arity > 0) { + buf.write_list_head(arity); + + for (int i = start; i < arity + start; i++) { + buf.write_any(elems[i]); + } + } + if (lastTail == null) { + buf.write_nil(); + } else { + buf.write_any(lastTail); + } + } + + /** + * Determine if two lists are equal. Lists are equal if they have the same + * arity and all of the elements are equal. + * + * @param o + * the list to compare to. + * + * @return true if the lists have the same arity and all the elements are + * equal. + */ + + @Override + public boolean equals(final Object o) { + + /* + * Be careful to use methods even for "this", so that equals work also + * for sublists + */ + + if (!(o instanceof OtpErlangList)) { + return false; + } + + final OtpErlangList l = (OtpErlangList) o; + + final int a = arity(); + if (a != l.arity()) { + return false; + } + for (int i = 0; i < a; i++) { + if (!elementAt(i).equals(l.elementAt(i))) { + return false; // early exit + } + } + final OtpErlangObject otherTail = l.getLastTail(); + if (getLastTail() == null && otherTail == null) { + return true; + } + if (getLastTail() == null) { + return false; + } + return getLastTail().equals(l.getLastTail()); + } + + public OtpErlangObject getLastTail() { + return lastTail; + } + + @Override + protected int doHashCode() { + OtpErlangObject.Hash hash = new OtpErlangObject.Hash(4); + final int a = arity(); + if (a == 0) { + return (int)3468870702L; + } + for (int i = 0; i < a; i++) { + hash.combine(elementAt(i).hashCode()); + } + final OtpErlangObject t = getLastTail(); + if (t != null) { + int h = t.hashCode(); + hash.combine(h, h); + } + return hash.valueOf(); + } + + @Override + public Object clone() { + try { + return new OtpErlangList(elements(), getLastTail()); + } catch (final OtpErlangException e) { + return null; + } + } + + public Iterator<OtpErlangObject> iterator() { + return iterator(0); + } + + private Iterator<OtpErlangObject> iterator(final int start) { + return new Itr(start); + } + + /** + * @return true if the list is proper, i.e. the last tail is nil + */ + public boolean isProper() { + return lastTail == null; + } + + public OtpErlangObject getHead() { + if (arity() > 0) { + return elems[0]; + } + return null; + } + + public OtpErlangObject getTail() { + return getNthTail(1); + } + + public OtpErlangObject getNthTail(final int n) { + final int arity = arity(); + if (arity >= n) { + if (arity == n && lastTail != null) { + return lastTail; + } else { + return new SubList(this, n); + } + } + return null; + } + + /** + * Convert a list of integers into a Unicode string, + * interpreting each integer as a Unicode code point value. + * + * @return A java.lang.String object created through its + * constructor String(int[], int, int). + * + * @exception OtpErlangException + * for non-proper and non-integer lists. + * + * @exception OtpErlangRangeException + * if any integer does not fit into a Java int. + * + * @exception java.security.InvalidParameterException + * if any integer is not within the Unicode range. + * + * @see String#String(int[], int, int) + * + */ + + public String stringValue() throws OtpErlangException { + if (! isProper()) { + throw new OtpErlangException("Non-proper list: " + this); + } + final int[] values = new int[arity()]; + for (int i = 0; i < values.length; ++i) { + final OtpErlangObject o = elementAt(i); + if (! (o instanceof OtpErlangLong)) { + throw new OtpErlangException("Non-integer term: " + o); + } + final OtpErlangLong l = (OtpErlangLong) o; + values[i] = l.intValue(); + } + return new String(values, 0, values.length); + } + + + + public static class SubList extends OtpErlangList { + private static final long serialVersionUID = OtpErlangList.serialVersionUID; + + private final int start; + + private final OtpErlangList parent; + + private SubList(final OtpErlangList parent, final int start) { + super(); + this.parent = parent; + this.start = start; + } + + @Override + public int arity() { + return parent.arity() - start; + } + + @Override + public OtpErlangObject elementAt(final int i) { + return parent.elementAt(i + start); + } + + @Override + public OtpErlangObject[] elements() { + final int n = parent.arity() - start; + final OtpErlangObject[] res = new OtpErlangObject[n]; + for (int i = 0; i < res.length; i++) { + res[i] = parent.elementAt(i + start); + } + return res; + } + + @Override + public boolean isProper() { + return parent.isProper(); + } + + @Override + public OtpErlangObject getHead() { + return parent.elementAt(start); + } + + @Override + public OtpErlangObject getNthTail(final int n) { + return parent.getNthTail(n + start); + } + + @Override + public String toString() { + return parent.toString(start); + } + + @Override + public void encode(final OtpOutputStream stream) { + parent.encode(stream, start); + } + + @Override + public OtpErlangObject getLastTail() { + return parent.getLastTail(); + } + + @Override + public Iterator<OtpErlangObject> iterator() { + return parent.iterator(start); + } + } + + private class Itr implements Iterator<OtpErlangObject> { + /** + * Index of element to be returned by subsequent call to next. + */ + private int cursor; + + private Itr(final int cursor) { + this.cursor = cursor; + } + + public boolean hasNext() { + return cursor < elems.length; + } + + public OtpErlangObject next() { + try { + return elems[cursor++]; + } catch (final IndexOutOfBoundsException e) { + throw new NoSuchElementException(); + } + } + + public void remove() { + throw new UnsupportedOperationException( + "OtpErlangList cannot be modified!"); + } + } +} |