Last active
July 28, 2021 17:59
-
-
Save nitsanw/4373453 to your computer and use it in GitHub Desktop.
Aligning a byte buffer
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
private static final long addressOffset; | |
static { | |
try { | |
addressOffset = UnsafeAccess.unsafe.objectFieldOffset(Buffer.class.getDeclaredField("address")); | |
} catch (Exception e) { | |
throw new RuntimeException(e); | |
} | |
} | |
public static long getAddress(ByteBuffer buffy) { | |
// steal the value of address field from Buffer, holding the memory address for this ByteBuffer | |
return UnsafeAccess.unsafe.getLong(buffy, addressOffset); | |
} | |
public static ByteBuffer allocateAlignedByteBuffer(int capacity, long align) { | |
// Power of 2 --> single bit, none power of 2 alignments are not allowed. | |
if (Long.bitCount(align) != 1) { | |
throw new IllegalArgumentException("Alignment must be a power of 2"); | |
} | |
// We over allocate by the alignment so we know we can have a large enough aligned | |
// block of memory to use. Also set order to native while we are here. | |
ByteBuffer buffy = ByteBuffer.allocateDirect((int) (capacity + align)); | |
long address = getAddress(buffy); | |
// check if we got lucky and the address is already aligned | |
if ((address & (align - 1)) == 0) { | |
// set the new limit to intended capacity | |
buffy.limit(capacity); | |
// the slice is now an aligned buffer of the required capacity | |
return buffy.slice().order(ByteOrder.nativeOrder()); | |
} else { | |
// we need to shift the start position to an aligned address --> address + (align - (address % align)) | |
// the modulo replacement with the & trick is valid for power of 2 values only | |
int newPosition = (int) (align - (address & (align - 1))); | |
// change the position | |
buffy.position(newPosition); | |
int newLimit = newPosition + capacity; | |
// set the new limit to accomodate offset + intended capacity | |
buffy.limit(newLimit); | |
// the slice is now an aligned buffer of the required capacity | |
return buffy.slice().order(ByteOrder.nativeOrder()); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment