src/core/names.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sat, 04 Jul 2009 08:15:48 +0200
changeset 4654 2eaebe77d66b
parent 4298 cc2db3e6bcae
permissions -rw-r--r--
Added tag ns-3.5 for changeset c975274c9707
     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 "object.h"
    21 #include "log.h"
    22 #include "assert.h"
    23 #include "abort.h"
    24 #include "names.h"
    25 #include "ns3/simulator.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> object);
    87   bool Add (std::string path, std::string name, Ptr<Object> object);
    88   bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
    89 
    90   bool Rename (std::string oldpath, std::string newname);
    91   bool Rename (std::string path, std::string oldname, std::string newname);
    92   bool Rename (Ptr<Object> context, std::string oldname, std::string newname);
    93 
    94   std::string FindName (Ptr<Object> object);
    95   std::string FindPath (Ptr<Object> object);
    96 
    97   Ptr<Object> Find (std::string name);
    98   Ptr<Object> Find (std::string path, std::string name);
    99   Ptr<Object> Find (Ptr<Object> context, std::string name);
   100 
   101   static NamesPriv *Get (void);
   102   static void Delete (void);
   103 private:
   104   static NamesPriv **DoGet (bool doCreate);
   105 
   106   NameNode *IsNamed (Ptr<Object>);
   107   bool IsDuplicateName (NameNode *node, std::string name);
   108 
   109   NameNode m_root;
   110   std::map<Ptr<Object>, NameNode *> m_objectMap;
   111 };
   112 
   113 NamesPriv *
   114 NamesPriv::Get (void)
   115 {
   116   return *(DoGet (true));
   117 }
   118 
   119 NamesPriv **
   120 NamesPriv::DoGet (bool doCreate)
   121 {
   122   static NamesPriv *ptr = 0;
   123 
   124   if (ptr == 0 && doCreate)
   125     {
   126       ptr = new NamesPriv;
   127       Simulator::ScheduleDestroy (&NamesPriv::Delete);
   128     }
   129 
   130   return &ptr;
   131 }
   132 
   133 void 
   134 NamesPriv::Delete (void)
   135 {
   136   NS_LOG_FUNCTION_NOARGS ();
   137 
   138   NamesPriv **ptr = DoGet (false);
   139   delete *ptr;
   140   *ptr = 0;
   141 }
   142 
   143 NamesPriv::NamesPriv ()
   144 {
   145   NS_LOG_FUNCTION_NOARGS ();
   146 
   147   m_root.m_parent = 0;
   148   m_root.m_name = "Names";
   149   m_root.m_object = 0;
   150 }
   151 
   152 NamesPriv::~NamesPriv ()
   153 {
   154   NS_LOG_FUNCTION_NOARGS ();
   155 
   156   //
   157   // Every name is associated with an object in the object map, so freeing the
   158   // NameNodes in this map will free all of the memory allocated for the NameNodes
   159   //
   160   for (std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.begin (); i != m_objectMap.end (); ++i)
   161     {
   162       delete i->second;
   163       i->second = 0;
   164     }
   165 
   166   m_root.m_parent = 0;
   167   m_root.m_name = "";
   168   m_root.m_object = 0;
   169 }
   170 
   171 bool
   172 NamesPriv::Add (std::string name, Ptr<Object> object)
   173 {
   174   NS_LOG_FUNCTION (name << object);
   175   //
   176   // This is the simple, easy to use version of Add, so we want it to be flexible.
   177   // We don't want to force a user to always type the fully qualified namespace 
   178   // name, so we allow the namespace name to be omitted.  For example, calling
   179   // Add ("Client/ath0", obj) should result in exactly the same behavior as
   180   // Add ("/Names/Client/ath0", obj).  Calling Add ("Client", obj) should have
   181   // the same effect as Add ("Names/Client", obj)
   182   //
   183   // The first thing to do, then, is to "canonicalize" the input string to always
   184   // be a fully qualified name.
   185   //
   186   // If we are given a name that begins with "/Names/" we assume that this is a
   187   // fully qualified path name to the object we want to create.  We split the name
   188   // into a path string and and a final segment (name) and then call the "Real" Add.
   189   //
   190   std::string namespaceName = "/Names";
   191   std::string::size_type offset = name.find (namespaceName);
   192   if (offset != 0)
   193     {
   194       //
   195       // This must be a name that has the "/Names" namespace prefix omitted.  
   196       // Do some reasonableness checking on the rest of the name.
   197       //
   198       offset = name.find ("/");
   199       if (offset == 0)
   200         {
   201           NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
   202           return false;
   203         }
   204 
   205       name = "/Names/" + name;
   206     }
   207   
   208   //
   209   // There must now be a fully qualified path in the string.  All fully 
   210   // qualified names begin with "/Names".  We have to split off the final 
   211   // segment which will become the name of the object.  A '/' that
   212   // separates the path from the final segment had better be there since
   213   // we just made sure that at least the namespace name was there.
   214   //
   215   std::string::size_type i = name.rfind ("/");
   216   NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error.  Can't find '/' in name");
   217 
   218   //
   219   // The slash we found cannot be the slash at the start of the namespaceName.
   220   // This would indicate there is no name in the path at all.  It can be
   221   // any other index.
   222   //
   223   NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a name in the path string");
   224 
   225   //
   226   // We now know where the path string starts and ends, and where the
   227   // name starts and ends.  All we have to do is to call our available
   228   // function for adding a name under a path string.
   229   //
   230   return Add (name.substr (0, i), name.substr (i + 1), object);
   231 }
   232 
   233 bool
   234 NamesPriv::Add (std::string path, std::string name, Ptr<Object> object)
   235 {
   236   if (path == "/Names")
   237     {
   238       return Add (Ptr<Object> (0, false), name, object);
   239     }
   240   return Add (Find (path), name, object);
   241 }
   242 
   243 bool
   244 NamesPriv::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
   245 {
   246   NS_LOG_FUNCTION (context << name << object);
   247 
   248   if (IsNamed (object))
   249     {
   250       NS_LOG_LOGIC ("Object is already named");
   251       return false;
   252     }
   253 
   254   NameNode *node = 0;
   255   if (context)
   256     {
   257       node = IsNamed (context);
   258       NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
   259     }
   260   else
   261     {
   262       node = &m_root;
   263     }
   264 
   265   if (IsDuplicateName (node, name))
   266     {
   267       NS_LOG_LOGIC ("Name is already taken");
   268       return false;
   269     }
   270 
   271   NameNode *newNode = new NameNode(node, name, object);
   272   node->m_nameMap[name] = newNode;
   273   m_objectMap[object] = newNode;
   274 
   275   return true;
   276 }
   277 
   278 bool
   279 NamesPriv::Rename (std::string oldpath, std::string newname)
   280 {
   281   NS_LOG_FUNCTION (oldpath << newname);
   282   //
   283   // This is the simple, easy to use version of Rename, so we want it to be 
   284   // flexible.   We don't want to force a user to always type the fully 
   285   // qualified namespace name, so we allow the namespace name to be omitted.
   286   // For example, calling Rename ("Client/ath0", "eth0") should result in 
   287   // exactly the same behavior as Rename ("/Names/Client/ath0", "eth0").
   288   // Calling Rename ("Client", "Router") should have the same effect as 
   289   // Rename ("Names/Client", "Router")
   290   //
   291   // The first thing to do, then, is to "canonicalize" the input string to always
   292   // be a fully qualified path.
   293   //
   294   // If we are given a name that begins with "/Names/" we assume that this is a
   295   // fully qualified path to the object we want to change.  We split the path into 
   296   // path string (cf directory) and and a final segment (cf filename) and then call
   297   // the "Real" Rename.
   298   //
   299   std::string namespaceName = "/Names";
   300   std::string::size_type offset = oldpath.find (namespaceName);
   301   if (offset != 0)
   302     {
   303       //
   304       // This must be a name that has the "/Names" namespace prefix omitted.  
   305       // Do some reasonableness checking on the rest of the name.
   306       //
   307       offset = oldpath.find ("/");
   308       if (offset == 0)
   309         {
   310           NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
   311           return false;
   312         }
   313 
   314       oldpath = "/Names/" + oldpath;
   315     }
   316   
   317   //
   318   // There must now be a fully qualified path in the oldpath string.  All 
   319   // fully qualified names begin with "/Names".  We have to split off the final 
   320   // segment which will become the name we want to rename.  A '/' that
   321   // separates the path from the final segment (name) had better be there since
   322   // we just made sure that at least the namespace name was there.
   323   //
   324   std::string::size_type i = oldpath.rfind ("/");
   325   NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error.  Can't find '/' in name");
   326 
   327   //
   328   // The slash we found cannot be the slash at the start of the namespaceName.
   329   // This would indicate there is no name in the path at all.  It can be
   330   // any other index.
   331   //
   332   NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a name in the path string");
   333 
   334   //
   335   // We now know where the path part of the string starts and ends, and where the
   336   // name part starts and ends.  All we have to do is to call our available
   337   // function for creating adding a name under a path string.
   338   //
   339   return Rename (oldpath.substr (0, i), oldpath.substr (i + 1), newname);
   340 }
   341 
   342 bool
   343 NamesPriv::Rename (std::string path, std::string oldname, std::string newname)
   344 {
   345   if (path == "/Names")
   346     {
   347       return Rename (Ptr<Object> (0, false), oldname, newname);
   348     }
   349   return Rename (Find (path), oldname, newname);
   350 }
   351 
   352 bool
   353 NamesPriv::Rename (Ptr<Object> context, std::string oldname, std::string newname)
   354 {
   355   NS_LOG_FUNCTION (context << oldname << newname);
   356 
   357   NameNode *node = 0;
   358   if (context)
   359     {
   360       node = IsNamed (context);
   361       NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
   362     }
   363   else
   364     {
   365       node = &m_root;
   366     }
   367 
   368   if (IsDuplicateName (node, newname))
   369     {
   370       NS_LOG_LOGIC ("New name is already taken");
   371       return false;
   372     }
   373 
   374   std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (oldname);
   375   if (i == node->m_nameMap.end ())
   376     {
   377       NS_LOG_LOGIC ("Old name does not exist in name map");
   378       return false;
   379     }
   380   else
   381     {
   382       NS_LOG_LOGIC ("Old name exists in name map");
   383 
   384       //
   385       // The rename process consists of:
   386       // 1.  Geting the pointer to the name node from the map and remembering it;
   387       // 2.  Removing the map entry corresponding to oldname from the map;
   388       // 3.  Changing the name string in the name node;
   389       // 4.  Adding the name node back in the map under the newname.
   390       //
   391       NameNode *changeNode = i->second;
   392       node->m_nameMap.erase (i);
   393       changeNode->m_name = newname;
   394       node->m_nameMap[newname] = changeNode;
   395       return true;
   396     }
   397 }
   398 
   399 std::string
   400 NamesPriv::FindName (Ptr<Object> object)
   401 {
   402   NS_LOG_FUNCTION (object);
   403 
   404   std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
   405   if (i == m_objectMap.end ())
   406     {
   407       NS_LOG_LOGIC ("Object does not exist in object map");
   408       return "";
   409     }
   410   else
   411     {
   412       NS_LOG_LOGIC ("Object exists in object map");
   413       return i->second->m_name;
   414     }
   415 }
   416 
   417 std::string
   418 NamesPriv::FindPath (Ptr<Object> object)
   419 {
   420   NS_LOG_FUNCTION (object);
   421 
   422   std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
   423   if (i == m_objectMap.end ())
   424     {
   425       NS_LOG_LOGIC ("Object does not exist in object map");
   426       return "";
   427     }
   428 
   429   NameNode *p = i->second;
   430   NS_ASSERT_MSG (p, "NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map");
   431 
   432   std::string path;
   433 
   434   do
   435     {
   436       path = "/" + p->m_name + path;
   437       NS_LOG_LOGIC ("path is " << path);
   438     }
   439   while ((p = p->m_parent) != 0);
   440 
   441   return path;
   442 }
   443 
   444 
   445 Ptr<Object>
   446 NamesPriv::Find (std::string path)
   447 {
   448   //
   449   // This is hooked in from simple, easy to use version of Find, so we want it
   450   // to be flexible.
   451   //
   452   // If we are provided a path that doesn't begin with "/Names", we assume 
   453   // that the caller has simply given us a path starting with a name that
   454   // is in the root namespace.  This allows peole to omit the "/Names" prefix.
   455   // and simply do a Find ("Client/eth0") instead of having to always do a
   456   // Find ("/Names/Client/eth0");
   457   //
   458   // So, if we are given a name that begins with "/Names/" the upshot is that we
   459   // just remove that prefix and treat the rest of the string as starting with a 
   460   // name in the root namespace.
   461   //
   462   std::string namespaceName = "/Names/";
   463   std::string remaining;
   464 
   465   std::string::size_type offset = path.find (namespaceName);
   466   if (offset == 0)
   467     {
   468       NS_LOG_LOGIC (path << " is a fully qualified name");
   469       remaining = path.substr (namespaceName.size ());
   470     }
   471   else
   472     {
   473       NS_LOG_LOGIC (path << " begins with a relative name");
   474       remaining = path;
   475     }
   476 
   477   NameNode *node = &m_root;
   478 
   479   //
   480   // The string <remaining> is now composed entirely of path segments in the
   481   // /Names name space and we have eaten the leading slash. e.g., 
   482   // remaining = "ClientNode/eth0"
   483   //
   484   // The start of the search is always at the root of the name space.
   485   //
   486   for (;;)
   487     {
   488       NS_LOG_LOGIC ("Looking for the object of name " << remaining);
   489       offset = remaining.find ("/");
   490       if (offset == std::string::npos)
   491         {
   492           //
   493           // There are no remaining slashes so this is the last segment of the 
   494           // specified name.  We're done when we find it
   495           //
   496           std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (remaining);
   497           if (i == node->m_nameMap.end ())
   498             {
   499               NS_LOG_LOGIC ("Name does not exist in name map");
   500               return 0;
   501             }
   502           else
   503             {
   504               NS_LOG_LOGIC ("Name parsed, found object");
   505               return i->second->m_object;
   506             }
   507         }
   508       else
   509         {
   510           //
   511           // There are more slashes so this is an intermediate segment of the 
   512           // specified name.  We need to "recurse" when we find this segment.
   513           //
   514           offset = remaining.find ("/");
   515           std::string segment = remaining.substr(0, offset);
   516 
   517           std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (segment);
   518           if (i == node->m_nameMap.end ())
   519             {
   520               NS_LOG_LOGIC ("Name does not exist in name map");
   521               return 0;
   522             }
   523           else
   524             {
   525               node = i->second;
   526               remaining = remaining.substr (offset + 1);
   527               NS_LOG_LOGIC ("Intermediate segment parsed");
   528               continue;
   529             }
   530         }
   531     }
   532 
   533   NS_ASSERT_MSG (node, "NamesPriv::Find(): Internal error:  this can't happen");
   534   return 0;
   535 }
   536 
   537 Ptr<Object>
   538 NamesPriv::Find (std::string path, std::string name)
   539 {
   540   NS_LOG_FUNCTION (path << name);
   541 
   542   if (path == "/Names")
   543     {
   544       return Find (Ptr<Object> (0, false), name);
   545     }
   546   return Find (Find (path), name);
   547 }
   548 
   549 Ptr<Object>
   550 NamesPriv::Find (Ptr<Object> context, std::string name)
   551 {
   552   NS_LOG_FUNCTION (context << name);
   553 
   554   NameNode *node = 0;
   555 
   556   if (context == 0)
   557     {
   558       NS_LOG_LOGIC ("Zero context implies root NameNode");
   559       node = &m_root;
   560     }
   561   else
   562     {
   563       node = IsNamed (context);
   564       if (node == 0)
   565         {
   566           NS_LOG_LOGIC ("Context does not point to a previously named node");
   567           return 0;
   568         }
   569     }
   570 
   571   std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
   572   if (i == node->m_nameMap.end ())
   573     {
   574       NS_LOG_LOGIC ("Name does not exist in name map");
   575       return 0;
   576     }
   577   else
   578     {
   579       NS_LOG_LOGIC ("Name exists in name map");
   580       return i->second->m_object;
   581     }
   582 }
   583 
   584 NameNode *
   585 NamesPriv::IsNamed (Ptr<Object> object)
   586 {
   587   NS_LOG_FUNCTION (object);
   588 
   589   std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
   590   if (i == m_objectMap.end ())
   591     {
   592       NS_LOG_LOGIC ("Object does not exist in object map, returning NameNode 0");
   593       return 0;
   594     }
   595   else
   596     {
   597       NS_LOG_LOGIC ("Object exists in object map, returning NameNode " << &i->second);
   598       return i->second;
   599     }
   600 }
   601 
   602 bool
   603 NamesPriv::IsDuplicateName (NameNode *node, std::string name)
   604 {
   605   NS_LOG_FUNCTION (node << name);
   606 
   607   std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
   608   if (i == node->m_nameMap.end ())
   609     {
   610       NS_LOG_LOGIC ("Name does not exist in name map");
   611       return false;
   612     }
   613   else
   614     {
   615       NS_LOG_LOGIC ("Name exists in name map");
   616       return true;
   617     }
   618 }
   619 
   620 void
   621 Names::Delete (void)
   622 {
   623   NamesPriv::Delete ();
   624 }
   625 
   626 void
   627 Names::Add (std::string name, Ptr<Object> object)
   628 {
   629   bool result = NamesPriv::Get ()->Add (name, object);
   630   NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name);
   631 }
   632 
   633 void
   634 Names::Rename (std::string oldpath, std::string newname)
   635 {
   636   bool result = NamesPriv::Get ()->Rename (oldpath, newname);
   637   NS_ABORT_MSG_UNLESS (result, "Names::Rename(): Error renaming " << oldpath << " to " << newname);
   638 }
   639 
   640 void
   641 Names::Add (std::string path, std::string name, Ptr<Object> object)
   642 {
   643   bool result = NamesPriv::Get ()->Add (path, name, object);
   644   NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding " << path << " " << name);
   645 }
   646 
   647 void
   648 Names::Rename (std::string path, std::string oldname, std::string newname)
   649 {
   650   bool result = NamesPriv::Get ()->Rename (path, oldname, newname);
   651   NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << path << " " << oldname << " to " << newname);
   652 }
   653 
   654 void
   655 Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
   656 {
   657   bool result = NamesPriv::Get ()->Add (context, name, object);
   658   NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name << " under context " << &context);
   659 }
   660 
   661 void
   662 Names::Rename (Ptr<Object> context, std::string oldname, std::string newname)
   663 {
   664   bool result = NamesPriv::Get ()->Rename (context, oldname, newname);
   665   NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << oldname << " to " << newname << " under context " <<
   666                        &context);
   667 }
   668 
   669 std::string
   670 Names::FindName (Ptr<Object> object)
   671 {
   672   return NamesPriv::Get ()->FindName (object);
   673 }
   674 
   675 std::string
   676 Names::FindPath (Ptr<Object> object)
   677 {
   678   return NamesPriv::Get ()->FindPath (object);
   679 }
   680 
   681 Ptr<Object>
   682 Names::FindInternal (std::string name)
   683 {
   684   return NamesPriv::Get ()->Find (name);
   685 }
   686 
   687 Ptr<Object>
   688 Names::FindInternal (std::string path, std::string name)
   689 {
   690   return NamesPriv::Get ()->Find (path, name);
   691 }
   692 
   693 Ptr<Object>
   694 Names::FindInternal (Ptr<Object> context, std::string name)
   695 {
   696   return NamesPriv::Get ()->Find (context, name);
   697 }
   698 
   699 } //namespace ns3
   700 
   701 #ifdef RUN_SELF_TESTS
   702 
   703 #include "test.h"
   704 #include "object-factory.h"
   705 
   706 namespace ns3 {
   707 
   708 class TestObject : public Object
   709 {
   710 public:
   711   static TypeId GetTypeId (void) 
   712   {
   713     static TypeId tid = TypeId ("TestObject")
   714       .SetParent (Object::GetTypeId ())
   715       .HideFromDocumentation ()
   716       .AddConstructor<TestObject> ();
   717     return tid;
   718   }
   719   TestObject () {}
   720   virtual void Dispose (void) {}
   721 };
   722 
   723 class NamesTest : public Test
   724 {
   725 public:
   726   NamesTest ();
   727   virtual bool RunTests (void);
   728 };
   729 
   730 NamesTest::NamesTest ()
   731   : Test ("Names")
   732 {
   733 }
   734 
   735 bool 
   736 NamesTest::RunTests (void)
   737 {
   738   bool result = true;
   739 
   740   //
   741   // Names::Add and Names::Rename return void to align with the Config API.
   742   // The private versions of these functions do return error codes so we
   743   // can test to make sure errors are detected.  Names::Add and 
   744   // Names::Rename check for these error codes and abort if an error was
   745   // detected.  So when we expect that an error should be detected, we 
   746   // have to call the private routine to avoid a fatal error popping.
   747   // 
   748   // Name a couple of objects at the root level
   749   //
   750   Ptr<TestObject> client = CreateObject<TestObject> ();
   751   Names::Add ("Client", client);
   752 
   753   Ptr<TestObject> server = CreateObject<TestObject> ();
   754   Names::Add ("Server", server);
   755 
   756   //
   757   // We shouldn't be able to add another name to a previously named object
   758   //
   759   result = NamesPriv::Get ()->Add ("Not Client", client);
   760   NS_TEST_ASSERT_EQUAL (result, false);
   761 
   762   //
   763   // We shouldn't be able to duplicate a name at the root level.
   764   //
   765   Ptr<TestObject> secondClient = CreateObject<TestObject> ();
   766   result = NamesPriv::Get ()->Add ("Client", secondClient);
   767   NS_TEST_ASSERT_EQUAL (result, false);
   768 
   769   //
   770   // We should be able to add a new name in the first object's context
   771   //
   772   Ptr<TestObject> clientEth0 = CreateObject<TestObject> ();
   773   Names::Add (client, "eth0", clientEth0);
   774 
   775   //
   776   // We shouldn't be able to duplicate a name in that context.
   777   //
   778   Ptr<TestObject> secondClientEth0 = CreateObject<TestObject> ();
   779   result = NamesPriv::Get ()->Add (client, "eth0", secondClientEth0);
   780   NS_TEST_ASSERT_EQUAL (result, false);
   781 
   782   //
   783   // We should be able to add the same name in the second object's context
   784   //
   785   Ptr<TestObject> serverEth0 = CreateObject<TestObject> ();
   786   Names::Add (server, "eth0", serverEth0);
   787 
   788   //
   789   // We should be able to find the short names for the objects we created
   790   //
   791   std::string found;
   792 
   793   found = Names::FindName (client);
   794   NS_TEST_ASSERT_EQUAL (found, "Client");
   795 
   796   found = Names::FindName (server);
   797   NS_TEST_ASSERT_EQUAL (found, "Server");
   798 
   799   found = Names::FindName (clientEth0);
   800   NS_TEST_ASSERT_EQUAL (found, "eth0");
   801 
   802   found = Names::FindName (serverEth0);
   803   NS_TEST_ASSERT_EQUAL (found, "eth0");
   804 
   805   //
   806   // We should be able to find the full names for the objects we created
   807   //
   808   found = Names::FindPath (client);
   809   NS_TEST_ASSERT_EQUAL (found, "/Names/Client");
   810 
   811   found = Names::FindPath (server);
   812   NS_TEST_ASSERT_EQUAL (found, "/Names/Server");
   813 
   814   found = Names::FindPath (clientEth0);
   815   NS_TEST_ASSERT_EQUAL (found, "/Names/Client/eth0");
   816 
   817   found = Names::FindPath (serverEth0);
   818   NS_TEST_ASSERT_EQUAL (found, "/Names/Server/eth0");
   819 
   820   // 
   821   // We should be able to find the objects from a context and name combination.
   822   // Note that the Ptr<Object> (0, false) below is to differentiate a null object
   823   // pointer from a null string pointer -- not normally needed in real use-cases.
   824   // 
   825   //
   826   Ptr<TestObject> foundObject;
   827 
   828   foundObject = Names::Find<TestObject> (Ptr<Object> (0, false), "Client");
   829   NS_TEST_ASSERT_EQUAL (foundObject, client);
   830 
   831   foundObject = Names::Find<TestObject> (Ptr<Object> (0, false), "Server");
   832   NS_TEST_ASSERT_EQUAL (foundObject, server);
   833 
   834   foundObject = Names::Find<TestObject> (client, "eth0");
   835   NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
   836 
   837   foundObject = Names::Find<TestObject> (server, "eth0");
   838   NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
   839 
   840   //
   841   // We should be able to do the same thing by providing path strings instead
   842   // of context objects.
   843   //
   844 
   845   foundObject = Names::Find<TestObject> ("/Names", "Client");
   846   NS_TEST_ASSERT_EQUAL (foundObject, client);
   847 
   848   foundObject = Names::Find<TestObject> ("/Names", "Server");
   849   NS_TEST_ASSERT_EQUAL (foundObject, server);
   850 
   851   foundObject = Names::Find<TestObject> ("/Names/Client", "eth0");
   852   NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
   853 
   854   foundObject = Names::Find<TestObject> ("/Names/Server", "eth0");
   855   NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
   856 
   857   // 
   858   // We should be able to find the objects from their full path names
   859   //
   860   foundObject = Names::Find<TestObject> ("/Names/Client");
   861   NS_TEST_ASSERT_EQUAL (foundObject, client);
   862 
   863   foundObject = Names::Find<TestObject> ("/Names/Server");
   864   NS_TEST_ASSERT_EQUAL (foundObject, server);
   865 
   866   foundObject = Names::Find<TestObject> ("/Names/Client/eth0");
   867   NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
   868 
   869   foundObject = Names::Find<TestObject> ("/Names/Server/eth0");
   870   NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
   871 
   872   // 
   873   // We should be able to omit the root of the namespace from the full path names
   874   //
   875   foundObject = Names::Find<TestObject> ("Client");
   876   NS_TEST_ASSERT_EQUAL (foundObject, client);
   877 
   878   foundObject = Names::Find<TestObject> ("Server");
   879   NS_TEST_ASSERT_EQUAL (foundObject, server);
   880 
   881   foundObject = Names::Find<TestObject> ("Client/eth0");
   882   NS_TEST_ASSERT_EQUAL (foundObject, clientEth0);
   883 
   884   foundObject = Names::Find<TestObject> ("Server/eth0");
   885   NS_TEST_ASSERT_EQUAL (foundObject, serverEth0);
   886 
   887   //
   888   // We should be able to add objects while including the root of the namespace
   889   // in the name.
   890   //
   891   Ptr<TestObject> router1 = CreateObject<TestObject> ();
   892   Names::Add ("/Names/Router1", router1);
   893 
   894   //
   895   // We should be able to add objects while not including the root of the namespace
   896   // in the name.
   897   //
   898   Ptr<TestObject> router2 = CreateObject<TestObject> ();
   899   Names::Add ("Router2", router2);
   900 
   901   //
   902   // We should be able to add sub-objects while including the root of the namespace
   903   // in the name.
   904   //
   905   Ptr<TestObject> router1Eth0 = CreateObject<TestObject> ();
   906   Names::Add ("/Names/Router1/eth0", router1Eth0);
   907 
   908   //
   909   // We should be able to add sub-objects while not including the root of the namespace
   910   // in the name.
   911   //
   912   Ptr<TestObject> router2Eth0 = CreateObject<TestObject> ();
   913   Names::Add ("Router2/eth0", router2Eth0);
   914 
   915   //
   916   // We should be able to find these objects in the same two ways
   917   //
   918   foundObject = Names::Find<TestObject> ("/Names/Router1");
   919   NS_TEST_ASSERT_EQUAL (foundObject, router1);
   920 
   921   foundObject = Names::Find<TestObject> ("Router1");
   922   NS_TEST_ASSERT_EQUAL (foundObject, router1);
   923 
   924   foundObject = Names::Find<TestObject> ("/Names/Router2");
   925   NS_TEST_ASSERT_EQUAL (foundObject, router2);
   926 
   927   foundObject = Names::Find<TestObject> ("Router2");
   928   NS_TEST_ASSERT_EQUAL (foundObject, router2);
   929 
   930   foundObject = Names::Find<TestObject> ("/Names/Router1/eth0");
   931   NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
   932 
   933   foundObject = Names::Find<TestObject> ("Router1/eth0");
   934   NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
   935 
   936   foundObject = Names::Find<TestObject> ("/Names/Router2/eth0");
   937   NS_TEST_ASSERT_EQUAL (foundObject, router2Eth0);
   938 
   939   foundObject = Names::Find<TestObject> ("Router2/eth0");
   940   NS_TEST_ASSERT_EQUAL (foundObject, router2Eth0);
   941 
   942   //
   943   // We have a pile of names defined.  We should be able to rename them in the
   944   // usual ways.
   945   //
   946   Names::Rename ("/Names/Router1", "RouterX");
   947 
   948   foundObject = Names::Find<TestObject> ("/Names/RouterX");
   949   NS_TEST_ASSERT_EQUAL (foundObject, router1);
   950 
   951   Names::Rename ("Router2", "RouterY");
   952 
   953   foundObject = Names::Find<TestObject> ("RouterY");
   954   NS_TEST_ASSERT_EQUAL (foundObject, router2);
   955 
   956   Names::Rename ("/Names/RouterX/eth0", "ath0");
   957 
   958   foundObject = Names::Find<TestObject> ("/Names/RouterX/ath0");
   959   NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
   960 
   961   foundObject = Names::Find<TestObject> ("RouterX/ath0");
   962   NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0);
   963 
   964   //
   965   // We should not be able to rename an object into conflict with another
   966   // object.
   967   //
   968 
   969   result = NamesPriv::Get ()->Rename ("/Names/RouterX", "RouterY");
   970   NS_TEST_ASSERT_EQUAL (result, false);
   971 
   972   Names::Delete ();
   973   return true;
   974 }
   975 
   976 static NamesTest g_namesTests;
   977 
   978 } // namespace ns3
   979 
   980 #endif /* RUN_SELF_TESTS */