/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */ /* * Copyright (c) 2007 INRIA, Gustavo Carneiro * * 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: Gustavo Carneiro , * Mathieu Lacage */ #include "object.h" #include "assert.h" #include "singleton.h" #include "trace-resolver.h" #include "attribute.h" #include "log.h" #include #include NS_LOG_COMPONENT_DEFINE ("Object"); /********************************************************************* * Helper code *********************************************************************/ namespace { class IidManager { public: IidManager (); uint16_t AllocateUid (std::string name); void SetParent (uint16_t uid, uint16_t parent); void SetTypeName (uint16_t uid, std::string typeName); void SetGroupName (uint16_t uid, std::string groupName); void AddConstructor (uint16_t uid, ns3::CallbackBase callback, uint32_t nArguments); uint16_t GetUid (std::string name) const; std::string GetName (uint16_t uid) const; uint16_t GetParent (uint16_t uid) const; std::string GetTypeName (uint16_t uid) const; std::string GetGroupName (uint16_t uid) const; ns3::CallbackBase GetConstructor (uint16_t uid, uint32_t nArguments); bool HasConstructor (uint16_t uid); uint32_t GetRegisteredN (void); uint16_t GetRegistered (uint32_t i); void AddParameter (uint16_t uid, std::string name, std::string help, uint32_t flags, ns3::Attribute initialValue, ns3::Ptr spec, ns3::Ptr checker); uint32_t GetParametersN (uint16_t uid) const; std::string GetParameterName (uint16_t uid, uint32_t i) const; uint32_t GetParameterFlags (uint16_t uid, uint32_t i) const; ns3::Attribute GetParameterInitialValue (uint16_t uid, uint32_t i) const; ns3::Ptr GetParameterAccessor (uint16_t uid, uint32_t i) const; ns3::Ptr GetParameterChecker (uint16_t uid, uint32_t i) const; private: struct ConstructorInformation { ns3::CallbackBase cb; uint32_t nArguments; }; struct ParameterInformation { std::string name; std::string help; uint32_t flags; ns3::Attribute initialValue; ns3::Ptr param; ns3::Ptr checker; }; struct IidInformation { std::string name; uint16_t parent; std::string typeName; std::string groupName; std::vector constructors; std::vector parameters; }; typedef std::vector::const_iterator Iterator; struct IidManager::IidInformation *LookupInformation (uint16_t uid) const; std::vector m_information; }; IidManager::IidManager () {} uint16_t IidManager::AllocateUid (std::string name) { uint16_t j = 1; for (Iterator i = m_information.begin (); i != m_information.end (); i++) { if (i->name == name) { NS_FATAL_ERROR ("Trying to allocate twice the same uid: " << name); return 0; } j++; } struct IidInformation information; information.name = name; information.parent = 0; information.typeName = ""; information.groupName = ""; m_information.push_back (information); uint32_t uid = m_information.size (); NS_ASSERT (uid <= 0xffff); return uid; } struct IidManager::IidInformation * IidManager::LookupInformation (uint16_t uid) const { NS_ASSERT (uid <= m_information.size ()); return const_cast (&m_information[uid-1]); } void IidManager::SetParent (uint16_t uid, uint16_t parent) { NS_ASSERT (parent <= m_information.size ()); struct IidInformation *information = LookupInformation (uid); information->parent = parent; } void IidManager::SetTypeName (uint16_t uid, std::string typeName) { struct IidInformation *information = LookupInformation (uid); information->typeName = typeName; } void IidManager::SetGroupName (uint16_t uid, std::string groupName) { struct IidInformation *information = LookupInformation (uid); information->groupName = groupName; } void IidManager::AddConstructor (uint16_t uid, ns3::CallbackBase callback, uint32_t nArguments) { struct IidInformation *information = LookupInformation (uid); struct ConstructorInformation constructor; constructor.cb = callback; constructor.nArguments = nArguments; for (std::vector::const_iterator i = information->constructors.begin (); i != information->constructors.end (); i++) { if (i->nArguments == nArguments) { NS_FATAL_ERROR ("registered two constructors on the same type with the same number of arguments."); break; } } information->constructors.push_back (constructor); } uint16_t IidManager::GetUid (std::string name) const { uint32_t j = 1; for (Iterator i = m_information.begin (); i != m_information.end (); i++) { if (i->name == name) { NS_ASSERT (j <= 0xffff); return j; } j++; } return 0; } std::string IidManager::GetName (uint16_t uid) const { struct IidInformation *information = LookupInformation (uid); return information->name; } uint16_t IidManager::GetParent (uint16_t uid) const { struct IidInformation *information = LookupInformation (uid); return information->parent; } std::string IidManager::GetTypeName (uint16_t uid) const { struct IidInformation *information = LookupInformation (uid); return information->typeName; } std::string IidManager::GetGroupName (uint16_t uid) const { struct IidInformation *information = LookupInformation (uid); return information->groupName; } ns3::CallbackBase IidManager::GetConstructor (uint16_t uid, uint32_t nArguments) { struct IidInformation *information = LookupInformation (uid); for (std::vector::const_iterator i = information->constructors.begin (); i != information->constructors.end (); i++) { if (i->nArguments == nArguments) { return i->cb; } } NS_FATAL_ERROR ("Requested constructor with "<constructors.empty (); } uint32_t IidManager::GetRegisteredN (void) { return m_information.size (); } uint16_t IidManager::GetRegistered (uint32_t i) { return i + 1; } void IidManager::AddParameter (uint16_t uid, std::string name, std::string help, uint32_t flags, ns3::Attribute initialValue, ns3::Ptr spec, ns3::Ptr checker) { struct IidInformation *information = LookupInformation (uid); for (std::vector::const_iterator j = information->parameters.begin (); j != information->parameters.end (); j++) { if (j->name == name) { NS_FATAL_ERROR ("Registered the same parameter twice name=\""<name<<"\""); return; } } struct ParameterInformation param; param.name = name; param.help = help; param.flags = flags; param.initialValue = initialValue; param.param = spec; param.checker = checker; information->parameters.push_back (param); } uint32_t IidManager::GetParametersN (uint16_t uid) const { struct IidInformation *information = LookupInformation (uid); return information->parameters.size (); } std::string IidManager::GetParameterName (uint16_t uid, uint32_t i) const { struct IidInformation *information = LookupInformation (uid); NS_ASSERT (i < information->parameters.size ()); return information->parameters[i].name; } uint32_t IidManager::GetParameterFlags (uint16_t uid, uint32_t i) const { struct IidInformation *information = LookupInformation (uid); NS_ASSERT (i < information->parameters.size ()); return information->parameters[i].flags; } ns3::Attribute IidManager::GetParameterInitialValue (uint16_t uid, uint32_t i) const { struct IidInformation *information = LookupInformation (uid); NS_ASSERT (i < information->parameters.size ()); return information->parameters[i].initialValue; } ns3::Ptr IidManager::GetParameterAccessor (uint16_t uid, uint32_t i) const { struct IidInformation *information = LookupInformation (uid); NS_ASSERT (i < information->parameters.size ()); return information->parameters[i].param; } ns3::Ptr IidManager::GetParameterChecker (uint16_t uid, uint32_t i) const { struct IidInformation *information = LookupInformation (uid); NS_ASSERT (i < information->parameters.size ()); return information->parameters[i].checker; } } // anonymous namespace /********************************************************************* * The TypeId TraceResolver *********************************************************************/ namespace ns3 { class TypeIdTraceResolver : public TraceResolver { public: TypeIdTraceResolver (Ptr aggregate); virtual void Connect (std::string path, CallbackBase const &cb, const TraceContext &context); virtual void Disconnect (std::string path, CallbackBase const &cb); virtual void CollectSources (std::string path, const TraceContext &context, SourceCollection *collection); virtual void TraceAll (std::ostream &os, const TraceContext &context); private: Ptr ParseForInterface (std::string path); Ptr m_aggregate; }; TypeIdTraceResolver::TypeIdTraceResolver (Ptr aggregate) : m_aggregate (aggregate) {} Ptr TypeIdTraceResolver::ParseForInterface (std::string path) { std::string element = GetElement (path); std::string::size_type dollar_pos = element.find ("$"); if (dollar_pos != 0) { return 0; } std::string interfaceName = element.substr (1, std::string::npos); TypeId interfaceId = TypeId::LookupByName (interfaceName); Ptr interface = m_aggregate->GetObject (interfaceId); return interface; } void TypeIdTraceResolver::Connect (std::string path, CallbackBase const &cb, const TraceContext &context) { Ptr interface = ParseForInterface (path); if (interface != 0) { interface->GetTraceResolver ()->Connect (GetSubpath (path), cb, context); } } void TypeIdTraceResolver::Disconnect (std::string path, CallbackBase const &cb) { Ptr interface = ParseForInterface (path); if (interface != 0) { interface->TraceDisconnect (GetSubpath (path), cb); } } void TypeIdTraceResolver::CollectSources (std::string path, const TraceContext &context, SourceCollection *collection) { m_aggregate->DoCollectSources (path, context, collection); } void TypeIdTraceResolver::TraceAll (std::ostream &os, const TraceContext &context) { m_aggregate->DoTraceAll (os, context); } /********************************************************************* * The TypeId class *********************************************************************/ TypeId::TypeId () : m_tid (0) {} TypeId::TypeId (std::string name) { uint16_t uid = Singleton::Get ()->AllocateUid (name); NS_ASSERT (uid != 0); m_tid = uid; } TypeId::TypeId (uint16_t tid) : m_tid (tid) {} TypeId::~TypeId () {} TypeId TypeId::LookupByName (std::string name) { uint16_t uid = Singleton::Get ()->GetUid (name); NS_ASSERT (uid != 0); return TypeId (uid); } bool TypeId::LookupParameterByFullName (std::string fullName, struct TypeId::ParameterInfo *info) { std::string::size_type pos = fullName.find ("::"); if (pos == std::string::npos) { return 0; } std::string tidName = fullName.substr (0, pos); std::string paramName = fullName.substr (pos+2, fullName.size () - (pos+2)); TypeId tid = LookupByName (tidName); return tid.LookupParameterByName (paramName, info); } uint32_t TypeId::GetRegisteredN (void) { return Singleton::Get ()->GetRegisteredN (); } TypeId TypeId::GetRegistered (uint32_t i) { return TypeId (Singleton::Get ()->GetRegistered (i)); } bool TypeId::LookupParameterByName (std::string name, struct TypeId::ParameterInfo *info) const { TypeId tid = TypeId (0); TypeId nextTid = *this; do { tid = nextTid; for (uint32_t i = 0; i < GetParametersN (); i++) { std::string paramName = GetParameterName (i); if (paramName == name) { info->spec = GetParameterAccessor (i); info->flags = GetParameterFlags (i); info->initialValue = tid.GetParameterInitialValue (i); info->checker = tid.GetParameterChecker (i); return true; } } nextTid = tid.GetParent (); } while (nextTid != tid); return false; } bool TypeId::LookupParameterByPosition (uint32_t i, struct TypeId::ParameterInfo *info) const { uint32_t cur = 0; TypeId tid = TypeId (0); TypeId nextTid = *this; do { tid = nextTid; for (uint32_t j = 0; j < tid.GetParametersN (); j++) { if (cur == i) { info->spec = tid.GetParameterAccessor (j); info->flags = tid.GetParameterFlags (j); info->initialValue = tid.GetParameterInitialValue (j); info->checker = tid.GetParameterChecker (j); return true; } cur++; } nextTid = tid.GetParent (); } while (nextTid != tid); return false; } TypeId TypeId::SetParent (TypeId tid) { Singleton::Get ()->SetParent (m_tid, tid.m_tid); return *this; } TypeId TypeId::SetGroupName (std::string groupName) { Singleton::Get ()->SetGroupName (m_tid, groupName); return *this; } TypeId TypeId::SetTypeName (std::string typeName) { Singleton::Get ()->SetTypeName (m_tid, typeName); return *this; } TypeId TypeId::GetParent (void) const { uint16_t parent = Singleton::Get ()->GetParent (m_tid); return TypeId (parent); } std::string TypeId::GetGroupName (void) const { std::string groupName = Singleton::Get ()->GetGroupName (m_tid); return groupName; } std::string TypeId::GetTypeName (void) const { std::string typeName = Singleton::Get ()->GetTypeName (m_tid); return typeName; } std::string TypeId::GetName (void) const { std::string name = Singleton::Get ()->GetName (m_tid); return name; } bool TypeId::HasConstructor (void) const { bool hasConstructor = Singleton::Get ()->HasConstructor (m_tid); return hasConstructor; } void TypeId::DoAddConstructor (CallbackBase cb, uint32_t nArguments) { Singleton::Get ()->AddConstructor (m_tid, cb, nArguments); } TypeId TypeId::AddParameter (std::string name, std::string help, Attribute initialValue, Ptr param, Ptr checker) { Singleton::Get ()->AddParameter (m_tid, name, help, ATTR_SGC, initialValue, param, checker); return *this; } TypeId TypeId::AddParameter (std::string name, std::string help, uint32_t flags, Attribute initialValue, Ptr param, Ptr checker) { Singleton::Get ()->AddParameter (m_tid, name, help, flags, initialValue, param, checker); return *this; } CallbackBase TypeId::LookupConstructor (uint32_t nArguments) const { CallbackBase constructor = Singleton::Get ()->GetConstructor (m_tid, nArguments); return constructor; } Ptr TypeId::CreateObject (void) const { return CreateObject (Parameters ()); } Ptr TypeId::CreateObject (const Parameters ¶meters) const { CallbackBase cb = LookupConstructor (0); Callback,const Parameters &> realCb; realCb.Assign (cb); Ptr object = realCb (parameters); return object; } uint32_t TypeId::GetParametersN (void) const { uint32_t n = Singleton::Get ()->GetParametersN (m_tid); return n; } std::string TypeId::GetParameterName (uint32_t i) const { std::string name = Singleton::Get ()->GetParameterName (m_tid, i); return name; } std::string TypeId::GetParameterFullName (uint32_t i) const { return GetName () + "::" + GetParameterName (i); } Attribute TypeId::GetParameterInitialValue (uint32_t i) const { Attribute value = Singleton::Get ()->GetParameterInitialValue (m_tid, i); return value; } Ptr TypeId::GetParameterAccessor (uint32_t i) const { // Used exclusively by the Object class. Ptr param = Singleton::Get ()->GetParameterAccessor (m_tid, i); return param; } uint32_t TypeId::GetParameterFlags (uint32_t i) const { // Used exclusively by the Object class. uint32_t flags = Singleton::Get ()->GetParameterFlags (m_tid, i); return flags; } Ptr TypeId::GetParameterChecker (uint32_t i) const { // Used exclusively by the Object class. Ptr checker = Singleton::Get ()->GetParameterChecker (m_tid, i); return checker; } bool operator == (TypeId a, TypeId b) { return a.m_tid == b.m_tid; } bool operator != (TypeId a, TypeId b) { return a.m_tid != b.m_tid; } /********************************************************************* * The Parameters container implementation *********************************************************************/ Parameters::Parameters () {} Parameters::Parameters (const Parameters &o) { for (Params::const_iterator i = o.m_parameters.begin (); i != o.m_parameters.end (); i++) { struct Param param; param.checker = i->checker; param.value = i->value.Copy (); m_parameters.push_back (param); } } Parameters & Parameters::operator = (const Parameters &o) { Reset (); for (Params::const_iterator i = o.m_parameters.begin (); i != o.m_parameters.end (); i++) { struct Param param; param.checker = i->checker; param.value = i->value.Copy (); m_parameters.push_back (param); } return *this; } Parameters::~Parameters () { Reset (); } bool Parameters::Set (std::string name, Attribute value) { struct TypeId::ParameterInfo info; TypeId::LookupParameterByFullName (name, &info); bool ok = DoSet (&info, value); return ok; } void Parameters::SetWithTid (TypeId tid, std::string name, Attribute value) { struct TypeId::ParameterInfo info; tid.LookupParameterByName (name, &info); DoSet (&info, value); } void Parameters::SetWithTid (TypeId tid, uint32_t position, Attribute value) { struct TypeId::ParameterInfo info; tid.LookupParameterByPosition (position, &info); DoSet (&info, value); } void Parameters::DoSetOne (Ptr checker, Attribute value) { // get rid of any previous value stored in this // vector of values. for (Params::iterator k = m_parameters.begin (); k != m_parameters.end (); k++) { if (k->checker == checker) { m_parameters.erase (k); break; } } // store the new value. struct Param p; p.checker = checker; p.value = value.Copy (); m_parameters.push_back (p); } bool Parameters::DoSet (struct TypeId::ParameterInfo *info, Attribute value) { if (info->checker == 0) { return false; } bool ok = info->checker->Check (value); if (!ok) { // attempt to convert to string. const StringValue *str = value.DynCast (); if (str == 0) { return false; } // attempt to convert back to value. Attribute v = info->initialValue.Copy (); ok = v.DeserializeFromString (str->Get (), info->checker); if (!ok) { return false; } ok = info->checker->Check (v); if (!ok) { return false; } value = v; } DoSetOne (info->checker, value); return true; } void Parameters::Reset (void) { m_parameters.clear (); } Parameters * Parameters::GetGlobal (void) { return Singleton::Get (); } std::string Parameters::LookupParameterFullNameByChecker (Ptr checker) const { for (uint32_t i = 0; i < TypeId::GetRegisteredN (); i++) { TypeId tid = TypeId::GetRegistered (i); for (uint32_t j = 0; j < tid.GetParametersN (); j++) { if (checker == tid.GetParameterChecker (j)) { return tid.GetParameterFullName (j); } } } NS_FATAL_ERROR ("Could not find requested Accessor."); // quiet compiler. return ""; } std::string Parameters::SerializeToString (void) const { std::ostringstream oss; for (Params::const_iterator i = m_parameters.begin (); i != m_parameters.end (); i++) { std::string name = LookupParameterFullNameByChecker (i->checker); oss << name << "=" << i->value.SerializeToString (i->checker); if (i != m_parameters.end ()) { oss << "|"; } } return oss.str (); } bool Parameters::DeserializeFromString (std::string str) { Reset (); std::string::size_type cur; cur = 0; do { std::string::size_type equal = str.find ("=", cur); if (equal == std::string::npos) { // XXX: invalid parameter. break; } else { std::string name = str.substr (cur, equal-cur); struct TypeId::ParameterInfo info; if (!TypeId::LookupParameterByFullName (name, &info)) { // XXX invalid name. break; } else { std::string::size_type next = str.find ("|", cur); std::string value; if (next == std::string::npos) { value = str.substr (equal+1, str.size () - (equal+1)); cur = str.size (); } else { value = str.substr (equal+1, next - (equal+1)); cur++; } Attribute val = info.initialValue.Copy (); bool ok = val.DeserializeFromString (value, info.checker); if (!ok) { // XXX invalid value break; } else { DoSetOne (info.checker, val); } } } } while (cur != str.size ()); return true; } /********************************************************************* * The Object implementation *********************************************************************/ NS_OBJECT_ENSURE_REGISTERED (Object); static TypeId GetObjectIid (void) { TypeId tid = TypeId ("Object"); tid.SetParent (tid); return tid; } TypeId Object::GetTypeId (void) { static TypeId tid = GetObjectIid (); return tid; } Object::Object () : m_count (1), m_tid (Object::GetTypeId ()), m_disposed (false), m_collecting (false), m_next (this) {} Object::~Object () { m_next = 0; } void Object::Construct (const Parameters ¶meters) { // loop over the inheritance tree back to the Object base class. TypeId tid = m_tid; do { // loop over all parameters in object type NS_LOG_DEBUG ("construct tid="<checker == checker) { // We have a matching parameter value. DoSet (paramSpec, initial, checker, j->value); NS_LOG_DEBUG ("construct \""<< tid.GetName ()<<"::"<< tid.GetParameterName (i)<<"\""); found = true; break; } } if (!found) { // is this parameter stored in the global instance instance ? for (Parameters::Params::const_iterator j = Parameters::GetGlobal ()->m_parameters.begin (); j != Parameters::GetGlobal ()->m_parameters.end (); j++) { if (j->checker == checker) { // We have a matching parameter value. DoSet (paramSpec, initial, checker, j->value); NS_LOG_DEBUG ("construct \""<< tid.GetName ()<<"::"<< tid.GetParameterName (i)<<"\" from global"); found = true; break; } } } if (!found) { // No matching parameter value so we set the default value. paramSpec->Set (this, initial); NS_LOG_DEBUG ("construct \""<< tid.GetName ()<<"::"<< tid.GetParameterName (i)<<"\" from local"); } } tid = tid.GetParent (); } while (tid != Object::GetTypeId ()); NotifyConstructionCompleted (); } bool Object::DoSet (Ptr spec, Attribute initialValue, Ptr checker, Attribute value) { bool ok = checker->Check (value); if (!ok) { // attempt to convert to string const StringValue *str = value.DynCast (); if (str == 0) { return false; } // attempt to convert back from string. Attribute v = initialValue.Copy (); ok = v.DeserializeFromString (str->Get (), checker); if (!ok) { return false; } ok = checker->Check (v); if (!ok) { return false; } value = v; } ok = spec->Set (this, value); return ok; } bool Object::Set (std::string name, Attribute value) { struct TypeId::ParameterInfo info; if (!m_tid.LookupParameterByName (name, &info)) { return false; } if (!(info.flags & TypeId::ATTR_SET)) { return false; } return DoSet (info.spec, info.initialValue, info.checker, value); } bool Object::Get (std::string name, std::string &value) const { struct TypeId::ParameterInfo info; if (!m_tid.LookupParameterByName (name, &info)) { return false; } if (!(info.flags & TypeId::ATTR_GET)) { return false; } Attribute v = info.initialValue.Copy (); bool ok = info.spec->Get (this, v); if (ok) { value = v.SerializeToString (info.checker); } return ok; } Attribute Object::Get (std::string name) const { struct TypeId::ParameterInfo info; if (!m_tid.LookupParameterByName (name, &info)) { return Attribute (); } if (!(info.flags & TypeId::ATTR_GET)) { return Attribute (); } Attribute value = info.initialValue.Copy (); bool ok = info.spec->Get (this, value); if (!ok) { return Attribute (); } return value; } Ptr Object::DoGetObject (TypeId tid) const { NS_ASSERT (CheckLoose ()); const Object *currentObject = this; do { NS_ASSERT (currentObject != 0); TypeId cur = currentObject->m_tid; while (cur != tid && cur != Object::GetTypeId ()) { cur = cur.GetParent (); } if (cur == tid) { return const_cast (currentObject); } currentObject = currentObject->m_next; } while (currentObject != this); return 0; } void Object::Dispose (void) { Object *current = this; do { NS_ASSERT (current != 0); NS_ASSERT (!current->m_disposed); current->DoDispose (); current->m_disposed = true; current = current->m_next; } while (current != this); } void Object::NotifyConstructionCompleted (void) {} void Object::AggregateObject (Ptr o) { NS_ASSERT (!m_disposed); NS_ASSERT (!o->m_disposed); NS_ASSERT (CheckLoose ()); NS_ASSERT (o->CheckLoose ()); Object *other = PeekPointer (o); Object *next = m_next; m_next = other->m_next; other->m_next = next; NS_ASSERT (CheckLoose ()); NS_ASSERT (o->CheckLoose ()); } void Object::TraceConnect (std::string path, const CallbackBase &cb) const { NS_ASSERT (CheckLoose ()); GetTraceResolver ()->Connect (path, cb, TraceContext ()); } void Object::TraceDisconnect (std::string path, const CallbackBase &cb) const { NS_ASSERT (CheckLoose ()); GetTraceResolver ()->Disconnect (path, cb); } void Object::SetTypeId (TypeId tid) { NS_ASSERT (Check ()); m_tid = tid; } void Object::DoDispose (void) { NS_ASSERT (!m_disposed); } Ptr Object::GetTraceResolver (void) const { NS_ASSERT (CheckLoose ()); Ptr resolver = Create (this); return resolver; } bool Object::Check (void) const { return (m_count > 0); } /* In some cases, when an event is scheduled against a subclass of * Object, and if no one owns a reference directly to this object, the * object is alive, has a refcount of zero and the method ran when the * event expires runs against the raw pointer which means that we are * manipulating an object with a refcount of zero. So, instead we * check the aggregate reference count. */ bool Object::CheckLoose (void) const { uint32_t refcount = 0; const Object *current = this; do { refcount += current->m_count; current = current->m_next; } while (current != this); return (refcount > 0); } void Object::MaybeDelete (void) const { // First, check if any of the attached // Object has a non-zero count. const Object *current = this; do { NS_ASSERT (current != 0); if (current->m_count != 0) { return; } current = current->m_next; } while (current != this); // all attached objects have a zero count so, // we can delete all attached objects. current = this; const Object *end = this; do { NS_ASSERT (current != 0); Object *next = current->m_next; delete current; current = next; } while (current != end); } void Object::DoCollectSources (std::string path, const TraceContext &context, TraceResolver::SourceCollection *collection) const { const Object *current; current = this; do { if (current->m_collecting) { return; } current = current->m_next; } while (current != this); m_collecting = true; current = this->m_next; while (current != this) { NS_ASSERT (current != 0); NS_LOG_LOGIC ("collect current=" << current); TypeId cur = current->m_tid; while (cur != Object::GetTypeId ()) { std::string name = cur.GetName (); std::string fullpath = path; fullpath.append ("/$"); fullpath.append (name); NS_LOG_LOGIC("collect: " << fullpath); current->GetTraceResolver ()->CollectSources (fullpath, context, collection); cur = cur.GetParent (); } current = current->m_next; } m_collecting = false; } void Object::DoTraceAll (std::ostream &os, const TraceContext &context) const { const Object *current; current = this; do { if (current->m_collecting) { return; } current = current->m_next; } while (current != this); m_collecting = true; current = this->m_next; while (current != this) { NS_ASSERT (current != 0); current->GetTraceResolver ()->TraceAll (os, context); current = current->m_next; } m_collecting = false; } } // namespace ns3 #ifdef RUN_SELF_TESTS #include "test.h" #include "sv-trace-source.h" #include "composite-trace-resolver.h" namespace { class BaseA : public ns3::Object { public: static ns3::TypeId GetTypeId (void) { static ns3::TypeId tid = ns3::TypeId ("BaseA") .SetParent (Object::GetTypeId ()) .AddConstructor (); return tid; } BaseA () {} void BaseGenerateTrace (int16_t v) { m_source = v; } virtual void Dispose (void) {} virtual ns3::Ptr GetTraceResolver (void) const { ns3::Ptr resolver = ns3::Create (); resolver->AddSource ("basea-x", ns3::TraceDoc ("test source"), m_source); resolver->SetParentResolver (Object::GetTraceResolver ()); return resolver; } ns3::SVTraceSource m_source; }; class DerivedA : public BaseA { public: static ns3::TypeId GetTypeId (void) { static ns3::TypeId tid = ns3::TypeId ("DerivedA") .SetParent (BaseA::GetTypeId ()) .AddConstructor (); return tid; } DerivedA () {} void DerivedGenerateTrace (int16_t v) { m_sourceDerived = v; } virtual void Dispose (void) { BaseA::Dispose (); } virtual ns3::Ptr GetTraceResolver (void) const { ns3::Ptr resolver = ns3::Create (); resolver->AddSource ("deriveda-x", ns3::TraceDoc ("test source"), m_sourceDerived); resolver->SetParentResolver (BaseA::GetTraceResolver ()); return resolver; } ns3::SVTraceSource m_sourceDerived; }; class BaseB : public ns3::Object { public: static ns3::TypeId GetTypeId (void) { static ns3::TypeId tid = ns3::TypeId ("BaseB") .SetParent (Object::GetTypeId ()) .AddConstructor (); return tid; } BaseB () {} void BaseGenerateTrace (int16_t v) { m_source = v; } virtual void Dispose (void) {} virtual ns3::Ptr GetTraceResolver (void) const { ns3::Ptr resolver = ns3::Create (); resolver->AddSource ("baseb-x", ns3::TraceDoc ("test source"), m_source); resolver->SetParentResolver (Object::GetTraceResolver ()); return resolver; } ns3::SVTraceSource m_source; }; class DerivedB : public BaseB { public: static ns3::TypeId GetTypeId (void) { static ns3::TypeId tid = ns3::TypeId ("DerivedB") .SetParent (BaseB::GetTypeId ()) .AddConstructor (); return tid; } DerivedB () {} void DerivedGenerateTrace (int16_t v) { m_sourceDerived = v; } virtual void Dispose (void) { BaseB::Dispose (); } virtual ns3::Ptr GetTraceResolver (void) const { ns3::Ptr resolver = ns3::Create (); resolver->AddSource ("derivedb-x", ns3::TraceDoc ("test source"), m_sourceDerived); resolver->SetParentResolver (BaseB::GetTraceResolver ()); return resolver; } ns3::SVTraceSource m_sourceDerived; }; NS_OBJECT_ENSURE_REGISTERED (BaseA); NS_OBJECT_ENSURE_REGISTERED (DerivedA); NS_OBJECT_ENSURE_REGISTERED (BaseB); NS_OBJECT_ENSURE_REGISTERED (DerivedB); } // namespace anonymous namespace ns3 { class ObjectTest : public Test { public: ObjectTest (); virtual bool RunTests (void); private: void BaseATrace (const TraceContext &context, int64_t oldValue, int64_t newValue); void DerivedATrace (const TraceContext &context, int64_t oldValue, int64_t newValue); void BaseBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue); void DerivedBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue); bool m_baseATrace; bool m_derivedATrace; bool m_baseBTrace; bool m_derivedBTrace; }; ObjectTest::ObjectTest () : Test ("Object") {} void ObjectTest::BaseATrace (const TraceContext &context, int64_t oldValue, int64_t newValue) { m_baseATrace = true; } void ObjectTest::DerivedATrace (const TraceContext &context, int64_t oldValue, int64_t newValue) { m_derivedATrace = true; } void ObjectTest::BaseBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue) { m_baseBTrace = true; } void ObjectTest::DerivedBTrace (const TraceContext &context, int64_t oldValue, int64_t newValue) { m_derivedBTrace = true; } bool ObjectTest::RunTests (void) { bool result = true; Ptr baseA = CreateObject (); NS_TEST_ASSERT_EQUAL (baseA->GetObject (), baseA); NS_TEST_ASSERT_EQUAL (baseA->GetObject (DerivedA::GetTypeId ()), 0); NS_TEST_ASSERT_EQUAL (baseA->GetObject (), 0); baseA = CreateObject (); NS_TEST_ASSERT_EQUAL (baseA->GetObject (), baseA); NS_TEST_ASSERT_EQUAL (baseA->GetObject (DerivedA::GetTypeId ()), baseA); NS_TEST_ASSERT_UNEQUAL (baseA->GetObject (), 0); baseA = CreateObject (); Ptr baseB = CreateObject (); Ptr baseBCopy = baseB; baseA->AggregateObject (baseB); NS_TEST_ASSERT_UNEQUAL (baseA->GetObject (), 0); NS_TEST_ASSERT_EQUAL (baseA->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseA->GetObject (), 0); NS_TEST_ASSERT_EQUAL (baseA->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); NS_TEST_ASSERT_EQUAL (baseB->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); NS_TEST_ASSERT_EQUAL (baseB->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject (), 0); baseA = CreateObject (); baseB = CreateObject (); baseBCopy = baseB; baseA->AggregateObject (baseB); NS_TEST_ASSERT_UNEQUAL (baseA->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseA->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0); NS_TEST_ASSERT_UNEQUAL (baseB->GetObject (), 0) baseA = CreateObject (); baseB = CreateObject (); baseA->AggregateObject (baseB); baseA = 0; baseA = baseB->GetObject (); baseA = CreateObject (); baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); m_baseATrace = false; baseA->BaseGenerateTrace (1); NS_TEST_ASSERT (m_baseATrace); baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); baseB = CreateObject (); baseB->TraceConnect ("/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this)); m_baseBTrace = false; baseB->BaseGenerateTrace (2); NS_TEST_ASSERT (m_baseBTrace); baseB->TraceDisconnect ("/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this)); baseA->AggregateObject (baseB); baseA->TraceConnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); m_baseATrace = false; baseA->BaseGenerateTrace (3); NS_TEST_ASSERT (m_baseATrace); baseA->TraceDisconnect ("/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); baseA->TraceConnect ("/$BaseB/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this)); m_baseBTrace = false; baseB->BaseGenerateTrace (4); NS_TEST_ASSERT (m_baseBTrace); baseA->TraceDisconnect ("/$BaseB/baseb-x", MakeCallback (&ObjectTest::BaseBTrace, this)); m_baseBTrace = false; baseB->BaseGenerateTrace (5); NS_TEST_ASSERT (!m_baseBTrace); baseB->TraceConnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); m_baseATrace = false; baseA->BaseGenerateTrace (6); NS_TEST_ASSERT (m_baseATrace); baseB->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); baseA->TraceConnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); m_baseATrace = false; baseA->BaseGenerateTrace (7); NS_TEST_ASSERT (m_baseATrace); baseA->TraceDisconnect ("/$BaseA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); Ptr derivedA; derivedA = CreateObject (); baseB = CreateObject (); derivedA->AggregateObject (baseB); baseB->TraceConnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::DerivedATrace, this)); baseB->TraceConnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); m_derivedATrace = false; m_baseATrace = false; derivedA->DerivedGenerateTrace (8); derivedA->BaseGenerateTrace (9); NS_TEST_ASSERT (m_derivedATrace); NS_TEST_ASSERT (m_baseATrace); baseB->TraceDisconnect ("/$DerivedA/deriveda-x", MakeCallback (&ObjectTest::BaseATrace, this)); baseB->TraceDisconnect ("/$DerivedA/basea-x", MakeCallback (&ObjectTest::BaseATrace, this)); baseB->TraceConnect ("/$DerivedA/*", MakeCallback (&ObjectTest::DerivedATrace, this)); m_derivedATrace = false; derivedA->DerivedGenerateTrace (10); NS_TEST_ASSERT (m_derivedATrace); // here, we have connected the derived trace sink to all // trace sources, including the base trace source. m_derivedATrace = false; derivedA->BaseGenerateTrace (11); NS_TEST_ASSERT (m_derivedATrace); baseB->TraceDisconnect ("/$DerivedA/*", MakeCallback (&ObjectTest::BaseATrace, this)); // Test the object creation code of TypeId Ptr a = BaseA::GetTypeId ().CreateObject (); NS_TEST_ASSERT_EQUAL (a->GetObject (), a); NS_TEST_ASSERT_EQUAL (a->GetObject (DerivedA::GetTypeId ()), 0); NS_TEST_ASSERT_EQUAL (a->GetObject (), 0); a = DerivedA::GetTypeId ().CreateObject (); NS_TEST_ASSERT_EQUAL (a->GetObject (), a); NS_TEST_ASSERT_EQUAL (a->GetObject (DerivedA::GetTypeId ()), a); NS_TEST_ASSERT_UNEQUAL (a->GetObject (), 0); return result; } static ObjectTest g_interfaceObjectTests; } // namespace ns3 #endif /* RUN_SELF_TESTS */