ILE バインド可能 API を使用したユーザー独自のヒープ管理

1 つ以上のユーザー作成ヒープを作成することによって、 活動化グループ内の一部のプログラムおよびプロシージャーで使用される動的記憶域を分離することができます。 ユーザー作成ヒープの作り方については、「ILE 概念」を参照してください。

次の例は、ILE RPG プロシージャーからユーザー作成ヒープを使用して、実行時配列用の動的記憶域を管理する方法を示したものです。 この例では、モジュール DYNARRAY 内のプロシージャーが、 実際にバインドされていないパック配列に記憶域を動的に割り振ります。 このモジュール内のプロシージャーは、この配列で以下の処置を実行します。

DYNARRAY は、REALLOC 命令コードだけでなく、CEECRHP (ヒープ作成)、CEEGTST (記憶域取得)、および CEEDSHP (ヒープ廃棄) という 3 つの ILE バインド可能記憶域 API を使用してこれらの処置を行います。 記憶域管理バインド可能 API に特有の情報は、Web サイト http://www.ibm.com/eserver/iseries/infocenteriSeries Information Center の中の『プログラミン グ』カテゴリーの『CL および API』の節を参 照してください。

図 55 では、DYNARRAY 内のプロシージャーのプロトタイプを含む、/COPY ファイル DYNARRI を示します。 この /COPY ファイルは、DYNARRAY にプロシージャーを呼び出す その他のモジュールだけでなく、DYNARRAY モジュールによって使用されます。

DYNARRAY は、(15,0) パック 10 進数配列で使用されるように定義されています。 これは、単に DYNA_TYPE の定義を文字フィールドに変更することによって、 文字配列の処理を容易に変換することができます。

図 55. DYNARRAY モジュールのプロトタイプを含む /COPY ファイル DYNARRI
      *=================================================================
      * DYNARRAY :  (実際には) バインドされていない実行時パック (15,0)
      *             配列の処理。DYNARRAY モジュールには、配列を割り振り、
      *             配列値を戻すか設定し、配列を割り振り解除する
      *             プロシージャーが含まれています。
      *=================================================================
     D DYNA_TYPE       S             15P 0
     D DYNA_INIT       PR
     D DYNA_TERM       PR
     D DYNA_SET        PR
     D   Element                             VALUE LIKE(DYNA_TYPE)
     D   Index                        5I 0   VALUE
     D DYNA_GET        PR                    LIKE(DYNA_TYPE)
     D   Index                        5I 0   VALUE

図 56 は、制御仕様書と定義仕様書を含むモジュール DYNARRAY の最初の部分を示します。

図 56. DYNARRAY のグローバル変数とローカル・プロトタイプ
      *=================================================================
      * DYNARRAY :  (実際には) バインドされていない実行時パック (15,0)
      *             配列の処理。このモジュールには、配列を割り振り、
      *             配列値を戻すか設定し、配列を割り振り解除する
      *             プロシージャーが含まれています。
      *=================================================================
     H NOMAIN
      *-----------------------------------------------------------------
      * このモジュール内のプロシージャー用のプロトタイプ
      *-----------------------------------------------------------------
      /COPY DYNARRI
      *-----------------------------------------------------------------
      * CEEGTST API (ヒープ記憶域取得) へのインターフェース
      *  1) HeapId     = ヒープの ID。
      *  2) Size   = 割り振るバイト数
      *  3) RetAddr= 割り振られた記憶域の戻りアドレス
      *  4) *OMIT  = フィードバック・パラメーター。ここに *OMIT を指定
      *                  することは、要求が満たされなかった時に API から
      *                  例外を受け取ることを意味します。
      *                  これを監視しているわけではないので、呼び出し
      *                  プロシージャーが例外を受け取ることになります。
      *-----------------------------------------------------------------
     D CEEGTST         PR
     D   HeapId                      10I 0       CONST
     D   Size                        10I 0       CONST
     D   RetAddr                       *
     D   Feedback                    12A         OPTIONS(*OMIT)
      *-----------------------------------------------------------------
      * CEECRHP API (ヒープ作成) へのインターフェース
      *  1) HeapId     = ヒープの ID。
      *  2) InitSize   = ヒープの初期サイズ。
      *  3) Incr       = ヒープを拡大する必要がある場合に
      *                  増分するバイト数。
      *  4) AllocStrat = このヒープの場合の割り振り方法。値を
      *                  0 に設定すると、システムが
      *                  最適な方法を選択することができます。
      *  5) *OMIT      = フィードバック・パラメーター。ここに *OMIT を指定
      *                  することは、要求が満たされなかった時に API から
      *                  例外を受け取ることを意味します。
      *                  これを監視しているわけではないので、呼び出し
      *                  プロシージャーが例外を受け取ることになります。
      *-----------------------------------------------------------------
     D CEECRHP         PR
     D   HeapId                      10I 0
     D   InitSize                    10I 0       CONST
     D   Incr                        10I 0       CONST
     D   AllocStrat                  10I 0       CONST
     D   Feedback                    12A         OPTIONS(*OMIT)
      *-----------------------------------------------------------------
      * CEEDSHP API (ヒープ廃棄) へのインターフェース
      *  1) HeapId     = ヒープの ID。
      *  2) *OMIT      = フィードバック・パラメーター。ここに *OMIT を指定
      *                  することは、要求が満たされなかった時に API から
      *                  例外を受け取ることを意味します。
      *                  これを監視しているわけではないので、呼び出し
      *                  プロシージャーが例外を受け取ることになります。
      *-----------------------------------------------------------------
     D CEEDSHP         PR
     D   HeapId                      10I 0
     D   Feedback                    12A         OPTIONS(*OMIT)
      *-----------------------------------------------------------------
      * グローバル変数
      *-----------------------------------------------------------------
     D HeapVars        DS
     D   HeapId                      10I 0
     D   DynArr@                       *
      *-----------------------------------------------------------------
      * 動的配列の定義。要素数を使用可能な最大数でコーディングしますが、
      * この定義には実際には記憶域は宣言されないことに注意して
      * ください (これが BASED であるため)。
      *-----------------------------------------------------------------
     D DynArr          S                   DIM(32767) BASED(DynArr@)
     D                                     LIKE(DYNA_TYPE)
      *-----------------------------------------------------------------
      * 動的配列の要素の現在数を、
      * 常にグローバルに記録しておきます。
      *-----------------------------------------------------------------
     D NumElems        S             10I 0 INZ(0)

      *-----------------------------------------------------------------
      * 配列に割り振られる要素の初期数および
      * 後続の割り振りで配列に追加される
      * 要素の最小数。
      *-----------------------------------------------------------------
     D INITALLOC       C                   100
     D SUBSALLOC       C                   100

図 57 は DYNARRAY にあるサブプロシージャーを示したものです。

図 57. DYNARRAY のサブプロシージャー
      *=================================================================
      * DYNA_INIT: 配列を初期化します。
      *
      * 機能:      ヒープを作成し、実行時配列に記憶域の初期量を
      *            割り振ります。
      *=================================================================
     P DYNA_INIT       B                   EXPORT
      *-----------------------------------------------------------------
      * ローカル変数。
      *-----------------------------------------------------------------
     D Size            S             10I 0
      *
      * 事前に定義された要素数で開始します。
      *
     C                   Z-ADD     INITALLOC     NumElems
      *
      * 配列に必要なバイト数を決定します。
      *
     C                   EVAL      Size =  NumElems * %SIZE(DynArr)
      *
      * ヒープの作成
      *
     C                   CALLP     CEECRHP(HeapId : Size : 0 : 0 : *OMIT)

      *
      * 記憶域を割り振り、配列の基底ポインターを、API から
      * 戻されたポインターに設定します。
      *
      * ALLOC 命令コードがデフォルト・ヒープを使用するため、CEEGTST API を
      * 使用して別のヒープを指定する必要があることに注意してください。
      *
     C                   CALLP     CEEGTST(HeapId : Size : DynArr@ : *OMIT)

      *
      * 配列の記憶域の初期化
      *
     C     1             DO        NumElems      I                 5 0
     C                   CLEAR                   DynArr(I)
     C                   ENDDO
     P DYNA_INIT       E

      *=================================================================
      * DYNA_TERM: 配列処理を終了させます。
      *
      * 機能:      ヒープを削除します。
      *=================================================================
     P DYNA_TERM       B                   EXPORT
     C                   CALLP     CEEDSHP(HeapId : *OMIT)
     C                   RESET                   HeapVars
     P DYNA_TERM       E
      *=================================================================
      * DYNA_SET: 配列要素を設定します。
      *
      * 機能:     この要素に対して配列が十分な大きさであることを確認して、
      *           要素を指定された値に設定します。
      *=================================================================
     P DYNA_SET        B                   EXPORT
      *-----------------------------------------------------------------
      * このプロシージャーの入力パラメーター。
      *-----------------------------------------------------------------
     D DYNA_SET        PI
     D   Element                             VALUE LIKE(DYNA_TYPE)
     D   Index                        5I 0   VALUE
      *-----------------------------------------------------------------
      * ローカル変数。
      *-----------------------------------------------------------------
     D Size            S             10I 0
      *-----------------------------------------------------------------
      * 配列への追加を選択した場合には、配列が十分に大きいかどうかが
      * 最初に検査され、十分でない場合にはそのサイズが増やされます。
      * 要素を追加します。
      *-----------------------------------------------------------------
     C     Index         IFGT      NumElems
     C                   EXSR      REALLOC
     C                   ENDIF
     C                   EVAL      DynArr(Index) = Element
      *=================================================================
      * REALLOC: 記憶域再割り振りサブルーチン
      *
      *         機能:    動的配列のサイズを増やして、
      *                  新しい要素を初期化します。
      *=================================================================
     C     REALLOC       BEGSR

      *
      *  元の要素の数を記憶
      *
     C                   Z-ADD     NumElems      OldElems          5 0

      *
      *  新しい要素の数を計算します。指標が配列内の現在の要素数に
      *  新しい割り振り数を加えたものより大きい場合には、その
      *  指標まで割り振り、そうでない場合には
      *  配列に新しい割り振り量を加算します。
      *
     C                   IF        Index > NumElems + SUBSALLOC
     C                   Z-ADD     Index         NumElems
     C                   ELSE
     C                   ADD       SUBSALLOC     NumElems
     C                   ENDIF
      *
      * 配列の新しいサイズを計算します
      *
     C                   EVAL      Size =  NumElems * %SIZE(DynArr)
      *
      * 記憶域を再割り振りします。新しい記憶域の値は、元の記憶域と
      * 同じです。
      *
     C                   REALLOC   Size          DynArr@
      *
      * 配列の新しい要素を初期化します。
      *
     C     1             ADD       OldElems      I
     C     I             DO        NumElems      I                 5 0
     C                   CLEAR                   DynArr(I)
     C                   ENDDO
     C                   ENDSR
     P DYNA_SET        E
      *=================================================================
      * DYNA_GET: 配列要素を戻します。
      *
      * 機能:     配列要素が配列のサイズ内である場合には、この要素の
      *           現在の値を戻します。そうでない場合には、
      *           デフォルト値を戻します。
      *=================================================================
     P DYNA_GET        B                   EXPORT
      *-----------------------------------------------------------------
      * このプロシージャーの入力パラメーター。
      *-----------------------------------------------------------------
     D DYNA_GET        PI                    LIKE(DYNA_TYPE)
     D   Index                        5I 0   VALUE
      *-----------------------------------------------------------------
      * ローカル変数。
      *-----------------------------------------------------------------
     D Element         S                     LIKE(DYNA_TYPE) INZ
      *-----------------------------------------------------------------
      * 要求した配列が現行サイズ内であれば、この要素の現行値を
      * 戻します。そうでない場合には、デフォルト (初期化) の値を
      * 使用することができます。
      *-----------------------------------------------------------------
     C     Index         IFLE      NumElems
     C                   EVAL      Element = DynArr(Index)
     C                   ENDIF
     C                   RETURN    Element
     P DYNA_GET        E

このサブプロシージャーのロジックは次のとおりです。

  1. DYNA_INIT は、ILE バインド可能 API CEECRHP (ヒープ作成) を使用してヒープを作成し、グローバル変数 HeapId にヒープ ID を保管する。 これは、ILE バインド可能 API CEEGTST (ヒープ記憶域取得) を呼び出すことによって、配列の初期値 (この場合は 100) に基づいて ヒープ記憶域を割り振ります。
  2. DYNA_TERM は、ILE バインド可能 API CEEDSHP (ヒープ廃棄) を使用してヒープを破棄する。
  3. DYNA_SET は要素の値を配列に設定する。

    要素を配列に追加する前に、プロシージャーは十分なヒープ記憶域があるかどうかを調べます。 十分でない場合には、命令コード REALLOC を使用して追加の記憶域を取得します。

  4. DYNA_GET は指定された要素の値を戻す。 プロシージャーは、要求された要素かゼロのいずれかを呼び出し元に戻します。 ゼロが戻されるのは、要求された要素が実際には配列に保管されていない場合です。

モジュール DYNARRAY を作成するには、以下のとおりタイプしてください。

CRTRPGMOD MODULE(MYLIB/DYNARRAY) SRCFILE(MYLIB/QRPGLESRC)

このプロシージャーは、この後で CRTPGM または CRTSRVPGM を使用してその他の モジュールとバインドすることができます。

図 58 DYNARRAY 内のモジュールをテストする、別のモジュールを示します。

図 58. DYNARRAY のプロシージャーを使用するサンプル・モジュール
      *=================================================================
      * DYNTEST: DYNARRAY モジュールのテスト・プログラム
      *=================================================================
      /COPY EXAMPLES,DYNARRI
     D X               S                   LIKE(DYNA_TYPE)
      * 配列の初期化
     C                   CALLP     DYNA_INIT
      * 一部要素の設定
     C                   CALLP     DYNA_SET (25 : 3)
     C                   CALLP     DYNA_SET (467252232 : 1)
     C                   CALLP     DYNA_SET (-2311 : 750)
      * 一部要素の検索
     C                   EVAL      X = DYNA_GET (750)
     C     '750'         DSPLY                   X
     C                   EVAL      X = DYNA_GET (8001)
     C     '8001'        DSPLY                   X
     C                   EVAL      X = DYNA_GET (2)
     C     '2'           DSPLY                   X

      * 終結処理
     C                   CALLP     DYNA_TERM
     C                   SETON                                        LR