如何使用D合同组织时间不变检查?

如何使用D合同组织时间不变检查?,d,time-measurement,D,Time Measurement,例如,我必须确保某个实时系统的某个功能可以工作20毫秒或更短时间。我可以简单地在函数开始和结束时测量时间,然后断言差异是令人满意的。我用C++做这个。p> 但这看起来很像合同,只是时间检查是一个事后条件,而开始时的时间度量根本不是一个条件。它将很好地投入到合同中,不仅因为它的符号,而且因为建筑的原因 所以我想知道,我可以使用合同功能来检查功能工作的时间吗 有点,但不是很好。原因是在in{}块中声明的变量在out{}块中不可见。(已经有人讨论过如何更改它,因此它可以通过在in块中创建副本来检查pr

例如,我必须确保某个实时系统的某个功能可以工作20毫秒或更短时间。我可以简单地在函数开始和结束时测量时间,然后断言差异是令人满意的。我用C++做这个。p> 但这看起来很像合同,只是时间检查是一个事后条件,而开始时的时间度量根本不是一个条件。它将很好地投入到合同中,不仅因为它的符号,而且因为建筑的原因


所以我想知道,我可以使用合同功能来检查功能工作的时间吗

有点,但不是很好。原因是在in{}块中声明的变量在out{}块中不可见。(已经有人讨论过如何更改它,因此它可以通过在in块中创建副本来检查pre-vs-post状态,但没有实现任何功能。)

因此,这是行不通的:

void foo()
在{auto before=Clock.currTime();}
out{assert(Clock.currTime-before
in中的变量不会结转到out,这会给您一个未定义的标识符错误。但是,我说“有点”,因为有一个潜在的解决办法:

import std.datetime;
struct Foo {
    SysTime test_before;
    void test()
    in {
        test_before = Clock.currTime();
    }
    out {
        assert(Clock.currTime - test_before < dur!"msecs"(20));
    }
    body {

    }
}
导入标准日期时间;
结构Foo{
系统时间测试;
无效测试()
在{
test_before=Clock.currTime();
}
出去{
断言(Clock.currTime-test_在
将变量声明为结构的常规成员。但这意味着每个函数都会有很多无用的变量,不能与递归一起工作,并且只会污染成员名称空间

我的一部分想法是,你可以把你自己的东西堆到一边,让进去的{}推时间,然后出去{}弹出它并检查。。。。但一个快速测试表明,一旦涉及到继承,它很容易被破坏。如果每次重复{}块中的操作,它可能会工作。但这让我觉得非常脆弱。契约继承的规则是继承树的所有out{}块都需要通过,但只有in{}块中的任何一个需要通过。因此,如果在链的下面有一个不同的in{},它可能会忘记推送时间,然后当out尝试弹出它时,堆栈将下溢

// just for experimenting.....
SysTime[] timeStack; // WARNING: use a real stack here in production, a plain array will waste a *lot* of time reallocating as you push and pop on to it

 class Foo {
    void test()
      in {
        timeStack ~= Clock.currTime();
      }
      out {
         auto start = timeStack[$-1];
         timeStack = timeStack[0 .. $-1];
         assert(Clock.currTime - start < dur!"msecs"(20));
         import std.stdio;
         // making sure the stack length is still sane
         writeln("stack length ", timeStack.length);
       }
    body { }
}

class Bar : Foo {
 override void test()
  in {
     // had to repeat the in block on the child class for this to work at all
    timeStack ~= Clock.currTime();
  }
  body {
    import core.thread;
    Thread.sleep(10.msecs); // bump that up to force a failure, ensuring the test is actually run
  }
}
//只是为了试验。。。。。
SysTime[]timeStack;//警告:在生产环境中使用真正的堆栈,普通数组在推送和弹出时将浪费大量时间重新分配
福班{
无效测试()
在{
timeStack~=Clock.currTime();
}
出去{
自动启动=timeStack[$-1];
timeStack=timeStack[0..$-1];
断言(Clock.currTime-start
这似乎管用,但我觉得麻烦太多了。我预计随着程序的扩大,它会以某种方式崩溃,如果你的测试破坏了你的程序,那就有点达不到目的了

如果使用显式测试进行检查满足您的需求,我可能会将其作为单元测试{}来执行(但是,请注意,与D中的大多数断言一样,如果使用-release开关编译,契约将被删除,因此它们实际上也不会在发布版本中被检查。如果您需要它可靠地失败,请抛出异常而不是断言,因为在调试和发布模式下,这将始终有效。)

或者您可以在函数或助手结构或任何类似的C++中使用断言,我将使用范围保护:

void test() {
    auto before = Clock.currTime();
    scope(exit) assert(Clock.currTime - before < dur!"msecs"(20)); // or import std.exception; and use enforce instead of assert if you want it in release builds too
    /* write the rest of your function */
}
void测试(){
前自动=时钟.currTime();
作用域(exit)assert(Clock.currTime-before
当然,这里您也必须在子类中复制它,但似乎您必须在{}块中执行此操作,所以meh,至少before变量是局部变量

<>底线,我想你最好还是用C++的方式做更多或更少的事情。

void test() {
    auto before = Clock.currTime();
    scope(exit) assert(Clock.currTime - before < dur!"msecs"(20)); // or import std.exception; and use enforce instead of assert if you want it in release builds too
    /* write the rest of your function */
}