1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.util;
17
18 import io.netty.util.internal.PlatformDependent;
19 import io.netty.util.internal.SWARUtil;
20
21
22
23
24 final class AsciiStringUtil {
25
26
27
28
29
30
31
32 static AsciiString toLowerCase(final AsciiString string) {
33 final byte[] byteArray = string.array();
34 final int offset = string.arrayOffset();
35 final int length = string.length();
36 if (!containsUpperCase(byteArray, offset, length)) {
37 return string;
38 }
39 final byte[] newByteArray = PlatformDependent.allocateUninitializedArray(length);
40 toLowerCase(byteArray, offset, newByteArray);
41 return new AsciiString(newByteArray, false);
42 }
43
44 private static boolean containsUpperCase(final byte[] byteArray, int offset, final int length) {
45 if (!PlatformDependent.isUnaligned()) {
46 return linearContainsUpperCase(byteArray, offset, length);
47 }
48
49 final int longCount = length >>> 3;
50 for (int i = 0; i < longCount; ++i) {
51 final long word = PlatformDependent.getLong(byteArray, offset);
52 if (SWARUtil.containsUpperCase(word)) {
53 return true;
54 }
55 offset += Long.BYTES;
56 }
57 return unrolledContainsUpperCase(byteArray, offset, length & 7);
58 }
59
60 private static boolean linearContainsUpperCase(final byte[] byteArray, final int offset, final int length) {
61 final int end = offset + length;
62 for (int idx = offset; idx < end; ++idx) {
63 if (isUpperCase(byteArray[idx])) {
64 return true;
65 }
66 }
67 return false;
68 }
69
70 private static boolean unrolledContainsUpperCase(final byte[] byteArray, int offset, final int byteCount) {
71 assert byteCount >= 0 && byteCount < 8;
72 if ((byteCount & Integer.BYTES) != 0) {
73 final int word = PlatformDependent.getInt(byteArray, offset);
74 if (SWARUtil.containsUpperCase(word)) {
75 return true;
76 }
77 offset += Integer.BYTES;
78 }
79 if ((byteCount & Short.BYTES) != 0) {
80 if (isUpperCase(PlatformDependent.getByte(byteArray, offset))) {
81 return true;
82 }
83 if (isUpperCase(PlatformDependent.getByte(byteArray, offset + 1))) {
84 return true;
85 }
86 offset += Short.BYTES;
87 }
88 if ((byteCount & Byte.BYTES) != 0) {
89 return isUpperCase(PlatformDependent.getByte(byteArray, offset));
90 }
91 return false;
92 }
93
94 private static void toLowerCase(final byte[] src, final int srcOffset, final byte[] dst) {
95 if (!PlatformDependent.isUnaligned()) {
96 linearToLowerCase(src, srcOffset, dst);
97 return;
98 }
99
100 final int length = dst.length;
101 final int longCount = length >>> 3;
102 int offset = 0;
103 for (int i = 0; i < longCount; ++i) {
104 final long word = PlatformDependent.getLong(src, srcOffset + offset);
105 PlatformDependent.putLong(dst, offset, SWARUtil.toLowerCase(word));
106 offset += Long.BYTES;
107 }
108 unrolledToLowerCase(src, srcOffset + offset, dst, offset, length & 7);
109 }
110
111 private static void linearToLowerCase(final byte[] src, final int srcOffset, final byte[] dst) {
112 for (int i = 0; i < dst.length; ++i) {
113 dst[i] = toLowerCase(src[srcOffset + i]);
114 }
115 }
116
117 private static void unrolledToLowerCase(final byte[] src, int srcPos,
118 final byte[] dst, int dstOffset, final int byteCount) {
119 assert byteCount >= 0 && byteCount < 8;
120 int offset = 0;
121 if ((byteCount & Integer.BYTES) != 0) {
122 final int word = PlatformDependent.getInt(src, srcPos + offset);
123 PlatformDependent.putInt(dst, dstOffset + offset, SWARUtil.toLowerCase(word));
124 offset += Integer.BYTES;
125 }
126
127 if ((byteCount & Short.BYTES) != 0) {
128 final short word = PlatformDependent.getShort(src, srcPos + offset);
129 final short result = (short) ((toLowerCase((byte) (word >>> 8)) << 8) | toLowerCase((byte) word));
130 PlatformDependent.putShort(dst, dstOffset + offset, result);
131 offset += Short.BYTES;
132 }
133
134
135 if ((byteCount & Byte.BYTES) != 0) {
136 PlatformDependent.putByte(dst, dstOffset + offset,
137 toLowerCase(PlatformDependent.getByte(src, srcPos + offset)));
138 }
139 }
140
141
142
143
144
145
146
147 static AsciiString toUpperCase(final AsciiString string) {
148 final byte[] byteArray = string.array();
149 final int offset = string.arrayOffset();
150 final int length = string.length();
151 if (!containsLowerCase(byteArray, offset, length)) {
152 return string;
153 }
154 final byte[] newByteArray = PlatformDependent.allocateUninitializedArray(length);
155 toUpperCase(byteArray, offset, newByteArray);
156 return new AsciiString(newByteArray, false);
157 }
158
159 private static boolean containsLowerCase(final byte[] byteArray, int offset, final int length) {
160 if (!PlatformDependent.isUnaligned()) {
161 return linearContainsLowerCase(byteArray, offset, length);
162 }
163
164 final int longCount = length >>> 3;
165 for (int i = 0; i < longCount; ++i) {
166 final long word = PlatformDependent.getLong(byteArray, offset);
167 if (SWARUtil.containsLowerCase(word)) {
168 return true;
169 }
170 offset += Long.BYTES;
171 }
172 return unrolledContainsLowerCase(byteArray, offset, length & 7);
173 }
174
175 private static boolean linearContainsLowerCase(final byte[] byteArray, final int offset, final int length) {
176 final int end = offset + length;
177 for (int idx = offset; idx < end; ++idx) {
178 if (isLowerCase(byteArray[idx])) {
179 return true;
180 }
181 }
182 return false;
183 }
184
185 private static boolean unrolledContainsLowerCase(final byte[] byteArray, int offset, final int byteCount) {
186 assert byteCount >= 0 && byteCount < 8;
187 if ((byteCount & Integer.BYTES) != 0) {
188 final int word = PlatformDependent.getInt(byteArray, offset);
189 if (SWARUtil.containsLowerCase(word)) {
190 return true;
191 }
192 offset += Integer.BYTES;
193 }
194 if ((byteCount & Short.BYTES) != 0) {
195 if (isLowerCase(PlatformDependent.getByte(byteArray, offset))) {
196 return true;
197 }
198 if (isLowerCase(PlatformDependent.getByte(byteArray, offset + 1))) {
199 return true;
200 }
201 offset += Short.BYTES;
202 }
203 if ((byteCount & Byte.BYTES) != 0) {
204 return isLowerCase(PlatformDependent.getByte(byteArray, offset));
205 }
206 return false;
207 }
208
209 private static void toUpperCase(final byte[] src, final int srcOffset, final byte[] dst) {
210 if (!PlatformDependent.isUnaligned()) {
211 linearToUpperCase(src, srcOffset, dst);
212 return;
213 }
214
215 final int length = dst.length;
216 final int longCount = length >>> 3;
217 int offset = 0;
218 for (int i = 0; i < longCount; ++i) {
219 final long word = PlatformDependent.getLong(src, srcOffset + offset);
220 PlatformDependent.putLong(dst, offset, SWARUtil.toUpperCase(word));
221 offset += Long.BYTES;
222 }
223 unrolledToUpperCase(src, srcOffset + offset, dst, offset, length & 7);
224 }
225
226 private static void linearToUpperCase(final byte[] src, final int srcOffset, final byte[] dst) {
227 for (int i = 0; i < dst.length; ++i) {
228 dst[i] = toUpperCase(src[srcOffset + i]);
229 }
230 }
231
232 private static void unrolledToUpperCase(final byte[] src, int srcOffset,
233 final byte[] dst, int dstOffset, final int byteCount) {
234 assert byteCount >= 0 && byteCount < 8;
235 int offset = 0;
236 if ((byteCount & Integer.BYTES) != 0) {
237 final int word = PlatformDependent.getInt(src, srcOffset + offset);
238 PlatformDependent.putInt(dst, dstOffset + offset, SWARUtil.toUpperCase(word));
239 offset += Integer.BYTES;
240 }
241 if ((byteCount & Short.BYTES) != 0) {
242 final short word = PlatformDependent.getShort(src, srcOffset + offset);
243 final short result = (short) ((toUpperCase((byte) (word >>> 8)) << 8) | toUpperCase((byte) word));
244 PlatformDependent.putShort(dst, dstOffset + offset, result);
245 offset += Short.BYTES;
246 }
247
248 if ((byteCount & Byte.BYTES) != 0) {
249 PlatformDependent.putByte(dst, dstOffset + offset,
250 toUpperCase(PlatformDependent.getByte(src, srcOffset + offset)));
251 }
252 }
253
254 private static boolean isLowerCase(final byte value) {
255 return value >= 'a' && value <= 'z';
256 }
257
258
259
260
261
262
263
264 static boolean isUpperCase(final byte value) {
265 return value >= 'A' && value <= 'Z';
266 }
267
268
269
270
271
272
273
274 static byte toLowerCase(final byte value) {
275 return isUpperCase(value)? (byte) (value + 32) : value;
276 }
277
278
279
280
281
282
283
284 static byte toUpperCase(final byte value) {
285 return isLowerCase(value)? (byte) (value - 32) : value;
286 }
287
288 private AsciiStringUtil() {
289
290 }
291 }