インタフェースMemoryLayout
- 既知のすべてのサブインタフェース:
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()から導出されたキャリア・タイプTL.byteAlignment()から導出された整列制約AL.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(points, 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このレイアウトに関連付けられているバイト単位の配置制約を返します。longbyteOffset(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたレイアウトのオフセットをバイト数で計算します。パス内の初期レイアウトはこのレイアウトです。byteOffsetHandle(MemoryLayout.PathElement... elements) 指定されたレイアウト・パスによって選択されたレイアウトのオフセット(バイト)を計算するメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。longbyteSize()レイアウト・サイズをバイト単位で返します。boolean指定されたオブジェクトをこのレイアウトと比較し、等価性を維持します。inthashCode()このレイアウトのハッシュ・コード値を返します。name()このレイアウトに関連付けられている名前(もしあれば)を返します。static PaddingLayoutpaddingLayout(long byteSize) 指定されたバイト・サイズでパディング・レイアウトを作成します。longscale(long offset, long index) offset + (byteSize() * index)を返します。このレイアウトでscale(long, long)を呼び出すために使用できるメソッド・ハンドルを返します。select(MemoryLayout.PathElement... elements) 指定されたパスから選択されたレイアウトを返します。パス内の初期レイアウトはこのレイアウトです。static SequenceLayoutsequenceLayout(long elementCount, MemoryLayout elementLayout) 指定された要素レイアウトおよび要素数を使用して順序レイアウトを作成します。sliceHandle(MemoryLayout.PathElement... elements) メモリー・セグメントを指定して、指定されたレイアウト・パスによって選択されたレイアウトに対応するsliceを返すメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。static StructLayoutstructLayout(MemoryLayout... elements) 指定されたメンバー・レイアウトを使用して構造体レイアウトを作成します。toString()このレイアウトの文字列表現を返します。static UnionLayoutunionLayout(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=4int aligned、A=2short 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オフセット定数(フィールド・オフセットなど)です。任意の動的引数
x_iの場合、0 <= x_i < size_iである必要があります。size_iは、x_iに関連付けられたオープン・パス要素のサイズです。 それ以外の場合、戻されたメソッド・ハンドルはIndexOutOfBoundsExceptionをスローします。 また、bの値は、offsetの計算がオーバーフローしないか、戻されたメソッド・ハンドルがArithmeticExceptionをスローするようにする必要があります。- 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.byteOffsetHandle(P).invokeExact(B, I1, I2, ... In);このメソッドによって返されるvarハンドルを使用してメモリー・セグメントにアクセスする場合、次のチェックが行われます。
- アクセスされるメモリー・セグメントの物理アドレスは、ルート・レイアウト(このレイアウト)の「線形拘束」に従って「連携」である必要があり、そうでない場合、
IllegalArgumentExceptionがスローされます。 ルート・レイアウトの配置制約は、選択した値レイアウトの配置制約よりも厳密な(次より小さい)になる場合があります。 - アクセス操作は、アクセスしたメモリー・セグメントの空間境界内に収まる必要があります。そうしないと、
IndexOutOfBoundsExceptionがスローされます。 これは、B + A <= Sの場合です (ここで、Bはベース・オフセット(前述の定義)、Aはこのレイアウトのサイズ、Sはアクセスされたメモリー・セグメントのサイズ)。 このレイアウトのサイズは、アクセスされたレイアウト(例:構造体メンバーにアクセスする場合)のサイズよりも「大きい」である場合があります。 - 指定されたレイアウト・パスに、サイズが
Sのオープン・パス要素がある場合、対応する後続のlong座標値Iを0 <= I < Sにするか、IndexOutOfBoundsExceptionをスローします。 - アクセスされるメモリー・セグメントは、アクセス操作を実行しているスレッドから
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とQが導出されます。Pには0からk - 1までのすべてのパス要素が含まれ、Qにはk + 1からm(k == mの場合、Qを空のレイアウト・パスにできます)までのすべてのパス要素が含まれます。 次に、返されるvarハンドルは次のように計算されます。(前述は、指定されたレイアウト・パスに複数の間接参照パス要素が含まれる場合に、簡単に一般化できます。)。VarHandle baseHandle = this.varHandle(P); MemoryLayout target = ((AddressLayout)this.select(P)).targetLayout().get(); VarHandle targetHandle = target.varHandle(Q); 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.byteOffsetHandle(P).invokeExact(this.scale(B, I0), I1, I2, ... In);さらに、このメソッドによって返されるメソッド・ハンドルは、次のように
varHandle(PathElement...)から取得されます:MethodHandles.collectCoordinates(varHandle(elements), 1, scaleHandle())このメソッドによって返されるvarハンドルを使用してメモリー・セグメントにアクセスする場合、次のチェックが行われます。
- アクセスされるメモリー・セグメントの物理アドレスは、ルート・レイアウト(このレイアウト)の「線形拘束」に従って「連携」である必要があり、そうでない場合、
IllegalArgumentExceptionがスローされます。 ルート・レイアウトの配置制約は、選択した値レイアウトの配置制約よりも厳密な(次より小さい)になる場合があります。 - アクセス操作は、アクセスしたメモリー・セグメントの空間境界内に収まる必要があります。そうしないと、
IndexOutOfBoundsExceptionがスローされます。 これは、B + A <= Sの場合です (ここで、Bはベース・オフセット(前述の定義)、Aはこのレイアウトのサイズ、Sはアクセスされたメモリー・セグメントのサイズ)。 このレイアウトのサイズは、アクセスされたレイアウト(例:構造体メンバーにアクセスする場合)のサイズよりも「大きい」である場合があります。 - 指定されたレイアウト・パスに、サイズが
Sのオープン・パス要素がある場合、対応する後続のlong座標値Iを0 <= I < Sにするか、IndexOutOfBoundsExceptionをスローします。 - アクセスされるメモリー・セグメントは、アクセス操作を実行しているスレッドから
accessibleである必要があり、そうでない場合、WrongThreadExceptionがスローされます。 - 書込み操作の場合、アクセスされるメモリー・セグメントを
read onlyにしないでください。そうしないと、IllegalArgumentExceptionがスローされます。 - アクセスされるセグメントに関連付けられたscopeは、aliveである必要があり、そうでない場合、
IllegalStateExceptionがスローされます。
- APIのノート:
- 先頭の索引座標
I0はどの順序レイアウトにもバインドされないため、負でない値を想定できます。 - 結果のオフセット計算がオーバーフローしない、または計算されたオフセットがアクセスされたメモリー・セグメントの空間境界外に収まらない場合。 そのため、このメソッドから返されるvarハンドルは、「可変長配列」にアクセスする場合に特に役立ちます。 - パラメータ:
elements- レイアウト・パス要素- 戻り値:
- 指定されたレイアウト・パスによって選択されたオフセットで、メモリー・セグメント内の隣接する要素にアクセスするvarハンドル
- スロー:
IllegalArgumentException- このレイアウトのレイアウト・パスがwell-formedでない場合IllegalArgumentException- 指定されたパスで選択されたレイアウトが「値レイアウト」でない場合
-
sliceHandle
MethodHandle sliceHandle(MemoryLayout.PathElement... elements) メモリー・セグメントを指定して、指定されたレイアウト・パスによって選択されたレイアウトに対応するsliceを返すメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。返されるメソッド・ハンドルには次の特性があります:
- 戻り型は
MemorySegmentです - スライスするメモリー・セグメントに対応する
MemorySegment型の先頭パラメータがあります。 - ベース・オフセットに対応する、次の
longパラメータ long型の末尾にゼロ個以上のパラメータがあり、指定されたレイアウト・パス内の「オープン・パス要素」ごとに1つずつあります。 これらのパラメータの順序は、指定されたレイアウト・パスでオープン・パス要素が発生する順序に対応します。
返されたセグメントのオフセット
Oは、指定されたパス要素を使用して構築された「バイト・オフセット・ハンドル」の呼出しによって計算される。このメソッドによって返されたメソッド・ハンドルを使用してメモリー・セグメントのスライスを計算する場合、次のチェックが行われます。
- アクセスされるメモリー・セグメントの物理アドレスは、ルート・レイアウト(このレイアウト)の「線形拘束」に従って「連携」である必要があります。そうでない場合、
IllegalArgumentExceptionが発行されます。 ルート・レイアウトの配置制約は、選択したレイアウトの配置制約よりも厳密な(次より小さい)になる場合があります。 - スライス操作は、アクセスされたメモリー・セグメントの空間境界内に収まる必要があります。そうしないと、
IndexOutOfBoundsExceptionがスローされます。 これは、B + A <= Sの場合です (ここで、Bはベース・オフセット(前述の定義)、Aはこのレイアウトのサイズ、Sはアクセスされたメモリー・セグメントのサイズ)。 このレイアウトのサイズは、アクセスされたレイアウト(例:構造体メンバーにアクセスする場合)のサイズよりも「大きい」である場合があります。 - 指定されたレイアウト・パスに、サイズが
Sのオープン・パス要素がある場合、対応する後続のlong座標値Iを0 <= I < Sにするか、IndexOutOfBoundsExceptionをスローします。
- 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- 組合レイアウトのメンバー・レイアウト- 戻り値:
- 指定されたメンバー・レイアウトを持つ和集合レイアウト
-