diff options
Diffstat (limited to 'lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java')
-rw-r--r-- | lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java | 363 |
1 files changed, 212 insertions, 151 deletions
diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java index 7f1a64b87d..0fd7d3ce37 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java @@ -3,59 +3,68 @@ * * Copyright Ericsson AB 2000-2013. 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/. + * 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 * - * 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. + * 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; +import java.util.HashMap; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; /** * Provides a Java representation of Erlang maps. Maps are created from one or * more arbitrary Erlang terms. - * + * * <p> * The arity of the map is the number of elements it contains. The keys and * values can be retrieved as arrays and the value for a key can be queried. - * + * */ public class OtpErlangMap extends OtpErlangObject { // don't change this! private static final long serialVersionUID = -6410770117696198497L; - private static final OtpErlangObject[] NO_ELEMENTS = new OtpErlangObject[0]; + private HashMap<OtpErlangObject, OtpErlangObject> map; - private OtpErlangObject[] keys = NO_ELEMENTS; - private OtpErlangObject[] values = NO_ELEMENTS; + /** + * Create an empty map. + */ + public OtpErlangMap() { + map = new HashMap<OtpErlangObject, OtpErlangObject>(); + } /** * Create a map from an array of keys and an array of values. - * + * * @param keys * the array of terms to create the map keys from. * @param values * the array of terms to create the map values from. - * + * * @exception java.lang.IllegalArgumentException * if any array is empty (null) or contains null elements. */ public OtpErlangMap(final OtpErlangObject[] keys, - final OtpErlangObject[] values) { - this(keys, 0, keys.length, values, 0, values.length); + final OtpErlangObject[] values) { + this(keys, 0, keys.length, values, 0, values.length); } /** * Create a map from an array of terms. - * + * * @param keys * the array of terms to create the map from. * @param kstart @@ -68,228 +77,280 @@ public class OtpErlangMap extends OtpErlangObject { * the offset of the first value to insert. * @param vcount * the number of values to insert. - * + * * @exception java.lang.IllegalArgumentException * if any array is empty (null) or contains null elements. * @exception java.lang.IllegalArgumentException * if kcount and vcount differ. */ public OtpErlangMap(final OtpErlangObject[] keys, final int kstart, - final int kcount, final OtpErlangObject[] values, final int vstart, - final int vcount) { - if (keys == null || values == null) { - throw new java.lang.IllegalArgumentException( - "Map content can't be null"); - } else if (kcount != vcount) { - throw new java.lang.IllegalArgumentException( - "Map keys and values must have same arity"); - } else if (vcount < 1) { - this.keys = NO_ELEMENTS; - this.values = NO_ELEMENTS; - } else { - this.keys = new OtpErlangObject[vcount]; - for (int i = 0; i < vcount; i++) { - if (keys[kstart + i] != null) { - this.keys[i] = keys[kstart + i]; - } else { - throw new java.lang.IllegalArgumentException( - "Map key cannot be null (element" + (kstart + i) - + ")"); - } - } - this.values = new OtpErlangObject[vcount]; - for (int i = 0; i < vcount; i++) { - if (values[vstart + i] != null) { - this.values[i] = values[vstart + i]; - } else { - throw new java.lang.IllegalArgumentException( - "Map value cannot be null (element" + (vstart + i) - + ")"); - } - } - } + final int kcount, final OtpErlangObject[] values, final int vstart, + final int vcount) { + if (keys == null || values == null) { + throw new java.lang.IllegalArgumentException( + "Map content can't be null"); + } else if (kcount != vcount) { + throw new java.lang.IllegalArgumentException( + "Map keys and values must have same arity"); + } + map = new HashMap<OtpErlangObject, OtpErlangObject>(vcount); + OtpErlangObject key, val; + for (int i = 0; i < vcount; i++) { + if ((key = keys[kstart + i]) == null) { + throw new java.lang.IllegalArgumentException( + "Map key cannot be null (element" + (kstart + i) + ")"); + } + if ((val = values[vstart + i]) == null) { + throw new java.lang.IllegalArgumentException( + "Map value cannot be null (element" + (vstart + i) + + ")"); + } + put(key, val); + } } /** * Create a map from a stream containing a map encoded in Erlang external * format. - * + * * @param buf * the stream containing the encoded map. - * + * * @exception OtpErlangDecodeException * if the buffer does not contain a valid external * representation of an Erlang map. */ public OtpErlangMap(final OtpInputStream buf) - throws OtpErlangDecodeException { - final int arity = buf.read_map_head(); - - if (arity > 0) { - keys = new OtpErlangObject[arity]; - values = new OtpErlangObject[arity]; - - for (int i = 0; i < arity; i++) { - keys[i] = buf.read_any(); - values[i] = buf.read_any(); - } - } else { - keys = NO_ELEMENTS; - values = NO_ELEMENTS; - } + throws OtpErlangDecodeException { + final int arity = buf.read_map_head(); + + if (arity > 0) { + map = new HashMap<OtpErlangObject, OtpErlangObject>(arity); + for (int i = 0; i < arity; i++) { + OtpErlangObject key, val; + key = buf.read_any(); + val = buf.read_any(); + put(key, val); + } + } else { + map = new HashMap<OtpErlangObject, OtpErlangObject>(); + } } /** * Get the arity of the map. - * + * * @return the number of elements contained in the map. */ public int arity() { - return keys.length; + return map.size(); + } + + /** + * Put value corresponding to key into the map. For detailed behavior + * description see {@link Map#put(Object, Object)}. + * + * @param key + * key to associate value with + * @param value + * value to associate with key + * @return previous value associated with key or null + */ + public OtpErlangObject put(final OtpErlangObject key, + final OtpErlangObject value) { + return map.put(key, value); + } + + /** + * removes mapping for the key if present. + * + * @param key + * key for which mapping is to be remove + * @return value associated with key or null + */ + public OtpErlangObject remove(final OtpErlangObject key) { + return map.remove(key); } /** * Get the specified value from the map. - * + * * @param key * the key of the requested value. - * + * * @return the requested value, of null if key is not a valid key. */ public OtpErlangObject get(final OtpErlangObject key) { - if (key == null) { - return null; - } - for (int i = 0; i < keys.length; i++) { - if (key.equals(keys[i])) { - return values[i]; - } - } - return null; + return map.get(key); } /** * Get all the keys from the map as an array. - * + * * @return an array containing all of the map's keys. */ public OtpErlangObject[] keys() { - final OtpErlangObject[] res = new OtpErlangObject[arity()]; - System.arraycopy(keys, 0, res, 0, res.length); - return res; + return map.keySet().toArray(new OtpErlangObject[arity()]); } /** * Get all the values from the map as an array. - * + * * @return an array containing all of the map's values. */ public OtpErlangObject[] values() { - final OtpErlangObject[] res = new OtpErlangObject[arity()]; - System.arraycopy(values, 0, res, 0, res.length); - return res; + return map.values().toArray(new OtpErlangObject[arity()]); + } + + /** + * make Set view of the map key-value pairs + * + * @return a set containing key-value pairs + */ + public Set<Entry<OtpErlangObject, OtpErlangObject>> entrySet() { + return map.entrySet(); } /** * Get the string representation of the map. - * + * * @return the string representation of the map. */ @Override public String toString() { - int i; - final StringBuffer s = new StringBuffer(); - final int arity = values.length; + final StringBuffer s = new StringBuffer(); - s.append("#{"); + s.append("#{"); - for (i = 0; i < arity; i++) { - if (i > 0) { - s.append(","); - } - s.append(keys[i].toString()); - s.append(" => "); - s.append(values[i].toString()); - } + boolean first = true; + for (final Map.Entry<OtpErlangObject, OtpErlangObject> e : entrySet()) { + if (first) { + first = false; + } else { + s.append(","); + } + s.append(e.getKey().toString()); + s.append(" => "); + s.append(e.getValue().toString()); + } - s.append("}"); + s.append("}"); - return s.toString(); + return s.toString(); } /** * Convert this map to the equivalent Erlang external representation. - * + * * @param buf * an output stream to which the encoded map should be written. */ @Override public void encode(final OtpOutputStream buf) { - final int arity = values.length; + final int arity = arity(); - buf.write_map_head(arity); + buf.write_map_head(arity); - for (int i = 0; i < arity; i++) { - buf.write_any(keys[i]); - buf.write_any(values[i]); - } + for (final Map.Entry<OtpErlangObject, OtpErlangObject> e : entrySet()) { + buf.write_any(e.getKey()); + buf.write_any(e.getValue()); + } } /** * Determine if two maps are equal. Maps are equal if they have the same * arity and all of the elements are equal. - * + * * @param o * the map to compare to. - * + * * @return true if the maps have the same arity and all the elements are * equal. */ @Override public boolean equals(final Object o) { - if (!(o instanceof OtpErlangMap)) { - return false; - } - - final OtpErlangMap t = (OtpErlangMap) o; - final int a = arity(); - - if (a != t.arity()) { - return false; - } - - for (int i = 0; i < a; i++) { - if (!keys[i].equals(t.keys[i])) { - return false; // early exit - } - } - for (int i = 0; i < a; i++) { - if (!values[i].equals(t.values[i])) { - return false; // early exit - } - } - - return true; + if (!(o instanceof OtpErlangMap)) { + return false; + } + + final OtpErlangMap t = (OtpErlangMap) o; + final int a = arity(); + + if (a != t.arity()) { + return false; + } + if (a == 0) { + return true; + } + + OtpErlangObject key, val; + for (final Map.Entry<OtpErlangObject, OtpErlangObject> e : entrySet()) { + key = e.getKey(); + val = e.getValue(); + final OtpErlangObject v = t.get(key); + if (v == null || !val.equals(v)) { + return false; + } + } + + return true; + } + + @Override + public <T> boolean match(final OtpErlangObject term, final T binds) { + if (!(term instanceof OtpErlangMap)) { + return false; + } + + final OtpErlangMap t = (OtpErlangMap) term; + final int a = arity(); + + if (a > t.arity()) { + return false; + } + if (a == 0) { + return true; + } + + OtpErlangObject key, val; + for (final Map.Entry<OtpErlangObject, OtpErlangObject> e : entrySet()) { + key = e.getKey(); + val = e.getValue(); + final OtpErlangObject v = t.get(key); + if (v == null || !val.match(v, binds)) { + return false; + } + } + + return true; + } + + @Override + public <T> OtpErlangObject bind(final T binds) throws OtpErlangException { + final OtpErlangMap ret = new OtpErlangMap(); + + OtpErlangObject key, val; + for (final Map.Entry<OtpErlangObject, OtpErlangObject> e : entrySet()) { + key = e.getKey(); + val = e.getValue(); + ret.put(key, val.bind(binds)); + } + + return ret; } @Override 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(keys[i].hashCode()); - } - for (int i = 0; i < a; i++) { - hash.combine(values[i].hashCode()); - } - return hash.valueOf(); + final OtpErlangObject.Hash hash = new OtpErlangObject.Hash(9); + hash.combine(map.hashCode()); + return hash.valueOf(); } @Override + @SuppressWarnings("unchecked") public Object clone() { - final OtpErlangMap newMap = (OtpErlangMap) super.clone(); - newMap.values = values.clone(); - return newMap; + final OtpErlangMap newMap = (OtpErlangMap) super.clone(); + newMap.map = (HashMap<OtpErlangObject, OtpErlangObject>) map.clone(); + return newMap; } } |