インタフェースMemoryLayout

既知のすべてのサブインタフェース:
AddressLayout, GroupLayout, PaddingLayout, SequenceLayout, StructLayout, UnionLayout, ValueLayout, ValueLayout.OfBoolean, ValueLayout.OfByte, ValueLayout.OfChar, ValueLayout.OfDouble, ValueLayout.OfFloat, ValueLayout.OfInt, ValueLayout.OfLong, ValueLayout.OfShort

public sealed interface MemoryLayout permits SequenceLayout, GroupLayout, PaddingLayout, ValueLayout
メモリー・レイアウトは、メモリー・セグメントの内容を記述します。

レイアウト階層には、指定されたサイズと種類の値を表すために使用される「値レイアウト」と、コンテンツが無視されるメモリー・セグメントの一部を表すために使用される「パディング・レイアウト」の2つのリーフがあります。これらのリーフは主に配置上の理由から存在します。 ValueLayout.JAVA_INTValueLayout.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を掛けた値です
  • サイズがS1S2、... SnであるM1M2、... Mnのメンバー・レイアウトを含む構造体レイアウトのサイズは、それぞれS1 + S2 + ... + Snです
  • サイズがS1S2、... Snのメンバー・レイアウトM1M2、... Mnを含む連結レイアウトUのサイズは、max(S1, S2, ... Sn)です。

さらに、すべてのレイアウトには、次のように定義された「自然整列」 (バイトで表されます)があります:

  • パディング・レイアウトの自然な配置は1です
  • サイズがNの値レイアウトの自然な位置合せは、Nです
  • 要素レイアウトがEである順序レイアウトの自然な位置合せは、Eの配置です
  • 整列がそれぞれA1A2、... 「1つの」であるメンバー・レイアウトM1M2、... Mnを含むグループ・レイアウトの自然整列は、max(A1, A2 ... An)です。
レイアウトの配置は、必要に応じて (withByteAlignment(long)を参照してください)で上書きできます。これは、より弱い位置合わせ拘束またはより強い位置合わせ拘束を持つレイアウトを記述するのに便利です。

レイアウト・パス

「レイアウト・パス」は、他のレイアウトにネストされているレイアウトを明確に選択するために使用します。 レイアウト・パスは通常、1つ以上の「パス要素」のシーケンスとして表されます。 (レイアウト・パスのより正式な定義は、belowで提供されています。)。

レイアウト・パスは、次の目的で使用できます:

  • 任意のネストされたレイアウトのoffsetsを取得
  • 選択したレイアウトに対応する値にアクセスするために使用できる「varハンドル」を取得
  • 「選択」は、任意のネストされたレイアウトです。

たとえば、前述の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に対して整形式とみなされます:

初期レイアウトC_0に対して整形式ではないレイアウト・パスPを指定しようとすると、IllegalArgumentExceptionになります。

アクセス・モード制限

varHandle(PathElement...)またはValueLayout.varHandle()によって返されるvarハンドルには、選択したレイアウトLから導出される特定のアクセス特性があります。
  • L.carrier()から導出されたキャリア・タイプT
  • L.byteAlignment()から導出された整列制約A
  • L.byteSize()から導出されたアクセス・サイズS
前述の特性に応じて、返されるvarハンドルには特定の「アクセス・モード制限」が含まれる場合があります。 整列制約Aがアクセス・サイズSと互換性がある場合、つまりA >= Sの場合、varハンドルは「連携」であるとします。 整列されたvarハンドルは、次のアクセス・モードをサポートすることが保証されています。
  • すべてのTの読取り/書込みアクセス・モード。 32ビット・プラットフォームでは、longdouble、およびMemorySegmentのアクセス・モードgetおよびsetがサポートされていますが、「Java言語仕様」のセクション17.7に説明されているように、ワード引き裂きにつながる可能性があります。
  • int, long, float, doubleおよびMemorySegmentのアトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードの追加タイプがサポートされる場合があります。)
  • intlongおよびMemorySegmentの数値アトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードに対して追加の数値型をサポートする場合があります。)
  • intlongおよびMemorySegmentのビット単位のアトミック更新アクセス・モード。 (JDKの将来のメジャー・プラットフォーム・リリースでは、現在サポートされていない特定のアクセス・モードに対して追加の数値型をサポートする場合があります。)
TfloatdoubleまたはMemorySegmentの場合、アトミック更新アクセス・モードはビット単位の表現(それぞれFloat.floatToRawIntBits(float)Double.doubleToRawLongBits(double)およびMemorySegment.address()を参照してください。)を使用して値を比較します。

または、VARハンドルは、その位置合せ制約Aがアクセス・サイズSと互換性がない場合(つまり、A < Sの場合)は「位置なし」です。 整列されていないvarハンドルは、getおよびsetアクセス・モードのみをサポートします。 他のすべてのアクセス・モードでは、UnsupportedOperationExceptionがスローされます。 さらに、サポートされているものの、アクセス・モードgetおよびsetはワード・リングにつながる可能性があります。

可変長配列の操作

順序レイアウトを使用して、サイズが「静的に」であることがわかっている配列の内容を記述する方法を見てきました。 ただし、配列サイズが認識されるのは「動的に」のみです。 このような配列を「可変長配列」と呼びます。 可変長配列には、次の2つの一般的な種類があります。
  • サイズが無関係な変数またはパラメータの値に依存する「トップレベル」可変長配列。
  • 構造体内の可変長配列「ネスト」。そのサイズは、包含構造体内の他のフィールドの値に依存します。
可変長配列はシーケンス・レイアウトを使用して直接モデル化することはできませんが、クライアントは、次の項に示すように、varハンドルを使用して可変長配列の要素への構造化されたアクセスを享受できます。

トップレベルの可変長配列

Cでは、次の構造体宣言を考慮してください:
typedef struct {
    int x;
    int y;
} Point;
前述のコードでは、点は2つの座標(それぞれ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")
);
ポイントの配列を作成してアクセスする必要があることがわかっているため、可変長配列をモデリングするシーケンス・レイアウトを作成し、シーケンス・レイアウトから必要なアクセスvarハンドルを導出することをお薦めします。 しかし、可変長配列のサイズが不明なため、このアプローチは問題になります。 かわりに、可変長配列の要素への構造化されたアクセスを提供するvarハンドルは、次に示すように、配列要素(例:点レイアウト)を記述するレイアウトから直接取得できます。
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;
前述のコードでは、ポリゴンはサイズ(ポリゴンのエッジ数)およびポイント(ポリゴンの頂点ごとに1つ)の配列としてモデル化されています。 頂点の数は、ポリゴンのエッジの数によって異なります。 そのため、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です。
シール済クラス階層グラフ:
MemoryLayoutのシール済クラス階層グラフMemoryLayoutのシール済クラス階層グラフ
導入されたバージョン:
22
  • ネストされたクラスのサマリー

    ネストされたクラス
    修飾子と型
    インタフェース
    説明
    static interface 
  • メソッドのサマリー

    修飾子と型
    メソッド
    説明
    指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメント内の隣接する要素にアクセスするvarハンドルを作成します。アクセスされた要素にはこのレイアウトがあり、パスの初期レイアウトはこのレイアウトです。
    long
    このレイアウトに関連付けられているバイト単位の配置制約を返します。
    long
    指定されたレイアウト・パスによって選択されたレイアウトのオフセットをバイト数で計算します。パス内の初期レイアウトはこのレイアウトです。
    指定されたレイアウト・パスによって選択されたレイアウトのオフセット(バイト)を計算するメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。
    long
    レイアウト・サイズをバイト単位で返します。
    boolean
    equals(Object other)
    指定されたオブジェクトをこのレイアウトと比較し、等価性を維持します。
    int
    このレイアウトのハッシュ・コード値を返します。
    このレイアウトに関連付けられている名前(もしあれば)を返します。
    paddingLayout(long byteSize)
    指定されたバイト・サイズでパディング・レイアウトを作成します。
    long
    scale(long offset, long index)
    offset + (byteSize() * index)を返します。
    このレイアウトでscale(long, long)を呼び出すために使用できるメソッド・ハンドルを返します。
    指定されたパスから選択されたレイアウトを返します。パス内の初期レイアウトはこのレイアウトです。
    sequenceLayout(long elementCount, MemoryLayout elementLayout)
    指定された要素レイアウトおよび要素数を使用して順序レイアウトを作成します。
    メモリー・セグメントを指定して、指定されたレイアウト・パスによって選択されたレイアウトに対応するsliceを返すメソッド・ハンドルを作成します。パス内の初期レイアウトはこのレイアウトです。
    指定されたメンバー・レイアウトを使用して構造体レイアウトを作成します。
    このレイアウトの文字列表現を返します。
    指定されたメンバー・レイアウトを使用してユニオン・レイアウトを作成します。
    指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメントにアクセスするvarハンドルを作成します。パス内の初期レイアウトはこのレイアウトになります。
    withByteAlignment(long byteAlignment)
    このレイアウトと同じ特性を持つメモリー・レイアウトを返しますが、指定された整列制約(バイト単位)を使用します。
    このレイアウトと同じ特性を持つメモリー・レイアウトを、指定された名前で返します。
    このレイアウトと同じ特性を持つメモリー・レイアウトを名前なしで返します。
  • メソッドの詳細

    • byteSize

      long byteSize()
      レイアウト・サイズをバイト単位で返します。
      戻り値:
      レイアウト・サイズ(バイト)
    • name

      Optional<String> 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_1x_2、... x_nは、「動的」 long引数として指定された順序のインデックスを表します。一方、s_1s_2、... s_nは、順序の要素レイアウトのサイズから導出されたstaticのstride定数で、c_1c_2、... c_mは、レイアウト・パスから導出された他のstaticオフセット定数(フィールド・オフセットなど)です。

      任意の動的引数x_iの場合、0 <= x_i < size_iである必要があります。size_iは、x_iに関連付けられたオープン・パス要素のサイズです。 それ以外の場合、戻されたメソッド・ハンドルはIndexOutOfBoundsExceptionをスローします。

      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座標値I0 <= 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および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.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座標値I0 <= 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座標値I0 <= I < Sにするか、IndexOutOfBoundsExceptionをスローします。

      APIのノート:
      戻されたメソッド・ハンドルは、MemorySegment.asSlice(long, long)と同様にメモリー・セグメント・スライスの取得に使用できますが、メソッド・ハンドルの起動時に索引を指定できるため、より柔軟に取得できます。
      パラメータ:
      elements - レイアウト・パス要素
      戻り値:
      指定されたレイアウト・パスによって選択されたオフセットでメモリー・セグメントをスライスするために使用されるメソッド・ハンドル
      例外:
      IllegalArgumentException - このレイアウトのレイアウト・パスがwell-formedでない場合
      IllegalArgumentException - レイアウト・パスに1つ以上の「パス要素を間接参照」が含まれる場合
    • select

      指定されたパスから選択されたレイアウトを返します。パス内の初期レイアウトはこのレイアウトです。
      パラメータ:
      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つのレイアウトは同じとみなされます。 また、レイアウトの種類に応じて、追加の条件を満たす必要があります:
      オーバーライド:
      equals、クラスObject
      パラメータ:
      other - このレイアウトと等しいかどうかを比較するオブジェクト
      戻り値:
      指定されたオブジェクトがこのレイアウトと等しい場合はtrue
      関連項目:
    • hashCode

      int hashCode()
      このレイアウトのハッシュ・コード値を返します。
      オーバーライド:
      hashCode、クラスObject
      戻り値:
      このレイアウトのハッシュ・コード値
      関連項目:
    • toString

      String toString()
      このレイアウトの文字列表現を返します。
      オーバーライド:
      toString、クラスObject
      戻り値:
      このレイアウトの文字列表現
    • 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 - 組合レイアウトのメンバー・レイアウト
      戻り値:
      指定されたメンバー・レイアウトを持つ和集合レイアウト