Time attributes with enforced bounds.

The following stanza in GetTypeId() will restrict the value to

    -5s  <=  m_timeWithBounds  <= 10s

.AddAttribute ("TestTimeWithBounds", "help text",
               TimeValue (Seconds (-2)),
               MakeTimeAccessor (&AttributeObjectTest::m_timeWithBounds),
               MakeTimeChecker (Seconds (-5), Seconds (10)))
This commit is contained in:
Peter D. Barnes, Jr.
2013-07-03 11:19:21 -07:00
parent e468df69c9
commit a7d87403f6
3 changed files with 177 additions and 4 deletions

View File

@@ -165,6 +165,21 @@ public:
*/
explicit Time (const std::string & s);
/**
* \brief Minimum representable Time
*/
static Time MIN ()
{
return Time ((long long int)LLONG_MIN);
}
/**
* \brief Maximum representable Time
*/
static Time MAX ()
{
return Time ((long long int)LLONG_MAX);
}
/**
* \return true if the time is zero, false otherwise.
*/
@@ -650,7 +665,37 @@ inline Time TimeStep (uint64_t ts)
ATTRIBUTE_VALUE_DEFINE (Time);
ATTRIBUTE_ACCESSOR_DEFINE (Time);
ATTRIBUTE_CHECKER_DEFINE (Time);
/**
* \brief Helper to make a Time checker with bounded range.
* Both limits are inclusive
*
* \return the AttributeChecker
*/
Ptr<const AttributeChecker> MakeTimeChecker (const Time min, const Time max);
/**
* \brief Helper to make an unbounded Time checker.
*
* \return the AttributeChecker
*/
inline
Ptr<const AttributeChecker> MakeTimeChecker (void)
{
return MakeTimeChecker (Time::MIN (), Time::MAX ());
}
/**
* \brief Helper to make a Time checker with an upper bound
*
* \return the AttributeChecker
*/
inline
Ptr<const AttributeChecker> MakeTimeChecker (const Time min)
{
return MakeTimeChecker (min, Time::MAX ());
}
} // namespace ns3

View File

@@ -186,7 +186,61 @@ std::istream& operator>> (std::istream& is, Time & time)
}
ATTRIBUTE_VALUE_IMPLEMENT (Time);
ATTRIBUTE_CHECKER_IMPLEMENT (Time);
Ptr<const AttributeChecker>
MakeTimeChecker (const Time min, const Time max)
{
NS_LOG_FUNCTION (min << max);
struct Checker : public AttributeChecker
{
Checker (const Time minValue, const Time maxValue)
: m_minValue (minValue),
m_maxValue (maxValue) {}
virtual bool Check (const AttributeValue &value) const {
NS_LOG_FUNCTION (&value);
const TimeValue *v = dynamic_cast<const TimeValue *> (&value);
if (v == 0)
{
return false;
}
return v->Get () >= m_minValue && v->Get () <= m_maxValue;
}
virtual std::string GetValueTypeName (void) const {
NS_LOG_FUNCTION_NOARGS ();
return "ns3::TimeValue";
}
virtual bool HasUnderlyingTypeInformation (void) const {
NS_LOG_FUNCTION_NOARGS ();
return true;
}
virtual std::string GetUnderlyingTypeInformation (void) const {
NS_LOG_FUNCTION_NOARGS ();
std::ostringstream oss;
oss << "Time" << " " << m_minValue << ":" << m_maxValue;
return oss.str ();
}
virtual Ptr<AttributeValue> Create (void) const {
NS_LOG_FUNCTION_NOARGS ();
return ns3::Create<TimeValue> ();
}
virtual bool Copy (const AttributeValue &source, AttributeValue &destination) const {
NS_LOG_FUNCTION (&source << &destination);
const TimeValue *src = dynamic_cast<const TimeValue *> (&source);
TimeValue *dst = dynamic_cast<TimeValue *> (&destination);
if (src == 0 || dst == 0)
{
return false;
}
*dst = *src;
return true;
}
Time m_minValue;
Time m_maxValue;
} *checker = new Checker (min, max);
return Ptr<const AttributeChecker> (checker, false);
}
} // namespace ns3

View File

@@ -33,6 +33,7 @@
#include "ns3/trace-source-accessor.h"
#include "ns3/pointer.h"
#include "ns3/object-factory.h"
#include "ns3/nstime.h"
using namespace ns3;
@@ -190,6 +191,10 @@ public:
CallbackValue (),
MakeCallbackAccessor (&AttributeObjectTest::m_cbValue),
MakeCallbackChecker ())
.AddAttribute ("TestTimeWithBounds", "help text",
TimeValue (Seconds (-2)),
MakeTimeAccessor (&AttributeObjectTest::m_timeWithBounds),
MakeTimeChecker (Seconds (-5), Seconds (10)))
;
return tid;
@@ -243,6 +248,7 @@ private:
TracedValue<enum Test_e> m_enumSrc;
TracedValue<double> m_doubleSrc;
TracedValue<bool> m_boolSrc;
Time m_timeWithBounds;
};
NS_OBJECT_ENSURE_REGISTERED (AttributeObjectTest);
@@ -643,6 +649,73 @@ AttributeTestCase<EnumValue>::DoRun (void)
NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes");
}
template <> void
AttributeTestCase<TimeValue>::DoRun (void)
{
Ptr<AttributeObjectTest> p;
bool ok;
p = CreateObject<AttributeObjectTest> ();
NS_TEST_ASSERT_MSG_NE (p, 0, "Unable to CreateObject");
//
// Set value
//
ok = p->SetAttributeFailSafe ("TestTimeWithBounds", TimeValue (Seconds (5)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via TimeValue to 5s");
ok = CheckGetCodePaths (p, "TestTimeWithBounds", "+5000000000.0ns", TimeValue (Seconds (5)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (5s) via TimeValue");
ok = p->SetAttributeFailSafe ("TestTimeWithBounds", StringValue ("3s"));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via TimeValue to 5s");
ok = CheckGetCodePaths (p, "TestTimeWithBounds", "+3000000000.0ns", TimeValue (Seconds (3)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (3s) via StringValue");
//
// Attributes can have limits other than the intrinsic limits of the
// underlying data types. These limits are specified in the Object.
//
//
// Set the Attribute at the positive limit
//
ok = p->SetAttributeFailSafe ("TestTimeWithBounds", TimeValue (Seconds (10)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via TimeValue to 10");
ok = CheckGetCodePaths (p, "TestTimeWithBounds", "+10000000000.0ns", TimeValue (Seconds (10)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (positive limit) via StringValue");
//
// Set the Attribute past the positive limit.
//
ok = p->SetAttributeFailSafe ("TestTimeWithBounds", TimeValue (Seconds (11)));
NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via TimeValue to 11");
ok = CheckGetCodePaths (p, "TestTimeWithBounds", "+10000000000.0ns", TimeValue (Seconds (10)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes");
//
// Set the Attribute at the negative limit.
//
ok = p->SetAttributeFailSafe ("TestTimeWithBounds", TimeValue (Seconds (-5)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Could not SetAttributeFailSafe() via TimeValue to -5");
ok = CheckGetCodePaths (p, "TestTimeWithBounds", "-5000000000.0ns", TimeValue (Seconds (-5)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Attribute not set properly by SetAttributeFailSafe() (negative limit) via StringValue");
//
// Set the Attribute past the negative limit.
//
ok = p->SetAttributeFailSafe ("TestTimeWithBounds", TimeValue (Seconds (-6)));
NS_TEST_ASSERT_MSG_EQ (ok, false, "Unexpectedly could SetAttributeFailSafe() via TimeValue to -6");
ok = CheckGetCodePaths (p, "TestTimeWithBounds", "-5000000000.0ns", TimeValue (Seconds (-5)));
NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes");
}
// ===========================================================================
// Test the Attributes of type RandomVariableStream.
// ===========================================================================
@@ -1279,14 +1352,15 @@ AttributesTestSuite::AttributesTestSuite ()
AddTestCase (new AttributeTestCase<UintegerValue> ("Check Attributes of type UintegerValue"), TestCase::QUICK);
AddTestCase (new AttributeTestCase<DoubleValue> ("Check Attributes of type DoubleValue"), TestCase::QUICK);
AddTestCase (new AttributeTestCase<EnumValue> ("Check Attributes of type EnumValue"), TestCase::QUICK);
AddTestCase (new AttributeTestCase<TimeValue> ("Check Attributes of type TimeValue"), TestCase::QUICK);
AddTestCase (new RandomVariableStreamAttributeTestCase ("Check Attributes of type RandomVariableStream"), TestCase::QUICK);
AddTestCase (new ObjectVectorAttributeTestCase ("Check Attributes of type ObjectVectorValue"), TestCase::QUICK);
AddTestCase (new ObjectMapAttributeTestCase ("Check Attributes of type ObjectMapValue"), TestCase::QUICK);
AddTestCase (new PointerAttributeTestCase ("Check Attributes of type PointerValue"), TestCase::QUICK);
AddTestCase (new CallbackValueTestCase ("Check Attributes of type CallbackValue"), TestCase::QUICK);
AddTestCase (new IntegerTraceSourceAttributeTestCase ("Ensure TracedValue<uint8_t> can be set like IntegerValue"), TestCase::QUICK);
AddTestCase (new IntegerTraceSourceTestCase ("Ensure TracedValue<uint8_t> also works as trace source"), TestCase::QUICK);
AddTestCase (new TracedCallbackTestCase ("Ensure TracedCallback<double, int, float> works as trace source"), TestCase::QUICK);
AddTestCase (new PointerAttributeTestCase ("Check Attributes of type PointerValue"), TestCase::QUICK);
AddTestCase (new CallbackValueTestCase ("Check Attributes of type CallbackValue"), TestCase::QUICK);
}
static AttributesTestSuite attributesTestSuite;