blob: d147797d618ba0f537d04cc5157aced151bee683 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2011, 2017 Willink Transformations and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* E.D.Willink - initial API and implementation
*******************************************************************************/
package org.eclipse.ocl.pivot.internal.complete;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.jdt.annotation.NonNull;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.ocl.pivot.CompleteInheritance;
import org.eclipse.ocl.pivot.Operation;
import org.eclipse.ocl.pivot.StandardLibrary;
import org.eclipse.ocl.pivot.ids.ParametersId;
import org.eclipse.ocl.pivot.utilities.ClassUtil;
import org.eclipse.ocl.pivot.utilities.EnvironmentFactory;
import org.eclipse.ocl.pivot.utilities.FeatureFilter;
import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
public class PartialOperations //extends HashMap<ParametersId, List<DomainOperation>>
{
// private static final long serialVersionUID = 1L;
public static final @NonNull Function<PartialOperations, Iterable<Iterable<Operation>>> partialOperations2allOperations =
new Function<PartialOperations, Iterable<Iterable<Operation>>>() {
@Override
public Iterable<Iterable<Operation>> apply(PartialOperations partialOperations) {
return partialOperations.getOperationsInternal(null);
}
};
/**
* An OverloadsList is a non-empty list of Operations sharing the same name and parameter types.
* It can be sorted into most-derived first order.
*/
private static class OverloadsList extends ArrayList<@NonNull Operation> implements Comparator</*@NonNull*/ Integer>
{
private static final long serialVersionUID = 1L;
private /*@NonNull*/ Integer[] keys;
private /*@NonNull*/ Integer[] metrics;
public OverloadsList() {
super(4);
}
@Override
public int compare(/*@NonNull*/ Integer o1, /*@NonNull*/ Integer o2) {
/*@NonNull*/ Integer m1 = metrics[o1];
/*@NonNull*/ Integer m2 = metrics[o2];
return m2 - m1;
}
public void sort(@NonNull EnvironmentFactory environmentFactory) {
StandardLibrary standardLibrary = environmentFactory.getStandardLibrary();
int size = size();
@NonNull Integer @NonNull [] keys2 = new @NonNull Integer[size];
keys = keys2;
metrics = new @NonNull Integer[size];
@NonNull Integer index = 0;
for (@NonNull Operation operation : this) {
keys2[index] = index;
int metric = 0;
org.eclipse.ocl.pivot.Class owningClass = operation.getOwningClass();
CompleteInheritance inheritance = owningClass.getInheritance(standardLibrary);
int depth = inheritance.getDepth();
// int isRedefinition = (operation instanceof Operation) && (((Operation)operation).getRedefinedOperation().size() > 0) ? 1 : 0;
metric = depth;
metrics[index] = metric;
index++;
}
Arrays.sort(keys, this);
List<@NonNull Operation> savedOperations = new ArrayList<@NonNull Operation>(this);
clear();
for (int i = 0; i < size; i++) {
add(savedOperations.get(keys[i]));
}
keys = null;
metrics = null;
}
}
/**
* Overloads maintains the distinct OverloadsLists for static and non-static operations
* that share the same name and parameter types.
*/
private class Overloads implements Iterable<@NonNull Operation>
{
private @Nullable OverloadsList staticOperations = null;
private @Nullable OverloadsList nonStaticOperations = null;
private boolean sorted = false;
public void add(@NonNull Operation pivotOperation) {
OverloadsList list;
if (pivotOperation.isIsStatic()) {
if (staticOperations == null) {
staticOperations = new OverloadsList();
}
list = staticOperations;
}
else {
if (nonStaticOperations == null) {
nonStaticOperations = new OverloadsList();
}
list = nonStaticOperations;
}
assert list != null;
if (!list.contains(pivotOperation)) {
list.add(pivotOperation);
sorted = false;
}
}
public @NonNull Operation getBest() {
OverloadsList list = nonStaticOperations != null ? nonStaticOperations : staticOperations;
assert list != null;
if ((list.size() > 1) && !sorted) {
// FIXME redefinitions
EnvironmentFactory environmentFactory = completeClass.getOwningCompletePackage().getCompleteModel().getEnvironmentFactory();
if (nonStaticOperations != null) {
nonStaticOperations.sort(environmentFactory);
}
if (staticOperations != null) {
staticOperations.sort(environmentFactory);
}
sorted = true;
}
Operation bestOperation = list.get(0);
assert bestOperation != null;
return bestOperation;
}
@Override
public @NonNull Iterator<@NonNull Operation> iterator() {
OverloadsList staticOperations2 = staticOperations;
OverloadsList nonStaticOperations2 = nonStaticOperations;
if (staticOperations2 != null) {
if (nonStaticOperations2 != null) {
return Iterators.concat(nonStaticOperations2.iterator(), staticOperations2.iterator());
}
else {
return staticOperations2.iterator();
}
}
else {
if (nonStaticOperations2 != null) {
return nonStaticOperations2.iterator();
}
else {
return ClassUtil.emptyIterator();
}
}
}
public boolean remove(@NonNull Operation pivotOperation) {
if (pivotOperation.isIsStatic()) {
OverloadsList staticOperations2 = staticOperations;
if (staticOperations2 != null) {
boolean remove = staticOperations2.remove(pivotOperation);
if (staticOperations2.isEmpty()) {
staticOperations = null;
}
return remove;
}
}
else {
OverloadsList nonStaticOperations2 = nonStaticOperations;
if (nonStaticOperations2 != null) {
boolean remove = nonStaticOperations2.remove(pivotOperation);
if (nonStaticOperations2.isEmpty()) {
nonStaticOperations = null;
}
return remove;
}
}
return false;
}
public int size() {
OverloadsList staticOperations2 = staticOperations;
OverloadsList nonStaticOperations2 = nonStaticOperations;
return (staticOperations2 != null ? staticOperations2.size() : 0) + (nonStaticOperations2 != null ? nonStaticOperations2.size() : 0);
}
}
protected final @NonNull CompleteClassInternal completeClass;
protected final @NonNull String name;
private final @NonNull Map<@NonNull ParametersId, Object> map = new HashMap<@NonNull ParametersId, Object>();
public PartialOperations(@NonNull CompleteClassInternal completeClass, @NonNull String name) {
this.completeClass = completeClass;
this.name = name;
}
public void didAddOperation(@NonNull Operation pivotOperation) {
ParametersId parametersId = pivotOperation.getParametersId();
Object partials = map.get(parametersId);
if (partials instanceof Overloads) {
Overloads overloads = (Overloads)partials;
overloads.add(pivotOperation);
}
else if (partials != null) { // Must be an Operation
if (partials != pivotOperation) {
Overloads overloads = new Overloads();
map.put(parametersId, overloads);
overloads.add((Operation)partials);
overloads.add(pivotOperation);
}
}
else {
map.put(parametersId, pivotOperation);
}
}
public boolean didRemoveOperation(@NonNull Operation pivotOperation) {
ParametersId parametersId = pivotOperation.getParametersId();
Object partials = map.get(parametersId);
if (partials instanceof Overloads) {
Overloads overloads = (Overloads)partials;
overloads.remove(pivotOperation);
if (overloads.size() == 1) {
map.put(parametersId, overloads.getBest());
}
else if (overloads.size() <= 0) {
map.remove(parametersId); // Never happens
}
}
else if (partials != null) { // Must be an Operation
map.remove(parametersId);
}
else {
map.put(parametersId, pivotOperation);
}
return map.isEmpty();
}
public @Nullable Operation getOperation(@NonNull ParametersId parametersId, @Nullable FeatureFilter featureFilter) {
Object partials = map.get(parametersId);
if (partials instanceof Overloads) {
Overloads overloads = (Overloads)partials;
Operation bestOperation = overloads.getBest();
if (featureFilter == null) {
return bestOperation;
}
for (@NonNull Operation operation : overloads) {
if (featureFilter.accept(operation)) {
return operation;
}
}
return null;
}
else if (partials != null) { // Must be an Operation
Operation operation = (Operation) partials;
return (featureFilter == null) || featureFilter.accept(operation) ? operation : null;
}
else {
return null;
}
}
public @NonNull Iterable<@NonNull Operation> getOperationOverloads(@NonNull ParametersId parametersId, final @Nullable FeatureFilter featureFilter) {
Object partials = map.get(parametersId);
if (partials instanceof Overloads) {
Overloads overloads = (Overloads)partials;
overloads.getBest();
if (featureFilter == null) {
return overloads;
}
return Iterables.filter(overloads, new Predicate<@NonNull Operation>()
{
@Override
public boolean apply(@NonNull Operation input) {
return featureFilter.accept(input);
}
});
}
else if (partials != null) { // Must be an Operation
Operation operation = (Operation) partials;
if ((featureFilter == null) || featureFilter.accept(operation)) {
return Collections.singletonList((Operation)partials);
}
}
return Collections.emptyList();
}
public @NonNull Iterable<@NonNull Operation> getOperationOverloads(final @Nullable FeatureFilter featureFilter) {
Iterable<@NonNull Operation> unfilteredOverloads = Iterables.concat(Iterables.transform(map.keySet(), new Function<@NonNull ParametersId, @NonNull Iterable<@NonNull Operation>>()
{
@Override
public @NonNull Iterable<@NonNull Operation> apply(@NonNull ParametersId parametersId) {
return getOperationOverloads(parametersId, featureFilter);
}
}));
if (featureFilter == null) {
return unfilteredOverloads;
}
return Iterables.filter(unfilteredOverloads, new Predicate<@NonNull Operation>()
{
@Override
public boolean apply(@NonNull Operation input) {
return featureFilter.accept(input);
}
});
}
@SuppressWarnings("null")
public @NonNull Iterable<@NonNull ? extends Operation> getOperations(final @Nullable FeatureFilter featureFilter) {
// if (featureFilter == FeatureFilter.SELECT_NON_STATIC) {
// return
// }
return Iterables.transform(map.keySet(), new Function<ParametersId, Operation>()
{
@Override
public Operation apply(ParametersId parametersId) {
return getOperation(parametersId, featureFilter);
}
});
}
private @NonNull Iterable<@NonNull Iterable<@NonNull Operation>> getOperationsInternal(final @Nullable FeatureFilter featureFilter) {
return Iterables.transform(map.keySet(), new Function<ParametersId, @NonNull Iterable<@NonNull Operation>>()
{
@Override
public @NonNull Iterable<@NonNull Operation> apply(ParametersId parametersId) {
assert parametersId != null;
return getOperationOverloads(parametersId, featureFilter);
}
});
}
public void initMemberOperationsPostProcess() {
for (Object partials : map.values()) {
if (partials instanceof Overloads) {
Overloads overloads = (Overloads)partials;
initMemberOperationsPostProcess(completeClass.getName(), overloads);
}
}
}
protected void initMemberOperationsPostProcess(String name, @NonNull Overloads operations) {
if (operations.size() > 1) {
}
}
}