1 /*
2  * Copyright (C) 2011 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 
17 package com.google.common.base;
18 
19 import com.google.caliper.BeforeExperiment;
20 import com.google.caliper.Benchmark;
21 import com.google.caliper.Param;
22 
23 /**
24  * Microbenchmark for {@link com.google.common.base.Strings#repeat}
25  *
26  * @author Mike Cripps
27  */
28 public class StringsRepeatBenchmark {
29   @Param({"1", "5", "25", "125"})
30   int count;
31 
32   @Param({"1", "10"})
33   int length;
34 
35   private String originalString;
36 
37   @BeforeExperiment
setUp()38   void setUp() {
39     originalString = Strings.repeat("x", length);
40   }
41 
42   @Benchmark
oldRepeat(int reps)43   void oldRepeat(int reps) {
44     for (int i = 0; i < reps; i++) {
45       String x = oldRepeat(originalString, count);
46       if (x.length() != (originalString.length() * count)) {
47         throw new RuntimeException("Wrong length: " + x);
48       }
49     }
50   }
51 
oldRepeat(String string, int count)52   private static String oldRepeat(String string, int count) {
53     // If this multiplication overflows, a NegativeArraySizeException or
54     // OutOfMemoryError is not far behind
55     final int len = string.length();
56     final int size = len * count;
57     char[] array = new char[size];
58     for (int i = 0; i < size; i += len) {
59       string.getChars(0, len, array, i);
60     }
61     return new String(array);
62   }
63 
64   @Benchmark
mikeRepeat(int reps)65   void mikeRepeat(int reps) {
66     for (int i = 0; i < reps; i++) {
67       String x = mikeRepeat(originalString, count);
68       if (x.length() != (originalString.length() * count)) {
69         throw new RuntimeException("Wrong length: " + x);
70       }
71     }
72   }
73 
mikeRepeat(String string, int count)74   private static String mikeRepeat(String string, int count) {
75     final int len = string.length();
76     char[] strCopy = new char[len * Integer.highestOneBit(count)];
77     string.getChars(0, len, strCopy, 0);
78 
79     char[] array = new char[len * count];
80 
81     int strCopyLen = len;
82     int pos = 0;
83     while (count != 0) {
84       if ((count & 1) != 0) {
85         System.arraycopy(strCopy, 0, array, pos, strCopyLen);
86         pos += strCopyLen;
87       }
88       count >>= 1;
89       if (count != 0) {
90         System.arraycopy(strCopy, 0, strCopy, strCopyLen, strCopyLen);
91         strCopyLen <<= 1;
92       }
93     }
94     return new String(array);
95   }
96 
97   @Benchmark
martinRepeat(int reps)98   void martinRepeat(int reps) {
99     for (int i = 0; i < reps; i++) {
100       String x = martinRepeat(originalString, count);
101       if (x.length() != (originalString.length() * count)) {
102         throw new RuntimeException("Wrong length: " + x);
103       }
104     }
105   }
106 
martinRepeat(String string, int count)107   private static String martinRepeat(String string, int count) {
108     final int len = string.length();
109     final int size = len * count;
110     final char[] array = new char[size];
111     string.getChars(0, len, array, 0);
112     int n;
113     for (n = len; n < size - n; n <<= 1) {
114       System.arraycopy(array, 0, array, n, n);
115     }
116     System.arraycopy(array, 0, array, n, size - n);
117     return new String(array);
118   }
119 }
120