--- 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;