Merge bounded Time attributes

This commit is contained in:
Peter D. Barnes, Jr.
2013-07-03 12:02:06 -07:00
5 changed files with 180 additions and 54 deletions

View File

@@ -55,6 +55,7 @@ us a note on ns-developers mailing list.</p>
<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>

View File

@@ -21,6 +21,7 @@ Supported platforms
New user-visible features
-------------------------
- Time attributes can now be bounded. See attribute-test-suite.cc for an example.
Bugs fixed
----------

View File

@@ -34,52 +34,6 @@ namespace ns3 {
* \ingroup core
* \defgroup time Time
*/
/**
* \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
@@ -87,10 +41,7 @@ namespace ns3 {
* 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
@@ -214,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.
*/
@@ -699,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;