diff --git a/src/core/model/attribute.cc b/src/core/model/attribute.cc --- a/src/core/model/attribute.cc +++ b/src/core/model/attribute.cc @@ -108,5 +108,89 @@ return true; } +EmptyAttributeAccessor::EmptyAttributeAccessor () : AttributeAccessor () +{ +} + +EmptyAttributeAccessor::~EmptyAttributeAccessor () +{ +} + +bool +EmptyAttributeAccessor::Set (ObjectBase * object, const AttributeValue &value) const +{ + (void) object; + (void) value; + return true; +} + +bool +EmptyAttributeAccessor::Get (const ObjectBase * object, AttributeValue &attribute) const +{ + (void) object; + (void) attribute; + return true; +} + +bool +EmptyAttributeAccessor::HasGetter (void) const +{ + return false; +} + +bool +EmptyAttributeAccessor::HasSetter (void) const +{ + return false; +} + +EmptyAttributeChecker::EmptyAttributeChecker () : AttributeChecker () +{ +} + +EmptyAttributeChecker::~EmptyAttributeChecker () +{ +} + +bool +EmptyAttributeChecker::Check (const AttributeValue &value) const +{ + (void) value; + return true; +} + +std::string +EmptyAttributeChecker::GetValueTypeName (void) const +{ + return "EmptyAttribute"; +} + +bool +EmptyAttributeChecker::HasUnderlyingTypeInformation (void) const +{ + return false; +} + +std::string +EmptyAttributeChecker::GetUnderlyingTypeInformation (void) const +{ + return ""; +} + +Ptr +EmptyAttributeChecker::Create (void) const +{ + static EmptyAttributeValue t; + return Ptr (&t, false); +} + +bool +EmptyAttributeChecker::Copy (const AttributeValue &source, AttributeValue &destination) const +{ + (void) source; + (void) destination; + return true; +} + } // namespace ns3 diff --git a/src/core/model/attribute.h b/src/core/model/attribute.h --- a/src/core/model/attribute.h +++ b/src/core/model/attribute.h @@ -222,8 +222,6 @@ * \return true if copy was successful */ virtual bool Copy (const AttributeValue &source, AttributeValue &destination) const = 0; - - }; /** @@ -259,6 +257,53 @@ virtual bool DeserializeFromString (std::string value, Ptr checker); }; +/** + * \brief An accessor for EmptyAttributeValue + * + * Does nothing, since every EmptyAttributeValue is the same. + */ +class EmptyAttributeAccessor : public AttributeAccessor +{ +public: + EmptyAttributeAccessor (); + ~EmptyAttributeAccessor (); + virtual bool Set (ObjectBase * object, const AttributeValue &value) const; + virtual bool Get (const ObjectBase * object, AttributeValue &attribute) const; + virtual bool HasGetter (void) const; + virtual bool HasSetter (void) const; +}; + +static inline Ptr +MakeEmptyAttributeAccessor () +{ + return Ptr (new EmptyAttributeAccessor (), false); +} + +/** + * \brief A checker for EmptyAttributeValue + * + * Does nothing, since every EmptyAttributeValue does not contain anything and + * is, of course, valid. + */ +class EmptyAttributeChecker : public AttributeChecker +{ +public: + EmptyAttributeChecker (); + ~EmptyAttributeChecker (); + virtual bool Check (const AttributeValue &value) const; + virtual std::string GetValueTypeName (void) const; + virtual bool HasUnderlyingTypeInformation (void) const; + virtual std::string GetUnderlyingTypeInformation (void) const; + virtual Ptr Create (void) const; + virtual bool Copy (const AttributeValue &source, AttributeValue &destination) const; +}; + +static inline Ptr +MakeEmptyAttributeChecker () +{ + return Ptr (new EmptyAttributeChecker (), false); +} + } // namespace ns3 #endif /* ATTRIBUTE_H */ diff --git a/src/core/model/trace-source-accessor.h b/src/core/model/trace-source-accessor.h --- a/src/core/model/trace-source-accessor.h +++ b/src/core/model/trace-source-accessor.h @@ -107,7 +107,7 @@ * type implements a statically-polymorphic set of Connect and Disconnect * methods and creates a dynamic-polymorphic class to wrap the underlying * static-polymorphic class. This functionality is typically provided - * by wrapping an object data member in a TracedCallback. + * by wrapping an object data member in a TracedCallback or TracedValue. * * \param [in] a The trace source * \returns The TraceSourceAccessor @@ -115,6 +115,19 @@ template Ptr MakeTraceSourceAccessor (T a); +/** + * \ingroup tracing + * + * Create an empty TraceSourceAccessor. + * + * \returns The empty TraceSourceAccessor (runtime exception if used) + */ +static inline +Ptr MakeEmptyTraceSourceAccessor () +{ + return Ptr (0); +} + } // namespace ns3 diff --git a/src/core/model/traced-value.h b/src/core/model/traced-value.h --- a/src/core/model/traced-value.h +++ b/src/core/model/traced-value.h @@ -87,6 +87,7 @@ typedef void (* Int32) (int32_t oldValue, int32_t newValue); typedef void (* Uint32)(uint32_t oldValue, uint32_t newValue); typedef void (* Double)(double oldValue, double newValue); + typedef void (* Void) (void); /**@}*/ } // namespace TracedValueCallback diff --git a/src/core/model/type-id.cc b/src/core/model/type-id.cc --- a/src/core/model/type-id.cc +++ b/src/core/model/type-id.cc @@ -195,6 +195,8 @@ * subclass. * \param [in] checker An instance of the associated AttributeChecker * subclass. + * \param [in] supportLevel The support/deprecation status for this attribute. + * \param [in] supportMsg Upgrade hint if this attribute is no longer supported. */ void AddAttribute (uint16_t uid, std::string name, @@ -202,7 +204,9 @@ uint32_t flags, Ptr initialValue, Ptr accessor, - Ptr checker); + Ptr checker, + TypeId::SupportLevel supportLevel = TypeId::SUPPORTED, + const std::string &supportMsg = ""); /** * Set the initial value of an Attribute. * \param [in] uid The id. @@ -236,13 +240,17 @@ * \param [in] callback Fully qualified typedef name for the callback * signature. Generally this should begin with the * "ns3::" namespace qualifier. + * \param [in] supportLevel The support/deprecation status for this attribute. + * \param [in] supportMsg Upgrade hint if this attribute is no longer supported. * \returns This TypeId instance. */ void AddTraceSource (uint16_t uid, std::string name, std::string help, Ptr accessor, - std::string callback); + std::string callback, + TypeId::SupportLevel supportLevel = TypeId::SUPPORTED, + const std::string &supportMsg = ""); /** * Get the number of Trace sources. * \param [in] uid The id. @@ -307,6 +315,10 @@ std::vector attributes; /** The container of TraceSources. */ std::vector traceSources; + /** Support level/deprecation. */ + TypeId::SupportLevel supportLevel; + /** Support message. */ + std::string supportMsg; }; /** Iterator type. */ typedef std::vector::const_iterator Iterator; @@ -617,15 +629,19 @@ } void -IidManager::AddAttribute (uint16_t uid, +IidManager::AddAttribute (uint16_t uid, std::string name, - std::string help, + std::string help, uint32_t flags, Ptr initialValue, Ptr accessor, - Ptr checker) + Ptr checker, + TypeId::SupportLevel supportLevel, + const std::string &supportMsg) { - NS_LOG_FUNCTION (this << uid << name << help << flags << initialValue << accessor << checker); + NS_LOG_FUNCTION (IID << uid << name << help << flags + << initialValue << accessor << checker + << supportLevel << supportMsg); struct IidInformation *information = LookupInformation (uid); if (HasAttribute (uid, name)) { @@ -640,6 +656,8 @@ info.originalInitialValue = initialValue; info.accessor = accessor; info.checker = checker; + info.supportLevel = supportLevel; + info.supportMsg = supportMsg; information->attributes.push_back (info); NS_LOG_LOGIC (IIDL << information->attributes.size () - 1); } @@ -711,9 +729,13 @@ std::string name, std::string help, Ptr accessor, - std::string callback) + std::string callback, + TypeId::SupportLevel supportLevel, + const std::string &supportMsg) { - NS_LOG_FUNCTION (this << uid << name << help << accessor); + NS_LOG_FUNCTION (IID << uid << name << help + << accessor << callback + << supportLevel << supportMsg); struct IidInformation *information = LookupInformation (uid); if (HasTraceSource (uid, name)) { @@ -725,6 +747,8 @@ source.help = help; source.accessor = accessor; source.callback = callback; + source.supportLevel = supportLevel; + source.supportMsg = supportMsg; information->traceSources.push_back (source); NS_LOG_LOGIC (IIDL << information->traceSources.size () - 1); } @@ -845,8 +869,24 @@ struct TypeId::AttributeInformation tmp = tid.GetAttribute(i); if (tmp.name == name) { - *info = tmp; - return true; + if (tmp.supportLevel == TypeId::SUPPORTED) + { + *info = tmp; + return true; + } + else if (tmp.supportLevel == TypeId::DEPRECATED) + { + NS_LOG_UNCOND ("Attribute '" << name << "' is deprecated: " + << tmp.supportMsg); + *info = tmp; + return true; + } + else if (tmp.supportLevel == TypeId::OBSOLETE) + { + NS_FATAL_ERROR ("Attribute '" << name + << "' is obsolete, with no fallback: " + << tmp.supportMsg); + } } } nextTid = tid.GetParent (); @@ -950,10 +990,16 @@ std::string help, const AttributeValue &initialValue, Ptr accessor, - Ptr checker) + Ptr checker, + SupportLevel supportLevel, + const std::string &supportMsg) { - NS_LOG_FUNCTION (this << name << help << &initialValue << accessor << checker); - IidManager::Get ()->AddAttribute (m_tid, name, help, ATTR_SGC, initialValue.Copy (), accessor, checker); + NS_LOG_FUNCTION (this << name << help + << &initialValue << accessor << checker + << supportLevel << supportMsg); + IidManager::Get ()->AddAttribute (m_tid, name, help, ATTR_SGC, + initialValue.Copy (), accessor, checker, + supportLevel, supportMsg); return *this; } @@ -963,10 +1009,16 @@ uint32_t flags, const AttributeValue &initialValue, Ptr accessor, - Ptr checker) + Ptr checker, + SupportLevel supportLevel, + const std::string &supportMsg) { - NS_LOG_FUNCTION (this << name << help << flags << &initialValue << accessor << checker); - IidManager::Get ()->AddAttribute (m_tid, name, help, flags, initialValue.Copy (), accessor, checker); + NS_LOG_FUNCTION (this << name << help << flags + << &initialValue << accessor << checker + << supportLevel << supportMsg); + IidManager::Get ()->AddAttribute (m_tid, name, help, flags, + initialValue.Copy (), accessor, checker, + supportLevel, supportMsg); return *this; } @@ -1042,10 +1094,16 @@ TypeId::AddTraceSource (std::string name, std::string help, Ptr accessor, - std::string callback) + std::string callback, + SupportLevel supportLevel, + const std::string &supportMsg) { - NS_LOG_FUNCTION (this << name << help << accessor); - IidManager::Get ()->AddTraceSource (m_tid, name, help, accessor, callback); + NS_LOG_FUNCTION (this << name << help + << accessor << callback + << supportLevel << supportMsg); + IidManager::Get ()->AddTraceSource (m_tid, name, help, + accessor, callback, + supportLevel, supportMsg); return *this; } @@ -1071,7 +1129,24 @@ struct TypeId::TraceSourceInformation tmp = tid.GetTraceSource (i); if (tmp.name == name) { - return info.accessor; + if (tmp.supportLevel == TypeId::SUPPORTED) + { + *info = tmp; + return tmp.accessor; + } + else if (tmp.supportLevel == TypeId::DEPRECATED) + { + NS_LOG_UNCOND ("TraceSource '" << name << "' is deprecated: " + << tmp.supportMsg); + *info = tmp; + return tmp.accessor; + } + else if (tmp.supportLevel == TypeId::OBSOLETE) + { + NS_FATAL_ERROR ("TraceSource '" << name + << "' is obsolete, with no fallback: " + << tmp.supportMsg); + } } } nextTid = tid.GetParent (); diff --git a/src/core/model/type-id.h b/src/core/model/type-id.h --- a/src/core/model/type-id.h +++ b/src/core/model/type-id.h @@ -65,6 +65,13 @@ ATTR_CONSTRUCT = 1<<2, /**< The attribute can be written at construction-time */ ATTR_SGC = ATTR_GET | ATTR_SET | ATTR_CONSTRUCT, /**< The attribute can be read, and written at any time */ }; + /** The level of support or deprecation for attributes or trace sources. */ + enum SupportLevel + { + SUPPORTED, /**< Attribute or trace source is currently used. */ + DEPRECATED, /**< Attribute or trace source is deprecated; user is warned. */ + OBSOLETE /**< Attribute or trace source is not used anymore; simulation fails. */ + }; /** Attribute implementation. */ struct AttributeInformation { /** Attribute name. */ @@ -81,6 +88,10 @@ Ptr accessor; /** Checker object. */ Ptr checker; + /** Support level/deprecation. */ + TypeId::SupportLevel supportLevel; + /** Support message. */ + std::string supportMsg; }; /** TraceSource implementation. */ struct TraceSourceInformation { @@ -92,6 +103,10 @@ std::string callback; /** Trace accessor. */ Ptr accessor; + /** Support level/deprecation. */ + TypeId::SupportLevel supportLevel; + /** Support message. */ + std::string supportMsg; }; /** Type of hash values. */ @@ -349,13 +364,24 @@ * subclass. * \param [in] checker An instance of the associated AttributeChecker * subclass. + * \param [in] supportLevel Support/deprecation status of the attribute. + * \param [in] supportMsg Upgrade hint if this attribute is no longer + * supported. If the attribute is \c DEPRECATED the attribute + * behavior still exists, but user code should be updated + * following guidance in the hint.. + * If the attribute is \c OBSOLETE, the hint should indicate + * which class the attribute functional has been moved to, + * or that the functionality is no longer supported. + * See \file type-id-test-case.cc for examples. * \returns This TypeId instance */ TypeId AddAttribute (std::string name, std::string help, const AttributeValue &initialValue, Ptr accessor, - Ptr checker); + Ptr checker, + SupportLevel supportLevel = SUPPORTED, + const std::string &supportMsg = ""); /** * Set the initial value of an Attribute. @@ -379,6 +405,14 @@ * subclass. * \param [in] checker An instance of the associated AttributeChecker * subclass. + * \param [in] supportLevel Support/deprecation status of the attribute. + * \param [in] supportMsg Upgrade hint if this attribute is no longer + * supported. If the attribute is \c DEPRECATED the attribute + * behavior still exists, but user code should be updated + * following guidance in the hint.. + * If the attribute is \c OBSOLETE, the hint should indicate + * which class the attribute functional has been moved to, + * or that the functionality is no longer supported. * \returns This TypeId instance */ TypeId AddAttribute (std::string name, @@ -386,7 +420,9 @@ uint32_t flags, const AttributeValue &initialValue, Ptr accessor, - Ptr checker); + Ptr checker, + SupportLevel supportLevel = SUPPORTED, + const std::string &supportMsg = ""); /** * Record a new TraceSource. @@ -415,12 +451,23 @@ * \param [in] callback Fully qualified typedef name for the callback * signature. Generally this should begin with the * "ns3::" namespace qualifier. + * \param [in] supportLevel Support/deprecation status of the attribute. + * \param [in] supportMsg Upgrade hint if this attribute is no longer + * supported. If the attribute is \c DEPRECATED the attribute + * behavior still exists, but user code should be updated + * following guidance in the hint.. + * If the attribute is \c OBSOLETE, the hint should indicate + * which class the attribute functional has been moved to, + * or that the functionality is no longer supported. + * See \file type-id-test-case.cc for examples. * \returns This TypeId instance. */ TypeId AddTraceSource (std::string name, std::string help, Ptr accessor, - std::string callback); + std::string callback, + SupportLevel supportLevel = SUPPORTED, + const std::string &supportMsg = ""); /** * Hide this TypeId from documentation. diff --git a/src/core/test/type-id-test-suite.cc b/src/core/test/type-id-test-suite.cc --- a/src/core/test/type-id-test-suite.cc +++ b/src/core/test/type-id-test-suite.cc @@ -22,6 +22,10 @@ #include #include +#include "ns3/integer.h" +#include "ns3/double.h" +#include "ns3/object.h" +#include "ns3/traced-value.h" #include "ns3/type-id.h" #include "ns3/test.h" #include "ns3/log.h" @@ -186,7 +190,140 @@ */ } + + +//---------------------------- +// +// Deprecated Attribute test + +class DeprecatedAttribute : public Object +{ +private: + // float m_obsAttr; // this is obsolete, no trivial forwarding + // int m_oldAttr; // this has become m_attr + int m_attr; + + // TracedValue m_obsTrace; // this is obsolete, no trivial forwarding + // TracedValue m_oldTrace; // this has become m_trace + TracedValue m_trace; + +public: + + virtual ~DeprecatedAttribute () { }; + + // Register a type with a deprecated Attribute and TraceSource + static TypeId GetTypeId (void) + { + static TypeId tid = TypeId ("DeprecatedAttribute") + .SetParent () + + // The new attribute + .AddAttribute ("attribute", + "the Attribute", + IntegerValue (1), + MakeIntegerAccessor (&DeprecatedAttribute::m_attr), + MakeIntegerChecker ()) + // The old deprecated attribute + .AddAttribute ("oldAttribute", + "the old attribute", + IntegerValue (1), + MakeIntegerAccessor (&DeprecatedAttribute::m_attr), + MakeIntegerChecker (), + TypeId::DEPRECATED, + "use 'attribute' instead") + // Obsolete attribute, as an example + .AddAttribute ("obsoleteAttribute", + "the obsolete attribute", + EmptyAttributeValue (), + MakeEmptyAttributeAccessor (), + MakeEmptyAttributeChecker (), + TypeId::OBSOLETE, + "refactor to use 'attribute'") + + // The new trace source + .AddTraceSource ("trace", + "the TraceSource", + MakeTraceSourceAccessor (&DeprecatedAttribute::m_trace), + "ns3::TracedValueCallback::Double") + // The old trace source + .AddTraceSource ("oldTrace", + "the old trace source", + MakeTraceSourceAccessor (&DeprecatedAttribute::m_trace), + "ns3::TracedValueCallback::Double", + TypeId::DEPRECATED, + "use 'trace' instead") + // Obsolete trace source, as an example + .AddTraceSource ("obsoleteTraceSource", + "the obsolete trace source", + MakeEmptyTraceSourceAccessor (), + "ns3::TracedValueCallback::Void", + TypeId::OBSOLETE, + "refactor to use 'trace'"); + + return tid; + } + +}; + + +class DeprecatedAttributeTestCase : public TestCase +{ +public: + DeprecatedAttributeTestCase (); + virtual ~DeprecatedAttributeTestCase (); +private: + virtual void DoRun (void); + +}; + +DeprecatedAttributeTestCase::DeprecatedAttributeTestCase () + : TestCase ("Check deprecated Attributes and TraceSources") +{ +} + +DeprecatedAttributeTestCase::~DeprecatedAttributeTestCase () +{ +} + +void +DeprecatedAttributeTestCase::DoRun (void) +{ + cerr << suite << endl; + cerr << suite << GetName () << endl; + + TypeId tid = DeprecatedAttribute::GetTypeId (); + cerr << suite << "DeprecatedAttribute TypeId: " << tid.GetUid () << endl; + // Try the lookups + struct TypeId::AttributeInformation ainfo; + NS_TEST_ASSERT_MSG_EQ (tid.LookupAttributeByName ("attribute", &ainfo), true, + "lookup new attribute"); + cerr << suite << "lookup new attribute:" + << (ainfo.supportLevel == TypeId::SUPPORTED ? "supported" : "error") + << endl; + + NS_TEST_ASSERT_MSG_EQ (tid.LookupAttributeByName ("oldAttribute", &ainfo), true, + "lookup old attribute"); + cerr << suite << "lookup old attribute:" + << (ainfo.supportLevel == TypeId::DEPRECATED ? "deprecated" : "error") + << endl; + + + struct TypeId::TraceSourceInformation tinfo; + Ptr acc; + acc = tid.LookupTraceSourceByName ("trace", &tinfo); + NS_TEST_ASSERT_MSG_NE (acc, 0, "lookup new trace source"); + cerr << suite << "lookup new trace source:" + << (tinfo.supportLevel == TypeId::SUPPORTED ? "supported" : "error") + << endl; + + acc = tid.LookupTraceSourceByName ("oldTrace", &tinfo); + NS_TEST_ASSERT_MSG_NE (acc, 0, "lookup old trace source"); + cerr << suite << "lookup old trace source:" + << (tinfo.supportLevel == TypeId::DEPRECATED ? "deprecated" : "error") + << endl; +} + //---------------------------- // @@ -298,6 +435,7 @@ // as chained. AddTestCase (new UniqueTypeIdTestCase, QUICK); AddTestCase (new CollisionTestCase, QUICK); + AddTestCase (new DeprecatedAttributeTestCase, QUICK); } static TypeIdTestSuite g_TypeIdTestSuite;