Skip to content

Commit 58daf5d

Browse files
authored
Merge pull request #6 from andrei-cristea/master
refactor: Improve performance for methods "formatByte" and "fromString"
2 parents fa780d6 + 361ed10 commit 58daf5d

File tree

1 file changed

+100
-54
lines changed

1 file changed

+100
-54
lines changed

src/main/java/fr/devnied/bitlib/BytesUtils.java

Lines changed: 100 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
package fr.devnied.bitlib;
22

33
import java.math.BigInteger;
4-
import java.util.Locale;
54

65
/**
76
* Class used to manage String/byte/int converter
8-
*
7+
*
98
* @author Millau Julien
10-
*
9+
*
1110
*/
1211
public final class BytesUtils {
1312

@@ -22,22 +21,45 @@ public final class BytesUtils {
2221
private static final int HEXA = 16;
2322

2423
/**
25-
* No space format
24+
* Byte left mask
2625
*/
27-
private static final String FORMAT_NOSPACE = "%02x";
26+
private static final int LEFT_MASK = 0xF0;
27+
28+
/**
29+
* Byte right mask
30+
*/
31+
private static final int RIGHT_MASK = 0xF;
32+
33+
/**
34+
* Char digit 0 (0x30) :<br>
35+
* <ul>
36+
* <li>char 0 = 0x30 + 0x0
37+
* <li>char 1 = 0x30 + 0x1
38+
* <li>...
39+
* <li>char 9 = 0x30 + 0x9
40+
* </ul>
41+
*/
42+
private static final int CHAR_DIGIT_ZERO = 0x30;
43+
2844
/**
29-
* Space format
45+
* Char digit 7 (0x37) :<br>
46+
* <ul>
47+
* <li>char A = 0x37 + 0xA
48+
* <li>char B = 0x37 + 0xB
49+
* <li>...
50+
* <li>char F = 0x37 + 0xF
51+
* </ul>
3052
*/
31-
private static final String FORMAT_SPACE = "%02x ";
53+
private static final int CHAR_DIGIT_SEVEN = 0x37;
3254

3355
/**
34-
* Default mask
56+
* Char space
3557
*/
36-
private static final int DEFAULT_MASK = 0xFF;
58+
private static final char CHAR_SPACE = (char) 0x20;
3759

3860
/**
3961
* Method used to convert byte array to int
40-
*
62+
*
4163
* @param byteArray
4264
* byte array to convert
4365
* @return int value
@@ -51,7 +73,7 @@ public static int byteArrayToInt(final byte[] byteArray) {
5173

5274
/**
5375
* Method used to convert byte array to int
54-
*
76+
*
5577
* @param byteArray
5678
* byte array to convert
5779
* @param startPos
@@ -79,95 +101,112 @@ public static int byteArrayToInt(final byte[] byteArray, final int startPos, fin
79101

80102
/**
81103
* Method to convert bytes to string with space between bytes
82-
*
104+
*
83105
* @param pBytes
84-
* Bytes to convert
85-
*
106+
* Bytes to convert
107+
*
86108
* @return a string
87109
*/
88110
public static String bytesToString(final byte[] pBytes) {
89-
return formatByte(pBytes, FORMAT_SPACE, false);
111+
return formatByte(pBytes, true, false);
90112
}
91113

92114
/**
93115
* Method to convert bytes to string with space between bytes
94-
*
116+
*
95117
* bytes to convert
118+
*
96119
* @param pBytes
97-
* Bytes to convert
120+
* Bytes to convert
98121
* @param pTruncate
99122
* true to remove 0 left byte value
100123
* @return a string
101124
*/
102125
public static String bytesToString(final byte[] pBytes, final boolean pTruncate) {
103-
return formatByte(pBytes, FORMAT_SPACE, pTruncate);
126+
return formatByte(pBytes, true, pTruncate);
104127
}
105128

106129
/**
107130
* Method to convert byte to string without space between byte
108-
*
131+
*
109132
* @param pByte
110133
* byte to convert
111134
* @return a string
112135
*/
113136
public static String bytesToStringNoSpace(final byte pByte) {
114-
return formatByte(new byte[] { pByte }, FORMAT_NOSPACE, false);
137+
return formatByte(new byte[] { pByte }, false, false);
115138
}
116139

117140
/**
118141
* Method to convert bytes to string without space between bytes
119-
*
142+
*
120143
* @param pBytes
121144
* bytes to convert
122145
* @return a string
123146
*/
124147
public static String bytesToStringNoSpace(final byte[] pBytes) {
125-
return formatByte(pBytes, FORMAT_NOSPACE, false);
148+
return formatByte(pBytes, false, false);
126149
}
127150

128151
/**
129152
* Method to convert bytes to string without space between bytes
130-
*
153+
*
131154
* @param pBytes
132155
* bytes to convert
133156
* @param pTruncate
134157
* true to remove 0 left byte value
135158
* @return a string
136159
*/
137160
public static String bytesToStringNoSpace(final byte[] pBytes, final boolean pTruncate) {
138-
return formatByte(pBytes, FORMAT_NOSPACE, pTruncate);
161+
return formatByte(pBytes, false, pTruncate);
139162
}
140163

141164
/**
142-
* Private method to format byte to hexa string
143-
*
165+
* Private method to format bytes to hexa string
166+
*
144167
* @param pByte
145-
* the byte to format
146-
* @param pFormat
147-
* the format
168+
* the bytes to format
169+
* @param pSpace
170+
* true if add spaces between bytes
148171
* @param pTruncate
149-
* true to remove 0 left byte value
172+
* true to remove 0 left bytes value
150173
* @return a string containing the requested string
151174
*/
152-
private static String formatByte(final byte[] pByte, final String pFormat, final boolean pTruncate) {
153-
StringBuffer sb = new StringBuffer();
175+
private static String formatByte(final byte[] pByte, final boolean pSpace, final boolean pTruncate) {
176+
String result;
154177
if (pByte == null) {
155-
sb.append("");
178+
result = "";
156179
} else {
157-
boolean t = false;
158-
for (byte b : pByte) {
159-
if (b != 0 || !pTruncate || t) {
160-
t = true;
161-
sb.append(String.format(pFormat, b & DEFAULT_MASK));
180+
int i = 0;
181+
if (pTruncate) {
182+
while (i < pByte.length && pByte[i] == 0) {
183+
i++;
184+
}
185+
}
186+
if (i < pByte.length) {
187+
int sizeMultiplier = pSpace ? 3 : 2;
188+
char[] c = new char[(pByte.length - i) * sizeMultiplier];
189+
byte b;
190+
for (int j = 0; i < pByte.length; i++, j++) {
191+
b = (byte) ((pByte[i] & LEFT_MASK) >> 4);
192+
c[j] = (char) (b > 9 ? b + CHAR_DIGIT_SEVEN : b + CHAR_DIGIT_ZERO);
193+
b = (byte) (pByte[i] & RIGHT_MASK);
194+
c[++j] = (char) (b > 9 ? b + CHAR_DIGIT_SEVEN : b + CHAR_DIGIT_ZERO);
195+
if (pSpace) {
196+
c[++j] = CHAR_SPACE;
197+
}
162198
}
199+
result = pSpace ? new String(c, 0, c.length - 1) : new String(c);
200+
} else {
201+
result = "";
163202
}
164203
}
165-
return sb.toString().toUpperCase(Locale.getDefault()).trim();
204+
return result;
166205
}
167206

168207
/**
169208
* Method to get bytes form string
170-
*
209+
*
171210
* @param pData
172211
* String to parse
173212
* @return a table of string
@@ -176,22 +215,28 @@ public static byte[] fromString(final String pData) {
176215
if (pData == null) {
177216
throw new IllegalArgumentException("Argument can't be null");
178217
}
179-
String text = pData.replace(" ", "");
180-
if (text.length() % 2 != 0) {
218+
StringBuilder sb = new StringBuilder(pData);
219+
int j = 0;
220+
for (int i = 0; i < sb.length(); i++) {
221+
if (!Character.isWhitespace(sb.charAt(i))) {
222+
sb.setCharAt(j++, sb.charAt(i));
223+
}
224+
}
225+
sb.delete(j, sb.length());
226+
if (sb.length() % 2 != 0) {
181227
throw new IllegalArgumentException("Hex binary needs to be even-length :" + pData);
182228
}
183-
byte[] commandByte = new byte[Math.round(text.length() / (float) 2.0)];
184-
int j = 0;
185-
for (int i = 0; i < text.length(); i += 2) {
186-
Integer val = Integer.parseInt(text.substring(i, i + 2), HEXA);
187-
commandByte[j++] = val.byteValue();
229+
byte[] result = new byte[sb.length() / 2];
230+
j = 0;
231+
for (int i = 0; i < sb.length(); i += 2) {
232+
result[j++] = (byte) ((Character.digit(sb.charAt(i), 16) << 4) + Character.digit(sb.charAt(i + 1), 16));
188233
}
189-
return commandByte;
234+
return result;
190235
}
191236

192237
/**
193238
* Test if bit at given index of given value is = 1.
194-
*
239+
*
195240
* @param pVal
196241
* value to test
197242
* @param pBitIndex
@@ -200,14 +245,15 @@ public static byte[] fromString(final String pData) {
200245
*/
201246
public static boolean matchBitByBitIndex(final int pVal, final int pBitIndex) {
202247
if (pBitIndex < 0 || pBitIndex > MAX_BIT_INTEGER) {
203-
throw new IllegalArgumentException("parameter 'pBitIndex' must be between 0 and 31. pBitIndex=" + pBitIndex);
248+
throw new IllegalArgumentException(
249+
"parameter 'pBitIndex' must be between 0 and 31. pBitIndex=" + pBitIndex);
204250
}
205251
return (pVal & 1 << pBitIndex) != 0;
206252
}
207253

208254
/**
209255
* Method used to set a bit index to 1 or 0.
210-
*
256+
*
211257
* @param pData
212258
* data to modify
213259
* @param pBitIndex
@@ -231,7 +277,7 @@ public static byte setBit(final byte pData, final int pBitIndex, final boolean p
231277

232278
/**
233279
* Convert byte array to binary String
234-
*
280+
*
235281
* @param pBytes
236282
* byte array to convert
237283
* @return a binary representation of the byte array
@@ -252,14 +298,14 @@ public static String toBinary(final byte[] pBytes) {
252298

253299
/**
254300
* Method used to convert integer to byet array
255-
*
301+
*
256302
* @param value
257303
* the value to convert
258304
* @return a byte array
259305
*/
260306
public static byte[] toByteArray(final int value) {
261307
return new byte[] { //
262-
(byte) (value >> 24), //
308+
(byte) (value >> 24), //
263309
(byte) (value >> 16), //
264310
(byte) (value >> 8), //
265311
(byte) value //

0 commit comments

Comments
 (0)