--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/examples/names.cc Tue Jan 20 15:47:14 2009 -0800
@@ -0,0 +1,142 @@
+/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * 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
+ */
+
+// Network topology
+//
+// n0 n1 n2 n3
+// | | | |
+// =================
+// LAN
+//
+
+#include <fstream>
+#include "ns3/core-module.h"
+#include "ns3/simulator-module.h"
+#include "ns3/helper-module.h"
+
+using namespace ns3;
+
+NS_LOG_COMPONENT_DEFINE ("NamesExample");
+
+void
+RxEvent (std::string context, Ptr<const Packet> packet)
+{
+ NS_LOG_INFO (context << " packet " << packet);
+}
+
+int
+main (int argc, char *argv[])
+{
+ //
+ // Users may find it convenient to turn on explicit debugging
+ // for selected modules; the below lines suggest how to do this
+ //
+#if 1
+ LogComponentEnable ("NamesExample", LOG_LEVEL_INFO);
+#endif
+
+ //
+ // Allow the user to override any of the defaults and the above Bind() at
+ // run-time, via command-line arguments
+ //
+ CommandLine cmd;
+ cmd.Parse (argc, argv);
+
+ //
+ // Explicitly create the nodes required by the topology (shown above).
+ //
+ NS_LOG_INFO ("Create nodes.");
+ NodeContainer n;
+ n.Create (4);
+
+ //
+ // We're going to use the zeroth node in the container as the client, and
+ // the first node as the server. Add some "human readable" names for these
+ // nodes. The first parameter specifies the root of the "/Names" name space
+ // as the destination, so these will go into the name system as "/Names/client"
+ // and "/Names/server".
+ //
+ Names::Add ("/Names", "client", n.Get (0));
+ Names::Add ("/Names", "server", n.Get (1));
+
+ InternetStackHelper internet;
+ internet.Install (n);
+
+ NS_LOG_INFO ("Create devices.");
+ CsmaHelper csma;
+ csma.SetChannelAttribute ("DataRate", DataRateValue (DataRate(5000000)));
+ csma.SetChannelAttribute ("Delay", TimeValue (MilliSeconds (2)));
+ csma.SetDeviceAttribute ("Mtu", UintegerValue (1400));
+ NetDeviceContainer d = csma.Install (n);
+
+ //
+ // Add some human readable names for the devices we'll be interested in.
+ // We add the names to the name space "under" the nodes we created above.
+ // This has the effect of making "/Names/client/eth0" and "/Names/server/eth0"
+ // Note that the first parameter must reference a previously named object,
+ // and we have, in fact, already named objects "/Names/client" and
+ // "/Names/server"
+ //
+ Names::Add ("/Names/client", "eth0", d.Get (0));
+ Names::Add ("/Names/server", "eth0", d.Get (1));
+
+ Ipv4AddressHelper ipv4;
+
+ //
+ // We've got the "hardware" in place. Now we need to add IP addresses.
+ //
+ NS_LOG_INFO ("Assign IP Addresses.");
+ ipv4.SetBase ("10.1.1.0", "255.255.255.0");
+ Ipv4InterfaceContainer i = ipv4.Assign (d);
+
+ NS_LOG_INFO ("Create Applications.");
+
+ //
+ // Create a UdpEchoServer application on the server node. Note that we
+ // reference the server node by name in the Install method below.
+ //
+ uint16_t port = 9; // well-known echo port number
+ UdpEchoServerHelper server (port);
+ ApplicationContainer apps = server.Install (Names::Find<Node> ("/Names/server"));
+ apps.Start (Seconds (1.0));
+ apps.Stop (Seconds (10.0));
+
+ //
+ // Create a UdpEchoClient application to send UDP datagrams from node zero to
+ // node one. Notice that we reference the client node by name in the Install
+ // method below.
+ //
+ uint32_t packetSize = 1024;
+ uint32_t maxPacketCount = 1;
+ Time interPacketInterval = Seconds (1.);
+ UdpEchoClientHelper client (i.GetAddress (1), port);
+ client.SetAttribute ("MaxPackets", UintegerValue (maxPacketCount));
+ client.SetAttribute ("Interval", TimeValue (interPacketInterval));
+ client.SetAttribute ("PacketSize", UintegerValue (packetSize));
+ apps = client.Install (Names::Find<Node> ("/Names/client"));
+ apps.Start (Seconds (2.0));
+ apps.Stop (Seconds (10.0));
+
+ Config::Connect ("/Names/client/eth0/Rx", MakeCallback (&RxEvent));
+
+ //
+ // Now, do the actual simulation.
+ //
+ NS_LOG_INFO ("Run Simulation.");
+ Simulator::Run ();
+ Simulator::Destroy ();
+ NS_LOG_INFO ("Done.");
+}
--- a/examples/wscript Sun Jan 18 22:47:25 2009 +0000
+++ b/examples/wscript Tue Jan 20 15:47:14 2009 -0800
@@ -16,6 +16,10 @@
['core', 'simulator', 'point-to-point', 'csma', 'wifi', 'internet-stack'])
obj.source = 'third.cc'
+ obj = bld.create_ns3_program('names',
+ ['core', 'simulator', 'csma', 'internet-stack'])
+ obj.source = 'names.cc'
+
obj = bld.create_ns3_program('mixed-wireless',
['core', 'simulator', 'mobility', 'wifi', 'point-to-point', 'internet-stack'])
obj.source = 'mixed-wireless.cc'
--- a/src/core/config.cc Sun Jan 18 22:47:25 2009 +0000
+++ b/src/core/config.cc Tue Jan 20 15:47:14 2009 -0800
@@ -22,6 +22,7 @@
#include "object.h"
#include "global-value.h"
#include "object-vector.h"
+#include "object-names.h"
#include "pointer.h"
#include "log.h"
#include <sstream>
@@ -294,6 +295,45 @@
std::string item = path.substr (1, next-1);
std::string pathLeft = path.substr (next, path.size ()-next);
+ //
+ // If root is zero, we're beginning to see if we can use the object name
+ // service to resolve this path. In this case, we must see the name space
+ // "/Names" on the front of this path. There is no object associated with
+ // the root of the "/Names" namespace, so we just ignore it and move on to
+ // the next segment.
+ //
+ if (root == 0)
+ {
+ std::string::size_type offset = path.find ("/Names");
+ if (offset == 0)
+ {
+ m_workStack.push_back (item);
+ DoResolve (pathLeft, root);
+ m_workStack.pop_back ();
+ return;
+ }
+ }
+
+ //
+ // We have an item (possibly a segment of a namespace path. Check to see if
+ // we can determine that this segment refers to a named object. If root is
+ // zero, this means to look in the root of the "/Names" name space, otherwise
+ // it refers to a name space context (level).
+ //
+ Ptr<Object> namedObject = Names::FindObjectFromShortName<Object> (root, item);
+ if (namedObject)
+ {
+ NS_LOG_DEBUG ("Name system resolved item = " << item << " to " << namedObject);
+ m_workStack.push_back (item);
+ DoResolve (pathLeft, namedObject);
+ m_workStack.pop_back ();
+ return;
+ }
+
+ //
+ // We're done with the object name service hooks, so proceed down the path
+ // of types and attributes.
+ //
std::string::size_type dollarPos = item.find ("$");
if (dollarPos == 0)
{
@@ -480,6 +520,14 @@
{
resolver.Resolve (*i);
}
+
+ //
+ // See if we can do something with the object name service. Starting with
+ // the root pointer zeroed indicates to the resolver that it should start
+ // looking at the root of the "/Names" namespace during this go.
+ //
+ resolver.Resolve (0);
+
return Config::MatchContainer (resolver.m_objects, resolver.m_contexts, path);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/object-names.cc Tue Jan 20 15:47:14 2009 -0800
@@ -0,0 +1,624 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 University of Washington
+ *
+ * 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
+ */
+
+#include <map>
+#include "ns3/object.h"
+#include "ns3/log.h"
+#include "ns3/assert.h"
+#include "ns3/abort.h"
+#include "ns3/simulator.h"
+#include "object-names.h"
+
+namespace ns3 {
+
+NS_LOG_COMPONENT_DEFINE ("Names");
+
+class NameNode
+{
+public:
+ NameNode ();
+ NameNode (const NameNode &nameNode);
+ NameNode (NameNode *parent, std::string name, Ptr<Object> object);
+ NameNode &operator = (const NameNode &rhs);
+
+ ~NameNode ();
+
+ NameNode *m_parent;
+ std::string m_name;
+ Ptr<Object> m_object;
+
+ std::map<std::string, NameNode *> m_nameMap;
+};
+
+NameNode::NameNode ()
+ : m_parent (0), m_name (""), m_object (0)
+{
+}
+
+NameNode::NameNode (const NameNode &nameNode)
+{
+ m_parent = nameNode.m_parent;
+ m_name = nameNode.m_name;
+ m_object = nameNode.m_object;
+ m_nameMap = nameNode.m_nameMap;
+}
+
+NameNode &
+NameNode::operator = (const NameNode &rhs)
+{
+ m_parent = rhs.m_parent;
+ m_name = rhs.m_name;
+ m_object = rhs.m_object;
+ m_nameMap = rhs.m_nameMap;
+ return *this;
+}
+
+NameNode::NameNode (NameNode *parent, std::string name, Ptr<Object> object)
+ : m_parent (parent), m_name (name), m_object (object)
+{
+}
+
+NameNode::~NameNode ()
+{
+}
+
+class NamesPriv
+{
+public:
+ NamesPriv ();
+ ~NamesPriv ();
+
+ bool Add (std::string name, Ptr<Object> obj);
+ bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
+ bool Add (std::string context, std::string name, Ptr<Object> object);
+ std::string FindShortName (Ptr<Object> object);
+ std::string FindFullName (Ptr<Object> object);
+ Ptr<Object> FindObjectFromFullName (std::string name);
+ Ptr<Object> FindObjectFromShortName (Ptr<Object> context, std::string name);
+
+ static NamesPriv *Get (void);
+
+private:
+ static NamesPriv **DoGet (void);
+ static void Delete (void);
+
+ NameNode *IsNamed (Ptr<Object>);
+ bool IsDuplicateName (NameNode *node, std::string name);
+
+ NameNode m_root;
+ std::map<Ptr<Object>, NameNode *> m_objectMap;
+};
+
+NamesPriv *
+NamesPriv::Get (void)
+{
+ return *(DoGet ());
+}
+
+NamesPriv **
+NamesPriv::DoGet (void)
+{
+ static NamesPriv *ptr = 0;
+
+ if (ptr == 0)
+ {
+ ptr = new NamesPriv;
+ Simulator::ScheduleDestroy (&NamesPriv::Delete);
+ }
+
+ return &ptr;
+}
+
+void
+NamesPriv::Delete (void)
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ NamesPriv **ptr = DoGet ();
+ delete *ptr;
+ *ptr = 0;
+}
+
+NamesPriv::NamesPriv ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ m_root.m_parent = 0;
+ m_root.m_name = "Names";
+ m_root.m_object = 0;
+}
+
+NamesPriv::~NamesPriv ()
+{
+ NS_LOG_FUNCTION_NOARGS ();
+
+ //
+ // Every name is associated with an object in the object map, so freeing the
+ // NameNodes in this map will free all of the memory allocated for the NameNodes
+ //
+ for (std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.begin (); i != m_objectMap.end (); ++i)
+ {
+ delete i->second;
+ i->second = 0;
+ }
+}
+
+bool
+NamesPriv::Add (std::string name, Ptr<Object> object)
+{
+ return Add (Ptr<Object> (0, false), name, object);
+}
+
+bool
+NamesPriv::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
+{
+ NS_LOG_FUNCTION (context << name << object);
+
+ if (IsNamed (object))
+ {
+ NS_LOG_LOGIC ("Object is already named");
+ return false;
+ }
+
+ NameNode *node = 0;
+ if (context)
+ {
+ node = IsNamed (context);
+ NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
+ }
+ else
+ {
+ node = &m_root;
+ }
+
+ if (IsDuplicateName (node, name))
+ {
+ NS_LOG_LOGIC ("Name is already taken");
+ return false;
+ }
+
+ NameNode *newNode = new NameNode(node, name, object);
+ node->m_nameMap[name] = newNode;
+ m_objectMap[object] = newNode;
+
+ return true;
+}
+
+bool
+NamesPriv::Add (std::string context, std::string name, Ptr<Object> object)
+{
+ if (context == "/Names")
+ {
+ return Add (name, object);
+ }
+ return Add (FindObjectFromFullName (context), name, object);
+}
+
+std::string
+NamesPriv::FindShortName (Ptr<Object> object)
+{
+ NS_LOG_FUNCTION (object);
+
+ std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
+ if (i == m_objectMap.end ())
+ {
+ NS_LOG_LOGIC ("Object does not exist in object map");
+ return "";
+ }
+ else
+ {
+ NS_LOG_LOGIC ("Object exists in object map");
+ return i->second->m_name;
+ }
+}
+
+std::string
+NamesPriv::FindFullName (Ptr<Object> object)
+{
+ NS_LOG_FUNCTION (object);
+
+ std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
+ if (i == m_objectMap.end ())
+ {
+ NS_LOG_LOGIC ("Object does not exist in object map");
+ return "";
+ }
+
+ NameNode *p = i->second;
+ NS_ASSERT_MSG (p, "NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map");
+
+ std::string fullname;
+
+ do
+ {
+ fullname = "/" + p->m_name + fullname;
+ NS_LOG_LOGIC ("fullname is " << fullname);
+ }
+ while ((p = p->m_parent) != 0);
+
+ return fullname;
+}
+
+
+Ptr<Object>
+NamesPriv::FindObjectFromFullName (std::string name)
+{
+ std::string namespaceName = "/Names/";
+ std::string::size_type offset = name.find (namespaceName);
+ if (offset == std::string::npos)
+ {
+ NS_LOG_LOGIC (name << " is not in the " << namespaceName << " name space");
+ return 0;
+ }
+
+ std::string remaining = name.substr (namespaceName.size ());
+ NameNode *node = &m_root;
+
+ //
+ // remaining is now composed entirely of path segments in the /Names name space.
+ // and we have eaten the leading slash. e.g., remaining = "ClientNode/eth0"
+ // The start of the search is at the root of the name space.
+ //
+ for (;;)
+ {
+ NS_LOG_LOGIC ("Looking for the object of name " << remaining);
+ offset = remaining.find ("/");
+ if (offset == std::string::npos)
+ {
+ //
+ // There are no remaining slashes so this is the last segment of the
+ // specified name. We're done when we find it
+ //
+ std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (remaining);
+ if (i == node->m_nameMap.end ())
+ {
+ NS_LOG_LOGIC ("Name does not exist in name map");
+ return 0;
+ }
+ else
+ {
+ NS_LOG_LOGIC ("Name parsed, found object");
+ return i->second->m_object;
+ }
+ }
+ else
+ {
+ //
+ // There are more slashes so this is an intermediate segment of the
+ // specified name. We need to "recurse" when we find this segment.
+ //
+ offset = remaining.find ("/");
+ std::string segment = remaining.substr(0, offset);
+
+ std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (segment);
+ if (i == node->m_nameMap.end ())
+ {
+ NS_LOG_LOGIC ("Name does not exist in name map");
+ return 0;
+ }
+ else
+ {
+ node = i->second;
+ remaining = remaining.substr (offset + 1);
+ NS_LOG_LOGIC ("Intermediate segment parsed");
+ continue;
+ }
+ }
+ }
+
+ NS_ASSERT_MSG (node, "NamesPriv::FindObjectFromFullName(): Internal error: this can't happen");
+ return 0;
+}
+
+Ptr<Object>
+NamesPriv::FindObjectFromShortName (Ptr<Object> context, std::string name)
+{
+ NS_LOG_FUNCTION (context << name);
+
+ NameNode *node = 0;
+
+ if (context == 0)
+ {
+ NS_LOG_LOGIC ("Zero context implies root NameNode");
+ node = &m_root;
+ }
+ else
+ {
+ node = IsNamed (context);
+ if (node == 0)
+ {
+ NS_LOG_LOGIC ("Context does not point to a previously named node");
+ return 0;
+ }
+ }
+
+ std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
+ if (i == node->m_nameMap.end ())
+ {
+ NS_LOG_LOGIC ("Name does not exist in name map");
+ return 0;
+ }
+ else
+ {
+ NS_LOG_LOGIC ("Name exists in name map");
+ return i->second->m_object;
+ }
+}
+
+NameNode *
+NamesPriv::IsNamed (Ptr<Object> object)
+{
+ NS_LOG_FUNCTION (object);
+
+ std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
+ if (i == m_objectMap.end ())
+ {
+ NS_LOG_LOGIC ("Object does not exist in object map, returning NameNode 0");
+ return 0;
+ }
+ else
+ {
+ NS_LOG_LOGIC ("Object exists in object map, returning NameNode " << &i->second);
+ return i->second;
+ }
+}
+
+bool
+NamesPriv::IsDuplicateName (NameNode *node, std::string name)
+{
+ NS_LOG_FUNCTION (node << name);
+
+ std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
+ if (i == node->m_nameMap.end ())
+ {
+ NS_LOG_LOGIC ("Name does not exist in name map");
+ return false;
+ }
+ else
+ {
+ NS_LOG_LOGIC ("Name exists in name map");
+ return true;
+ }
+}
+
+bool
+Names::Add (std::string name, Ptr<Object> object)
+{
+ return NamesPriv::Get ()->Add (name, object);
+}
+
+bool
+Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
+{
+ return NamesPriv::Get ()->Add (context, name, object);
+}
+
+bool
+Names::Add (std::string context, std::string name, Ptr<Object> object)
+{
+ return NamesPriv::Get ()->Add (context, name, object);
+}
+
+std::string
+Names::FindShortName (Ptr<Object> object)
+{
+ return NamesPriv::Get ()->FindShortName (object);
+}
+
+std::string
+Names::FindFullName (Ptr<Object> object)
+{
+ return NamesPriv::Get ()->FindFullName (object);
+}
+
+Ptr<Object>
+Names::FindObjectFromFullNameInternal (std::string name)
+{
+ return NamesPriv::Get ()->FindObjectFromFullName (name);
+}
+
+Ptr<Object>
+Names::FindObjectFromShortNameInternal (Ptr<Object> context, std::string name)
+{
+ return NamesPriv::Get ()->FindObjectFromShortName (context, name);
+}
+
+} //namespace ns3
+
+#ifdef RUN_SELF_TESTS
+
+#include "test.h"
+#include "object-factory.h"
+
+namespace ns3 {
+
+class TestObject : public Object
+{
+public:
+ static TypeId GetTypeId (void)
+ {
+ static TypeId tid = TypeId ("TestObject")
+ .SetParent (Object::GetTypeId ())
+ .HideFromDocumentation ()
+ .AddConstructor<TestObject> ();
+ return tid;
+ }
+ TestObject () {}
+ virtual void Dispose (void) {}
+};
+
+class NamesTest : public Test
+{
+public:
+ NamesTest ();
+ virtual bool RunTests (void);
+};
+
+NamesTest::NamesTest ()
+ : Test ("Names")
+{
+}
+
+bool
+NamesTest::RunTests (void)
+{
+ bool result = true;
+
+ //
+ // Name a couple of objects at the root level
+ //
+ Ptr<TestObject> client = CreateObject<TestObject> ();
+ result = Names::Add ("Client", client);
+ NS_TEST_ASSERT_EQUAL (result, true);
+
+ Ptr<TestObject> server = CreateObject<TestObject> ();
+ result = Names::Add ("Server", server);
+ NS_TEST_ASSERT_EQUAL (result, true);
+
+ //
+ // We shouldn't be able to add another name to a previously named object
+ //
+ result = Names::Add ("Not Client", client);
+ NS_TEST_ASSERT_EQUAL (result, false);
+
+ //
+ // We shouldn't be able to duplicate a name at the root level.
+ //
+ Ptr<TestObject> secondClient = CreateObject<TestObject> ();
+ result = Names::Add ("Client", secondClient);
+ NS_TEST_ASSERT_EQUAL (result, false);
+
+ //
+ // We should be able to add a new name in the first object's context
+ //
+ Ptr<TestObject> clientEth0 = CreateObject<TestObject> ();
+ result = Names::Add (client, "eth0", clientEth0);
+ NS_TEST_ASSERT_EQUAL (result, true);
+
+ //
+ // We shouldn't be able to duplicate a name in that context.
+ //
+ Ptr<TestObject> secondClientEth0 = CreateObject<TestObject> ();
+ result = Names::Add (client, "eth0", secondClientEth0);
+ NS_TEST_ASSERT_EQUAL (result, false);
+
+ //
+ // We should be able to add the same name in the second object's context
+ //
+ Ptr<TestObject> serverEth0 = CreateObject<TestObject> ();
+ result = Names::Add (server, "eth0", serverEth0);
+ NS_TEST_ASSERT_EQUAL (result, true);
+
+ //
+ // We should be able to find the short names for the objects we created
+ //
+ std::string found;
+
+ found = Names::FindShortName (client);
+ NS_TEST_ASSERT_EQUAL (found, "Client");
+
+ found = Names::FindShortName (server);
+ NS_TEST_ASSERT_EQUAL (found, "Server");
+
+ found = Names::FindShortName (clientEth0);
+ NS_TEST_ASSERT_EQUAL (found, "eth0");
+
+ found = Names::FindShortName (serverEth0);
+ NS_TEST_ASSERT_EQUAL (found, "eth0");
+
+ //
+ // We should be able to find the full names for the objects we created
+ //
+ found = Names::FindFullName (client);
+ NS_TEST_ASSERT_EQUAL (found, "/Names/Client");
+
+ found = Names::FindFullName (server);
+ NS_TEST_ASSERT_EQUAL (found, "/Names/Server");
+
+ found = Names::FindFullName (clientEth0);
+ NS_TEST_ASSERT_EQUAL (found, "/Names/Client/eth0");
+
+ found = Names::FindFullName (serverEth0);
+ NS_TEST_ASSERT_EQUAL (found, "/Names/Server/eth0");
+
+ //
+ // We should be able to find the objects from the short names
+ //
+ Ptr<TestObject> foundObject;
+
+ foundObject = Names::FindObjectFromShortName<TestObject> (0, "Client");
+ NS_TEST_ASSERT_EQUAL (foundObject, client);
+
+ foundObject = Names::FindObjectFromShortName<TestObject> (0, "Server");
+ NS_TEST_ASSERT_EQUAL (foundObject, server);
+
+ foundObject = Names::FindObjectFromShortName<TestObject> (client, "eth0");
+ NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
+
+ foundObject = Names::FindObjectFromShortName<TestObject> (server, "eth0");
+ NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
+
+ //
+ // We should be able to find the objects from their full names
+ //
+ foundObject = Names::Find<TestObject> ("/Names/Client");
+ NS_TEST_ASSERT_EQUAL (foundObject, client);
+
+ foundObject = Names::Find<TestObject> ("/Names/Server");
+ NS_TEST_ASSERT_EQUAL (foundObject, server);
+
+ foundObject = Names::Find<TestObject> ("/Names/Client/eth0");
+ NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
+
+ foundObject = Names::Find<TestObject> ("/Names/Server/eth0");
+ NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
+
+ //
+ // We also have some syntactical sugary methods, so make sure they do what
+ // they should as well.
+ //
+ Ptr<TestObject> bridge = CreateObject<TestObject> ();
+ result = Names::Add ("/Names", "Bridge", client);
+ NS_TEST_ASSERT_EQUAL (result, true);
+
+ Ptr<TestObject> bridgeEth0 = CreateObject<TestObject> ();
+ result = Names::Add ("/Names/Bridge", "eth0", bridgeEth0);
+ NS_TEST_ASSERT_EQUAL (result, true);
+
+ foundObject = Names::Find<TestObject> ("/Names/Bridge");
+ NS_TEST_ASSERT_EQUAL (foundObject, bridge);
+
+ foundObject = Names::Find<TestObject> ("/Names/Bridge/eth0");
+ NS_TEST_ASSERT_EQUAL (foundObject, bridgeEth0);
+
+ //
+ // Run the simulator and destroy it to get the Destroy method called on the
+ // private implementation object. We depend on seeing a valgrind-clean run of
+ // the unit tests to really determine if the clean up was really successful.
+ //
+ Simulator::Run ();
+ Simulator::Destroy ();
+
+ return true;
+}
+
+static NamesTest g_namesTests;
+
+} // namespace ns3
+
+#endif /* RUN_SELF_TESTS */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/object-names.h Tue Jan 20 15:47:14 2009 -0800
@@ -0,0 +1,245 @@
+/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
+/*
+ * Copyright (c) 2009 University of Washington
+ *
+ * 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
+ */
+
+#ifndef OBJECT_NAMES_H
+#define OBJECT_NAMES_H
+
+#include "ns3/ptr.h"
+#include "ns3/object.h"
+
+namespace ns3 {
+
+/**
+ * \brief A directory of name and Ptr<Object> associations that allows us to
+ * give any ns3 Object a name.
+ */
+class Names
+{
+public:
+
+ /**
+ * Add the association between the string "name" and the Ptr<Object> obj
+ * at the root of the "/Names" name space. This can be seen as equivalent
+ * to adding a Pointer Attribute called "name" to the to the root name
+ * space object and then assigning the value obj to that attribute. The
+ * config facility will see it that way.
+ *
+ * \param name The name of the object you want to associate.
+ * \param obj A smart pointer to the object itself.
+ */
+ static bool Add (std::string name, Ptr<Object> obj);
+
+ /**
+ * Add the association between the string "name" and the Ptr<Object> obj
+ * in the object context given by the Ptr<Object> context. This can be
+ * seen as equivalent to adding a Pointer Attribute called "name" to the
+ * object given by "context" and then assigning the value obj to that
+ * attribute. The config facility will see it that way.
+ *
+ * \param context A spart pointer to an object under which you want this
+ * name to be defined.
+ * \param name The name of the object you want to associate.
+ * \param obj A smart pointer to the object itself.
+ */
+ static bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
+
+ /**
+ * Syntactic sugar around the Object context Name method. Allows you to
+ * specify the context with a string instead of the pointer. If the first
+ * parameter (context) is "/Names" this turns into a call into Name at the
+ * root of the name space. Otherwise it does a FindObjectFromFullNameInternal
+ * on the context and adds the name to a subspace.
+ *
+ * \param context A fully qualified name describing a previously named object.
+ * under which you want this name to be defined.
+ * \param name The name of the object you want to associate.
+ * \param obj A smart pointer to the object itself.
+ */
+ static bool Add (std::string context, std::string name, Ptr<Object> object);
+
+ /**
+ * Given a pointer to an object, look to see if that object has a name
+ * associated with it and return the shortname for the object.
+ *
+ * The fullname of an object is a fully qualified namespace name, for example
+ * if you have a device that you have previously named "eth0" under a node
+ * you have named "client", the fullname of the device will then be
+ * "/Names/client/eth0".
+ *
+ * The shortname of an object is the name of the object in its parent name
+ * space. Using the example above, asking for the shortname of the device
+ * will result in "eth0" being returned.
+ *
+ * \param object A spart pointer to an object for which you want to find
+ * its shortname.
+ */
+ static std::string FindShortName (Ptr<Object> object);
+
+ /**
+ * Given a pointer to an object, look to see if that object has a name
+ * associated with it and return the fully qualified namespace name
+ * for the object.
+ *
+ * The fullname of an object is a fully qualified namespace name, for example
+ * if you have a device that you have previously named "eth0" under a node
+ * you have named "client", the fullname of the device will then be
+ * "/Names/client/eth0".
+ *
+ * The shortname of an object is the name of the object in its parent name
+ * space. Using the example above, asking for the shortname of the device
+ * will result in "eth0" being returned.
+ *
+ * \param object A spart pointer to an object for which you want to find
+ * its fullname.
+ */
+ static std::string FindFullName (Ptr<Object> object);
+
+ /**
+ * Given a fullname string, look to see if there's an object in the system
+ * with a that associated with it. If there is, do a QueryObject on the
+ * resulting object to convert it to the requested typename.
+ *
+ * The fullname of an object is a fully qualified namespace name, for example
+ * if you have a device that you have previously named "eth0" under a node
+ * you have named "client", the fullname of the device will then be
+ * "/Names/client/eth0".
+ *
+ * \param name A string containing a fully qualified name space name
+ * used to locate the object.
+ */
+ template <typename T>
+ static Ptr<T> FindObjectFromFullName (std::string name);
+
+ /**
+ * Given a fullname string, look to see if there's an object in the system
+ * with a that associated with it. If there is, do a QueryObject on the
+ * resulting object to convert it to the requested typename.
+ *
+ * The fullname of an object is a fully qualified namespace name, for example
+ * if you have a device that you have previously named "eth0" under a node
+ * you have named "client", the fullname of the device will then be
+ * "/Names/client/eth0".
+ *
+ * \param name A string containing a fully qualified name space name
+ * used to locate the object.
+ *
+ * @comment This method is identical to FindObjectFromFullName, but has a
+ * short signature since it is a common use and we want it to be easy to
+ * type.
+ */
+ template <typename T>
+ static Ptr<T> Find (std::string name);
+
+ /**
+ * Given an object context and a shortname string, look through the names
+ * associated with the namespace defined by the context object to see if
+ * there's an object there with the given shortname.
+ *
+ * The fullname of an object is a fully qualified namespace name, for example
+ * if you have a device that you have previously named "eth0" under a node
+ * you have named "client", the fullname of the device will then be
+ * "/Names/client/eth0".
+ *
+ * The shortname of an object is the name of the object in its parent name
+ * space. Using the example above, asking for the shortname of the device
+ * will result in "eth0" being returned.
+ *
+ * The context object provides a namespace context, in the case of the example
+ * it would be the "client" object under which we look for the short name.
+ * In the example above, the context pointer would be the Ptr<Object> to the
+ * client node, and the name would be the shortname "eth0"
+ *
+ * \param context A spart pointer to an object under which you want to look
+ * for the provided name.
+ * \param name A string containing a shortname to look for.
+ */
+ template <typename T>
+ static Ptr<T> FindObjectFromShortName (Ptr<Object> context, std::string name);
+
+private:
+
+ /**
+ * \internal
+ *
+ * \brief Non-templated internal version of FindObjectFromLongName
+ *
+ * \param name A string containing a longname to look for.
+ */
+ static Ptr<Object> FindObjectFromFullNameInternal (std::string name);
+
+ /**
+ * \internal
+ *
+ * \brief Non-templated internal version of FindObjectFromShortName
+ *
+ * \param context A spart pointer to an object under which you want to look
+ * for the provided name.
+ * \param name A string containing a shortname to look for.
+ */
+ static Ptr<Object> FindObjectFromShortNameInternal (Ptr<Object> context, std::string name);
+};
+
+/**
+ * \brief Template definition of corresponding template declaration found in class Names.
+ */
+template <typename T>
+Ptr<T>
+Names::Find (std::string name)
+{
+ return FindObjectFromFullName<T> (name);
+}
+
+/**
+ * \brief Template definition of corresponding template declaration found in class Names.
+ */
+template <typename T>
+Ptr<T>
+Names::FindObjectFromFullName (std::string name)
+{
+ Ptr<Object> obj = FindObjectFromFullNameInternal (name);
+ if (obj)
+ {
+ return obj->GetObject<T> ();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+/**
+ * \brief Template definition of corresponding template declaration found in class Names.
+ */
+template <typename T>
+Ptr<T>
+Names::FindObjectFromShortName (Ptr<Object> context, std::string name)
+{
+ Ptr<Object> obj = FindObjectFromShortNameInternal (context, name);
+ if (obj)
+ {
+ return obj->GetObject<T> ();
+ }
+ else
+ {
+ return 0;
+ }
+}
+
+}//namespace ns3
+
+#endif /* OBJECT_NAMES_H */
--- a/src/core/wscript Sun Jan 18 22:47:25 2009 +0000
+++ b/src/core/wscript Tue Jan 20 15:47:14 2009 -0800
@@ -53,6 +53,7 @@
'trace-source-accessor.cc',
'config.cc',
'callback.cc',
+ 'object-names.cc',
]
core.uselib = 'RT'
@@ -98,6 +99,7 @@
'object-vector.h',
'deprecated.h',
'abort.h',
+ 'object-names.h',
]
if sys.platform == 'win32':