動作環境
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());
}
//---------------------------------------------------------------------------
実行結果
デバッグ出力: 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を押す
結果
デバッグ出力: 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にして実行する。
結果
デバッグ出力: 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)
結果
デバッグ出力: 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までのコードではこれらは考慮されていません。