core: refactor ObjectBase::ConstructSelf
This commit is contained in:
@@ -26,6 +26,7 @@
|
||||
|
||||
#include <cstdlib> // getenv
|
||||
#include <cstring> // strlen
|
||||
#include <unordered_map>
|
||||
|
||||
/**
|
||||
* \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<bool, std::string>
|
||||
EnvDictionary (std::string key)
|
||||
{
|
||||
static std::unordered_map<std::string, std::string> 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<AttributeValue> value = attributes.Find (info.checker);
|
||||
|
||||
Ptr<const AttributeValue> 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<StringValue> (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<const AttributeAccessor> accessor,
|
||||
|
||||
Reference in New Issue
Block a user