001: /*
002: * Copyright 2007 Google Inc.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License"); you may not
005: * use this file except in compliance with the License. You may obtain a copy of
006: * the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
012: * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
013: * License for the specific language governing permissions and limitations under
014: * the License.
015: */
016: package com.google.gwt.dev.cfg;
017:
018: import com.google.gwt.core.ext.TreeLogger;
019: import com.google.gwt.core.ext.UnableToCompleteException;
020: import com.google.gwt.dev.jdt.RebindOracle;
021:
022: import java.util.ArrayList;
023: import java.util.Iterator;
024: import java.util.List;
025:
026: /**
027: * Manages a set of {@link Compilation} objects keyed by deferred binding
028: * decisions. This class encapsulaes the idea of caching a set of compilations,
029: * some of which may be reusable between permutations to avoid redundant
030: * recompilation.
031: */
032: public class Compilations {
033:
034: private final List<Compilation> list = new ArrayList<Compilation>();
035:
036: public void add(Compilation compilation) {
037: list.add(compilation);
038: }
039:
040: /**
041: * Finds an existing compilation that is equivalent to what would be
042: * generated.
043: */
044: public Compilation find(TreeLogger logger,
045: RebindOracle rebindOracle, String[] entryPts)
046: throws UnableToCompleteException {
047: // NOTE: This could be optimized in a wide variety of ways.
048: //
049:
050: // Clone the list so that we can easily whittle it down.
051: //
052: List<Compilation> candidates = new ArrayList<Compilation>(list);
053:
054: // First, the entry points must all be present and map the same way in the
055: // correct compilation.
056: //
057: for (int i = 0; !candidates.isEmpty() && i < entryPts.length; i++) {
058: String in = entryPts[i];
059: String out = rebindOracle.rebind(logger, in);
060: removeMismatches(candidates, in, out);
061: }
062:
063: // For the remaining compilations, all recorded rebinds must still match.
064: //
065: for (Iterator<Compilation> iter = candidates.iterator(); iter
066: .hasNext();) {
067: Compilation c = iter.next();
068: String[] cachedIns = c.getRebindInputs();
069: for (int i = 0; i < cachedIns.length; i++) {
070: String cachedIn = cachedIns[i];
071: String cachedOut = c.getRebindOutput(cachedIn);
072: String out = rebindOracle.rebind(logger, cachedIn);
073: if (!cachedOut.equals(out)) {
074: // Not a candidate anymore; remove it.
075: //
076: iter.remove();
077: break;
078: }
079: }
080: }
081:
082: if (candidates.isEmpty()) {
083: // Not found in the cache.
084: //
085: return null;
086: } else if (candidates.size() == 1) {
087: // Found the perfect match.
088: //
089: return candidates.get(0);
090: } else {
091: // Unexpected situation that means something really weird happened.
092: //
093: String msg = "Cannot decided between multiple existing compilations; cannot continue";
094: logger.log(TreeLogger.ERROR, msg, null);
095: throw new UnableToCompleteException();
096: }
097: }
098:
099: public Iterator<Compilation> iterator() {
100: return list.iterator();
101: }
102:
103: private void removeMismatches(List<Compilation> candidates,
104: String in, String out) {
105: for (Iterator<Compilation> iter = candidates.iterator(); iter
106: .hasNext();) {
107: Compilation c = iter.next();
108: String cachedOut = c.getRebindOutput(in);
109: if (!out.equals(cachedOut)) {
110: iter.remove();
111: }
112: }
113: }
114: }
|