Extraction of lengths from ByteBuffer (Java / Scala)

I am BigInt numbers that consist of two Long each of the following ways:

 val msb = -1L // some arbitrary long value, can be anything between Long.Min/MaxValue val lsb = 25L // a second arbitrary long value val bb = ByteBuffer .allocate(17) .put(0.toByte) // 1 byte .putLong(msb) // 8 bytes .putLong(lsb) // 8 bytes val number = BigInt(bb.array) // in this case: 340282366920938463444927863358058659865 

The reason I add another 0- Byte to the front is to ensure that the result is a positive number. Otherwise, the result of BigInt may be negative due to two additions. An algorithm that is called subsequently expects numbers to be greater than or equal to zero.

So far so good.

I'm having trouble reversing this entire process - converting BigInt back to two Long (exactly the two values ​​that were used as input). I can't just do the following:

 val arr = number.toByteArray val bb = ByteBuffer.wrap(arr) val ignore = bb.getByte val msb = bb.getLong val lsb = bb.getLong 

Imagine the number of BigInt is equal, for example. 3. Then .toByteArray will result in an array of size 1, not 16 (or 17), and therefore calls to getLong will BufferUnderflowException .

What is the easiest way to solve this problem? I tried several ways to manually fill the buffer until 16 bytes are available, but since this "filling" should correctly account for the two additions of these two numbers, I was not successful.

+7
java arrays scala bytebuffer
source share
4 answers

Modulo may be useful here:

 .... val number = BigInt(bb.array) // in this case: 340282366920938463444927863358058659865 val modulo = BigInt(2).pow(64) val lsb2 = (number / modulo).toLong //25 val msb2 = (number.mod(modulo)).toLong //-1 
+5
source share

Using the plumbing / extension approach and number as defined in the question,

 val msb, lsb = split(number) // (-1,25) /** split the passed Bigint into a (msb: Long, lsb: Long) tuple */ def split(bi: BigInt) = splitArray(bi.toByteArray.takeRight(16)) // Considers only the last bytes if there are more than 16 /** assumes arrays of size 16 or less */ def splitArray(ba: Array[Byte]): (Long, Long) = ( toLong(ba.take(ba.length - 8)), // Take the msb part: anything before the last 8 bytes (take() seems happy with negative numbers ;)) toLong(ba.takeRight(8)) // Take at most 8 bytes from the lsb part ) /** Convert the passed byte-array to a long. Expect arrays of size 8 and less. */ def toLong(ba: Array[Byte]) = ByteBuffer.wrap(zeroPad(ba)).getLong /** prefix the passed array with 0 bytes. Expect arrays of size 8 and less, returns an array of length 8. */ def zeroPad(ba: Array[Byte]) = Array.fill[Byte](8 - ba.length)(0) ++ ba 

Not as short as the proposal for the module of Peter, the bus costs a little mental gymnastics :)

+2
source share

Instead of ByteBuffer.wrap you can simply allocate sufficiently large ByteBuffer (i.e. 17 bytes in size) and put(byte[]) array of bytes in the correct position (that is, so that it is "aligned" using the lsb buffer) as follows:

 val number = BigInt("340282366920938463444927863358058659865") val arr = number.toByteArray // of length 0-17 val bb = ByteBuffer.allocate(17) bb.position(1 + (16 - arr.length)) bb.put(arr) bb.rewind() val ignore = bb.get val msb = bb.getLong val lsb = bb.getLong 
+1
source share

Your suggested extraction method will work, you just need to use this leading 0-byte for better use.

 val bb = ByteBuffer .allocate(17) .put(1.toByte) // 1 byte (some positive value) .putLong(msb) // 8 bytes .putLong(lsb) // 8 bytes val number = BigInt(bb.array) // never negative, always 17 bytes val bbx = ByteBuffer.wrap(number.toByteArray) bbx.get // throw away bbx.getLong // msb bbx.getLong // lsb 

If for some reason you need number contain only msb and lsb bits, then you can create a mask to help with extraction.

 val maskbb = ByteBuffer .allocate(17) .put(Byte.MinValue) // 1 byte .putLong(0L) // 8 bytes .putLong(0L) // 8 bytes val arr = (BigInt(maskbb.array) + number).toByteArray val bbx = ByteBuffer.wrap(arr) ... // the rest us unchanged 
+1
source share

All Articles