A Discrete-Event Network Simulator
API
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
object.cc
Go to the documentation of this file.
1 /* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2 /*
3  * Copyright (c) 2007 INRIA, Gustavo Carneiro
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  * Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
19  * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
20  */
21 
22 #include "object.h"
23 #include "object-factory.h"
24 #include "assert.h"
25 #include "singleton.h"
26 #include "attribute.h"
27 #include "log.h"
28 #include "string.h"
29 #include <vector>
30 #include <sstream>
31 #include <cstdlib>
32 #include <cstring>
33 
34 
35 
36 NS_LOG_COMPONENT_DEFINE ("Object");
37 
38 namespace ns3 {
39 
40 /*********************************************************************
41  * The Object implementation
42  *********************************************************************/
43 
45 
47  : m_object (0),
48  m_current (0)
49 {
50  NS_LOG_FUNCTION (this);
51 }
52 
53 bool
55 {
56  NS_LOG_FUNCTION (this);
57  return m_current < m_object->m_aggregates->n;
58 }
61 {
62  NS_LOG_FUNCTION (this);
63  Object *object = m_object->m_aggregates->buffer[m_current];
64  m_current++;
65  return object;
66 }
68  : m_object (object),
69  m_current (0)
70 {
71  NS_LOG_FUNCTION (this << object);
72 }
73 
74 
75 TypeId
77 {
78  NS_LOG_FUNCTION (this);
79  return m_tid;
80 }
81 
82 TypeId
84 {
85  static TypeId tid = TypeId ("ns3::Object")
87  ;
88  return tid;
89 }
90 
91 
93  : m_tid (Object::GetTypeId ()),
94  m_disposed (false),
95  m_started (false),
96  m_aggregates ((struct Aggregates *) std::malloc (sizeof (struct Aggregates))),
98 {
99  NS_LOG_FUNCTION (this);
100  m_aggregates->n = 1;
101  m_aggregates->buffer[0] = this;
102 }
104 {
105  // remove this object from the aggregate list
106  NS_LOG_FUNCTION (this);
107  uint32_t n = m_aggregates->n;
108  for (uint32_t i = 0; i < n; i++)
109  {
110  Object *current = m_aggregates->buffer[i];
111  if (current == this)
112  {
113  std::memmove (&m_aggregates->buffer[i],
114  &m_aggregates->buffer[i+1],
115  sizeof (Object *)*(m_aggregates->n - (i+1)));
116  m_aggregates->n--;
117  }
118  }
119  // finally, if all objects have been removed from the list,
120  // delete the aggregate list
121  if (m_aggregates->n == 0)
122  {
123  std::free (m_aggregates);
124  }
125  m_aggregates = 0;
126 }
128  : m_tid (o.m_tid),
129  m_disposed (false),
130  m_started (false),
131  m_aggregates ((struct Aggregates *) std::malloc (sizeof (struct Aggregates))),
132  m_getObjectCount (0)
133 {
134  m_aggregates->n = 1;
135  m_aggregates->buffer[0] = this;
136 }
137 void
139 {
140  NS_LOG_FUNCTION (this << &attributes);
141  ConstructSelf (attributes);
142 }
143 
146 {
147  NS_LOG_FUNCTION (this << tid);
148  NS_ASSERT (CheckLoose ());
149 
150  uint32_t n = m_aggregates->n;
151  TypeId objectTid = Object::GetTypeId ();
152  for (uint32_t i = 0; i < n; i++)
153  {
154  Object *current = m_aggregates->buffer[i];
155  TypeId cur = current->GetInstanceTypeId ();
156  while (cur != tid && cur != objectTid)
157  {
158  cur = cur.GetParent ();
159  }
160  if (cur == tid)
161  {
162  // This is an attempt to 'cache' the result of this lookup.
163  // the idea is that if we perform a lookup for a TypeId on this object,
164  // we are likely to perform the same lookup later so, we make sure
165  // that the aggregate array is sorted by the number of accesses
166  // to each object.
167 
168  // first, increment the access count
169  current->m_getObjectCount++;
170  // then, update the sort
172  // finally, return the match
173  return const_cast<Object *> (current);
174  }
175  }
176  return 0;
177 }
178 void
180 {
189  NS_LOG_FUNCTION (this);
190 restart:
191  uint32_t n = m_aggregates->n;
192  for (uint32_t i = 0; i < n; i++)
193  {
194  Object *current = m_aggregates->buffer[i];
195  if (!current->m_started)
196  {
197  current->DoStart ();
198  current->m_started = true;
199  goto restart;
200  }
201  }
202 }
203 void
205 {
214  NS_LOG_FUNCTION (this);
215 restart:
216  uint32_t n = m_aggregates->n;
217  for (uint32_t i = 0; i < n; i++)
218  {
219  Object *current = m_aggregates->buffer[i];
220  if (!current->m_disposed)
221  {
222  current->DoDispose ();
223  current->m_disposed = true;
224  goto restart;
225  }
226  }
227 }
228 void
229 Object::UpdateSortedArray (struct Aggregates *aggregates, uint32_t j) const
230 {
231  NS_LOG_FUNCTION (this << aggregates << j);
232  while (j > 0 &&
233  aggregates->buffer[j]->m_getObjectCount > aggregates->buffer[j-1]->m_getObjectCount)
234  {
235  Object *tmp = aggregates->buffer[j-1];
236  aggregates->buffer[j-1] = aggregates->buffer[j];
237  aggregates->buffer[j] = tmp;
238  j--;
239  }
240 }
241 void
243 {
244  NS_LOG_FUNCTION (this << o);
246  NS_ASSERT (!o->m_disposed);
247  NS_ASSERT (CheckLoose ());
248  NS_ASSERT (o->CheckLoose ());
249 
250  if (DoGetObject (o->GetInstanceTypeId ()))
251  {
252  NS_FATAL_ERROR ("Object::AggregateObject(): "
253  "Multiple aggregation of objects of type " <<
254  o->GetInstanceTypeId ().GetName ());
255  }
256 
257  Object *other = PeekPointer (o);
258  // first create the new aggregate buffer.
259  uint32_t total = m_aggregates->n + other->m_aggregates->n;
260  struct Aggregates *aggregates =
261  (struct Aggregates *)std::malloc (sizeof(struct Aggregates)+(total-1)*sizeof(Object*));
262  aggregates->n = total;
263 
264  // copy our buffer to the new buffer
265  std::memcpy (&aggregates->buffer[0],
266  &m_aggregates->buffer[0],
267  m_aggregates->n*sizeof(Object*));
268 
269  // append the other buffer into the new buffer too
270  for (uint32_t i = 0; i < other->m_aggregates->n; i++)
271  {
272  aggregates->buffer[m_aggregates->n+i] = other->m_aggregates->buffer[i];
273  UpdateSortedArray (aggregates, m_aggregates->n + i);
274  }
275 
276  // keep track of the old aggregate buffers for the iteration
277  // of NotifyNewAggregates
278  struct Aggregates *a = m_aggregates;
279  struct Aggregates *b = other->m_aggregates;
280 
281  // Then, assign the new aggregation buffer to every object
282  uint32_t n = aggregates->n;
283  for (uint32_t i = 0; i < n; i++)
284  {
285  Object *current = aggregates->buffer[i];
286  current->m_aggregates = aggregates;
287  }
288 
289  // Finally, call NotifyNewAggregate on all the objects aggregates together.
290  // We purposedly use the old aggregate buffers to iterate over the objects
291  // because this allows us to assume that they will not change from under
292  // our feet, even if our users call AggregateObject from within their
293  // NotifyNewAggregate method.
294  for (uint32_t i = 0; i < a->n; i++)
295  {
296  Object *current = a->buffer[i];
297  current->NotifyNewAggregate ();
298  }
299  for (uint32_t i = 0; i < b->n; i++)
300  {
301  Object *current = b->buffer[i];
302  current->NotifyNewAggregate ();
303  }
304 
305  // Now that we are done with them, we can free our old aggregate buffers
306  std::free (a);
307  std::free (b);
308 }
313 void
315 {
316  NS_LOG_FUNCTION (this);
317 }
318 
321 {
322  NS_LOG_FUNCTION (this);
323  return AggregateIterator (this);
324 }
325 
326 void
328 {
329  NS_LOG_FUNCTION (this << tid);
330  NS_ASSERT (Check ());
331  m_tid = tid;
332 }
333 
334 void
336 {
337  NS_LOG_FUNCTION (this);
339 }
340 
341 void
343 {
344  NS_LOG_FUNCTION (this);
345  NS_ASSERT (!m_started);
346 }
347 
348 bool
349 Object::Check (void) const
350 {
351  NS_LOG_FUNCTION (this);
352  return (GetReferenceCount () > 0);
353 }
354 
355 /* In some cases, when an event is scheduled against a subclass of
356  * Object, and if no one owns a reference directly to this object, the
357  * object is alive, has a refcount of zero and the method ran when the
358  * event expires runs against the raw pointer which means that we are
359  * manipulating an object with a refcount of zero. So, instead we
360  * check the aggregate reference count.
361  */
362 bool
363 Object::CheckLoose (void) const
364 {
365  NS_LOG_FUNCTION (this);
366  uint32_t refcount = 0;
367  uint32_t n = m_aggregates->n;
368  for (uint32_t i = 0; i < n; i++)
369  {
370  Object *current = m_aggregates->buffer[i];
371  refcount += current->GetReferenceCount ();
372  }
373  return (refcount > 0);
374 }
375 void
377 {
378  // check if we really need to die
379  NS_LOG_FUNCTION (this);
380  for (uint32_t i = 0; i < m_aggregates->n; i++)
381  {
382  Object *current = m_aggregates->buffer[i];
383  if (current->GetReferenceCount () > 0)
384  {
385  return;
386  }
387  }
388 
389  // Now, we know that we are alone to use this aggregate so,
390  // we can dispose and delete everything safely.
391 
392  uint32_t n = m_aggregates->n;
393  // Ensure we are disposed.
394  for (uint32_t i = 0; i < n; i++)
395  {
396  Object *current = m_aggregates->buffer[i];
397  if (!current->m_disposed)
398  {
399  current->DoDispose ();
400  }
401  }
402 
403  // Now, actually delete all objects
404  struct Aggregates *aggregates = m_aggregates;
405  for (uint32_t i = 0; i < n; i++)
406  {
407  // There is a trick here: each time we call delete below,
408  // the deleted object is removed from the aggregate buffer
409  // in the destructor so, the index of the next element to
410  // lookup is always zero
411  Object *current = aggregates->buffer[0];
412  delete current;
413  }
414 }
415 } // namespace ns3
416