- All Superinterfaces:
Constable
- All Known Implementing Classes:
GroupLayout
,SequenceLayout
,ValueLayout
public interface MemoryLayout extends Constable
ValueLayout
) 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 (see ofPaddingBits(long)
).
Some common value layout constants are defined in the MemoryLayouts
class.
More complex layouts can be derived from simpler ones: a sequence layout denotes a repetition of one or more
element layout (see SequenceLayout
); a group layout denotes an aggregation of (typically) heterogeneous
member layouts (see GroupLayout
).
All implementations of this interface must be value-based;
use of identity-sensitive operations (including reference equality (==
), identity hash code, or synchronization) on
instances of MemoryLayout
may have unpredictable results and should be avoided. The equals
method should
be used for comparisons.
Non-platform classes should not implement MemoryLayout directly.
Size, alignment and byte order
All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed as follows:- for a finite sequence layout S whose element layout is E and size is L, the size of S is that of E, multiplied by L
- the size of an unbounded sequence layout is unknown
- for a group layout G with member layouts M1, M2, ... Mn whose sizes are S1, S2, ... Sn, respectively, the size of G is either S1 + S2 + ... + Sn or max(S1, S2, ... Sn) depending on whether the group is a struct or an union, respectively
Furthermore, all layouts feature a natural alignment which can be inferred as follows:
- for value and padding layout L whose size is N, the natural alignment of L is N
- for a sequence layout S whose element layout is E, the natural alignment of S is that of E
- for a group layout G with member layouts M1, M2, ... Mn whose alignments are A1, A2, ... An, respectively, the natural alignment of G is max(A1, A2 ... An)
withBitAlignment(long)
), which can be useful to describe
hyper-aligned layouts.
All value layouts have an explicit byte order (see ByteOrder
) which is set when the layout is created.
Layout paths
A layout path originates from a root layout (typically a group or a sequence layout) and terminates at a layout nested within the root layout - this is the layout selected by the layout path. Layout paths are typically expressed as a sequence of one or moreMemoryLayout.PathElement
instances.
Layout paths are for example useful in order to obtain offsets of arbitrarily nested layouts inside another layout
(see offset(PathElement...)
), to quickly obtain a memory access handle corresponding to the selected
layout (see varHandle(Class, PathElement...)
), to select an arbitrarily nested layout inside
another layout (see select(PathElement...)
, or to transform a nested layout element inside
another layout (see map(UnaryOperator, PathElement...)
).
Such layout paths can be constructed programmatically using the methods in this class. For instance, given a layout constructed as follows:
We can obtain the offset of the member layout namedSequenceLayout seq = MemoryLayout.ofSequence(5, MemoryLayout.ofStruct( MemoryLayout.ofPaddingBits(32), MemoryLayout.ofValueBits(32, ByteOrder.BIG_ENDIAN).withName("value") ));
value
from seq
, as follows:
Similarly, we can select the member layout namedlong valueOffset = seq.addOffset(PathElement.sequenceElement(), PathElement.groupElement("value"));
value
, as follows:
And, we can also replace the layout namedMemoryLayout value = seq.select(PathElement.sequenceElement(), PathElement.groupElement("value"));
value
with another layout, as follows:
That is, the above declaration is identical to the following, more verbose one:MemoryLayout newSeq = seq.map(l -> MemoryLayout.ofPadding(32), PathElement.sequenceElement(), PathElement.groupElement("value"));
Layout paths can feature one or more free dimensions. For instance, a layout path traversing an unspecified sequence element (that is, where one of the path component was obtained with theMemoryLayout newSeq = MemoryLayout.ofSequence(5, MemoryLayout.ofStruct( MemoryLayout.ofPaddingBits(32), MemoryLayout.ofPaddingBits(32) ));
MemoryLayout.PathElement.sequenceElement()
method) features an additional free dimension, which will have to be bound at runtime.
This is important when obtaining memory access var handle from layouts, as in the following code:
Since the layout pathVarHandle valueHandle = seq.map(int.class, PathElement.sequenceElement(), PathElement.groupElement("value"));
seq
constructed in the above example features exactly one free dimension,
it follows that the memory access var handle valueHandle
will feature an extra long
access coordinate.- API Note:
- In the future, if the Java language permits,
MemoryLayout
may become asealed
interface, which would prohibit subclassing except by explicitly permitted types. - Implementation Requirements:
- Implementations of this class are immutable and thread-safe.
-
Nested Class Summary
Nested Classes Modifier and Type Interface Description static interface
MemoryLayout.PathElement
Instances of this class are used to form layout paths. -
Method Summary
Modifier and Type Method Description long
bitAlignment()
Returns the alignment constraint associated with this layout, expressed in bits.long
bitSize()
Computes the layout size, in bits.default long
byteAlignment()
Returns the alignment constraint associated with this layout, expressed in bytes.default long
byteSize()
Computes the layout size, in bytes.Optional<? extends DynamicConstantDesc<? extends MemoryLayout>>
describeConstable()
boolean
equals(Object that)
Compares the specified object with this layout for equality.int
hashCode()
Returns the hash code value for this layout.boolean
hasSize()
Does this layout have a specified size?default MemoryLayout
map(UnaryOperator<MemoryLayout> op, MemoryLayout.PathElement... elements)
Creates a transformed copy of this layout where a selected layout, from a path rooted in this layout, is replaced with the result of applying the given operation.Optional<String>
name()
Return the name (if any) associated with this layout.default long
offset(MemoryLayout.PathElement... elements)
Computes the offset, in bits, of the layout selected by a given layout path, where the path is considered rooted in this layout.static MemoryLayout
ofPaddingBits(long size)
Create a new padding layout with given size.static SequenceLayout
ofSequence(long elementCount, MemoryLayout elementLayout)
Create a new sequence layout with given element layout and element count.static SequenceLayout
ofSequence(MemoryLayout elementLayout)
Create a new sequence layout, with unbounded element count and given element layout.static GroupLayout
ofStruct(MemoryLayout... elements)
Create a new struct group layout with given member layouts.static GroupLayout
ofUnion(MemoryLayout... elements)
Create a new union group layout with given member layouts.static ValueLayout
ofValueBits(long size, ByteOrder order)
Create a value layout of given byte order and size.default MemoryLayout
select(MemoryLayout.PathElement... elements)
Selects the layout from a path rooted in this layout.String
toString()
Returns a string representation of this layout.default VarHandle
varHandle(Class<?> carrier, MemoryLayout.PathElement... elements)
Creates a memory access var handle that can be used to dereference memory at the layout selected by a given layout path, where the path is considered rooted in this layout.MemoryLayout
withBitAlignment(long bitAlignment)
Creates a new layout which features the desired alignment constraint.MemoryLayout
withName(String name)
Creates a new layout which features the desired layout name.
-
Method Details
-
describeConstable
Optional<? extends DynamicConstantDesc<? extends MemoryLayout>> describeConstable()Returns anOptional
containing the nominal descriptor for this layout, if one can be constructed, or an emptyOptional
if one cannot be constructed.- Specified by:
describeConstable
in interfaceConstable
- Returns:
- An
Optional
containing the resulting nominal descriptor, or an emptyOptional
if one cannot be constructed.
-
hasSize
boolean hasSize()Does this layout have a specified size? A layout does not have a specified size if it is (or contains) a sequence layout whose size is unspecified (seeSequenceLayout.elementCount()
). Value layouts (seeValueLayout
) and padding layouts (seeofPaddingBits(long)
) always have a specified size, therefore this method always returnstrue
in these cases.- Returns:
true
, if this layout has a specified size.
-
bitSize
long bitSize()Computes the layout size, in bits.- Returns:
- the layout size, in bits.
- Throws:
UnsupportedOperationException
- if the layout is, or contains, a sequence layout with unspecified size (seeSequenceLayout
).
-
byteSize
default long byteSize()Computes the layout size, in bytes.- Returns:
- the layout size, in bytes.
- Throws:
UnsupportedOperationException
- if the layout is, or contains, a sequence layout with unspecified size (seeSequenceLayout
), or ifbitSize()
is not a multiple of 8.
-
name
Return the name (if any) associated with this layout.- Returns:
- the layout name (if any).
- See Also:
withName(String)
-
withName
Creates a new layout which features the desired layout name.- Parameters:
name
- the layout name.- Returns:
- a new layout which is the same as this layout, except for the name associated to it.
- See Also:
name()
-
bitAlignment
long bitAlignment()Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power of twoA
which is the bit-wise alignment of the layout. IfA <= 8
thenA/8
is the number of bytes that must be aligned for any pointer that correctly points to this layout. Thus:A=8
means unaligned (in the usual sense), which is common in packets.A=64
means word aligned (on LP64),A=32
int aligned,A=16
short aligned, etc.A=512
is the most strict alignment required by the x86/SV ABI (for AVX-512 data).
withBitAlignment(long)
), then this method returns the natural alignment constraint (in bits) associated with this layout.- Returns:
- the layout alignment constraint, in bits.
-
byteAlignment
default long byteAlignment()Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power of twoA
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).
withBitAlignment(long)
), then this method returns the natural alignment constraint (in bytes) associated with this layout.- Returns:
- the layout alignment constraint, in bytes.
- Throws:
UnsupportedOperationException
- ifbitAlignment()
is not a multiple of 8.
-
withBitAlignment
Creates a new layout which features the desired alignment constraint.- Parameters:
bitAlignment
- the layout alignment constraint, expressed in bits.- Returns:
- a new layout which is the same as this layout, except for the alignment constraint associated to it.
- Throws:
IllegalArgumentException
- ifbitAlignment
is not a power of two, or if it's less than than 8.
-
offset
Computes the offset, in bits, of the layout selected by a given layout path, where the path is considered rooted in this layout.- API Note:
- if the layout path has one (or more) free dimensions,
the offset is computed as if all the indices corresponding to such dimensions were set to
0
. - Parameters:
elements
- the layout path elements.- Returns:
- The offset, in bits, of the layout selected by the layout path in
elements
. - Throws:
IllegalArgumentException
- if the layout path does not select any layout nested in this layout, or if the layout path contains one or more path elements that select multiple sequence element indices (seeMemoryLayout.PathElement.sequenceElement()
andMemoryLayout.PathElement.sequenceElement(long, long)
).UnsupportedOperationException
- if one of the layouts traversed by the layout path has unspecified size.
-
varHandle
Creates a memory access var handle that can be used to dereference memory at the layout selected by a given layout path, where the path is considered rooted in this layout.- API Note:
- the resulting var handle will feature an additional
long
access coordinate for every unspecified sequence access component contained in this layout path. Moreover, the resulting var handle features certain access mode restrictions, which are common to all memory access var handles. - Parameters:
carrier
- the var handle carrier type.elements
- the layout path elements.- Returns:
- a var handle which can be used to dereference memory at the (possibly nested) layout selected by the layout path in
elements
. - Throws:
UnsupportedOperationException
- if the layout path has one or more elements with incompatible alignment constraints, or if one of the layouts traversed by the layout path has unspecified size.IllegalArgumentException
- if the carrier does not represent a primitive type, if the carrier isvoid
,boolean
, or if the layout path inelements
does not select a value layout (seeValueLayout
), or if the selected value layout has a size that that does not match that of the specified carrier type.
-
select
Selects the layout from a path rooted in this layout.- Parameters:
elements
- the layout path elements.- Returns:
- the layout selected by the layout path in
elements
. - Throws:
IllegalArgumentException
- if the layout path does not select any layout nested in this layout, or if the layout path contains one or more path elements that select one or more sequence element indices (seeMemoryLayout.PathElement.sequenceElement(long)
andMemoryLayout.PathElement.sequenceElement(long, long)
).
-
map
Creates a transformed copy of this layout where a selected layout, from a path rooted in this layout, is replaced with the result of applying the given operation.- Parameters:
op
- the unary operation to be applied to the selected layout.elements
- the layout path elements.- Returns:
- a new layout where the layout selected by the layout path in
elements
, has been replaced by the result of applyingop
to the selected layout. - Throws:
IllegalArgumentException
- if the layout path does not select any layout nested in this layout, or if the layout path contains one or more path elements that select one or more sequence element indices (seeMemoryLayout.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 constraints. Furthermore, depending on the layout kind, additional conditions must be satisfied:- two value layouts are considered equal if they have the same endianness (see
ValueLayout.order()
) - 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 kind (see
GroupLayout.isStruct()
,GroupLayout.isUnion()
) and if their member layouts (seeGroupLayout.memberLayouts()
) are also equal
- Overrides:
equals
in classObject
- Parameters:
that
- the object to be compared for equality with this layout.- Returns:
true
if the specified object is equal to this layout.- See Also:
Object.hashCode()
,HashMap
- two value layouts are considered equal if they have the same endianness (see
-
hashCode
int hashCode()Returns the hash code value for this layout.- Overrides:
hashCode
in classObject
- Returns:
- the hash code value for this layout.
- See Also:
Object.equals(java.lang.Object)
,System.identityHashCode(java.lang.Object)
-
toString
String toString()Returns a string representation of this layout. -
ofPaddingBits
Create a new padding layout with given size.- Parameters:
size
- the padding size in bits.- Returns:
- the new selector layout.
- Throws:
IllegalArgumentException
- ifsize <= 0
.
-
ofValueBits
Create a value layout of given byte order and size.- Parameters:
size
- the value layout size.order
- the value layout's byte order.- Returns:
- a new value layout.
- Throws:
IllegalArgumentException
- ifsize <= 0
.
-
ofSequence
Create a new sequence layout with given element layout and element count.- Parameters:
elementCount
- the sequence element count.elementLayout
- the sequence element layout.- Returns:
- the new sequence layout with given element layout and size.
- Throws:
IllegalArgumentException
- ifelementCount < 0
.
-
ofSequence
Create a new sequence layout, with unbounded element count and given element layout.- Parameters:
elementLayout
- the element layout of the sequence layout.- Returns:
- the new sequence layout with given element layout.
-
ofStruct
Create a new struct group layout with given member layouts.- Parameters:
elements
- The member layouts of the struct group layout.- Returns:
- a new struct group layout with given member layouts.
-
ofUnion
Create a new union group layout with given member layouts.- Parameters:
elements
- The member layouts of the union layout.- Returns:
- a new union group layout with given member layouts.
-