Merge bounded Time attributes
authorPeter D. Barnes, Jr. <barnes26@llnl.gov>
Wed, 03 Jul 2013 12:02:06 -0700
changeset 9892 91a40fb09b58
parent 9889 727fce98f147 (current diff)
parent 9891 e12094c8b31b (diff)
child 9893 18f2d30eddbe
Merge bounded Time attributes
CHANGES.html
RELEASE_NOTES
--- a/CHANGES.html	Wed Jul 03 16:58:46 2013 +0200
+++ b/CHANGES.html	Wed Jul 03 12:02:06 2013 -0700
@@ -55,6 +55,7 @@
 
 <h2>New API:</h2>
 <ul>
+  <li>Time attributes can now be bounded.  See attribute-test-suite.cc for an example.</li>
 </ul>
 
 <h2>Changes to existing API:</h2>
--- a/RELEASE_NOTES	Wed Jul 03 16:58:46 2013 +0200
+++ b/RELEASE_NOTES	Wed Jul 03 12:02:06 2013 -0700
@@ -21,6 +21,7 @@
 
 New user-visible features
 -------------------------
+- Time attributes can now be bounded.  See attribute-test-suite.cc for an example.
 
 Bugs fixed
 ----------
--- a/src/core/model/nstime.h	Wed Jul 03 16:58:46 2013 +0200
+++ b/src/core/model/nstime.h	Wed Jul 03 12:02:06 2013 -0700
@@ -36,61 +36,12 @@
  */
 /**
  * \ingroup time
- * \brief keep track of time unit.
- *
- * This template class is used to keep track of the value
- * of a specific time unit: the type TimeUnit<1> is used to
- * keep track of seconds, the type TimeUnit<2> is used to keep
- * track of seconds squared, the type TimeUnit<-1> is used to
- * keep track of 1/seconds, etc.
- *
- * This base class defines all the functionality shared by all
- * these time unit objects: it defines all the classic arithmetic
- * operators +, -, *, /, and all the classic comparison operators:
- * ==, !=, <, >, <=, >=. It is thus easy to add, substract, or
- * multiply multiple TimeUnit objects. The return type of any such
- * arithmetic expression is always a TimeUnit object.
- *
- * The ns3::uint64_t, ns3::Time, ns3::TimeSquare, and ns3::TimeInvert classes
- * are aliases for the TimeUnit<0>, TimeUnit<1>, TimeUnit<2> and TimeUnit<-1>
- * types respectively.
- *
- * For example:
- * \code
- * Time<1> t1 = Seconds (10.0);
- * Time<1> t2 = Seconds (10.0);
- * Time<2> t3 = t1 * t2;
- * Time<0> t4 = t1 / t2;
- * Time<3> t5 = t3 * t1;
- * Time<-2> t6 = t1 / t5;
- * TimeSquare t7 = t3;
- * uint64_t s = t4;
- * \endcode
- *
- * If you try to assign the result of an expression which does not
- * match the type of the variable it is assigned to, you will get a
- * compiler error. For example, the following will not compile:
- * \code
- * Time<1> = Seconds (10.0) * Seconds (1.5);
- * \endcode
- *
- * You can also use the following non-member functions to manipulate
- * any of these ns3::TimeUnit object:
- *  - \ref ns3-Time-Abs ns3::Abs
- *  - \ref ns3-Time-Max ns3::Max
- *  - \ref ns3-Time-Min ns3::Min
- */
-/**
- * \ingroup time
  * \brief keep track of time values and allow control of global simulation resolution
  *
  * This class defines all the classic C++ arithmetic
  * operators +, -, *, /, and all the classic comparison operators:
  * ==, !=, <, >, <=, >=. It is thus easy to add, substract, or
- * multiply multiple Time objects.
- *
- * The ns3::uint64_t, ns3::TimeSquare, and ns3::TimeInvert classes
- * are backward-compatibility aliases for ns3::Time.
+ * multiply Time objects.
  *
  * For example:
  * \code
@@ -215,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
@@ -699,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 16:58:46 2013 +0200
+++ b/src/core/model/time.cc	Wed Jul 03 12:02:06 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 16:58:46 2013 +0200
+++ b/src/core/test/attribute-test-suite.cc	Wed Jul 03 12:02:06 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;