diff --git a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java index a7a3dcb8db7..181d4449949 100644 --- a/src/java.base/share/classes/java/lang/foreign/MemorySegment.java +++ b/src/java.base/share/classes/java/lang/foreign/MemorySegment.java @@ -1707,6 +1707,104 @@ default void set(ValueLayout.OfAddress layout, long offset, MemorySegment value) ((ValueLayouts.OfAddressImpl) layout).accessHandle().set(this, offset, value); } + /** + * Reads a byte from this segment at the given index, scaled by the given layout size. + * + * @param layout the layout of the region of memory to be read. + * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation + * will occur can be expressed as {@code (index * layout.byteSize())}. + * @return a byte value read from this segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}. + * @throws WrongThreadException if this method is called from a thread other than the thread owning + * the {@linkplain #session() session} associated with this segment. + * @throws IllegalArgumentException if the access operation is + * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout, + * or if the layout alignment is greater than its size. + * @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the + * memory segment. + */ + @ForceInline + default byte getAtIndex(ValueLayout.OfByte layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (byte) ((ValueLayouts.OfByteImpl) layout).accessHandle().get(this, index * layout.byteSize()); + } + + /** + * Writes a byte into this segment at the given index, scaled by the given layout size. + * + * @param layout the layout of the region of memory to be written. + * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation + * will occur can be expressed as {@code (index * layout.byteSize())}. + * @param value the byte value to be written. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}. + * @throws WrongThreadException if this method is called from a thread other than the thread owning + * the {@linkplain #session() session} associated with this segment. + * @throws IllegalArgumentException if the access operation is + * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout, + * or if the layout alignment is greater than its size. + * @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the + * memory segment. + * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. + */ + @ForceInline + default void setAtIndex(ValueLayout.OfByte layout, long index, byte value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + ((ValueLayouts.OfByteImpl) layout).accessHandle().set(this, index * layout.byteSize(), value); + } + + /** + * Reads a boolean from this segment at the given index, scaled by the given layout size. + * + * @param layout the layout of the region of memory to be read. + * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation + * will occur can be expressed as {@code (index * layout.byteSize())}. + * @return a boolean value read from this segment. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}. + * @throws WrongThreadException if this method is called from a thread other than the thread owning + * the {@linkplain #session() session} associated with this segment. + * @throws IllegalArgumentException if the access operation is + * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout, + * or if the layout alignment is greater than its size. + * @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the + * memory segment. + */ + @ForceInline + default boolean getAtIndex(ValueLayout.OfBoolean layout, long index) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + return (boolean) ((ValueLayouts.OfBooleanImpl) layout).accessHandle().get(this, index * layout.byteSize()); + } + + /** + * Writes a boolean into this segment at the given index, scaled by the given layout size. + * + * @param layout the layout of the region of memory to be written. + * @param index a logical index. The offset in bytes (relative to this segment address) at which the access operation + * will occur can be expressed as {@code (index * layout.byteSize())}. + * @param value the boolean value to be written. + * @throws IllegalStateException if the {@linkplain #session() session} associated with this segment is not + * {@linkplain MemorySession#isAlive() alive}. + * @throws WrongThreadException if this method is called from a thread other than the thread owning + * the {@linkplain #session() session} associated with this segment. + * @throws IllegalArgumentException if the access operation is + * <a href="MemorySegment.html#segment-alignment">incompatible with the alignment constraint</a> in the provided layout, + * or if the layout alignment is greater than its size. + * @throws IndexOutOfBoundsException when the access operation falls outside the <em>spatial bounds</em> of the + * memory segment. + * @throws UnsupportedOperationException if this segment is {@linkplain #isReadOnly() read-only}. + */ + @ForceInline + default void setAtIndex(ValueLayout.OfBoolean layout, long index, boolean value) { + Utils.checkElementAlignment(layout, "Layout alignment greater than its size"); + // note: we know size is a small value (as it comes from ValueLayout::byteSize()) + ((ValueLayouts.OfBooleanImpl) layout).accessHandle().set(this, index * layout.byteSize(), value); + } + /** * Reads a char from this segment at the given index, scaled by the given layout size. * diff --git a/test/jdk/java/foreign/TestMemoryAccessInstance.java b/test/jdk/java/foreign/TestMemoryAccessInstance.java index 756af73c470..600179f324e 100644 --- a/test/jdk/java/foreign/TestMemoryAccessInstance.java +++ b/test/jdk/java/foreign/TestMemoryAccessInstance.java @@ -184,6 +184,14 @@ static Object[][] segmentAccessors() { }) }, + {"byte/index", Accessor.ofSegment(ValueLayout.JAVA_BYTE, (byte) 42, + MemorySegment::getAtIndex, MemorySegment::setAtIndex, + (bb, pos) -> bb.order(NE).get(pos), (bb, pos, v) -> bb.order(NE).put(pos, v)) + }, + {"bool/index", Accessor.ofSegment(ValueLayout.JAVA_BOOLEAN, false, + MemorySegment::getAtIndex, MemorySegment::setAtIndex, + (bb, pos) -> bb.order(NE).get(pos) != 0, (bb, pos, v) -> bb.order(NE).put(pos, v ? (byte) 1 : (byte) 0)) + }, {"char/index", Accessor.ofSegment(ValueLayout.JAVA_CHAR, (char) 42, MemorySegment::getAtIndex, MemorySegment::setAtIndex, (bb, pos) -> bb.order(NE).getChar(pos * 2), (bb, pos, v) -> bb.order(NE).putChar(pos * 2, v))