| /******************************************************************************* |
| * 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) { |
| |
| } |
| } |
| } |