Skip to content

Commit

Permalink
improved performance BitString, minor tweaks for AdnlAddress and tests
Browse files Browse the repository at this point in the history
  • Loading branch information
h6x0r committed Aug 16, 2024
1 parent 74337f7 commit c8b9a97
Show file tree
Hide file tree
Showing 6 changed files with 336 additions and 80 deletions.
121 changes: 80 additions & 41 deletions bitstring/src/main/java/org/ton/java/bitstring/BitString.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
package org.ton.java.bitstring;

import org.apache.commons.lang3.StringUtils;
import org.ton.java.address.Address;
import org.ton.java.utils.Utils;

Expand Down Expand Up @@ -200,22 +199,15 @@ public void writeUint(BigInteger number, int bitLength) {
throw new Error("bitLength is too small for number, got number=" + number + ", bitLength=" + bitLength);
}

byte[] s = number.toString(2).getBytes(StandardCharsets.UTF_8);

if (s.length != bitLength) {
s = repeatZerosAndMerge(bitLength - s.length, s);
}
boolean[] bits = new boolean[bitLength];

for (int i = 0; i < bitLength; i++) {
writeBit(s[i] == (byte) '1');
bits[bitLength - 1 - i] = number.testBit(i);
}
}

private byte[] repeatZerosAndMerge(int count, byte[] s) {
byte[] a = new byte[count + s.length];
Arrays.fill(a, 0, count, (byte) '0');
System.arraycopy(s, 0, a, count, s.length);
return a;
for (boolean bit : bits) {
writeBit(bit);
}
}

/**
Expand Down Expand Up @@ -248,8 +240,7 @@ public void writeInt(BigInteger number, int bitLength) {
} else {
if (number.signum() == -1) {
writeBit(true);
BigInteger b = BigInteger.valueOf(2);
BigInteger nb = b.pow(bitLength - 1);
BigInteger nb = BigInteger.ONE.shiftLeft(bitLength - 1);
writeUint(nb.add(number), bitLength - 1);
} else {
writeBit(false);
Expand Down Expand Up @@ -359,8 +350,9 @@ public void writeAddress(Address address) {
* @param anotherBitString BitString
*/
public void writeBitString(BitString anotherBitString) {
for (Boolean b : anotherBitString.array) {
writeBit(anotherBitString.readBit());
Deque<Boolean> bits = anotherBitString.array;
for (boolean bit : bits) {
writeBit(bit);
}
}

Expand Down Expand Up @@ -402,10 +394,13 @@ public BitString readBits(int n) {
* @return BitString with length of read bits from original Bitstring
*/
public BitString readBits() {
BitString result = new BitString(array.size());
for (int i = 0; i < array.size(); i++) {
int sz = array.size();
BitString result = new BitString(sz);

for (int i = 0; i < sz; i++) {
result.writeBit(readBit());
}

return result;
}

Expand All @@ -421,14 +416,32 @@ public BigInteger preReadUint(int bitLength) {
}

BitString cloned = clone();
StringBuilder s = new StringBuilder();
int bytesNeeded = (bitLength + 7) / 8;
byte[] bytes = new byte[bytesNeeded];

int bitIndex = 0;
int byteIndex = 0;

for (int i = 0; i < bitLength; i++) {
Boolean b = cloned.readBit();
s.append(b ? 1 : 0);
Boolean bit = cloned.readBit();
if (bit) {
bytes[byteIndex] |= (byte) (1 << (7 - bitIndex));
}

bitIndex++;
if (bitIndex == 8) {
bitIndex = 0;
byteIndex++;
}
}

return new BigInteger(s.toString(), 2);
BigInteger bigInteger = new BigInteger(1, bytes);
int excessBits = bytesNeeded * 8 - bitLength;
if (excessBits > 0) {
bigInteger = bigInteger.shiftRight(excessBits);
}

return bigInteger;
}

/**
Expand All @@ -442,13 +455,33 @@ public BigInteger readUint(int bitLength) {
throw new Error("Incorrect bitLength");
}

StringBuilder s = new StringBuilder();
int bytesNeeded = (bitLength + 7) / 8;
byte[] bytes = new byte[bytesNeeded];

int bitIndex = 0;
int byteIndex = 0;

for (int i = 0; i < bitLength; i++) {
Boolean b = readBit();
s.append(b ? 1 : 0);
Boolean bit = readBit();
if (bit) {
bytes[byteIndex] |= (byte) (1 << (7 - bitIndex));
}

bitIndex++;
if (bitIndex == 8) {
bitIndex = 0;
byteIndex++;
}
}

BigInteger bigInteger = new BigInteger(1, bytes);

int excessBits = bytesNeeded * 8 - bitLength;
if (excessBits > 0) {
bigInteger = bigInteger.shiftRight(excessBits);
}

return new BigInteger(s.toString(), 2);
return bigInteger;
}

/**
Expand All @@ -464,14 +497,13 @@ public BigInteger readInt(int bitLength) {

Boolean sign = readBit();
if (bitLength == 1) {
return sign ? new BigInteger("-1") : BigInteger.ZERO;
return sign != null && sign ? BigInteger.valueOf(-1) : BigInteger.ZERO;
}

BigInteger number = readUint(bitLength - 1);
if (sign) {
BigInteger b = BigInteger.valueOf(2);
BigInteger nb = b.pow(bitLength - 1);
number = number.subtract(nb);
BigInteger maxValue = BigInteger.ONE.shiftLeft(bitLength - 1);
number = number.subtract(maxValue);
}

return number;
Expand Down Expand Up @@ -515,12 +547,12 @@ public Address readAddress() {
readBits(2);
return null;
}
readBits(2);
readBits(1);
readBits(3);

int workchain = readInt(8).intValue();
BigInteger hashPart = readUint(256);
String address = String.format("%d:%064x", workchain, hashPart);

String address = workchain + ":" + String.format("%64s", hashPart.toString(16)).replace(' ', '0');
return Address.of(address);
}

Expand Down Expand Up @@ -550,11 +582,15 @@ public String toString() {
*/
public String toBitString() {
BitString cloned = clone();
StringBuilder s = new StringBuilder();
for (Boolean b : cloned.array) {
s.append(b ? '1' : '0');
Deque<Boolean> deque = cloned.array;
char[] chars = new char[deque.size()];

int i = 0;
for (Boolean b : deque) {
chars[i++] = b ? '1' : '0';
}
return s.toString();

return new String(chars);
}

public int getLength() {
Expand All @@ -565,11 +601,14 @@ public int getLength() {
* @return BitString from current position to writeCursor
*/
public String getBitString() {
StringBuilder s = new StringBuilder();
char[] chars = new char[array.size()];

int i = 0;
for (Boolean b : array) {
s.append(b ? '1' : '0');
chars[i++] = b ? '1' : '0';
}
return s.toString();

return new String(chars);
}

public int[] toUnsignedByteArray() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,141 @@
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import java.math.BigInteger;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;

@Slf4j
@RunWith(JUnit4.class)
public class TestBitStringPerformance {

private static final int SIZE = 1_000_000;

@Test
public void testBitStringPerformance1() {
// todo
public void testWriteBitStringPerformance() {
BitString bitString = new BitString(SIZE);
long startTime = System.nanoTime();

for (int i = 0; i < SIZE; i++) {
bitString.writeBit(i % 2 == 0);
}

long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("Write BitString performance: " + duration / 1_000_000 + " ms");

assertTrue("Test should complete in less than 300 ms", duration < 300_000_000);
}

@Test
public void testReadBitStringPerformance() {
BitString bitString = new BitString(SIZE);
for (int i = 0; i < SIZE; i++) {
bitString.writeBit(i % 2 == 0);
}

long startTime = System.nanoTime();

for (int i = 0; i < SIZE; i++) {
bitString.readBit();
}

long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("Read BitString performance: " + duration / 1_000_000 + " ms");

assertTrue("Test should complete in less than 300 ms", duration < 300_000_000);
}

@Test
public void testWriteUintPerformance() {
BitString bitString = new BitString(SIZE);
long startTime = System.nanoTime();

for (int i = 0; i < SIZE; i++) {
bitString.writeUint(i, 32);
}

long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("Write Uint performance: " + duration / 1_000_000 + " ms");

assertTrue("Test should complete in less than 300 ms", duration < 300_000_000);
}

@Test
public void testReadUintPerformance() {
BitString bitString = new BitString(SIZE);
for (int i = 0; i < SIZE; i++) {
bitString.writeUint(i, 64);
}

long startTime = System.nanoTime();

for (int i = 0; i < SIZE; i++) {
bitString.readUint(64);
}

long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("Read Uint performance: " + duration / 1_000_000 + " ms");

assertTrue("Test should complete in less than 300 ms", duration < 300_000_000);
}

@Test
public void testWriteBytesPerformance() {
byte[] data = new byte[SIZE];
new java.util.Random().nextBytes(data);
BitString bitString = new BitString(SIZE);
long startTime = System.nanoTime();

bitString.writeBytes(data);

long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("Write Bytes performance: " + duration / 1_000_000 + " ms");

assertTrue("Test should complete in less than 300 ms", duration < 300_000_000);
}

@Test
public void testReadBytesPerformance() {
byte[] data = new byte[SIZE];
new java.util.Random().nextBytes(data);
BitString bitString = new BitString(SIZE);
bitString.writeBytes(data);

long startTime = System.nanoTime();

bitString.readBytes(SIZE * 8);

long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("Read Bytes performance: " + duration / 1_000_000 + " ms");

assertTrue("Test should complete in less than 300 ms", duration < 300_000_000);
}

@Test
public void testWriteUint() {
BitString bitString = new BitString(SIZE);

BigInteger number = new BigInteger("12345678901234567890");
int bitLength = SIZE;

long startTime = System.nanoTime();
bitString.writeUint(number, bitLength);

BigInteger result = bitString.readUint(bitLength);

long endTime = System.nanoTime();
long duration = endTime - startTime;
System.out.println("Read Bytes performance: " + duration / 1_000_000 + " ms");
assertTrue("Test should complete in less than 300 ms", duration < 300_000_000);

assertEquals(number, result);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -74,16 +74,14 @@ public ExtMessageInfo deploy(Cell deployMessageBody) {

public Message prepareDeployMsg(Cell deployMessageBody) {

Cell body = deployMessageBody;

return Message.builder()
.info(ExternalMessageInfo.builder()
.dstAddr(getAddressIntStd())
.build())
.init(getStateInit())
.body(CellBuilder.beginCell()
.storeBytes(Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), body.hash()))
.storeCell(body)
.storeBytes(Utils.signData(keyPair.getPublicKey(), keyPair.getSecretKey(), deployMessageBody.hash()))
.storeCell(deployMessageBody)
.endCell())
.build();
}
Expand Down
Loading

0 comments on commit c8b9a97

Please sign in to comment.