82 public: |
82 public: |
83 NamesPriv (); |
83 NamesPriv (); |
84 ~NamesPriv (); |
84 ~NamesPriv (); |
85 |
85 |
86 bool Add (std::string name, Ptr<Object> obj); |
86 bool Add (std::string name, Ptr<Object> obj); |
|
87 bool Add (std::string context, std::string name, Ptr<Object> object); |
87 bool Add (Ptr<Object> context, std::string name, Ptr<Object> object); |
88 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); |
89 std::string FindShortName (Ptr<Object> object); |
90 std::string FindFullName (Ptr<Object> object); |
90 std::string FindFullName (Ptr<Object> object); |
91 Ptr<Object> FindObjectFromFullName (std::string name); |
91 Ptr<Object> FindObjectFromFullName (std::string name); |
92 Ptr<Object> FindObjectFromShortName (Ptr<Object> context, std::string name); |
92 Ptr<Object> FindObjectFromShortName (Ptr<Object> context, std::string name); |
93 |
93 |
165 NamesPriv::Add (std::string name, Ptr<Object> object) |
165 NamesPriv::Add (std::string name, Ptr<Object> object) |
166 { |
166 { |
167 NS_LOG_FUNCTION (name << object); |
167 NS_LOG_FUNCTION (name << object); |
168 // |
168 // |
169 // This is the simple, easy to use version of Add, so we want it to be flexible. |
169 // This is the simple, easy to use version of Add, so we want it to be flexible. |
170 // |
170 // We don't want to force a user to always type the fully qualified namespace |
171 // If we are provided a name that doesn't begin with "/Names", we assume |
171 // name, so we allow the namespace name to be omitted. For example, calling |
172 // that the caller has given us a shortname that she wants added to the root |
172 // Add ("Client/ath0", obj) should result in exactly the same behavior as |
173 // namespace. This results in a call to the "real" Add with context set to |
173 // Add ("/Names/Client/ath0", obj). Calling Add ("Client", obj) should have |
174 // zero, indicating what we want to do. |
174 // the same effect as Add ("Names/Client", obj) |
|
175 // |
|
176 // The first thing to do, then, is to "canonicalize" the input string to always |
|
177 // be a fully qualified name. |
175 // |
178 // |
176 // If we are given a name that begins with "/Names/" we assume that this is a |
179 // If we are given a name that begins with "/Names/" we assume that this is a |
177 // fullname to the object we want to create. We split the fullname into a |
180 // fullname to the object we want to create. We split the fullname into a |
178 // context string and and a final segment and then call the "Real" Add. |
181 // context string and and a final segment and then call the "Real" Add. |
179 // |
182 // |
180 std::string namespaceName = "/Names"; |
183 std::string namespaceName = "/Names"; |
181 std::string::size_type offset = name.find (namespaceName); |
184 std::string::size_type offset = name.find (namespaceName); |
182 if (offset == 0) |
185 if (offset != 0) |
183 { |
186 { |
184 // |
187 // |
185 // This must be a fully qualified longname. All fully qualified names begin |
188 // This must be a name that has the "/Names" namespace prefix omitted. |
186 // with "/Names". We have to split off the final segment which will become |
189 // Do some reasonableness checking on the rest of the name. |
187 // the shortname of the object. |
|
188 // |
190 // |
189 std::string::size_type i = name.rfind ("/"); |
191 offset = name.find ("/"); |
190 NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error. Can't find '/' in name"); |
192 if (offset == 0) |
191 |
193 { |
192 // |
194 NS_ASSERT_MSG (false, "NamesPriv::Add(): Name begins with '/' but not \"/Names\""); |
193 // The slash we found cannot be the slash at the start of the namespaceName. |
195 return false; |
194 // This would indicate there is no shortname in the path at all. |
196 } |
195 // |
197 |
196 NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a shortname in the name string"); |
198 name = "/Names/" + name; |
197 |
199 } |
198 // |
200 |
199 // We now know where the context string starts and ends, and where the |
201 // |
200 // shortname starts and ends. All we have to do is to call our available |
202 // There must now be a fully qualified longname in the string. All fully |
201 // function for creating addubg a shortname under a context string. |
203 // qualified names begin with "/Names". We have to split off the final |
202 // |
204 // segment which will become the shortname of the object. A '/' that |
203 return Add (name.substr (0, i), name.substr (i + 1), object); |
205 // separates the context from the final segment had better be there since |
204 } |
206 // we just made sure that at least the namespace name was there. |
205 else |
207 // |
206 { |
208 std::string::size_type i = name.rfind ("/"); |
207 // |
209 NS_ASSERT_MSG (i != std::string::npos, "NamesPriv::Add(): Internal error. Can't find '/' in name"); |
208 // This must be a shortname. Shortnames can't have ANY '/' characters in |
210 |
209 // them since they are interpreted as a final segment of a fullname. A |
211 // |
210 // shortname in this context means creating a name in the root namespace. |
212 // The slash we found cannot be the slash at the start of the namespaceName. |
211 // We indicate this by passing a zero context to the "real" add. |
213 // This would indicate there is no shortname in the path at all. It can be |
212 // |
214 // any other index. |
213 NS_ASSERT_MSG (offset == std::string::npos, "NamesPriv::Add(): Unexpected '/' in shortname"); |
215 // |
214 return Add (Ptr<Object> (0, false), name, object); |
216 NS_ASSERT_MSG (i != 0, "NamesPriv::Add(): Can't find a shortname in the name string"); |
215 } |
217 |
|
218 // |
|
219 // We now know where the context string starts and ends, and where the |
|
220 // shortname starts and ends. All we have to do is to call our available |
|
221 // function for creating addubg a shortname under a context string. |
|
222 // |
|
223 return Add (name.substr (0, i), name.substr (i + 1), object); |
216 } |
224 } |
217 |
225 |
218 bool |
226 bool |
219 NamesPriv::Add (std::string context, std::string name, Ptr<Object> object) |
227 NamesPriv::Add (std::string context, std::string name, Ptr<Object> object) |
220 { |
228 { |
681 |
689 |
682 foundObject = Names::Find<TestObject> ("Server/eth0"); |
690 foundObject = Names::Find<TestObject> ("Server/eth0"); |
683 NS_TEST_ASSERT_EQUAL (foundObject, serverEth0); |
691 NS_TEST_ASSERT_EQUAL (foundObject, serverEth0); |
684 |
692 |
685 // |
693 // |
|
694 // We should be able to add objects while including the root of the namespace |
|
695 // in the name. |
|
696 // |
|
697 Ptr<TestObject> router1 = CreateObject<TestObject> (); |
|
698 result = Names::Add ("/Names/Router1", router1); |
|
699 NS_TEST_ASSERT_EQUAL (result, true); |
|
700 |
|
701 // |
|
702 // We should be able to add objects while not including the root of the namespace |
|
703 // in the name. |
|
704 // |
|
705 Ptr<TestObject> router2 = CreateObject<TestObject> (); |
|
706 result = Names::Add ("Router2", router2); |
|
707 NS_TEST_ASSERT_EQUAL (result, true); |
|
708 |
|
709 // |
|
710 // We should be able to add sub-objects while including the root of the namespace |
|
711 // in the name. |
|
712 // |
|
713 Ptr<TestObject> router1Eth0 = CreateObject<TestObject> (); |
|
714 result = Names::Add ("/Names/Router1/eth0", router1Eth0); |
|
715 NS_TEST_ASSERT_EQUAL (result, true); |
|
716 |
|
717 // |
|
718 // We should be able to add sub-objects while not including the root of the namespace |
|
719 // in the name. |
|
720 // |
|
721 Ptr<TestObject> router2Eth0 = CreateObject<TestObject> (); |
|
722 result = Names::Add ("Router2/eth0", router2Eth0); |
|
723 NS_TEST_ASSERT_EQUAL (result, true); |
|
724 |
|
725 // |
|
726 // We should be able to find these objects in the same two ways |
|
727 // |
|
728 foundObject = Names::Find<TestObject> ("/Names/Router1"); |
|
729 NS_TEST_ASSERT_EQUAL (foundObject, router1); |
|
730 |
|
731 foundObject = Names::Find<TestObject> ("Router1"); |
|
732 NS_TEST_ASSERT_EQUAL (foundObject, router1); |
|
733 |
|
734 foundObject = Names::Find<TestObject> ("/Names/Router2"); |
|
735 NS_TEST_ASSERT_EQUAL (foundObject, router2); |
|
736 |
|
737 foundObject = Names::Find<TestObject> ("Router2"); |
|
738 NS_TEST_ASSERT_EQUAL (foundObject, router2); |
|
739 |
|
740 foundObject = Names::Find<TestObject> ("/Names/Router1/eth0"); |
|
741 NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0); |
|
742 |
|
743 foundObject = Names::Find<TestObject> ("Router1/eth0"); |
|
744 NS_TEST_ASSERT_EQUAL (foundObject, router1Eth0); |
|
745 |
|
746 foundObject = Names::Find<TestObject> ("/Names/Router2/eth0"); |
|
747 NS_TEST_ASSERT_EQUAL (foundObject, router2Eth0); |
|
748 |
|
749 foundObject = Names::Find<TestObject> ("Router2/eth0"); |
|
750 NS_TEST_ASSERT_EQUAL (foundObject, router2Eth0); |
|
751 |
|
752 // |
686 // We also have some syntactically sugary methods, so make sure they do what |
753 // We also have some syntactically sugary methods, so make sure they do what |
687 // they should as well. |
754 // they should as well. |
688 // |
755 // |
689 Ptr<TestObject> bridge = CreateObject<TestObject> (); |
756 Ptr<TestObject> bridge = CreateObject<TestObject> (); |
690 result = Names::Add ("/Names", "Bridge", bridge); |
757 result = Names::Add ("/Names", "Bridge", bridge); |