367 lines
11 KiB
C++
367 lines
11 KiB
C++
/*
|
|
* Copyright (c) 2008 INRIA
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License version 2 as
|
|
* published by the Free Software Foundation;
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*
|
|
* Authors: Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
|
|
*/
|
|
#include "object-base.h"
|
|
|
|
#include "assert.h"
|
|
#include "attribute-construction-list.h"
|
|
#include "environment-variable.h"
|
|
#include "log.h"
|
|
#include "string.h"
|
|
#include "trace-source-accessor.h"
|
|
|
|
#include "ns3/core-config.h"
|
|
|
|
/**
|
|
* \file
|
|
* \ingroup object
|
|
* ns3::ObjectBase class implementation.
|
|
*/
|
|
|
|
namespace ns3
|
|
{
|
|
|
|
NS_LOG_COMPONENT_DEFINE("ObjectBase");
|
|
|
|
NS_OBJECT_ENSURE_REGISTERED(ObjectBase);
|
|
|
|
/**
|
|
* Ensure the TypeId for ObjectBase gets fully configured
|
|
* to anchor the inheritance tree properly.
|
|
*
|
|
* \relates ns3::ObjectBase
|
|
*
|
|
* \return The TypeId for ObjectBase.
|
|
*/
|
|
static TypeId
|
|
GetObjectIid()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
TypeId tid = TypeId("ns3::ObjectBase");
|
|
tid.SetParent(tid);
|
|
tid.SetGroupName("Core");
|
|
return tid;
|
|
}
|
|
|
|
TypeId
|
|
ObjectBase::GetTypeId()
|
|
{
|
|
NS_LOG_FUNCTION_NOARGS();
|
|
static TypeId tid = GetObjectIid();
|
|
return tid;
|
|
}
|
|
|
|
ObjectBase::~ObjectBase()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
}
|
|
|
|
void
|
|
ObjectBase::NotifyConstructionCompleted()
|
|
{
|
|
NS_LOG_FUNCTION(this);
|
|
}
|
|
|
|
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 this tid and all parents
|
|
{
|
|
// loop over all attributes in object type
|
|
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<const AttributeValue> value = attributes.Find(info.checker);
|
|
std::string where = "argument";
|
|
|
|
// See if this attribute should not be set here in the
|
|
// constructor.
|
|
if (!(info.flags & TypeId::ATTR_CONSTRUCT))
|
|
{
|
|
// Handle this attribute if it should not be
|
|
// set here.
|
|
if (!value)
|
|
{
|
|
// Skip this attribute if it's not in the
|
|
// AttributeConstructionList.
|
|
NS_LOG_DEBUG("skipping, not settable at construction");
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
// This is an error because this attribute is not
|
|
// settable in its constructor but is present in
|
|
// the AttributeConstructionList.
|
|
NS_FATAL_ERROR("Attribute name="
|
|
<< info.name << " tid=" << tid.GetName()
|
|
<< ": initial value cannot be set using attributes");
|
|
}
|
|
}
|
|
|
|
if (!value)
|
|
{
|
|
NS_LOG_DEBUG("trying to set from environment variable NS_ATTRIBUTE_DEFAULT");
|
|
auto [found, val] =
|
|
EnvironmentVariable::Get("NS_ATTRIBUTE_DEFAULT", tid.GetAttributeFullName(i));
|
|
if (found)
|
|
{
|
|
NS_LOG_DEBUG("found in environment: " << val);
|
|
value = Create<StringValue>(val);
|
|
where = "env var";
|
|
}
|
|
}
|
|
|
|
bool initial{false};
|
|
if (!value)
|
|
{
|
|
// This is guaranteed to exist
|
|
NS_LOG_DEBUG("falling back to initial value from tid");
|
|
value = info.initialValue;
|
|
where = "initial value";
|
|
initial = true;
|
|
}
|
|
|
|
// We have a matching attribute value, if only from the initialValue
|
|
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);
|
|
}
|
|
else
|
|
{
|
|
/*
|
|
One would think this is an error...
|
|
|
|
but there are cases where `attributes.Find(info.checker)`
|
|
returns a non-null value which still fails the `DoSet()` call.
|
|
For example, `value` is sometimes a real `PointerValue`
|
|
containing 0 as the pointed-to address. Since value
|
|
is not null (it just contains null) the initial
|
|
value is not used, the DoSet fails, and we end up
|
|
here.
|
|
|
|
If we were adventurous we might try to fix this deep
|
|
below DoSet, but there be dragons.
|
|
*/
|
|
/*
|
|
NS_ASSERT_MSG(false,
|
|
"Failed to set attribute '" << info.name << "' from '"
|
|
<< value->SerializeToString(info.checker)
|
|
<< "'");
|
|
*/
|
|
}
|
|
|
|
} // for i attributes
|
|
tid = tid.GetParent();
|
|
} while (tid != ObjectBase::GetTypeId());
|
|
NotifyConstructionCompleted();
|
|
}
|
|
|
|
bool
|
|
ObjectBase::DoSet(Ptr<const AttributeAccessor> accessor,
|
|
Ptr<const AttributeChecker> checker,
|
|
const AttributeValue& value)
|
|
{
|
|
NS_LOG_FUNCTION(this << accessor << checker << &value);
|
|
Ptr<AttributeValue> v = checker->CreateValidValue(value);
|
|
if (!v)
|
|
{
|
|
return false;
|
|
}
|
|
bool ok = accessor->Set(this, *v);
|
|
return ok;
|
|
}
|
|
|
|
void
|
|
ObjectBase::SetAttribute(std::string name, const AttributeValue& value)
|
|
{
|
|
NS_LOG_FUNCTION(this << name << &value);
|
|
struct TypeId::AttributeInformation info;
|
|
TypeId tid = GetInstanceTypeId();
|
|
if (!tid.LookupAttributeByName(name, &info))
|
|
{
|
|
NS_FATAL_ERROR(
|
|
"Attribute name=" << name << " does not exist for this object: tid=" << tid.GetName());
|
|
}
|
|
if (!(info.flags & TypeId::ATTR_SET) || !info.accessor->HasSetter())
|
|
{
|
|
NS_FATAL_ERROR(
|
|
"Attribute name=" << name << " is not settable for this object: tid=" << tid.GetName());
|
|
}
|
|
if (!DoSet(info.accessor, info.checker, value))
|
|
{
|
|
NS_FATAL_ERROR("Attribute name=" << name << " could not be set for this object: tid="
|
|
<< tid.GetName());
|
|
}
|
|
}
|
|
|
|
bool
|
|
ObjectBase::SetAttributeFailSafe(std::string name, const AttributeValue& value)
|
|
{
|
|
NS_LOG_FUNCTION(this << name << &value);
|
|
struct TypeId::AttributeInformation info;
|
|
TypeId tid = GetInstanceTypeId();
|
|
if (!tid.LookupAttributeByName(name, &info))
|
|
{
|
|
return false;
|
|
}
|
|
if (!(info.flags & TypeId::ATTR_SET) || !info.accessor->HasSetter())
|
|
{
|
|
return false;
|
|
}
|
|
return DoSet(info.accessor, info.checker, value);
|
|
}
|
|
|
|
void
|
|
ObjectBase::GetAttribute(std::string name, AttributeValue& value) const
|
|
{
|
|
NS_LOG_FUNCTION(this << name << &value);
|
|
struct TypeId::AttributeInformation info;
|
|
TypeId tid = GetInstanceTypeId();
|
|
if (!tid.LookupAttributeByName(name, &info))
|
|
{
|
|
NS_FATAL_ERROR(
|
|
"Attribute name=" << name << " does not exist for this object: tid=" << tid.GetName());
|
|
}
|
|
if (!(info.flags & TypeId::ATTR_GET) || !info.accessor->HasGetter())
|
|
{
|
|
NS_FATAL_ERROR(
|
|
"Attribute name=" << name << " is not gettable for this object: tid=" << tid.GetName());
|
|
}
|
|
bool ok = info.accessor->Get(this, value);
|
|
if (ok)
|
|
{
|
|
return;
|
|
}
|
|
StringValue* str = dynamic_cast<StringValue*>(&value);
|
|
if (str == nullptr)
|
|
{
|
|
NS_FATAL_ERROR("Attribute name=" << name << " tid=" << tid.GetName()
|
|
<< ": input value is not a string");
|
|
}
|
|
Ptr<AttributeValue> v = info.checker->Create();
|
|
ok = info.accessor->Get(this, *PeekPointer(v));
|
|
if (!ok)
|
|
{
|
|
NS_FATAL_ERROR("Attribute name=" << name << " tid=" << tid.GetName()
|
|
<< ": could not get value");
|
|
}
|
|
str->Set(v->SerializeToString(info.checker));
|
|
}
|
|
|
|
bool
|
|
ObjectBase::GetAttributeFailSafe(std::string name, AttributeValue& value) const
|
|
{
|
|
NS_LOG_FUNCTION(this << name << &value);
|
|
struct TypeId::AttributeInformation info;
|
|
TypeId tid = GetInstanceTypeId();
|
|
if (!tid.LookupAttributeByName(name, &info))
|
|
{
|
|
return false;
|
|
}
|
|
if (!(info.flags & TypeId::ATTR_GET) || !info.accessor->HasGetter())
|
|
{
|
|
return false;
|
|
}
|
|
bool ok = info.accessor->Get(this, value);
|
|
if (ok)
|
|
{
|
|
return true;
|
|
}
|
|
StringValue* str = dynamic_cast<StringValue*>(&value);
|
|
if (str == nullptr)
|
|
{
|
|
return false;
|
|
}
|
|
Ptr<AttributeValue> v = info.checker->Create();
|
|
ok = info.accessor->Get(this, *PeekPointer(v));
|
|
if (!ok)
|
|
{
|
|
return false;
|
|
}
|
|
str->Set(v->SerializeToString(info.checker));
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
ObjectBase::TraceConnectWithoutContext(std::string name, const CallbackBase& cb)
|
|
{
|
|
NS_LOG_FUNCTION(this << name << &cb);
|
|
TypeId tid = GetInstanceTypeId();
|
|
Ptr<const TraceSourceAccessor> accessor = tid.LookupTraceSourceByName(name);
|
|
if (!accessor)
|
|
{
|
|
return false;
|
|
}
|
|
bool ok = accessor->ConnectWithoutContext(this, cb);
|
|
return ok;
|
|
}
|
|
|
|
bool
|
|
ObjectBase::TraceConnect(std::string name, std::string context, const CallbackBase& cb)
|
|
{
|
|
NS_LOG_FUNCTION(this << name << context << &cb);
|
|
TypeId tid = GetInstanceTypeId();
|
|
Ptr<const TraceSourceAccessor> accessor = tid.LookupTraceSourceByName(name);
|
|
if (!accessor)
|
|
{
|
|
return false;
|
|
}
|
|
bool ok = accessor->Connect(this, context, cb);
|
|
return ok;
|
|
}
|
|
|
|
bool
|
|
ObjectBase::TraceDisconnectWithoutContext(std::string name, const CallbackBase& cb)
|
|
{
|
|
NS_LOG_FUNCTION(this << name << &cb);
|
|
TypeId tid = GetInstanceTypeId();
|
|
Ptr<const TraceSourceAccessor> accessor = tid.LookupTraceSourceByName(name);
|
|
if (!accessor)
|
|
{
|
|
return false;
|
|
}
|
|
bool ok = accessor->DisconnectWithoutContext(this, cb);
|
|
return ok;
|
|
}
|
|
|
|
bool
|
|
ObjectBase::TraceDisconnect(std::string name, std::string context, const CallbackBase& cb)
|
|
{
|
|
NS_LOG_FUNCTION(this << name << context << &cb);
|
|
TypeId tid = GetInstanceTypeId();
|
|
Ptr<const TraceSourceAccessor> accessor = tid.LookupTraceSourceByName(name);
|
|
if (!accessor)
|
|
{
|
|
return false;
|
|
}
|
|
bool ok = accessor->Disconnect(this, context, cb);
|
|
return ok;
|
|
}
|
|
|
|
} // namespace ns3
|