見出し画像

Notes C API探訪: RANGE(データ型)その8

LIST型には、保持しているエントリーすべてを削除できるListRemoveAllEntries関数というのがありました。今回はそれのRANGE型版を作ってみます。

RangeRemoveAllItems

RangeRemoveAllItemsテンプレート関数は、RANGE型のアイテムリス領域にあるすべてのアイテムデータを削除します。確保しているメモリ領域は、アイテムリストデータすべての領域削除を要求しますが、必ずしもそのサイズになるとは限りません。

template <typename Traits>
STATUS RangeRemoveAllItems(
   DHANDLE hRange,
   BOOL fPrefixDataType
   ) {
 // メモリハンドルをロックしてポインタを取得
 void *p0 = reinterpret_cast<char*>(OSLockObject(hRange));
 WORD realsize = RangeGetSize<Traits>(p0, fPrefixDataType);

 // RANGE型データポインタを取得
 DWORD offset = sizeof(WORD) * (fPrefixDataType ? 1 : 0);
 RANGE *pRange = reinterpret_cast<RANGE*>(
       reinterpret_cast<char*>(p0) + offset
       );

 // 元々削除できるエントリーがなければ返す。
 if (pRange->ListEntries == 0) {
   OSUnlockObject(hRange);
   return NOERROR;
 }

 // ペアデータがなければ移動データがないので最低限のサイズにして返す。
 if (pRange->RangeEntries == 0) {
   pRange->ListEntries = 0;
   OSUnlockObject(hRange);
   return OSMemRealloc(hRange, offset + sizeof(RANGE));
 }

 // 減らすサイズを求める。
 size_t delta = sizeof(Traits::item) * pRange->ListEntries;

 // 削除位置の先端から終端まで求める
 char *pos = reinterpret_cast<char*>(p0) + offset + sizeof(RANGE);
 char *pos2 = pos + delta;

 // カウントを0にし、ペアデータをまるごと移動する。
 pRange->ListEntries = 0;
 memmove(pos, pos2, sizeof(Traits::pair) * pRange->RangeEntries);

 // メモリハンドルをアンロックする
 OSUnlockObject(hRange);

 // メモリをアイテムサイズ分減らす
 return OSMemRealloc(hRange, realsize - delta);
}

・Traitsは、以前の記事で紹介した特性構造体、NumberRangeTraitsかTimeDateRangeTraitsかを指定します。
・hRangeは、RANGE型メモリハンドルを指定します。
・fPrefixDataTypeは、データタイププレフィックスを持つかどうか指定します。

RangeRemoveAllPairs

RangeRemoveAllPairsテンプレート関数は、RANGE型の領域からペアデータをすべて削除します。確保しているメモリ領域はすべてのペアデータ分の縮小を要求しますが、必ずしもそのサイズになるとは限りません。

template <typename Traits>
STATUS RangeRemoveAllPairs(
   DHANDLE hRange,
   BOOL fPrefixDataType
   ) {
 // メモリハンドルをロックしてポインタを取得
 void *p0 = reinterpret_cast<char*>(OSLockObject(hRange));
 WORD realsize = RangeGetSize<Traits>(p0, fPrefixDataType);

 // RANGE型データポインタを取得
 DWORD offset = sizeof(WORD) * (fPrefixDataType ? 1 : 0);
 RANGE *pRange = reinterpret_cast<RANGE*>(
       reinterpret_cast<char*>(p0) + offset
       );

 // 元々削除できるエントリーがなければ返す。
 if (pRange->RangeEntries == 0) {
   OSUnlockObject(hRange);
   return NOERROR;
 }

 // 削除後の新しいサイズを求める(ペアリストは末端なので移動する必要なし)
 DWORD newSize = realsize - sizeof(Traits::pair) * pRange->RangeEntries;
 pRange->RangeEntries = 0;

 // メモリハンドルをアンロックする
 OSUnlockObject(hRange);

 // メモリをペアサイズ分減らす
 return OSMemRealloc(hRange, newSize);
}

・Traitsは、以前の記事で紹介した特性構造体、NumberRangeTraitsかTimeDateRangeTraitsかを指定します。
・hRangeは、RANGE型メモリハンドルを指定します。
・fPrefixDataTypeは、データタイププレフィックスを持つかどうか指定します。

RangeRemoveAll

RangeRemoveAllインライン関数は、RANGE型のデータ領域をすべて削除します。残るのは、(あれば)プレフィックスとRANGE型のデータのみになります。RANGE::ListEntries、RANGE::RangeEntriesともに0に設定されます。なお、確保しているメモリ領域のデータ部すべての縮小を要求しますが、必ずしもそのサイズになるとは限りません。

inline STATUS RangeRemoveAll(
   DHANDLE hRange,
   BOOL fPrefixDataType
   ) {
 // メモリハンドルをロックしてポインタを取得
 char *p0 = reinterpret_cast<char*>(OSLockObject(hRange));

 // RANGE型データポインタを取得
 DWORD offset = sizeof(WORD) * (fPrefixDataType ? 1 : 0);
 RANGE *pRange = reinterpret_cast<RANGE*>(p0 + offset);

 // カウンターを0にする。
 pRange->ListEntries = 0;
 pRange->RangeEntries = 0;

 // メモリハンドルをアンロックする
 OSUnlockObject(hRange);

 // メモリを最小限にする。
 return OSMemRealloc(hRange, offset + sizeof(RANGE));
}

・hRangeは、RANGE型メモリハンドルを指定します。
・fPrefixDataTypeは、データタイププレフィックスを持つかどうか指定します。

コーディング例

STATUS status = RangeRemoveAllItems<TimeDateRangeTraits>(hRange, TRUE);
status = RangeRemoveAllPairs<TimeDateRangeTraits>(hRange, TRUE);
status = RangeRemoveAll(hRange, TRUE);

まとめ

RANGE型のデータ構造は、LIST型に比べて、アイテム1つ1つのデータ長が固定なので、メモリ移動などに必要な計算は非常に簡単です。すべてのアイテムを消去するRangeRemoveAllを使ってニュートラルにしてしまえば、TIMEDATE型用からNUMBER型用に変更することもできます。

注意: コードの利用においてチブル・システムズは一切の責任を負いません。自己責任でご利用をお願いいたします。


この記事が気に入ったらサポートをしてみませんか?