diff --git a/src/core/model/attribute-helper.h b/src/core/model/attribute-helper.h --- a/src/core/model/attribute-helper.h +++ b/src/core/model/attribute-helper.h @@ -22,6 +22,7 @@ #include "attribute.h" #include "attribute-accessor-helper.h" +#include "config.h" #include #include "fatal-error.h" @@ -29,7 +30,7 @@ /** * \ingroup attribute - * \defgroup attributehelper Attribute Helper + * \defgroup attributehelper Attribute Helpers * * All these macros can be used to generate automatically the code * for subclasses of AttributeValue, AttributeAccessor, and, AttributeChecker, @@ -127,8 +128,7 @@ return Ptr (checker, false); } -} - + /** * \ingroup attributehelper * @@ -192,8 +192,7 @@ Ptr checker); \ private: \ type m_value; \ - }; - + } /** * \ingroup attributehelper @@ -247,6 +246,32 @@ class type ## Checker : public AttributeChecker {}; \ Ptr Make ## type ## Checker (void) +/** + * \ingroup attributehelper + * + * Declare the Config::GetDefaultValue<>() specializations for \p type. + * + * \param type The return type. + * + * This macro declares the Config::GetDefaultValue<>() specialization + * returning the current default configuration value of an attribute, + * as a \c type. If the attribute at the configuration path is not + * compatible with the requested type, the function will raise a + * fatal error. + * + * This macro is typically invoked in the class header file. + * + * \note This macro must be invoked from namespace ns3. + * + * \see + * GetDefaultValue<>() + */ +#define ATTRIBUTE_GETDEFAULT_DEFINE(type) \ + namespace Config { \ + template<> type \ + GetDefaultValue (const std::string attributePath); \ + } /* namespace Config */ + /** * \ingroup attributehelper @@ -345,12 +370,98 @@ Ptr Make ## type ## Checker (void) { \ return MakeSimpleAttributeChecker \ (# type "Value", name); \ - } \ + } + + +namespace Config { + +/** + * \ingroup config + * Config::GetDefaultValue<>() helper to fetch an attribute path as + * the base AttributeValue. + * + * \param attributePath The configuration path for the attribute. + * \returns The AttributeValue. + * + * \internal + * This is declared in attribute-helper.h to break an include cycle. + * The implementation is in config.cc. + */ +Ptr +GetDefaultAttributeValue (const std::string attributePath); + +} // namespace Config + /** * \ingroup attributehelper * - * Declare the attribute value, accessor and checkers for class \p type + * Define the Config::GetDefaultValue<>() specialization for the attribute + * value class \c \typeValue, for underlying class \p type. + * + * \param type The underlying type name. + * \param typeValue The derived AttributeValue class corresponding to + * \c type. + * + * This macro implements the Config::GetDefaultValue<>() specialization + * returning the current default configuration value of an attribute + * as a \c type. If the attribute at the configuration path is not + * compatible with the requested type, the function will raise a + * fatal error. + * + * This macro is typically invoked in the source file. + * + * \note This macro must be invoked from namespace ns3. + * + * \see Config::GetDefaultValue<>() + */ +#define ATTRIBUTE_GETDEFAULT_IMPLEMENT_WITH_NAME(type,typeValue) \ + namespace Config { \ + template<> type \ + GetDefaultValue (const std::string attributePath) \ + { \ + Ptr attrValue = \ + GetDefaultAttributeValue (attributePath); \ + Ptr attr = \ + DynamicCast (attrValue); \ + if (!attr) { \ + NS_FATAL_ERROR ("Unable to convert attribute \"" \ + << attributePath << "\" to type " \ + << #typeValue ); \ + } \ + return attr->Get (); \ + } \ + } /* namespace Config */ + + +/** + * \ingroup attributehelper + * + * Define the Config::GetDefaultValue<>() specialization for the attribute + * value class \p \Value, for underlying class \p Name. + * + * \param Name The underlying type name. + * + * This macro implements the Config::GetDefaultValue<>() specialization + * returning the current default configuration value of an attribute, + * as a \c Name. If the attribute at the configuration path is not + * compatible with the requested type, the function will raise a + * fatal error. + * + * This macro is typically invoked in the source file. + * + * \note This macro must be invoked from namespace ns3. + * + * \see Config::GetDefaultValue<>() + */ +#define ATTRIBUTE_GETDEFAULT_IMPLEMENT(Name) \ + ATTRIBUTE_GETDEFAULT_IMPLEMENT_WITH_NAME(Name, Name ## Value) + +/** + * \ingroup attributehelper + * + * Declare the attribute value, accessor, checkers and + * Config::GetDefaultValue<>() specialization for class \p type * * \param type the name of the class * @@ -363,20 +474,25 @@ * - The AttributeChecker class \p \Checker * and the \c MakeTypeChecker function, * + * - The Config::GetDefaultValue<>() specialization for getting the default + * configuration value of an attribute as a \p type, + * * for class \p type. * * This macro should be invoked outside of the class - * declaration in its public header. + * declaration in its public header, normally in namespace ns3. */ #define ATTRIBUTE_HELPER_HEADER(type) \ ATTRIBUTE_VALUE_DEFINE (type); \ ATTRIBUTE_ACCESSOR_DEFINE (type); \ - ATTRIBUTE_CHECKER_DEFINE (type); + ATTRIBUTE_CHECKER_DEFINE (type); \ + ATTRIBUTE_GETDEFAULT_DEFINE (type) /** * \ingroup attributehelper * - * Define the attribute value, accessor and checkers for class \p type + * Define the attribute value, accessor, checkers and + * Config::GetDefaultValue<>() specialization for class \p type * * \param type the name of the class * @@ -386,13 +502,19 @@ * * - The \c MakeTypeChecker function, * + * - The Config::GetDefaultValue<>() specialization, + * * for class \p type. * - * This macro should be invoked from the class implementation file. + * This macro should be invoked from the class implementation file, + * normally in namespace ns3. */ #define ATTRIBUTE_HELPER_CPP(type) \ ATTRIBUTE_CHECKER_IMPLEMENT (type); \ - ATTRIBUTE_VALUE_IMPLEMENT (type); + ATTRIBUTE_VALUE_IMPLEMENT (type); \ + ATTRIBUTE_GETDEFAULT_IMPLEMENT (type) + +} // namespace ns3 #endif /* ATTRIBUTE_HELPER_H */ diff --git a/src/core/model/callback.h b/src/core/model/callback.h --- a/src/core/model/callback.h +++ b/src/core/model/callback.h @@ -1718,13 +1718,28 @@ virtual bool DeserializeFromString (std::string value, Ptr checker); private: CallbackBase m_value; //!< the CallbackBase -}; + +}; // class CallbackValue ATTRIBUTE_ACCESSOR_DEFINE (Callback); ATTRIBUTE_CHECKER_DEFINE (Callback); +/* + Can't implement Config::GetDefault<> specialization for + Callback + + This ends up being a function partial specialization, + which isn't allowed. + +ATTRIBUTE_GETDEFAULT_DEFINE (Callback); +*/ } // namespace ns3 + +/******************************************************************** + * Implementation of templates defined above + ********************************************************************/ + namespace ns3 { template diff --git a/src/core/model/config.cc b/src/core/model/config.cc --- a/src/core/model/config.cc +++ b/src/core/model/config.cc @@ -776,6 +776,50 @@ return Singleton::Get ()->GetRootNamespaceObject (i); } +/** + * \ingroup config + * GetDefaultValue<>() helper to fetch the TypeId::AttributeInformation. + * + * \param attributePath The configuration path for the attribute. + * \returns The TypeId::AttributeInformation. + * + * This is internal to the Config system. + */ +Ptr +GetAttributeInformation(const std::string attributePath) +{ + NS_LOG_FUNCTION (attributePath); + // Attribute name is last token + size_t colon = attributePath.rfind ("::"); + const std::string typeName = attributePath.substr (0, colon); + NS_LOG_DEBUG ("typeName: '" << typeName << "', colon: " << colon); + + TypeId tid; + if (!TypeId::LookupByNameFailSafe (typeName, &tid)) + { + NS_FATAL_ERROR ("Unknown type=" << typeName); + } + + const std::string attrName = attributePath.substr (colon + 2); + Ptr info = + Create (); + if (!tid.LookupAttributeByName (attrName, PeekPointer (info)) ) + { + NS_FATAL_ERROR ("Attribute not found: " << attributePath); + } + return info; +} + +Ptr +GetDefaultAttributeValue (const std::string attributePath) +{ + Ptr info = + GetAttributeInformation (attributePath); + Ptr attr = info->initialValue; + return attr; +} + + } // namespace Config } // namespace ns3 diff --git a/src/core/model/config.h b/src/core/model/config.h --- a/src/core/model/config.h +++ b/src/core/model/config.h @@ -247,6 +247,42 @@ */ Ptr GetRootNamespaceObject (uint32_t i); +/** + * \ingroup config + * Get the current default value for an attribute. + * + * The current default is the initial value which would be + * used by new instances of the type, including any + * CommandLine or environment variable configuration. + * + * \tparam R The type to return. + * \param attributePath The configuration path for the attribute. + * \returns The default value. + * + * GetDefaultValue<>() will raise a fatal error if the attribute + * can't be converted to the desired type. + * + * \internal + * + * GetDefaultValue<>() proceeds by first looking up the default value as a base + * AttributeValue, then attempting to upcast to the derived AttributeValue + * type associated with the requested return type, then finally + * getting the default value from the derived AttributeValue. + * + * For example, if the desired return type is an ns3::DataRate, the + * base AttributeValue will be upcast to a DataRateValue. If this fails + * GetDefaultValue<>() will raise a fatal error. + * + * There is no generic template declaration; only specializations + * of this template exist. Specializations are declared and implemented + * by the ATTRIBUTE_GETDEFAULT_DEFINE() and ATTRIBUTE_GETDEFAULT_IMPLEMENT() + * macros, which are normally invoked by the ATTRIBUTE_HELPER_HEADER() and + * ATTRIBUTE_HELPER_CPP() macros. + */ +template +R +GetDefaultValue (const std::string attributePath); + } // namespace Config } // namespace ns3 diff --git a/src/core/model/double.cc b/src/core/model/double.cc --- a/src/core/model/double.cc +++ b/src/core/model/double.cc @@ -27,6 +27,7 @@ NS_LOG_COMPONENT_DEFINE ("Double"); ATTRIBUTE_VALUE_IMPLEMENT_WITH_NAME (double, Double); +ATTRIBUTE_GETDEFAULT_IMPLEMENT_WITH_NAME (double, DoubleValue); namespace internal { diff --git a/src/core/model/double.h b/src/core/model/double.h --- a/src/core/model/double.h +++ b/src/core/model/double.h @@ -34,6 +34,7 @@ */ ATTRIBUTE_VALUE_DEFINE_WITH_NAME (double, Double); ATTRIBUTE_ACCESSOR_DEFINE (Double); +ATTRIBUTE_GETDEFAULT_DEFINE (double); template Ptr MakeDoubleChecker (void); diff --git a/src/core/model/integer.cc b/src/core/model/integer.cc --- a/src/core/model/integer.cc +++ b/src/core/model/integer.cc @@ -27,6 +27,7 @@ NS_LOG_COMPONENT_DEFINE ("Integer"); ATTRIBUTE_VALUE_IMPLEMENT_WITH_NAME (int64_t, Integer); +ATTRIBUTE_GETDEFAULT_IMPLEMENT_WITH_NAME (int64_t, IntegerValue); namespace internal { diff --git a/src/core/model/integer.h b/src/core/model/integer.h --- a/src/core/model/integer.h +++ b/src/core/model/integer.h @@ -37,6 +37,7 @@ */ ATTRIBUTE_VALUE_DEFINE_WITH_NAME (int64_t, Integer); ATTRIBUTE_ACCESSOR_DEFINE (Integer); +ATTRIBUTE_GETDEFAULT_DEFINE (int64_t); template Ptr MakeIntegerChecker (void); diff --git a/src/core/model/nstime.h b/src/core/model/nstime.h --- a/src/core/model/nstime.h +++ b/src/core/model/nstime.h @@ -919,6 +919,7 @@ * \brief Attribute for objects of type ns3::Time */ ATTRIBUTE_VALUE_DEFINE (Time); +ATTRIBUTE_GETDEFAULT_DEFINE (Time); /** * Attribute accessor function for Time 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 @@ -60,7 +60,8 @@ 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 */ }; - struct AttributeInformation { + struct AttributeInformation : public SimpleRefCount + { std::string name; std::string help; uint32_t flags; @@ -412,7 +413,7 @@ * \brief hold objects of type ns3::TypeId */ - + ATTRIBUTE_HELPER_HEADER (TypeId); } // namespace ns3 diff --git a/src/core/test/attribute-test-suite.cc b/src/core/test/attribute-test-suite.cc --- a/src/core/test/attribute-test-suite.cc +++ b/src/core/test/attribute-test-suite.cc @@ -72,8 +72,20 @@ { return is; } -ATTRIBUTE_HELPER_HEADER (ValueClassTest); -ATTRIBUTE_HELPER_CPP (ValueClassTest); + +ATTRIBUTE_VALUE_DEFINE (ValueClassTest); +ATTRIBUTE_ACCESSOR_DEFINE (ValueClassTest); +ATTRIBUTE_CHECKER_DEFINE (ValueClassTest); + +namespace ns3 { +ATTRIBUTE_GETDEFAULT_DEFINE (ValueClassTest); +} + +ATTRIBUTE_CHECKER_IMPLEMENT (ValueClassTest); +ATTRIBUTE_VALUE_IMPLEMENT (ValueClassTest); +namespace ns3 { +ATTRIBUTE_GETDEFAULT_IMPLEMENT (ValueClassTest); +} class Derived : public Object { diff --git a/src/mesh/model/dot11s/ie-dot11s-id.cc b/src/mesh/model/dot11s/ie-dot11s-id.cc --- a/src/mesh/model/dot11s/ie-dot11s-id.cc +++ b/src/mesh/model/dot11s/ie-dot11s-id.cc @@ -151,8 +151,11 @@ return is; } -ATTRIBUTE_HELPER_CPP (IeMeshId); - +ATTRIBUTE_VALUE_IMPLEMENT (IeMeshId); +ATTRIBUTE_CHECKER_IMPLEMENT (IeMeshId); } // namespace dot11s + +ATTRIBUTE_GETDEFAULT_IMPLEMENT (ns3::dot11s::IeMeshId); + } // namespace ns3 diff --git a/src/mesh/model/dot11s/ie-dot11s-id.h b/src/mesh/model/dot11s/ie-dot11s-id.h --- a/src/mesh/model/dot11s/ie-dot11s-id.h +++ b/src/mesh/model/dot11s/ie-dot11s-id.h @@ -58,12 +58,13 @@ std::ostream &operator << (std::ostream &os, const IeMeshId &meshId); -/** - * \class ns3::IeMeshIdValue - * \brief hold objects of type ns3::IeMeshId - */ +ATTRIBUTE_VALUE_DEFINE (IeMeshId); +ATTRIBUTE_ACCESSOR_DEFINE (IeMeshId); +ATTRIBUTE_CHECKER_DEFINE (IeMeshId); -ATTRIBUTE_HELPER_HEADER (IeMeshId); } // namespace dot11s + +ATTRIBUTE_GETDEFAULT_DEFINE (ns3::dot11s::IeMeshId); + } // namespace ns3 #endif /* MESH_ID_H */