- All Known Subinterfaces:
AddressLayout
,GroupLayout
,PaddingLayout
,SequenceLayout
,StructLayout
,UnionLayout
,ValueLayout
,ValueLayout.OfBoolean
,ValueLayout.OfByte
,ValueLayout.OfChar
,ValueLayout.OfDouble
,ValueLayout.OfFloat
,ValueLayout.OfInt
,ValueLayout.OfLong
,ValueLayout.OfShort
There are two leaves in the layout hierarchy, value layouts,
which are used to represent values of given size and kind and
padding layouts which are used, as the name suggests, to
represent a portion of a memory segment whose contents should be ignored, and which
are primarily present for alignment reasons. Some common value layout constants, such
as ValueLayout.JAVA_INT
and ValueLayout.JAVA_FLOAT_UNALIGNED
are
defined in the ValueLayout
class. A special kind of value layout, namely an
address layout, is used to model values that denote the
address of a region of memory.
More complex layouts can be derived from simpler ones: a sequence layout denotes a homogeneous repetition of zero or more occurrences of an element layout; a group layout denotes a heterogeneous aggregation of zero or more member layouts. Group layouts come in two flavors: struct layouts, where member layouts are laid out one after the other, and union layouts where member layouts are laid out at the same starting offset.
Layouts can be optionally associated with a name. A layout name can be referred to when constructing layout paths.
Consider the following struct declaration in C:
typedef struct {
char kind;
int value;
} TaggedValues[5];
SequenceLayout TAGGED_VALUES = MemoryLayout.sequenceLayout(5,
MemoryLayout.structLayout(
ValueLayout.JAVA_BYTE.withName("kind"),
MemoryLayout.paddingLayout(3),
ValueLayout.JAVA_INT.withName("value")
)
).withName("TaggedValues");
Characteristics of memory layouts
All layouts have a size (expressed in bytes), which is defined as follows:- The size of a value layout is determined by the ValueLayout.carrier()
associated with the value layout. That is, the constant
ValueLayout.JAVA_INT
has carrierint
, and size of 4 bytes; - The size of an address layout is platform-dependent. That is, the constant
ValueLayout.ADDRESS
has a size of 8 bytes on a 64-bit platform; - The size of a padding layout is always provided explicitly, on construction;
- The size of a sequence layout whose element layout is E and element count is L, is the size of E, multiplied by L;
- The size of a struct layout with member layouts M1, M2, ... Mn whose sizes are S1, S2, ... Sn, respectively, is S1 + S2 + ... + Sn;
- The size of a union layout U with member layouts M1, M2, ... Mn whose sizes are S1, S2, ... Sn, respectively, is max(S1, S2, ... Sn).
Furthermore, all layouts have a natural alignment (expressed in bytes) which is defined as follows:
- The natural alignment of a padding layout is 1;
- The natural alignment of a value layout whose size is N is N;
- The natural alignment of a sequence layout whose element layout is E is the alignment of E;
- The natural alignment of a group layout with member layouts M1, M2, ... Mn whose alignments are A1, A2, ... An, respectively, is max(A1, A2 ... An).
withByteAlignment(long)
), which can be useful to describe
layouts with weaker or stronger alignment constraints.
Layout paths
A layout path is used to unambiguously select a layout that is nested in some other layout. Layout paths are typically expressed as a sequence of one or more path elements. (A more formal definition of layout paths is provided below).Layout paths can be used to:
- obtain offsets of arbitrarily nested layouts;
- obtain a var handle that can be used to access the value corresponding to the selected layout;
- select an arbitrarily nested layout.
For instance, given the taggedValues
sequence layout constructed above, we can
obtain the offset, in bytes, of the member layout named value
in the
first sequence element, as follows:
long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0),
PathElement.groupElement("value")); // yields 4
value
, as follows:
MemoryLayout value = TAGGED_VALUES.select(PathElement.sequenceElement(),
PathElement.groupElement("value"));
Open path elements
Some layout path elements, said open path elements, can select multiple layouts at once. For instance, the open path elementsMemoryLayout.PathElement.sequenceElement()
, MemoryLayout.PathElement.sequenceElement(long, long)
select an unspecified element in a sequence layout. A var handle derived from a
layout path containing one or more open path element features additional coordinates
of type long
, which can be used by clients to bind the open elements
in the path:
VarHandle valueHandle = TAGGED_VALUES.varHandle(PathElement.sequenceElement(),
PathElement.groupElement("value"));
MemorySegment taggedValues = ...
// reads the "value" field of the third struct in the array (taggedValues[2].value)
int val = (int) valueHandle.get(taggedValues,
0L, // base offset
2L); // sequence index
Open path elements also affect the creation of
offset-computing method handles. Each
open path element becomes an additional long
parameter in the obtained method
handle. This parameter can be used to specify the index of the sequence element whose
offset is to be computed:
MethodHandle offsetHandle = TAGGED_VALUES.byteOffsetHandle(PathElement.sequenceElement(),
PathElement.groupElement("kind"));
long offset1 = (long) offsetHandle.invokeExact(0L, 1L); // 0 + (1 * 8) = 8
long offset2 = (long) offsetHandle.invokeExact(0L, 2L); // 0 + (2 * 8) = 16
Dereference path elements
A special kind of path element, called dereference path element, allows var handles obtained from memory layouts to follow pointers. Consider the following layout:StructLayout RECTANGLE = MemoryLayout.structLayout(
ValueLayout.ADDRESS.withTargetLayout(
MemoryLayout.sequenceLayout(4,
MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
).withName("point")
)
).withName("points")
);
points
, an address layout whose
target layout is a sequence layout of four
struct layouts. Each struct layout describes a two-dimensional point, and is defined
as a pair or ValueLayout.JAVA_INT
coordinates, with names x
and
y
, respectively.
With dereference path elements, we can obtain a var handle that accesses the y
coordinate of one of the
point in the rectangle, as follows:
VarHandle rectPointYs = RECTANGLE.varHandle(
PathElement.groupElement("points"),
PathElement.dereferenceElement(),
PathElement.sequenceElement(),
PathElement.groupElement("y")
);
MemorySegment rect = ...
// dereferences the third point struct in the "points" array, and reads its "y" coordinate (rect.points[2]->y)
int rect_y_2 = (int) rectPointYs.get(rect,
0L, // base offset
2L); // sequence index
Layout path well-formedness
A layout path is applied to a layoutC_0
, also called the
initial layout. Each path element in a layout path can be thought of as a
function that updates the current layout C_i-1
to some other layout
C_i
. That is, for each path element E1, E2, ... En
, in a layout path
P
, we compute C_i = f_i(C_i-1)
, where f_i
is the selection
function associated with the path element under consideration, denoted as E_i
.
The final layout C_i
is also called the selected layout.
A layout path P
is considered well-formed for an initial layout C_0
if all its path elements E1, E2, ... En
are well-formed for their
corresponding input layouts C_0, C_1, ... C_n-1
. A path element E
is
considered well-formed for a layout L
if any of the following is true:
L
is a sequence layout andE
is a sequence path element (one ofMemoryLayout.PathElement.sequenceElement(long)
,MemoryLayout.PathElement.sequenceElement(long, long)
orMemoryLayout.PathElement.sequenceElement()
). Moreover, ifE
contains one or more sequence indices, such indices have to be compatible with the sequence layout's element count;L
is a group layout andE
is a group path element (one ofMemoryLayout.PathElement.groupElement(String)
orMemoryLayout.PathElement.groupElement(long)
). Moreover, the group path element must refer to a valid member layout inL
, either by name, or index;L
is an address layout andE
is a dereference path element. Moreover,L
must define some target layout.
P
that is not well-formed for an initial
layout C_0
will result in an IllegalArgumentException
.
Access mode restrictions
A var handle returned byvarHandle(PathElement...)
or
ValueLayout.varHandle()
features certain access characteristics, which are
derived from the selected layout L
:
- A carrier type
T
, derived fromL.carrier()
- An alignment constraint
A
, derived fromL.byteAlignment()
- An access size
S
, derived fromL.byteSize()
A
is compatible with the access size S
, that is
if A >= S
. An aligned var handle is guaranteed to support the following
access modes:
- read write access modes for all
T
. On 32-bit platforms, access modesget
andset
forlong
,double
andMemorySegment
are supported but might lead to word tearing, as described in Section 17.7. of The Java Language Specification. - atomic update access modes for
int
,long
,float
,double
andMemorySegment
. (Future major platform releases of the JDK may support additional types for certain currently unsupported access modes.) - numeric atomic update access modes for
int
,long
andMemorySegment
. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.) - bitwise atomic update access modes for
int
,long
andMemorySegment
. (Future major platform releases of the JDK may support additional numeric types for certain currently unsupported access modes.)
T
is float
, double
or MemorySegment
then atomic
update access modes compare values using their bitwise representation
(see Float.floatToRawIntBits(float)
, Double.doubleToRawLongBits(double)
and MemorySegment.address()
, respectively).
Alternatively, a var handle is unaligned if its alignment constraint A
is incompatible with the access size S
, that is, if A < S
. An
unaligned var handle only supports the get
and set
access modes. All
other access modes will result in UnsupportedOperationException
being thrown.
Moreover, while supported, access modes get
and set
might lead to
word tearing.
Working with variable-length arrays
We have seen how sequence layouts are used to describe the contents of an array whose size is known statically. There are cases, however, where the array size is only known dynamically. We call such arrays variable-length arrays. There are two common kinds of variable-length arrays:- a toplevel variable-length array whose size depends on the value of some unrelated variable, or parameter;
- an variable-length array nested in a struct, whose size depends on the value of some other field in the enclosing struct.
Toplevel variable-length arrays
Consider the following struct declaration in C:typedef struct {
int x;
int y;
} Point;
x
and
y
respectively). Now consider the following snippet of C code:
int size = ...
Point *points = (Point*)malloc(sizeof(Point) * size);
for (int i = 0 ; i < size ; i++) {
... points[i].x ...
}
points
). Crucially, the size of
the array is dynamically bound to the value of the size
variable. Inside
the loop, the x
coordinate of all the points in the array is accessed.
To model this code in Java, let's start by defining a layout for the Point
struct, as follows:
StructLayout POINT = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
);
VarHandle POINT_ARR_X = POINT.arrayElementVarHandle(PathElement.groupElement("x"));
int size = ...
MemorySegment points = ...
for (int i = 0 ; i < size ; i++) {
... POINT_ARR_X.get(segment, 0L, (long)i) ...
}
x
of subsequent point in the array is accessed using the
POINT_ARR_X
var handle, which is obtained using the
arrayElementVarHandle(PathElement...)
method. This var handle features two
long
coordinates: the first is a base offset (set to 0L
), while the
second is a logical index that can be used to stride over all the elements of the
point array.
The base offset coordinate allows clients to express complex access operations, by
injecting additional offset computation into the var handle (we will see an example
of that below). In cases where the base offset is constant (as in the previous
example) clients can, if desired, drop the base offset parameter and make the access
expression simpler. This is achieved using the
MethodHandles.insertCoordinates(VarHandle, int, Object...)
var handle adapter.
Nested variable-length arrays
Consider the following struct declaration in C:typedef struct {
int size;
Point points[];
} Polygon;
points
array is left unspecified in the C declaration, using a
Flexible Array Member (a feature standardized in C99).
Again, clients can perform structured access to elements in the nested variable-length
array using the arrayElementVarHandle(PathElement...)
method, as demonstrated
below:
StructLayout POLYGON = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("size"),
MemoryLayout.sequenceLayout(0, POINT).withName("points")
);
VarHandle POLYGON_SIZE = POLYGON.varHandle(0, PathElement.groupElement("size"));
long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points"));
POLYGON
layout contains a sequence layout of size zero. The
element layout of the sequence layout is the POINT
layout, shown previously.
The polygon layout is used to obtain a var handle that provides access to the polygon
size, as well as an offset (POINTS_OFFSET
) to the start of the variable-length
points
array.
The x
coordinates of all the points in a polygon can then be accessed as
follows:
MemorySegment polygon = ...
int size = POLYGON_SIZE.get(polygon, 0L);
for (int i = 0 ; i < size ; i++) {
... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ...
}
POLYGON_SIZE
var handle.
Then, in a loop, we read the x
coordinates of all the points in the polygon.
This is done by providing a custom offset (namely, POINTS_OFFSET
) to the
offset coordinate of the POINT_ARR_X
var handle. As before, the loop
induction variable i
is passed as the index of the POINT_ARR_X
var handle, to stride over all the elements of the variable-length array.- Implementation Requirements:
- Implementations of this interface are immutable, thread-safe and value-based.
- Sealed Class Hierarchy Graph:
- Since:
- 22
-
Nested Class Summary
-
Method Summary
Modifier and TypeMethodDescriptionarrayElementVarHandle
(MemoryLayout.PathElement... elements) Creates a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path, where the accessed elements have this layout, and where the initial layout in the path is this layout.long
Returns the alignment constraint associated with this layout, expressed in bytes.long
byteOffset
(MemoryLayout.PathElement... elements) Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout.byteOffsetHandle
(MemoryLayout.PathElement... elements) Creates a method handle that computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout.long
byteSize()
Returns the layout size, in bytes.boolean
Compares the specified object with this layout for equality.int
hashCode()
Returns the hash code value for this layout.name()
Returns the name (if any) associated with this layout.static PaddingLayout
paddingLayout
(long byteSize) Creates a padding layout with the given byte size.long
scale
(long offset, long index) Returnsoffset + (byteSize() * index)
.Returns a method handle that can be used to invokescale(long, long)
on this layout.select
(MemoryLayout.PathElement... elements) Returns the layout selected from the provided path, where the initial layout in the path is this layout.static SequenceLayout
sequenceLayout
(long elementCount, MemoryLayout elementLayout) Creates a sequence layout with the given element layout and element count.sliceHandle
(MemoryLayout.PathElement... elements) Creates a method handle which, given a memory segment, returns a slice corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout.static StructLayout
structLayout
(MemoryLayout... elements) Creates a struct layout with the given member layouts.toString()
Returns the string representation of this layout.static UnionLayout
unionLayout
(MemoryLayout... elements) Creates a union layout with the given member layouts.varHandle
(MemoryLayout.PathElement... elements) Creates a var handle that accesses a memory segment at the offset selected by the given layout path, where the initial layout in the path is this layout.withByteAlignment
(long byteAlignment) Returns a memory layout with the same characteristics as this layout, but with the given alignment constraint (in bytes).Returns a memory layout with the same characteristics as this layout, but with the given name.Returns a memory layout with the same characteristics as this layout, but with no name.
-
Method Details
-
byteSize
long byteSize()Returns the layout size, in bytes.- Returns:
- the layout size, in bytes
-
name
-
withName
Returns a memory layout with the same characteristics as this layout, but with the given name.- Parameters:
name
- the layout name- Returns:
- a memory layout with the same characteristics as this layout, but with the given name
- See Also:
-
withoutName
MemoryLayout withoutName()Returns a memory layout with the same characteristics as this layout, but with no name.- API Note:
- This can be useful to compare two layouts that have different names, but are otherwise equal.
- Returns:
- a memory layout with the same characteristics as this layout, but with no name
- See Also:
-
byteAlignment
long byteAlignment()Returns the alignment constraint associated with this layout, expressed in bytes.Layout alignment defines a power of two
A
which is the byte-wise alignment of the layout, whereA
is the number of bytes that must be aligned for any pointer that correctly points to this layout. Thus:A=1
means unaligned (in the usual sense), which is common in packets.A=8
means word aligned (on LP64),A=4
int aligned,A=2
short aligned, etc.A=64
is the most strict alignment required by the x86/SV ABI (for AVX-512 data).
withByteAlignment(long)
), then this method returns the natural alignment constraint (in bytes) associated with this layout.- Returns:
- the alignment constraint associated with this layout, expressed in bytes
-
withByteAlignment
Returns a memory layout with the same characteristics as this layout, but with the given alignment constraint (in bytes).- Parameters:
byteAlignment
- the layout alignment constraint, expressed in bytes- Returns:
- a memory layout with the same characteristics as this layout, but with the given alignment constraint (in bytes)
- Throws:
IllegalArgumentException
- ifbyteAlignment
is not a power of two
-
scale
long scale(long offset, long index) Returnsoffset + (byteSize() * index)
.- Parameters:
offset
- the base offsetindex
- the index to be scaled by the byte size of this layout- Returns:
offset + (byteSize() * index)
- Throws:
IllegalArgumentException
- ifoffset
orindex
is negativeArithmeticException
- if either the addition or multiplication overflows
-
scaleHandle
MethodHandle scaleHandle()Returns a method handle that can be used to invokescale(long, long)
on this layout.- Returns:
- a method handle that can be used to invoke
scale(long, long)
on this layout
-
byteOffset
Computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout.- Parameters:
elements
- the layout path elements- Returns:
- The offset, in bytes, of the layout selected by the layout path in
elements
- Throws:
IllegalArgumentException
- if the layout path is not well-formed for this layoutIllegalArgumentException
- if the layout path contains one or more open path elementsIllegalArgumentException
- if the layout path contains one or more dereference path elements
-
byteOffsetHandle
Creates a method handle that computes the offset, in bytes, of the layout selected by the given layout path, where the initial layout in the path is this layout.The returned method handle has the following characteristics:
- its return type is
long
; - it has one leading
long
parameter representing the base offset; - it has as zero or more trailing parameters of type
long
, one for each open path element in the provided layout path. The order of these parameters corresponds to the order in which the open path elements occur in the provided layout path.
The final offset returned by the method handle is computed as follows:
whereoffset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
b
represents the base offset provided as a dynamiclong
argument,x_1
,x_2
, ...x_n
represent indices into sequences provided as dynamiclong
arguments, whereass_1
,s_2
, ...s_n
are static stride constants derived from the size of the element layout of a sequence, andc_1
,c_2
, ...c_m
are other static offset constants (such as field offsets) which are derived from the layout path.- API Note:
- The returned method handle can be used to compute a layout offset,
similarly to
byteOffset(PathElement...)
, but more flexibly, as some indices can be specified when invoking the method handle. - Parameters:
elements
- the layout path elements- Returns:
- a method handle that computes the offset, in bytes, of the layout selected by the given layout path
- Throws:
IllegalArgumentException
- if the layout path is not well-formed for this layoutIllegalArgumentException
- if the layout path contains one or more dereference path elements
- its return type is
-
varHandle
Creates a var handle that accesses a memory segment at the offset selected by the given layout path, where the initial layout in the path is this layout.The returned var handle has the following characteristics:
- its type is derived from the carrier of the selected value layout;
- it has a leading parameter of type
MemorySegment
representing the accessed segment - a following
long
parameter, corresponding to the base offset, denoted asB
; - it has zero or more trailing access coordinates of type
long
, one for each open path element in the provided layout path, denoted asI1, I2, ... In
, respectively. The order of these access coordinates corresponds to the order in which the open path elements occur in the provided layout path.
If the provided layout path
P
contains no dereference elements, then the offsetO
of the access operation is computed as follows:O = this.offsetHandle(P).invokeExact(B, I1, I2, ... In);
Accessing a memory segment using the var handle returned by this method is subject to the following checks:
- The physical address of the accessed memory segment must be
aligned according to the
alignment constraint of the root layout
(this layout), or an
IllegalArgumentException
is thrown. Note that the alignment constraint of the root layout can be more strict (but not less) than the alignment constraint of the selected value layout. - The offset of the access operation (computed as above) must fall inside
the spatial bounds of the accessed memory segment, or an
IndexOutOfBoundsException
is thrown. This is the case whenO + A <= S
, whereO
is the accessed offset (computed as above),A
is the size of the selected layout andS
is the size of the accessed memory segment. - The accessed memory segment must be
accessible
from the thread performing the access operation, or aWrongThreadException
is thrown. - For write operations, the accessed memory segment must not be
read only
, or anIllegalArgumentException
is thrown. - The scope associated with the accessed
segment must be alive, or an
IllegalStateException
is thrown.
If the selected layout is an address layout, calling
VarHandle.get(Object...)
on the returned var handle will return a new memory segment. The segment is associated with the global scope. Moreover, the size of the segment depends on whether the address layout has a target layout. More specifically:- If the address layout has a target layout
T
, then the size of the returned segment isT.byteSize()
; - Otherwise, the address layout has no target layout and the size of the returned segment is zero.
VarHandle.set(Object...)
can throwIllegalArgumentException
if the memory segment representing the address to be written is not a native memory segment.If the provided layout path has size
m
and contains a dereference path element in positionk
(wherek <= m
) then two layout pathsP
andP'
are derived, where P contains all the path elements from 0 tok - 1
andP'
contains all the path elements fromk + 1
tom
(if any). Then, the returned var handle is computed as follows:VarHandle baseHandle = this.varHandle(P); MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get(); VarHandle targetHandle = target.varHandle(P); targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0 targetHandle = MethodHandles.collectCoordinates(targetHandle, 0, baseHandle.toMethodHandle(VarHandle.AccessMode.GET));
As an example, consider the memory layout expressed by a
GroupLayout
instance constructed as follows:GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout( MemoryLayout.paddingLayout(4), ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value") );
value
, we can construct a var handle as follows:VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int
- API Note:
- The resulting var handle features certain access mode restrictions, which are common to all var handles derived from memory layouts.
- Parameters:
elements
- the layout path elements- Returns:
- a var handle that accesses a memory segment at the offset selected by the given layout path
- Throws:
IllegalArgumentException
- if the layout path is not well-formed for this layoutIllegalArgumentException
- if the layout selected by the provided path is not a value layout
-
arrayElementVarHandle
Creates a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path, where the accessed elements have this layout, and where the initial layout in the path is this layout.The returned var handle has the following characteristics:
- its type is derived from the carrier of the selected value layout;
- it has a leading parameter of type
MemorySegment
representing the accessed segment - a following
long
parameter, corresponding to the base offset, denoted asB
; - a following
long
parameter, corresponding to the array index, denoted asI0
. The array index is used to scale the accessed offset by this layout size; - it has zero or more trailing access coordinates of type
long
, one for each open path element in the provided layout path, denoted asI1, I2, ... In
, respectively. The order of these access coordinates corresponds to the order in which the open path elements occur in the provided layout path.
If the provided layout path
P
contains no dereference elements, then the offsetO
of the access operation is computed as follows:O = this.offsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
More formally, this method can be obtained from the
varHandle(PathElement...)
, as follows:MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())
- API Note:
- As the leading index coordinate
I0
is not bound by any sequence layout, it can assume any non-negative value - provided that the resulting offset computation does not overflow, or that the computed offset does not fall outside the spatial bound of the accessed memory segment. As such, the var handles returned from this method can be especially useful when accessing variable-length arrays. - Parameters:
elements
- the layout path elements- Returns:
- a var handle that accesses adjacent elements in a memory segment at offsets selected by the given layout path
- Throws:
IllegalArgumentException
- if the layout path is not well-formed for this layoutIllegalArgumentException
- if the layout selected by the provided path is not a value layout
-
sliceHandle
Creates a method handle which, given a memory segment, returns a slice corresponding to the layout selected by the given layout path, where the initial layout in the path is this layout.The returned method handle has the following characteristics:
- its return type is
MemorySegment
; - it has a leading parameter of type
MemorySegment
corresponding to the memory segment to be sliced - a following
long
parameter, corresponding to the base offset - it has as zero or more trailing parameters of type
long
, one for each open path element in the provided layout path. The order of these parameters corresponds to the order in which the open path elements occur in the provided layout path.
The offset
O
of the returned segment is computed as if by a call to a byte offset handle constructed using the given path elements.Computing a slice of a memory segment using the method handle returned by this method is subject to the following checks:
- The physical address of the accessed memory segment must be
aligned according to the
alignment constraint of the root layout
(this layout), or an
IllegalArgumentException
will be issued. Note that the alignment constraint of the root layout can be more strict (but not less) than the alignment constraint of the selected layout. - The start offset of the slicing operation (computed as above) must fall
inside the spatial bounds of the accessed memory segment, or an
IndexOutOfBoundsException
is thrown. This is the case whenO + A <= S
, whereO
is the start offset of the slicing operation (computed as above),A
is the size of the selected layout andS
is the size of the accessed memory segment.
- API Note:
- The returned method handle can be used to obtain a memory segment slice,
similarly to
MemorySegment.asSlice(long, long)
, but more flexibly, as some indices can be specified when invoking the method handle. - Parameters:
elements
- the layout path elements- Returns:
- a method handle that is used to slice a memory segment at the offset selected by the given layout path
- Throws:
IllegalArgumentException
- if the layout path is not well-formed for this layoutIllegalArgumentException
- if the layout path contains one or more dereference path elements
- its return type is
-
select
Returns the layout selected from the provided path, where the initial layout in the path is this layout.- Parameters:
elements
- the layout path elements- Returns:
- the layout selected by the layout path in
elements
- Throws:
IllegalArgumentException
- if the layout path is not well-formed for this layoutIllegalArgumentException
- if the layout path contains one or more dereference path elementsIllegalArgumentException
- if the layout path contains one or more path elements that select one or more sequence element indices, such asMemoryLayout.PathElement.sequenceElement(long)
andMemoryLayout.PathElement.sequenceElement(long, long)
)
-
equals
Compares the specified object with this layout for equality. Returnstrue
if and only if the specified object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of the same kind, have the same size, name and alignment constraint. Furthermore, depending on the layout kind, additional conditions must be satisfied:- two value layouts are considered equal if they have the same order, and carrier. Additionally, two address layouts are considered equal if they also have the same target layout;
- two sequence layouts are considered equal if they have the same element
count (see
SequenceLayout.elementCount()
), and if their element layouts (seeSequenceLayout.elementLayout()
) are also equal; - two group layouts are considered equal if they are of the same type
(see
StructLayout
,UnionLayout
) and if their member layouts (seeGroupLayout.memberLayouts()
) are also equal.
-
hashCode
-
toString
-
paddingLayout
Creates a padding layout with the given byte size. The alignment constraint of the returned layout is 1. As such, regardless of its size, in the absence of an explicit alignment constraint, a padding layout does not affect the natural alignment of the group or sequence layout it is nested into.- Parameters:
byteSize
- the padding size (expressed in bytes)- Returns:
- the new selector layout
- Throws:
IllegalArgumentException
- ifbyteSize <= 0
-
sequenceLayout
Creates a sequence layout with the given element layout and element count.- Parameters:
elementCount
- the sequence element countelementLayout
- the sequence element layout- Returns:
- the new sequence layout with the given element layout and size
- Throws:
IllegalArgumentException
- ifelementCount
is negativeIllegalArgumentException
- ifelementLayout.byteSize() * elementCount
overflowsIllegalArgumentException
- ifelementLayout.byteSize() % elementLayout.byteAlignment() != 0
-
structLayout
Creates a struct layout with the given member layouts.- API Note:
- This factory does not automatically align element layouts, by inserting
additional padding layout elements. As such,
the following struct layout creation will fail with an exception:
structLayout(JAVA_SHORT, JAVA_INT);
structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);
structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
- Parameters:
elements
- The member layouts of the struct layout- Returns:
- a struct layout with the given member layouts
- Throws:
IllegalArgumentException
- if the sum of the byte sizes of the member layouts overflowsIllegalArgumentException
- if a member layout inelements
occurs at an offset (relative to the start of the struct layout) which is not compatible with its alignment constraint
-
unionLayout
Creates a union layout with the given member layouts.- Parameters:
elements
- The member layouts of the union layout- Returns:
- a union layout with the given member layouts
-