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