/* * Copyright 2010 The Closure Compiler Authors. * * 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.google.javascript.jscomp; import com.google.common.base.Function; import com.google.common.base.Preconditions; import com.google.javascript.jscomp.graph.LatticeElement; import java.util.Iterator; import java.util.List; /** * Defines a way join a list of LatticeElements. */ interface JoinOp<L extends LatticeElement> extends Function<List<L>, L> { /** * An implementation of {@code JoinOp} that makes it easy to join to * lattice elements at a time. */ abstract static class BinaryJoinOp<L extends LatticeElement> implements JoinOp<L> { @Override public L apply(List<L> values) { Preconditions.checkArgument(!values.isEmpty()); int size = values.size(); if (size == 1) { return values.get(0); } else if (size == 2) { return apply(values.get(0), values.get(1)); } else if (size <= 16) { // Do a Tree merge which request the least number of merges int mid = computeMidPoint(size); return apply( apply(values.subList(0, mid)), apply(values.subList(mid, size))); } else { // If the merge set is getting out of hand, avoid tree merges as it is // more memory intense. Instead, stick with linear merges that requires // more merges but less memory. This avoids GC trashing. Iterator<L> iter = values.iterator(); L result = iter.next(); // Never null, we have 16+ values. while (iter.hasNext()) { result = apply(result, iter.next()); } return result; } } /** * Creates a new lattice that will be the join of two input lattices. * * @return The join of {@code latticeA} and {@code latticeB}. */ abstract L apply(L latticeA, L latticeB); /** * Finds the midpoint of a list. The function will favor two lists of * even length instead of two lists of the same odd length. The list * must be at least length two. * * @param size Size of the list. */ static int computeMidPoint(int size) { int midpoint = size >>> 1; if (size > 4) { /* Any list longer than 4 should prefer an even split point * over the true midpoint, so that [0,6] splits at 2, not 3. */ midpoint &= -2; // (0xfffffffe) clears low bit so midpoint is even } return midpoint; } } }