diff --git a/src/core/model/object-base.cc b/src/core/model/object-base.cc index a289c70c5..9f77cb169 100644 --- a/src/core/model/object-base.cc +++ b/src/core/model/object-base.cc @@ -26,6 +26,7 @@ #include // getenv #include // strlen +#include /** * \file @@ -39,6 +40,64 @@ NS_LOG_COMPONENT_DEFINE ("ObjectBase"); NS_OBJECT_ENSURE_REGISTERED (ObjectBase); + /** Unnamed namespace */ +namespace { + +/** + * Get key, value pairs from the "NS_ATTRIBUTE_DEFAULT" environment variable. + * + * \param [in] key The key to search for. + * \return \c true if the key was found, and the associated value. + */ +std::pair +EnvDictionary (std::string key) +{ + static std::unordered_map dict; + + if (dict.size () == 0) + { + const char *envVar = getenv ("NS_ATTRIBUTE_DEFAULT"); + if (envVar != 0 && std::strlen (envVar) > 0) + { + std::string env = envVar; + std::string::size_type cur = 0; + std::string::size_type next = 0; + while (next != std::string::npos) + { + next = env.find (";", cur); + std::string tmp = std::string (env, cur, next - cur); + std::string::size_type equal = tmp.find ("="); + if (equal != std::string::npos) + { + std::string name = tmp.substr (0, equal); + std::string envval = tmp.substr (equal + 1, tmp.size () - equal - 1); + dict.insert ({name, envval}); + } + cur = next + 1; + } + } + else + { + // insert an empty key, so we don't do this again + dict.insert ({"", ""}); + } + } + + std::string value; + bool found {false}; + + auto loc = dict.find (key); + if (loc != dict.end ()) + { + value = loc->second; + found = true; + } + return {found, value}; +} + +} // unnamed namespace + + /** * Ensure the TypeId for ObjectBase gets fully configured * to anchor the inheritance tree properly. @@ -76,25 +135,49 @@ ObjectBase::NotifyConstructionCompleted (void) NS_LOG_FUNCTION (this); } +/** + * \def LOG_WHERE_VALUE(where, value) + * Log where and what value we find for the attribute + * \param where The source of the value + * \param value The value found, or "nothing" + */ +#ifdef NS3_LOG_ENABLE +#define LOG_WHERE_VALUE(where, value) \ + do { \ + std::string valStr {"nothing"}; \ + if (value) \ + { \ + valStr = "\"" + value->SerializeToString (info.checker) + "\""; \ + } \ + NS_LOG_DEBUG (where << " gave " << valStr); \ + } while (false) +#else +#define LOG_WHERE_VALUE(where, value) +#endif + void ObjectBase::ConstructSelf (const AttributeConstructionList &attributes) { // loop over the inheritance tree back to the Object base class. NS_LOG_FUNCTION (this << &attributes); TypeId tid = GetInstanceTypeId (); - do + do // Do this tid and all parents { // loop over all attributes in object type - NS_LOG_DEBUG ("construct tid=" << tid.GetName () << ", params=" << tid.GetAttributeN ()); + NS_LOG_DEBUG ("construct tid=" << tid.GetName () << + ", params=" << tid.GetAttributeN ()); for (uint32_t i = 0; i < tid.GetAttributeN (); i++) { struct TypeId::AttributeInformation info = tid.GetAttribute (i); NS_LOG_DEBUG ("try to construct \"" << tid.GetName () << "::" << info.name << "\""); - // is this attribute stored in this AttributeConstructionList instance ? - Ptr value = attributes.Find (info.checker); + + Ptr value = attributes.Find (info.checker); + std::string where = "argument"; + + LOG_WHERE_VALUE (where, value); // See if this attribute should not be set here in the - // constructor. + // constructor. if (!(info.flags & TypeId::ATTR_CONSTRUCT)) { // Handle this attribute if it should not be @@ -103,6 +186,7 @@ ObjectBase::ConstructSelf (const AttributeConstructionList &attributes) { // Skip this attribute if it's not in the // AttributeConstructionList. + NS_LOG_DEBUG ("skipping, not settable at construction"); continue; } else @@ -114,57 +198,44 @@ ObjectBase::ConstructSelf (const AttributeConstructionList &attributes) } } - if (value != 0) + if (!value) { - // We have a matching attribute value. - if (DoSet (info.accessor, info.checker, *value)) + auto [found, val] = EnvDictionary (tid.GetAttributeFullName (i)); + if (found) { - NS_LOG_DEBUG ("construct \"" << tid.GetName () << "::" << - info.name << "\""); - continue; + value = Create (val); + where = "env var"; + LOG_WHERE_VALUE (where, value); } } - // No matching attribute value so we try to look at the env var. - const char *envVar = getenv ("NS_ATTRIBUTE_DEFAULT"); - if (envVar != 0 && std::strlen (envVar) > 0) + bool initial = false; + if (!value) { - std::string env = envVar; - std::string::size_type cur = 0; - std::string::size_type next = 0; - while (next != std::string::npos) - { - next = env.find (";", cur); - std::string tmp = std::string (env, cur, next - cur); - std::string::size_type equal = tmp.find ("="); - if (equal != std::string::npos) - { - std::string name = tmp.substr (0, equal); - std::string envval = tmp.substr (equal + 1, tmp.size () - equal - 1); - if (name == tid.GetAttributeFullName (i)) - { - if (DoSet (info.accessor, info.checker, StringValue (envval))) - { - NS_LOG_DEBUG ("construct \"" << tid.GetName () << "::" << - info.name << "\" from env var"); - break; - } - } - } - cur = next + 1; - } + // Set from Tid initialValue, which is guaranteed to exist + value = info.initialValue; + where = "initial value"; + initial = true; + LOG_WHERE_VALUE (where, value); } - // No matching attribute value so we try to set the default value. - DoSet (info.accessor, info.checker, *info.initialValue); - NS_LOG_DEBUG ("construct \"" << tid.GetName () << "::" << - info.name << "\" from initial value."); - } + if (DoSet (info.accessor, info.checker, *value) || initial) + { + // Setting from initial value may fail, e.g. setting + // ObjectVectorValue from "" + // That's ok, so we still report success since construction is complete + NS_LOG_DEBUG ("construct \"" << tid.GetName () << "::" << + info.name << "\" from " << where); + } + + } // for i attributes tid = tid.GetParent (); } while (tid != ObjectBase::GetTypeId ()); NotifyConstructionCompleted (); + } +#undef LOG_WHERE_VALUE bool ObjectBase::DoSet (Ptr accessor,