View Javadoc
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 }