
eu.mihosoft.vmf.vmftext.grammar.impl.CodeLocationImpl Maven / Gradle / Ivy
package eu.mihosoft.vmf.vmftext.grammar.impl;
// vmf imports
// import eu.mihosoft.vmf.runtime.core.*;
// import eu.mihosoft.vmf.runtime.core.internal.*;
import eu.mihosoft.vcollections.*;
import eu.mihosoft.vmf.vmftext.grammar.*;
import java.beans.PropertyChangeSupport;
import java.beans.PropertyChangeListener;
import java.util.Objects;
import java.util.Arrays;
// property types imports
// implementation
/**
* An implementation of the immutable model object {@code eu.mihosoft.vmf.vmftext.grammar.CodeLocation}.
*/
@SuppressWarnings("deprecation")
public class CodeLocationImpl implements CodeLocation, eu.mihosoft.vmf.runtime.core.VObject, eu.mihosoft.vmf.runtime.core.internal.VObjectInternal, VCloneableInternal {
// --------------------------------------------------------------------
// --- declaration of member variables
// --------------------------------------------------------------------
/*package private*/ int charPosInLine;
/*package private*/ int index;
/*package private*/ int line;
// --------------------------------------------------------------------
// --- declaration of delegation variables
// --------------------------------------------------------------------
// referenced by
private final VList referencedBy = VList.newInstance(new java.util.ArrayList<>());
// references
private final VList references = VList.newInstance(new java.util.ArrayList<>());
// --------------------------------------------------------------------
// --- private constructor
// --------------------------------------------------------------------
private CodeLocationImpl() {
// ...
}
// --------------------------------------------------------------------
// --- public getter methods for accessing properties
// --------------------------------------------------------------------
@Override
public int getCharPosInLine() {
return this.charPosInLine;
}
@Override
public int getIndex() {
return this.index;
}
@Override
public int getLine() {
return this.line;
}
// --------------------------------------------------------------------
// --- Object methods (equals(), toString() etc.)
// --------------------------------------------------------------------
// --------------------------- BEGIN TO_STRING -----------------------------
@Override
public String toString() {
boolean entry = _vmf_getThreadLocalToString().get().isEmpty();
try {
// test if "this" has been seen before
// implementation based on http://stackoverflow.com/a/11300376/1493549
boolean isImmutable = (this instanceof eu.mihosoft.vmf.runtime.core.Immutable);
if (!isImmutable && _vmf_getThreadLocalToString().get().containsKey(this)) {
return "{skipping recursion}";
} else {
if(!isImmutable) {
_vmf_getThreadLocalToString().get().put(this, null);
}
entry = true;
}
return "{\"@type\":\"CodeLocation\"" +
", \"charPosInLine\": \"" + this.charPosInLine + "\"" +
", \"index\": \"" + this.index + "\"" +
", \"line\": \"" + this.line + "\"" +
"}";
} finally {
if (entry) {
_vmf_getThreadLocalToString().get().clear();
_vmf_fToStringChecker = null;
}
}
}
private ThreadLocal> _vmf_getThreadLocalToString() {
if (_vmf_fToStringChecker==null) {
_vmf_fToStringChecker = ThreadLocal.withInitial(
() -> new java.util.IdentityHashMap<>());
}
return _vmf_fToStringChecker;
}
private ThreadLocal> _vmf_fToStringChecker;
// end toString()
// ---------------------------- END TO_STRING ------------------------------
// --------------------------- BEGIN EQUALITY -----------------------------
@Override
public boolean equals(Object o) {
boolean entry = _vmf_getThreadLocalEquals().get().isEmpty();
try {
// test if the object pair (this,o) has been checked before
boolean isImmutable = (o instanceof eu.mihosoft.vmf.runtime.core.Immutable);
if (!isImmutable && _vmf_getThreadLocalEquals().get().containsKey(new EqualsPair(this, o))) {
// This pair has been seen before. That's why we return true now.
// If this pair wasn't equal, we wouldn't need to do a second
// comparison. Returning 'true' is equivalent to ignoring this
// particular test in the calling 'equals()' method.
return true;
} else {
if(!isImmutable) {
_vmf_getThreadLocalEquals().get().put(new EqualsPair(this, o), null);
}
entry = true;
}
if (o==null) return false;
else if (this==o) return true;
// -- try our interface/implementation --
// perform the actual comparison for each property
if (o instanceof CodeLocationImpl) {
CodeLocationImpl other = (CodeLocationImpl) o;
return _vmf_equals(this.charPosInLine, other.charPosInLine) &&
_vmf_equals(this.index, other.index) &&
_vmf_equals(this.line, other.line);
}
// -- try every implementation that implements our interface --
// no implementation matched. we end the comparison.
return false;
} finally {
if (entry) {
_vmf_getThreadLocalEquals().get().clear();
_vmf_fEqualsChecker = null;
}
}
} // end equals()
private static boolean _vmf_equals(Object o1, Object o2) {
boolean oneAndOnlyOneIsNull = (o1 == null) != (o2 == null);
boolean collectionType = o1 instanceof VList || o2 instanceof VList;
// since we support lazy initialization for collections,
// uninitialized empty collection values are defined as equal to null
// otherwise we would have to initialize these values, which would then
// neutralize or even negate the positive effect of lazy initialization
if(oneAndOnlyOneIsNull && collectionType) {
if(o1==null) {
return ((VList)o2).isEmpty();
} else {
return ((VList)o1).isEmpty();
}
} else {
return Objects.equals(o1,o2);
}
}
@Override
public int hashCode() {
boolean entry = _vmf_getThreadLocalHashCode().get().isEmpty();
try {
// test if "this class" has been seen before
//
// WARNING we use `System.identityHashCode(this)` to prevent recursive
// hashCode() calls before we do the actual test. This would eliminate
// the effect of the thread-local map
if (_vmf_getThreadLocalHashCode().get().containsKey(System.identityHashCode(this))) {
return 0; // already visited
} else {
_vmf_getThreadLocalHashCode().get().put(System.identityHashCode(this), null);
int value = _vmf_deepHashCode(
this.charPosInLine, this.index, this.line );
entry = true;
return value;
}
} finally {
if (entry) {
_vmf_getThreadLocalHashCode().get().clear();
_vmf_fHashCodeChecker = null;
}
}
} // end hashCode()
// fixes 'array discovery problems' with the 'Objects.hash(...)' method
// see http://stackoverflow.com/questions/30385018/how-to-use-java-7-objects-hash-with-arrays
private int _vmf_deepHashCode(Object... fields) {
// WARNING we are not allowed to pass arrays that contain itself
// or are contained in nested arrays
return Arrays.deepHashCode(fields);
} // end _vmf_deepHashCode()
/**
* The purpose of this class is to store a pair of objects used for equals().
* This class's equals() method checks equality by object identity. Same
* for hashCode() which uses identity hashes of 'first' and 'second' to
* compute the hash.
*
* This class can be used in conjunction with a regular HashMap to get
* similar results to an IdentityHashMap, except that in this case identity
* pairs can be used. And we don't have to use a map implementation that is
* deliberately broken by design.
*/
private static class EqualsPair {
final Object first;
final Object second;
public EqualsPair(Object first, Object second) {
this.first = first;
this.second = second;
}
@Override
public int hashCode() {
return Objects.hash(System.identityHashCode(first),
System.identityHashCode(second));
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final EqualsPair other = (EqualsPair) obj;
if (this.first!=other.first) {
return false;
}
if (this.second!=other.second) {
return false;
}
return true;
}
}
private ThreadLocal> _vmf_getThreadLocalEquals() {
if (_vmf_fEqualsChecker==null) {
_vmf_fEqualsChecker = ThreadLocal.withInitial(
() -> new java.util.HashMap<>());
}
return _vmf_fEqualsChecker;
}
private ThreadLocal> _vmf_getThreadLocalHashCode() {
if (_vmf_fHashCodeChecker==null) {
_vmf_fHashCodeChecker = ThreadLocal.withInitial(
() -> new java.util.HashMap<>());
}
return _vmf_fHashCodeChecker;
}
private ThreadLocal> _vmf_fEqualsChecker;
private ThreadLocal> _vmf_fHashCodeChecker;
// ---------------------------- END EQUALITY ------------------------------
public CodeLocation clone() {
// we don't need to perform actual cloning since this is an
// immutable type
return this;
}
// --------------------------------------------------------------------
// --- Builder methods
// --------------------------------------------------------------------
public static class BuilderImpl implements CodeLocation.Builder {
private int charPosInLine;
private int index;
private int line;
private boolean appendCollections = true;
public BuilderImpl() {}
public CodeLocation.Builder withCharPosInLine(int charPosInLine) {
this.charPosInLine = charPosInLine;
return this;
}
public CodeLocation.Builder withIndex(int index) {
this.index = index;
return this;
}
public CodeLocation.Builder withLine(int line) {
this.line = line;
return this;
}
public Builder appendCollections(boolean value) {
this.appendCollections = value;
return this;
}
public CodeLocation build() {
CodeLocationImpl result = new CodeLocationImpl();
result.charPosInLine = this.charPosInLine;
result.index = this.index;
result.line = this.line;
return result;
}
public Builder applyFrom(CodeLocation o) {
this.charPosInLine = o.getCharPosInLine();
this.index = o.getIndex();
this.line = o.getLine();
return this;
}
} // end class BuilderImpl
// --------------------------------------------------------------------
// --- declaration of delegation methods
// --------------------------------------------------------------------
// --------------------------------------------------------------------
// --- Utility methods
// --------------------------------------------------------------------
@Override
public void addPropertyChangeListener(PropertyChangeListener l) {
// don't do anything. immutable types don't publish change events
}
@Override
public void removePropertyChangeListener(PropertyChangeListener l) {
// don't do anything. immutable types don't publish change events
}
private boolean _vmf_hasListeners() {
return false;
}
private void _vmf_firePropertyChangeIfListenersArePresent() {
// don't do anything. immutable types don't publish change events
}
@Override
public CodeLocation _vmf_deepCopy(
java.util.IdentityHashMap
© 2015 - 2025 Weber Informatics LLC | Privacy Policy