• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright (c) 2016, the R8 project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4 package com.android.tools.r8.utils;
5 
6 import com.android.tools.r8.errors.Unreachable;
7 import java.security.MessageDigest;
8 import java.security.NoSuchAlgorithmException;
9 import java.util.Arrays;
10 import java.util.Collection;
11 import java.util.function.Function;
12 
13 public class StringUtils {
14 
15   private final static char[] IDENTIFIER_LETTERS
16       = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_".toCharArray();
17   private final static int NUMBER_OF_LETTERS = IDENTIFIER_LETTERS.length;
18 
19   public enum BraceType {
20     PARENS,
21     SQUARE,
22     TUBORG,
23     NONE;
24 
left()25     public String left() {
26       switch (this) {
27         case PARENS: return "(";
28         case SQUARE: return "[";
29         case TUBORG: return "{";
30         case NONE: return "";
31         default: throw new Unreachable("Invalid brace type: " + this);
32       }
33     }
34 
right()35     public String right() {
36       switch (this) {
37         case PARENS: return ")";
38         case SQUARE: return "]";
39         case TUBORG: return "}";
40         case NONE: return "";
41         default: throw new Unreachable("Invalid brace type: " + this);
42       }
43     }
44   }
45 
appendNonEmpty(StringBuilder builder, String pre, Object item, String post)46   public static void appendNonEmpty(StringBuilder builder, String pre, Object item, String post) {
47     if (item == null) {
48       return;
49     }
50     String text = item.toString();
51     if (!text.isEmpty()) {
52       if (pre != null) {
53         builder.append(pre);
54       }
55       builder.append(text);
56       if (post != null) {
57         builder.append(post);
58       }
59     }
60   }
61 
appendIndent(StringBuilder builder, String subject, int indent)62   public static StringBuilder appendIndent(StringBuilder builder, String subject, int indent) {
63     for (int i = 0; i < indent; i++) {
64       builder.append(" ");
65     }
66     builder.append(subject);
67     return builder;
68   }
69 
appendLeftPadded(StringBuilder builder, String subject, int width)70   public static StringBuilder appendLeftPadded(StringBuilder builder, String subject, int width) {
71     for (int i = subject.length(); i < width; i++) {
72       builder.append(" ");
73     }
74     builder.append(subject);
75     return builder;
76   }
77 
appendRightPadded(StringBuilder builder, String subject, int width)78   public static StringBuilder appendRightPadded(StringBuilder builder, String subject, int width) {
79     builder.append(subject);
80     for (int i = subject.length(); i < width; i++) {
81       builder.append(" ");
82     }
83     return builder;
84   }
85 
append(StringBuilder builder, Collection<T> collection)86   public static <T> StringBuilder append(StringBuilder builder, Collection<T> collection) {
87     return append(builder, collection, ", ", BraceType.PARENS);
88   }
89 
append(StringBuilder builder, Collection<T> collection, String seperator, BraceType brace)90   public static <T> StringBuilder append(StringBuilder builder, Collection<T> collection,
91       String seperator, BraceType brace) {
92     builder.append(brace.left());
93     boolean first = true;
94     for (T element : collection) {
95       if (first) {
96         first = false;
97       } else {
98         builder.append(seperator);
99       }
100       builder.append(element);
101     }
102     builder.append(brace.right());
103     return builder;
104   }
105 
join(Collection<T> collection, String separator)106   public static <T> String join(Collection<T> collection, String separator) {
107     return join(collection, separator, BraceType.NONE);
108   }
109 
join(String separator, String... strings)110   public static String join(String separator, String... strings) {
111     return join(Arrays.asList(strings), separator, BraceType.NONE);
112   }
113 
join(Collection<T> collection, String separator, BraceType brace)114   public static <T> String join(Collection<T> collection, String separator, BraceType brace) {
115     return join(collection, separator, brace, Object::toString);
116   }
117 
join(Collection<T> collection, String separator, BraceType brace, Function<T, String> fn)118   public static <T> String join(Collection<T> collection, String separator, BraceType brace,
119       Function<T, String> fn) {
120     StringBuilder builder = new StringBuilder();
121     append(builder, ListUtils.map(collection, fn), separator, brace);
122     return builder.toString();
123   }
124 
zeroPrefix(int i, int width)125   public static String zeroPrefix(int i, int width) {
126     return zeroPrefixString(Integer.toString(i), width);
127   }
128 
zeroPrefixString(String s, int width)129   private static String zeroPrefixString(String s, int width) {
130     String prefix = "0000000000000000";
131     assert(width <= prefix.length());
132     int prefixLength = width - s.length();
133     if (prefixLength > 0) {
134       StringBuilder builder = new StringBuilder();
135       builder.append(prefix, 0, prefixLength);
136       builder.append(s);
137       return builder.toString();
138     } else {
139       return s;
140     }
141   }
142 
hexString(int value, int width)143   public static String hexString(int value, int width) {
144     assert(0 <= width && width <= 8);
145     String hex = Integer.toHexString(value);
146     if (value >= 0) {
147       return zeroPrefixString(hex, width);
148     } else {
149       // Negative ints are always formatted as 8 characters.
150       assert(hex.length() == 8);
151       return hex;
152     }
153   }
154 
hexString(long value, int width)155   public static String hexString(long value, int width) {
156     assert(0 <= width && width <= 16);
157     String hex = Long.toHexString(value);
158     if (value >= 0) {
159       return zeroPrefixString(hex, width);
160     } else {
161       // Negative longs are always formatted as 16 characters.
162       assert(hex.length() == 16);
163       return hex;
164     }
165   }
166 
computeMD5Hash(String name)167   public static String computeMD5Hash(String name) {
168     byte[] digest = null;
169     try {
170       MessageDigest m = MessageDigest.getInstance("MD5");
171       m.reset();
172       m.update(name.getBytes());
173       digest = m.digest();
174     } catch (NoSuchAlgorithmException e) {
175       throw new RuntimeException(e);
176     }
177     return Arrays.toString(digest);
178   }
179 
numberToIdentifier(char[] prefix, int nameCount, boolean addSemicolon)180   public static String numberToIdentifier(char[] prefix, int nameCount, boolean addSemicolon) {
181     // TODO(herhut): Add support for using numbers.
182     int size = addSemicolon ? 1 : 0;
183     int number = nameCount;
184     while (number >= NUMBER_OF_LETTERS) {
185       number /= NUMBER_OF_LETTERS;
186       size++;
187     }
188     size++;
189     char characters[] = Arrays.copyOfRange(prefix, 0, prefix.length + size);
190     number = nameCount;
191 
192     int i = prefix.length;
193     while (number >= NUMBER_OF_LETTERS) {
194       characters[i++] = IDENTIFIER_LETTERS[number % NUMBER_OF_LETTERS];
195       number /= NUMBER_OF_LETTERS;
196     }
197     characters[i++] = IDENTIFIER_LETTERS[number - 1];
198     if (addSemicolon) {
199       characters[i++] = ';';
200     }
201     assert i == characters.length;
202 
203     return new String(characters);
204   }
205 }
206