|
1 |
/* -*- Mode: C++; c-file-style: "gnu"; indent-tabs-mode:nil; -*- */ |
2 |
/* |
3 |
* Copyright (c) 2008 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 "ns3/object.h" |
20 |
#include "ns3/log.h" |
21 |
#include "ns3/assert.h" |
22 |
#include "ns3/abort.h" |
23 |
#include "ns3/simulator.h" |
24 |
#include "name-list.h" |
25 |
|
26 |
namespace ns3 { |
27 |
|
28 |
NS_LOG_COMPONENT_DEFINE ("NameList"); |
29 |
|
30 |
/** |
31 |
* \brief private implementation detail of the NameList API. |
32 |
*/ |
33 |
class NameListPriv |
34 |
{ |
35 |
public: |
36 |
NameListPriv (); |
37 |
~NameListPriv (); |
38 |
|
39 |
bool Add (Ptr<Object> obj, std::string name); |
40 |
Ptr<Object> GetObjectOfName (std::string name); |
41 |
|
42 |
static NameListPriv *Get (void); |
43 |
|
44 |
private: |
45 |
static NameListPriv **DoGet (void); |
46 |
|
47 |
static void Delete (void); |
48 |
std::vector<std::pair<Ptr<Object>, std::string> > m_names; |
49 |
}; |
50 |
|
51 |
NameListPriv * |
52 |
NameListPriv::Get (void) |
53 |
{ |
54 |
return *(DoGet ()); |
55 |
} |
56 |
|
57 |
NameListPriv ** |
58 |
NameListPriv::DoGet (void) |
59 |
{ |
60 |
NS_LOG_FUNCTION_NOARGS (); |
61 |
|
62 |
// |
63 |
// ptr is declared as a function-local static variable. This variable is |
64 |
// guaranteed to be initialized to zero (by code generated by the compiler) |
65 |
// the first time the function is called. Afterward it acts like a global |
66 |
// variable whose scope is defined by the function. |
67 |
// |
68 |
static NameListPriv *ptr = 0; |
69 |
|
70 |
// |
71 |
// We "piggyback" on the guaranteed initialization of ptr to zero and do |
72 |
// essentially the same thing the compiler did there in order to create |
73 |
// the private object one time. This is a simple way to implement a |
74 |
// singleton (a simpleton?). |
75 |
// |
76 |
if (ptr == 0) |
77 |
{ |
78 |
ptr = new NameListPriv; |
79 |
Simulator::ScheduleDestroy (&NameListPriv::Delete); |
80 |
} |
81 |
// |
82 |
// Returns a pointer to the pointer to the name list implementation object. |
83 |
// Why? See NameListPriv::Delete |
84 |
// |
85 |
return &ptr; |
86 |
} |
87 |
|
88 |
void |
89 |
NameListPriv::Delete (void) |
90 |
{ |
91 |
NS_LOG_FUNCTION_NOARGS (); |
92 |
|
93 |
// |
94 |
// DoGet returns a pointer to a pointer to the private implementation. We |
95 |
// need to call the destructor on the pointer, and also set the pointer |
96 |
// itself to zero to complete the teardown. |
97 |
// |
98 |
NameListPriv **ptr = DoGet (); |
99 |
// |
100 |
// This is a sneaky, behind the sheets way to get the object pointed to by the |
101 |
// function local variable ptr, with scope up in DoGet, torn down and the |
102 |
// pointer set to zero. |
103 |
// |
104 |
delete *ptr; |
105 |
*ptr = 0; |
106 |
} |
107 |
|
108 |
NameListPriv::NameListPriv () |
109 |
{ |
110 |
NS_LOG_FUNCTION_NOARGS (); |
111 |
} |
112 |
|
113 |
NameListPriv::~NameListPriv () |
114 |
{ |
115 |
NS_LOG_FUNCTION_NOARGS (); |
116 |
|
117 |
// |
118 |
// Clean up the list of names we have stored. This function is expected to be |
119 |
// called during Simulator::Destroy |
120 |
// |
121 |
for (std::vector<std::pair<Ptr<Object>, std::string> >::iterator i = m_names.begin (); i != m_names.end (); ++i) |
122 |
{ |
123 |
// |
124 |
// We just decrement the reference count here. We leave it to others, |
125 |
// for example the node list, to call dispose. |
126 |
// |
127 |
Ptr<Object> object = i->first; |
128 |
i->first = 0; |
129 |
} |
130 |
// |
131 |
// get rid of all of the <object, name> pairs in the underlying vector. |
132 |
// |
133 |
m_names.erase (m_names.begin (), m_names.end ()); |
134 |
} |
135 |
|
136 |
bool |
137 |
NameListPriv::Add (Ptr<Object> object, std::string name) |
138 |
{ |
139 |
// |
140 |
// We demand that all objects have a unique name in this particular namespace. |
141 |
// If the proposed name is unique, we add it to the collection and return true. |
142 |
// If there is an existing name in the collection, then we refuse to add it |
143 |
// and return false. |
144 |
// |
145 |
if (GetObjectOfName (name) == 0) |
146 |
{ |
147 |
m_names.push_back (std::make_pair (object, name)); |
148 |
return true; |
149 |
} |
150 |
else |
151 |
{ |
152 |
return false; |
153 |
} |
154 |
} |
155 |
|
156 |
Ptr<Object> |
157 |
NameListPriv::GetObjectOfName (std::string name) |
158 |
{ |
159 |
NS_LOG_FUNCTION (name); |
160 |
|
161 |
// |
162 |
// Just do a simple, old-fashioned, linear search through the name/object mappings |
163 |
// for a name match. If we find an object of the given name, return its Ptr. The |
164 |
// inability to find an object/name pair is reflected by returning a zero Ptr. |
165 |
// |
166 |
for (std::vector<std::pair<Ptr<Object>, std::string> >::iterator i = m_names.begin (); i != m_names.end (); ++i) |
167 |
{ |
168 |
if (i->second == name) |
169 |
{ |
170 |
return i->first; |
171 |
} |
172 |
} |
173 |
return 0; |
174 |
} |
175 |
|
176 |
} |
177 |
|
178 |
namespace ns3 { |
179 |
|
180 |
bool |
181 |
NameList::Add (Ptr<Object> object, std::string name) |
182 |
{ |
183 |
return NameListPriv::Get ()->Add (object, name); |
184 |
} |
185 |
|
186 |
Ptr<Object> |
187 |
NameList::GetObjectOfNameInternal (std::string name) |
188 |
{ |
189 |
return NameListPriv::Get ()->GetObjectOfName (name); |
190 |
} |
191 |
|
192 |
}//namespace ns3 |
193 |
|
194 |
#ifdef RUN_SELF_TESTS |
195 |
|
196 |
#include "test.h" |
197 |
#include "object-factory.h" |
198 |
|
199 |
namespace { |
200 |
|
201 |
class TestObject : public ns3::Object |
202 |
{ |
203 |
public: |
204 |
static ns3::TypeId GetTypeId (void) |
205 |
{ |
206 |
static ns3::TypeId tid = ns3::TypeId ("TestObject") |
207 |
.SetParent (Object::GetTypeId ()) |
208 |
.HideFromDocumentation () |
209 |
.AddConstructor<TestObject> (); |
210 |
return tid; |
211 |
} |
212 |
TestObject () {} |
213 |
virtual void Dispose (void) {} |
214 |
}; |
215 |
|
216 |
class FakeTestObject : public ns3::Object |
217 |
{ |
218 |
public: |
219 |
static ns3::TypeId GetTypeId (void) |
220 |
{ |
221 |
static ns3::TypeId tid = ns3::TypeId ("FaleTestObject") |
222 |
.SetParent (Object::GetTypeId ()) |
223 |
.HideFromDocumentation () |
224 |
.AddConstructor<TestObject> (); |
225 |
return tid; |
226 |
} |
227 |
FakeTestObject () {} |
228 |
virtual void Dispose (void) {} |
229 |
}; |
230 |
|
231 |
} // namespace anonymous |
232 |
|
233 |
namespace ns3 { |
234 |
|
235 |
class NameListTest : public Test |
236 |
{ |
237 |
public: |
238 |
NameListTest (); |
239 |
virtual bool RunTests (void); |
240 |
}; |
241 |
|
242 |
NameListTest::NameListTest () |
243 |
: Test ("NameList") |
244 |
{ |
245 |
} |
246 |
|
247 |
bool |
248 |
NameListTest::RunTests (void) |
249 |
{ |
250 |
bool result = true; |
251 |
|
252 |
std::string name1 = "Test Object 1"; |
253 |
Ptr<TestObject> obj1 = CreateObject<TestObject> (); |
254 |
|
255 |
result = NameList::Add (obj1, name1); |
256 |
NS_TEST_ASSERT_EQUAL (result, true); |
257 |
|
258 |
result = NameList::Add (obj1, name1); |
259 |
NS_TEST_ASSERT_EQUAL (result, false); |
260 |
|
261 |
std::string name2 = "Test Object 2"; |
262 |
Ptr<TestObject> obj2 = CreateObject<TestObject> (); |
263 |
|
264 |
result = NameList::Add (obj2, name2); |
265 |
NS_TEST_ASSERT_EQUAL (result, true); |
266 |
|
267 |
Ptr<TestObject> obj = NameList::GetObjectOfName<TestObject> (name1); |
268 |
NS_TEST_ASSERT_EQUAL (obj, obj1); |
269 |
|
270 |
Ptr<FakeTestObject> fobj = NameList::GetObjectOfName<FakeTestObject> (name1); |
271 |
NS_TEST_ASSERT_EQUAL (fobj, 0); |
272 |
|
273 |
obj = NameList::GetObjectOfName<TestObject> (name2); |
274 |
NS_TEST_ASSERT_EQUAL (obj, obj2); |
275 |
|
276 |
obj = NameList::GetObjectOfName<TestObject> ("yadda"); |
277 |
NS_TEST_ASSERT_EQUAL (obj, 0); |
278 |
|
279 |
// |
280 |
// Run the simulator and destroy it to get the Destroy method called on the |
281 |
// private implementation object. We don't hack in a way here to get access |
282 |
// to the raw pointer and assert that it is zeroed since taht really doesn't |
283 |
// tell us that the memory allcated during the tests has successfully been |
284 |
// released. Instead we depend on seeing a valgrind-clean run of the unit |
285 |
// tests to really determine if the clean up was successful. |
286 |
// |
287 |
Simulator::Run (); |
288 |
Simulator::Destroy (); |
289 |
|
290 |
return result; |
291 |
} |
292 |
|
293 |
static NameListTest g_nameListTests; |
294 |
|
295 |
} // namespace ns3 |
296 |
|
297 |
#endif /* RUN_SELF_TESTS */ |