1/*
2 * Copyright (C) 2010 The Guava Authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.common.base;
18
19import com.google.caliper.BeforeExperiment;
20import com.google.caliper.Benchmark;
21import com.google.caliper.Param;
22import com.google.common.base.Ascii;
23import com.google.common.collect.Lists;
24import com.google.common.primitives.Chars;
25
26import java.util.Collections;
27import java.util.List;
28import java.util.Locale;
29import java.util.Random;
30
31/**
32 * Benchmarks for the ASCII class.
33 *
34 * @author Kevin Bourrillion
35 */
36public class AsciiBenchmark {
37  private static String ALPHA =
38      "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
39  private static String NONALPHA =
40      "0123456789`~-_=+[]{}|;:',.<>/?!@#$%^&*()\"\\";
41
42  @Param({"20", "2000"}) int size;
43  @Param({"2", "20"}) int nonAlphaRatio; // one non-alpha char per this many chars
44  @Param boolean noWorkToDo;
45
46  Random random;
47  String testString;
48
49  @BeforeExperiment void setUp() {
50    random = new Random();
51
52    int nonAlpha = size / nonAlphaRatio;
53    int alpha = size - nonAlpha;
54
55    List<Character> chars = Lists.newArrayListWithCapacity(size);
56    for (int i = 0; i < alpha; i++) {
57      chars.add(randomAlpha());
58    }
59    for (int i = 0; i < nonAlpha; i++) {
60      chars.add(randomNonAlpha());
61    }
62    Collections.shuffle(chars, random);
63    char[] array = Chars.toArray(chars);
64    this.testString = new String(array);
65  }
66
67  private char randomAlpha() {
68    return ALPHA.charAt(random.nextInt(ALPHA.length()));
69  }
70
71  private char randomNonAlpha() {
72    return NONALPHA.charAt(random.nextInt(NONALPHA.length()));
73  }
74
75  @Benchmark int asciiStringToUpperCase(int reps) {
76    String string = noWorkToDo
77        ? Ascii.toUpperCase(testString)
78        : testString;
79
80    int dummy = 0;
81    for (int i = 0; i < reps; i++) {
82      dummy += Ascii.toUpperCase(string).length();
83    }
84    return dummy;
85  }
86
87  @Benchmark int asciiCharSequenceToUpperCase(int reps) {
88    String string = noWorkToDo
89        ? charSequenceToUpperCase(testString)
90        : testString;
91
92    int dummy = 0;
93    for (int i = 0; i < reps; i++) {
94      dummy += charSequenceToUpperCase(string).length();
95    }
96    return dummy;
97  }
98
99  @Benchmark int stringToUpperCase(int reps) {
100    String string = noWorkToDo
101        ? testString.toUpperCase(Locale.US)
102        : testString;
103
104    int dummy = 0;
105    for (int i = 0; i < reps; i++) {
106      dummy += string.toUpperCase(Locale.US).length();
107    }
108    return dummy;
109  }
110
111  @Benchmark boolean equalsIgnoreCaseCharSequence(int reps) {
112    // This benchmark has no concept of "noWorkToDo".
113    String upperString = testString.toUpperCase();
114    CharSequence testSeq = new StringBuilder(testString);
115    CharSequence upperSeq = new StringBuilder(upperString);
116    CharSequence[] lhs = new CharSequence[] { testString, testSeq, testString, testSeq };
117    CharSequence[] rhs = new CharSequence[] { upperString, upperString, upperSeq, upperSeq };
118
119    boolean dummy = false;
120    for (int i = 0; i < reps; i++) {
121      dummy ^= Ascii.equalsIgnoreCase(lhs[i & 0x3], rhs[i & 0x3]);
122    }
123    return dummy;
124  }
125
126  @Benchmark boolean equalsIgnoreCaseStringOnly(int reps) {
127    // This benchmark has no concept of "noWorkToDo".
128    String lhs = testString;
129    String rhs = testString.toUpperCase();
130
131    boolean dummy = false;
132    for (int i = 0; i < reps; i++) {
133      dummy ^= Ascii.equalsIgnoreCase(lhs, rhs);
134    }
135    return dummy;
136  }
137
138  @Benchmark boolean equalsIgnoreCaseJDK(int reps) {
139    // This benchmark has no concept of "noWorkToDo".
140    String lhs = testString;
141    String rhs = testString.toUpperCase();
142
143    boolean dummy = false;
144    for (int i = 0; i < reps; i++) {
145        dummy ^= lhs.equalsIgnoreCase(rhs);
146    }
147    return dummy;
148  }
149
150  @Benchmark boolean isUpperCase(int reps) {
151    // This benchmark has no concept of "noWorkToDo".
152    char[] chars = testString.toCharArray();
153
154    boolean dummy = false;
155    for (int i = 0; i < reps; i++) {
156      for (int n = 0; n < chars.length; n++) {
157        dummy ^= Ascii.isUpperCase(chars[n]);
158      }
159    }
160    return dummy;
161  }
162
163  static String charSequenceToUpperCase(CharSequence chars) {
164    int length = chars.length();
165    StringBuilder builder = new StringBuilder(length);
166    for (int i = 0; i < length; i++) {
167      builder.append(Ascii.toUpperCase(chars.charAt(i)));
168    }
169    return builder.toString();
170  }
171}
172