![見出し画像](https://assets.st-note.com/production/uploads/images/57235116/rectangle_large_type_2_5baea5761d62c6e838673001bf5e12ff.png?width=1200)
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関数が要求したサイズを返さないのには驚きました)。
注意: コードの利用においてチブル・システムズは一切の責任を負いません。自己責任でご利用をお願いいたします。