146. Shaping C-like structs into memory segments
Let’s consider the C-like struct from the following figure:

Figure 7.12 – A C-like structure
So, in Figure 7.12, we have a C-like struct named point to shape an (x, y) pair of double values. Moreover, we have 5 such pairs declared under the name pointarr. We can try to shape a memory segment to fit this model as follows (arena is an instance of Arena):
MemorySegment segment = MemorySegment.allocateNative(
2 * ValueLayout.JAVA_DOUBLE.byteSize() * 5,
ValueLayout.JAVA_DOUBLE.byteAlignment(), arena.scope());
Next, we should set (x, y) pairs into this segment. For this, we can visualize it as follows:

Figure 7.13 – Memory segment to store (x, y) pairs
Based on this diagram, we can easily come up with the following snippet of code for setting the (x, y) pairs:
for (int i = 0; i < 5; i++) {
segment.setAtIndex(
ValueLayout.JAVA_DOUBLE, i * 2, Math.random());
segment.setAtIndex(
ValueLayout.JAVA_DOUBLE, i * 2 + 1, Math.random());
}
But, another approach consists of using the StructLayout.
Introducing StructLayout
A StructLayout is a group layout. In this layout, the members (other memory layouts) are laid out one after the other exactly as in a C struct. This means that we can shape our C-like struct by laying out two ValueLayout.JAVA_DOUBLE as follows:
StructLayout struct = MemoryLayout.structLayout(
ValueLayout.JAVA_DOUBLE.withName(“x”),
ValueLayout.JAVA_DOUBLE.withName(“y”));
But, we have 5 pairs of (x, y), so we need to nest this StructLayout in a SequenceLayout containing 5 StructLayout as follows:
SequenceLayout struct
= MemoryLayout.sequenceLayout(5,
MemoryLayout.structLayout(
ValueLayout.JAVA_DOUBLE.withName(“x”),
ValueLayout.JAVA_DOUBLE.withName(“y”)));
Next, as we already know from Problem x, we need to define the proper layout paths via PathElement and get back the VarHandle. We need a VarHandle for x and one for y. Notice in the following code how we point them out via their names:
// VarHandle[varType=double,
// coord=[interface java.lang.foreign.MemorySegment, long]]
VarHandle xHandle = struct.varHandle(
PathElement.sequenceElement(),
PathElement.groupElement(“x”));
// VarHandle[varType=double,
// coord=[interface java.lang.foreign.MemorySegment, long]]
VarHandle yHandle = struct.varHandle(
PathElement.sequenceElement(),
PathElement.groupElement(“y”));
Finally, we can use these VarHandle and the element count for setting the data as follows:
try (Arena arena = Arena.openConfined()) {
MemorySegment segment = arena.allocate(struct);
for (int i = 0; i < struct.elementCount(); i++) {
xHandle.set(segment, i, Math.random());
yHandle.set(segment, i, Math.random());
}
…
Getting the data is straightforward:
for (int i = 0; i < struct.elementCount(); i++) {
System.out.printf(“\nx = %.2f”, xHandle.get(segment, i));
System.out.printf(“\ny = %.2f”, yHandle.get(segment, i));
}
}
Challenge yourself to implement this example via ValueLayout.JAVA_DOUBLE.arrayElementVarHandle(int… shape).