- 既知のすべてのサブインタフェース:
AddressLayout
,GroupLayout
,PaddingLayout
,SequenceLayout
,StructLayout
,UnionLayout
,ValueLayout
,ValueLayout.OfBoolean
,ValueLayout.OfByte
,ValueLayout.OfChar
,ValueLayout.OfDouble
,ValueLayout.OfFloat
,ValueLayout.OfInt
,ValueLayout.OfLong
,ValueLayout.OfShort
レイアウト階層には、指定されたサイズと種類の値を表すために使用される「値レイアウト」と、コンテンツが無視されるメモリー・セグメントの一部を表すために使用される「パディング・レイアウト」の2つのリーフがあります。これらのリーフは主に配置上の理由から存在します。 ValueLayout.JAVA_INT
やValueLayout.JAVA_FLOAT_UNALIGNED
などの一般的な値のレイアウト定数は、ValueLayout
クラスで定義されます。 特別な種類の値レイアウト、つまりアドレス・レイアウトを使用して、メモリー・リージョンのアドレスを示す値をモデル化します。
より複雑なレイアウトをより単純なものから導出できます: 「順序レイアウト」は、要素レイアウトの0個以上の出現の同種の繰返しを示します。「グループ・レイアウト」は、0個以上のメンバー・レイアウトの異機種間集計を示します。 グループ・レイアウトには2つの種類があります: 構造体レイアウト。メンバー・レイアウトは順番に配置され、メンバー・レイアウトは同じ開始オフセットに配置される共用体レイアウト。
レイアウトは、オプションでnameに関連付けることができます。 レイアウト名は、「レイアウト・パス」の作成時に参照できます。
Cでは、次の構造体宣言を考慮してください:
typedef struct {
char kind;
int value;
} TaggedValues[5];
SequenceLayout TAGGED_VALUES = MemoryLayout.sequenceLayout(5,
MemoryLayout.structLayout(
ValueLayout.JAVA_BYTE.withName("kind"),
MemoryLayout.paddingLayout(3),
ValueLayout.JAVA_INT.withName("value")
)
).withName("TaggedValues");
メモリー・レイアウトの特性
すべてのレイアウトにはsize (バイトで表されます)があり、次のように定義されています:- 値レイアウトのサイズは、値レイアウトに関連付けられたValueLayout.carrier()によって決まります。 つまり、定数
ValueLayout.JAVA_INT
は、キャリアint
を持ち、サイズは4バイトです。 - アドレス・レイアウトのサイズはプラットフォームに依存します。 つまり、定数
ValueLayout.ADDRESS
のサイズは、64ビット・プラットフォームでは8バイトです。 - パディング・レイアウトのサイズは、常に「紺ストレクション」で明示的に指定されます
- 要素レイアウトがEで要素数がLのシーケンス・レイアウトのサイズは、EのサイズにLを掛けた値です
- サイズがS1、S2、... SnであるM1、M2、... Mnのメンバー・レイアウトを含む構造体レイアウトのサイズは、それぞれS1 + S2 + ... + Snです
- サイズがS1、S2、... Snのメンバー・レイアウトM1、M2、... Mnを含む連結レイアウトUのサイズは、max(S1, S2, ... Sn)です。
さらに、すべてのレイアウトには、次のように定義された「自然整列」 (バイトで表されます)があります:
- パディング・レイアウトの自然な配置は1です
- サイズがNの値レイアウトの自然な位置合せは、Nです
- 要素レイアウトがEである順序レイアウトの自然な位置合せは、Eの配置です
- 整列がそれぞれA1、A2、... 「1つの」であるメンバー・レイアウトM1、M2、... Mnを含むグループ・レイアウトの自然整列は、max(A1, A2 ... An)です。
withByteAlignment(long)
を参照してください)で上書きできます。これは、より弱い位置合わせ拘束またはより強い位置合わせ拘束を持つレイアウトを記述するのに便利です。
レイアウト・パス
「レイアウト・パス」は、他のレイアウトにネストされているレイアウトを明確に選択するために使用します。 レイアウト・パスは通常、1つ以上の「パス要素」のシーケンスとして表されます。 (レイアウト・パスのより正式な定義は、belowで提供されています。)。レイアウト・パスは、次の目的で使用できます:
たとえば、前述のtaggedValues
順序レイアウトの場合、first順序要素内のvalue
という名前のメンバー・レイアウトのオフセット(バイト)を次のように取得できます:
long valueOffset = TAGGED_VALUES.byteOffset(PathElement.sequenceElement(0),
PathElement.groupElement("value")); // yields 4
value
という名前のメンバー・レイアウトを次のように選択できます:
MemoryLayout value = TAGGED_VALUES.select(PathElement.sequenceElement(),
PathElement.groupElement("value"));
オープン・パス要素
レイアウト・パス要素の一部(「オープン・パス要素」)は、複数のレイアウトを一度に選択できます。 たとえば、オープン・パス要素MemoryLayout.PathElement.sequenceElement()
、MemoryLayout.PathElement.sequenceElement(long, long)
は、順序レイアウトで未指定の要素を選択します。 1つ以上のオープン・パス要素を含むレイアウト・パスから導出されたvarハンドルには、タイプlong
の追加の座標があります。この座標は、クライアントがパス内のオープン要素を「バインド」するために使用できます:
VarHandle valueHandle = TAGGED_VALUES.varHandle(PathElement.sequenceElement(),
PathElement.groupElement("value"));
MemorySegment taggedValues = ...
// reads the "value" field of the third struct in the array (taggedValues[2].value)
int val = (int) valueHandle.get(taggedValues,
0L, // base offset
2L); // sequence index
オープン・パス要素は、「オフセット計算メソッド・ハンドル」の作成にも影響します。 各オープン・パス要素は、取得したメソッド・ハンドルで追加のlong
パラメータになります。 このパラメータを使用して、オフセットを計算する順序要素のインデックスを指定できます:
MethodHandle offsetHandle = TAGGED_VALUES.byteOffsetHandle(PathElement.sequenceElement(),
PathElement.groupElement("kind"));
long offset1 = (long) offsetHandle.invokeExact(0L, 1L); // 0 + (1 * 8) = 8
long offset2 = (long) offsetHandle.invokeExact(0L, 2L); // 0 + (2 * 8) = 16
パス要素を間接参照
「間接参照パス要素」という特別な種類のパス要素を使用すると、メモリー・レイアウトから取得されたvarハンドルがポインタに従うことができます。 次のレイアウトを検討します:StructLayout RECTANGLE = MemoryLayout.structLayout(
ValueLayout.ADDRESS.withTargetLayout(
MemoryLayout.sequenceLayout(4,
MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
).withName("point")
)
).withName("points")
);
points
(「ターゲット・レイアウト」が4つの構造体レイアウトのシーケンス・レイアウトであるアドレス・レイアウト)が含まれています。 各構造体レイアウトは、2ディメンション・ポイントを記述し、それぞれx
およびy
という名前のペアまたはValueLayout.JAVA_INT
座標として定義されます。
間接参照パス要素を使用すると、次のように、矩形内のいずれかの点のy
座標にアクセスするvarハンドルを取得できます。
VarHandle rectPointYs = RECTANGLE.varHandle(
PathElement.groupElement("points"),
PathElement.dereferenceElement(),
PathElement.sequenceElement(),
PathElement.groupElement("y")
);
MemorySegment rect = ...
// dereferences the third point struct in the "points" array, and reads its "y" coordinate (rect.points[2]->y)
int rect_y_2 = (int) rectPointYs.get(rect,
0L, // base offset
2L); // sequence index
レイアウト・パスの整形式
レイアウト・パスは、「初期レイアウト」とも呼ばれるレイアウトC_0
に適用されます。 レイアウト・パスの各パス要素は、現在のレイアウトC_i-1
を他のレイアウトC_i
に更新する関数とみなすことができます。 つまり、レイアウト・パスP
のパス要素E1, E2, ... En
ごとに、C_i = f_i(C_i-1)
をコンピュートします。ここで、f_i
は、対象となるパス要素に関連付けられた選択関数で、E_i
と示されます。 最後のレイアウトC_i
は、「選択したレイアウト」とも呼ばれます。
レイアウト・パスP
は、対応する入力レイアウトC_0, C_1, ... C_n-1
に対してすべてのパス要素E1, E2, ... En
が整形式になっている場合、初期レイアウトC_0
に対して整形式とみなされます。 次のいずれかがtrueの場合、パス要素E
はレイアウトL
に対して整形式とみなされます:
L
は順序レイアウトで、E
は順序パス要素(MemoryLayout.PathElement.sequenceElement(long)
、MemoryLayout.PathElement.sequenceElement(long, long)
またはMemoryLayout.PathElement.sequenceElement()
のいずれか)です。 さらに、E
に1つ以上のシーケンス・インデックスが含まれている場合、このようなインデックスはシーケンス・レイアウトの要素数と互換性がある必要がありますL
はグループ・レイアウトで、E
はグループ・パス要素(MemoryLayout.PathElement.groupElement(String)
またはMemoryLayout.PathElement.groupElement(long)
のいずれか)です。 さらに、グループ・パス要素は、名前または索引のいずれかでL
の有効なメンバー・レイアウトを参照する必要がありますL
はアドレス・レイアウトで、E
は「間接参照パス要素」です。 さらに、L
は「ターゲット・レイアウト」を定義する必要があります。
C_0
に対して整形式ではないレイアウト・パスP
を指定しようとすると、IllegalArgumentException
になります。
アクセス・モード制限
varHandle(PathElement...)
またはValueLayout.varHandle()
によって返されるvarハンドルには、選択したレイアウトL
から導出される特定のアクセス特性があります。
L.carrier()
から導出されたキャリア・タイプT
L.byteAlignment()
から導出された整列制約A
L.byteSize()
から導出されたアクセス・サイズS
A
がアクセス・サイズS
と互換性がある場合、つまりA >= S
の場合、varハンドルは「連携」であるとします。 整列されたvarハンドルは、次のアクセス・モードをサポートすることが保証されています。
- すべての
T
の読取り/書込みアクセス・モード。 32ビット・プラットフォームでは、long
、double
、およびMemorySegment
のアクセス・モードget
およびset
がサポートされていますが、「Java言語仕様」のセクション17.7に説明されているように、ワード引き裂きにつながる可能性があります。 int
,long
,float
,double
およびMemorySegment
のアトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードの追加タイプがサポートされる場合があります。)int
、long
およびMemorySegment
の数値アトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードに対して追加の数値型をサポートする場合があります。)int
、long
およびMemorySegment
のビット単位のアトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードに対して追加の数値型をサポートする場合があります。)
T
がfloat
、double
またはMemorySegment
の場合、アトミック更新アクセス・モードはビット単位の表現(それぞれFloat.floatToRawIntBits(float)
、Double.doubleToRawLongBits(double)
およびMemorySegment.address()
を参照してください。)を使用して値を比較します。
または、VARハンドルは、その位置合せ制約A
がアクセス・サイズS
と互換性がない場合(つまり、A < S
の場合)は「位置なし」です。 整列されていないvarハンドルは、get
およびset
アクセス・モードのみをサポートします。 他のすべてのアクセス・モードでは、UnsupportedOperationException
がスローされます。 さらに、サポートされているものの、アクセス・モードget
およびset
はワード・リングにつながる可能性があります。
可変長配列の操作
順序レイアウトを使用して、サイズが「静的に」であることがわかっている配列の内容を記述する方法を見てきました。 ただし、配列サイズが認識されるのは「動的に」のみです。 このような配列を「可変長配列」と呼びます。 可変長配列には、次の2つの一般的な種類があります。- サイズが無関係な変数またはパラメータの値に依存する「トップレベル」可変長配列。
- 構造体内の可変長配列「ネスト」。そのサイズは、包含構造体内の他のフィールドの値に依存します。
トップレベルの可変長配列
Cでは、次の構造体宣言を考慮してください:typedef struct {
int x;
int y;
} Point;
x
およびy
)としてモデル化されます。 次に、Cコードの次のスニペットについて考えてみます。
int size = ...
Point *points = (Point*)malloc(sizeof(Point) * size);
for (int i = 0 ; i < size ; i++) {
... points[i].x ...
}
points
)の配列を割り当てます。 特に、配列のサイズは、size
変数の値に動的にバインドされます。 ループ内では、配列内のすべての点のx
座標がアクセスされます。
このコードをJavaでモデル化するには、Point
構造体のレイアウトを次のように定義します。
StructLayout POINT = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("x"),
ValueLayout.JAVA_INT.withName("y")
);
VarHandle POINT_ARR_X = POINT.arrayElementVarHandle(PathElement.groupElement("x"));
int size = ...
MemorySegment points = ...
for (int i = 0 ; i < size ; i++) {
... POINT_ARR_X.get(segment, 0L, (long)i) ...
}
x
に、arrayElementVarHandle(PathElement...)
メソッドを使用して取得されるPOINT_ARR_X
varハンドルを使用してアクセスします。 このvarハンドルは、2つのlong
座標を備えています: 1つ目はベース・オフセット(0L
に設定)で、2つ目はポイント配列のすべての要素にまたがる論理索引です。
ベース・オフセット座標を使用すると、クライアントは、varハンドル(その例を以下に示します。)に追加のオフセット計算を注入することで、複雑なアクセス操作を表現できます。 ベース・オフセットが定数(前の例のように)クライアントの場合、必要に応じてベース・オフセット・パラメータを削除し、アクセス式を簡素化できます。 これは、MethodHandles.insertCoordinates(VarHandle, int, Object...)
varハンドル・アダプタを使用して実現されます。
ネストされた可変長配列
Cでは、次の構造体宣言を考慮してください:typedef struct {
int size;
Point points[];
} Polygon;
points
配列のサイズは、「フレキシブル配列メンバー」 (C99で標準化された機能)を使用して、C宣言でunspecifiedのままになります。
再度、クライアントは、次に示すように、arrayElementVarHandle(PathElement...)
メソッドを使用して、ネストされた可変長配列内の要素への構造化アクセスを実行できます。
StructLayout POLYGON = MemoryLayout.structLayout(
ValueLayout.JAVA_INT.withName("size"),
MemoryLayout.sequenceLayout(0, POINT).withName("points")
);
VarHandle POLYGON_SIZE = POLYGON.varHandle(0, PathElement.groupElement("size"));
long POINTS_OFFSET = POLYGON.byteOffset(PathElement.groupElement("points"));
POLYGON
レイアウトには、サイズzeroのシーケンス・レイアウトが含まれます。 順序レイアウトの要素レイアウトは、前に示したPOINT
レイアウトです。 ポリゴン・レイアウトは、ポリゴン・サイズへのアクセスを提供するvarハンドル、および可変長のpoints
配列の先頭へのオフセット(POINTS_OFFSET
)を取得するために使用されます。
次に、ポリゴン内のすべての点のx
座標に次のようにアクセスできます。
MemorySegment polygon = ...
int size = POLYGON_SIZE.get(polygon, 0L);
for (int i = 0 ; i < size ; i++) {
... POINT_ARR_X.get(polygon, POINTS_OFFSET, (long)i) ...
}
POLYGON_SIZE
varハンドルを使用してポリゴン・サイズを取得します。 次に、ループで、ポリゴン内のすべての点のx
座標を読み取ります。 これを行うには、POINT_ARR_X
varハンドルのオフセット座標にカスタム・オフセット(namely, POINTS_OFFSET
)を指定します。 前述のように、ループ・インダクション変数i
は、可変長配列のすべての要素に分類するために、POINT_ARR_X
varハンドルの索引として渡されます。 - 実装要件:
- このインタフェースの実装は不変、スレッド・セーフ、およびvalue-basedです。
- シール済クラス階層グラフ:
- 導入されたバージョン:
- 22
-
ネストされたクラスのサマリー
-
メソッドのサマリー
修飾子と型メソッド説明arrayElementVarHandle
(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメント内の隣接する要素にアクセスするvarハンドルを作成します。アクセスされた要素にはこのレイアウトがあり、パスの初期レイアウトはこのレイアウトです。long
このレイアウトに関連付けられているバイト単位の配置制約を返します。long
byteOffset
(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたレイアウトのオフセットをバイト数で計算します。パス内の初期レイアウトはこのレイアウトです。byteOffsetHandle
(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたレイアウトのオフセット(バイト)を計算するメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。long
byteSize()
レイアウト・サイズをバイト単位で返します。boolean
指定されたオブジェクトをこのレイアウトと比較し、等価性を維持します。int
hashCode()
このレイアウトのハッシュ・コード値を返します。name()
このレイアウトに関連付けられている名前(もしあれば)を返します。static PaddingLayout
paddingLayout
(long byteSize) 指定されたバイト・サイズでパディング・レイアウトを作成します。long
scale
(long offset, long index) offset + (byteSize() * index)
を返します。このレイアウトでscale(long, long)
を呼び出すために使用できるメソッド・ハンドルを返します。select
(MemoryLayout.PathElement... elements) 指定されたパスから選択されたレイアウトを返します。パス内の初期レイアウトはこのレイアウトです。static SequenceLayout
sequenceLayout
(long elementCount, MemoryLayout elementLayout) 指定された要素レイアウトおよび要素数を使用して順序レイアウトを作成します。sliceHandle
(MemoryLayout.PathElement... elements) メモリー・セグメントを指定して、指定されたレイアウト・パスによって選択されたレイアウトに対応するsliceを返すメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。static StructLayout
structLayout
(MemoryLayout... elements) 指定されたメンバー・レイアウトを使用して構造体レイアウトを作成します。toString()
このレイアウトの文字列表現を返します。static UnionLayout
unionLayout
(MemoryLayout... elements) 指定されたメンバー・レイアウトを使用してユニオン・レイアウトを作成します。varHandle
(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメントにアクセスするvarハンドルを作成します。パス内の初期レイアウトはこのレイアウトになります。withByteAlignment
(long byteAlignment) このレイアウトと同じ特性を持つメモリー・レイアウトを返しますが、指定された整列制約(バイト単位)を使用します。このレイアウトと同じ特性を持つメモリー・レイアウトを、指定された名前で返します。このレイアウトと同じ特性を持つメモリー・レイアウトを名前なしで返します。
-
メソッドの詳細
-
byteSize
long byteSize()レイアウト・サイズをバイト単位で返します。- 戻り値:
- レイアウト・サイズ(バイト)
-
name
-
withName
MemoryLayout withName(String name) このレイアウトと同じ特性を持つメモリー・レイアウトを、指定された名前で返します。- パラメータ:
name
- レイアウト名- 戻り値:
- このレイアウトと同じ特性を持つが、指定された名前を持つメモリー・レイアウト
- 関連項目:
-
withoutName
MemoryLayout withoutName()このレイアウトと同じ特性を持つメモリー・レイアウトを名前なしで返します。- APIのノート:
- これは、異なる名前を持つが等しくない2つのレイアウトを比較する場合に便利です。
- 戻り値:
- このレイアウトと同じ特性を持つが名前のないメモリー・レイアウト
- 関連項目:
-
byteAlignment
long byteAlignment()このレイアウトに関連付けられているバイト単位の配置制約を返します。レイアウトの位置合せでは、レイアウトのバイト単位の位置合せである2つの
A
の累乗を定義します。A
は、このレイアウトを適切に示すポインタに対して整列する必要があるバイト数です。 このため、:A=1
では、すべての(通常の意味で)がパケットで共有されないことを意味します。A=8
は、aligned (on LP64)、A=4
int aligned、A=2
short alignedなどの単語を意味します。A=64
は、x86/SV ABI (AVX-512データ)で必要とされる最も厳密な位置合せです。
withByteAlignment(long)
を参照してください)に明示的な位置合せ制約が設定されていない場合、このメソッドはこのレイアウトに関連付けられた「自然整列」制約(バイト単位)を返します。- 戻り値:
- このレイアウトに関連付けられた整列制約(バイト単位)
-
withByteAlignment
MemoryLayout withByteAlignment(long byteAlignment) このレイアウトと同じ特性を持つメモリー・レイアウトを返しますが、指定された整列制約(バイト単位)を使用します。- パラメータ:
byteAlignment
- レイアウト整列制約(バイト単位)- 戻り値:
- このレイアウトと同じ特性を持つメモリー・レイアウト。ただし、指定された整列制約(バイト単位)
- 例外:
IllegalArgumentException
-byteAlignment
が2の累乗でない場合
-
scale
long scale(long offset, long index) offset + (byteSize() * index)
を返します。- パラメータ:
offset
- ベース・オフセットindex
- このレイアウトのバイト・サイズでスケーリングする索引- 戻り値:
offset + (byteSize() * index)
- 例外:
IllegalArgumentException
-offset
またはindex
が負の場合ArithmeticException
- 加算または乗算がオーバーフローした場合
-
scaleHandle
MethodHandle scaleHandle()このレイアウトでscale(long, long)
を呼び出すために使用できるメソッド・ハンドルを返します。- 戻り値:
- このレイアウトで
scale(long, long)
を呼び出すために使用できるメソッド・ハンドル
-
byteOffset
long byteOffset(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたレイアウトのオフセットをバイト数で計算します。パス内の初期レイアウトはこのレイアウトです。- パラメータ:
elements
- レイアウト・パス要素- 戻り値:
elements
のレイアウト・パスによって選択されたレイアウトのオフセット(バイト)- 例外:
IllegalArgumentException
- このレイアウトのレイアウト・パスがwell-formedでない場合IllegalArgumentException
- レイアウト・パスに1つ以上の「オープン・パス要素」が含まれる場合IllegalArgumentException
- レイアウト・パスに1つ以上の「パス要素を間接参照」が含まれる場合
-
byteOffsetHandle
MethodHandle byteOffsetHandle(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたレイアウトのオフセット(バイト)を計算するメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。返されるメソッド・ハンドルには次の特性があります:
- 戻り型は
long
です - ベース・オフセットを表す先行する
long
パラメータが1つあります。 long
型の末尾にゼロ個以上のパラメータがあり、指定されたレイアウト・パス内の「オープン・パス要素」ごとに1つずつあります。 これらのパラメータの順序は、指定されたレイアウト・パスでオープン・パス要素が発生する順序に対応します。
メソッド・ハンドルによって返される最後のオフセットは、次のように計算されます:
ここで、offset = b + c_1 + c_2 + ... + c_m + (x_1 * s_1) + (x_2 * s_2) + ... + (x_n * s_n)
b
は、「動的」long
引数として指定されたベース・オフセットを表し、x_1
、x_2
、...x_n
は、「動的」long
引数として指定された順序のインデックスを表します。一方、s_1
、s_2
、...s_n
は、順序の要素レイアウトのサイズから導出されたstaticのstride定数で、c_1
、c_2
、...c_m
は、レイアウト・パスから導出された他のstaticオフセット定数(フィールド・オフセットなど)です。- APIのノート:
- 返されたメソッド・ハンドルは、
byteOffset(PathElement...)
と同様にレイアウト・オフセットをコンピュートするために使用できますが、メソッド・ハンドルの起動時に索引を指定できるため、柔軟性が高くなります。 - パラメータ:
elements
- レイアウト・パス要素- 戻り値:
- 指定されたレイアウト・パスによって選択されたレイアウトのオフセットをバイト単位で計算するメソッド・ハンドル
- 例外:
IllegalArgumentException
- このレイアウトのレイアウト・パスがwell-formedでない場合IllegalArgumentException
- レイアウト・パスに1つ以上の「パス要素を間接参照」が含まれる場合
- 戻り型は
-
varHandle
VarHandle varHandle(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメントにアクセスするvarハンドルを作成します。パス内の初期レイアウトはこのレイアウトになります。返されるvarハンドルには次の特性があります:
- その型は、選択した値レイアウトの「キャリア」から導出されます。
- アクセスされたセグメントを表す
MemorySegment
型の先頭パラメータがあります。 - ベース・オフセットに対応する次の
long
パラメータは、B
として示されます。 long
型の末尾アクセス座標がゼロ以上あり、指定されたレイアウト・パス内の「オープン・パス要素」ごとに1つずつ、それぞれI1, I2, ... In
と示されます。 これらのアクセス座標の順序は、指定されたレイアウト・パスでオープン・パス要素が発生する順序に対応します。
指定されたレイアウト・パス
P
に参照解除要素が含まれていない場合、アクセス操作のオフセットO
は次のように計算されます。O = this.offsetHandle(P).invokeExact(B, I1, I2, ... In);
このメソッドによって返されるvarハンドルを使用してメモリー・セグメントにアクセスする場合、次のチェックが行われます。
- アクセスされるメモリー・セグメントの物理アドレスは、ルート・レイアウト(このレイアウト)の「線形拘束」に従って「連携」である必要があり、そうでない場合、
IllegalArgumentException
がスローされます。 ルート・レイアウトの配置制約は、選択した値レイアウトの配置制約よりも厳密な(次より小さい)になる場合があります。 - アクセス操作(上記のように計算)のオフセットは、アクセスされたメモリー・セグメントの空間境界内にある必要があります。そうでない場合、
IndexOutOfBoundsException
がスローされます。 これは、O + A <= S
の場合です。ここで、O
はアクセスされるオフセット(上記のように計算)、A
は選択したレイアウトのサイズ、S
はアクセスされるメモリー・セグメントのサイズです。 - アクセスされるメモリー・セグメントは、アクセス操作を実行しているスレッドから
accessible
である必要があり、そうでない場合、WrongThreadException
がスローされます。 - 書込み操作の場合、アクセスされるメモリー・セグメントを
read only
にしないでください。そうしないと、IllegalArgumentException
がスローされます。 - アクセスされるセグメントに関連付けられたscopeは、aliveである必要があり、そうでない場合、
IllegalStateException
がスローされます。
選択したレイアウトがアドレス・レイアウトの場合、戻されたvarハンドルで
VarHandle.get(Object...)
をコールすると、新しいメモリー・セグメントが返されます。 セグメントはグローバル・スコープに関連付けられています。 さらに、セグメントのサイズは、アドレス・レイアウトに「ターゲット・レイアウト」があるかどうかによって異なります。 具体的には、次の条件を満たしている必要があります。- アドレス・レイアウトにターゲット・レイアウト
T
がある場合、返されるセグメントのサイズはT.byteSize()
です。 - それ以外の場合、アドレス・レイアウトにはターゲット・レイアウトがなく、返されるセグメントのサイズはzeroです。
VarHandle.set(Object...)
をコールしてIllegalArgumentException
をスローできます。指定されたレイアウト・パスにサイズ
m
があり、位置k
(ここで、k <= m
)に参照解除パス要素が含まれている場合、2つのレイアウト・パスP
およびP'
が導出されます。ここで、Pには0からk - 1
までのすべてのパス要素が含まれ、P'
にはk + 1
からm
(もしあれば)までのすべてのパス要素が含まれます。 次に、返されるvarハンドルは次のように計算されます。VarHandle baseHandle = this.varHandle(P); MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get(); VarHandle targetHandle = target.varHandle(P); targetHandle = MethodHandles.insertCoordinates(targetHandle, 1, 0L); // always access nested targets at offset 0 targetHandle = MethodHandles.collectCoordinates(targetHandle, 0, baseHandle.toMethodHandle(VarHandle.AccessMode.GET));
たとえば、次のように構築された
GroupLayout
インスタンスで表されるメモリー・レイアウトを考えます:GroupLayout grp = java.lang.foreign.MemoryLayout.structLayout( MemoryLayout.paddingLayout(4), ValueLayout.JAVA_INT.withOrder(ByteOrder.BIG_ENDIAN).withName("value") );
value
という名前のメンバー・レイアウトにアクセスするには、次のようにvarハンドルを作成します。VarHandle handle = grp.varHandle(PathElement.groupElement("value")); //(MemorySegment, long) -> int
- APIのノート:
- 結果のvarハンドルには、メモリー・レイアウトから導出されるすべてのvarハンドルに共通する特定の「アクセス・モード制限」があります。
- パラメータ:
elements
- レイアウト・パス要素- 戻り値:
- 指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメントにアクセスするvarハンドル
- 例外:
IllegalArgumentException
- このレイアウトのレイアウト・パスがwell-formedでない場合IllegalArgumentException
- 指定されたパスで選択されたレイアウトが「値レイアウト」でない場合
-
arrayElementVarHandle
VarHandle arrayElementVarHandle(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメント内の隣接する要素にアクセスするvarハンドルを作成します。アクセスされた要素にはこのレイアウトがあり、パスの初期レイアウトはこのレイアウトです。返されるvarハンドルには次の特性があります:
- その型は、選択した値レイアウトの「キャリア」から導出されます。
- アクセスされたセグメントを表す
MemorySegment
型の先頭パラメータがあります。 - ベース・オフセットに対応する次の
long
パラメータは、B
として示されます。 - 配列索引に対応する次の
long
パラメータで、I0
と示されます。 配列インデックスは、アクセスされたオフセットをこのレイアウト・サイズでスケールするために使用されます。 long
型の末尾アクセス座標がゼロ以上あり、指定されたレイアウト・パス内の「オープン・パス要素」ごとに1つずつ、それぞれI1, I2, ... In
と示されます。 これらのアクセス座標の順序は、指定されたレイアウト・パスでオープン・パス要素が発生する順序に対応します。
指定されたレイアウト・パス
P
に参照解除要素が含まれていない場合、アクセス操作のオフセットO
は次のように計算されます。O = this.offsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);
より正式には、このメソッドは次の
varHandle(PathElement...)
から取得できます。MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())
- APIのノート:
- 先頭の索引座標
I0
はどの順序レイアウトにもバインドされないため、負でない値を想定できます。 - 結果のオフセット計算がオーバーフローしない、または計算されたオフセットがアクセスされたメモリー・セグメントの空間境界外に収まらない場合。 そのため、このメソッドから返されるvarハンドルは、「可変長配列」にアクセスする場合に特に役立ちます。 - パラメータ:
elements
- レイアウト・パス要素- 戻り値:
- 指定されたレイアウト・パスによって選択されたオフセットで、メモリー・セグメント内の隣接する要素にアクセスするvarハンドル
- 例外:
IllegalArgumentException
- このレイアウトのレイアウト・パスがwell-formedでない場合IllegalArgumentException
- 指定されたパスで選択されたレイアウトが「値レイアウト」でない場合
-
sliceHandle
MethodHandle sliceHandle(MemoryLayout.PathElement... elements) メモリー・セグメントを指定して、指定されたレイアウト・パスによって選択されたレイアウトに対応するsliceを返すメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。返されるメソッド・ハンドルには次の特性があります:
- 戻り型は
MemorySegment
です - スライスするメモリー・セグメントに対応する
MemorySegment
型の先頭パラメータがあります。 - ベース・オフセットに対応する、次の
long
パラメータ long
型の末尾にゼロ個以上のパラメータがあり、指定されたレイアウト・パス内の「オープン・パス要素」ごとに1つずつあります。 これらのパラメータの順序は、指定されたレイアウト・パスでオープン・パス要素が発生する順序に対応します。
返されたセグメントのオフセット
O
は、指定されたパス要素を使用して構築された「バイト・オフセット・ハンドル」の呼出しによって計算される。このメソッドによって返されたメソッド・ハンドルを使用してメモリー・セグメントのスライスを計算する場合、次のチェックが行われます。
- アクセスされるメモリー・セグメントの物理アドレスは、ルート・レイアウト(このレイアウト)の「線形拘束」に従って「連携」である必要があります。そうでない場合、
IllegalArgumentException
が発行されます。 ルート・レイアウトの配置制約は、選択したレイアウトの配置制約よりも厳密な(次より小さい)になる場合があります。 - スライス操作(上記のように計算)の開始オフセットは、アクセスされたメモリー・セグメントの空間境界内にある必要があります。そうでない場合、
IndexOutOfBoundsException
がスローされます。 これは、O + A <= S
の場合です。ここで、O
はスライス操作(上記のように計算)の開始オフセット、A
は選択したレイアウトのサイズ、S
はアクセスされたメモリー・セグメントのサイズです。
- APIのノート:
- 戻されたメソッド・ハンドルは、
MemorySegment.asSlice(long, long)
と同様にメモリー・セグメント・スライスの取得に使用できますが、メソッド・ハンドルの起動時に索引を指定できるため、より柔軟に取得できます。 - パラメータ:
elements
- レイアウト・パス要素- 戻り値:
- 指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメントをスライスするために使用されるメソッド・ハンドル
- 例外:
IllegalArgumentException
- このレイアウトのレイアウト・パスがwell-formedでない場合IllegalArgumentException
- レイアウト・パスに1つ以上の「パス要素を間接参照」が含まれる場合
- 戻り型は
-
select
MemoryLayout select(MemoryLayout.PathElement... elements) 指定されたパスから選択されたレイアウトを返します。パス内の初期レイアウトはこのレイアウトです。- パラメータ:
elements
- レイアウト・パス要素- 戻り値:
elements
のレイアウト・パスによって選択されたレイアウト- 例外:
IllegalArgumentException
- このレイアウトのレイアウト・パスがwell-formedでない場合IllegalArgumentException
- レイアウト・パスに1つ以上の「パス要素を間接参照」が含まれる場合IllegalArgumentException
- レイアウト・パスに、1つ以上の順序要素インデックスを選択する1つ以上のパス要素が含まれている場合(MemoryLayout.PathElement.sequenceElement(long)
やMemoryLayout.PathElement.sequenceElement(long, long)
など)
-
equals
boolean equals(Object other) 指定されたオブジェクトをこのレイアウトと比較し、等価性を維持します。 指定されたオブジェクトもレイアウトであり、このレイアウトと等しい場合にのみ、true
を返します。 2つのレイアウトが同じ種類で、サイズ、名前および整列制約が同じ場合、2つのレイアウトは同じとみなされます。 また、レイアウトの種類に応じて、追加の条件を満たす必要があります:- 2つの値レイアウトは、orderと「キャリア」が同じ場合、等しいとみなされます。 さらに、2つのアドレス・レイアウトが同じ「ターゲット・レイアウト」を持つ場合、同じとみなされます。
- 2つの順序レイアウトは、同じ要素数(
SequenceLayout.elementCount()
を参照してください)を持ち、その要素レイアウト(SequenceLayout.elementLayout()
を参照してください)も同じである場合、等しいとみなされます。 - 2つのグループ・レイアウトは、同じタイプ(「
StructLayout
」、「UnionLayout
」を参照してください。)であり、メンバー・レイアウト(GroupLayout.memberLayouts()
を参照してください)も同じである場合、同じとみなされます。
-
hashCode
-
toString
-
paddingLayout
static PaddingLayout paddingLayout(long byteSize) 指定されたバイト・サイズでパディング・レイアウトを作成します。 返されるレイアウトの線形拘束は1です。 そのため、サイズに関係なく、explicit整列制約がない場合、パディング・レイアウトは、ネストされるグループまたは順序レイアウトの自然整列には影響しません。- パラメータ:
byteSize
- パディング・サイズ(バイトで表されます。)- 戻り値:
- 新しいセレクタ・レイアウト
- 例外:
IllegalArgumentException
-byteSize <= 0
の場合
-
sequenceLayout
static SequenceLayout sequenceLayout(long elementCount, MemoryLayout elementLayout) 指定された要素レイアウトおよび要素数を使用して順序レイアウトを作成します。- パラメータ:
elementCount
- シーケンス要素数elementLayout
- 順序要素のレイアウト- 戻り値:
- 指定された要素のレイアウトとサイズを持つ新しいシーケンス・レイアウト
- 例外:
IllegalArgumentException
-elementCount
が負の場合IllegalArgumentException
-elementLayout.byteSize() * elementCount
がオーバーフローした場合IllegalArgumentException
-elementLayout.byteSize() % elementLayout.byteAlignment() != 0
の場合
-
structLayout
static StructLayout structLayout(MemoryLayout... elements) 指定されたメンバー・レイアウトを使用して構造体レイアウトを作成します。- APIのノート:
- このファクトリでは、追加の「パディング・レイアウト」要素を挿入しても、要素レイアウトは自動的に整列されません。 したがって、次の構造体レイアウトの作成は例外で失敗します:
structLayout(JAVA_SHORT, JAVA_INT);
structLayout(JAVA_SHORT, MemoryLayout.paddingLayout(2), JAVA_INT);
structLayout(JAVA_SHORT, JAVA_INT.withByteAlignment(2));
- パラメータ:
elements
- 構造体レイアウトのメンバー・レイアウト- 戻り値:
- 指定されたメンバー・レイアウトを持つ構造体レイアウト
- 例外:
IllegalArgumentException
- メンバー・レイアウトの「バイト・サイズ」の合計がオーバーフローした場合IllegalArgumentException
-elements
内のメンバー・レイアウトが、位置合せ制約と互換性がないオフセット(構造体レイアウトの開始に対する相対)で発生する場合
-
unionLayout
static UnionLayout unionLayout(MemoryLayout... elements) 指定されたメンバー・レイアウトを使用してユニオン・レイアウトを作成します。- パラメータ:
elements
- 組合レイアウトのメンバー・レイアウト- 戻り値:
- 指定されたメンバー・レイアウトを持つ和集合レイアウト
-