Ряд методов создания сегментов памяти в классе Arena принимают в качестве параметра объект типа MemoryLayout. Этот интерфейс описывает компоновку памяти - размер сегмента памяти, выравнивание, порядок байтов.
Интерфейс ValueLayout (который наследуется от MemoryLayout) предоставляет ряд констант,
которые представляют встроенную компоновку памяти для определенного типа данных:
ADDRESS: константа компоновки адреса, размер которой совпадает с размером машинного адреса (size_t в языке С), выравнивание по байтам установлено равным sizeof(size_t)
ADDRESS_UNALIGNED: константа компоновки адреса без выравнивания, размер которой совпадает с размером машинного адреса (size_t)
JAVA_BOOLEAN: константа компоновки значения, размер которой совпадает с размером типа boolean в Java, выравнивание по байтам установлено равным 1
JAVA_BYTE: константа компоновки значения, размер которой совпадает с размером типа byte в Java, выравнивание по байтам установлено на 1
JAVA_CHAR: константа компоновки значения, размер которой совпадает с размером типа char в Java, выравнивание по байтам установлено на 2
JAVA_CHAR_UNALIGNED: константа компоновки адреса без выравнивания, размер которой совпадает с размером типа char в Java
JAVA_DOUBLE: константа компоновки значений, размер которой совпадает с размером типа double в Java, выравнивание по байтам установлено на 8
JAVA_DOUBLE_UNALIGNED: константа компоновки адреса без выравнивания, размер которой совпадает с размером типа double в Java
JAVA_FLOAT: константа компоновки значений, размер которой совпадает с размером типа float в Java, выравнивание по байтам установлено на 4
JAVA_FLOAT_UNALIGNED: константа компоновки адреса без выравнивания, размер которой совпадает с размером типа float в Java
JAVA_INT: константа расположения значений, размер которой совпадает с размером типа int в Java, выравнивание байтов установлено на 4
JAVA_INT_UNALIGNED: константа компоновки адреса без выравнивания, размер которой совпадает с размером типа int в Java
JAVA_LONG: константа компоновки значений, размер которой совпадает с размером типа long в Java, выравнивание по байтам установлено на 8
JAVA_LONG_UNALIGNED: константа компоновки адреса без выравнивания, размер которой совпадает с размером типа long в Java
JAVA_SHORT: константа компоновки значений, размер которой совпадает с размером типа short в Java, выравнивание по байтам установлено на 2
JAVA_SHORT_UNALIGNED: константа компоновки адреса без выравнивания, размер которой совпадает с размером типа short в Java
Для выделения массива необходимо указать структуру элементов и количество элементов. Для этого можно использовать константы компоновки памяти, определенные в классе ValueLayout.
Например, выделим массив значений типа double:
import java.lang.foreign.*;
public class Program {
public static void main(String[] args) {
try (Arena arena = Arena.ofConfined()) {
// выделяем память для 16 значений double
MemorySegment double_seg = arena.allocate(ValueLayout.JAVA_DOUBLE, 16);
System.out.println(double_seg); // MemorySegment{ kind: native, address: 0x7477a8184cb0, byteSize: 128 }
}
}
}
Если у нас уже есть значения в массиве, можно использовать метод allocateFrom():
import java.lang.foreign.*;
public class Program {
public static void main(String[] args) {
try (Arena arena = Arena.ofConfined()) {
double[] nums = {1.0, 2.0, 3.0, 4.0};
// выделяем память для массива nums
MemorySegment double_seg = arena.allocateFrom(ValueLayout.JAVA_DOUBLE, nums);
System.out.println(double_seg); // MemorySegment{ kind: native, address: 0x75f5cc1851a0, byteSize: 32 }
}
}
}
Интерфейс MemorySegment предоставляет множество методов для различных операций с данными в памяти. Рассмотрим некоторые из них:
String getString(long offset)
преобразует строку UTF-8 в строку Java.
type getAtIndex(ValueLayout.oftype layout, long index)
считывает значение примитивного типа по заданному индексу массива.
void setAtIndex(ValueLayout.oftype layout, long index, type value)
записывает значение примитивного типа по заданному индексу массива.
type get(ValueLayout.oftype layout, long offset)
считывает значение примитивного типа по заданному смещению.
void set(ValueLayout.oftype layout, long offset, type value)
записывает значение примитивного типа по заданному смещению.
type[] toArray(ValueLayout.oftype elementLayout)
копирует содержимое сегмента памяти в массив примитивного типа type.
Например, возьмем метод getString(). Предположим, что функция C заполнила сегмент памяти данными. Чтобы преобразовать строку UTF-8 в строку Java, в метод getString() передается
смещение 0:
import java.lang.foreign.*;
public class Program {
public static void main(String[] args) {
try (Arena arena = Arena.ofConfined()) {
String str = "Hello METANIT.COM";
// преобразуем строку Java в строку UTF-8
MemorySegment str_seg = arena.allocateFrom(str);
System.out.println(str_seg); // MemorySegment{ kind: native, address: 0x7aa79c1802d0, byteSize: 18 }
// обратное преобразование в строку Java
String java_str = str_seg.getString(0);
System.out.println(java_str); // Hello METANIT.COM
}
}
}
Для чтения или записи по индексу массива указывается структура памяти и индекс:
import java.lang.foreign.*;
public class Program {
public static void main(String[] args) {
try (Arena arena = Arena.ofConfined()) {
double[] nums = {1.0, 2.0, 3.0, 4.0};
// выделяем память для массива nums
MemorySegment double_seg = arena.allocateFrom(ValueLayout.JAVA_DOUBLE, nums);
// устанавливаем для элемента с индексом 2 значение 5.0
int index = 2;
double_seg.setAtIndex(ValueLayout.JAVA_DOUBLE, index, 5.0);
// получаем один элемент double по индексу 2
double second_double = double_seg.getAtIndex(ValueLayout.JAVA_DOUBLE, index);
System.out.println(second_double); // 5.0
}
}
}
Обратите внимание, что сегмент не сохраняет никакой информации о структуре данных внутри. Вам необходимо указывать структуру данных (в данном случае ValueLayout.JAVA_DOUBLE)
при каждом доступе к элементам или при их обновлении.
Также можно получить массив Java со всеми значениями:
double[] double_nums = double_seg.toArray(ValueLayout.JAVA_DOUBLE);
Методы get()/set() аналогичны методам getAtIndex/setAtIndex, но принимают смещение в байтах:
import java.lang.foreign.*;
public class Program {
public static void main(String[] args) {
try (Arena arena = Arena.ofConfined()) {
double[] nums = {1.0, 2.0, 3.0, 4.0};
// выделяем память для массива nums
MemorySegment double_seg = arena.allocateFrom(ValueLayout.JAVA_DOUBLE, nums);
// устанавливаем значение 11 по смещению 8 байт
double_seg.set(ValueLayout.JAVA_DOUBLE, 8, 11);
// получаем один элемент double по смещению 16 байт
double second_double = double_seg.get(ValueLayout.JAVA_DOUBLE, 16);
System.out.println(second_double); // 3.0
}
}
}