8000 Honor pointer offsets in getByteBuffer views by RicheyWorks · Pull Request #50 · jcuda/jcuda · GitHub
[go: up one dir, main page]

Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 25 additions & 6 deletions JCudaJava/src/main/java/jcuda/Pointer.java
Original file line number Diff line number Diff line change
Expand Up @@ -541,14 +541,17 @@ public Pointer withByteOffset(long byteOffset)
* <br>
* For other pointer types, <code>null</code> is returned.
*
* @param byteOffset The offset in bytes
* The range is relative to this pointer, including any offset added
* with {@link #withByteOffset(long)}.
*
* @param byteOffset The offset in bytes relative to this pointer
* @param byteSize The size of the byte buffer, in bytes
* @return The byte buffer
* @throws IllegalArgumentException If the <code>byteOffset</code> and
* <code>byteSize</code> describe an invalid memory range (for example,
* when the <code>byteOffset</code> is negative)
* @throws ArithmeticException If the <code>byteOffset</code> or
* <code>byteOffset + byteSize</code> overflows an <code>int</code>.
* @throws ArithmeticException If computing the memory range overflows
* a <code>long</code>, or its start or end overflows an <code>int</code>.
*/
public ByteBuffer getByteBuffer(long byteOffset, long byteSize)
{
Expand All @@ -562,8 +565,15 @@ public ByteBuffer getByteBuffer(long byteOffset, long byteSize)
}
ByteBuffer internalByteBuffer = (ByteBuffer)buffer;
ByteBuffer byteBuffer = internalByteBuffer.slice();
byteBuffer.limit(Math.toIntExact(byteOffset + byteSize));
byteBuffer.position(Math.toIntExact(byteOffset));
if (byteOffset < 0 || byteSize < 0)
{
throw new IllegalArgumentException(
"Byte offset and size must be non-negative");
}
long start = Math.addExact(this.byteOffset, byteOffset);
long end = Math.addExact(start, byteSize);
byteBuffer.limit(Math.toIntExact(end));
byteBuffer.position(Math.toIntExact(start));
return byteBuffer.slice().order(ByteOrder.nativeOrder());
}

Expand Down Expand Up @@ -591,7 +601,15 @@ public ByteBuffer getByteBuffer(long byteOffset, long byteSize)
* <br>
* For other pointer types, <code>null</code> is returned.
*
* Any offset added with {@link #withByteOffset(long)} is taken into
* account. The returned buffer covers the remaining memory from this
* pointer to the end of the internally stored buffer's remaining region.
*
* @return The byte buffer
* @throws IllegalArgumentException If this pointer's offset is outside
* the internally stored buffer's remaining region
* @throws ArithmeticException If this pointer's offset overflows an
* <code>int</code>
*/
public ByteBuffer getByteBuffer()
{
Expand All @@ -605,7 +623,8 @@ public ByteBuffer getByteBuffer()
}
ByteBuffer internalByteBuffer = (ByteBuffer)buffer;
ByteBuffer byteBuffer = internalByteBuffer.slice();
return byteBuffer.order(ByteOrder.nativeOrder());
byteBuffer.position(Math.toIntExact(this.byteOffset));
return byteBuffer.slice().order(ByteOrder.nativeOrder());
}


Expand Down
130 changes: 130 additions & 0 deletions JCudaJava/src/test/java/jcuda/test/PointerByteBufferOffsetTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
/*
* JCuda - Java bindings for CUDA
*
* http://www.jcuda.org
*/
package jcuda.test;

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

import java.nio.ByteBuffer;
import java.nio.ByteOrder;

import org.junit.Test;

import jcuda.Pointer;

/** Tests pointer-relative buffer views without loading CUDA. */
public class PointerByteBufferOffsetTest
{
@Test
public void testWholeViewStartsAtPointerOffset()
{
byte[] values = { 0, 1, 2, 3, 4, 5 };
ByteBuffer view = Pointer.to(values).withByteOffset(2).getByteBuffer();
assertEquals(0, view.position());
assertEquals(4, view.remaining());
assertEquals(2, view.get(0));
assertEquals(ByteOrder.nativeOrder(), view.order());
view.put(1, (byte) 42);
assertEquals(42, values[3]);
}

@Test
public void testRangeIsRelativeToPointerOffset()
{
byte[] values = { 0, 1, 2, 3, 4, 5 };
ByteBuffer view = Pointer.to(values).withByteOffset(2).getByteBuffer(1, 2);
assertEquals(0, view.position());
assertEquals(2, view.remaining());
assertEquals(3, view.get(0));
assertEquals(4, view.get(1));
assertEquals(ByteOrder.nativeOrder(), view.order());
}

@Test
public void testComposedPointerOffsets()
{
Pointer pointer = Pointer.to(new byte[] { 0, 1, 2, 3, 4, 5 });
ByteBuffer view = pointer.withByteOffset(1).withByteOffset(2)
.getByteBuffer(1, 1);
assertEquals(4, view.get(0));
}

@Test
public void testDirectBufferViewSharesMemoryAndPreservesState()
{
ByteBuffer source = ByteBuffer.allocateDirect(8);
source.put(3, (byte) 17);
source.position(1);
ByteBuffer slice = source.slice();
slice.limit(5);
slice.mark();
ByteBuffer view = Pointer.to(slice).withByteOffset(2).getByteBuffer();
assertEquals(3, view.remaining());
assertEquals(17, view.get(0));
view.put(0, (byte) 23);
assertEquals(23, source.get(3));
assertEquals(1, source.position());
assertEquals(0, slice.position());
assertEquals(5, slice.limit());
slice.reset();
assertEquals(0, slice.position());
}

@Test
public void testEmptyViewAtEnd()
{
Pointer pointer = Pointer.to(new byte[4]).withByteOffset(4);
assertEquals(0, pointer.getByteBuffer().remaining());
assertEquals(0, pointer.getByteBuffer(0, 0).remaining());
}

@Test(expected = IllegalArgumentException.class)
public void testRangeCannotExtendPastPointerRemainingMemory()
{
Pointer.to(new byte[4]).withByteOffset(2).getByteBuffer(1, 2);
}

@Test(expected = IllegalArgumentException.class)
public void testWholeViewCannotStartBeyondEnd()
{
Pointer.to(new byte[4]).withByteOffset(5).getByteBuffer();
}

@Test(expected = ArithmeticException.class)
public void testPointerOffsetCannotOverflowBufferIndex()
{
Pointer.to(new byte[4]).withByteOffset(Long.MAX_VALUE)
.getByteBuffer(1, 1);
}

@Test
public void testUnsupportedPointersStillReturnNull()
{
assertNull(new Pointer().withByteOffset(2).getByteBuffer());
assertNull(Pointer.to(new float[4]).withByteOffset(2).getByteBuffer(0, 1));
}

@Test(expected = IllegalArgumentException.class)
public void testNegativeRelativeOffsetRemainsInvalid()
{
Pointer.to(new byte[4]).withByteOffset(2).getByteBuffer(-1, 1);
}

@Test(expected = IllegalArgumentException.class)
public void testNegativeSizeRemainsInvalid()
{
Pointer.to(new byte[4]).withByteOffset(2).getByteBuffer(0, -1);
}

@Test
public void testZeroOffsetBehaviorIsUnchanged()
{
Pointer pointer = Pointer.to(new byte[] { 0, 1, 2, 3 });
assertEquals(4, pointer.getByteBuffer().remaining());
assertEquals(1, pointer.getByteBuffer(1, 2).get(0));
assertEquals(2, pointer.getByteBuffer(1, 2).remaining());
}
}
0