Package Summary Overview Summary

Module java.base
Package java.lang.foreign

# Interface MemoryLayout

All Known Implementing Classes:
  `GroupLayoutPREVIEW`, `SequenceLayoutPREVIEW`, `ValueLayoutPREVIEW`, `ValueLayout.OfAddressPREVIEW`, `ValueLayout.OfBooleanPREVIEW`, `ValueLayout.OfBytePREVIEW`, `ValueLayout.OfCharPREVIEW`, `ValueLayout.OfDoublePREVIEW`, `ValueLayout.OfFloatPREVIEW`, `ValueLayout.OfIntPREVIEW`, `ValueLayout.OfLongPREVIEW`, `ValueLayout.OfShortPREVIEW`

public sealed interface MemoryLayout permits SequenceLayoutPREVIEW, GroupLayoutPREVIEW, ValueLayoutPREVIEW(not exhaustive)
`MemoryLayout` is a preview API of the Java platform.
Programs can only use `MemoryLayout` when preview features are enabled.
Preview features may be removed in a future release, or upgraded to permanent features of the Java platform.
A memory layout can be used to describe the contents of a memory segment. There are two leaves in the layout hierarchy, value layouts , which are used to represent values of given size and kind (see `ValueLayout`PREVIEW) 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 `paddingLayout(long)`). Some common value layout constants are defined in the `ValueLayout`PREVIEW class.

More complex layouts can be derived from simpler ones: a sequence layout denotes a repetition of one or more element layout (see `SequenceLayout`PREVIEW); a group layout denotes an aggregation of (typically) heterogeneous member layouts (see `GroupLayout`PREVIEW).

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];

The above declaration can be modelled using a layout object, as follows:

    SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
        MemoryLayout.structLayout(
            ValueLayout.JAVA_BYTE.withName("kind"),
            MemoryLayout.paddingLayout(24),
            ValueLayout.JAVA_INT.withName("value")
        )
    ).withName("TaggedValues");

## 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 sequence layout S whose element layout is E and size is L, the size of S is that of E, multiplied by L
- 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 a padding layout L, the natural alignment is 1, regardless of its size; that is, in the absence of an explicit alignment constraint, a padding layout should not affect the alignment constraint of the group layout it is nested into
- for a value 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)

A layout's natural alignment can be overridden if needed (see `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 more `MemoryLayout.PathElement`PREVIEW instances.

Layout paths are for example useful in order to obtain offsets of arbitrarily nested layouts inside another layout, to quickly obtain a memory access handle corresponding to the selected layout, or to select an arbitrarily nested layout inside another layout.

Such layout paths can be constructed programmatically using the methods in this class. For instance, given the `taggedValues` layout instance constructed as above, we can obtain the offset, in bits, of the member layout named `value` in the first sequence element, as follows:

    long valueOffset = taggedValues.bitOffset(PathElement.sequenceElement(0),
                                              PathElement.groupElement("value")); // yields 32

Similarly, we can select the member layout named `value`, as follows:

    MemoryLayout value = taggedValues.select(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 the `MemoryLayout.PathElement.sequenceElement()`PREVIEW method) features an additional free dimension, which will have to be bound at runtime. This is important when obtaining a memory segment view var handle PREVIEW from layouts, as in the following code:

    VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(),
                                                   PathElement.groupElement("value"));

Since the layout path constructed in the above example features exactly one free dimension (as it doesn't specify which member layout named `value` should be selected from the enclosing sequence layout), it follows that the var handle `valueHandle` will feature an additional `long` access coordinate.

A layout path with free dimensions can also be used to create an offset-computing method handle, using the `bitOffset(PathElement...)` or `byteOffsetHandle(PathElement...)` method. Again, free dimensions are translated into `long` parameters of the created method handle. The method handle can be used to compute the offsets of elements of a sequence at different indices, by supplying these indices when invoking the method handle. For instance:

    MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
                                                              PathElement.groupElement("kind"));
    long offset1 = (long) offsetHandle.invokeExact(1L); // 8
    long offset2 = (long) offsetHandle.invokeExact(2L); // 16

Implementation Requirements:
  Implementations of this interface are immutable, thread-safe and value-based.
Since:
  19

- ## Nested Class Summary

  Nested Classes
  Modifier and Type
  Interface
  Description
  `static interface`
  `MemoryLayout.PathElementPREVIEW`
  Preview.
  An element in a layout path .

- ## Method Summary

  Modifier and Type
  Method
  Description
  `long`
  `bitAlignment()`
  Returns the alignment constraint associated with this layout, expressed in bits.
  `default long`
  `bitOffset (MemoryLayout.PathElementPREVIEW... elements)`
  Computes the offset, in bits, of the layout selected by the given layout path, where the path is considered rooted in this layout.
  `default MethodHandle`
  `bitOffsetHandle (MemoryLayout.PathElementPREVIEW... elements)`
  Creates a method handle that can be used to compute the offset, in bits, of the layout selected by the given layout path, where the path is considered rooted in this layout.
  `long`
  `bitSize()`
  Returns the layout size, in bits.
  `default long`
  `byteAlignment()`
  Returns the alignment constraint associated with this layout, expressed in bytes.
  `default long`
  `byteOffset (MemoryLayout.PathElementPREVIEW... elements)`
  Computes the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in this layout.
  `default MethodHandle`
  `byteOffsetHandle (MemoryLayout.PathElementPREVIEW... elements)`
  Creates a method handle that can be used to compute the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in this layout.
  `long`
  `byteSize()`
  Returns the layout size, in bytes.
  `boolean`
  `equals (Object that)`
  Compares the specified object with this layout for equality.
  `int`
  `hashCode()`
  Returns the hash code value for this layout.
  `boolean`
  `isPadding()`
  Returns true, if this layout is a padding layout.
  `Optional<String>`
  `name()`
  Returns the name (if any) associated with this layout.
  `static MemoryLayoutPREVIEW`
  `paddingLayout (long size)`
  Creates a padding layout with the given size.
  `default MemoryLayoutPREVIEW`
  `select (MemoryLayout.PathElementPREVIEW... elements)`
  Selects the layout from a path rooted in this layout.
  `static SequenceLayoutPREVIEW`
  `sequenceLayout (long elementCount, MemoryLayoutPREVIEW elementLayout)`
  Creates a sequence layout with the given element layout and element count.
  `default MethodHandle`
  `sliceHandle (MemoryLayout.PathElementPREVIEW... elements)`
  Creates a method handle which, given a memory segment, returns a slicePREVIEW corresponding to the layout selected by the given layout path, where the path is considered rooted in this layout.
  `static GroupLayoutPREVIEW`
  `structLayout (MemoryLayoutPREVIEW... elements)`
  Creates a struct layout with the given member layouts.
  `String`
  `toString()`
  Returns the string representation of this layout.
  `static GroupLayoutPREVIEW`
  `unionLayout (MemoryLayoutPREVIEW... elements)`
  Creates a union layout with the given member layouts.
  `static ValueLayoutPREVIEW`
  `valueLayout (Class<?> carrier, ByteOrder order)`
  Creates a value layout of given Java carrier and byte order.
  `default VarHandle`
  `varHandle (MemoryLayout.PathElementPREVIEW... elements)`
  Creates an access var handle that can be used to dereference memory at the layout selected by the given layout path, where the path is considered rooted in this layout.
  `MemoryLayoutPREVIEW`
  `withBitAlignment (long bitAlignment)`
  Returns a memory layout with the same size and name as this layout, but with the specified alignment constraints (in bits).
  `MemoryLayoutPREVIEW`
  `withName (String name)`
  Returns a memory layout with the same size and alignment constraints as this layout, but with the specified name.

- ## Method Details

  - ### bitSize

    long bitSize()
    Returns the layout size, in bits.
    Returns:
      the layout size, in bits

  - ### byteSize

    long byteSize()
    Returns the layout size, in bytes.
    Returns:
      the layout size, in bytes
    Throws:
      `UnsupportedOperationException` - if `bitSize()` is not a multiple of 8.

  - ### name

    Optional<String> name()
    Returns the name (if any) associated with this layout.
    Returns:
      the name (if any) associated with this layout
    See Also:
      - `withName(String)`

  - ### withName

    MemoryLayoutPREVIEW withName (String name)
    Returns a memory layout with the same size and alignment constraints as this layout, but with the specified name.
    Parameters:
      `name` - the layout name.
    Returns:
      a memory layout with the given name.
    See Also:
      - `name()`

  - ### bitAlignment

    long bitAlignment()
    Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power of two `A` which is the bit-wise alignment of the layout. If `A <= 8` then `A/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).
    If no explicit alignment constraint was set on this layout (see `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 two `A` which is the byte-wise alignment of the layout, where `A` 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).
    If no explicit alignment constraint was set on this layout (see `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` - if `bitAlignment()` is not a multiple of 8.

  - ### withBitAlignment

    MemoryLayoutPREVIEW withBitAlignment (long bitAlignment)
    Returns a memory layout with the same size and name as this layout, but with the specified alignment constraints (in bits).
    Parameters:
      `bitAlignment` - the layout alignment constraint, expressed in bits.
    Returns:
      a memory layout with the given alignment constraints.
    Throws:
      `IllegalArgumentException` - if `bitAlignment` is not a power of two, or if it's less than 8.

  - ### bitOffset

    default long bitOffset (MemoryLayout.PathElementPREVIEW... elements)
    Computes the offset, in bits, of the layout selected by the given layout path, where the path is considered rooted in this layout.
    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 (see `MemoryLayout.PathElement.sequenceElement()`PREVIEW and `MemoryLayout.PathElement.sequenceElement(long, long)` PREVIEW).
      `NullPointerException` - if either `elements == null` , or if any of the elements in `elements` is `null`.

  - ### bitOffsetHandle

    default MethodHandle bitOffsetHandle (MemoryLayout.PathElementPREVIEW... elements)
    Creates a method handle that can be used to compute the offset, in bits, of the layout selected by the given layout path, where the path is considered rooted in this layout.

    The returned method handle has a return type of `long`, and features as many `long` parameter types as there are free dimensions in the provided layout path (see `MemoryLayout.PathElement.sequenceElement()`PREVIEW), where the order of the parameters corresponds to the order of the path elements. The returned method handle can be used to compute a layout offset similar to `bitOffset(PathElement...)`, but where some sequence indices are specified only when invoking the method handle.

    The final offset returned by the method handle is computed as follows:

    >      offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)

    where `x_1`, `x_2`, ... `x_n` are dynamic values provided as `long` arguments, whereas `c_1`, `c_2`, ... `c_m` are static offset constants and `s_0`, `s_1`, ... `s_n` are static stride constants which are derived from the layout path.
    Parameters:
      `elements` - the layout path elements.
    Returns:
      a method handle that can be used to compute the bit offset of the layout element specified by the given layout path elements, when supplied with the missing sequence element indices.
    Throws:
      `IllegalArgumentException` - if the layout path contains one or more path elements that select multiple sequence element indices (see `MemoryLayout.PathElement.sequenceElement(long, long)` PREVIEW).

  - ### byteOffset

    default long byteOffset (MemoryLayout.PathElementPREVIEW... elements)
    Computes the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in 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 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 (see `MemoryLayout.PathElement.sequenceElement()`PREVIEW and `MemoryLayout.PathElement.sequenceElement(long, long)` PREVIEW).
      `UnsupportedOperationException` - if `bitOffset(elements)` is not a multiple of 8.
      `NullPointerException` - if either `elements == null` , or if any of the elements in `elements` is `null`.

  - ### byteOffsetHandle

    default MethodHandle byteOffsetHandle (MemoryLayout.PathElementPREVIEW... elements)
    Creates a method handle that can be used to compute the offset, in bytes, of the layout selected by the given layout path, where the path is considered rooted in this layout.

    The returned method handle has a return type of `long`, and features as many `long` parameter types as there are free dimensions in the provided layout path (see `MemoryLayout.PathElement.sequenceElement()`PREVIEW), where the order of the parameters corresponds to the order of the path elements. The returned method handle can be used to compute a layout offset similar to `byteOffset(PathElement...)`, but where some sequence indices are specified only when invoking the method handle.

    The final offset returned by the method handle is computed as follows:

    >      bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
    >      offset = bitOffset / 8

    where `x_1`, `x_2`, ... `x_n` are dynamic values provided as `long` arguments, whereas `c_1`, `c_2`, ... `c_m` are static offset constants and `s_0`, `s_1`, ... `s_n` are static stride constants which are derived from the layout path.

    The method handle will throw an `UnsupportedOperationException` if the computed offset in bits is not a multiple of 8.

    Parameters:
      `elements` - the layout path elements.
    Returns:
      a method handle that can be used to compute the byte offset of the layout element specified by the given layout path elements, when supplied with the missing sequence element indices.
    Throws:
      `IllegalArgumentException` - if the layout path contains one or more path elements that select multiple sequence element indices (see `MemoryLayout.PathElement.sequenceElement(long, long)` PREVIEW).

  - ### varHandle

    default VarHandle varHandle (MemoryLayout.PathElementPREVIEW... elements)
    Creates an access var handle that can be used to dereference memory at the layout selected by the given layout path, where the path is considered rooted in this layout.

    The final memory location accessed by the returned var handle can be computed as follows:

    >      address = base + offset

    where `base` denotes the base address expressed by the `MemorySegment`PREVIEW access coordinate (see `MemorySegment.address()`PREVIEW and `MemoryAddress.toRawLongValue()`PREVIEW) and `offset` can be expressed in the following form:

    >      offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)

    where `x_1`, `x_2`, ... `x_n` are dynamic values provided as `long` arguments, whereas `c_1`, `c_2`, ... `c_m` are static offset constants and `s_1`, `s_2`, ... `s_n` are static stride constants which are derived from the layout path.
    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 segment view handles.
    Parameters:
      `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.
      `IllegalArgumentException` - if the layout path in `elements` does not select a value layout (see `ValueLayout`PREVIEW).
    See Also:
      - `MethodHandles.memorySegmentViewVarHandle(ValueLayout)`PREVIEW

  - ### sliceHandle

    default MethodHandle sliceHandle (MemoryLayout.PathElementPREVIEW... elements)
    Creates a method handle which, given a memory segment, returns a slicePREVIEW corresponding to the layout selected by the given layout path, where the path is considered rooted in this layout.

    The returned method handle has a return type of `MemorySegment`, features a `MemorySegment` parameter as leading parameter representing the segment to be sliced, and features as many trailing `long` parameter types as there are free dimensions in the provided layout path (see `MemoryLayout.PathElement.sequenceElement()`PREVIEW), where the order of the parameters corresponds to the order of the path elements. The returned method handle can be used to create a slice similar to using `MemorySegment.asSlice(long, long)` PREVIEW, but where the offset argument is dynamically compute based on indices specified when invoking the method handle.

    The offset of the returned segment is computed as follows:

    >      bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
    >      offset = bitOffset / 8

    where `x_1`, `x_2`, ... `x_n` are dynamic values provided as `long` arguments, whereas `c_1`, `c_2`, ... `c_m` are static offset constants and `s_1`, `s_2`, ... `s_n` are static stride constants which are derived from the layout path.

    After the offset is computed, the returned segment is created as if by calling:

        segment.asSlice(offset, layout.byteSize());

    where `segment` is the segment to be sliced, and where `layout` is the layout selected by the given layout path, as per `select(PathElement...)`.

    The method handle will throw an `UnsupportedOperationException` if the computed offset in bits is not a multiple of 8.

    Parameters:
      `elements` - the layout path elements.
    Returns:
      a method handle which can be used to create a slice of the selected layout element, given a segment.
    Throws:
      `UnsupportedOperationException` - if the size of the selected layout in bits is not a multiple of 8.

  - ### select

    default MemoryLayoutPREVIEW select (MemoryLayout.PathElementPREVIEW... elements)
    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 (see `MemoryLayout.PathElement.sequenceElement(long)`PREVIEW and `MemoryLayout.PathElement.sequenceElement(long, long)` PREVIEW).

  - ### isPadding

    boolean isPadding()
    Returns true, if this layout is a padding layout.
    Returns:
      true, if this layout is a padding layout

  - ### equals

    boolean equals (Object that)
    Compares the specified object with this layout for equality. Returns `true` 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 byte order (see `ValueLayout.order()`PREVIEW)
    - two sequence layouts are considered equal if they have the same element count (see `SequenceLayout.elementCount()`PREVIEW), and if their element layouts (see `SequenceLayout.elementLayout()`PREVIEW) are also equal
    - two group layouts are considered equal if they are of the same kind (see `GroupLayout.isStruct()`PREVIEW, `GroupLayout.isUnion()`PREVIEW) and if their member layouts (see `GroupLayout.memberLayouts()`PREVIEW) are also equal
    Overrides:
      `equals` in class `Object`
    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`

  - ### hashCode

    int hashCode()
    Returns the hash code value for this layout.
    Overrides:
      `hashCode` in class `Object`
    Returns:
      the hash code value for this layout
    See Also:
      - `Object.equals(java.lang.Object)`
      - `System.identityHashCode(java.lang.Object)`

  - ### toString

    String toString()
    Returns the string representation of this layout.
    Overrides:
      `toString` in class `Object`
    Returns:
      the string representation of this layout

  - ### paddingLayout

    static MemoryLayoutPREVIEW paddingLayout (long size)
    Creates a padding layout with the given size.
    Parameters:
      `size` - the padding size in bits.
    Returns:
      the new selector layout.
    Throws:
      `IllegalArgumentException` - if `size <= 0` .

  - ### valueLayout

    static ValueLayoutPREVIEW valueLayout (Class<?> carrier, ByteOrder order)
    Creates a value layout of given Java carrier and byte order. The type of resulting value layout is determined by the carrier provided:
    - `ValueLayout.OfBoolean`PREVIEW, for `boolean.class`
    - `ValueLayout.OfByte`PREVIEW, for `byte.class`
    - `ValueLayout.OfShort`PREVIEW, for `short.class`
    - `ValueLayout.OfChar`PREVIEW, for `char.class`
    - `ValueLayout.OfInt`PREVIEW, for `int.class`
    - `ValueLayout.OfFloat`PREVIEW, for `float.class`
    - `ValueLayout.OfLong`PREVIEW, for `long.class`
    - `ValueLayout.OfDouble`PREVIEW, for `double.class`
    - `ValueLayout.OfAddress`PREVIEW, for `MemoryAddress.class`
    Parameters:
      `carrier` - the value layout carrier.
      `order` - the value layout's byte order.
    Returns:
      a value layout with the given Java carrier and byte-order.
    Throws:
      `IllegalArgumentException` - if the carrier type is not supported.

  - ### sequenceLayout

    static SequenceLayoutPREVIEW sequenceLayout (long elementCount, MemoryLayoutPREVIEW elementLayout)
    Creates a sequence layout with the given element layout and element count. If the element count has the special value `-1`, the element count is inferred to be the biggest possible count such that the sequence layout size does not overflow, using the following formula:

    >      inferredElementCount = Long.MAX_VALUE / elementLayout.bitSize();

    Parameters:
      `elementCount` - the sequence element count; if set to `-1`, the sequence element count is inferred.
      `elementLayout` - the sequence element layout.
    Returns:
      the new sequence layout with the given element layout and size.
    Throws:
      `IllegalArgumentException` - if `elementCount < -1` .
      `IllegalArgumentException` - if `elementCount != -1` and the computation `elementCount * elementLayout.bitSize()` overflows.

  - ### structLayout

    static GroupLayoutPREVIEW structLayout (MemoryLayoutPREVIEW... elements)
    Creates a struct layout with the given member layouts.
    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 bit sizes of the member layouts overflows.

  - ### unionLayout

    static GroupLayoutPREVIEW unionLayout (MemoryLayoutPREVIEW... elements)
    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.