@Override public void putNormalizedKey(Integer iValue, MemorySegment target, int offset, int numBytes) { int value = iValue.intValue() - Integer.MIN_VALUE; // see IntValue for an explanation of the logic if (numBytes == 4) { // default case, full normalized key target.putIntBigEndian(offset, value); } else if (numBytes <= 0) { } else if (numBytes < 4) { for (int i = 0; numBytes > 0; numBytes--, i++) { target.put(offset + i, (byte) (value >>> ((3-i)<<3))); } } else { target.putLongBigEndian(offset, value); for (int i = 4; i < numBytes; i++) { target.put(offset + i, (byte) 0); } } }
long l1 = this.getLongBigEndian(offset1); long l2 = seg2.getLongBigEndian(offset2); int b1 = this.get(offset1) & 0xff; int b2 = seg2.get(offset2) & 0xff; int cmp = b1 - b2; if (cmp != 0) {
/** * Writes the given long value (64bit, 8 bytes) to the given position in little endian * byte order. This method's speed depends on the system's native byte order, and it * is possibly slower than {@link #putLong(int, long)}. For most cases (such as * transient storage in memory or serialization for I/O and network), * it suffices to know that the byte order in which the value is written is the same as the * one in which it is read, and {@link #putLong(int, long)} is the preferable choice. * * @param index The position at which the value will be written. * @param value The long value to be written. * * @throws IndexOutOfBoundsException Thrown, if the index is negative, or larger then the segment * size minus 8. */ public final void putLongLittleEndian(int index, long value) { if (LITTLE_ENDIAN) { putLong(index, value); } else { putLong(index, Long.reverseBytes(value)); } }
@Override public void copyNormalizedKey(MemorySegment target, int offset, int len) { // see IntValue for an explanation of the logic if (len == 8) { // default case, full normalized key target.putLongBigEndian(offset, value - Long.MIN_VALUE); } else if (len <= 0) { } else if (len < 8) { long value = this.value - Long.MIN_VALUE; for (int i = 0; len > 0; len--, i++) { target.put(offset + i, (byte) (value >>> ((7-i)<<3))); } } else { target.putLongBigEndian(offset, value - Long.MIN_VALUE); for (int i = 8; i < len; i++) { target.put(offset + i, (byte) 0); } } }
@Override public void copyNormalizedKey(MemorySegment target, int offset, int len) { // take out value and add the integer min value. This gets an offset // representation when interpreted as an unsigned integer (as is the case // with normalized keys). write this value as big endian to ensure the // most significant byte comes first. if (len == 4) { target.putIntBigEndian(offset, value - Integer.MIN_VALUE); } else if (len <= 0) { } else if (len < 4) { int value = this.value - Integer.MIN_VALUE; for (int i = 0; len > 0; len--, i++) { target.put(offset + i, (byte) ((value >>> ((3-i)<<3)) & 0xff)); } } else { target.putIntBigEndian(offset, value - Integer.MIN_VALUE); for (int i = 4; i < len; i++) { target.put(offset + i, (byte) 0); } } }
private void testOpsOnFreedSegment(MemorySegment segment) throws Exception { segment.free(); assertTrue(segment.isFreed()); segment.get(0); fail("Should fail with an exception"); segment.get(-1); fail("Should fail with an exception"); segment.get(1); fail("Should fail with an exception"); segment.get(segment.size()); fail("Should fail with an exception"); segment.get(-segment.size()); fail("Should fail with an exception"); segment.get(Integer.MAX_VALUE); fail("Should fail with an exception"); segment.get(Integer.MIN_VALUE); fail("Should fail with an exception"); segment.put(0, (byte) 0); fail("Should fail with an exception"); segment.put(-1, (byte) 0); fail("Should fail with an exception");
segment.putLongLittleEndian(pos, val); long r = segment.getLongBigEndian(pos); assertEquals(val, Long.reverseBytes(r)); segment.putLongBigEndian(pos, val); r = segment.getLongLittleEndian(pos); assertEquals(val, Long.reverseBytes(r)); segment.putIntLittleEndian(pos, val); int r = segment.getIntBigEndian(pos); assertEquals(val, Integer.reverseBytes(r)); segment.putIntBigEndian(pos, val); r = segment.getIntLittleEndian(pos); assertEquals(val, Integer.reverseBytes(r)); segment.putShortLittleEndian(pos, val); short r = segment.getShortBigEndian(pos); assertEquals(val, Short.reverseBytes(r)); segment.putShortBigEndian(pos, val); r = segment.getShortLittleEndian(pos); assertEquals(val, Short.reverseBytes(r)); segment.putCharLittleEndian(pos, val); char r = segment.getCharBigEndian(pos); assertEquals(val, Character.reverseBytes(r)); segment.putCharBigEndian(pos, val);
private void testByteBufferPut(boolean directBuffer) { byte[] bytes = new byte[pageSize]; random.nextBytes(bytes); ByteBuffer source = directBuffer ? ByteBuffer.allocateDirect(pageSize) : ByteBuffer.allocate(pageSize); source.put(bytes); source.clear(); MemorySegment seg = createSegment(3 * pageSize); int offset = 2 * pageSize; // transfer the segment in chunks into the byte buffer int pos = 0; while (pos < pageSize) { int len = random.nextInt(pageSize / 10); len = Math.min(len, pageSize - pos); seg.put(offset + pos, source, len); pos += len; } // verify that we read the same bytes byte[] result = new byte[pageSize]; seg.get(offset, result); assertArrayEquals(bytes, result); }
private void testSwap(MemorySegment seg1, MemorySegment seg2, Random random, int smallerSize) { assertEquals(pageSize, seg1.size()); assertEquals(smallerSize, seg2.size()); final byte[] bytes1 = new byte[pageSize]; final byte[] bytes2 = new byte[smallerSize]; Arrays.fill(bytes2, (byte) 1); seg1.put(0, bytes1); seg2.put(0, bytes2); // wap the second half of the first segment with the second segment int pos = 0; while (pos < smallerSize) { int len = random.nextInt(pageSize / 40); len = Math.min(len, smallerSize - pos); seg1.swapBytes(new byte[len], seg2, pos + smallerSize, pos, len); pos += len; } // the second segment should now be all zeros, the first segment should have one in its second half for (int i = 0; i < smallerSize; i++) { assertEquals((byte) 0, seg1.get(i)); assertEquals((byte) 0, seg2.get(i)); assertEquals((byte) 1, seg1.get(i + smallerSize)); } }
segment.putLong(-1, 0L); fail("IndexOutOfBoundsException expected"); segment.putLong(pageSize, 0L); fail("IndexOutOfBoundsException expected"); segment.putLong(pageSize - 7, 0L); fail("IndexOutOfBoundsException expected"); segment.putLong(Integer.MIN_VALUE, 0L); fail("IndexOutOfBoundsException expected"); segment.putLong(Integer.MAX_VALUE, 0L); fail("IndexOutOfBoundsException expected"); segment.putLong(Integer.MAX_VALUE - 7, 0L); fail("IndexOutOfBoundsException expected"); segment.getLong(-1); fail("IndexOutOfBoundsException expected"); segment.getLong(pageSize); fail("IndexOutOfBoundsException expected"); segment.getLong(pageSize - 7); fail("IndexOutOfBoundsException expected"); segment.getLong(Integer.MIN_VALUE); fail("IndexOutOfBoundsException expected");
@Test public void testSwapBytes() { final int halfPageSize = pageSize / 2; final byte[] bytes1 = new byte[pageSize]; final byte[] bytes2 = new byte[halfPageSize]; Arrays.fill(bytes2, (byte) 1); MemorySegment seg1 = createSegment(pageSize); MemorySegment seg2 = createSegment(halfPageSize); seg1.put(0, bytes1); seg2.put(0, bytes2); // wap the second half of the first segment with the second segment int pos = 0; while (pos < halfPageSize) { int len = random.nextInt(pageSize / 40); len = Math.min(len, halfPageSize - pos); seg1.swapBytes(new byte[len], seg2, pos + halfPageSize, pos, len); pos += len; } // the second segment should now be all zeros, the first segment should have one in its second half for (int i = 0; i < halfPageSize; i++) { assertEquals((byte) 0, seg1.get(i)); assertEquals((byte) 0, seg2.get(i)); assertEquals((byte) 1, seg1.get(i + halfPageSize)); } }
segment.put(0, (byte) 0); fail("IndexOutOfBoundsException expected"); segment.get(0); fail("IndexOutOfBoundsException expected"); segment.putBoolean(0, true); fail("IndexOutOfBoundsException expected"); segment.getBoolean(0); fail("IndexOutOfBoundsException expected");
private void writeSegment(MemorySegment segment, int writePosition, boolean lastSegment) throws IOException { segment.putShort(0, HEADER_MAGIC_NUMBER); segment.putShort(HEADER_FLAGS_OFFSET, lastSegment ? FLAG_LAST_BLOCK : 0); segment.putInt(HEAD_BLOCK_LENGTH_OFFSET, writePosition); this.writer.writeBlock(segment); this.bytesBeforeSegment += writePosition - HEADER_LENGTH; } }
@Override public void putNormalizedKey(T record, MemorySegment target, int offset, int numBytes) { if (numBytes > 0) { // write a null byte with padding if (record == null) { target.putBoolean(offset, false); // write padding for (int j = 0; j < numBytes - 1; j++) { target.put(offset + 1 + j, (byte) 0); } } // write a non-null byte with key else { target.putBoolean(offset, true); // write key wrappedComparator.putNormalizedKey(record, target, offset + 1, numBytes - 1); } } }
/** * Reads a short integer value (16 bit, 2 bytes) from the given position, in big-endian byte order. * This method's speed depends on the system's native byte order, and it * is possibly slower than {@link #getShort(int)}. For most cases (such as * transient storage in memory or serialization for I/O and network), * it suffices to know that the byte order in which the value is written is the same as the * one in which it is read, and {@link #getShort(int)} is the preferable choice. * * @param index The position from which the value will be read. * @return The short value at the given position. * * @throws IndexOutOfBoundsException Thrown, if the index is negative, or larger then the segment size minus 2. */ public final short getShortBigEndian(int index) { if (LITTLE_ENDIAN) { return Short.reverseBytes(getShort(index)); } else { return getShort(index); } }
ByteBuffer buf1 = seg.wrap(13, 47); assertEquals(13, buf1.position()); assertEquals(60, buf1.limit()); assertEquals(47, buf1.remaining()); ByteBuffer buf2 = seg.wrap(500, 267); assertEquals(500, buf2.position()); assertEquals(767, buf2.limit()); assertEquals(267, buf2.remaining()); ByteBuffer buf3 = seg.wrap(0, 1024); assertEquals(0, buf3.position()); assertEquals(1024, buf3.limit()); assertEquals(651797651, seg.getIntLittleEndian(112)); assertEquals(992288337, seg.getIntBigEndian(187)); seg.wrap(-1, 20); fail("should throw an exception"); seg.wrap(10, -20); fail("should throw an exception"); seg.wrap(10, 1024); fail("should throw an exception"); seg.free();
@Test public void testCheckAgainstOverflowUnderflowOnRelease() { MemorySegment seg = createSegment(512); seg.free(); seg.get(0); fail("Expecting an IllegalStateException"); seg.get(Integer.MAX_VALUE); fail("Expecting an IllegalStateException"); seg.get(Integer.MIN_VALUE); fail("Expecting an IllegalStateException"); seg.getLong(0); fail("Expecting an IllegalStateException"); seg.getLong(Integer.MAX_VALUE); fail("Expecting an IllegalStateException"); seg.getLong(Integer.MIN_VALUE); fail("Expecting an IllegalStateException");
/** * Reads a single-precision floating point value (32bit, 4 bytes) from the given position, in the system's * native byte order. This method offers the best speed for float reading and should be used * unless a specific byte order is required. In most cases, it suffices to know that the * byte order in which the value is written is the same as the one in which it is read * (such as transient storage in memory, or serialization for I/O and network), making this * method the preferable choice. * * @param index The position from which the value will be read. * @return The float value at the given position. * * @throws IndexOutOfBoundsException Thrown, if the index is negative, or larger then the segment * size minus 4. */ public final float getFloat(int index) { return Float.intBitsToFloat(getInt(index)); }
@Test public void testSizeAndFreeing() { // a segment without an owner has a null owner final int segmentSize = 651; MemorySegment seg = createSegment(segmentSize); assertEquals(segmentSize, seg.size()); assertFalse(seg.isFreed()); seg.free(); assertTrue(seg.isFreed()); assertEquals(segmentSize, seg.size()); }