見出し画像

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は、なかなか意図したサイズにならなかったのを思い出しました。十分時間を割いてテストしておいてよかったと思いました。

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