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