C++ Builder > テーブルに基づく経過時間ごとの条件ON/OFF > v0.1..v0.2

```txt:動作環境
C++ Builder XE4
```

- テーブルを用意する
- 時間ごとにそのテーブルに基づき、条件をON/OFFする
- 条件1は他の条件と同時発生できない
  - テーブルの宣言で調整する

## v0.1

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <DateUtils.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

/*
v0.1 2017/01/15
	- Timer1Timer()実装
	- processMyEvent()実装
	- kTable_conditions[], kTable_default[]定義
	- [kNumCondition]定義
*/


//---------------------------------------------------------------------------
// 条件の定義
static const int kNumCondition = 3; // 条件の個数。kTable_conditions[]に合わせて指定する

// 3つの条件
//   1つ目は「排他」
//   2つ目、3つ目は「非排他」(同時に発生してよい)
static const int kTable_conditions[][kNumCondition] =
{
	// { conditions 1..3 }
	{ 1, 0, 0 }, //
	{ 0, 1, 0 }, //
	{ 0, 0, 1 }, //
	{ 0, 1, 1 }, //
};
static const int kTable_default[kNumCondition] = { 0,0,0 }; // { conditions 1..3 }

//---------------------------------------------------------------------------
//
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	Timer1->Interval = 10000; // msec
	Timer1->Enabled = true;
}

void __fastcall TForm1::processMyEvent(TDateTime currentDt)
{
#if 1 // test
	int curmin = SecondOf(currentDt) / 10; // 10秒ごと
#else
	int curmin = MinuteOf(currentDt); // 1分ごと
#endif
	int tbl[kNumCondition];
	int sizeCond = sizeof(kTable_conditions) / sizeof(tbl);

	// 1. set conditions
	if (curmin < sizeCond) {
		for(int idx=0; idx<kNumCondition; idx++) {
			tbl[idx] = kTable_conditions[curmin][idx];
		}
	} else {
		for(int idx=0; idx<kNumCondition; idx++) {
			tbl[idx] = kTable_default[idx];
		}
	}

	// 2. debug print
	String msg = L"";
	for(int idx=0; idx<kNumCondition; idx++) {
		msg = msg + IntToStr(tbl[idx]);
	}
	msg = msg + L" @ " + DateTimeToStr(currentDt);
	OutputDebugString(msg.c_str());
}

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
	processMyEvent(Now());
}
//---------------------------------------------------------------------------
```

```txt:実行結果
デバッグ出力: 001 @ 2017/01/15 9:19:29 プロセス Project1.exe (4064)
デバッグ出力: 011 @ 2017/01/15 9:19:39 プロセス Project1.exe (4064)
デバッグ出力: 000 @ 2017/01/15 9:19:49 プロセス Project1.exe (4064)
デバッグ出力: 000 @ 2017/01/15 9:19:59 プロセス Project1.exe (4064)
デバッグ出力: 100 @ 2017/01/15 9:20:09 プロセス Project1.exe (4064)
デバッグ出力: 010 @ 2017/01/15 9:20:19 プロセス Project1.exe (4064)
デバッグ出力: 001 @ 2017/01/15 9:20:29 プロセス Project1.exe (4064)
デバッグ出力: 011 @ 2017/01/15 9:20:39 プロセス Project1.exe (4064)
```

## v0.2

処理を外部クラスに変更してみた。

### 関連ファイル

- Unit1.cpp, .h : サンプル用フォーム
- UtilDummyConditionsHandler.cpp, .h : 処理のメイン
- UtilDummyConditionsTable.h : 条件の定義用ヘッダ

### UtilDummyConditionsTable.h

```UtilDummyConditionsTable.h
#ifndef UtilDummyConditionsTableH
#define UtilDummyConditionsTableH

//---------------------------------------------------------------------------
// 条件の定義

// prefix: UDCT(Util Dummy Condition Table)

/*
v0.1 2017/01/15
	- kUDCT_Table_default[]定義
	- kUDCT_table_conditions[][]定義
	- [kUDCT_numDummyConditions]定義
*/


static const int kUDCT_numDummyConditions = 3; // 条件の個数。kTable_conditions[]に合わせて指定する

// 例として、
// 3つの条件
//   1つ目は「排他」
//   2つ目、3つ目は「非排他」(同時に発生してよい)
static const int kUDCT_table_conditions[][kUDCT_numDummyConditions] =
{
	// { conditions 1..3 }
	{ 1, 0, 0 }, //
	{ 0, 1, 0 }, //
	{ 0, 0, 1 }, //
	{ 0, 1, 1 }, //
};
static const int kUDCT_Table_default[kUDCT_numDummyConditions] = { 0,0,0 }; // { conditions 1..3 }


#endif
```

### UtilDummyConditionsHandler.h

```UtilDummyConditionsHandler.h
//---------------------------------------------------------------------------

#ifndef UtilDummyConditionsHandlerH
#define UtilDummyConditionsHandlerH
//---------------------------------------------------------------------------

#include <System.hpp>

#include "UtilDummyConditionsTable.h"

/*
複数の条件のTrue/Falseのテーブルを定義して、時刻に基づくTrue/Falseを設定する。
プロダクションコードでの使用でなく、デバッグでの使用を想定している。
*/

class CUtilDummyConditionsHandler {
private:
	int m_conditionTable[kUDCT_numDummyConditions]; // 現在の条件のTrue/Falseを保持する

public:
	void __fastcall UpdateConditionTable(TDateTime currentDt);
	int __fastcall GetCondition_indexOf(int idx);
	void __fastcall CheckAllConditions(TDateTime currentDt);

	// テスト用
	static void __fastcall Test_main_runner();

	// コンストラクタ
	__fastcall CUtilDummyConditionsHandler();
};

#endif
```

### UtilDummyConditionsHandler.cpp

```UtilDummyConditionsHandler.cpp
//---------------------------------------------------------------------------

#pragma hdrstop

#include <DateUtils.hpp>
#include "UtilDummyConditionsHandler.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)

/*
注意: 2017/01/15
	kTable_conditions[][]などをuint8_t型で定義すると、sizeof(kTable_conditions)が48でなく12のようになってしまう。
	そのため、
	  int sizeCond = sizeof(kTable_conditions) / sizeof(m_conditionTable);
	が正しく計算されずに処理が失敗する。
*/

/*
v0.3 2017/01/15
	- [EVERY_HOURS]追加
	- getTimingIndex()追加
	- 10秒ごとの判断と分ごとの判断を切り替えしやすくした
		+ Test_main_runner(): test_increaseTimer()使用
		+ UpdateConditionTable(): [kCheckInterval]チェック追加
		+ increaseTimer()追加
		+ UDCH_CheckInterval[]追加
v0.2 2017/01/15
	- 条件定義を[UtilDummyConditionsTable.h]に移行
		+ 条件の変更と処理の変更を分離するため
v0.1 2017/01/15
	- CheckAllConditions()実装
	- GetCondition_indexOf()実装
	- UpdateConditionTable()実装
	- [条件の定義]追加
		+ kTable_default[]追加
		+ kTable_conditions[][]追加
		+ [kNumCondition]追加
	- コンストラクタ実装
*/

enum UDCH_CheckInterval {
	EVERY_10SECONDS,
	EVERY_MINUTES,
	EVERY_HOURS,
};

/*
TODO:zz > チェックインターバルに応じて以下の定義を変更すること
*/
static const int kCheckInterval = EVERY_10SECONDS;
//static const int kCheckInterval = EVERY_MINUTES;
//static const int kCheckInterval = EVERY_HOURS;


//---------------------------------------------------------------------------
// コンストラクタ・デストラクタ
__fastcall CUtilDummyConditionsHandler::CUtilDummyConditionsHandler()
{
	for(int idx=0; idx<kUDCT_numDummyConditions; idx++) {
		m_conditionTable[idx] = 0;
	}
}
//---------------------------------------------------------------------------
// ファイルスコープstatic関数

static int getTimingIndex(TDateTime currentDt)
{
	// 1. インデックスcurminの計算
	switch(kCheckInterval) {
	case EVERY_10SECONDS:
		return SecondOf(currentDt) / 10; // 10秒ごと
	case EVERY_MINUTES:
		return MinuteOf(currentDt);
	case EVERY_HOURS:
		return HourOf(currentDt);
	default:
		return -1; // error
	}
}
static TDateTime increaseTimer(TDateTime curDt)
{
	switch(kCheckInterval) {
	case EVERY_10SECONDS:
		return IncSecond(curDt, 10);
	case EVERY_MINUTES:
		return IncMinute(curDt, 1);
	case EVERY_HOURS:
		return IncHour(curDt, 1);
	default:
		return curDt; // error
	}
}

//---------------------------------------------------------------------------
//
void __fastcall CUtilDummyConditionsHandler::UpdateConditionTable(TDateTime currentDt)
{
	int tmidx; // timing index
	tmidx = getTimingIndex(currentDt);
	if (tmidx < 0) {
        return; // error
	}

	// set conditions
	int sizeCond = sizeof(kUDCT_table_conditions) / sizeof(m_conditionTable);
	if (tmidx < sizeCond) {
		for(int ci=0; ci<kUDCT_numDummyConditions; ci++) { // ci: condition index
			m_conditionTable[ci] = kUDCT_table_conditions[tmidx][ci];
		}
	} else {
		for(int ci=0; ci<kUDCT_numDummyConditions; ci++) { // ci: condition index
			m_conditionTable[ci] = kUDCT_Table_default[ci];
		}
	}
}

int __fastcall CUtilDummyConditionsHandler::GetCondition_indexOf(int idx)
{
	int sizeCond = sizeof(kUDCT_table_conditions) / sizeof(m_conditionTable);

	if (idx >= sizeCond) {
		return false; // error
	}

	return m_conditionTable[idx];
}

void __fastcall CUtilDummyConditionsHandler::CheckAllConditions(TDateTime currentDt)
{
	// debug print
	String msg = L"";
	for(int idx=0; idx<kUDCT_numDummyConditions; idx++) {
		msg = msg + IntToStr(GetCondition_indexOf(idx));
	}
	msg = msg + L" @ " + DateTimeToStr(currentDt);
	OutputDebugString(msg.c_str());
}

//---------------------------------------------------------------------------
// テスト用関数
//
/* static */void __fastcall CUtilDummyConditionsHandler::Test_main_runner()
{
	CUtilDummyConditionsHandler *m_conditionTable;

	m_conditionTable = new CUtilDummyConditionsHandler();

	TDateTime curdt = VarToDateTime("2017/01/15 23:59:55"); // Lマクロにしないこと (VarToDateTimeとLマクロで「はまる」ため)
	for(int loop=0; loop < 8; loop++) { // 8: arbitrary
		curdt = increaseTimer(curdt);

		m_conditionTable->UpdateConditionTable(curdt);

		m_conditionTable->CheckAllConditions(curdt);

		if (false) {
			/*
			以下のように条件を指定してTrue/Falseを確認できる。
			*/
			bool cond1 = m_conditionTable->GetCondition_indexOf(/*idx=*/0);
			bool cond2 = m_conditionTable->GetCondition_indexOf(/*idx=*/1);
			/*
			用途としては、isFlag1On()のようなプロダクションコードで使う関数内において
			デバッグ時のみGetCondition_indexOf()を呼び出し、特定の時刻に条件を成立させる。
			*/
		}
	}

	delete m_conditionTable;
}
```

### Unit1.h

```Unit1.h
//---------------------------------------------------------------------------

#ifndef Unit1H
#define Unit1H
//---------------------------------------------------------------------------
#include <System.Classes.hpp>
#include <Vcl.Controls.hpp>
#include <Vcl.StdCtrls.hpp>
#include <Vcl.Forms.hpp>
#include <Vcl.ExtCtrls.hpp>

#include "UtilDummyConditionsHandler.h"
//---------------------------------------------------------------------------
class TForm1 : public TForm
{
__published:	// IDE で管理されるコンポーネント
	TTimer *Timer1;
	TButton *Button1;
	void __fastcall Timer1Timer(TObject *Sender);
	void __fastcall FormShow(TObject *Sender);
	void __fastcall FormClose(TObject *Sender, TCloseAction &Action);
	void __fastcall Button1Click(TObject *Sender);
private:	// ユーザー宣言
	CUtilDummyConditionsHandler *m_dummyCondition; // 時刻に基づく条件のON/OFFに使う

	bool __fastcall isCondition1(void);
	bool __fastcall isCondition2(void);
public:		// ユーザー宣言
	__fastcall TForm1(TComponent* Owner);
};
//---------------------------------------------------------------------------
extern PACKAGE TForm1 *Form1;
//---------------------------------------------------------------------------
#endif
```

### Unit1.cpp

```Unit1.cpp
//---------------------------------------------------------------------------

#include <vcl.h>
#pragma hdrstop

#include <DateUtils.hpp>
#include "Unit1.h"
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
//---------------------------------------------------------------------------

/*
v0.3 2017/01/15
	- UtilDummyConditionsHandler:v0.3
	- UtilDummyConditionsHandler:v0.2
v0.2 2017/01/15
	- isCondition2()実装
	- isCondition1()実装
	- [CUtilDummyConditionsHandler]クラスに一連の処理を移した
		+ UtilDummyConditionsHandler:v0.1
	- kTable_conditions[]削除、kTable_default[]削除
	- processMyEvent()削除
v0.1 2017/01/15
	- Timer1Timer()実装
	- processMyEvent()実装
	- kTable_conditions[], kTable_default[]定義
	- [kNumCondition]定義
*/

//---------------------------------------------------------------------------
//
__fastcall TForm1::TForm1(TComponent* Owner)
	: TForm(Owner)
{
	Timer1->Interval = 10000; // msec
	Timer1->Enabled = true;
}

void __fastcall TForm1::Timer1Timer(TObject *Sender)
{
	m_dummyCondition->UpdateConditionTable(Now());

	m_dummyCondition->CheckAllConditions(Now());

	if (isCondition1()) {
		String msg = L"Condition1 is right";
		OutputDebugString(msg.c_str());
	}

	if (isCondition2()) {
		String msg = L"Condition2 is right";
		OutputDebugString(msg.c_str());
	}
}
//---------------------------------------------------------------------------
// m_dummyConditionのnew/delete
void __fastcall TForm1::FormShow(TObject *Sender)
{
	m_dummyCondition = new CUtilDummyConditionsHandler();
}
void __fastcall TForm1::FormClose(TObject *Sender, TCloseAction &Action)
{
	delete m_dummyCondition;
}
//---------------------------------------------------------------------------

bool __fastcall TForm1::isCondition1(void)
{
	return (m_dummyCondition->GetCondition_indexOf(/*idx=*/0) > 0);
}

bool __fastcall TForm1::isCondition2(void)
{
	return (m_dummyCondition->GetCondition_indexOf(/*idx=*/1) > 0);
}
void __fastcall TForm1::Button1Click(TObject *Sender)
{
	// ボタン押下時に一連のテストを行う
	CUtilDummyConditionsHandler::Test_main_runner();
}
//---------------------------------------------------------------------------
```

### 実行

- UtilDummyConditionsHandler.cppの`static const int kCheckInterval = EVERY_10SECONDS;`だけをアンコメントする
- Unit1のButtonを押す

```txt:結果
デバッグ出力: 100 @ 2017/01/16 0:00:05 プロセス Project1.exe (3584)
デバッグ出力: 010 @ 2017/01/16 0:00:15 プロセス Project1.exe (3584)
デバッグ出力: 001 @ 2017/01/16 0:00:25 プロセス Project1.exe (3584)
デバッグ出力: 011 @ 2017/01/16 0:00:35 プロセス Project1.exe (3584)
デバッグ出力: 000 @ 2017/01/16 0:00:45 プロセス Project1.exe (3584)
デバッグ出力: 000 @ 2017/01/16 0:00:55 プロセス Project1.exe (3584)
デバッグ出力: 100 @ 2017/01/16 0:01:05 プロセス Project1.exe (3584)
デバッグ出力: 010 @ 2017/01/16 0:01:15 プロセス Project1.exe (3584)
```

同様に[kCheckInterval]をEVERY_MINUTESやEVERY_HOURSにして実行する。

```txt:結果
デバッグ出力: 100 @ 2017/01/16 0:00:55 プロセス Project1.exe (3760)
デバッグ出力: 010 @ 2017/01/16 0:01:55 プロセス Project1.exe (3760)
デバッグ出力: 001 @ 2017/01/16 0:02:55 プロセス Project1.exe (3760)
デバッグ出力: 011 @ 2017/01/16 0:03:55 プロセス Project1.exe (3760)
デバッグ出力: 000 @ 2017/01/16 0:04:55 プロセス Project1.exe (3760)
デバッグ出力: 000 @ 2017/01/16 0:05:55 プロセス Project1.exe (3760)
デバッグ出力: 000 @ 2017/01/16 0:06:55 プロセス Project1.exe (3760)
デバッグ出力: 000 @ 2017/01/16 0:07:55 プロセス Project1.exe (3760)
```

```txt:結果
デバッグ出力: 100 @ 2017/01/16 0:59:55 プロセス Project1.exe (1592)
デバッグ出力: 010 @ 2017/01/16 1:59:55 プロセス Project1.exe (1592)
デバッグ出力: 001 @ 2017/01/16 2:59:55 プロセス Project1.exe (1592)
デバッグ出力: 011 @ 2017/01/16 3:59:55 プロセス Project1.exe (1592)
デバッグ出力: 000 @ 2017/01/16 4:59:55 プロセス Project1.exe (1592)
デバッグ出力: 000 @ 2017/01/16 5:59:55 プロセス Project1.exe (1592)
デバッグ出力: 000 @ 2017/01/16 6:59:55 プロセス Project1.exe (1592)
デバッグ出力: 000 @ 2017/01/16 7:59:55 プロセス Project1.exe (1592)
```

## 補足
(追記 2017/01/15)

C++11において、各次元での要素数を取得する方法、および、配列全体の大きさを取得する方法について、以下の詳しい記事を用意いただきました。
http://qiita.com/SaitoAtsushi/items/ee17466c464fb7a270d2

上のv0.2までのコードではこれらは考慮されていません。