diff options
author | Zandra Hird <[email protected]> | 2015-04-29 14:41:39 +0200 |
---|---|---|
committer | Zandra Hird <[email protected]> | 2015-04-29 14:41:39 +0200 |
commit | de6ef63b143557558436b5c0213030a27d78da0d (patch) | |
tree | d84847fe669fd707d1e3039507906908834f6513 /lib/jinterface/java_src/com/ericsson/otp | |
parent | 65cd6574a37af1dfcc01fc4cc9681b4b758f1284 (diff) | |
parent | 2fdc3d313485a76b6acf12154b8f3bd3e1ceb2ca (diff) | |
download | otp-de6ef63b143557558436b5c0213030a27d78da0d.tar.gz otp-de6ef63b143557558436b5c0213030a27d78da0d.tar.bz2 otp-de6ef63b143557558436b5c0213030a27d78da0d.zip |
Merge branch 'x0id/jinterface_generic_match'
* x0id/jinterface_generic_match:
jinterface: match/bind added to OtpErlangObject
fix typo error from recent merge
OTP-12691
Diffstat (limited to 'lib/jinterface/java_src/com/ericsson/otp')
4 files changed, 237 insertions, 73 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 index 990e50ddcd..268261ec10 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangList.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangList.java @@ -297,6 +297,54 @@ public class OtpErlangList extends OtpErlangObject implements return getLastTail().equals(l.getLastTail()); } + @Override + public <T> boolean match(final OtpErlangObject term, final T bindings) { + if (!(term instanceof OtpErlangList)) { + return false; + } + final OtpErlangList that = (OtpErlangList) term; + + final int thisArity = this.arity(); + final int thatArity = that.arity(); + final OtpErlangObject thisTail = this.getLastTail(); + final OtpErlangObject thatTail = that.getLastTail(); + + if (thisTail == null) { + if (thisArity != thatArity || thatTail != null) { + return false; + } + } else { + if (thisArity > thatArity) { + return false; + } + } + for (int i = 0; i < thisArity; i++) { + if (!elementAt(i).match(that.elementAt(i), bindings)) { + return false; + } + } + if (thisTail == null) { + return true; + } + return thisTail.match(that.getNthTail(thisArity), bindings); + } + + @Override + public <T> OtpErlangObject bind(final T binds) throws OtpErlangException { + final OtpErlangList list = (OtpErlangList) this.clone(); + + final int a = list.elems.length; + for (int i = 0; i < a; i++) { + list.elems[i] = list.elems[i].bind(binds); + } + + if (list.lastTail != null) { + list.lastTail = list.lastTail.bind(binds); + } + + return list; + } + public OtpErlangObject getLastTail() { return lastTail; } 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 7f2621923a..a8cd9d5392 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangMap.java @@ -18,6 +18,11 @@ */ 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. @@ -31,10 +36,14 @@ 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. @@ -82,30 +91,20 @@ public class OtpErlangMap extends OtpErlangObject { } 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) - + ")"); - } + } + 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) + ")"); } - 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) - + ")"); - } + if ((val = values[vstart + i]) == null) { + throw new java.lang.IllegalArgumentException( + "Map value cannot be null (element" + (vstart + i) + + ")"); } + put(key, val); } } @@ -125,16 +124,15 @@ public class OtpErlangMap extends OtpErlangObject { final int arity = buf.read_map_head(); if (arity > 0) { - keys = new OtpErlangObject[arity]; - values = new OtpErlangObject[arity]; - + map = new HashMap<OtpErlangObject, OtpErlangObject>(arity); for (int i = 0; i < arity; i++) { - keys[i] = buf.read_any(); - values[i] = buf.read_any(); + OtpErlangObject key, val; + key = buf.read_any(); + val = buf.read_any(); + put(key, val); } } else { - keys = NO_ELEMENTS; - values = NO_ELEMENTS; + map = new HashMap<OtpErlangObject, OtpErlangObject>(); } } @@ -144,7 +142,33 @@ public class OtpErlangMap extends OtpErlangObject { * @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); } /** @@ -156,15 +180,7 @@ public class OtpErlangMap extends OtpErlangObject { * @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); } /** @@ -173,9 +189,7 @@ public class OtpErlangMap extends OtpErlangObject { * @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()]); } /** @@ -184,9 +198,16 @@ public class OtpErlangMap extends OtpErlangObject { * @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(); } /** @@ -196,19 +217,20 @@ public class OtpErlangMap extends OtpErlangObject { */ @Override public String toString() { - int i; final StringBuffer s = new StringBuffer(); - final int arity = values.length; s.append("#{"); - for (i = 0; i < arity; i++) { - if (i > 0) { + boolean first = true; + for (final Map.Entry<OtpErlangObject, OtpErlangObject> e : entrySet()) { + if (first) { + first = false; + } else { s.append(","); } - s.append(keys[i].toString()); + s.append(e.getKey().toString()); s.append(" => "); - s.append(values[i].toString()); + s.append(e.getValue().toString()); } s.append("}"); @@ -224,13 +246,13 @@ public class OtpErlangMap extends OtpErlangObject { */ @Override public void encode(final OtpOutputStream buf) { - final int arity = values.length; + final int arity = 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()); } } @@ -256,15 +278,46 @@ public class OtpErlangMap extends OtpErlangObject { if (a != t.arity()) { return false; } + if (a == 0) { + return true; + } - for (int i = 0; i < a; i++) { - if (!keys[i].equals(t.keys[i])) { - return false; // early exit + 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; } } - for (int i = 0; i < a; i++) { - if (!values[i].equals(t.values[i])) { - return false; // early exit + + 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; } } @@ -272,23 +325,31 @@ public class OtpErlangMap extends OtpErlangObject { } @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()); - } + hash.combine(map.hashCode()); return hash.valueOf(); } @Override + @SuppressWarnings("unchecked") public Object clone() { final OtpErlangMap newMap = (OtpErlangMap) super.clone(); - newMap.values = values.clone(); + newMap.map = (HashMap<OtpErlangObject, OtpErlangObject>) map.clone(); return newMap; } } diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangObject.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangObject.java index 7ab160bcdd..9339d3749b 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangObject.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangObject.java @@ -80,6 +80,32 @@ public abstract class OtpErlangObject implements Serializable, Cloneable { @Override public abstract boolean equals(Object o); + /** + * Perform match operation against given term. + * + * @param term + * the object to match + * @param binds + * variable bindings + * @return true if match succeeded + */ + public <T> boolean match(final OtpErlangObject term, final T binds) { + return equals(term); + } + + /** + * Make new Erlang term replacing variables with the respective values from + * bindings argument(s). + * + * @param binds + * variable bindings + * @return new term + * @throws OtpErlangException + */ + public <T> OtpErlangObject bind(final T binds) throws OtpErlangException { + return this; + } + @Override public int hashCode() { if (hashCodeValue == 0) { diff --git a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangTuple.java b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangTuple.java index af2559e62e..ef0a453de1 100644 --- a/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangTuple.java +++ b/lib/jinterface/java_src/com/ericsson/otp/erlang/OtpErlangTuple.java @@ -236,6 +236,35 @@ public class OtpErlangTuple extends OtpErlangObject { } @Override + 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; + } + + @Override + 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; + } + + @Override protected int doHashCode() { final OtpErlangObject.Hash hash = new OtpErlangObject.Hash(9); final int a = arity(); |