1 /*
2 * Copyright 2024 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License, version 2.0 (the
5 * "License"); you may not use this file except in compliance with the License. You may obtain a
6 * copy of the License at:
7 *
8 * https://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software distributed under the License
11 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12 * or implied. See the License for the specific language governing permissions and limitations under
13 * the License.
14 */
15 package io.netty.util.internal;
16
17
18 /**
19 * Utility class for SWAR (SIMD within a register) operations.
20 */
21 public final class SWARUtil {
22
23 /**
24 * Compiles given byte into a long pattern suitable for SWAR operations.
25 */
26 public static long compilePattern(byte byteToFind) {
27 return (byteToFind & 0xFFL) * 0x101010101010101L;
28 }
29
30 /**
31 * Applies a compiled pattern to given word.
32 * Returns a word where each byte that matches the pattern has the highest bit set.
33 *
34 * @param word the word to apply the pattern to
35 * @param pattern the pattern to apply
36 * @return a word where each byte that matches the pattern has the highest bit set
37 */
38 public static long applyPattern(final long word, final long pattern) {
39 long input = word ^ pattern;
40 long tmp = (input & 0x7F7F7F7F7F7F7F7FL) + 0x7F7F7F7F7F7F7F7FL;
41 return ~(tmp | input | 0x7F7F7F7F7F7F7F7FL);
42 }
43
44 /**
45 * Returns the index of the first occurrence of byte that specificied in the pattern.
46 * If no pattern is found, returns 8.
47 *
48 * @param word the return value of {@link #applyPattern(long, long)}
49 * @param isBigEndian if true, if given word is big endian
50 * if false, if given word is little endian
51 * @return the index of the first occurrence of the specified pattern in the specified word.
52 * If no pattern is found, returns 8.
53 */
54 public static int getIndex(final long word, final boolean isBigEndian) {
55 final int zeros = isBigEndian? Long.numberOfLeadingZeros(word) : Long.numberOfTrailingZeros(word);
56 return zeros >>> 3;
57 }
58
59 /**
60 * Returns a word where each ASCII uppercase byte has the highest bit set.
61 */
62 private static long applyUpperCasePattern(final long word) {
63 // Inspired by https://github.com/facebook/folly/blob/add4049dd6c2371eac05b92b6fd120fd6dd74df5/folly/String.cpp
64 long rotated = word & 0x7F7F7F7F7F7F7F7FL;
65 rotated += 0x2525252525252525L;
66 rotated &= 0x7F7F7F7F7F7F7F7FL;
67 rotated += 0x1A1A1A1A1A1A1A1AL;
68 rotated &= ~word;
69 rotated &= 0x8080808080808080L;
70 return rotated;
71 }
72
73 /**
74 * Returns a word where each ASCII uppercase byte has the highest bit set.
75 */
76 private static int applyUpperCasePattern(final int word) {
77 int rotated = word & 0x7F7F7F7F;
78 rotated += 0x25252525;
79 rotated &= 0x7F7F7F7F;
80 rotated += 0x1A1A1A1A;
81 rotated &= ~word;
82 rotated &= 0x80808080;
83 return rotated;
84 }
85
86 /**
87 * Returns a word where each ASCII lowercase byte has the highest bit set.
88 */
89 private static long applyLowerCasePattern(final long word) {
90 long rotated = word & 0x7F7F7F7F7F7F7F7FL;
91 rotated += 0x0505050505050505L;
92 rotated &= 0x7F7F7F7F7F7F7F7FL;
93 rotated += 0x1A1A1A1A1A1A1A1AL;
94 rotated &= ~word;
95 rotated &= 0x8080808080808080L;
96 return rotated;
97 }
98
99 /**
100 * Returns a word where each lowercase ASCII byte has the highest bit set.
101 */
102 private static int applyLowerCasePattern(final int word) {
103 int rotated = word & 0x7F7F7F7F;
104 rotated += 0x05050505;
105 rotated &= 0x7F7F7F7F;
106 rotated += 0x1A1A1A1A;
107 rotated &= ~word;
108 rotated &= 0x80808080;
109 return rotated;
110 }
111
112 /**
113 * Returns true if the given word contains at least one ASCII uppercase byte.
114 */
115 public static boolean containsUpperCase(final long word) {
116 return applyUpperCasePattern(word) != 0;
117 }
118
119 /**
120 * Returns true if the given word contains at least one ASCII uppercase byte.
121 */
122 public static boolean containsUpperCase(final int word) {
123 return applyUpperCasePattern(word) != 0;
124 }
125
126 /**
127 * Returns true if the given word contains at least one ASCII lowercase byte.
128 */
129 public static boolean containsLowerCase(final long word) {
130 return applyLowerCasePattern(word) != 0;
131 }
132
133 /**
134 * Returns true if the given word contains at least one ASCII lowercase byte.
135 */
136 public static boolean containsLowerCase(final int word) {
137 return applyLowerCasePattern(word) != 0;
138 }
139
140 /**
141 * Returns a word with all bytes converted to lowercase ASCII.
142 */
143 public static long toLowerCase(final long word) {
144 final long mask = applyUpperCasePattern(word) >>> 2;
145 return word | mask;
146 }
147
148 /**
149 * Returns a word with all bytes converted to lowercase ASCII.
150 */
151 public static int toLowerCase(final int word) {
152 final int mask = applyUpperCasePattern(word) >>> 2;
153 return word | mask;
154 }
155
156 /**
157 * Returns a word with all bytes converted to uppercase ASCII.
158 */
159 public static long toUpperCase(final long word) {
160 final long mask = applyLowerCasePattern(word) >>> 2;
161 return word & ~mask;
162 }
163
164 /**
165 * Returns a word with all bytes converted to uppercase ASCII.
166 */
167 public static int toUpperCase(final int word) {
168 final int mask = applyLowerCasePattern(word) >>> 2;
169 return word & ~mask;
170 }
171
172 private SWARUtil() {
173 // Utility
174 }
175
176 }