1 // Copyright 2017 The Bazel Authors. All rights reserved. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 package com.google.devtools.build.android.desugar; 15 16 import static com.google.common.base.Preconditions.checkArgument; 17 import static com.google.common.base.Preconditions.checkState; 18 19 import com.google.common.collect.ImmutableMap; 20 import java.util.HashMap; 21 import java.util.List; 22 import java.util.Map; 23 import javax.annotation.CheckReturnValue; 24 import javax.annotation.Nullable; 25 26 /** 27 * Opens the given list of input files and compute an index of all classes in them, to avoid 28 * scanning all inputs over and over for each class to load. An indexed inputs can have a parent 29 * that is firstly used when a file name is searched. 30 */ 31 class IndexedInputs { 32 33 private final ImmutableMap<String, InputFileProvider> inputFiles; 34 35 /** 36 * Parent {@link IndexedInputs} to use before to search a file name into this {@link 37 * IndexedInputs}. 38 */ 39 @Nullable 40 private final IndexedInputs parent; 41 42 /** Index a list of input files without a parent {@link IndexedInputs}. */ 43 public IndexedInputs(List<InputFileProvider> inputProviders) { 44 this.parent = null; 45 this.inputFiles = indexInputs(inputProviders); 46 } 47 48 /** 49 * Create a new {@link IndexedInputs} with input files previously indexed and with a parent {@link 50 * IndexedInputs}. 51 */ 52 private IndexedInputs( 53 ImmutableMap<String, InputFileProvider> inputFiles, IndexedInputs parentIndexedInputs) { 54 this.parent = parentIndexedInputs; 55 this.inputFiles = inputFiles; 56 } 57 58 /** 59 * Create a new {@link IndexedInputs} with input files already indexed and with a parent {@link 60 * IndexedInputs}. 61 */ 62 @CheckReturnValue 63 public IndexedInputs withParent(IndexedInputs parent) { 64 checkState(this.parent == null); 65 return new IndexedInputs(this.inputFiles, parent); 66 } 67 68 @Nullable 69 public InputFileProvider getInputFileProvider(String filename) { 70 checkArgument(filename.endsWith(".class")); 71 72 if (parent != null) { 73 InputFileProvider inputFileProvider = parent.getInputFileProvider(filename); 74 if (inputFileProvider != null) { 75 return inputFileProvider; 76 } 77 } 78 79 return inputFiles.get(filename); 80 } 81 82 private ImmutableMap<String, InputFileProvider> indexInputs( 83 List<InputFileProvider> inputProviders) { 84 Map<String, InputFileProvider> indexedInputs = new HashMap<>(); 85 for (InputFileProvider inputProvider : inputProviders) { 86 for (String relativePath : inputProvider) { 87 if (relativePath.endsWith(".class") && !indexedInputs.containsKey(relativePath)) { 88 indexedInputs.put(relativePath, inputProvider); 89 } 90 } 91 } 92 return ImmutableMap.copyOf(indexedInputs); 93 } 94 } 95