Como uma instância VarHandle pode ser criada para acessar elementos de uma matriz de tamanho dinâmico (no contexto da Função Estrangeira e da API de Memória)?
package org.example;
import java.lang.foreign.*;
import java.lang.invoke.VarHandle;
public class ArrayVarHandle {
static final StructLayout coordinateLayout = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
);
static final SequenceLayout arrayLayout = MemoryLayout.sequenceLayout(1, coordinateLayout);
static final VarHandle xInArrayVarHandle = arrayLayout.varHandle(
MemoryLayout.PathElement.sequenceElement(),
MemoryLayout.PathElement.groupElement("x")
);
public static void main(String[] args) {
try (var arena = Arena.ofConfined()) {
int count = 10;
var array = arena.allocate(coordinateLayout, count);
setXValues(array, count);
}
}
static void setXValues(MemorySegment array, int count) {
for (int i = 0; i < count; i++)
xInArrayVarHandle.set(array, 0, i, 100);
}
}
Este código falha com a exceção:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Index 1 out of bounds for length 1
at org.example.ArrayVarHandle.setValues(ArrayVarHandle.java:30)
at org.example.ArrayVarHandle.main(ArrayVarHandle.java:24)
Obviamente, ele verifica os limites do layout arrayLayout
. Ele é declarado com elementCount = 1
(primeiro parâmetro).
Se, em vez disso, for declarado com elementCount = 999999
, o erro muda:
Exception in thread "main" java.lang.IndexOutOfBoundsException: Out of bound access on segment MemorySegment{ address: 0x6000014b8140, byteSize: 80 }; new offset = 0; new length = 7999992
at org.example.ArrayVarHandle.setValues(ArrayVarHandle.java:30)
at org.example.ArrayVarHandle.main(ArrayVarHandle.java:24)
Então ele verifica o tamanho do layout em relação ao tamanho do segmento de memória e falha novamente.
É possível criar um layout de array/sequência sem um tamanho fixo? Ou criar de VarHandle
forma diferente?
No exemplo acima, count
tem um valor fixo. Mas na aplicação real, a contagem não é conhecida em tempo de compilação. E o objetivo seria criar a VarHandle
instância uma vez, e não em cada chamada do método.
Parece que você não está procurando por
SequenceLayout
(que, como você observou, é destinado ao uso com arrays de tamanho fixo), mas em vez disso você está procurando porarrayElementVarHandle
, que é destinado a arrays de tamanho variável. Você então alocaria comarena.allocate(coordinateLayout, count)
.Isso é abordado explicitamente nesta seção da documentação .