0
0

More than 5 years have passed since last update.

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

Last updated at Posted at 2017-01-15
動作環境
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までのコードではこれらは考慮されていません。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0