blob: 47dd414322aa70fe62c7913b0f785497ccd1c0c8 [file] [log] [blame]
/*
* Copyright 2012-present Facebook, Inc.
*
* 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.facebook.buck.android;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
/**
* Filter for internal class names.
*
* <p>We use this to determine if a class must be placed in our primary dex.
* It supports prefix, suffix, substring, and exact matches.
*/
public class ClassNameFilter {
// We use naive algorithms for prefix, suffix, and substring, but these could easily be
// optimzied using RE2 or some other more specialized search algorithms.
private final ImmutableList<String> prefixes;
private final ImmutableList<String> suffixes;
private final ImmutableList<String> substrings;
private final ImmutableSet<String> exactMatches;
private ClassNameFilter(
Iterable<String> prefixes,
Iterable<String> suffixes,
Iterable<String> substrings,
Iterable<String> exactMatches) {
this.prefixes = ImmutableList.copyOf(prefixes);
this.suffixes = ImmutableList.copyOf(suffixes);
this.substrings = ImmutableList.copyOf(substrings);
this.exactMatches = ImmutableSet.copyOf(exactMatches);
}
/**
* Convenience factory to produce a filter from a very simple pattern language.
*
* <p>patterns are substrings by default, but {@code ^} at the start or end of a pattern
* anchors it to the start or end of the class name.
*
* @param patterns Patterns to include in the filter.
* @return A new filter.
*/
public static ClassNameFilter fromConfiguration(Iterable<String> patterns) {
ImmutableList.Builder<String> prefixes = ImmutableList.builder();
ImmutableList.Builder<String> suffixes = ImmutableList.builder();
ImmutableList.Builder<String> substrings = ImmutableList.builder();
ImmutableSet.Builder<String> exactMatches = ImmutableSet.builder();
for (String pattern : patterns) {
boolean isPrefix = pattern.charAt(0) == '^';
boolean isSuffix = pattern.charAt(pattern.length() - 1) == '^';
if (isPrefix && isSuffix) {
exactMatches.add(pattern.substring(1, pattern.length() - 1));
} else if (isPrefix) {
prefixes.add(pattern.substring(1));
} else if (isSuffix) {
suffixes.add(pattern.substring(0, pattern.length() - 1));
} else {
substrings.add(pattern);
}
}
return new ClassNameFilter(
prefixes.build(),
suffixes.build(),
substrings.build(),
exactMatches.build());
}
public boolean matches(String internalClassName) {
if (exactMatches.contains(internalClassName)) {
return true;
}
for (String prefix : prefixes) {
if (internalClassName.startsWith(prefix)) {
return true;
}
}
for (String suffix : suffixes) {
if (internalClassName.endsWith(suffix)) {
return true;
}
}
for (String substring : substrings) {
if (internalClassName.contains(substring)) {
return true;
}
}
return false;
}
}