A Discrete-Event Network Simulator
API
object.cc
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2007 INRIA, Gustavo Carneiro
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License version 2 as
6  * published by the Free Software Foundation;
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16  *
17  * Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
18  * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
19  */
20 
21 #include "object.h"
22 
23 #include "assert.h"
24 #include "attribute.h"
25 #include "log.h"
26 #include "object-factory.h"
27 #include "string.h"
28 
29 #include <cstdlib>
30 #include <cstring>
31 #include <sstream>
32 #include <vector>
33 
40 namespace ns3
41 {
42 
43 NS_LOG_COMPONENT_DEFINE("Object");
44 
45 /*********************************************************************
46  * The Object implementation
47  *********************************************************************/
48 
50 
52  : m_object(nullptr),
53  m_current(0)
54 {
55  NS_LOG_FUNCTION(this);
56 }
57 
58 bool
60 {
61  NS_LOG_FUNCTION(this);
62  return m_current < m_object->m_aggregates->n;
63 }
64 
67 {
68  NS_LOG_FUNCTION(this);
69  Object* object = m_object->m_aggregates->buffer[m_current];
70  m_current++;
71  return object;
72 }
73 
75  : m_object(object),
76  m_current(0)
77 {
78  NS_LOG_FUNCTION(this << object);
79 }
80 
81 TypeId
83 {
84  NS_LOG_FUNCTION(this);
85  return m_tid;
86 }
87 
88 TypeId
90 {
91  static TypeId tid = TypeId("ns3::Object").SetParent<ObjectBase>().SetGroupName("Core");
92  return tid;
93 }
94 
96  : m_tid(Object::GetTypeId()),
97  m_disposed(false),
98  m_initialized(false),
99  m_aggregates((Aggregates*)std::malloc(sizeof(Aggregates))),
101 {
102  NS_LOG_FUNCTION(this);
103  m_aggregates->n = 1;
104  m_aggregates->buffer[0] = this;
105 }
106 
108 {
109  // remove this object from the aggregate list
110  NS_LOG_FUNCTION(this);
111  uint32_t n = m_aggregates->n;
112  for (uint32_t i = 0; i < n; i++)
113  {
114  Object* current = m_aggregates->buffer[i];
115  if (current == this)
116  {
117  std::memmove(&m_aggregates->buffer[i],
118  &m_aggregates->buffer[i + 1],
119  sizeof(Object*) * (m_aggregates->n - (i + 1)));
120  m_aggregates->n--;
121  }
122  }
123  // finally, if all objects have been removed from the list,
124  // delete the aggregate list
125  if (m_aggregates->n == 0)
126  {
127  std::free(m_aggregates);
128  }
129  m_aggregates = nullptr;
130 }
131 
133  : m_tid(o.m_tid),
134  m_disposed(false),
135  m_initialized(false),
136  m_aggregates((Aggregates*)std::malloc(sizeof(Aggregates))),
137  m_getObjectCount(0)
138 {
139  m_aggregates->n = 1;
140  m_aggregates->buffer[0] = this;
141 }
142 
143 void
145 {
146  NS_LOG_FUNCTION(this << &attributes);
147  ConstructSelf(attributes);
148 }
149 
152 {
153  NS_LOG_FUNCTION(this << tid);
155 
156  uint32_t n = m_aggregates->n;
157  TypeId objectTid = Object::GetTypeId();
158  for (uint32_t i = 0; i < n; i++)
159  {
160  Object* current = m_aggregates->buffer[i];
161  TypeId cur = current->GetInstanceTypeId();
162  while (cur != tid && cur != objectTid)
163  {
164  cur = cur.GetParent();
165  }
166  if (cur == tid)
167  {
168  // This is an attempt to 'cache' the result of this lookup.
169  // the idea is that if we perform a lookup for a TypeId on this object,
170  // we are likely to perform the same lookup later so, we make sure
171  // that the aggregate array is sorted by the number of accesses
172  // to each object.
173 
174  // first, increment the access count
175  current->m_getObjectCount++;
176  // then, update the sort
178  // finally, return the match
179  return const_cast<Object*>(current);
180  }
181  }
182  return nullptr;
183 }
184 
185 void
187 {
196  NS_LOG_FUNCTION(this);
197 restart:
198  uint32_t n = m_aggregates->n;
199  for (uint32_t i = 0; i < n; i++)
200  {
201  Object* current = m_aggregates->buffer[i];
202  if (!current->m_initialized)
203  {
204  current->DoInitialize();
205  current->m_initialized = true;
206  goto restart;
207  }
208  }
209 }
210 
211 bool
213 {
214  NS_LOG_FUNCTION(this);
215  return m_initialized;
216 }
217 
218 void
220 {
229  NS_LOG_FUNCTION(this);
230 restart:
231  uint32_t n = m_aggregates->n;
232  for (uint32_t i = 0; i < n; i++)
233  {
234  Object* current = m_aggregates->buffer[i];
235  if (!current->m_disposed)
236  {
237  current->DoDispose();
238  current->m_disposed = true;
239  goto restart;
240  }
241  }
242 }
243 
244 void
245 Object::UpdateSortedArray(Aggregates* aggregates, uint32_t j) const
246 {
247  NS_LOG_FUNCTION(this << aggregates << j);
248  while (j > 0 &&
249  aggregates->buffer[j]->m_getObjectCount > aggregates->buffer[j - 1]->m_getObjectCount)
250  {
251  Object* tmp = aggregates->buffer[j - 1];
252  aggregates->buffer[j - 1] = aggregates->buffer[j];
253  aggregates->buffer[j] = tmp;
254  j--;
255  }
256 }
257 
258 void
260 {
261  NS_LOG_FUNCTION(this << o);
263  NS_ASSERT(!o->m_disposed);
265  NS_ASSERT(o->CheckLoose());
266 
267  Object* other = PeekPointer(o);
268  // first create the new aggregate buffer.
269  uint32_t total = m_aggregates->n + other->m_aggregates->n;
270  auto aggregates = (Aggregates*)std::malloc(sizeof(Aggregates) + (total - 1) * sizeof(Object*));
271  aggregates->n = total;
272 
273  // copy our buffer to the new buffer
274  std::memcpy(&aggregates->buffer[0],
275  &m_aggregates->buffer[0],
276  m_aggregates->n * sizeof(Object*));
277 
278  // append the other buffer into the new buffer too
279  for (uint32_t i = 0; i < other->m_aggregates->n; i++)
280  {
281  aggregates->buffer[m_aggregates->n + i] = other->m_aggregates->buffer[i];
282  const TypeId typeId = other->m_aggregates->buffer[i]->GetInstanceTypeId();
283  if (DoGetObject(typeId))
284  {
285  NS_FATAL_ERROR("Object::AggregateObject(): "
286  "Multiple aggregation of objects of type "
287  << other->GetInstanceTypeId() << " on objects of type " << typeId);
288  }
289  UpdateSortedArray(aggregates, m_aggregates->n + i);
290  }
291 
292  // keep track of the old aggregate buffers for the iteration
293  // of NotifyNewAggregates
295  Aggregates* b = other->m_aggregates;
296 
297  // Then, assign the new aggregation buffer to every object
298  uint32_t n = aggregates->n;
299  for (uint32_t i = 0; i < n; i++)
300  {
301  Object* current = aggregates->buffer[i];
302  current->m_aggregates = aggregates;
303  }
304 
305  // Finally, call NotifyNewAggregate on all the objects aggregates together.
306  // We purposely use the old aggregate buffers to iterate over the objects
307  // because this allows us to assume that they will not change from under
308  // our feet, even if our users call AggregateObject from within their
309  // NotifyNewAggregate method.
310  for (uint32_t i = 0; i < a->n; i++)
311  {
312  Object* current = a->buffer[i];
313  current->NotifyNewAggregate();
314  }
315  for (uint32_t i = 0; i < b->n; i++)
316  {
317  Object* current = b->buffer[i];
318  current->NotifyNewAggregate();
319  }
320 
321  // Now that we are done with them, we can free our old aggregate buffers
322  std::free(a);
323  std::free(b);
324 }
325 
330 void
332 {
333  NS_LOG_FUNCTION(this);
334 }
335 
338 {
339  NS_LOG_FUNCTION(this);
340  return AggregateIterator(this);
341 }
342 
343 void
345 {
346  NS_LOG_FUNCTION(this << tid);
347  NS_ASSERT(Check());
348  m_tid = tid;
349 }
350 
351 void
353 {
354  NS_LOG_FUNCTION(this);
356 }
357 
358 void
360 {
361  NS_LOG_FUNCTION(this);
363 }
364 
365 bool
367 {
368  NS_LOG_FUNCTION(this);
369  return (GetReferenceCount() > 0);
370 }
371 
372 /* In some cases, when an event is scheduled against a subclass of
373  * Object, and if no one owns a reference directly to this object, the
374  * object is alive, has a refcount of zero and the method ran when the
375  * event expires runs against the raw pointer which means that we are
376  * manipulating an object with a refcount of zero. So, instead we
377  * check the aggregate reference count.
378  */
379 bool
381 {
382  NS_LOG_FUNCTION(this);
383  bool nonZeroRefCount = false;
384  uint32_t n = m_aggregates->n;
385  for (uint32_t i = 0; i < n; i++)
386  {
387  Object* current = m_aggregates->buffer[i];
388  if (current->GetReferenceCount())
389  {
390  nonZeroRefCount = true;
391  break;
392  }
393  }
394  return nonZeroRefCount;
395 }
396 
397 void
399 {
400  // check if we really need to die
401  NS_LOG_FUNCTION(this);
402  for (uint32_t i = 0; i < m_aggregates->n; i++)
403  {
404  Object* current = m_aggregates->buffer[i];
405  if (current->GetReferenceCount() > 0)
406  {
407  return;
408  }
409  }
410 
411  // Now, we know that we are alone to use this aggregate so,
412  // we can dispose and delete everything safely.
413 
414  uint32_t n = m_aggregates->n;
415  // Ensure we are disposed.
416  for (uint32_t i = 0; i < n; i++)
417  {
418  Object* current = m_aggregates->buffer[i];
419  if (!current->m_disposed)
420  {
421  current->DoDispose();
422  }
423  }
424 
425  // Now, actually delete all objects
426  Aggregates* aggregates = m_aggregates;
427  for (uint32_t i = 0; i < n; i++)
428  {
429  // There is a trick here: each time we call delete below,
430  // the deleted object is removed from the aggregate buffer
431  // in the destructor so, the index of the next element to
432  // lookup is always zero
433  Object* current = aggregates->buffer[0];
434  delete current;
435  }
436 }
437 } // namespace ns3
NS_ASSERT() and NS_ASSERT_MSG() macro definitions.
ns3::AttributeValue, ns3::AttributeAccessor and ns3::AttributeChecker declarations.
List of Attribute name, value and checker triples used to construct Objects.
Iterate over the Objects aggregated to an ns3::Object.
Definition: object.h:106
Ptr< const Object > Next()
Get the next Aggregated Object.
Definition: object.cc:66
AggregateIterator()
Default constructor, which has no Object.
Definition: object.cc:51
bool HasNext() const
Check if there are more Aggregates to iterate over.
Definition: object.cc:59
Anchor the ns-3 type and attribute system.
Definition: object-base.h:173
void ConstructSelf(const AttributeConstructionList &attributes)
Complete construction of ObjectBase; invoked by derived classes.
Definition: object-base.cc:85
A base class which provides memory management and object aggregation.
Definition: object.h:89
Aggregates * m_aggregates
A pointer to an array of 'aggregates'.
Definition: object.h:438
void Initialize()
Invoke DoInitialize on all Objects aggregated to this one.
Definition: object.cc:186
void UpdateSortedArray(Aggregates *aggregates, uint32_t i) const
Keep the list of aggregates in most-recently-used order.
Definition: object.cc:245
void Construct(const AttributeConstructionList &attributes)
Initialize all member variables registered as Attributes of this TypeId.
Definition: object.cc:144
bool Check() const
Verify that this Object is still live, by checking it's reference count.
Definition: object.cc:366
Ptr< Object > DoGetObject(TypeId tid) const
Find an Object of TypeId tid in the aggregates of this Object.
Definition: object.cc:151
friend class AggregateIterator
Friends.
Definition: object.h:329
bool m_disposed
Set to true when the DoDispose() method of the Object has run, false otherwise.
Definition: object.h:425
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:331
bool CheckLoose() const
Check if any aggregated Objects have non-zero reference counts.
Definition: object.cc:380
~Object() override
Destructor.
Definition: object.cc:107
AggregateIterator GetAggregateIterator() const
Get an iterator to the Objects aggregated to this one.
Definition: object.cc:337
virtual void DoInitialize()
Initialize() implementation.
Definition: object.cc:359
void SetTypeId(TypeId tid)
Set the TypeId of this Object.
Definition: object.cc:344
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition: object.cc:259
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
Definition: object.cc:82
static TypeId GetTypeId()
Register this type.
Definition: object.cc:89
void Dispose()
Dispose of this Object.
Definition: object.cc:219
TypeId m_tid
Identifies the type of this Object instance.
Definition: object.h:420
Object()
Constructor.
Definition: object.cc:95
virtual void DoDispose()
Destructor implementation.
Definition: object.cc:352
bool IsInitialized() const
Check if the object has been initialized.
Definition: object.cc:212
uint32_t m_getObjectCount
The number of times the Object was accessed with a call to GetObject().
Definition: object.h:446
void DoDelete()
Attempt to delete this Object.
Definition: object.cc:398
bool m_initialized
Set to true once the DoInitialize() method has run, false otherwise.
Definition: object.h:430
Smart pointer class similar to boost::intrusive_ptr.
Definition: ptr.h:77
uint32_t GetReferenceCount() const
Get the reference count of the object.
a unique identifier for an interface.
Definition: type-id.h:59
TypeId GetParent() const
Get the parent of this TypeId.
Definition: type-id.cc:955
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:931
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition: assert.h:66
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
Definition: fatal-error.h:179
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition: log.h:202
#define NS_LOG_FUNCTION(parameters)
If log level LOG_FUNCTION is enabled, this macro will output all input parameters separated by ",...
#define NS_OBJECT_ENSURE_REGISTERED(type)
Register an Object subclass with the TypeId system.
Definition: object-base.h:46
Debug message logging.
Every class exported by the ns3 library is enclosed in the ns3 namespace.
U * PeekPointer(const Ptr< U > &p)
Definition: ptr.h:449
ns3::ObjectFactory class declaration.
ns3::Object class declaration, which is the root of the Object hierarchy and Aggregation.
ns3::StringValue attribute value declarations.
The list of Objects aggregated to this one.
Definition: object.h:347
uint32_t n
The number of entries in buffer.
Definition: object.h:349
Object * buffer[1]
The array of Objects.
Definition: object.h:351