X-array

通常の配列のフィールドを定義するときは、インデックスの範囲、つまり次元ごとのオカレンス数を正確に指定する必要があります。ランタイムには配列のすべてのフィールドがデフォルトで存在するため、追加の割り当て操作を行うことなく、定義した各オカレンスにアクセスできます。サイズのレイアウトは変更できません。したがって、フィールドのオカレンスを追加することも削除することもできません。

一方、必要なオカレンス数が開発時にわからないため、ランタイムに配列のフィールド数を柔軟に増減したい場合は、X-array(eXtensible array:拡張可能な配列)と呼ばれているものを使用します。

X-array では、ランタイムにサイズ変更できるため、メモリをより効率よく管理できます。例えば、大量の配列オカレンスを短期間だけ使用してから、アプリケーションが配列を使用しなくなった時点でメモリを削減することができます。

このドキュメントでは、次のトピックについて説明します。


定義

X-array とは、コンパイル時にオカレンス数を定義しない配列のことです。X-array は、DEFINE DATA ステートメント内で、少なくとも 1 つの次元のインデックス範囲に、アスタリスク(*)を使用して定義します。インデックス定義内のアスタリスク文字(*)は、プログラムの実行時に特定の値を割り当てることができる、変更可能なインデックス範囲を表します。上限または下限のいずれかのみを可変として定義できます。両方を定義することはできません。

X-array は、(固定の)配列を定義できる場所にならどこにでも、つまり、任意のレベルで、またはインデックス付きのグループとして定義できます。ただし、データベースビューのMU-/PE- フィールドへのアクセスには使用できません。複数次元の配列では、定数と変更可能な境界を組み合わせて使用できます。

例:

DEFINE DATA LOCAL
1 #X-ARR1 (A5/1:*)          /* lower bound is fixed at 1, upper bound is variable
1 #X-ARR2 (A5/*)            /* shortcut for (A5/1:*)
1 #X-ARR3 (A5/*:100)        /* lower bound is variable, upper bound is fixed at 100
1 #X-ARR4 (A5/1:10,1:*)     /* 1st dimension has a fixed index range with (1:10)
END-DEFINE                  /* 2nd dimension has fixed lower bound 1 and variable upper bound

X-array のストレージ管理

X-array のオカレンス数は、アクセスする前に明示的に割り当てる必要があります。次元のオカレンス数を増減するには、EXPANDRESIZEREDUCE の各ステートメントを使用します。

ただし、X-array の次元数(1、2、または 3 次元)は変更できません。

例:

DEFINE DATA LOCAL
1 #X-ARR(I4/10:*)
END-DEFINE
EXPAND ARRAY #X-ARR TO (10:10000) 
/* #X-ARR(10) to #X-ARR(10000) are accessible
WRITE *LBOUND(#X-ARR)                  /* is 10
   *UBOUND(#X-ARR)                     /* is 10000
   *OCCURRENCE(#X-ARR)                 /* is 9991
#X-ARR(*) := 4711                      /* same as #X-ARR(10:10000) := 4711
/* resize array from current lower bound=10 to upper bound =1000 
RESIZE ARRAY #X-ARR TO (*:1000)
/* #X-ARR(10) to #X-ARR(1000) are accessible
/* #X-ARR(1001) to #X-ARR(10000) are released
WRITE *LBOUND(#X-ARR)                  /* is 10
   *UBOUND(#X-ARR)                     /* is 1000
   *OCCURRENCE(#X-ARR)                 /* is 991
/* release all occurrences
REDUCE ARRAY #X-ARR TO  0
WRITE *OCCURRENCE(#X-ARR)              /* is 0

X-Group 配列のストレージ管理

X-group 配列のオカレンス数を増減する場合、独立した次元と従属した次元を区別する必要があります。

直接指定されている(継承していない)X-group 配列または X-array の次元は、独立しています。

直接指定されていない(上位の配列から継承している)X-group 配列または X-array の次元は、従属しています。

X-array の独立した次元のみ、EXPANDRESIZEREDUCE の各ステートメントで変更できます。従属した次元の変更は、その次元を独立した次元として所有している X-group 配列の名前を使用して行う必要があります。

独立した次元と従属した次元の例:

DEFINE  DATA LOCAL                                    
1 #X-GROUP-ARR1(1:*)                  /* (1:*)        
  2 #X-ARR1    (I4)                   /* (1:*)        
  2 #X-ARR2    (I4/2:*)               /* (1:*,2:*)    
  2 #X-GROUP-ARR2                     /* (1:*)        
    3 #X-ARR3  (I4)                   /* (1:*)        
    3 #X-ARR4  (I4/3:*)               /* (1:*,3:*)    
    3 #X-ARR5  (I4/4:*, 5:*)          /* (1:*,4:*,5:*)
END-DEFINE

以下の表は、上記のプログラム内の各次元が独立しているのか従属しているのかを示しています。

Name 従属した次元 独立した次元
#X-GROUP-ARR1   (1:*)
#X-ARR1 (1:*)  
#X-ARR2 (1:*) (2:*)
#X-GROUP-ARR2 (1:*)  
#X-ARR3 (1:*)  
#X-ARR4 (1:*) (3:*)
#X-ARR5 (1:*) (4:*,5:*)

従属した次元に使用できる添字表記は、単一のアスタリスク(*)、アスタリスクで定義した範囲(*:*)、または定義済みの添字範囲のみです。

これは、従属した次元の境界は変更できないことを示しています。

従属した次元のオカレンス数は、対応するグループ配列を操作することによってのみ変更できます。

EXPAND ARRAY #X-GROUP-ARR1 TO (1:11)       /* #X-ARR1(1:11) are allocated
                                           /* #X-ARR3(1:11) are allocated
EXPAND ARRAY #X-ARR2 TO (*:*, 2:12)        /* #X-ARR2(1:11, 2:12) are allocated
EXPAND ARRAY #X-ARR2 TO (1:*, 2:12)        /* same as before
EXPAND ARRAY #X-ARR2 TO (*  , 2:12)        /* same as before
EXPAND ARRAY #X-ARR4 TO (*:*, 3:13)        /* #X-ARR4(1:11, 3:13) are allocated
EXPAND ARRAY #X-ARR5 TO (*:*, 4:14, 5:15)  /* #X-ARR5(1:11, 4:14, 5:15) are allocated

EXPAND ステートメントは、任意の順序で記述できます。

従属した次元しか配列にないため、以下のような EXPAND ステートメントは使用できません。

EXPAND ARRAY #X-ARR1 TO ...
EXPAND ARRAY #X-GROUP-ARR2 TO ...
EXPAND ARRAY #X-ARR3 TO ...

X-array の参照

X-array のオカレンス数は、アクセスする前に EXPAND ステートメントまたは RESIZE ステートメントを使用して、明示的に割り当てる必要があります。値を Tamino から取得する場合、ステートメント READFINDGET ではオカレンスが暗黙的に割り当てられます。

一般的なルールとして、存在しない X-array のオカレンスにアクセスしようとするとランタイムエラーが発生します。ただし、全体範囲表記を使用して X-array のすべてのオカレンスを参照する場合は、実体を持たない X-array フィールドにアクセスしてもエラーにならないステートメントもあります。例:#X-ARR(*)これは、以下に対して適用されます。

  • CALL ステートメント内で使用されているパラメータ

  • オプションパラメータとして定義されている場合、ステートメント CALLNATPERFORM または OPEN DIALOG で使用されるパラメータ、

  • COMPRESS ステートメント内で使用されているソースフィールド

  • PRINT ステートメント内で指定されている出力フィールド

  • RESET ステートメント内で参照されているフィールド

これらのステートメントの 1 つを使用して実体を持たない X-array のオカレンスを個別に参照すると、対応するエラーメッセージが発行されます。

例:

DEFINE DATA LOCAL 
1 #X-ARR (A10/1:*) /* X-array only defined, but not allocated
END-DEFINE        
RESET #X-ARR(*)    /* no error, because complete field referenced with (*)   
RESET #X-ARR(1:3)  /* runtime error, because individual occurrences (1:3) are referenced
END  

配列参照のアスタリスク(*)表記は、次元のすべての範囲を表します。配列が X-array の場合、アスタリスクは、現在割り当てられている下限おへよび上限のインデックス範囲を表します。この下限および上限は、システム変数 *LBOUND および *UBOUND によって確認できます。

X-array を使用したパラメータ引き渡し

X-array をパラメータとして使用すると、以下の整合性チェックで定数の配列と同じように扱われます。

  • フォーマット

  • 長さ

  • 次元

  • オカレンス数

また、X-array パラメータは、ステートメント RESIZEREDUCE、または EXPAND を使用することにより、オカレンス数を変更することもできます。X-array パラメータのサイズ変更が可能かどうかは、以下の 3 つの要素によって決まります。

  • 使用するパラメータ引き渡しのタイプ(参照渡しまたは値渡し)

  • 呼び出し元または X-array パラメータの定義

  • 引き渡す X-array の範囲のタイプ(全体または一部)

以下の表は、X-array パラメータに EXPANDRESIZEREDUCE の各ステートメントを適用できる条件を示しています。

値渡しの例

呼び出し元 パラメータ
スタティック 変数(1:V) X-array
スタティック × ×
X-array の一部。例:
CALLNAT...#XA(1:5)
× ×
X-array 全体。例:
CALLNAT...#XA(*)
× ×

参照渡し/値渡し(結果)

呼び出し元 パラメータ
スタティック 変数(1:V) 固定の下限を持つ X-array。例:
DEFINE DATA PARAMETER
1 #PX (A10/1:*)
固定の上限を持つ X-array。例:
DEFINE DATA PARAMETER
1 #PX (A10/*:1)
スタティック × × × ×
X-array の一部。例:
CALLNAT...#XA(1:5)
× × × ×
固定の下限を持つ X-array の全体。例:
DEFINE DATA LOCAL
1 #XA(A10/1:*) 
... 
CALLNAT...#XA(*)
× × ×
固定の上限を持つ X-array の全体。例:
DEFINE DATA LOCAL
1 #XA(A10/*:1)
... 
CALLNAT...#XA(*)
× × ×

X-group 配列を使用したパラメータ引き渡し

X-group 配列の宣言は、グループの各要素が同じ上限および下限を持つことを暗黙的に意味します。したがって、X-group 配列フィールドの従属した次元のオカレンス数は、RESIZEREDUCEEXPAND の各ステートメントで X-group 配列のグループ名を指定したときにのみ変更できます(前述の「X-Group 配列のストレージ管理」を参照)。

X-group 配列のメンバは、パラメータデータエリアに定義されている X-group 配列にパラメータとして引き渡すことができます。呼び出す側と呼び出される側のグループ構造は必ずしも同一である必要はありません。呼び出した側の X-group 配列に矛盾がない限り、呼び出された側は RESIZEREDUCE または EXPAND を実行できます。

パラメータとして引き渡す X-group 配列の要素の例:

プログラム:

DEFINE DATA LOCAL
1 #X-GROUP-ARR1(1:*)                    /* (1:*)
   2 #X-ARR1 (I4)                       /* (1:*)
   2 #X-ARR2 (I4)                       /* (1:*)
1 #X-GROUP-ARR2(1:*)                    /* (1:*)
   2 #X-ARR3 (I4)                       /* (1:*)
   2 #X-ARR4 (I4)                       /* (1:*)
END-DEFINE
...
CALLNAT ... #X-ARR1(*) #X-ARR4(*)
...
END

Subprogram:

DEFINE DATA PARAMETER
1 #X-GROUP-ARR(1:*)                     /* (1:*)
   2 #X-PAR1 (I4)                       /* (1:*)
   2 #X-PAR2 (I4)                       /* (1:*)
END-DEFINE
...
RESIZE ARRAY #X-GROUP-ARR to (1:5)
...
END

サブプログラムの RESIZE ステートメントは実行できません。プログラムの X-group 配列で定義されているフィールドのオカレンス数と矛盾しています。

ダイナミック変数の X-array

ダイナミック変数の X-array の割り当てでは、最初に EXPAND ステートメントを使用してオカレンス数を指定し、後でそのオカレンス数に値を割り当てることによって変更できます。

例:

DEFINE DATA LOCAL
 1 #X-ARRAY(A/1:*)  DYNAMIC
END-DEFINE
EXPAND  ARRAY   #X-ARRAY TO (1:10)
  /* allocate #X-ARRAY(1) to #X-ARRAY(10) with zero length.
  /* *LENGTH(#X-ARRAY(1:10)) is zero 
#X-ARRAY(*) := 'abc'
  /* #X-ARRAY(1:10) contains 'abc',
  /* *LENGTH(#X-ARRAY(1:10)) is 3
EXPAND  ARRAY   #X-ARRAY TO (1:20)
  /* allocate #X-ARRAY(11) to #X-ARRAY(20) with zero length
  /* *LENGTH(#X-ARRAY(11:20)) is zero
#X-ARRAY(11:20) := 'def'
  /* #X-ARRAY(11:20) contains 'def'
  /* *LENGTH(#X-ARRAY(11:20)) is 3

配列の上限および下限

システム変数 *LBOUND および *UBOUND には、指定した次元(1、2、または 3 次元。複数指定可)に対する配列の、その時点での下限および上限が設定されます。(1、2 または 3)。

X-array のオカレンスが割り当てられていない場合、*LBOUND または *UBOUND へのアクセスは、変更可能なインデックス範囲、つまりインデックス定義でアスタリスク(*)文字により表されている境界に対して定義されておらず、ランタイムエラーが発生します。ランタイムエラーを回避するには、*LBOUND または *UBOUND を評価する前にシステム変数 *OCCURRENCE を使用して、オカレンス数がゼロかどうかを確認します。

例:

IF *OCCURRENCE (#A) NE 0  AND  *UBOUND(#A) < 100 THEN ...