| /* |
| * Copyright (C) 2009 The Guava 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.common.escape; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| |
| import com.google.common.annotations.Beta; |
| import com.google.common.annotations.GwtCompatible; |
| import com.google.common.annotations.VisibleForTesting; |
| import java.util.Collections; |
| import java.util.Map; |
| |
| /** |
| * An implementation-specific parameter class suitable for initializing {@link |
| * ArrayBasedCharEscaper} or {@link ArrayBasedUnicodeEscaper} instances. This class should be used |
| * when more than one escaper is created using the same character replacement mapping to allow the |
| * underlying (implementation specific) data structures to be shared. |
| * |
| * <p>The size of the data structure used by ArrayBasedCharEscaper and ArrayBasedUnicodeEscaper is |
| * proportional to the highest valued character that has a replacement. For example a replacement |
| * map containing the single character '{@literal \}u1000' will require approximately 16K of memory. |
| * As such sharing this data structure between escaper instances is the primary goal of this class. |
| * |
| * @author David Beaumont |
| * @since 15.0 |
| */ |
| @Beta |
| @GwtCompatible |
| public final class ArrayBasedEscaperMap { |
| /** |
| * Returns a new ArrayBasedEscaperMap for creating ArrayBasedCharEscaper or |
| * ArrayBasedUnicodeEscaper instances. |
| * |
| * @param replacements a map of characters to their escaped representations |
| */ |
| public static ArrayBasedEscaperMap create(Map<Character, String> replacements) { |
| return new ArrayBasedEscaperMap(createReplacementArray(replacements)); |
| } |
| |
| // The underlying replacement array we can share between multiple escaper |
| // instances. |
| private final char[][] replacementArray; |
| |
| private ArrayBasedEscaperMap(char[][] replacementArray) { |
| this.replacementArray = replacementArray; |
| } |
| |
| // Returns the non-null array of replacements for fast lookup. |
| char[][] getReplacementArray() { |
| return replacementArray; |
| } |
| |
| // Creates a replacement array from the given map. The returned array is a |
| // linear lookup table of replacement character sequences indexed by the |
| // original character value. |
| @VisibleForTesting |
| static char[][] createReplacementArray(Map<Character, String> map) { |
| checkNotNull(map); // GWT specific check (do not optimize) |
| if (map.isEmpty()) { |
| return EMPTY_REPLACEMENT_ARRAY; |
| } |
| char max = Collections.max(map.keySet()); |
| char[][] replacements = new char[max + 1][]; |
| for (char c : map.keySet()) { |
| replacements[c] = map.get(c).toCharArray(); |
| } |
| return replacements; |
| } |
| |
| // Immutable empty array for when there are no replacements. |
| private static final char[][] EMPTY_REPLACEMENT_ARRAY = new char[0][0]; |
| } |