1 /*
  2  *  Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
  3  *  DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  *  This code is free software; you can redistribute it and/or modify it
  6  *  under the terms of the GNU General Public License version 2 only, as
  7  *  published by the Free Software Foundation.  Oracle designates this
  8  *  particular file as subject to the "Classpath" exception as provided
  9  *  by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  *  This code is distributed in the hope that it will be useful, but WITHOUT
 12  *  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  *  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  *  version 2 for more details (a copy is included in the LICENSE file that
 15  *  accompanied this code).
 16  *
 17  *  You should have received a copy of the GNU General Public License version
 18  *  2 along with this work; if not, write to the Free Software Foundation,
 19  *  Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  *   Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  *  or visit www.oracle.com if you need additional information or have any
 23  *  questions.
 24  *
 25  */
 26 package jdk.incubator.foreign;
 27 
 28 import jdk.internal.foreign.LayoutPath;
 29 import jdk.internal.foreign.LayoutPath.PathElementImpl.PathKind;
 30 import jdk.internal.foreign.Utils;
 31 
 32 import java.lang.constant.Constable;
 33 import java.lang.constant.DynamicConstantDesc;
 34 import java.lang.invoke.MethodHandle;
 35 import java.lang.invoke.MethodHandles;
 36 import java.lang.invoke.VarHandle;
 37 import java.nio.ByteOrder;
 38 import java.util.EnumSet;
 39 import java.util.Objects;
 40 import java.util.Optional;
 41 import java.util.OptionalLong;
 42 import java.util.Set;
 43 import java.util.function.Function;
 44 import java.util.function.UnaryOperator;
 45 import java.util.stream.Collectors;
 46 import java.util.stream.Stream;
 47 
 48 /**
 49  * A memory layout can be used to describe the contents of a memory segment.
 50  * There are two leaves in the layout hierarchy, <em>value layouts</em>, which are used to represent values of given size and kind (see
 51  * {@link ValueLayout}) and <em>padding layouts</em> which are used, as the name suggests, to represent a portion of a memory
 52  * segment whose contents should be ignored, and which are primarily present for alignment reasons (see {@link MemoryLayout#paddingLayout(long)}).
 53  * Some common value layout constants are defined in the {@link ValueLayout} class.
 54  * <p>
 55  * More complex layouts can be derived from simpler ones: a <em>sequence layout</em> denotes a repetition of one or more
 56  * element layout (see {@link SequenceLayout}); a <em>group layout</em> denotes an aggregation of (typically) heterogeneous
 57  * member layouts (see {@link GroupLayout}).
 58  * <p>
 59  * For instance, consider the following struct declaration in C:
 60  *
 61  * {@snippet lang=c :
 62  * typedef struct {
 63  *     char kind;
 64  *     int value;
 65  * } TaggedValues[5];
 66  * }
 67  *
 68  * The above declaration can be modelled using a layout object, as follows:
 69  *
 70  * {@snippet lang=java :
 71  * SequenceLayout taggedValues = MemoryLayout.sequenceLayout(5,
 72  *     MemoryLayout.structLayout(
 73  *         ValueLayout.JAVA_BYTE.withName("kind"),
 74  *         MemoryLayout.paddingLayout(24),
 75  *         ValueLayout.JAVA_INT.withName("value")
 76  *     )
 77  * ).withName("TaggedValues");
 78  * }
 79  * <p>
 80  * All implementations of this interface must be <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>;
 81  * programmers should treat instances that are {@linkplain #equals(Object) equal} as interchangeable and should not
 82  * use instances for synchronization, or unpredictable behavior may occur. For example, in a future release,
 83  * synchronization may fail. The {@code equals} method should be used for comparisons.
 84  *
 85  * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
 86  * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
 87  *
 88  * <h2><a id = "layout-align">Size, alignment and byte order</a></h2>
 89  *
 90  * All layouts have a size; layout size for value and padding layouts is always explicitly denoted; this means that a layout description
 91  * always has the same size in bits, regardless of the platform in which it is used. For derived layouts, the size is computed
 92  * as follows:
 93  * <ul>
 94  *     <li>for a <em>finite</em> sequence layout <em>S</em> whose element layout is <em>E</em> and size is L,
 95  *     the size of <em>S</em> is that of <em>E</em>, multiplied by <em>L</em></li>
 96  *     <li>the size of an <em>unbounded</em> sequence layout is <em>unknown</em></li>
 97  *     <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose sizes are
 98  *     <em>S1</em>, <em>S2</em>, ... <em>Sn</em>, respectively, the size of <em>G</em> is either <em>S1 + S2 + ... + Sn</em> or
 99  *     <em>max(S1, S2, ... Sn)</em> depending on whether the group is a <em>struct</em> or an <em>union</em>, respectively</li>
100  * </ul>
101  * <p>
102  * Furthermore, all layouts feature a <em>natural alignment</em> which can be inferred as follows:
103  * <ul>
104  *     <li>for a padding layout <em>L</em>, the natural alignment is 1, regardless of its size; that is, in the absence
105  *     of an explicit alignment constraint, a padding layout should not affect the alignment constraint of the group
106  *     layout it is nested into</li>
107  *     <li>for a value layout <em>L</em> whose size is <em>N</em>, the natural alignment of <em>L</em> is <em>N</em></li>
108  *     <li>for a sequence layout <em>S</em> whose element layout is <em>E</em>, the natural alignment of <em>S</em> is that of <em>E</em></li>
109  *     <li>for a group layout <em>G</em> with member layouts <em>M1</em>, <em>M2</em>, ... <em>Mn</em> whose alignments are
110  *     <em>A1</em>, <em>A2</em>, ... <em>An</em>, respectively, the natural alignment of <em>G</em> is <em>max(A1, A2 ... An)</em></li>
111  * </ul>
112  * A layout's natural alignment can be overridden if needed (see {@link MemoryLayout#withBitAlignment(long)}), which can be useful to describe
113  * hyper-aligned layouts.
114  * <p>
115  * All value layouts have an <em>explicit</em> byte order (see {@link java.nio.ByteOrder}) which is set when the layout is created.
116  *
117  * <h2><a id = "layout-paths">Layout paths</a></h2>
118  *
119  * A <em>layout path</em> originates from a <em>root</em> layout (typically a group or a sequence layout) and terminates
120  * at a layout nested within the root layout - this is the layout <em>selected</em> by the layout path.
121  * Layout paths are typically expressed as a sequence of one or more {@link PathElement} instances.
122  * <p>
123  * Layout paths are for example useful in order to obtain {@linkplain MemoryLayout#bitOffset(PathElement...) offsets} of
124  * arbitrarily nested layouts inside another layout, to quickly obtain a {@linkplain #varHandle(PathElement...) memory access handle}
125  * corresponding to the selected layout, to {@linkplain #select(PathElement...) select} an arbitrarily nested layout inside
126  * another layout, or to {@link #map(UnaryOperator, PathElement...) transform} a nested layout element inside
127  * another layout.
128  * <p>
129  * Such <em>layout paths</em> can be constructed programmatically using the methods in this class.
130  * For instance, given the {@code taggedValues} layout instance constructed as above, we can obtain the offset,
131  * in bits, of the member layout named <code>value</code> in the <em>first</em> sequence element, as follows:
132  * {@snippet lang=java :
133  * long valueOffset = taggedValues.bitOffset(PathElement.sequenceElement(0),
134  *                                           PathElement.groupElement("value")); // yields 32
135  * }
136  *
137  * Similarly, we can select the member layout named {@code value}, as follows:
138  * {@snippet lang=java :
139  * MemoryLayout value = taggedValues.select(PathElement.sequenceElement(),
140  *                                          PathElement.groupElement("value"));
141  * }
142  *
143  * And, we can also replace the layout named {@code value} with another layout, as follows:
144  * {@snippet lang=java :
145  * MemoryLayout taggedValuesWithHole = taggedValues.map(l -> MemoryLayout.paddingLayout(32),
146  *                                             PathElement.sequenceElement(), PathElement.groupElement("value"));
147  * }
148  *
149  * That is, the above declaration is identical to the following, more verbose one:
150  * {@snippet lang=java :
151  * MemoryLayout taggedValuesWithHole = MemoryLayout.sequenceLayout(5,
152  *     MemoryLayout.structLayout(
153  *         ValueLayout.JAVA_BYTE.withName("kind"),
154  *         MemoryLayout.paddingLayout(32),
155  *         MemoryLayout.paddingLayout(32)
156  * ));
157  * }
158  *
159  * Layout paths can feature one or more <em>free dimensions</em>. For instance, a layout path traversing
160  * an unspecified sequence element (that is, where one of the path component was obtained with the
161  * {@link PathElement#sequenceElement()} method) features an additional free dimension, which will have to be bound at runtime.
162  * This is important when obtaining memory access var handle from layouts, as in the following code:
163  *
164  * {@snippet lang=java :
165  * VarHandle valueHandle = taggedValues.varHandle(PathElement.sequenceElement(),
166  *                                                PathElement.groupElement("value"));
167  * }
168  *
169  * Since the layout path constructed in the above example features exactly one free dimension (as it doesn't specify
170  * <em>which</em> member layout named {@code value} should be selected from the enclosing sequence layout),
171  * it follows that the memory access var handle {@code valueHandle} will feature an <em>additional</em> {@code long}
172  * access coordinate.
173  *
174  * <p>A layout path with free dimensions can also be used to create an offset-computing method handle, using the
175  * {@link #bitOffset(PathElement...)} or {@link #byteOffsetHandle(PathElement...)} method. Again, free dimensions are
176  * translated into {@code long} parameters of the created method handle. The method handle can be used to compute the
177  * offsets of elements of a sequence at different indices, by supplying these indices when invoking the method handle.
178  * For instance:
179  *
180  * {@snippet lang=java :
181  * MethodHandle offsetHandle = taggedValues.byteOffsetHandle(PathElement.sequenceElement(),
182  *                                                           PathElement.groupElement("kind"));
183  * long offset1 = (long) offsetHandle.invokeExact(1L); // 8
184  * long offset2 = (long) offsetHandle.invokeExact(2L); // 16
185  * }
186  *
187  * <h2>Layout attributes</h2>
188  *
189  * Layouts can be optionally associated with a <em>name</em>. A layout name can be referred to when
190  * constructing <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>.
191  *
192  * @implSpec
193  * Implementations of this interface are immutable, thread-safe and <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a>.
194  */
195 public sealed interface MemoryLayout extends Constable permits AbstractLayout, SequenceLayout, GroupLayout, PaddingLayout, ValueLayout {
196 
197     /**
198      * {@return an {@link Optional} containing the nominal descriptor for this
199      * layout, if one can be constructed, or an empty {@link Optional}
200      * if one cannot be constructed}
201      */
202     @Override
203     Optional<? extends DynamicConstantDesc<? extends MemoryLayout>> describeConstable();
204 
205     /**
206      * Returns {@code true} if this layout has a specified size. A layout does not have a specified size if it is (or contains) a sequence layout whose
207      * size is unspecified (see {@link SequenceLayout#elementCount()}).
208      *
209      * Value layouts (see {@link ValueLayout}) and padding layouts (see {@link MemoryLayout#paddingLayout(long)})
210      * <em>always</em> have a specified size, therefore this method always returns {@code true} in these cases.
211      *
212      * @return {@code true}, if this layout has a specified size.
213      */
214     boolean hasSize();
215 
216     /**
217      * {@return the layout size, in bits}
218      * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}).
219      */
220     long bitSize();
221 
222     /**
223      * {@return the layout size, in bytes}
224      * @throws UnsupportedOperationException if the layout is, or contains, a sequence layout with unspecified size (see {@link SequenceLayout}),
225      * or if {@code bitSize()} is not a multiple of 8.
226      */
227     long byteSize();
228 
229     /**
230      * {@return the <em>name</em> (if any) associated with this layout}
231      * @see MemoryLayout#withName(String)
232      */
233     Optional<String> name();
234 
235     /**
236      * Creates a new layout which features the desired layout <em>name</em>.
237      *
238      * @param name the layout name.
239      * @return a new layout which is the same as this layout, except for the <em>name</em> associated with it.
240      * @see MemoryLayout#name()
241      */
242     MemoryLayout withName(String name);
243 
244     /**
245      * Returns the alignment constraint associated with this layout, expressed in bits. Layout alignment defines a power
246      * of two {@code A} which is the bit-wise alignment of the layout. If {@code A <= 8} then {@code A/8} is the number of
247      * bytes that must be aligned for any pointer that correctly points to this layout. Thus:
248      *
249      * <ul>
250      * <li>{@code A=8} means unaligned (in the usual sense), which is common in packets.</li>
251      * <li>{@code A=64} means word aligned (on LP64), {@code A=32} int aligned, {@code A=16} short aligned, etc.</li>
252      * <li>{@code A=512} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
253      * </ul>
254      *
255      * If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
256      * then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bits) associated with this layout.
257      *
258      * @return the layout alignment constraint, in bits.
259      */
260     long bitAlignment();
261 
262     /**
263      * Returns the alignment constraint associated with this layout, expressed in bytes. Layout alignment defines a power
264      * of two {@code A} which is the byte-wise alignment of the layout, where {@code A} is the number of bytes that must be aligned
265      * for any pointer that correctly points to this layout. Thus:
266      *
267      * <ul>
268      * <li>{@code A=1} means unaligned (in the usual sense), which is common in packets.</li>
269      * <li>{@code A=8} means word aligned (on LP64), {@code A=4} int aligned, {@code A=2} short aligned, etc.</li>
270      * <li>{@code A=64} is the most strict alignment required by the x86/SV ABI (for AVX-512 data).</li>
271      * </ul>
272      *
273      * If no explicit alignment constraint was set on this layout (see {@link #withBitAlignment(long)}),
274      * then this method returns the <a href="#layout-align">natural alignment</a> constraint (in bytes) associated with this layout.
275      *
276      * @return the layout alignment constraint, in bytes.
277      * @throws UnsupportedOperationException if {@code bitAlignment()} is not a multiple of 8.
278      */
279     default long byteAlignment() {
280         return Utils.bitsToBytesOrThrow(bitAlignment(),
281                 () -> new UnsupportedOperationException("Cannot compute byte alignment; bit alignment is not a multiple of 8"));
282     }
283 
284     /**
285      * Creates a new layout which features the desired alignment constraint.
286      *
287      * @param bitAlignment the layout alignment constraint, expressed in bits.
288      * @return a new layout which is the same as this layout, except for the alignment constraint associated with it.
289      * @throws IllegalArgumentException if {@code bitAlignment} is not a power of two, or if it's less than 8.
290      */
291     MemoryLayout withBitAlignment(long bitAlignment);
292 
293     /**
294      * Computes the offset, in bits, of the layout selected by a given layout path, where the path is considered rooted in this
295      * layout.
296      *
297      * @param elements the layout path elements.
298      * @return The offset, in bits, of the layout selected by the layout path in {@code elements}.
299      * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
300      * layout path contains one or more path elements that select multiple sequence element indices
301      * (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
302      * @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size.
303      * @throws NullPointerException if either {@code elements == null}, or if any of the elements
304      * in {@code elements} is {@code null}.
305      */
306     default long bitOffset(PathElement... elements) {
307         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::offset,
308                 EnumSet.of(PathKind.SEQUENCE_ELEMENT, PathKind.SEQUENCE_RANGE), elements);
309     }
310 
311     /**
312      * Creates a method handle that can be used to compute the offset, in bits, of the layout selected
313      * by a given layout path, where the path is considered rooted in this layout.
314      *
315      * <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
316      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
317      * where the order of the parameters corresponds to the order of the path elements.
318      * The returned method handle can be used to compute a layout offset similar to {@link #bitOffset(PathElement...)},
319      * but where some sequence indices are specified only when invoking the method handle.
320      *
321      * <p>The final offset returned by the method handle is computed as follows:
322      *
323      * <blockquote><pre>{@code
324      * offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
325      * }</pre></blockquote>
326      *
327      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
328      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
329      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
330      * the layout path.
331      *
332      * @param elements the layout path elements.
333      * @return a method handle that can be used to compute the bit offset of the layout element
334      * specified by the given layout path elements, when supplied with the missing sequence element indices.
335      * @throws IllegalArgumentException if the layout path contains one or more path elements that select
336      * multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
337      * @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size.
338      */
339     default MethodHandle bitOffsetHandle(PathElement... elements) {
340         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::offsetHandle,
341                 EnumSet.of(PathKind.SEQUENCE_RANGE), elements);
342     }
343 
344     /**
345      * Computes the offset, in bytes, of the layout selected by a given layout path, where the path is considered rooted in this
346      * layout.
347      *
348      * @param elements the layout path elements.
349      * @return The offset, in bytes, of the layout selected by the layout path in {@code elements}.
350      * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout, or if the
351      * layout path contains one or more path elements that select multiple sequence element indices
352      * (see {@link PathElement#sequenceElement()} and {@link PathElement#sequenceElement(long, long)}).
353      * @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size,
354      * or if {@code bitOffset(elements)} is not a multiple of 8.
355      * @throws NullPointerException if either {@code elements == null}, or if any of the elements
356      * in {@code elements} is {@code null}.
357      */
358     default long byteOffset(PathElement... elements) {
359         return Utils.bitsToBytesOrThrow(bitOffset(elements), Utils.bitsToBytesThrowOffset);
360     }
361 
362     /**
363      * Creates a method handle that can be used to compute the offset, in bytes, of the layout selected
364      * by a given layout path, where the path is considered rooted in this layout.
365      *
366      * <p>The returned method handle has a return type of {@code long}, and features as many {@code long}
367      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
368      * where the order of the parameters corresponds to the order of the path elements.
369      * The returned method handle can be used to compute a layout offset similar to {@link #byteOffset(PathElement...)},
370      * but where some sequence indices are specified only when invoking the method handle.
371      *
372      * <p>The final offset returned by the method handle is computed as follows:
373      *
374      * <blockquote><pre>{@code
375      * bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
376      * offset = bitOffset / 8
377      * }</pre></blockquote>
378      *
379      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
380      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
381      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
382      * the layout path.
383      *
384      * <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
385      * offset in bits is not a multiple of 8.
386      *
387      * @param elements the layout path elements.
388      * @return a method handle that can be used to compute the byte offset of the layout element
389      * specified by the given layout path elements, when supplied with the missing sequence element indices.
390      * @throws IllegalArgumentException if the layout path contains one or more path elements that select
391      * multiple sequence element indices (see {@link PathElement#sequenceElement(long, long)}).
392      * @throws UnsupportedOperationException if one of the layouts traversed by the layout path has unspecified size.
393      */
394     default MethodHandle byteOffsetHandle(PathElement... elements) {
395         MethodHandle mh = bitOffsetHandle(elements);
396         mh = MethodHandles.filterReturnValue(mh, Utils.MH_bitsToBytesOrThrowForOffset);
397         return mh;
398     }
399 
400     /**
401      * Creates a memory access var handle that can be used to dereference memory at the layout selected by a given layout path,
402      * where the path is considered rooted in this layout.
403      * <p>
404      * The final memory location accessed by the returned memory access var handle can be computed as follows:
405      *
406      * <blockquote><pre>{@code
407      * address = base + offset
408      * }</pre></blockquote>
409      *
410      * where {@code base} denotes the base address expressed by the {@link MemorySegment} access coordinate
411      * (see {@link MemorySegment#address()} and {@link MemoryAddress#toRawLongValue()}) and {@code offset}
412      * can be expressed in the following form:
413      *
414      * <blockquote><pre>{@code
415      * offset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
416      * }</pre></blockquote>
417      *
418      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
419      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
420      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
421      * the layout path.
422      *
423      * @apiNote the resulting var handle will feature an additional {@code long} access coordinate for every
424      * unspecified sequence access component contained in this layout path. Moreover, the resulting var handle
425      * features certain <a href="MemoryHandles.html#memaccess-mode">access mode restrictions</a>, which are common to all memory access var handles.
426      *
427      * @param elements the layout path elements.
428      * @return a var handle which can be used to dereference memory at the (possibly nested) layout selected by the layout path in {@code elements}.
429      * @throws UnsupportedOperationException if the layout path has one or more elements with incompatible alignment constraints,
430      * or if one of the layouts traversed by the layout path has unspecified size.
431      * @throws IllegalArgumentException if the layout path in {@code elements} does not select a value layout (see {@link ValueLayout}).
432      */
433     default VarHandle varHandle(PathElement... elements) {
434         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::dereferenceHandle,
435                 Set.of(), elements);
436     }
437 
438     /**
439      * Creates a method handle which, given a memory segment, returns a {@linkplain MemorySegment#asSlice(long,long) slice}
440      * corresponding to the layout selected by a given layout path, where the path is considered rooted in this layout.
441      *
442      * <p>The returned method handle has a return type of {@code MemorySegment}, features a {@code MemorySegment}
443      * parameter as leading parameter representing the segment to be sliced, and features as many trailing {@code long}
444      * parameter types as there are free dimensions in the provided layout path (see {@link PathElement#sequenceElement()}),
445      * where the order of the parameters corresponds to the order of the path elements.
446      * The returned method handle can be used to create a slice similar to using {@link MemorySegment#asSlice(long, long)},
447      * but where the offset argument is dynamically compute based on indices specified when invoking the method handle.
448      *
449      * <p>The offset of the returned segment is computed as follows:
450      *
451      * <blockquote><pre>{@code
452      * bitOffset = c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
453      * offset = bitOffset / 8
454      * }</pre></blockquote>
455      *
456      * where {@code x_1}, {@code x_2}, ... {@code x_n} are <em>dynamic</em> values provided as {@code long}
457      * arguments, whereas {@code c_1}, {@code c_2}, ... {@code c_m} are <em>static</em> offset constants
458      * and {@code s_0}, {@code s_1}, ... {@code s_n} are <em>static</em> stride constants which are derived from
459      * the layout path.
460      *
461      * <p>After the offset is computed, the returned segment is created as if by calling:
462      * {@snippet lang=java :
463      * segment.asSlice(offset, layout.byteSize());
464      * }
465      *
466      * where {@code segment} is the segment to be sliced, and where {@code layout} is the layout selected by the given
467      * layout path, as per {@link MemoryLayout#select(PathElement...)}.
468      *
469      * <p>The method handle will throw an {@link UnsupportedOperationException} if the computed
470      * offset in bits is not a multiple of 8.
471      *
472      * @param elements the layout path elements.
473      * @return a method handle which can be used to create a slice of the selected layout element, given a segment.
474      * @throws UnsupportedOperationException if the size of the selected layout in bits is not a multiple of 8.
475      */
476     default MethodHandle sliceHandle(PathElement... elements) {
477         return computePathOp(LayoutPath.rootPath(this, MemoryLayout::bitSize), LayoutPath::sliceHandle,
478                 Set.of(), elements);
479     }
480 
481 
482     /**
483      * Selects the layout from a path rooted in this layout.
484      *
485      * @param elements the layout path elements.
486      * @return the layout selected by the layout path in {@code elements}.
487      * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout,
488      * or if the layout path contains one or more path elements that select one or more sequence element indices
489      * (see {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}).
490      */
491     default MemoryLayout select(PathElement... elements) {
492         return computePathOp(LayoutPath.rootPath(this, l -> 0L), LayoutPath::layout,
493                 EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE), elements);
494     }
495 
496     /**
497      * Creates a transformed copy of this layout where a selected layout, from a path rooted in this layout,
498      * is replaced with the result of applying the given operation.
499      *
500      * @param op the unary operation to be applied to the selected layout.
501      * @param elements the layout path elements.
502      * @return a new layout where the layout selected by the layout path in {@code elements},
503      * has been replaced by the result of applying {@code op} to the selected layout.
504      * @throws IllegalArgumentException if the layout path does not select any layout nested in this layout,
505      * or if the layout path contains one or more path elements that select one or more sequence element indices
506      * (see {@link PathElement#sequenceElement(long)} and {@link PathElement#sequenceElement(long, long)}).
507      */
508     default MemoryLayout map(UnaryOperator<MemoryLayout> op, PathElement... elements) {
509         Objects.requireNonNull(op);
510         return computePathOp(LayoutPath.rootPath(this, l -> 0L), path -> path.map(op),
511                 EnumSet.of(PathKind.SEQUENCE_ELEMENT_INDEX, PathKind.SEQUENCE_RANGE), elements);
512     }
513 
514     private static <Z> Z computePathOp(LayoutPath path, Function<LayoutPath, Z> finalizer,
515                                        Set<LayoutPath.PathElementImpl.PathKind> badKinds, PathElement... elements) {
516         Objects.requireNonNull(elements);
517         for (PathElement e : elements) {
518             LayoutPath.PathElementImpl pathElem = (LayoutPath.PathElementImpl)Objects.requireNonNull(e);
519             if (badKinds.contains(pathElem.kind())) {
520                 throw new IllegalArgumentException(String.format("Invalid %s selection in layout path", pathElem.kind().description()));
521             }
522             path = pathElem.apply(path);
523         }
524         return finalizer.apply(path);
525     }
526 
527     /**
528      * {@return true, if this layout is a padding layout}
529      */
530     boolean isPadding();
531 
532     /**
533      * Instances of this class are used to form <a href="MemoryLayout.html#layout-paths"><em>layout paths</em></a>. There
534      * are two kinds of path elements: <em>group path elements</em> and <em>sequence path elements</em>. Group
535      * path elements are used to select a given named member layout within a {@link GroupLayout}. Sequence
536      * path elements are used to select a sequence element layout within a {@link SequenceLayout}; selection
537      * of sequence element layout can be <em>explicit</em> (see {@link PathElement#sequenceElement(long)}) or
538      * <em>implicit</em> (see {@link PathElement#sequenceElement()}). When a path uses one or more implicit
539      * sequence path elements, it acquires additional <em>free dimensions</em>.
540      *
541      * <p> Unless otherwise specified, passing a {@code null} argument, or an array argument containing one or more {@code null}
542      * elements to a method in this class causes a {@link NullPointerException NullPointerException} to be thrown. </p>
543      *
544      * @implSpec
545      * Implementations of this interface are immutable and thread-safe.
546      */
547     sealed interface PathElement permits LayoutPath.PathElementImpl {
548 
549         /**
550          * Returns a path element which selects a member layout with given name from a given group layout.
551          * The path element returned by this method does not alter the number of free dimensions of any path
552          * that is combined with such element.
553          *
554          * @implSpec in case multiple group elements with a matching name exist, the path element returned by this
555          * method will select the first one; that is, the group element with the lowest offset from current path is selected.
556          *
557          * @param name the name of the group element to be selected.
558          * @return a path element which selects the group element with given name.
559          */
560         static PathElement groupElement(String name) {
561             Objects.requireNonNull(name);
562             return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.GROUP_ELEMENT,
563                                                   path -> path.groupElement(name));
564         }
565 
566         /**
567          * Returns a path element which selects the element layout at the specified position in a given the sequence layout.
568          * The path element returned by this method does not alter the number of free dimensions of any path
569          * that is combined with such element.
570          *
571          * @param index the index of the sequence element to be selected.
572          * @return a path element which selects the sequence element layout with given index.
573          * @throws IllegalArgumentException if {@code index < 0}.
574          */
575         static PathElement sequenceElement(long index) {
576             if (index < 0) {
577                 throw new IllegalArgumentException("Index must be positive: " + index);
578             }
579             return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.SEQUENCE_ELEMENT_INDEX,
580                                                   path -> path.sequenceElement(index));
581         }
582 
583         /**
584          * Returns a path element which selects the element layout in a <em>range</em> of positions in a given the sequence layout,
585          * where the range is expressed as a pair of starting index (inclusive) {@code S} and step factor (which can also be negative)
586          * {@code F}.
587          * If a path with free dimensions {@code n} is combined with the path element returned by this method,
588          * the number of free dimensions of the resulting path will be {@code 1 + n}. If the free dimension associated
589          * with this path is bound by an index {@code I}, the resulting accessed offset can be obtained with the following
590          * formula:
591          * <blockquote><pre>{@code
592          * E * (S + I * F)
593          * }</pre></blockquote>
594          * where {@code E} is the size (in bytes) of the sequence element layout.
595          *
596          * @param start the index of the first sequence element to be selected.
597          * @param step the step factor at which subsequence sequence elements are to be selected.
598          * @return a path element which selects the sequence element layout with given index.
599          * @throws IllegalArgumentException if {@code start < 0}, or {@code step == 0}.
600          */
601         static PathElement sequenceElement(long start, long step) {
602             if (start < 0) {
603                 throw new IllegalArgumentException("Start index must be positive: " + start);
604             }
605             if (step == 0) {
606                 throw new IllegalArgumentException("Step must be != 0: " + step);
607             }
608             return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.SEQUENCE_RANGE,
609                                                   path -> path.sequenceElement(start, step));
610         }
611 
612         /**
613          * Returns a path element which selects an unspecified element layout from a given sequence layout.
614          * If a path with free dimensions {@code n} is combined with the path element returned by this method,
615          * the number of free dimensions of the resulting path will be {@code 1 + n}.
616          *
617          * @return a path element which selects an unspecified sequence element layout.
618          */
619         static PathElement sequenceElement() {
620             return new LayoutPath.PathElementImpl(LayoutPath.PathElementImpl.PathKind.SEQUENCE_ELEMENT,
621                                                   LayoutPath::sequenceElement);
622         }
623     }
624 
625     /**
626      * Compares the specified object with this layout for equality. Returns {@code true} if and only if the specified
627      * object is also a layout, and it is equal to this layout. Two layouts are considered equal if they are of
628      * the same kind, have the same size, name and alignment constraints. Furthermore, depending on the layout kind, additional
629      * conditions must be satisfied:
630      * <ul>
631      *     <li>two value layouts are considered equal if they have the same byte order (see {@link ValueLayout#order()})</li>
632      *     <li>two sequence layouts are considered equal if they have the same element count (see {@link SequenceLayout#elementCount()}), and
633      *     if their element layouts (see {@link SequenceLayout#elementLayout()}) are also equal</li>
634      *     <li>two group layouts are considered equal if they are of the same kind (see {@link GroupLayout#isStruct()},
635      *     {@link GroupLayout#isUnion()}) and if their member layouts (see {@link GroupLayout#memberLayouts()}) are also equal</li>
636      * </ul>
637      *
638      * @param that the object to be compared for equality with this layout.
639      * @return {@code true} if the specified object is equal to this layout.
640      */
641     boolean equals(Object that);
642 
643     /**
644      * {@return the hash code value for this layout}
645      */
646     int hashCode();
647 
648     /**
649      * {@return the string representation of this layout}
650      */
651     @Override
652     String toString();
653 
654     /**
655      * Create a new padding layout with given size.
656      *
657      * @param size the padding size in bits.
658      * @return the new selector layout.
659      * @throws IllegalArgumentException if {@code size <= 0}.
660      */
661     static MemoryLayout paddingLayout(long size) {
662         AbstractLayout.checkSize(size);
663         return new PaddingLayout(size);
664     }
665 
666     /**
667      * Creates a value layout of given Java carrier and byte order. The type of resulting value layout is determined
668      * by the carrier provided:
669      * <ul>
670      *     <li>{@link ValueLayout.OfBoolean}, for {@code boolean.class}</li>
671      *     <li>{@link ValueLayout.OfByte}, for {@code byte.class}</li>
672      *     <li>{@link ValueLayout.OfShort}, for {@code short.class}</li>
673      *     <li>{@link ValueLayout.OfChar}, for {@code char.class}</li>
674      *     <li>{@link ValueLayout.OfInt}, for {@code int.class}</li>
675      *     <li>{@link ValueLayout.OfFloat}, for {@code float.class}</li>
676      *     <li>{@link ValueLayout.OfLong}, for {@code long.class}</li>
677      *     <li>{@link ValueLayout.OfDouble}, for {@code double.class}</li>
678      *     <li>{@link ValueLayout.OfAddress}, for {@code MemoryAddress.class}</li>
679      * </ul>
680      * @param carrier the value layout carrier.
681      * @param order the value layout's byte order.
682      * @return a new value layout.
683      * @throws IllegalArgumentException if the carrier type is not supported.
684      */
685     static ValueLayout valueLayout(Class<?> carrier, ByteOrder order) {
686         Objects.requireNonNull(carrier);
687         Objects.requireNonNull(order);
688         if (carrier == boolean.class) {
689             return new ValueLayout.OfBoolean(order);
690         } else if (carrier == char.class) {
691             return new ValueLayout.OfChar(order);
692         } else if (carrier == byte.class) {
693             return new ValueLayout.OfByte(order);
694         } else if (carrier == short.class) {
695             return new ValueLayout.OfShort(order);
696         } else if (carrier == int.class) {
697             return new ValueLayout.OfInt(order);
698         } else if (carrier == float.class) {
699             return new ValueLayout.OfFloat(order);
700         } else if (carrier == long.class) {
701             return new ValueLayout.OfLong(order);
702         } else if (carrier == double.class) {
703             return new ValueLayout.OfDouble(order);
704         } else if (carrier == MemoryAddress.class) {
705             return new ValueLayout.OfAddress(order);
706         } else {
707             throw new IllegalArgumentException("Unsupported carrier: " + carrier.getName());
708         }
709     }
710 
711     /**
712      * Create a new sequence layout with given element layout and element count.
713      *
714      * @param elementCount the sequence element count.
715      * @param elementLayout the sequence element layout.
716      * @return the new sequence layout with given element layout and size.
717      * @throws IllegalArgumentException if {@code elementCount < 0}.
718      */
719     static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) {
720         AbstractLayout.checkSize(elementCount, true);
721         OptionalLong size = OptionalLong.of(elementCount);
722         return new SequenceLayout(size, Objects.requireNonNull(elementLayout));
723     }
724 
725     /**
726      * Create a new sequence layout, with unbounded element count and given element layout.
727      *
728      * @param elementLayout the element layout of the sequence layout.
729      * @return the new sequence layout with given element layout.
730      */
731     static SequenceLayout sequenceLayout(MemoryLayout elementLayout) {
732         return new SequenceLayout(OptionalLong.empty(), Objects.requireNonNull(elementLayout));
733     }
734 
735     /**
736      * Create a new <em>struct</em> group layout with given member layouts.
737      *
738      * @param elements The member layouts of the <em>struct</em> group layout.
739      * @return a new <em>struct</em> group layout with given member layouts.
740      */
741     static GroupLayout structLayout(MemoryLayout... elements) {
742         Objects.requireNonNull(elements);
743         return new GroupLayout(GroupLayout.Kind.STRUCT,
744                 Stream.of(elements)
745                         .map(Objects::requireNonNull)
746                         .collect(Collectors.toList()));
747     }
748 
749     /**
750      * Create a new <em>union</em> group layout with given member layouts.
751      *
752      * @param elements The member layouts of the <em>union</em> layout.
753      * @return a new <em>union</em> group layout with given member layouts.
754      */
755     static GroupLayout unionLayout(MemoryLayout... elements) {
756         Objects.requireNonNull(elements);
757         return new GroupLayout(GroupLayout.Kind.UNION,
758                 Stream.of(elements)
759                         .map(Objects::requireNonNull)
760                         .collect(Collectors.toList()));
761     }
762 }