![見出し画像](https://assets.st-note.com/production/uploads/images/63145391/rectangle_large_type_2_ccce7f80d44d80c840a18cca2ca7a42d.png?width=1200)
Notes C API探訪: Rangeテンプレートクラス(その1)
以前の記事「RANGE(データ型)その1」〜「同その9」で、テキスト用LIST型向けに用意されているAPI関数と同等なものを、RANGE型向けに関数を定義してみました。今回から、これらを使ってnxpp::Rangeテンプレートクラスとしてラップしてみたいと思います。
Rangeテンプレートクラスのベース
ここでも、まず外郭から作っていきます。
#ifndef NXPP_RANGE_HPP
#define NXPP_RANGE_HPP
#include "./nxpp_range_fn.hpp"
#include "./nxpp_status.hpp"
#include "./nxpp_utils.hpp"
#ifdef NT
#pragma pack(push, 1)
#endif
#include <nsfnote.h>
#ifdef NT
#pragma pack(pop)
#endif
namespace nxpp {
/**
* @brief RANGE構造体ラップクラス
* @tparam Traits 特性構造体
* Traits::item typename シングル要素データ型
* Traits::pair typename ペア要素データ型
* Traits::type WORD データタイププレフィックス値
* Traits::defaultItem static-method シングル要素のデフォルト値
* Traits::defaultPair static-method ペア要素のデフォルト値
*/
template <class Traits>
class Range
{
DHANDLE handle_; ///< ハンドル
BOOL fPrefix_; ///< データタイププレフィックスの有無
public:
/**
* @brief コンストラクタ
* @param fPrefix データタイププレフィックスの有無
*/
Range(BOOL fPrefix = FALSE)
: handle_(NULLHANDLE)
, fPrefix_(fPrefix)
{}
/**
* @brief デストラクタ
*/
virtual ~Range() {
if (handle_ != NULLHANDLE) {
OSMemFree(handle_);
}
}
/**
* @return データタイププレフィックスの有無
*/
BOOL fPrefix() const { return fPrefix_; }
private:
/**
* @brief LIST領域の確保
* @param count 初期シングル要素数
* @param pairCount 初期ペア要素数 // <= 2021-10-11 修正
* @return 成功すればTRUE
*/
bool allocate(WORD count = 0, WORD pairCount = 0) {
void *ptr = nullptr;
DWORD size = 0;
Status status = RangeAllocate<Traits>(
count,
pairCount,
fPrefix_,
&handle_,
&ptr,
&size
);
if (!status) { throw status; }
if (fPrefix_) {
auto pType = reinterpret_cast<WORD*>(ptr);
*pType = Traits::type;
}
OSUnlockObject(handle_);
return true;
}
};
} // namespace nxpp
#endif // NXPP_RANGE_HPP
テンプレート引数の「特性構造体」については後述します。
nxpp::TextListと同様に、ハンドルとデータタイププレフィックスの有無をメンバ変数に持ちます。
インスタンスを破棄する時に有効なハンドルがあればOSMemFree関数で解放します。
最初にハンドルを持つ時は、こちらの記事で紹介しているRangeAllocateテンプレート関数で領域を確保します。なお、RangeAllocateテンプレート関数のように、以前紹介したRANGE型の操作関数は、おなじディレクトリ上のnxpp_range_fn.hpp内で定義しているとものとします。
もしデータタイププレフィックスが「有り」としているインスタンスであれば、確保したメモリの先頭に、データタイププレフィックスを設定します。
特性構造体(拡張版)
さきほどと同じ記事で紹介している、TYPE_NUMBER_RANGEとTYPE_TIME_RANGE用の特性構造体ですが、nxpp::Rangeテンプレートクラスでも使用するにあたり、パラメータを少し増やしました。
まず、数値範囲型(TYPE_NUMBER_RANGE)用はこちらです。
// nxpp/include/nxpp_numberrange.hpp
#ifndef NXPP_NUMBERRANGE_HPP
#define NXPP_NUMBERRANGE_HPP
#include "./nxpp_number.hpp"
#include "./nxpp_range.hpp"
#ifdef NT
#pragma pack(push, 1)
#endif
#include <global.h>
#include <nsfnote.h>
#ifdef NT
#pragma pack(pop)
#endif
namespace nxpp {
/**
* @brief NUMBER範囲用特性構造体
*/
struct NumberRangeTraits {
static constexpr WORD type = TYPE_NUMBER_RANGE;
using item = NUMBER; ///< 単数データ型定義
using pair = NUMBER_PAIR; ///< ペアデータ型定義
static NUMBER defaultItem() { return 0; }
static NUMBER_PAIR defaultPair() { NUMBER_PAIR v { 0, 0 }; return v; }
};
using NumberRange = Range<NumberRangeTraits>;
} // namespace nxpp
#endif // NXPP_NUMBERRANGE_HPP
次に、日時範囲型(TYPE_TIME_RANGE)用はこちらです。
// nxpp/include/nxpp_timedaterange.hpp
#ifndef NXPP_TIMEDATERANGE_HPP
#define NXPP_TIMEDATERANGE_HPP
#include "./nxpp_timedate.hpp"
#include "./nxpp_range.hpp"
#ifdef NT
#pragma pack(push, 1)
#endif
#include <global.h>
#include <nsfnote.h>
#ifdef NT
#pragma pack(pop)
#endif
namespace nxpp {
/**
* @brief NUMBER範囲用特性構造体
*/
struct TimeDateRangeTraits {
static constexpr WORD type = TYPE_TIME_RANGE;
using item = TIMEDATE; ///< 単数データ型定義
using pair = TIMEDATE_PAIR; ///< ペアデータ型定義
static TIMEDATE defaultItem() {
return TimeDate::getConstant<TIMEDATE_MINIMUM>();
}
static TIMEDATE_PAIR defaultPair() {
TIMEDATE_PAIR v {
TimeDate::getConstant<TIMEDATE_MINIMUM>(),
TimeDate::getConstant<TIMEDATE_MINIMUM>()
};
return v;
}
};
using TimeDateRange = Range<TimeDateRangeTraits>;
} // namespace nxpp
#endif // NXPP_TIMEDATERANGE_HPP
まとめ
Rangeテンプレートクラスでは、メモリの確保にOSMemAllocを使用しています。確保自体は難しい話ではないのですが、挿入や削除で使用するOSMemReallocは、なかなか意図したサイズにならなかったのを思い出しました。十分時間を割いてテストしておいてよかったと思いました。