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 
33 namespace ns3 {
34 
35 NS_LOG_COMPONENT_DEFINE ("Names");
36 
37 class NameNode
38 {
39 public:
40  NameNode ();
41  NameNode (const NameNode &nameNode);
42  NameNode (NameNode *parent, std::string name, Ptr<Object> object);
43  NameNode &operator = (const NameNode &rhs);
44 
45  ~NameNode ();
46 
48  std::string m_name;
50 
51  std::map<std::string, NameNode *> m_nameMap;
52 };
53 
55  : m_parent (0), m_name (""), m_object (0)
56 {
57 }
58 
59 NameNode::NameNode (const NameNode &nameNode)
60 {
61  m_parent = nameNode.m_parent;
62  m_name = nameNode.m_name;
63  m_object = nameNode.m_object;
64  m_nameMap = nameNode.m_nameMap;
65 }
66 
67 NameNode &
69 {
70  m_parent = rhs.m_parent;
71  m_name = rhs.m_name;
72  m_object = rhs.m_object;
73  m_nameMap = rhs.m_nameMap;
74  return *this;
75 }
76 
77 NameNode::NameNode (NameNode *parent, std::string name, Ptr<Object> object)
78  : m_parent (parent), m_name (name), m_object (object)
79 {
80  NS_LOG_FUNCTION (this << parent << name << object);
81 }
82 
84 {
85  NS_LOG_FUNCTION (this);
86 }
87 
88 class NamesPriv
89 {
90 public:
91  NamesPriv ();
92  ~NamesPriv ();
93 
94  bool Add (std::string name, Ptr<Object> object);
95  bool Add (std::string path, std::string name, Ptr<Object> object);
96  bool Add (Ptr<Object> context, std::string name, Ptr<Object> object);
97 
98  bool Rename (std::string oldpath, std::string newname);
99  bool Rename (std::string path, std::string oldname, std::string newname);
100  bool Rename (Ptr<Object> context, std::string oldname, std::string newname);
101 
102  std::string FindName (Ptr<Object> object);
103  std::string FindPath (Ptr<Object> object);
104 
105  void Clear (void);
106 
107  Ptr<Object> Find (std::string name);
108  Ptr<Object> Find (std::string path, std::string name);
109  Ptr<Object> Find (Ptr<Object> context, std::string name);
110 
111 private:
112  friend class Names;
113  static NamesPriv *Get (void);
114 
116  bool IsDuplicateName (NameNode *node, std::string name);
117 
119  std::map<Ptr<Object>, NameNode *> m_objectMap;
120 };
121 
122 NamesPriv *
124 {
126  static NamesPriv namesPriv;
127  return &namesPriv;
128 }
129 
131 {
132  NS_LOG_FUNCTION (this);
133 
134  m_root.m_parent = 0;
135  m_root.m_name = "Names";
136  m_root.m_object = 0;
137 }
138 
140 {
141  NS_LOG_FUNCTION (this);
142  Clear ();
143  m_root.m_name = "";
144 }
145 
146 void
148 {
149  NS_LOG_FUNCTION (this);
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  m_objectMap.clear ();
161 
162  m_root.m_parent = 0;
163  m_root.m_name = "Names";
164  m_root.m_object = 0;
165  m_root.m_nameMap.clear ();
166 }
167 
168 bool
169 NamesPriv::Add (std::string name, Ptr<Object> object)
170 {
171  NS_LOG_FUNCTION (this << name << object);
172  //
173  // This is the simple, easy to use version of Add, so we want it to be flexible.
174  // We don't want to force a user to always type the fully qualified namespace
175  // name, so we allow the namespace name to be omitted. For example, calling
176  // Add ("Client/ath0", obj) should result in exactly the same behavior as
177  // Add ("/Names/Client/ath0", obj). Calling Add ("Client", obj) should have
178  // the same effect as Add ("Names/Client", obj)
179  //
180  // The first thing to do, then, is to "canonicalize" the input string to always
181  // be a fully qualified name.
182  //
183  // If we are given a name that begins with "/Names/" we assume that this is a
184  // fully qualified path name to the object we want to create. We split the name
185  // into a path string and and a final segment (name) and then call the "Real" Add.
186  //
187  std::string namespaceName = "/Names";
188  std::string::size_type offset = name.find (namespaceName);
189  if (offset != 0)
190  {
191  //
192  // This must be a name that has the "/Names" namespace prefix omitted.
193  // Do some reasonableness checking on the rest of the name.
194  //
195  offset = name.find ("/");
196  if (offset == 0)
197  {
198  NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
199  return false;
200  }
201 
202  name = "/Names/" + name;
203  }
204 
205  //
206  // There must now be a fully qualified path in the string. All fully
207  // qualified names begin with "/Names". We have to split off the final
208  // segment which will become the name of the object. A '/' that
209  // separates the path from the final segment had better be there since
210  // we just made sure that at least the namespace name was there.
211  //
212  std::string::size_type i = name.rfind ("/");
213  NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error. Can't find '/' in name");
214 
215  //
216  // The slash we found cannot be the slash at the start of the namespaceName.
217  // This would indicate there is no name in the path at all. It can be
218  // any other index.
219  //
220  NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a name in the path string");
221 
222  //
223  // We now know where the path string starts and ends, and where the
224  // name starts and ends. All we have to do is to call our available
225  // function for adding a name under a path string.
226  //
227  return Add (name.substr (0, i), name.substr (i + 1), object);
228 }
229 
230 bool
231 NamesPriv::Add (std::string path, std::string name, Ptr<Object> object)
232 {
233  NS_LOG_FUNCTION (this << path << name << object);
234  if (path == "/Names")
235  {
236  return Add (Ptr<Object> (0, false), name, object);
237  }
238  return Add (Find (path), name, object);
239 }
240 
241 bool
242 NamesPriv::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
243 {
244  NS_LOG_FUNCTION (this << context << name << object);
245 
246  if (IsNamed (object))
247  {
248  NS_LOG_LOGIC ("Object is already named");
249  return false;
250  }
251 
252  NameNode *node = 0;
253  if (context)
254  {
255  node = IsNamed (context);
256  NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
257  }
258  else
259  {
260  node = &m_root;
261  }
262 
263  if (IsDuplicateName (node, name))
264  {
265  NS_LOG_LOGIC ("Name is already taken");
266  return false;
267  }
268 
269  NameNode *newNode = new NameNode (node, name, object);
270  node->m_nameMap[name] = newNode;
271  m_objectMap[object] = newNode;
272 
273  return true;
274 }
275 
276 bool
277 NamesPriv::Rename (std::string oldpath, std::string newname)
278 {
279  NS_LOG_FUNCTION (this << oldpath << newname);
280  //
281  // This is the simple, easy to use version of Rename, so we want it to be
282  // flexible. We don't want to force a user to always type the fully
283  // qualified namespace name, so we allow the namespace name to be omitted.
284  // For example, calling Rename ("Client/ath0", "eth0") should result in
285  // exactly the same behavior as Rename ("/Names/Client/ath0", "eth0").
286  // Calling Rename ("Client", "Router") should have the same effect as
287  // Rename ("Names/Client", "Router")
288  //
289  // The first thing to do, then, is to "canonicalize" the input string to always
290  // be a fully qualified path.
291  //
292  // If we are given a name that begins with "/Names/" we assume that this is a
293  // fully qualified path to the object we want to change. We split the path into
294  // path string (cf directory) and and a final segment (cf filename) and then call
295  // the "Real" Rename.
296  //
297  std::string namespaceName = "/Names";
298  std::string::size_type offset = oldpath.find (namespaceName);
299  if (offset != 0)
300  {
301  //
302  // This must be a name that has the "/Names" namespace prefix omitted.
303  // Do some reasonableness checking on the rest of the name.
304  //
305  offset = oldpath.find ("/");
306  if (offset == 0)
307  {
308  NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\"");
309  return false;
310  }
311 
312  oldpath = "/Names/" + oldpath;
313  }
314 
315  //
316  // There must now be a fully qualified path in the oldpath string. All
317  // fully qualified names begin with "/Names". We have to split off the final
318  // segment which will become the name we want to rename. A '/' that
319  // separates the path from the final segment (name) had better be there since
320  // we just made sure that at least the namespace name was there.
321  //
322  std::string::size_type i = oldpath.rfind ("/");
323  NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error. Can't find '/' in name");
324 
325  //
326  // The slash we found cannot be the slash at the start of the namespaceName.
327  // This would indicate there is no name in the path at all. It can be
328  // any other index.
329  //
330  NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a name in the path string");
331 
332  //
333  // We now know where the path part of the string starts and ends, and where the
334  // name part starts and ends. All we have to do is to call our available
335  // function for creating adding a name under a path string.
336  //
337  return Rename (oldpath.substr (0, i), oldpath.substr (i + 1), newname);
338 }
339 
340 bool
341 NamesPriv::Rename (std::string path, std::string oldname, std::string newname)
342 {
343  NS_LOG_FUNCTION (this << path << oldname << newname);
344  if (path == "/Names")
345  {
346  return Rename (Ptr<Object> (0, false), oldname, newname);
347  }
348  return Rename (Find (path), oldname, newname);
349 }
350 
351 bool
352 NamesPriv::Rename (Ptr<Object> context, std::string oldname, std::string newname)
353 {
354  NS_LOG_FUNCTION (this << context << oldname << newname);
355 
356  NameNode *node = 0;
357  if (context)
358  {
359  node = IsNamed (context);
360  NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node");
361  }
362  else
363  {
364  node = &m_root;
365  }
366 
367  if (IsDuplicateName (node, newname))
368  {
369  NS_LOG_LOGIC ("New name is already taken");
370  return false;
371  }
372 
373  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (oldname);
374  if (i == node->m_nameMap.end ())
375  {
376  NS_LOG_LOGIC ("Old name does not exist in name map");
377  return false;
378  }
379  else
380  {
381  NS_LOG_LOGIC ("Old name exists in name map");
382 
383  //
384  // The rename process consists of:
385  // 1. Geting the pointer to the name node from the map and remembering it;
386  // 2. Removing the map entry corresponding to oldname from the map;
387  // 3. Changing the name string in the name node;
388  // 4. Adding the name node back in the map under the newname.
389  //
390  NameNode *changeNode = i->second;
391  node->m_nameMap.erase (i);
392  changeNode->m_name = newname;
393  node->m_nameMap[newname] = changeNode;
394  return true;
395  }
396 }
397 
398 std::string
400 {
401  NS_LOG_FUNCTION (this << object);
402 
403  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
404  if (i == m_objectMap.end ())
405  {
406  NS_LOG_LOGIC ("Object does not exist in object map");
407  return "";
408  }
409  else
410  {
411  NS_LOG_LOGIC ("Object exists in object map");
412  return i->second->m_name;
413  }
414 }
415 
416 std::string
418 {
419  NS_LOG_FUNCTION (this << object);
420 
421  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
422  if (i == m_objectMap.end ())
423  {
424  NS_LOG_LOGIC ("Object does not exist in object map");
425  return "";
426  }
427 
428  NameNode *p = i->second;
429  NS_ASSERT_MSG (p, "NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map");
430 
431  std::string path;
432 
433  do
434  {
435  path = "/" + p->m_name + path;
436  NS_LOG_LOGIC ("path is " << path);
437  }
438  while ((p = p->m_parent) != 0);
439 
440  return path;
441 }
442 
443 
445 NamesPriv::Find (std::string path)
446 {
447  //
448  // This is hooked in from simple, easy to use version of Find, so we want it
449  // to be flexible.
450  //
451  // If we are provided a path that doesn't begin with "/Names", we assume
452  // that the caller has simply given us a path starting with a name that
453  // is in the root namespace. This allows peole to omit the "/Names" prefix.
454  // and simply do a Find ("Client/eth0") instead of having to always do a
455  // Find ("/Names/Client/eth0");
456  //
457  // So, if we are given a name that begins with "/Names/" the upshot is that we
458  // just remove that prefix and treat the rest of the string as starting with a
459  // name in the root namespace.
460  //
461 
462  NS_LOG_FUNCTION (this << path);
463  std::string namespaceName = "/Names/";
464  std::string remaining;
465 
466  std::string::size_type offset = path.find (namespaceName);
467  if (offset == 0)
468  {
469  NS_LOG_LOGIC (path << " is a fully qualified name");
470  remaining = path.substr (namespaceName.size ());
471  }
472  else
473  {
474  NS_LOG_LOGIC (path << " begins with a relative name");
475  remaining = path;
476  }
477 
478  NameNode *node = &m_root;
479 
480  //
481  // The string <remaining> is now composed entirely of path segments in
482  // the /Names name space and we have eaten the leading slash. e.g.,
483  // remaining = "ClientNode/eth0"
484  //
485  // The start of the search is always at the root of the name space.
486  //
487  for (;;)
488  {
489  NS_LOG_LOGIC ("Looking for the object of name " << remaining);
490  offset = remaining.find ("/");
491  if (offset == std::string::npos)
492  {
493  //
494  // There are no remaining slashes so this is the last segment of the
495  // specified name. We're done when we find it
496  //
497  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (remaining);
498  if (i == node->m_nameMap.end ())
499  {
500  NS_LOG_LOGIC ("Name does not exist in name map");
501  return 0;
502  }
503  else
504  {
505  NS_LOG_LOGIC ("Name parsed, found object");
506  return i->second->m_object;
507  }
508  }
509  else
510  {
511  //
512  // There are more slashes so this is an intermediate segment of the
513  // specified name. We need to "recurse" when we find this segment.
514  //
515  offset = remaining.find ("/");
516  std::string segment = remaining.substr (0, offset);
517 
518  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (segment);
519  if (i == node->m_nameMap.end ())
520  {
521  NS_LOG_LOGIC ("Name does not exist in name map");
522  return 0;
523  }
524  else
525  {
526  node = i->second;
527  remaining = remaining.substr (offset + 1);
528  NS_LOG_LOGIC ("Intermediate segment parsed");
529  continue;
530  }
531  }
532  }
533 
534  NS_ASSERT_MSG (node, "NamesPriv::Find(): Internal error: this can't happen");
535  return 0;
536 }
537 
539 NamesPriv::Find (std::string path, std::string name)
540 {
541  NS_LOG_FUNCTION (this << path << name);
542 
543  if (path == "/Names")
544  {
545  return Find (Ptr<Object> (0, false), name);
546  }
547  return Find (Find (path), name);
548 }
549 
551 NamesPriv::Find (Ptr<Object> context, std::string name)
552 {
553  NS_LOG_FUNCTION (this << context << name);
554 
555  NameNode *node = 0;
556 
557  if (context == 0)
558  {
559  NS_LOG_LOGIC ("Zero context implies root NameNode");
560  node = &m_root;
561  }
562  else
563  {
564  node = IsNamed (context);
565  if (node == 0)
566  {
567  NS_LOG_LOGIC ("Context does not point to a previously named node");
568  return 0;
569  }
570  }
571 
572  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
573  if (i == node->m_nameMap.end ())
574  {
575  NS_LOG_LOGIC ("Name does not exist in name map");
576  return 0;
577  }
578  else
579  {
580  NS_LOG_LOGIC ("Name exists in name map");
581  return i->second->m_object;
582  }
583 }
584 
585 NameNode *
587 {
588  NS_LOG_FUNCTION (this << object);
589 
590  std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object);
591  if (i == m_objectMap.end ())
592  {
593  NS_LOG_LOGIC ("Object does not exist in object map, returning NameNode 0");
594  return 0;
595  }
596  else
597  {
598  NS_LOG_LOGIC ("Object exists in object map, returning NameNode " << &i->second);
599  return i->second;
600  }
601 }
602 
603 bool
604 NamesPriv::IsDuplicateName (NameNode *node, std::string name)
605 {
606  NS_LOG_FUNCTION (this << node << name);
607 
608  std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name);
609  if (i == node->m_nameMap.end ())
610  {
611  NS_LOG_LOGIC ("Name does not exist in name map");
612  return false;
613  }
614  else
615  {
616  NS_LOG_LOGIC ("Name exists in name map");
617  return true;
618  }
619 }
620 
621 void
622 Names::Add (std::string name, Ptr<Object> object)
623 {
624  NS_LOG_FUNCTION (name << object);
625  bool result = NamesPriv::Get ()->Add (name, object);
626  NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding name " << name);
627 }
628 
629 void
630 Names::Rename (std::string oldpath, std::string newname)
631 {
632  NS_LOG_FUNCTION (oldpath << newname);
633  bool result = NamesPriv::Get ()->Rename (oldpath, newname);
634  NS_ABORT_MSG_UNLESS (result, "Names::Rename(): Error renaming " << oldpath << " to " << newname);
635 }
636 
637 void
638 Names::Add (std::string path, std::string name, Ptr<Object> object)
639 {
640  NS_LOG_FUNCTION (path << name << object);
641  bool result = NamesPriv::Get ()->Add (path, name, object);
642  NS_ABORT_MSG_UNLESS (result, "Names::Add(): Error adding " << path << " " << name);
643 }
644 
645 void
646 Names::Rename (std::string path, std::string oldname, std::string newname)
647 {
648  NS_LOG_FUNCTION (path << oldname << newname);
649  bool result = NamesPriv::Get ()->Rename (path, oldname, newname);
650  NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << path << " " << oldname << " to " << newname);
651 }
652 
653 void
654 Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object)
655 {
656  NS_LOG_FUNCTION (context << name << object);
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  NS_LOG_FUNCTION (context << oldname << newname);
665  bool result = NamesPriv::Get ()->Rename (context, oldname, newname);
666  NS_ABORT_MSG_UNLESS (result, "Names::Rename (): Error renaming " << oldname << " to " << newname << " under context " <<
667  &context);
668 }
669 
670 std::string
672 {
673  NS_LOG_FUNCTION (object);
674  return NamesPriv::Get ()->FindName (object);
675 }
676 
677 std::string
679 {
680  NS_LOG_FUNCTION (object);
681  return NamesPriv::Get ()->FindPath (object);
682 }
683 
684 void
686 {
688  return NamesPriv::Get ()->Clear ();
689 }
690 
692 Names::FindInternal (std::string name)
693 {
694  NS_LOG_FUNCTION (name);
695  return NamesPriv::Get ()->Find (name);
696 }
697 
699 Names::FindInternal (std::string path, std::string name)
700 {
701  NS_LOG_FUNCTION (path << name);
702  return NamesPriv::Get ()->Find (path, name);
703 }
704 
706 Names::FindInternal (Ptr<Object> context, std::string name)
707 {
708  NS_LOG_FUNCTION (context << name);
709  return NamesPriv::Get ()->Find (context, name);
710 }
711 
712 } // namespace ns3
Ptr< Object > m_object
Definition: names.cc:49
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by "...
std::map< std::string, NameNode * > m_nameMap
Definition: names.cc:51
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:201
#define NS_LOG_FUNCTION_NOARGS()
Output the name of the function.
NameNode * m_parent
Definition: names.cc:47
static void Add(std::string name, Ptr< Object > object)
Add the association between the string "name" and the Ptr obj.
Definition: names.cc:622
A directory of name and Ptr associations that allows us to give any ns3 Object a name...
Definition: names.h:37
static void Clear(void)
Clear the list of objects associated with names.
Definition: names.cc:685
bool Rename(std::string oldpath, std::string newname)
Definition: names.cc:277
std::string FindPath(Ptr< Object > object)
Definition: names.cc:417
Definition of assertion macros NS_ASSERT() and NS_ASSERT_MSG().
std::string m_name
Definition: names.cc:48
void Clear(void)
Definition: names.cc:147
std::string FindName(Ptr< Object > object)
Definition: names.cc:399
#define NS_LOG_LOGIC(msg)
Use NS_LOG to output a message of level LOG_LOGIC.
Definition: log.h:252
Every class exported by the ns3 library is enclosed in the ns3 namespace.
static void Rename(std::string oldpath, std::string newname)
Rename a previously associated name.
Definition: names.cc:630
NameNode & operator=(const NameNode &rhs)
Definition: names.cc:68
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:678
#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:90
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
Definition: names.cc:119
static NamesPriv * Get(void)
Definition: names.cc:123
NameNode m_root
Definition: names.cc:118
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:671
Declaration of class ns3::Names.
NameNode * IsNamed(Ptr< Object >)
Definition: names.cc:586
bool Add(std::string name, Ptr< Object > object)
Definition: names.cc:169
Debug message logging.
static Ptr< Object > FindInternal(std::string path)
Non-templated internal version of Names::Find.
Definition: names.cc:692
Ptr< Object > Find(std::string name)
Definition: names.cc:445
bool IsDuplicateName(NameNode *node, std::string name)
Definition: names.cc:604
NS_ABORT_x macro definitions.