見出し画像

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

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

RangeRemoveItem

RangeRemoveItemテンプレート関数は、RANGE型のアイテムリスト領域にあるアイテムデータを削除します。確保しているメモリ領域はデータ1つ分縮小要求しますが、必ずしもそのサイズになるとは限りません。RANGE型が専有しているサイズは、前回の記事で紹介したRangeGetSizeテンプレート関数を使用して下さい。

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

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

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

 // 削除位置を0~(エントリー数-1)までとする
 EntryNumber = (EntryNumber >= pRange->ListEntries)
     ? (pRange->ListEntries - 1)
     : EntryNumber;

 // 削除位置までのオフセットを求める
 WORD offset1 = offset + sizeof(RANGE) + sizeof(Traits::item) * EntryNumber;
 WORD offset2 = offset1 + sizeof(Traits::item);
 char *pos1 = reinterpret_cast<char*>(p0) + offset1;
 char *pos2 = reinterpret_cast<char*>(p0) + offset2;
 size_t delta = realsize - offset2;

 --pRange->ListEntries;
 memmove(pos1, pos2, delta);

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

 // メモリをアイテムサイズ1つ分減らす(必ず減るとは限らない)
 DWORD newSize = realsize - sizeof(Traits::item);
 return OSMemRealloc(hRange, newSize);
}

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

RangeRemovePair

RangeRemovePairテンプレート関数は、RANGE型の領域からペアデータを削除します。確保しているメモリ領域はデータ1つ分縮小要求しますが、必ずしもそのサイズになるとは限りません。RANGE型が専有しているサイズは、前回の記事で紹介したRangeGetSizeテンプレート関数を使用して下さい。

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

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

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

 // 削除位置を0~(エントリー数-1)までとする
 EntryNumber = (EntryNumber >= pRange->RangeEntries)
     ? (pRange->RangeEntries - 1)
     : EntryNumber;

 // 削除位置までのオフセットを求める
 offset += sizeof(RANGE) + sizeof(Traits::pair) * EntryNumber
      + sizeof(Traits::item) * pRange->ListEntries;
 char *pos = p0 + offset;

 --pRange->RangeEntries;
 memmove(pos, pos + sizeof(Traits::pair),
         realsize - offset - sizeof(Traits::pair));

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

 // メモリをアイテムサイズ1つ分減らす(必ず減るとは限らない)
 DWORD newSize = realsize - sizeof(Traits::pair);
 return OSMemRealloc(hRange, newSize);
}

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

コーディング例

STATUS status = RangeRemoveItem<TimeDateRangeTraits>(hRange, TRUE, 5);
status = RangeRemovePair<TimeDateRangeTraits>(hRange, TRUE, 3);

まとめ

前回のメモリを追加する作業と今回の削除する作業は、いずれも非常に気を遣います(実際、OSMemRealloc関数が要求したサイズを返さないのには驚きました)。

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


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