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