src/core/object-names.cc
changeset 4139 d45e62c78504
child 4141 3f7f08d9daad
equal deleted inserted replaced
4110:04170734fa8b 4139:d45e62c78504
       
     1 /* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */
       
     2 /*
       
     3  * Copyright (c) 2009 University of Washington
       
     4  *
       
     5  * This program is free software; you can redistribute it and/or modify
       
     6  * it under the terms of the GNU General Public License version 2 as
       
     7  * published by the Free Software Foundation;
       
     8  *
       
     9  * This program is distributed in the hope that it will be useful,
       
    10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
       
    11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
       
    12  * GNU General Public License for more details.
       
    13  *
       
    14  * You should have received a copy of the GNU General Public License
       
    15  * along with this program; if not, write to the Free Software
       
    16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
       
    17  */
       
    18 
       
    19 #include <map>
       
    20 #include "ns3/object.h"
       
    21 #include "ns3/log.h"
       
    22 #include "ns3/assert.h"
       
    23 #include "ns3/abort.h"
       
    24 #include "ns3/simulator.h"
       
    25 #include "object-names.h"
       
    26 
       
    27 namespace ns3 {
       
    28 
       
    29 NS_LOG_COMPONENT_DEFINE ("Names");
       
    30 
       
    31 class NameNode
       
    32 {
       
    33 public:
       
    34   NameNode ();
       
    35   NameNode (const NameNode &nameNode);
       
    36   NameNode (NameNode *parent, std::string name, Ptr<Object> object);
       
    37   NameNode &operator = (const NameNode &rhs);
       
    38 
       
    39  ~NameNode ();
       
    40 
       
    41   NameNode *m_parent;
       
    42   std::string m_name;
       
    43   Ptr<Object> m_object;
       
    44 
       
    45   std::map<std::string, NameNode *> m_nameMap;
       
    46 };
       
    47 
       
    48 NameNode::NameNode ()
       
    49   : m_parent (0), m_name (""), m_object (0)
       
    50 {
       
    51 }
       
    52 
       
    53 NameNode::NameNode (const NameNode &nameNode)
       
    54 {
       
    55   m_parent = nameNode.m_parent;
       
    56   m_name = nameNode.m_name;
       
    57   m_object = nameNode.m_object;
       
    58   m_nameMap = nameNode.m_nameMap;
       
    59 }
       
    60 
       
    61 NameNode &
       
    62 NameNode::operator = (const NameNode &rhs)
       
    63 {
       
    64   m_parent = rhs.m_parent;
       
    65   m_name = rhs.m_name;
       
    66   m_object = rhs.m_object;
       
    67   m_nameMap = rhs.m_nameMap;
       
    68   return *this;
       
    69 }
       
    70 
       
    71 NameNode::NameNode (NameNode *parent, std::string name, Ptr<Object> object)
       
    72   : m_parent (parent), m_name (name), m_object (object)
       
    73 {
       
    74 }
       
    75 
       
    76 NameNode::~NameNode ()
       
    77 {
       
    78 }
       
    79 
       
    80 class NamesPriv 
       
    81 {
       
    82 public:
       
    83   NamesPriv ();
       
    84   ~NamesPriv ();
       
    85 
       
    86   bool Add (std::string name, Ptr<Object> obj);
       
    87   bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
       
    88   bool Add (std::string context, std::string name, Ptr<Object> object);
       
    89   std::string FindShortName (Ptr<Object> object);
       
    90   std::string FindFullName (Ptr<Object> object);
       
    91   Ptr<Object> FindObjectFromFullName (std::string name);
       
    92   Ptr<Object> FindObjectFromShortName (Ptr<Object> context, std::string name);
       
    93 
       
    94   static NamesPriv *Get (void);
       
    95   
       
    96 private:
       
    97   static NamesPriv **DoGet (void);
       
    98   static void Delete (void);
       
    99 
       
   100   NameNode *IsNamed (Ptr<Object>);
       
   101   bool IsDuplicateName (NameNode *node, std::string name);
       
   102 
       
   103   NameNode m_root;
       
   104   std::map<Ptr<Object>, NameNode *> m_objectMap;
       
   105 };
       
   106 
       
   107 NamesPriv *
       
   108 NamesPriv::Get (void)
       
   109 {
       
   110   return *(DoGet ());
       
   111 }
       
   112 
       
   113 NamesPriv **
       
   114 NamesPriv::DoGet (void)
       
   115 {
       
   116   static NamesPriv *ptr = 0;
       
   117 
       
   118   if (ptr == 0)
       
   119     {
       
   120       ptr = new NamesPriv;
       
   121       Simulator::ScheduleDestroy (&NamesPriv::Delete);
       
   122     }
       
   123 
       
   124   return &ptr;
       
   125 }
       
   126 
       
   127 void 
       
   128 NamesPriv::Delete (void)
       
   129 {
       
   130   NS_LOG_FUNCTION_NOARGS ();
       
   131 
       
   132   NamesPriv **ptr = DoGet ();
       
   133   delete *ptr;
       
   134   *ptr = 0;
       
   135 }
       
   136 
       
   137 NamesPriv::NamesPriv ()
       
   138 {
       
   139   NS_LOG_FUNCTION_NOARGS ();
       
   140 
       
   141   m_root.m_parent = 0;
       
   142   m_root.m_name = "Names";
       
   143   m_root.m_object = 0;
       
   144 }
       
   145 
       
   146 NamesPriv::~NamesPriv ()
       
   147 {
       
   148   NS_LOG_FUNCTION_NOARGS ();
       
   149 
       
   150   //
       
   151   // Every name is associated with an object in the object map, so freeing the
       
   152   // NameNodes in this map will free all of the memory allocated for the NameNodes
       
   153   //
       
   154   for (std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.begin (); i != m_objectMap.end (); ++i)
       
   155     {
       
   156       delete i->second;
       
   157       i->second = 0;
       
   158     }
       
   159 }
       
   160 
       
   161 bool
       
   162 NamesPriv::Add (std::string name, Ptr<Object> object)
       
   163 {
       
   164   return Add (Ptr<Object> (0, false), name, object);
       
   165 }
       
   166 
       
   167 bool
       
   168 NamesPriv::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
       
   169 {
       
   170   NS_LOG_FUNCTION (context << name << object);
       
   171 
       
   172   if (IsNamed (object))
       
   173     {
       
   174       NS_LOG_LOGIC ("Object is already named");
       
   175       return false;
       
   176     }
       
   177 
       
   178   NameNode *node = 0;
       
   179   if (context)
       
   180     {
       
   181       node = IsNamed (context);
       
   182       NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
       
   183     }
       
   184   else
       
   185     {
       
   186       node = &m_root;
       
   187     }
       
   188 
       
   189   if (IsDuplicateName (node, name))
       
   190     {
       
   191       NS_LOG_LOGIC ("Name is already taken");
       
   192       return false;
       
   193     }
       
   194 
       
   195   NameNode *newNode = new NameNode(node, name, object);
       
   196   node->m_nameMap[name] = newNode;
       
   197   m_objectMap[object] = newNode;
       
   198 
       
   199   return true;
       
   200 }
       
   201 
       
   202 bool
       
   203 NamesPriv::Add (std::string context, std::string name, Ptr<Object> object)
       
   204 {
       
   205   if (context == "/Names")
       
   206     {
       
   207       return Add (name, object);
       
   208     }
       
   209   return Add (FindObjectFromFullName (context), name, object);
       
   210 }
       
   211 
       
   212 std::string
       
   213 NamesPriv::FindShortName (Ptr<Object> object)
       
   214 {
       
   215   NS_LOG_FUNCTION (object);
       
   216 
       
   217   std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
       
   218   if (i == m_objectMap.end ())
       
   219     {
       
   220       NS_LOG_LOGIC ("Object does not exist in object map");
       
   221       return "";
       
   222     }
       
   223   else
       
   224     {
       
   225       NS_LOG_LOGIC ("Object exists in object map");
       
   226       return i->second->m_name;
       
   227     }
       
   228 }
       
   229 
       
   230 std::string
       
   231 NamesPriv::FindFullName (Ptr<Object> object)
       
   232 {
       
   233   NS_LOG_FUNCTION (object);
       
   234 
       
   235   std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
       
   236   if (i == m_objectMap.end ())
       
   237     {
       
   238       NS_LOG_LOGIC ("Object does not exist in object map");
       
   239       return "";
       
   240     }
       
   241 
       
   242   NameNode *p = i->second;
       
   243   NS_ASSERT_MSG (p, "NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map");
       
   244 
       
   245   std::string fullname;
       
   246 
       
   247   do
       
   248     {
       
   249       fullname = "/" + p->m_name + fullname;
       
   250       NS_LOG_LOGIC ("fullname is " << fullname);
       
   251     }
       
   252   while ((p = p->m_parent) != 0);
       
   253 
       
   254   return fullname;
       
   255 }
       
   256 
       
   257 
       
   258 Ptr<Object>
       
   259 NamesPriv::FindObjectFromFullName (std::string name)
       
   260 {
       
   261   std::string namespaceName = "/Names/";
       
   262   std::string::size_type offset = name.find (namespaceName);
       
   263   if (offset == std::string::npos)
       
   264     {
       
   265       NS_LOG_LOGIC (name << " is not in the " << namespaceName << " name space");
       
   266       return 0;
       
   267     }
       
   268 
       
   269   std::string remaining = name.substr (namespaceName.size ());
       
   270   NameNode *node = &m_root;
       
   271 
       
   272   //
       
   273   // remaining is now composed entirely of path segments in the /Names name space.
       
   274   // and we have eaten the leading slash. e.g., remaining = "ClientNode/eth0"
       
   275   // The start of the search is at the root of the name space.
       
   276   //
       
   277   for (;;)
       
   278     {
       
   279       NS_LOG_LOGIC ("Looking for the object of name " << remaining);
       
   280       offset = remaining.find ("/");
       
   281       if (offset == std::string::npos)
       
   282         {
       
   283           //
       
   284           // There are no remaining slashes so this is the last segment of the 
       
   285           // specified name.  We're done when we find it
       
   286           //
       
   287           std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (remaining);
       
   288           if (i == node->m_nameMap.end ())
       
   289             {
       
   290               NS_LOG_LOGIC ("Name does not exist in name map");
       
   291               return 0;
       
   292             }
       
   293           else
       
   294             {
       
   295               NS_LOG_LOGIC ("Name parsed, found object");
       
   296               return i->second->m_object;
       
   297             }
       
   298         }
       
   299       else
       
   300         {
       
   301           //
       
   302           // There are more slashes so this is an intermediate segment of the 
       
   303           // specified name.  We need to "recurse" when we find this segment.
       
   304           //
       
   305           offset = remaining.find ("/");
       
   306           std::string segment = remaining.substr(0, offset);
       
   307 
       
   308           std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (segment);
       
   309           if (i == node->m_nameMap.end ())
       
   310             {
       
   311               NS_LOG_LOGIC ("Name does not exist in name map");
       
   312               return 0;
       
   313             }
       
   314           else
       
   315             {
       
   316               node = i->second;
       
   317               remaining = remaining.substr (offset + 1);
       
   318               NS_LOG_LOGIC ("Intermediate segment parsed");
       
   319               continue;
       
   320             }
       
   321         }
       
   322     }
       
   323 
       
   324   NS_ASSERT_MSG (node, "NamesPriv::FindObjectFromFullName(): Internal error:  this can't happen");
       
   325   return 0;
       
   326 }
       
   327 
       
   328 Ptr<Object>
       
   329 NamesPriv::FindObjectFromShortName (Ptr<Object> context, std::string name)
       
   330 {
       
   331   NS_LOG_FUNCTION (context << name);
       
   332 
       
   333   NameNode *node = 0;
       
   334 
       
   335   if (context == 0)
       
   336     {
       
   337       NS_LOG_LOGIC ("Zero context implies root NameNode");
       
   338       node = &m_root;
       
   339     }
       
   340   else
       
   341     {
       
   342       node = IsNamed (context);
       
   343       if (node == 0)
       
   344         {
       
   345           NS_LOG_LOGIC ("Context does not point to a previously named node");
       
   346           return 0;
       
   347         }
       
   348     }
       
   349 
       
   350   std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
       
   351   if (i == node->m_nameMap.end ())
       
   352     {
       
   353       NS_LOG_LOGIC ("Name does not exist in name map");
       
   354       return 0;
       
   355     }
       
   356   else
       
   357     {
       
   358       NS_LOG_LOGIC ("Name exists in name map");
       
   359       return i->second->m_object;
       
   360     }
       
   361 }
       
   362 
       
   363 NameNode *
       
   364 NamesPriv::IsNamed (Ptr<Object> object)
       
   365 {
       
   366   NS_LOG_FUNCTION (object);
       
   367 
       
   368   std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
       
   369   if (i == m_objectMap.end ())
       
   370     {
       
   371       NS_LOG_LOGIC ("Object does not exist in object map, returning NameNode 0");
       
   372       return 0;
       
   373     }
       
   374   else
       
   375     {
       
   376       NS_LOG_LOGIC ("Object exists in object map, returning NameNode " << &i->second);
       
   377       return i->second;
       
   378     }
       
   379 }
       
   380 
       
   381 bool
       
   382 NamesPriv::IsDuplicateName (NameNode *node, std::string name)
       
   383 {
       
   384   NS_LOG_FUNCTION (node << name);
       
   385 
       
   386   std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
       
   387   if (i == node->m_nameMap.end ())
       
   388     {
       
   389       NS_LOG_LOGIC ("Name does not exist in name map");
       
   390       return false;
       
   391     }
       
   392   else
       
   393     {
       
   394       NS_LOG_LOGIC ("Name exists in name map");
       
   395       return true;
       
   396     }
       
   397 }
       
   398 
       
   399 bool
       
   400 Names::Add (std::string name, Ptr<Object> object)
       
   401 {
       
   402   return NamesPriv::Get ()->Add (name, object);
       
   403 }
       
   404 
       
   405 bool
       
   406 Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
       
   407 {
       
   408   return NamesPriv::Get ()->Add (context, name, object);
       
   409 }
       
   410 
       
   411 bool
       
   412 Names::Add (std::string context, std::string name, Ptr<Object> object)
       
   413 {
       
   414   return NamesPriv::Get ()->Add (context, name, object);
       
   415 }
       
   416 
       
   417 std::string
       
   418 Names::FindShortName (Ptr<Object> object)
       
   419 {
       
   420   return NamesPriv::Get ()->FindShortName (object);
       
   421 }
       
   422 
       
   423 std::string
       
   424 Names::FindFullName (Ptr<Object> object)
       
   425 {
       
   426   return NamesPriv::Get ()->FindFullName (object);
       
   427 }
       
   428 
       
   429 Ptr<Object>
       
   430 Names::FindObjectFromFullNameInternal (std::string name)
       
   431 {
       
   432   return NamesPriv::Get ()->FindObjectFromFullName (name);
       
   433 }
       
   434 
       
   435 Ptr<Object>
       
   436 Names::FindObjectFromShortNameInternal (Ptr<Object> context, std::string name)
       
   437 {
       
   438   return NamesPriv::Get ()->FindObjectFromShortName (context, name);
       
   439 }
       
   440 
       
   441 } //namespace ns3
       
   442 
       
   443 #ifdef RUN_SELF_TESTS
       
   444 
       
   445 #include "test.h"
       
   446 #include "object-factory.h"
       
   447 
       
   448 namespace ns3 {
       
   449 
       
   450 class TestObject : public Object
       
   451 {
       
   452 public:
       
   453   static TypeId GetTypeId (void) 
       
   454   {
       
   455     static TypeId tid = TypeId ("TestObject")
       
   456       .SetParent (Object::GetTypeId ())
       
   457       .HideFromDocumentation ()
       
   458       .AddConstructor<TestObject> ();
       
   459     return tid;
       
   460   }
       
   461   TestObject () {}
       
   462   virtual void Dispose (void) {}
       
   463 };
       
   464 
       
   465 class NamesTest : public Test
       
   466 {
       
   467 public:
       
   468   NamesTest ();
       
   469   virtual bool RunTests (void);
       
   470 };
       
   471 
       
   472 NamesTest::NamesTest ()
       
   473   : Test ("Names")
       
   474 {
       
   475 }
       
   476 
       
   477 bool 
       
   478 NamesTest::RunTests (void)
       
   479 {
       
   480   bool result = true;
       
   481 
       
   482   // 
       
   483   // Name a couple of objects at the root level
       
   484   //
       
   485   Ptr<TestObject> client = CreateObject<TestObject> ();
       
   486   result = Names::Add ("Client", client);
       
   487   NS_TEST_ASSERT_EQUAL (result, true);
       
   488 
       
   489   Ptr<TestObject> server = CreateObject<TestObject> ();
       
   490   result = Names::Add ("Server", server);
       
   491   NS_TEST_ASSERT_EQUAL (result, true);
       
   492 
       
   493   //
       
   494   // We shouldn't be able to add another name to a previously named object
       
   495   //
       
   496   result = Names::Add ("Not Client", client);
       
   497   NS_TEST_ASSERT_EQUAL (result, false);
       
   498 
       
   499   //
       
   500   // We shouldn't be able to duplicate a name at the root level.
       
   501   //
       
   502   Ptr<TestObject> secondClient = CreateObject<TestObject> ();
       
   503   result = Names::Add ("Client", secondClient);
       
   504   NS_TEST_ASSERT_EQUAL (result, false);
       
   505 
       
   506   //
       
   507   // We should be able to add a new name in the first object's context
       
   508   //
       
   509   Ptr<TestObject> clientEth0 = CreateObject<TestObject> ();
       
   510   result = Names::Add (client, "eth0", clientEth0);
       
   511   NS_TEST_ASSERT_EQUAL (result, true);
       
   512 
       
   513   //
       
   514   // We shouldn't be able to duplicate a name in that context.
       
   515   //
       
   516   Ptr<TestObject> secondClientEth0 = CreateObject<TestObject> ();
       
   517   result = Names::Add (client, "eth0", secondClientEth0);
       
   518   NS_TEST_ASSERT_EQUAL (result, false);
       
   519 
       
   520   //
       
   521   // We should be able to add the same name in the second object's context
       
   522   //
       
   523   Ptr<TestObject> serverEth0 = CreateObject<TestObject> ();
       
   524   result = Names::Add (server, "eth0", serverEth0);
       
   525   NS_TEST_ASSERT_EQUAL (result, true);
       
   526 
       
   527   //
       
   528   // We should be able to find the short names for the objects we created
       
   529   //
       
   530   std::string found;
       
   531 
       
   532   found = Names::FindShortName (client);
       
   533   NS_TEST_ASSERT_EQUAL (found, "Client");
       
   534 
       
   535   found = Names::FindShortName (server);
       
   536   NS_TEST_ASSERT_EQUAL (found, "Server");
       
   537 
       
   538   found = Names::FindShortName (clientEth0);
       
   539   NS_TEST_ASSERT_EQUAL (found, "eth0");
       
   540 
       
   541   found = Names::FindShortName (serverEth0);
       
   542   NS_TEST_ASSERT_EQUAL (found, "eth0");
       
   543 
       
   544   //
       
   545   // We should be able to find the full names for the objects we created
       
   546   //
       
   547   found = Names::FindFullName (client);
       
   548   NS_TEST_ASSERT_EQUAL (found, "/Names/Client");
       
   549 
       
   550   found = Names::FindFullName (server);
       
   551   NS_TEST_ASSERT_EQUAL (found, "/Names/Server");
       
   552 
       
   553   found = Names::FindFullName (clientEth0);
       
   554   NS_TEST_ASSERT_EQUAL (found, "/Names/Client/eth0");
       
   555 
       
   556   found = Names::FindFullName (serverEth0);
       
   557   NS_TEST_ASSERT_EQUAL (found, "/Names/Server/eth0");
       
   558 
       
   559   // 
       
   560   // We should be able to find the objects from the short names
       
   561   //
       
   562   Ptr<TestObject> foundObject;
       
   563 
       
   564   foundObject = Names::FindObjectFromShortName<TestObject> (0, "Client");
       
   565   NS_TEST_ASSERT_EQUAL (foundObject, client);
       
   566 
       
   567   foundObject = Names::FindObjectFromShortName<TestObject> (0, "Server");
       
   568   NS_TEST_ASSERT_EQUAL (foundObject, server);
       
   569 
       
   570   foundObject = Names::FindObjectFromShortName<TestObject> (client, "eth0");
       
   571   NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
       
   572 
       
   573   foundObject = Names::FindObjectFromShortName<TestObject> (server, "eth0");
       
   574   NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
       
   575 
       
   576   // 
       
   577   // We should be able to find the objects from their full names
       
   578   //
       
   579   foundObject = Names::Find<TestObject> ("/Names/Client");
       
   580   NS_TEST_ASSERT_EQUAL (foundObject, client);
       
   581 
       
   582   foundObject = Names::Find<TestObject> ("/Names/Server");
       
   583   NS_TEST_ASSERT_EQUAL (foundObject, server);
       
   584 
       
   585   foundObject = Names::Find<TestObject> ("/Names/Client/eth0");
       
   586   NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
       
   587 
       
   588   foundObject = Names::Find<TestObject> ("/Names/Server/eth0");
       
   589   NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
       
   590 
       
   591   //
       
   592   // We also have some syntactical sugary methods, so make sure they do what
       
   593   // they should as well.
       
   594   //
       
   595   Ptr<TestObject> bridge = CreateObject<TestObject> ();
       
   596   result = Names::Add ("/Names", "Bridge", client);
       
   597   NS_TEST_ASSERT_EQUAL (result, true);
       
   598 
       
   599   Ptr<TestObject> bridgeEth0 = CreateObject<TestObject> ();
       
   600   result = Names::Add ("/Names/Bridge", "eth0", bridgeEth0);
       
   601   NS_TEST_ASSERT_EQUAL (result, true);
       
   602 
       
   603   foundObject = Names::Find<TestObject> ("/Names/Bridge");
       
   604   NS_TEST_ASSERT_EQUAL (foundObject, bridge);
       
   605 
       
   606   foundObject = Names::Find<TestObject> ("/Names/Bridge/eth0");
       
   607   NS_TEST_ASSERT_EQUAL (foundObject, bridgeEth0);
       
   608 
       
   609   //
       
   610   // Run the simulator and destroy it to get the Destroy method called on the
       
   611   // private implementation object.  We depend on seeing a valgrind-clean run of
       
   612   // the unit tests to really determine if the clean up was really successful.
       
   613   //
       
   614   Simulator::Run ();
       
   615   Simulator::Destroy ();
       
   616   
       
   617   return true;
       
   618 }
       
   619 
       
   620 static NamesTest g_namesTests;
       
   621 
       
   622 } // namespace ns3
       
   623 
       
   624 #endif /* RUN_SELF_TESTS */