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