|  | // Copyright (c) 2019, the R8 project authors. Please see the AUTHORS file | 
|  | // for details. All rights reserved. Use of this source code is governed by a | 
|  | // BSD-style license that can be found in the LICENSE file. | 
|  |  | 
|  | package com.android.tools.r8.utils; | 
|  |  | 
|  | import static com.android.tools.r8.utils.StringUtils.EMPTY_CHAR_ARRAY; | 
|  |  | 
|  | import com.google.common.collect.Sets; | 
|  | import java.util.Arrays; | 
|  | import java.util.Set; | 
|  |  | 
|  | public class SymbolGenerationUtils { | 
|  |  | 
|  | public enum MixedCasing { | 
|  | USE_MIXED_CASE, | 
|  | DONT_USE_MIXED_CASE | 
|  | } | 
|  |  | 
|  | public static Set<String> RESERVED_NAMES = | 
|  | Sets.newHashSet( | 
|  | "boolean", "byte", "char", "double", "float", "int", "long", "short", "void", "it", "by"); | 
|  |  | 
|  | // These letters are used not creating fresh names to output and not for parsing dex/class files. | 
|  | private static final char[] IDENTIFIER_CHARACTERS = | 
|  | "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ".toCharArray(); | 
|  | private static final int NUMBER_OF_CHARACTERS = IDENTIFIER_CHARACTERS.length; | 
|  | private static final int NUMBER_OF_CHARACTERS_MINUS_CAPITAL_LETTERS = NUMBER_OF_CHARACTERS - 26; | 
|  | private static final int NON_ALLOWED_FIRST_CHARACTERS = 10; | 
|  |  | 
|  | public static String numberToIdentifier(int nameCount, MixedCasing mixedCasing) { | 
|  | return numberToIdentifier(nameCount, mixedCasing, EMPTY_CHAR_ARRAY, false); | 
|  | } | 
|  |  | 
|  | public static String numberToIdentifier(int nameCount, MixedCasing mixedCasing, char[] prefix) { | 
|  | return numberToIdentifier(nameCount, mixedCasing, prefix, false); | 
|  | } | 
|  |  | 
|  | public static String numberToIdentifier( | 
|  | int nameCount, MixedCasing mixedCasing, char[] prefix, boolean addSemicolon) { | 
|  | int size = 1; | 
|  | int number = nameCount; | 
|  | int maximumNumberOfCharacters = | 
|  | mixedCasing == MixedCasing.USE_MIXED_CASE | 
|  | ? NUMBER_OF_CHARACTERS | 
|  | : NUMBER_OF_CHARACTERS_MINUS_CAPITAL_LETTERS; | 
|  | int firstNumberOfCharacters = maximumNumberOfCharacters - NON_ALLOWED_FIRST_CHARACTERS; | 
|  | int availableCharacters = firstNumberOfCharacters; | 
|  | // We first do an initial computation to find the size of the resulting string to allocate an | 
|  | // array that will fit in length. | 
|  | while (number > availableCharacters) { | 
|  | number = (number - 1) / availableCharacters; | 
|  | availableCharacters = maximumNumberOfCharacters; | 
|  | size++; | 
|  | } | 
|  | size += addSemicolon ? 1 : 0; | 
|  | char characters[] = Arrays.copyOfRange(prefix, 0, prefix.length + size); | 
|  | number = nameCount; | 
|  |  | 
|  | int i = prefix.length; | 
|  | availableCharacters = firstNumberOfCharacters; | 
|  | int firstLetterPadding = NON_ALLOWED_FIRST_CHARACTERS; | 
|  | while (number > availableCharacters) { | 
|  | characters[i++] = | 
|  | IDENTIFIER_CHARACTERS[(number - 1) % availableCharacters + firstLetterPadding]; | 
|  | number = (number - 1) / availableCharacters; | 
|  | availableCharacters = maximumNumberOfCharacters; | 
|  | firstLetterPadding = 0; | 
|  | } | 
|  | characters[i++] = IDENTIFIER_CHARACTERS[number - 1 + firstLetterPadding]; | 
|  | if (addSemicolon) { | 
|  | characters[i++] = ';'; | 
|  | } | 
|  | assert i == characters.length; | 
|  | assert !Character.isDigit(characters[prefix.length]); | 
|  |  | 
|  | return new String(characters); | 
|  | } | 
|  | } |