Skip to content

Commit 8899e09

Browse files
committed
Refactor BitUtils for improved memory handling and performance
1 parent d0c1eff commit 8899e09

7 files changed

Lines changed: 171 additions & 87 deletions

File tree

.github/workflows/maven.yml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ jobs:
1212
runs-on: ubuntu-latest
1313
strategy:
1414
matrix:
15-
java: [ 7, 8, 9, 10, 11]
15+
java: [ 8, 11, 17, 21]
1616
steps:
17-
- uses: actions/checkout@v2
17+
- uses: actions/checkout@v4
1818
- name: Set up JDK ${{ matrix.java }}
19-
uses: actions/setup-java@v2
19+
uses: actions/setup-java@v4
2020
with:
21-
distribution: 'zulu'
21+
distribution: 'temurin'
2222
java-version: ${{ matrix.java }}
2323
- name: Build with Maven
2424
run: mvn -B clean package
@@ -27,11 +27,11 @@ jobs:
2727
needs: build
2828
runs-on: ubuntu-latest
2929
steps:
30-
- uses: actions/checkout@v2
31-
- name: Set up JDK 1.8
32-
uses: actions/setup-java@v2
30+
- uses: actions/checkout@v4
31+
- name: Set up JDK 8
32+
uses: actions/setup-java@v4
3333
with:
34-
distribution: 'zulu'
34+
distribution: 'temurin'
3535
java-version: 8
3636
- name: Build with Maven
3737
run: mvn -B clean cobertura:cobertura coveralls:report -DrepoToken=${{ secrets.COVERALLS_TOKEN }}

README.md

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
Bit-lib4j ![Bit-lib4j CI](https://github.com/devnied/Bit-lib4j/workflows/Bit-lib4j%20CI/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/devnied/Bit-lib4j/badge.svg?branch=master)](https://coveralls.io/github/devnied/Bit-lib4j?branch=master) [![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.github.devnied/bit-lib4j/badge.svg?style=flat)](https://maven-badges.herokuapp.com/maven-central/com.github.devnied/bit-lib4j)
1+
Bit-lib4j ![Bit-lib4j CI](https://github.com/devnied/Bit-lib4j/workflows/Bit-lib4j%20CI/badge.svg) [![Coverage Status](https://coveralls.io/repos/github/devnied/Bit-lib4j/badge.svg?branch=master)](https://coveralls.io/github/devnied/Bit-lib4j?branch=master)
22
========
33

44
Bit-Lib4j is an useful library to handle bytes or bits in Java.<br/>
@@ -36,7 +36,7 @@ It is very easy to get started with bit-lib4j:
3636
// Result
3737
bit.getNextIntegerSigned(4); // return -2
3838
```
39-
You can also use ```getNextSignedLong()``` to handle long signed values.
39+
You can also use ```getNextLongSigned()``` to handle long signed values.
4040

4141

4242
## Handle bytes more easily
@@ -67,7 +67,7 @@ You can download this library on [Maven central](http://search.maven.org/#search
6767
If you are not using Maven or some other dependency management tool that can understand Maven repositories, the list below is what you need to run bit-lib4j.
6868

6969
**Runtime Dependencies**
70-
* slf4j-api 1.7.30
70+
* slf4j-api 1.7.36
7171

7272
## Bugs
7373

@@ -78,13 +78,13 @@ Forks and Pull Requests are also welcome.
7878

7979
**Millau Julien**
8080

81-
+ [http://twitter.com/devnied](http://twitter.com/devnied)
81+
+ [http://x.com/devnied](http://x.com/devnied)
8282
+ [http://github.com/devnied](http://github.com/devnied)
8383

8484

8585
## Copyright and license
8686

87-
Copyright 2020 Millau Julien.
87+
Copyright 2026 Millau Julien.
8888

8989
Licensed under the Apache License, Version 2.0 (the "License");
9090
you may not use this work except in compliance with the License.
@@ -97,5 +97,3 @@ distributed under the License is distributed on an "AS IS" BASIS,
9797
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
9898
See the License for the specific language governing permissions and
9999
limitations under the License.
100-
101-
[![Analytics](https://ga-beacon.appspot.com/UA-19411627-5/Bit-lib4j/index)](https://github.com/igrigorik/ga-beacon)

pom.xml

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@
4747

4848
<properties>
4949
<!-- slf4j -->
50-
<slf4j.version>1.7.32</slf4j.version>
50+
<slf4j.version>1.7.36</slf4j.version>
5151
</properties>
5252

5353
<dependencies>
@@ -67,7 +67,7 @@
6767
<dependency>
6868
<groupId>org.apache.logging.log4j</groupId>
6969
<artifactId>log4j-core</artifactId>
70-
<version>2.17.0</version>
70+
<version>2.25.3</version>
7171
<scope>test</scope>
7272
</dependency>
7373

@@ -104,33 +104,33 @@
104104
<plugins>
105105
<plugin>
106106
<artifactId>maven-compiler-plugin</artifactId>
107-
<version>3.8.1</version>
107+
<version>3.15.0</version>
108108
<configuration>
109-
<source>1.6</source>
110-
<target>1.6</target>
109+
<source>1.8</source>
110+
<target>1.8</target>
111111
<encoding>UTF-8</encoding>
112112
</configuration>
113113
</plugin>
114114
<plugin>
115115
<groupId>org.apache.maven.plugins</groupId>
116116
<artifactId>maven-resources-plugin</artifactId>
117-
<version>3.1.0</version>
117+
<version>3.4.0</version>
118118
<configuration>
119119
<encoding>UTF-8</encoding>
120120
</configuration>
121121
</plugin>
122122
<plugin>
123123
<groupId>org.apache.maven.plugins</groupId>
124124
<artifactId>maven-release-plugin</artifactId>
125-
<version>2.5.3</version>
125+
<version>3.3.1</version>
126126
<configuration>
127127
<mavenExecutorId>forked-path</mavenExecutorId>
128128
<localCheckout>true</localCheckout>
129129
</configuration>
130130
</plugin>
131131
<plugin>
132132
<artifactId>maven-source-plugin</artifactId>
133-
<version>3.2.1</version>
133+
<version>3.4.0</version>
134134
<executions>
135135
<execution>
136136
<id>attach-sources</id>

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

Lines changed: 16 additions & 54 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,6 @@
33
import org.slf4j.Logger;
44
import org.slf4j.LoggerFactory;
55

6-
import java.nio.Buffer;
7-
import java.nio.ByteBuffer;
86
import java.nio.charset.Charset;
97
import java.text.ParseException;
108
import java.text.SimpleDateFormat;
@@ -26,10 +24,6 @@ public final class BitUtils {
2624
* Constant for byte size
2725
*/
2826
public static final int BYTE_SIZE = Byte.SIZE;
29-
/**
30-
* Constant for byte size (float)
31-
*/
32-
public static final float BYTE_SIZE_F = Byte.SIZE;
3327
/**
3428
* 255 init value
3529
*/
@@ -66,8 +60,7 @@ public final class BitUtils {
6660
* byte read
6761
*/
6862
public BitUtils(final byte[] pByte) {
69-
byteTab = new byte[pByte.length];
70-
System.arraycopy(pByte, 0, byteTab, 0, pByte.length);
63+
byteTab = Arrays.copyOf(pByte, pByte.length);
7164
size = pByte.length * BYTE_SIZE;
7265
}
7366

@@ -78,7 +71,7 @@ public BitUtils(final byte[] pByte) {
7871
* the size of the tab in bit
7972
*/
8073
public BitUtils(final int pSize) {
81-
byteTab = new byte[(int) Math.ceil(pSize / BYTE_SIZE_F)];
74+
byteTab = new byte[(pSize + BYTE_SIZE - 1) / BYTE_SIZE];
8275
size = pSize;
8376
}
8477

@@ -110,9 +103,7 @@ public int getCurrentBitIndex() {
110103
* @return a byte tab which contain all data
111104
*/
112105
public byte[] getData() {
113-
byte[] ret = new byte[byteTab.length];
114-
System.arraycopy(byteTab, 0, ret, 0, byteTab.length);
115-
return ret;
106+
return Arrays.copyOf(byteTab, byteTab.length);
116107
}
117108

118109
/**
@@ -178,7 +169,7 @@ public byte[] getNextByte(final int pSize) {
178169
* @return a byte array
179170
*/
180171
public byte[] getNextByte(final int pSize, final boolean pShift) {
181-
byte[] tab = new byte[(int) Math.ceil(pSize / BYTE_SIZE_F)];
172+
byte[] tab = new byte[(pSize + BYTE_SIZE - 1) / BYTE_SIZE];
182173

183174
if (currentBitIndex % BYTE_SIZE != 0) {
184175
int index = 0;
@@ -311,36 +302,21 @@ public int getNextIntegerSigned(final int pLength) {
311302
* @return an long
312303
*/
313304
public long getNextLong(final int pLength) {
314-
// allocate Size of Integer
315-
ByteBuffer buffer = ByteBuffer.allocate(BYTE_SIZE * 2);
316-
// final value
317305
long finalValue = 0;
318-
// Incremental value
319-
long currentValue = 0;
320-
// Size to read
306+
long currentValue;
321307
int readSize = pLength;
322-
// length max of the index
323308
int max = currentBitIndex + pLength;
324309
while (currentBitIndex < max) {
325310
int mod = currentBitIndex % BYTE_SIZE;
326-
// apply the mask to the selected byte
327311
currentValue = byteTab[currentBitIndex / BYTE_SIZE] & getMask(mod, readSize) & DEFAULT_VALUE;
328-
// Shift right the read value
329312
int dec = Math.max(BYTE_SIZE - (mod + readSize), 0);
330313
currentValue = (currentValue & DEFAULT_VALUE) >>> dec & DEFAULT_VALUE;
331-
// Shift left the previously read value and add the current value
332314
finalValue = finalValue << Math.min(readSize, BYTE_SIZE) | currentValue;
333-
// calculate read value size
334315
int val = BYTE_SIZE - mod;
335-
// Decrease the size left
336316
readSize = readSize - val;
337317
currentBitIndex = Math.min(currentBitIndex + val, max);
338318
}
339-
buffer.putLong(finalValue);
340-
// reset the current bytebuffer index to 0
341-
((Buffer)buffer).rewind();
342-
// return integer
343-
return buffer.getLong();
319+
return finalValue;
344320
}
345321

346322
/**
@@ -469,21 +445,11 @@ public void setNextByte(final byte[] pValue, final int pLength) {
469445
* if true pad with 0
470446
*/
471447
public void setNextByte(final byte[] pValue, final int pLength, final boolean pPadBefore) {
472-
int totalSize = (int) Math.ceil(pLength / BYTE_SIZE_F);
473-
ByteBuffer buffer = ByteBuffer.allocate(totalSize);
474-
int size = Math.max(totalSize - pValue.length, 0);
475-
if (pPadBefore) {
476-
for (int i = 0; i < size; i++) {
477-
buffer.put((byte) 0);
478-
}
479-
}
480-
buffer.put(pValue, 0, Math.min(totalSize, pValue.length));
481-
if (!pPadBefore) {
482-
for (int i = 0; i < size; i++) {
483-
buffer.put((byte) 0);
484-
}
485-
}
486-
byte[] tab = buffer.array();
448+
int totalSize = (pLength + BYTE_SIZE - 1) / BYTE_SIZE;
449+
byte[] tab = new byte[totalSize];
450+
int padSize = Math.max(totalSize - pValue.length, 0);
451+
int copyLen = Math.min(totalSize, pValue.length);
452+
System.arraycopy(pValue, 0, tab, pPadBefore ? padSize : 0, copyLen);
487453
if (currentBitIndex % BYTE_SIZE != 0) {
488454
int index = 0;
489455
int max = currentBitIndex + pLength;
@@ -587,22 +553,18 @@ public void setNextLong(final long pValue, final int pLength) {
587553
private void setNextValue(final long pValue, final int pLength, final int pMaxSize) {
588554
long value = pValue;
589555
// Set to max value if pValue cannot be stored on pLength bits.
590-
long bitMax = (long) Math.pow(2, Math.min(pLength, pMaxSize));
591-
if (pValue > bitMax) {
556+
long bitMax = 1L << Math.min(pLength, pMaxSize);
557+
if (bitMax > 0 && pValue >= bitMax) {
592558
value = bitMax - 1;
593559
}
594-
// size to wrote
595560
int writeSize = pLength;
596561
while (writeSize > 0) {
597-
// modulo
598562
int mod = currentBitIndex % BYTE_SIZE;
599-
byte ret = 0;
563+
byte ret;
600564
if (mod == 0 && writeSize <= BYTE_SIZE || pLength < BYTE_SIZE - mod) {
601-
// shift left value
602565
ret = (byte) (value << BYTE_SIZE - (writeSize + mod));
603566
} else {
604-
// shift right
605-
long length = Long.toBinaryString(value).length();
567+
int length = value == 0 ? 1 : Long.SIZE - Long.numberOfLeadingZeros(value);
606568
ret = (byte) (value >> writeSize - length - (BYTE_SIZE - length - mod));
607569
}
608570
byteTab[currentBitIndex / BYTE_SIZE] |= ret;
@@ -656,6 +618,6 @@ public void setNextString(final String pValue, final int pLength) {
656618
* indicate if the string is padded before or after
657619
*/
658620
public void setNextString(final String pValue, final int pLength, final boolean pPaddedBefore) {
659-
setNextByte(pValue.getBytes(Charset.defaultCharset()), pLength, pPaddedBefore);
621+
setNextByte(pValue.getBytes(DEFAULT_CHARSET), pLength, pPaddedBefore);
660622
}
661623
}

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

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

3-
import java.math.BigInteger;
4-
53
/**
64
* Class used to manage String/byte/int converter
75
*
@@ -285,11 +283,11 @@ public static byte setBit(final byte pData, final int pBitIndex, final boolean p
285283
public static String toBinary(final byte[] pBytes) {
286284
String ret = null;
287285
if (pBytes != null && pBytes.length > 0) {
288-
BigInteger val = new BigInteger(bytesToStringNoSpace(pBytes), HEXA);
289-
StringBuilder build = new StringBuilder(val.toString(2));
290-
// left pad with 0 to fit byte size
291-
for (int i = build.length(); i < pBytes.length * BitUtils.BYTE_SIZE; i++) {
292-
build.insert(0, 0);
286+
StringBuilder build = new StringBuilder(pBytes.length * BitUtils.BYTE_SIZE);
287+
for (byte b : pBytes) {
288+
for (int i = 7; i >= 0; i--) {
289+
build.append((b >> i) & 1);
290+
}
293291
}
294292
ret = build.toString();
295293
}

0 commit comments

Comments
 (0)