|
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 "ns3/object.h" |
|
21 #include "ns3/log.h" |
|
22 #include "ns3/assert.h" |
|
23 #include "ns3/abort.h" |
|
24 #include "ns3/simulator.h" |
|
25 #include "object-names.h" |
|
26 |
|
27 namespace ns3 { |
|
28 |
|
29 NS_LOG_COMPONENT_DEFINE ("Names"); |
|
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 |
|
41 NameNode *m_parent; |
|
42 std::string m_name; |
|
43 Ptr<Object> m_object; |
|
44 |
|
45 std::map<std::string, NameNode *> m_nameMap; |
|
46 }; |
|
47 |
|
48 NameNode::NameNode () |
|
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 & |
|
62 NameNode::operator = (const NameNode &rhs) |
|
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 } |
|
75 |
|
76 NameNode::~NameNode () |
|
77 { |
|
78 } |
|
79 |
|
80 class NamesPriv |
|
81 { |
|
82 public: |
|
83 NamesPriv (); |
|
84 ~NamesPriv (); |
|
85 |
|
86 bool Add (std::string name, Ptr<Object> obj); |
|
87 bool Add (Ptr<Object> context, std::string name, Ptr<Object> object); |
|
88 bool Add (std::string context, std::string name, Ptr<Object> object); |
|
89 std::string FindShortName (Ptr<Object> object); |
|
90 std::string FindFullName (Ptr<Object> object); |
|
91 Ptr<Object> FindObjectFromFullName (std::string name); |
|
92 Ptr<Object> FindObjectFromShortName (Ptr<Object> context, std::string name); |
|
93 |
|
94 static NamesPriv *Get (void); |
|
95 |
|
96 private: |
|
97 static NamesPriv **DoGet (void); |
|
98 static void Delete (void); |
|
99 |
|
100 NameNode *IsNamed (Ptr<Object>); |
|
101 bool IsDuplicateName (NameNode *node, std::string name); |
|
102 |
|
103 NameNode m_root; |
|
104 std::map<Ptr<Object>, NameNode *> m_objectMap; |
|
105 }; |
|
106 |
|
107 NamesPriv * |
|
108 NamesPriv::Get (void) |
|
109 { |
|
110 return *(DoGet ()); |
|
111 } |
|
112 |
|
113 NamesPriv ** |
|
114 NamesPriv::DoGet (void) |
|
115 { |
|
116 static NamesPriv *ptr = 0; |
|
117 |
|
118 if (ptr == 0) |
|
119 { |
|
120 ptr = new NamesPriv; |
|
121 Simulator::ScheduleDestroy (&NamesPriv::Delete); |
|
122 } |
|
123 |
|
124 return &ptr; |
|
125 } |
|
126 |
|
127 void |
|
128 NamesPriv::Delete (void) |
|
129 { |
|
130 NS_LOG_FUNCTION_NOARGS (); |
|
131 |
|
132 NamesPriv **ptr = DoGet (); |
|
133 delete *ptr; |
|
134 *ptr = 0; |
|
135 } |
|
136 |
|
137 NamesPriv::NamesPriv () |
|
138 { |
|
139 NS_LOG_FUNCTION_NOARGS (); |
|
140 |
|
141 m_root.m_parent = 0; |
|
142 m_root.m_name = "Names"; |
|
143 m_root.m_object = 0; |
|
144 } |
|
145 |
|
146 NamesPriv::~NamesPriv () |
|
147 { |
|
148 NS_LOG_FUNCTION_NOARGS (); |
|
149 |
|
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 |
|
161 bool |
|
162 NamesPriv::Add (std::string name, Ptr<Object> object) |
|
163 { |
|
164 return Add (Ptr<Object> (0, false), name, object); |
|
165 } |
|
166 |
|
167 bool |
|
168 NamesPriv::Add (Ptr<Object> context, std::string name, Ptr<Object> object) |
|
169 { |
|
170 NS_LOG_FUNCTION (context << name << object); |
|
171 |
|
172 if (IsNamed (object)) |
|
173 { |
|
174 NS_LOG_LOGIC ("Object is already named"); |
|
175 return false; |
|
176 } |
|
177 |
|
178 NameNode *node = 0; |
|
179 if (context) |
|
180 { |
|
181 node = IsNamed (context); |
|
182 NS_ASSERT_MSG (node, "NamesPriv::Name(): context must point to a previously named node"); |
|
183 } |
|
184 else |
|
185 { |
|
186 node = &m_root; |
|
187 } |
|
188 |
|
189 if (IsDuplicateName (node, name)) |
|
190 { |
|
191 NS_LOG_LOGIC ("Name is already taken"); |
|
192 return false; |
|
193 } |
|
194 |
|
195 NameNode *newNode = new NameNode(node, name, object); |
|
196 node->m_nameMap[name] = newNode; |
|
197 m_objectMap[object] = newNode; |
|
198 |
|
199 return true; |
|
200 } |
|
201 |
|
202 bool |
|
203 NamesPriv::Add (std::string context, std::string name, Ptr<Object> object) |
|
204 { |
|
205 if (context == "/Names") |
|
206 { |
|
207 return Add (name, object); |
|
208 } |
|
209 return Add (FindObjectFromFullName (context), name, object); |
|
210 } |
|
211 |
|
212 std::string |
|
213 NamesPriv::FindShortName (Ptr<Object> object) |
|
214 { |
|
215 NS_LOG_FUNCTION (object); |
|
216 |
|
217 std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object); |
|
218 if (i == m_objectMap.end ()) |
|
219 { |
|
220 NS_LOG_LOGIC ("Object does not exist in object map"); |
|
221 return ""; |
|
222 } |
|
223 else |
|
224 { |
|
225 NS_LOG_LOGIC ("Object exists in object map"); |
|
226 return i->second->m_name; |
|
227 } |
|
228 } |
|
229 |
|
230 std::string |
|
231 NamesPriv::FindFullName (Ptr<Object> object) |
|
232 { |
|
233 NS_LOG_FUNCTION (object); |
|
234 |
|
235 std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object); |
|
236 if (i == m_objectMap.end ()) |
|
237 { |
|
238 NS_LOG_LOGIC ("Object does not exist in object map"); |
|
239 return ""; |
|
240 } |
|
241 |
|
242 NameNode *p = i->second; |
|
243 NS_ASSERT_MSG (p, "NamesPriv::FindFullName(): Internal error: Invalid NameNode pointer from map"); |
|
244 |
|
245 std::string fullname; |
|
246 |
|
247 do |
|
248 { |
|
249 fullname = "/" + p->m_name + fullname; |
|
250 NS_LOG_LOGIC ("fullname is " << fullname); |
|
251 } |
|
252 while ((p = p->m_parent) != 0); |
|
253 |
|
254 return fullname; |
|
255 } |
|
256 |
|
257 |
|
258 Ptr<Object> |
|
259 NamesPriv::FindObjectFromFullName (std::string name) |
|
260 { |
|
261 std::string namespaceName = "/Names/"; |
|
262 std::string::size_type offset = name.find (namespaceName); |
|
263 if (offset == std::string::npos) |
|
264 { |
|
265 NS_LOG_LOGIC (name << " is not in the " << namespaceName << " name space"); |
|
266 return 0; |
|
267 } |
|
268 |
|
269 std::string remaining = name.substr (namespaceName.size ()); |
|
270 NameNode *node = &m_root; |
|
271 |
|
272 // |
|
273 // remaining is now composed entirely of path segments in the /Names name space. |
|
274 // and we have eaten the leading slash. e.g., remaining = "ClientNode/eth0" |
|
275 // The start of the search is at the root of the name space. |
|
276 // |
|
277 for (;;) |
|
278 { |
|
279 NS_LOG_LOGIC ("Looking for the object of name " << remaining); |
|
280 offset = remaining.find ("/"); |
|
281 if (offset == std::string::npos) |
|
282 { |
|
283 // |
|
284 // There are no remaining slashes so this is the last segment of the |
|
285 // specified name. We're done when we find it |
|
286 // |
|
287 std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (remaining); |
|
288 if (i == node->m_nameMap.end ()) |
|
289 { |
|
290 NS_LOG_LOGIC ("Name does not exist in name map"); |
|
291 return 0; |
|
292 } |
|
293 else |
|
294 { |
|
295 NS_LOG_LOGIC ("Name parsed, found object"); |
|
296 return i->second->m_object; |
|
297 } |
|
298 } |
|
299 else |
|
300 { |
|
301 // |
|
302 // There are more slashes so this is an intermediate segment of the |
|
303 // specified name. We need to "recurse" when we find this segment. |
|
304 // |
|
305 offset = remaining.find ("/"); |
|
306 std::string segment = remaining.substr(0, offset); |
|
307 |
|
308 std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (segment); |
|
309 if (i == node->m_nameMap.end ()) |
|
310 { |
|
311 NS_LOG_LOGIC ("Name does not exist in name map"); |
|
312 return 0; |
|
313 } |
|
314 else |
|
315 { |
|
316 node = i->second; |
|
317 remaining = remaining.substr (offset + 1); |
|
318 NS_LOG_LOGIC ("Intermediate segment parsed"); |
|
319 continue; |
|
320 } |
|
321 } |
|
322 } |
|
323 |
|
324 NS_ASSERT_MSG (node, "NamesPriv::FindObjectFromFullName(): Internal error: this can't happen"); |
|
325 return 0; |
|
326 } |
|
327 |
|
328 Ptr<Object> |
|
329 NamesPriv::FindObjectFromShortName (Ptr<Object> context, std::string name) |
|
330 { |
|
331 NS_LOG_FUNCTION (context << name); |
|
332 |
|
333 NameNode *node = 0; |
|
334 |
|
335 if (context == 0) |
|
336 { |
|
337 NS_LOG_LOGIC ("Zero context implies root NameNode"); |
|
338 node = &m_root; |
|
339 } |
|
340 else |
|
341 { |
|
342 node = IsNamed (context); |
|
343 if (node == 0) |
|
344 { |
|
345 NS_LOG_LOGIC ("Context does not point to a previously named node"); |
|
346 return 0; |
|
347 } |
|
348 } |
|
349 |
|
350 std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name); |
|
351 if (i == node->m_nameMap.end ()) |
|
352 { |
|
353 NS_LOG_LOGIC ("Name does not exist in name map"); |
|
354 return 0; |
|
355 } |
|
356 else |
|
357 { |
|
358 NS_LOG_LOGIC ("Name exists in name map"); |
|
359 return i->second->m_object; |
|
360 } |
|
361 } |
|
362 |
|
363 NameNode * |
|
364 NamesPriv::IsNamed (Ptr<Object> object) |
|
365 { |
|
366 NS_LOG_FUNCTION (object); |
|
367 |
|
368 std::map<Ptr<Object>, NameNode *>::iterator i = m_objectMap.find (object); |
|
369 if (i == m_objectMap.end ()) |
|
370 { |
|
371 NS_LOG_LOGIC ("Object does not exist in object map, returning NameNode 0"); |
|
372 return 0; |
|
373 } |
|
374 else |
|
375 { |
|
376 NS_LOG_LOGIC ("Object exists in object map, returning NameNode " << &i->second); |
|
377 return i->second; |
|
378 } |
|
379 } |
|
380 |
|
381 bool |
|
382 NamesPriv::IsDuplicateName (NameNode *node, std::string name) |
|
383 { |
|
384 NS_LOG_FUNCTION (node << name); |
|
385 |
|
386 std::map<std::string, NameNode *>::iterator i = node->m_nameMap.find (name); |
|
387 if (i == node->m_nameMap.end ()) |
|
388 { |
|
389 NS_LOG_LOGIC ("Name does not exist in name map"); |
|
390 return false; |
|
391 } |
|
392 else |
|
393 { |
|
394 NS_LOG_LOGIC ("Name exists in name map"); |
|
395 return true; |
|
396 } |
|
397 } |
|
398 |
|
399 bool |
|
400 Names::Add (std::string name, Ptr<Object> object) |
|
401 { |
|
402 return NamesPriv::Get ()->Add (name, object); |
|
403 } |
|
404 |
|
405 bool |
|
406 Names::Add (Ptr<Object> context, std::string name, Ptr<Object> object) |
|
407 { |
|
408 return NamesPriv::Get ()->Add (context, name, object); |
|
409 } |
|
410 |
|
411 bool |
|
412 Names::Add (std::string context, std::string name, Ptr<Object> object) |
|
413 { |
|
414 return NamesPriv::Get ()->Add (context, name, object); |
|
415 } |
|
416 |
|
417 std::string |
|
418 Names::FindShortName (Ptr<Object> object) |
|
419 { |
|
420 return NamesPriv::Get ()->FindShortName (object); |
|
421 } |
|
422 |
|
423 std::string |
|
424 Names::FindFullName (Ptr<Object> object) |
|
425 { |
|
426 return NamesPriv::Get ()->FindFullName (object); |
|
427 } |
|
428 |
|
429 Ptr<Object> |
|
430 Names::FindObjectFromFullNameInternal (std::string name) |
|
431 { |
|
432 return NamesPriv::Get ()->FindObjectFromFullName (name); |
|
433 } |
|
434 |
|
435 Ptr<Object> |
|
436 Names::FindObjectFromShortNameInternal (Ptr<Object> context, std::string name) |
|
437 { |
|
438 return NamesPriv::Get ()->FindObjectFromShortName (context, name); |
|
439 } |
|
440 |
|
441 } //namespace ns3 |
|
442 |
|
443 #ifdef RUN_SELF_TESTS |
|
444 |
|
445 #include "test.h" |
|
446 #include "object-factory.h" |
|
447 |
|
448 namespace ns3 { |
|
449 |
|
450 class TestObject : public Object |
|
451 { |
|
452 public: |
|
453 static TypeId GetTypeId (void) |
|
454 { |
|
455 static TypeId tid = TypeId ("TestObject") |
|
456 .SetParent (Object::GetTypeId ()) |
|
457 .HideFromDocumentation () |
|
458 .AddConstructor<TestObject> (); |
|
459 return tid; |
|
460 } |
|
461 TestObject () {} |
|
462 virtual void Dispose (void) {} |
|
463 }; |
|
464 |
|
465 class NamesTest : public Test |
|
466 { |
|
467 public: |
|
468 NamesTest (); |
|
469 virtual bool RunTests (void); |
|
470 }; |
|
471 |
|
472 NamesTest::NamesTest () |
|
473 : Test ("Names") |
|
474 { |
|
475 } |
|
476 |
|
477 bool |
|
478 NamesTest::RunTests (void) |
|
479 { |
|
480 bool result = true; |
|
481 |
|
482 // |
|
483 // Name a couple of objects at the root level |
|
484 // |
|
485 Ptr<TestObject> client = CreateObject<TestObject> (); |
|
486 result = Names::Add ("Client", client); |
|
487 NS_TEST_ASSERT_EQUAL (result, true); |
|
488 |
|
489 Ptr<TestObject> server = CreateObject<TestObject> (); |
|
490 result = Names::Add ("Server", server); |
|
491 NS_TEST_ASSERT_EQUAL (result, true); |
|
492 |
|
493 // |
|
494 // We shouldn't be able to add another name to a previously named object |
|
495 // |
|
496 result = Names::Add ("Not Client", client); |
|
497 NS_TEST_ASSERT_EQUAL (result, false); |
|
498 |
|
499 // |
|
500 // We shouldn't be able to duplicate a name at the root level. |
|
501 // |
|
502 Ptr<TestObject> secondClient = CreateObject<TestObject> (); |
|
503 result = Names::Add ("Client", secondClient); |
|
504 NS_TEST_ASSERT_EQUAL (result, false); |
|
505 |
|
506 // |
|
507 // We should be able to add a new name in the first object's context |
|
508 // |
|
509 Ptr<TestObject> clientEth0 = CreateObject<TestObject> (); |
|
510 result = Names::Add (client, "eth0", clientEth0); |
|
511 NS_TEST_ASSERT_EQUAL (result, true); |
|
512 |
|
513 // |
|
514 // We shouldn't be able to duplicate a name in that context. |
|
515 // |
|
516 Ptr<TestObject> secondClientEth0 = CreateObject<TestObject> (); |
|
517 result = Names::Add (client, "eth0", secondClientEth0); |
|
518 NS_TEST_ASSERT_EQUAL (result, false); |
|
519 |
|
520 // |
|
521 // We should be able to add the same name in the second object's context |
|
522 // |
|
523 Ptr<TestObject> serverEth0 = CreateObject<TestObject> (); |
|
524 result = Names::Add (server, "eth0", serverEth0); |
|
525 NS_TEST_ASSERT_EQUAL (result, true); |
|
526 |
|
527 // |
|
528 // We should be able to find the short names for the objects we created |
|
529 // |
|
530 std::string found; |
|
531 |
|
532 found = Names::FindShortName (client); |
|
533 NS_TEST_ASSERT_EQUAL (found, "Client"); |
|
534 |
|
535 found = Names::FindShortName (server); |
|
536 NS_TEST_ASSERT_EQUAL (found, "Server"); |
|
537 |
|
538 found = Names::FindShortName (clientEth0); |
|
539 NS_TEST_ASSERT_EQUAL (found, "eth0"); |
|
540 |
|
541 found = Names::FindShortName (serverEth0); |
|
542 NS_TEST_ASSERT_EQUAL (found, "eth0"); |
|
543 |
|
544 // |
|
545 // We should be able to find the full names for the objects we created |
|
546 // |
|
547 found = Names::FindFullName (client); |
|
548 NS_TEST_ASSERT_EQUAL (found, "/Names/Client"); |
|
549 |
|
550 found = Names::FindFullName (server); |
|
551 NS_TEST_ASSERT_EQUAL (found, "/Names/Server"); |
|
552 |
|
553 found = Names::FindFullName (clientEth0); |
|
554 NS_TEST_ASSERT_EQUAL (found, "/Names/Client/eth0"); |
|
555 |
|
556 found = Names::FindFullName (serverEth0); |
|
557 NS_TEST_ASSERT_EQUAL (found, "/Names/Server/eth0"); |
|
558 |
|
559 // |
|
560 // We should be able to find the objects from the short names |
|
561 // |
|
562 Ptr<TestObject> foundObject; |
|
563 |
|
564 foundObject = Names::FindObjectFromShortName<TestObject> (0, "Client"); |
|
565 NS_TEST_ASSERT_EQUAL (foundObject, client); |
|
566 |
|
567 foundObject = Names::FindObjectFromShortName<TestObject> (0, "Server"); |
|
568 NS_TEST_ASSERT_EQUAL (foundObject, server); |
|
569 |
|
570 foundObject = Names::FindObjectFromShortName<TestObject> (client, "eth0"); |
|
571 NS_TEST_ASSERT_EQUAL (foundObject, clientEth0); |
|
572 |
|
573 foundObject = Names::FindObjectFromShortName<TestObject> (server, "eth0"); |
|
574 NS_TEST_ASSERT_EQUAL (foundObject, serverEth0); |
|
575 |
|
576 // |
|
577 // We should be able to find the objects from their full names |
|
578 // |
|
579 foundObject = Names::Find<TestObject> ("/Names/Client"); |
|
580 NS_TEST_ASSERT_EQUAL (foundObject, client); |
|
581 |
|
582 foundObject = Names::Find<TestObject> ("/Names/Server"); |
|
583 NS_TEST_ASSERT_EQUAL (foundObject, server); |
|
584 |
|
585 foundObject = Names::Find<TestObject> ("/Names/Client/eth0"); |
|
586 NS_TEST_ASSERT_EQUAL (foundObject, clientEth0); |
|
587 |
|
588 foundObject = Names::Find<TestObject> ("/Names/Server/eth0"); |
|
589 NS_TEST_ASSERT_EQUAL (foundObject, serverEth0); |
|
590 |
|
591 // |
|
592 // We also have some syntactical sugary methods, so make sure they do what |
|
593 // they should as well. |
|
594 // |
|
595 Ptr<TestObject> bridge = CreateObject<TestObject> (); |
|
596 result = Names::Add ("/Names", "Bridge", client); |
|
597 NS_TEST_ASSERT_EQUAL (result, true); |
|
598 |
|
599 Ptr<TestObject> bridgeEth0 = CreateObject<TestObject> (); |
|
600 result = Names::Add ("/Names/Bridge", "eth0", bridgeEth0); |
|
601 NS_TEST_ASSERT_EQUAL (result, true); |
|
602 |
|
603 foundObject = Names::Find<TestObject> ("/Names/Bridge"); |
|
604 NS_TEST_ASSERT_EQUAL (foundObject, bridge); |
|
605 |
|
606 foundObject = Names::Find<TestObject> ("/Names/Bridge/eth0"); |
|
607 NS_TEST_ASSERT_EQUAL (foundObject, bridgeEth0); |
|
608 |
|
609 // |
|
610 // Run the simulator and destroy it to get the Destroy method called on the |
|
611 // private implementation object. We depend on seeing a valgrind-clean run of |
|
612 // the unit tests to really determine if the clean up was really successful. |
|
613 // |
|
614 Simulator::Run (); |
|
615 Simulator::Destroy (); |
|
616 |
|
617 return true; |
|
618 } |
|
619 |
|
620 static NamesTest g_namesTests; |
|
621 |
|
622 } // namespace ns3 |
|
623 |
|
624 #endif /* RUN_SELF_TESTS */ |