A Discrete-Event Network Simulator
API
names.cc
Go to the documentation of this file.
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 "singleton.h"
26 
33 namespace ns3 {
34 
35 NS_LOG_COMPONENT_DEFINE ("Names");
36 
41 class NameNode
42 {
43 public:
45  NameNode ();
51  NameNode (const NameNode &nameNode);
59  NameNode (NameNode *parent, std::string name, Ptr<Object> object);
66  NameNode &operator = (const NameNode &rhs);
67 
69  ~NameNode ();
70 
74  std::string m_name;
77 
79  std::map<std::string, NameNode *> m_nameMap;
80 };
81 
83  : m_parent (0), m_name (""), m_object (0)
84 {
85 }
86 
87 NameNode::NameNode (const NameNode &nameNode)
88 {
89  m_parent = nameNode.m_parent;
90  m_name = nameNode.m_name;
91  m_object = nameNode.m_object;
92  m_nameMap = nameNode.m_nameMap;
93 }
94 
95 NameNode &
97 {
98  m_parent = rhs.m_parent;
99  m_name = rhs.m_name;
100  m_object = rhs.m_object;
101  m_nameMap = rhs.m_nameMap;
102  return *this;
103 }
104 
105 NameNode::NameNode (NameNode *parent, std::string name, Ptr<Object> object)
106  : m_parent (parent), m_name (name), m_object (object)
107 {
108  NS_LOG_FUNCTION (this << parent << name << object);
109 }
110 
112 {
113  NS_LOG_FUNCTION (this);
114 }
115 
120 class NamesPriv : public Singleton<NamesPriv>
121 {
122 public:
124  NamesPriv ();
126  ~NamesPriv ();
127 
128  // Doxygen \copydoc bug: won't copy these docs, so we repeat them.
129 
138  bool Add (std::string name, Ptr<Object> object);
148  bool Add (std::string path, std::string name, Ptr<Object> object);
159  bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
160 
169  bool Rename (std::string oldpath, std::string newname);
181  bool Rename (std::string path, std::string oldname, std::string newname);
195  bool Rename (Ptr<Object> context, std::string oldname, std::string newname);
196 
205  std::string FindName (Ptr<Object> object);
214  std::string FindPath (Ptr<Object> object);
215 
219  void Clear (void);
220 
229  Ptr<Object> Find (std::string path);
239  Ptr<Object> Find (std::string path, std::string name);
250  Ptr<Object> Find (Ptr<Object> context, std::string name);
251 
252 private:
253  friend class Names;
254 
261  NameNode *IsNamed (Ptr<Object> object);
269  bool IsDuplicateName (NameNode *node, std::string name);
270 
273 
275  std::map<Ptr<Object>, NameNode *> m_objectMap;
276 };
277 
279 {
280  NS_LOG_FUNCTION (this);
281 
282  m_root.m_parent = 0;
283  m_root.m_name = "Names";
284  m_root.m_object = 0;
285 }
286 
288 {
289  NS_LOG_FUNCTION (this);
290  Clear ();
291  m_root.m_name = "";
292 }
293 
294 void
296 {
297  NS_LOG_FUNCTION (this);
298  //
299  // Every name is associated with an object in the object map, so freeing the
300  // NameNodes in this map will free all of the memory allocated for the NameNodes
301  //
302  for (std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.begin (); i != m_objectMap.end (); ++i)
303  {
304  delete i->second;
305  i->second = 0;
306  }
307 
308  m_objectMap.clear ();
309 
310  m_root.m_parent = 0;
311  m_root.m_name = "Names";
312  m_root.m_object = 0;
313  m_root.m_nameMap.clear ();
314 }
315 
316 bool
317 NamesPriv::Add (std::string name, Ptr<Object> object)
318 {
319  NS_LOG_FUNCTION (this << name << object);
320  //
321  // This is the simple, easy to use version of Add, so we want it to be flexible.
322  // We don't want to force a user to always type the fully qualified namespace
323  // name, so we allow the namespace name to be omitted. For example, calling
324  // Add ("Client/ath0", obj) should result in exactly the same behavior as
325  // Add ("/Names/Client/ath0", obj). Calling Add ("Client", obj) should have
326  // the same effect as Add ("Names/Client", obj)
327  //
328  // The first thing to do, then, is to "canonicalize" the input string to always
329  // be a fully qualified name.
330  //
331  // If we are given a name that begins with "/Names/" we assume that this is a
332  // fully qualified path name to the object we want to create. We split the name
333  // into a path string and a final segment (name) and then call the "Real" Add.
334  //
335  std::string namespaceName = "/Names";
336  std::string::size_type offset = name.find (namespaceName);
337  if (offset != 0)
338  {
339  //
340  // This must be a name that has the "/Names" namespace prefix omitted.
341  // Do some reasonableness checking on the rest of the name.
342  //
343  offset = name.find ("/");
344  if (offset == 0)
345  {
346  NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
347  return false;
348  }
349 
350  name = "/Names/" + name;
351  }
352 
353  //
354  // There must now be a fully qualified path in the string. All fully
355  // qualified names begin with "/Names". We have to split off the final
356  // segment which will become the name of the object. A '/' that
357  // separates the path from the final segment had better be there since
358  // we just made sure that at least the namespace name was there.
359  //
360  std::string::size_type i = name.rfind ("/");
361  NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error. Can't find '/' in name");
362 
363  //
364  // The slash we found cannot be the slash at the start of the namespaceName.
365  // This would indicate there is no name in the path at all. It can be
366  // any other index.
367  //
368  NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a name in the path string");
369 
370  //
371  // We now know where the path string starts and ends, and where the
372  // name starts and ends. All we have to do is to call our available
373  // function for adding a name under a path string.
374  //
375  return Add (name.substr (0, i), name.substr (i + 1), object);
376 }
377 
378 bool
379 NamesPriv::Add (std::string path, std::string name, Ptr<Object> object)
380 {
381  NS_LOG_FUNCTION (this << path << name << object);
382  if (path == "/Names")
383  {
384  return Add (Ptr<Object> (0, false), name, object);
385  }
386  return Add (Find (path), name, object);
387 }
388 
389 bool
390 NamesPriv::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
391 {
392  NS_LOG_FUNCTION (this << context << name << object);
393 
394  if (IsNamed (object))
395  {
396  NS_LOG_LOGIC ("Object is already named");
397  return false;
398  }
399 
400  NameNode *node = 0;
401  if (context)
402  {
403  node = IsNamed (context);
404  NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
405  }
406  else
407  {
408  node = &m_root;
409  }
410 
411  if (IsDuplicateName (node, name))
412  {
413  NS_LOG_LOGIC ("Name is already taken");
414  return false;
415  }
416 
417  NameNode *newNode = new NameNode (node, name, object);
418  node->m_nameMap[name] = newNode;
419  m_objectMap[object] = newNode;
420 
421  return true;
422 }
423 
424 bool
425 NamesPriv::Rename (std::string oldpath, std::string newname)
426 {
427  NS_LOG_FUNCTION (this << oldpath << newname);
428  //
429  // This is the simple, easy to use version of Rename, so we want it to be
430  // flexible. We don't want to force a user to always type the fully
431  // qualified namespace name, so we allow the namespace name to be omitted.
432  // For example, calling Rename ("Client/ath0", "eth0") should result in
433  // exactly the same behavior as Rename ("/Names/Client/ath0", "eth0").
434  // Calling Rename ("Client", "Router") should have the same effect as
435  // Rename ("Names/Client", "Router")
436  //
437  // The first thing to do, then, is to "canonicalize" the input string to always
438  // be a fully qualified path.
439  //
440  // If we are given a name that begins with "/Names/" we assume that this is a
441  // fully qualified path to the object we want to change. We split the path into
442  // path string (cf directory) and a final segment (cf filename) and then call
443  // the "Real" Rename.
444  //
445  std::string namespaceName = "/Names";
446  std::string::size_type offset = oldpath.find (namespaceName);
447  if (offset != 0)
448  {
449  //
450  // This must be a name that has the "/Names" namespace prefix omitted.
451  // Do some reasonableness checking on the rest of the name.
452  //
453  offset = oldpath.find ("/");
454  if (offset == 0)
455  {
456  NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
457  return false;
458  }
459 
460  oldpath = "/Names/" + oldpath;
461  }
462 
463  //
464  // There must now be a fully qualified path in the oldpath string. All
465  // fully qualified names begin with "/Names". We have to split off the final
466  // segment which will become the name we want to rename. A '/' that
467  // separates the path from the final segment (name) had better be there since
468  // we just made sure that at least the namespace name was there.
469  //
470  std::string::size_type i = oldpath.rfind ("/");
471  NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error. Can't find '/' in name");
472 
473  //
474  // The slash we found cannot be the slash at the start of the namespaceName.
475  // This would indicate there is no name in the path at all. It can be
476  // any other index.
477  //
478  NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a name in the path string");
479 
480  //
481  // We now know where the path part of the string starts and ends, and where the
482  // name part starts and ends. All we have to do is to call our available
483  // function for creating adding a name under a path string.
484  //
485  return Rename (oldpath.substr (0, i), oldpath.substr (i + 1), newname);
486 }
487 
488 bool
489 NamesPriv::Rename (std::string path, std::string oldname, std::string newname)
490 {
491  NS_LOG_FUNCTION (this << path << oldname << newname);
492  if (path == "/Names")
493  {
494  return Rename (Ptr<Object> (0, false), oldname, newname);
495  }
496  return Rename (Find (path), oldname, newname);
497 }
498 
499 bool
500 NamesPriv::Rename (Ptr<Object> context, std::string oldname, std::string newname)
501 {
502  NS_LOG_FUNCTION (this << context << oldname << newname);
503 
504  NameNode *node = 0;
505  if (context)
506  {
507  node = IsNamed (context);
508  NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
509  }
510  else
511  {
512  node = &m_root;
513  }
514 
515  if (IsDuplicateName (node, newname))
516  {
517  NS_LOG_LOGIC ("New name is already taken");
518  return false;
519  }
520 
521  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (oldname);
522  if (i == node->m_nameMap.end ())
523  {
524  NS_LOG_LOGIC ("Old name does not exist in name map");
525  return false;
526  }
527  else
528  {
529  NS_LOG_LOGIC ("Old name exists in name map");
530 
531  //
532  // The rename process consists of:
533  // 1. Getting the pointer to the name node from the map and remembering it;
534  // 2. Removing the map entry corresponding to oldname from the map;
535  // 3. Changing the name string in the name node;
536  // 4. Adding the name node back in the map under the newname.
537  //
538  NameNode *changeNode = i->second;
539  node->m_nameMap.erase (i);
540  changeNode->m_name = newname;
541  node->m_nameMap[newname] = changeNode;
542  return true;
543  }
544 }
545 
546 std::string
548 {
549  NS_LOG_FUNCTION (this << object);
550 
551  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
552  if (i == m_objectMap.end ())
553  {
554  NS_LOG_LOGIC ("Object does not exist in object map");
555  return "";
556  }
557  else
558  {
559  NS_LOG_LOGIC ("Object exists in object map");
560  return i->second->m_name;
561  }
562 }
563 
564 std::string
566 {
567  NS_LOG_FUNCTION (this << object);
568 
569  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
570  if (i == m_objectMap.end ())
571  {
572  NS_LOG_LOGIC ("Object does not exist in object map");
573  return "";
574  }
575 
576  NameNode *p = i->second;
577  NS_ASSERT_MSG (p, "NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map");
578 
579  std::string path;
580 
581  do
582  {
583  path = "/" + p->m_name + path;
584  NS_LOG_LOGIC ("path is " << path);
585  }
586  while ((p = p->m_parent) != 0);
587 
588  return path;
589 }
590 
591 
593 NamesPriv::Find (std::string path)
594 {
595  //
596  // This is hooked in from simple, easy to use version of Find, so we want it
597  // to be flexible.
598  //
599  // If we are provided a path that doesn't begin with "/Names", we assume
600  // that the caller has simply given us a path starting with a name that
601  // is in the root namespace. This allows people to omit the "/Names" prefix.
602  // and simply do a Find ("Client/eth0") instead of having to always do a
603  // Find ("/Names/Client/eth0");
604  //
605  // So, if we are given a name that begins with "/Names/" the upshot is that we
606  // just remove that prefix and treat the rest of the string as starting with a
607  // name in the root namespace.
608  //
609 
610  NS_LOG_FUNCTION (this << path);
611  std::string namespaceName = "/Names/";
612  std::string remaining;
613 
614  std::string::size_type offset = path.find (namespaceName);
615  if (offset == 0)
616  {
617  NS_LOG_LOGIC (path << " is a fully qualified name");
618  remaining = path.substr (namespaceName.size ());
619  }
620  else
621  {
622  NS_LOG_LOGIC (path << " begins with a relative name");
623  remaining = path;
624  }
625 
626  NameNode *node = &m_root;
627 
628  //
629  // The string <remaining> is now composed entirely of path segments in
630  // the /Names name space and we have eaten the leading slash. e.g.,
631  // remaining = "ClientNode/eth0"
632  //
633  // The start of the search is always at the root of the name space.
634  //
635  for (;;)
636  {
637  NS_LOG_LOGIC ("Looking for the object of name " << remaining);
638  offset = remaining.find ("/");
639  if (offset == std::string::npos)
640  {
641  //
642  // There are no remaining slashes so this is the last segment of the
643  // specified name. We're done when we find it
644  //
645  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (remaining);
646  if (i == node->m_nameMap.end ())
647  {
648  NS_LOG_LOGIC ("Name does not exist in name map");
649  return 0;
650  }
651  else
652  {
653  NS_LOG_LOGIC ("Name parsed, found object");
654  return i->second->m_object;
655  }
656  }
657  else
658  {
659  //
660  // There are more slashes so this is an intermediate segment of the
661  // specified name. We need to "recurse" when we find this segment.
662  //
663  offset = remaining.find ("/");
664  std::string segment = remaining.substr (0, offset);
665 
666  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (segment);
667  if (i == node->m_nameMap.end ())
668  {
669  NS_LOG_LOGIC ("Name does not exist in name map");
670  return 0;
671  }
672  else
673  {
674  node = i->second;
675  remaining = remaining.substr (offset + 1);
676  NS_LOG_LOGIC ("Intermediate segment parsed");
677  continue;
678  }
679  }
680  }
681 
682  NS_ASSERT_MSG (node, "NamesPriv::Find(): Internal error: this can't happen");
683  return 0;
684 }
685 
687 NamesPriv::Find (std::string path, std::string name)
688 {
689  NS_LOG_FUNCTION (this << path << name);
690 
691  if (path == "/Names")
692  {
693  return Find (Ptr<Object> (0, false), name);
694  }
695  return Find (Find (path), name);
696 }
697 
699 NamesPriv::Find (Ptr<Object> context, std::string name)
700 {
701  NS_LOG_FUNCTION (this << context << name);
702 
703  NameNode *node = 0;
704 
705  if (context == 0)
706  {
707  NS_LOG_LOGIC ("Zero context implies root NameNode");
708  node = &m_root;
709  }
710  else
711  {
712  node = IsNamed (context);
713  if (node == 0)
714  {
715  NS_LOG_LOGIC ("Context does not point to a previously named node");
716  return 0;
717  }
718  }
719 
720  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
721  if (i == node->m_nameMap.end ())
722  {
723  NS_LOG_LOGIC ("Name does not exist in name map");
724  return 0;
725  }
726  else
727  {
728  NS_LOG_LOGIC ("Name exists in name map");
729  return i->second->m_object;
730  }
731 }
732 
733 NameNode *
735 {
736  NS_LOG_FUNCTION (this << object);
737 
738  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
739  if (i == m_objectMap.end ())
740  {
741  NS_LOG_LOGIC ("Object does not exist in object map, returning NameNode 0");
742  return 0;
743  }
744  else
745  {
746  NS_LOG_LOGIC ("Object exists in object map, returning NameNode " << &i->second);
747  return i->second;
748  }
749 }
750 
751 bool
752 NamesPriv::IsDuplicateName (NameNode *node, std::string name)
753 {
754  NS_LOG_FUNCTION (this << node << name);
755 
756  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
757  if (i == node->m_nameMap.end ())
758  {
759  NS_LOG_LOGIC ("Name does not exist in name map");
760  return false;
761  }
762  else
763  {
764  NS_LOG_LOGIC ("Name exists in name map");
765  return true;
766  }
767 }
768 
769 void
770 Names::Add (std::string name, Ptr<Object> object)
771 {
772  NS_LOG_FUNCTION (name << object);
773  bool result = NamesPriv::Get ()->Add (name, object);
774  NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name);
775 }
776 
777 void
778 Names::Rename (std::string oldpath, std::string newname)
779 {
780  NS_LOG_FUNCTION (oldpath << newname);
781  bool result = NamesPriv::Get ()->Rename (oldpath, newname);
782  NS_ABORT_MSG_UNLESS (result, "Names::Rename(): Error renaming " << oldpath << " to " << newname);
783 }
784 
785 void
786 Names::Add (std::string path, std::string name, Ptr<Object> object)
787 {
788  NS_LOG_FUNCTION (path << name << object);
789  bool result = NamesPriv::Get ()->Add (path, name, object);
790  NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding " << path << " " << name);
791 }
792 
793 void
794 Names::Rename (std::string path, std::string oldname, std::string newname)
795 {
796  NS_LOG_FUNCTION (path << oldname << newname);
797  bool result = NamesPriv::Get ()->Rename (path, oldname, newname);
798  NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << path << " " << oldname << " to " << newname);
799 }
800 
801 void
802 Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
803 {
804  NS_LOG_FUNCTION (context << name << object);
805  bool result = NamesPriv::Get ()->Add (context, name, object);
806  NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name << " under context " << &context);
807 }
808 
809 void
810 Names::Rename (Ptr<Object> context, std::string oldname, std::string newname)
811 {
812  NS_LOG_FUNCTION (context << oldname << newname);
813  bool result = NamesPriv::Get ()->Rename (context, oldname, newname);
814  NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << oldname << " to " << newname << " under context " <<
815  &context);
816 }
817 
818 std::string
820 {
821  NS_LOG_FUNCTION (object);
822  return NamesPriv::Get ()->FindName (object);
823 }
824 
825 std::string
827 {
828  NS_LOG_FUNCTION (object);
829  return NamesPriv::Get ()->FindPath (object);
830 }
831 
832 void
834 {
836  return NamesPriv::Get ()->Clear ();
837 }
838 
840 Names::FindInternal (std::string name)
841 {
842  NS_LOG_FUNCTION (name);
843  return NamesPriv::Get ()->Find (name);
844 }
845 
847 Names::FindInternal (std::string path, std::string name)
848 {
849  NS_LOG_FUNCTION (path << name);
850  return NamesPriv::Get ()->Find (path, name);
851 }
852 
854 Names::FindInternal (Ptr<Object> context, std::string name)
855 {
856  NS_LOG_FUNCTION (context << name);
857  return NamesPriv::Get ()->Find (context, name);
858 }
859 
860 } // namespace ns3
Ptr< Object > m_object
The object corresponding to this NameNode.
Definition: names.cc:76
The singleton root Names object.
Definition: names.cc:120
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
ns3::Singleton declaration and template implementation.
std::map< std::string, NameNode * > m_nameMap
Children of this NameNode.
Definition: names.cc:79
Node in the naming tree.
Definition: names.cc:41
NameNode * IsNamed(Ptr< Object > object)
Check if an object has a name.
Definition: names.cc:734
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
~NameNode()
Destructor.
Definition: names.cc:111
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
NameNode * m_parent
The parent NameNode.
Definition: names.cc:72
static NamesPriv * Get(void)
Get a pointer to the singleton instance.
Ptr< Object > Find(std::string path)
Internal implementation for ns3::Names::Find(std::string)
Definition: names.cc:593
~NamesPriv()
Destructor.
Definition: names.cc:287
static void Add(std::string name, Ptr< Object > object)
Add the association between the string "name" and the Ptr<Object> obj.
Definition: names.cc:770
A template singleton.
Definition: singleton.h:63
A directory of name and Ptr<Object> associations that allows us to give any ns3 Object a name...
Definition: names.h:38
NS_ASSERT_MSG(false,"Ipv4AddressGenerator::MaskToIndex(): Impossible")
static void Clear(void)
Clear the list of objects associated with names.
Definition: names.cc:833
bool Rename(std::string oldpath, std::string newname)
Internal implementation for Names::Rename(std::string,std::string)
Definition: names.cc:425
std::string FindPath(Ptr< Object > object)
Internal implementation of Names::FindPath()
Definition: names.cc:565
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
std::string m_name
The name of this NameNode.
Definition: names.cc:74
void Clear(void)
Internal implementation for Names::Clear()
Definition: names.cc:295
std::string FindName(Ptr< Object > object)
Internal implementation for Names::FindName()
Definition: names.cc:547
Every class exported by the ns3 library is enclosed in the ns3 namespace.
NameNode & operator=(const NameNode &rhs)
Assignment operator.
Definition: names.cc:96
static std::string FindPath(Ptr< Object > object)
Given a pointer to an object, look to see if that object has a name associated with it and return the...
Definition: names.cc:826
NS_LOG_LOGIC("Net device "<< nd<< " is not bridged")
static void Rename(std::string oldpath, std::string newname)
Rename a previously associated name.
ns3::Object class declaration, which is the root of the Object hierarchy and Aggregation.
#define NS_ABORT_MSG_UNLESS(cond, msg)
Abnormal program termination if a condition is false, with a message.
Definition: abort.h:144
std::map< Ptr< Object >, NameNode * > m_objectMap
Map from object pointers to their NameNodes.
Definition: names.cc:275
NameNode m_root
The root NameNode.
Definition: names.cc:272
NameNode()
Default constructor.
Definition: names.cc:82
static std::string FindName(Ptr< Object > object)
Given a pointer to an object, look to see if that object has a name associated with it and...
Definition: names.cc:819
Declaration of class ns3::Names.
bool Add(std::string name, Ptr< Object > object)
Internal implementation for Names::Add(std::string,Ptr<Object>)
Definition: names.cc:317
Debug message logging.
NamesPriv()
Constructor.
Definition: names.cc:278
static Ptr< Object > FindInternal(std::string path)
Non-templated internal version of Names::Find.
Definition: names.cc:840
bool IsDuplicateName(NameNode *node, std::string name)
Check if a name already exists as a child of a NameNode.
Definition: names.cc:752
NS_ABORT_x macro definitions.