/*
* #%~
* VDM Code Generator Runtime
* %%
* Copyright (C) 2008 - 2014 Overture
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* <http://www.gnu.org/licenses/gpl-3.0.html>.
* #~%
*/
package org.overture.codegen.runtime;
/*
* The source of inspiration for the implementation of this class:
* https://github.com/ripper234/Basic/tree/master/java/src/main/java/org/basic/datastructures/tuple
*/
@SuppressWarnings("rawtypes")
public class Tuple implements ValueType, Comparable
{
private static final long serialVersionUID = 8013562414260810880L;
private final Object[] values;
public static Tuple mk_(Object... values)
{
return new Tuple(values);
}
private Tuple(Object[] values)
{
if (values == null || values.length < 2)
{
throw new IllegalArgumentException("A tuple can only have two or more values");
} else
{
this.values = new Object[values.length];
init(values);
}
}
private void init(Object[] initvalues)
{
for (int i = 0; i < initvalues.length; i++)
{
Object currentValue = initvalues[i];
if (currentValue instanceof ValueType)
{
this.values[i] = ((ValueType) currentValue).copy();
} else
{
this.values[i] = currentValue;
}
}
}
public Long size()
{
return (long) values.length;
}
public Object get(int i)
{
return values[i];
}
public boolean compatible(Class... types)
{
if (this.values.length != types.length)
{
return false;
}
for (int i = 0; i < this.values.length; i++)
{
Object toValue = this.values[i];
Class type = types[i];
if (type == null)
{
return false;
}
if (toValue instanceof VDMSeq && type == String.class)
{
for (Object c : (VDMSeq) toValue)
{
if (!(c instanceof Character))
{
return false;
}
}
return true;
}
if (toValue instanceof String && type == VDMSeq.class)
{
return true;
}
if (toValue != null && !type.isInstance(toValue))
{
return false;
}
}
return true;
}
@Override
public boolean equals(Object obj)
{
if (obj == null)
{
return false;
}
if (this == obj)
{
return true;
}
if (!(obj instanceof Tuple))
{
return false;
}
final Tuple other = (Tuple) obj;
if (other.size() != size())
{
return false;
}
final int size = values.length;
for (int i = 0; i < size; i++)
{
final Object thisNthValue = get(i);
final Object otherNthValue = other.get(i);
if (thisNthValue == null && otherNthValue != null
|| thisNthValue != null
&& !thisNthValue.equals(otherNthValue))
{
return false;
}
}
return true;
}
@Override
public int hashCode()
{
int hash = 17;
for (Object value : values)
{
if (value != null)
{
hash = hash * 37 + value.hashCode();
}
}
return hash;
}
public Tuple copy()
{
return new Tuple(values);
}
@Override
public String toString()
{
StringBuilder str = new StringBuilder();
str.append(Utils.toString(values[0]));
for (int i = 1; i < values.length; i++)
{
str.append(", " + Utils.toString(values[i]));
}
return "mk_(" + str + ")";
}
@Override
public int compareTo(Object o)
{
if (o instanceof Tuple)
{
Tuple ot = (Tuple) o;
int diff = values.length - ot.values.length;
if (diff != 0)
{
return diff;
} else
{
for (int i = 0; i < values.length; i++)
{
Object val = values[i];
if (val instanceof Comparable)
{
Comparable compVal = (Comparable) val;
@SuppressWarnings("unchecked")
int c = compVal.compareTo(ot.values[i]);
if (c != 0)
{
return c;
}
} else
{
return 1;
}
}
return 0;
}
}
if (o == null)
{
return 1;
}
return this.toString().compareTo(o.toString());
}
}