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 #include "object.h"
22 #include "object-factory.h"
23 #include "assert.h"
24 #include "singleton.h"
25 #include "attribute.h"
26 #include "log.h"
27 #include "string.h"
28 #include <vector>
29 #include <sstream>
30 #include <stdlib.h>
31 #include <string.h>
32 
33 NS_LOG_COMPONENT_DEFINE ("Object");
34 
35 namespace ns3 {
36 
37 /*********************************************************************
38  * The Object implementation
39  *********************************************************************/
40 
42 
44  : m_object (0),
45  m_current (0)
46 {
47 }
48 
49 bool
51 {
52  return m_current < m_object->m_aggregates->n;
53 }
56 {
57  Object *object = m_object->m_aggregates->buffer[m_current];
58  m_current++;
59  return object;
60 }
62  : m_object (object),
63  m_current (0)
64 {
65 }
66 
67 
68 TypeId
70 {
71  return m_tid;
72 }
73 
74 TypeId
76 {
77  static TypeId tid = TypeId ("ns3::Object")
79  ;
80  return tid;
81 }
82 
83 
85  : m_tid (Object::GetTypeId ()),
86  m_disposed (false),
87  m_started (false),
88  m_aggregates ((struct Aggregates *) malloc (sizeof (struct Aggregates))),
90 {
91  m_aggregates->n = 1;
92  m_aggregates->buffer[0] = this;
93 }
95 {
96  // remove this object from the aggregate list
97  uint32_t n = m_aggregates->n;
98  for (uint32_t i = 0; i < n; i++)
99  {
100  Object *current = m_aggregates->buffer[i];
101  if (current == this)
102  {
103  memmove (&m_aggregates->buffer[i],
104  &m_aggregates->buffer[i+1],
105  sizeof (Object *)*(m_aggregates->n - (i+1)));
106  m_aggregates->n--;
107  }
108  }
109  // finally, if all objects have been removed from the list,
110  // delete the aggregate list
111  if (m_aggregates->n == 0)
112  {
113  free (m_aggregates);
114  }
115  m_aggregates = 0;
116 }
118  : m_tid (o.m_tid),
119  m_disposed (false),
120  m_started (false),
121  m_aggregates ((struct Aggregates *) malloc (sizeof (struct Aggregates))),
122  m_getObjectCount (0)
123 {
124  m_aggregates->n = 1;
125  m_aggregates->buffer[0] = this;
126 }
127 void
129 {
130  ConstructSelf (attributes);
131 }
132 
135 {
136  NS_ASSERT (CheckLoose ());
137 
138  uint32_t n = m_aggregates->n;
139  TypeId objectTid = Object::GetTypeId ();
140  for (uint32_t i = 0; i < n; i++)
141  {
142  Object *current = m_aggregates->buffer[i];
143  TypeId cur = current->GetInstanceTypeId ();
144  while (cur != tid && cur != objectTid)
145  {
146  cur = cur.GetParent ();
147  }
148  if (cur == tid)
149  {
150  // This is an attempt to 'cache' the result of this lookup.
151  // the idea is that if we perform a lookup for a TypeId on this object,
152  // we are likely to perform the same lookup later so, we make sure
153  // that the aggregate array is sorted by the number of accesses
154  // to each object.
155 
156  // first, increment the access count
157  current->m_getObjectCount++;
158  // then, update the sort
160  // finally, return the match
161  return const_cast<Object *> (current);
162  }
163  }
164  return 0;
165 }
166 void
168 {
177 restart:
178  uint32_t n = m_aggregates->n;
179  for (uint32_t i = 0; i < n; i++)
180  {
181  Object *current = m_aggregates->buffer[i];
182  if (!current->m_started)
183  {
184  current->DoStart ();
185  current->m_started = true;
186  goto restart;
187  }
188  }
189 }
190 void
192 {
201 restart:
202  uint32_t n = m_aggregates->n;
203  for (uint32_t i = 0; i < n; i++)
204  {
205  Object *current = m_aggregates->buffer[i];
206  if (!current->m_disposed)
207  {
208  current->DoDispose ();
209  current->m_disposed = true;
210  goto restart;
211  }
212  }
213 }
214 void
215 Object::UpdateSortedArray (struct Aggregates *aggregates, uint32_t j) const
216 {
217  while (j > 0 &&
218  aggregates->buffer[j]->m_getObjectCount > aggregates->buffer[j-1]->m_getObjectCount)
219  {
220  Object *tmp = aggregates->buffer[j-1];
221  aggregates->buffer[j-1] = aggregates->buffer[j];
222  aggregates->buffer[j] = tmp;
223  j--;
224  }
225 }
226 void
228 {
230  NS_ASSERT (!o->m_disposed);
231  NS_ASSERT (CheckLoose ());
232  NS_ASSERT (o->CheckLoose ());
233 
234  if (DoGetObject (o->GetInstanceTypeId ()))
235  {
236  NS_FATAL_ERROR ("Object::AggregateObject(): "
237  "Multiple aggregation of objects of type " <<
238  o->GetInstanceTypeId ().GetName ());
239  }
240 
241  Object *other = PeekPointer (o);
242  // first create the new aggregate buffer.
243  uint32_t total = m_aggregates->n + other->m_aggregates->n;
244  struct Aggregates *aggregates =
245  (struct Aggregates *)malloc (sizeof(struct Aggregates)+(total-1)*sizeof(Object*));
246  aggregates->n = total;
247 
248  // copy our buffer to the new buffer
249  memcpy (&aggregates->buffer[0],
250  &m_aggregates->buffer[0],
251  m_aggregates->n*sizeof(Object*));
252 
253  // append the other buffer into the new buffer too
254  for (uint32_t i = 0; i < other->m_aggregates->n; i++)
255  {
256  aggregates->buffer[m_aggregates->n+i] = other->m_aggregates->buffer[i];
257  UpdateSortedArray (aggregates, m_aggregates->n + i);
258  }
259 
260  // keep track of the old aggregate buffers for the iteration
261  // of NotifyNewAggregates
262  struct Aggregates *a = m_aggregates;
263  struct Aggregates *b = other->m_aggregates;
264 
265  // Then, assign the new aggregation buffer to every object
266  uint32_t n = aggregates->n;
267  for (uint32_t i = 0; i < n; i++)
268  {
269  Object *current = aggregates->buffer[i];
270  current->m_aggregates = aggregates;
271  }
272 
273  // Finally, call NotifyNewAggregate on all the objects aggregates together.
274  // We purposedly use the old aggregate buffers to iterate over the objects
275  // because this allows us to assume that they will not change from under
276  // our feet, even if our users call AggregateObject from within their
277  // NotifyNewAggregate method.
278  for (uint32_t i = 0; i < a->n; i++)
279  {
280  Object *current = a->buffer[i];
281  current->NotifyNewAggregate ();
282  }
283  for (uint32_t i = 0; i < b->n; i++)
284  {
285  Object *current = b->buffer[i];
286  current->NotifyNewAggregate ();
287  }
288 
289  // Now that we are done with them, we can free our old aggregate buffers
290  free (a);
291  free (b);
292 }
297 void
299 {
300 
301 }
302 
305 {
306  return AggregateIterator (this);
307 }
308 
309 void
311 {
312  NS_ASSERT (Check ());
313  m_tid = tid;
314 }
315 
316 void
318 {
320 }
321 
322 void
324 {
325  NS_ASSERT (!m_started);
326 }
327 
328 bool
329 Object::Check (void) const
330 {
331  return (GetReferenceCount () > 0);
332 }
333 
334 /* In some cases, when an event is scheduled against a subclass of
335  * Object, and if no one owns a reference directly to this object, the
336  * object is alive, has a refcount of zero and the method ran when the
337  * event expires runs against the raw pointer which means that we are
338  * manipulating an object with a refcount of zero. So, instead we
339  * check the aggregate reference count.
340  */
341 bool
342 Object::CheckLoose (void) const
343 {
344  uint32_t refcount = 0;
345  uint32_t n = m_aggregates->n;
346  for (uint32_t i = 0; i < n; i++)
347  {
348  Object *current = m_aggregates->buffer[i];
349  refcount += current->GetReferenceCount ();
350  }
351  return (refcount > 0);
352 }
353 void
355 {
356  // check if we really need to die
357  for (uint32_t i = 0; i < m_aggregates->n; i++)
358  {
359  Object *current = m_aggregates->buffer[i];
360  if (current->GetReferenceCount () > 0)
361  {
362  return;
363  }
364  }
365 
366  // Now, we know that we are alone to use this aggregate so,
367  // we can dispose and delete everything safely.
368 
369  uint32_t n = m_aggregates->n;
370  // Ensure we are disposed.
371  for (uint32_t i = 0; i < n; i++)
372  {
373  Object *current = m_aggregates->buffer[i];
374  if (!current->m_disposed)
375  {
376  current->DoDispose ();
377  }
378  }
379 
380  // Now, actually delete all objects
381  struct Aggregates *aggregates = m_aggregates;
382  for (uint32_t i = 0; i < n; i++)
383  {
384  // There is a trick here: each time we call delete below,
385  // the deleted object is removed from the aggregate buffer
386  // in the destructor so, the index of the next element to
387  // lookup is always zero
388  Object *current = aggregates->buffer[0];
389  delete current;
390  }
391 }
392 } // namespace ns3
393