/*******************************************************************************
* Copyright 2014 Analog Devices, Inc.
*
* 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
*
* 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.
********************************************************************************/
package com.analog.lyric.dimple.model.domains;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Objects;
import com.analog.lyric.collect.Supers;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
public class ArrayDiscreteDomain<Element> extends TypedDiscreteDomain<Element>
{
/*-------
* State
*/
private static final long serialVersionUID = 1L;
private final Element[] _elements;
private final HashMap<Object,Integer> _elementToIndex;
private final boolean _hasIntCompatibleValues;
/*--------------
* Construction
*/
@SuppressWarnings("unchecked")
ArrayDiscreteDomain(Element firstElement, int offset, Object ... moreElements)
{
super(computeHashCode(firstElement, moreElements));
Class<?> eltClass = Supers.nearestCommonSuperClass(firstElement, moreElements);
Object[] elements = (Object[]) Array.newInstance(eltClass, moreElements.length + 1 - offset);
elements[0] = firstElement;
for (int i = moreElements.length; --i>=offset;)
{
elements[i+1-offset] = Objects.requireNonNull(moreElements[i]);
}
_elements = (Element[])elements;
boolean hasIntCompatibleValues = isIntCompatibleClass(eltClass);
_elementToIndex = new HashMap<Object,Integer>(elements.length);
for (int i = 0, end = elements.length; i < end; ++i)
{
Object element = elements[i];
_elementToIndex.put(element, i);
// HACK: In Java, although 0.0 == -0.0, this is not true when wrapped in a
// Double or Float object!
if (element instanceof Double)
{
Double d = (Double)element;
if (d == 0.0)
{
_elementToIndex.put(Double.valueOf(-d), i);
}
}
else if (element instanceof Float)
{
Float f = (Float)element;
if (f == 0.0)
{
_elementToIndex.put(Float.valueOf(-f), i);
}
}
}
if (!hasIntCompatibleValues && Number.class.isAssignableFrom(eltClass))
{
Number[] numbers = (Number[])elements;
hasIntCompatibleValues = true;
for (Number number : numbers)
{
if (!isIntCompatibleValue(number))
{
hasIntCompatibleValues = false;
break;
}
}
}
_hasIntCompatibleValues = hasIntCompatibleValues;
}
private static int computeHashCode(Object firstElement, Object[] elements)
{
final int prime = 31;
int result = 1;
result = prime * result + Arrays.hashCode(elements);
return result;
}
/*----------------
* Domain methods
*/
@Override
public final boolean hasIntCompatibleValues()
{
return _hasIntCompatibleValues;
}
@Override
public boolean inDomain(@Nullable Object value)
{
return _elementToIndex.containsKey(value);
}
@Override
public boolean isNumber()
{
return isNumeric();
}
@Override
public boolean isNumeric()
{
return Number.class.isAssignableFrom(getElementClass());
}
/*------------------------
* DiscreteDomain methods
*/
@Override
public final Class<? extends Element> getElementClass()
{
@SuppressWarnings("unchecked")
Class<? extends Element> elementClass = (Class<? extends Element>) _elements.getClass().getComponentType();
return elementClass;
}
@NonNull // FIXME - workaround for Eclipse JDT bug (467610?)
@Override
public Element getElement(int i)
{
return _elements[i];
}
@Override
public final Element[] getElements()
{
return _elements.clone();
}
// Find the list of elements corresponding to the value; return -1 if not a valid value
@Override
public int getIndex(@Nullable Object value)
{
Integer index = _elementToIndex.get(value);
return index != null ? index : -1;
}
@Override
public final int size()
{
return _elements.length;
}
}