From a7d87403f63ceb54e0bead5e099908d67cecda79 Mon Sep 17 00:00:00 2001 From: "Peter D. Barnes, Jr." Date: Wed, 3 Jul 2013 11:19:21 -0700 Subject: [PATCH] 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))) --- src/core/model/nstime.h | 47 +++++++++++++++- src/core/model/time.cc | 56 ++++++++++++++++++- src/core/test/attribute-test-suite.cc | 78 ++++++++++++++++++++++++++- 3 files changed, 177 insertions(+), 4 deletions(-) diff --git a/src/core/model/nstime.h b/src/core/model/nstime.h index 49f7179ae..cd9c79846 100644 --- a/src/core/model/nstime.h +++ b/src/core/model/nstime.h @@ -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 MakeTimeChecker (const Time min, const Time max); + +/** + * \brief Helper to make an unbounded Time checker. + * + * \return the AttributeChecker + */ +inline +Ptr MakeTimeChecker (void) +{ + return MakeTimeChecker (Time::MIN (), Time::MAX ()); +} + +/** + * \brief Helper to make a Time checker with an upper bound + * + * \return the AttributeChecker + */ +inline +Ptr MakeTimeChecker (const Time min) +{ + return MakeTimeChecker (min, Time::MAX ()); +} + } // namespace ns3 diff --git a/src/core/model/time.cc b/src/core/model/time.cc index 8dc163c24..46cc78d77 100644 --- a/src/core/model/time.cc +++ b/src/core/model/time.cc @@ -186,7 +186,61 @@ std::istream& operator>> (std::istream& is, Time & time) } ATTRIBUTE_VALUE_IMPLEMENT (Time); -ATTRIBUTE_CHECKER_IMPLEMENT (Time); + +Ptr +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 (&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 Create (void) const { + NS_LOG_FUNCTION_NOARGS (); + return ns3::Create (); + } + virtual bool Copy (const AttributeValue &source, AttributeValue &destination) const { + NS_LOG_FUNCTION (&source << &destination); + const TimeValue *src = dynamic_cast (&source); + TimeValue *dst = dynamic_cast (&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 (checker, false); +} + } // namespace ns3 diff --git a/src/core/test/attribute-test-suite.cc b/src/core/test/attribute-test-suite.cc index ebdfba82b..0d9a84c99 100644 --- a/src/core/test/attribute-test-suite.cc +++ b/src/core/test/attribute-test-suite.cc @@ -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 m_enumSrc; TracedValue m_doubleSrc; TracedValue m_boolSrc; + Time m_timeWithBounds; }; NS_OBJECT_ENSURE_REGISTERED (AttributeObjectTest); @@ -643,6 +649,73 @@ AttributeTestCase::DoRun (void) NS_TEST_ASSERT_MSG_EQ (ok, true, "Error in SetAttributeFailSafe() but value changes"); } +template <> void +AttributeTestCase::DoRun (void) +{ + Ptr p; + bool ok; + + p = CreateObject (); + 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 ("Check Attributes of type UintegerValue"), TestCase::QUICK); AddTestCase (new AttributeTestCase ("Check Attributes of type DoubleValue"), TestCase::QUICK); AddTestCase (new AttributeTestCase ("Check Attributes of type EnumValue"), TestCase::QUICK); + AddTestCase (new AttributeTestCase ("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 can be set like IntegerValue"), TestCase::QUICK); AddTestCase (new IntegerTraceSourceTestCase ("Ensure TracedValue also works as trace source"), TestCase::QUICK); AddTestCase (new TracedCallbackTestCase ("Ensure TracedCallback 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;