Skip to main content
summaryrefslogtreecommitdiffstats
blob: 1342e9751a94bb84b8e13e3e992c1ec0192270a1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
/**
 * This file was copied and re-packaged automatically by
 *     org.eclipse.qvtd.doc.miniocl.build.MiniOCLBuildEverything
 * from 
 *     ..\..\plugins\org.eclipse.qvtd.runtime\src\org\eclipse\qvtd\runtime\internal\evaluation\AbstractComputationConstructor.java
 *
 * Do not edit this file. 
 */
/*******************************************************************************
 * Copyright (c) 2016 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.qvtd.doc.minioclcs.xtext.internal.tx;

import java.util.ArrayList;
import java.util.HashMap;
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.ids.IdResolver;
import org.eclipse.qvtd.doc.minioclcs.xtext.tx.AbstractTransformer;
import org.eclipse.qvtd.doc.minioclcs.xtext.tx.Computation;

public abstract class AbstractComputationConstructor implements Computation.Constructor
{
	protected final IdResolver.@NonNull IdResolverExtension idResolver;
	
	/**
	 * Map from invocation hashCode to one or more computations with that hashCode. Single map entries use the
	 * Computation directly as the entry. Colliding entries use a List<@NonNull Computation> for the collisions.
	 * <br>
	 * This map is used to inhibit repeated computations.
	 */
	private final @NonNull Map<@NonNull Integer, @NonNull Object> hashCode2computations = new HashMap<@NonNull Integer, @NonNull Object>();
	
	protected AbstractComputationConstructor(@NonNull IdResolver idResolver) {
		this.idResolver = (IdResolver.IdResolverExtension)idResolver;
	}
	
	@Override
	public @NonNull Computation getUniqueComputation(@Nullable Object @NonNull ... argValues) {
		int hashCode = 0;
    	for (@Nullable Object argValue : argValues) {
    		hashCode = 3 * hashCode + idResolver.oclHashCode(argValue);
    	}
    	synchronized (hashCode2computations) {
	    	Object zeroOrMoreComputations = hashCode2computations.get(hashCode);
	    	Computation oneComputation = null;
	    	if (zeroOrMoreComputations instanceof Computation) {
	    		oneComputation = (Computation)zeroOrMoreComputations;
	    		if (oneComputation.isEqual(idResolver, argValues)) {
	    	    	AbstractTransformer.INVOCATIONS.println("getUniqueComputation old:" + oneComputation);
		    		return oneComputation;
		    	}
	    	}
	    	else if (zeroOrMoreComputations instanceof List<?>) {
	    		@SuppressWarnings("unchecked")@NonNull List<@NonNull Computation> zeroOrMoreComputations2 = (List<@NonNull Computation>)zeroOrMoreComputations;
				for (@NonNull Computation aComputation : zeroOrMoreComputations2) {
			   		if (aComputation.isEqual(idResolver, argValues)) {
		    	    	AbstractTransformer.INVOCATIONS.println("getUniqueComputation old:" + aComputation);
			    		return aComputation;
	    	    	}
	    		}
	    	}
    	}
    	//
    	//	Must resynchronize after newInstance creation and execution in case the execution is recursive.
    	//
	    Computation theComputation = newInstance(argValues);
    	synchronized (hashCode2computations) {
	    	Object zeroOrMoreComputations = hashCode2computations.get(hashCode);
			if (zeroOrMoreComputations == null) {
				hashCode2computations.put(hashCode, theComputation);
			}
			else if (zeroOrMoreComputations instanceof Computation) {
				Computation oneComputation = (Computation)zeroOrMoreComputations;
	    		if (oneComputation.isEqual(idResolver, argValues)) {
	    	    	AbstractTransformer.INVOCATIONS.println("getUniqueComputation old:" + oneComputation);
		    		return oneComputation;
		    	}
	    		List<@NonNull Computation> twoOrMoreComputations = new ArrayList<@NonNull Computation>(4);
	    		twoOrMoreComputations.add(oneComputation);
	    		twoOrMoreComputations.add(theComputation);
	    		hashCode2computations.put(hashCode, twoOrMoreComputations);
			}
	    	else if (zeroOrMoreComputations instanceof List<?>) {
	    		@SuppressWarnings("unchecked")@NonNull List<@NonNull Computation> twoOrMoreComputations = (List<@NonNull Computation>)zeroOrMoreComputations;
	    		for (@NonNull Computation aComputation : twoOrMoreComputations) {
			   		if (aComputation.isEqual(idResolver, argValues)) {
		    	    	AbstractTransformer.INVOCATIONS.println("getUniqueComputation old:" + aComputation);
			    		return aComputation;
	    	    	}
	    		}
	    		twoOrMoreComputations.add(theComputation);
	    	}
	    	AbstractTransformer.INVOCATIONS.println("getUniqueComputation new:" + theComputation);
			return theComputation;
    	}
    }

	protected abstract @NonNull Computation newInstance(@Nullable Object @NonNull [] values);
	
}

Back to the top