Time attributes with enforced bounds.
authorPeter D. Barnes, Jr. <barnes26@llnl.gov>
Wed, 03 Jul 2013 11:19:21 -0700
changeset 9891 e12094c8b31b
parent 9890 3c64a1fbfcf9
child 9892 91a40fb09b58
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
src/core/model/time.cc
src/core/test/attribute-test-suite.cc
--- a/src/core/model/nstime.h	Wed Jul 03 10:53:00 2013 -0700
+++ b/src/core/model/nstime.h	Wed Jul 03 11:19:21 2013 -0700
@@ -166,6 +166,21 @@
   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.
    */
   inline bool IsZero (void) const
@@ -650,7 +665,37 @@
 
 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
 
--- a/src/core/model/time.cc	Wed Jul 03 10:53:00 2013 -0700
+++ b/src/core/model/time.cc	Wed Jul 03 11:19:21 2013 -0700
@@ -186,7 +186,61 @@
 }
 
 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
 
--- a/src/core/test/attribute-test-suite.cc	Wed Jul 03 10:53:00 2013 -0700
+++ b/src/core/test/attribute-test-suite.cc	Wed Jul 03 11:19:21 2013 -0700
@@ -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 @@
                      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 @@
   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 @@
   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 @@
   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;