From f2c02fe3bb385a33a65b44c858c91a59bad429be Mon Sep 17 00:00:00 2001 From: Mathieu Lacage Date: Thu, 17 May 2007 14:39:54 +0200 Subject: [PATCH] a replacement for the Interface base class --- SConstruct | 2 + src/core/interface-object.cc | 552 +++++++++++++++++++++++++++++++++++ src/core/interface-object.h | 94 ++++++ 3 files changed, 648 insertions(+) create mode 100644 src/core/interface-object.cc create mode 100644 src/core/interface-object.h diff --git a/SConstruct b/SConstruct index 6a187c7af..3cb51eb7a 100644 --- a/SConstruct +++ b/SConstruct @@ -38,6 +38,7 @@ core.add_sources([ 'command-line.cc', 'type-name.cc', 'component-manager.cc', + 'interface-object.cc', ]) env = Environment() if env['PLATFORM'] == 'posix' or env['PLATFORM'] == 'darwin' or env['PLATFORM'] == 'cygwin': @@ -70,6 +71,7 @@ core.add_inst_headers([ 'command-line.h', 'type-name.h', 'component-manager.h', + 'interface-object.h', ]) def config_core (env, config): diff --git a/src/core/interface-object.cc b/src/core/interface-object.cc new file mode 100644 index 000000000..942b3e9f3 --- /dev/null +++ b/src/core/interface-object.cc @@ -0,0 +1,552 @@ +/* -*- 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 "interface-object.h" +#include "assert.h" +#include "singleton.h" +#include "uid-manager.h" +#include + +namespace { + +class IidManager : public ns3::UidManager +{}; + +class IidTree +{ +public: + void SetParent (uint32_t child, const uint32_t *parent); + uint32_t LookupParent (uint32_t child); +private: + std::vector m_parents; +}; + +void +IidTree::SetParent (uint32_t child, const uint32_t *parent) +{ + m_parents.resize (child+1); + m_parents[child] = parent; +} +uint32_t +IidTree::LookupParent (uint32_t child) +{ + return *(m_parents[child]); +} + +} // anonymous namespace + +namespace ns3 { + +MyInterfaceId::MyInterfaceId (uint32_t iid) + : m_iid (iid) +{} +MyInterfaceId +MyInterfaceId::LookupByName (std::string name) +{ + return MyInterfaceId (Singleton::Get ()->LookupByName (name)); +} +MyInterfaceId +MyInterfaceId::LookupParent (MyInterfaceId iid) +{ + return Singleton::Get ()->LookupParent (iid.m_iid); +} + +bool operator == (const MyInterfaceId &a, const MyInterfaceId &b) +{ + return a.m_iid == b.m_iid; +} + +bool operator != (const MyInterfaceId &a, const MyInterfaceId &b) +{ + return a.m_iid != b.m_iid; +} + +MyInterfaceId +MakeInterfaceId (std::string name, const MyInterfaceId &parent) +{ + MyInterfaceId iid = Singleton::Get ()->Allocate (name); + Singleton::Get ()->SetParent (iid.m_iid, &parent.m_iid); + return iid; +} + +MyInterfaceId +MakeObjectInterfaceId (void) +{ + MyInterfaceId iid = Singleton::Get ()->Allocate ("Object"); + Singleton::Get ()->SetParent (iid.m_iid, &iid.m_iid); + return iid; +} + + +class AggregateObject +{ +public: + AggregateObject (); + ~AggregateObject (); + void Ref (void); + void Ref (AggregateObject *other); + void RefAll (uint32_t count); + void Unref (void); + void UnrefAll (void); + InterfaceObject *PeekQueryInterface (MyInterfaceId iid, InterfaceObject *caller); + void Dispose (void); + void AddObject (InterfaceObject *object); + void Swallow (AggregateObject *object); +private: + typedef std::vector ObjectList; + uint32_t m_count; + ObjectList m_objectList; +}; + +AggregateObject::AggregateObject () + : m_count (1) +{} +AggregateObject::~AggregateObject () +{ + NS_ASSERT (m_count == 0); +} +void +AggregateObject::Ref (void) +{ + m_count++; +} +void +AggregateObject::Ref (AggregateObject *other) +{ + m_count+= other->m_count; +} +void +AggregateObject::RefAll (uint32_t count) +{ + m_count += count; +} +void +AggregateObject::UnrefAll (void) +{ + m_count = 0; + delete this; +} +void +AggregateObject::Unref (void) +{ + m_count--; + if (m_count == 0) + { + for (ObjectList::iterator i = m_objectList.begin (); i != m_objectList.end (); i++) + { + delete *i; + } + delete this; + } +} +InterfaceObject * +AggregateObject::PeekQueryInterface (MyInterfaceId iid, InterfaceObject *caller) +{ + for (ObjectList::iterator i = m_objectList.begin (); i != m_objectList.end (); i++) + { + if (*i != caller) + { + MyInterfaceId cur = (*i)->m_iid; + while (cur != iid && cur != InterfaceObject::iid) + { + cur = MyInterfaceId::LookupParent (cur); + } + if (cur == iid) + { + return *i; + } + } + } + return 0; +} +void +AggregateObject::Dispose (void) +{ + for (ObjectList::iterator i = m_objectList.begin (); i != m_objectList.end (); i++) + { + (*i)->DoDispose (); + } +} +void +AggregateObject::AddObject (InterfaceObject *object) +{ + // XXX should check for interface uniqueness. + m_objectList.push_back (object); +} + +void +AggregateObject::Swallow (AggregateObject *other) +{ + for (ObjectList::iterator i = other->m_objectList.begin (); i != other->m_objectList.end (); i++) + { + m_objectList.push_back (*i); + } + other->m_objectList.clear (); +} + +const MyInterfaceId InterfaceObject::iid = MakeObjectInterfaceId (); + + +InterfaceObject::InterfaceObject () + : m_count (1), + m_iid (InterfaceObject::iid), + m_aggregate (0) +{} +InterfaceObject::~InterfaceObject () +{} +void +InterfaceObject::Ref (void) +{ + NS_ASSERT (Check ()); + if (m_aggregate != 0) + { + NS_ASSERT (m_count == 0); + m_aggregate->Ref (); + } + else + { + m_count++; + } +} +void +InterfaceObject::Unref (void) +{ + NS_ASSERT (Check ()); + if (m_aggregate != 0) + { + NS_ASSERT (m_count == 0); + m_aggregate->Unref (); + } + else + { + m_count--; + if (m_count == 0) + { + delete this; + } + } +} +Ptr +InterfaceObject::DoQueryInterface (MyInterfaceId iid) +{ + NS_ASSERT (Check ()); + MyInterfaceId cur = m_iid; + while (cur != iid && cur != InterfaceObject::iid) + { + cur = MyInterfaceId::LookupParent (cur); + } + if (cur == iid) + { + return this; + } + if (m_aggregate != 0) + { + NS_ASSERT (m_count == 0); + return m_aggregate->PeekQueryInterface (iid, this); + } + return 0; +} +void +InterfaceObject::Dispose (void) +{ + NS_ASSERT (Check ()); + if (m_aggregate != 0) + { + NS_ASSERT (m_count == 0); + m_aggregate->Dispose (); + } + else + { + DoDispose (); + } +} + +void +InterfaceObject::Add (Ptr o) +{ + NS_ASSERT (Check ()); + NS_ASSERT (o->Check ()); + InterfaceObject *other = PeekPointer (o); + if (m_aggregate != 0 && other->m_aggregate != 0) + { + NS_ASSERT (m_count == 0); + NS_ASSERT (other->m_count == 0); + m_aggregate->Swallow (other->m_aggregate); + m_aggregate->Ref (other->m_aggregate); + other->m_aggregate->UnrefAll (); + other->m_aggregate = m_aggregate; + } + else if (m_aggregate != 0) + { + NS_ASSERT (other->m_aggregate == 0); + NS_ASSERT (m_count == 0); + m_aggregate->AddObject (other); + other->m_aggregate = m_aggregate; + other->m_aggregate->RefAll (other->m_count); + other->m_count = 0; + } + else if (other->m_aggregate != 0) + { + NS_ASSERT (m_aggregate == 0); + other->m_aggregate->AddObject (this); + m_aggregate = other->m_aggregate; + m_aggregate->RefAll (m_count); + m_count = 0; + } + else + { + NS_ASSERT (m_aggregate == 0); + NS_ASSERT (other->m_aggregate == 0); + m_aggregate = new AggregateObject (); + other->m_aggregate = m_aggregate; + m_aggregate->AddObject (this); + m_aggregate->AddObject (other); + m_aggregate->RefAll (m_count); + m_aggregate->RefAll (other->m_count); + m_aggregate->Unref (); + other->m_count = 0; + m_count = 0; + } + NS_ASSERT (Check ()); + NS_ASSERT (o->Check ()); +} + +void +InterfaceObject::SetInterfaceId (MyInterfaceId iid) +{ + NS_ASSERT (Check ()); + m_iid = iid; +} + +void +InterfaceObject::DoDispose (void) +{ + NS_ASSERT (Check ()); +} + +bool +InterfaceObject::Check (void) +{ + return (m_count == 0 && m_aggregate != 0) || (m_count != 0 && m_aggregate == 0); +} + +} // namespace ns3 + + +#ifdef RUN_SELF_TESTS + +#include "test.h" + +namespace { + +class BaseA : public ns3::InterfaceObject +{ +public: + static const ns3::MyInterfaceId iid; + BaseA () + { + SetInterfaceId (BaseA::iid); + } + virtual void Dispose (void) {} +}; + +class DerivedA : public BaseA +{ +public: + static const ns3::MyInterfaceId iid; + DerivedA (int v) + { + SetInterfaceId (DerivedA::iid); + } + virtual void Dispose (void) { + BaseA::Dispose (); + } +}; + +const ns3::MyInterfaceId BaseA::iid = + ns3::MakeInterfaceId ("BaseA", InterfaceObject::iid); +const ns3::MyInterfaceId DerivedA::iid = + ns3::MakeInterfaceId ("DerivedA", BaseA::iid);; + +class BaseB : public ns3::InterfaceObject +{ +public: + static const ns3::MyInterfaceId iid; + BaseB () + { + SetInterfaceId (BaseB::iid); + } + virtual void Dispose (void) {} +}; + +class DerivedB : public BaseB +{ +public: + static const ns3::MyInterfaceId iid; + DerivedB (int v) + { + SetInterfaceId (DerivedB::iid); + } + virtual void Dispose (void) { + BaseB::Dispose (); + } +}; + +const ns3::MyInterfaceId BaseB::iid = + ns3::MakeInterfaceId ("BaseB", InterfaceObject::iid); +const ns3::MyInterfaceId DerivedB::iid = + ns3::MakeInterfaceId ("DerivedB", BaseB::iid);; + +} // namespace anonymous + +namespace ns3 { + +class InterfaceObjectTest : public Test +{ +public: + InterfaceObjectTest (); + virtual bool RunTests (void); +}; + +InterfaceObjectTest::InterfaceObjectTest () + : Test ("InterfaceObject") +{} +bool +InterfaceObjectTest::RunTests (void) +{ + bool ok = true; + + Ptr baseA = MakeNewObject (); + if (baseA->QueryInterface (BaseA::iid) != baseA) + { + ok = false; + } + if (baseA->QueryInterface (DerivedA::iid) != 0) + { + ok = false; + } + if (baseA->QueryInterface (DerivedA::iid) != 0) + { + ok = false; + } + baseA = MakeNewObject (10); + if (baseA->QueryInterface (BaseA::iid) != baseA) + { + ok = false; + } + if (baseA->QueryInterface (DerivedA::iid) != baseA) + { + ok = false; + } + if (baseA->QueryInterface (DerivedA::iid) == 0) + { + ok = false; + } + + baseA = MakeNewObject (); + Ptr baseB = MakeNewObject (); + Ptr baseBCopy = baseB; + baseA->Add (baseB); + if (baseA->QueryInterface (BaseA::iid) == 0) + { + ok = false; + } + if (baseA->QueryInterface (DerivedA::iid) != 0) + { + ok = false; + } + if (baseA->QueryInterface (BaseB::iid) == 0) + { + ok = false; + } + if (baseA->QueryInterface (DerivedB::iid) != 0) + { + ok = false; + } + if (baseB->QueryInterface (BaseB::iid) == 0) + { + ok = false; + } + if (baseB->QueryInterface (DerivedB::iid) != 0) + { + ok = false; + } + if (baseB->QueryInterface (BaseA::iid) == 0) + { + ok = false; + } + if (baseB->QueryInterface (DerivedA::iid) != 0) + { + ok = false; + } + if (baseBCopy->QueryInterface (BaseA::iid) == 0) + { + ok = false; + } + + baseA = MakeNewObject (1); + baseB = MakeNewObject (1); + baseBCopy = baseB; + baseA->Add (baseB); + if (baseA->QueryInterface (DerivedB::iid) == 0) + { + ok = false; + } + if (baseA->QueryInterface (BaseB::iid) == 0) + { + ok = false; + } + if (baseB->QueryInterface (DerivedA::iid) == 0) + { + ok = false; + } + if (baseB->QueryInterface (BaseA::iid) == 0) + { + ok = false; + } + if (baseBCopy->QueryInterface (DerivedA::iid) == 0) + { + ok = false; + } + if (baseBCopy->QueryInterface (BaseA::iid) == 0) + { + ok = false; + } + if (baseB->QueryInterface (DerivedB::iid) == 0) + { + ok = false; + } + if (baseB->QueryInterface (BaseB::iid) == 0) + { + ok = false; + } + + + return ok; +} + +static InterfaceObjectTest g_interfaceObjectTests; + + +} // namespace ns3 + +#endif /* RUN_SELF_TESTS */ + + diff --git a/src/core/interface-object.h b/src/core/interface-object.h new file mode 100644 index 000000000..9d349301b --- /dev/null +++ b/src/core/interface-object.h @@ -0,0 +1,94 @@ +/* -*- 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 + */ +#ifndef INTERFACE_OBJECT_H +#define INTERFACE_OBJECT_H + +#include +#include +#include "ptr.h" + +namespace ns3 { + +class MyInterfaceId +{ +public: + static MyInterfaceId LookupByName (std::string name); + static MyInterfaceId LookupParent (MyInterfaceId iid); +private: + MyInterfaceId (uint32_t iid); + friend MyInterfaceId MakeInterfaceId (std::string name, const MyInterfaceId &parent); + friend MyInterfaceId MakeObjectInterfaceId (void); + friend class AggregateObject; + friend bool operator == (const MyInterfaceId &a, const MyInterfaceId &b); + friend bool operator != (const MyInterfaceId &a, const MyInterfaceId &b); + uint32_t m_iid; +}; + +MyInterfaceId +MakeInterfaceId (std::string name, const MyInterfaceId &parent); + +class AggregateObject; + +class InterfaceObject +{ +public: + static const MyInterfaceId iid; + + InterfaceObject (); + virtual ~InterfaceObject (); + void Ref (void); + void Unref (void); + template + Ptr QueryInterface (MyInterfaceId iid); + void Dispose (void); + void Add (Ptr other); +protected: + void SetInterfaceId (MyInterfaceId iid); +private: + friend class AggregateObject; + virtual void DoDispose (void); + Ptr DoQueryInterface (MyInterfaceId iid); + bool Check (void); + uint32_t m_count; + MyInterfaceId m_iid; + AggregateObject *m_aggregate; +}; + +} // namespace ns3 + +namespace ns3 { + +template +Ptr +InterfaceObject::QueryInterface (MyInterfaceId iid) +{ + Ptr found = DoQueryInterface (iid); + if (found != 0) + { + return Ptr (dynamic_cast (PeekPointer (found))); + } + return 0; +} + +} // namespace ns3 + +#endif /* INTERFACE_OBJECT_H */ +