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((struct Aggregates*)std::malloc(sizeof(struct 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((struct Aggregates*)std::malloc(sizeof(struct 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(struct 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  struct Aggregates* aggregates =
271  (struct Aggregates*)std::malloc(sizeof(struct Aggregates) + (total - 1) * sizeof(Object*));
272  aggregates->n = total;
273 
274  // copy our buffer to the new buffer
275  std::memcpy(&aggregates->buffer[0],
276  &m_aggregates->buffer[0],
277  m_aggregates->n * sizeof(Object*));
278 
279  // append the other buffer into the new buffer too
280  for (uint32_t i = 0; i < other->m_aggregates->n; i++)
281  {
282  aggregates->buffer[m_aggregates->n + i] = other->m_aggregates->buffer[i];
283  const TypeId typeId = other->m_aggregates->buffer[i]->GetInstanceTypeId();
284  if (DoGetObject(typeId))
285  {
286  NS_FATAL_ERROR("Object::AggregateObject(): "
287  "Multiple aggregation of objects of type "
288  << other->GetInstanceTypeId() << " on objects of type " << typeId);
289  }
290  UpdateSortedArray(aggregates, m_aggregates->n + i);
291  }
292 
293  // keep track of the old aggregate buffers for the iteration
294  // of NotifyNewAggregates
295  struct Aggregates* a = m_aggregates;
296  struct Aggregates* b = other->m_aggregates;
297 
298  // Then, assign the new aggregation buffer to every object
299  uint32_t n = aggregates->n;
300  for (uint32_t i = 0; i < n; i++)
301  {
302  Object* current = aggregates->buffer[i];
303  current->m_aggregates = aggregates;
304  }
305 
306  // Finally, call NotifyNewAggregate on all the objects aggregates together.
307  // We purposely use the old aggregate buffers to iterate over the objects
308  // because this allows us to assume that they will not change from under
309  // our feet, even if our users call AggregateObject from within their
310  // NotifyNewAggregate method.
311  for (uint32_t i = 0; i < a->n; i++)
312  {
313  Object* current = a->buffer[i];
314  current->NotifyNewAggregate();
315  }
316  for (uint32_t i = 0; i < b->n; i++)
317  {
318  Object* current = b->buffer[i];
319  current->NotifyNewAggregate();
320  }
321 
322  // Now that we are done with them, we can free our old aggregate buffers
323  std::free(a);
324  std::free(b);
325 }
326 
331 void
333 {
334  NS_LOG_FUNCTION(this);
335 }
336 
339 {
340  NS_LOG_FUNCTION(this);
341  return AggregateIterator(this);
342 }
343 
344 void
346 {
347  NS_LOG_FUNCTION(this << tid);
348  NS_ASSERT(Check());
349  m_tid = tid;
350 }
351 
352 void
354 {
355  NS_LOG_FUNCTION(this);
357 }
358 
359 void
361 {
362  NS_LOG_FUNCTION(this);
364 }
365 
366 bool
368 {
369  NS_LOG_FUNCTION(this);
370  return (GetReferenceCount() > 0);
371 }
372 
373 /* In some cases, when an event is scheduled against a subclass of
374  * Object, and if no one owns a reference directly to this object, the
375  * object is alive, has a refcount of zero and the method ran when the
376  * event expires runs against the raw pointer which means that we are
377  * manipulating an object with a refcount of zero. So, instead we
378  * check the aggregate reference count.
379  */
380 bool
382 {
383  NS_LOG_FUNCTION(this);
384  bool nonZeroRefCount = false;
385  uint32_t n = m_aggregates->n;
386  for (uint32_t i = 0; i < n; i++)
387  {
388  Object* current = m_aggregates->buffer[i];
389  if (current->GetReferenceCount())
390  {
391  nonZeroRefCount = true;
392  break;
393  }
394  }
395  return nonZeroRefCount;
396 }
397 
398 void
400 {
401  // check if we really need to die
402  NS_LOG_FUNCTION(this);
403  for (uint32_t i = 0; i < m_aggregates->n; i++)
404  {
405  Object* current = m_aggregates->buffer[i];
406  if (current->GetReferenceCount() > 0)
407  {
408  return;
409  }
410  }
411 
412  // Now, we know that we are alone to use this aggregate so,
413  // we can dispose and delete everything safely.
414 
415  uint32_t n = m_aggregates->n;
416  // Ensure we are disposed.
417  for (uint32_t i = 0; i < n; i++)
418  {
419  Object* current = m_aggregates->buffer[i];
420  if (!current->m_disposed)
421  {
422  current->DoDispose();
423  }
424  }
425 
426  // Now, actually delete all objects
427  struct Aggregates* aggregates = m_aggregates;
428  for (uint32_t i = 0; i < n; i++)
429  {
430  // There is a trick here: each time we call delete below,
431  // the deleted object is removed from the aggregate buffer
432  // in the destructor so, the index of the next element to
433  // lookup is always zero
434  Object* current = aggregates->buffer[0];
435  delete current;
436  }
437 }
438 } // 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:81
A base class which provides memory management and object aggregation.
Definition: object.h:89
void Initialize()
Invoke DoInitialize on all Objects aggregated to this one.
Definition: object.cc:186
struct Aggregates * m_aggregates
A pointer to an array of 'aggregates'.
Definition: object.h:438
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:367
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
void UpdateSortedArray(struct Aggregates *aggregates, uint32_t i) const
Keep the list of aggregates in most-recently-used order.
Definition: object.cc:245
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition: object.cc:332
bool CheckLoose() const
Check if any aggregated Objects have non-zero reference counts.
Definition: object.cc:381
~Object() override
Destructor.
Definition: object.cc:107
AggregateIterator GetAggregateIterator() const
Get an iterator to the Objects aggregated to this one.
Definition: object.cc:338
virtual void DoInitialize()
Initialize() implementation.
Definition: object.cc:360
void SetTypeId(TypeId tid)
Set the TypeId of this Object.
Definition: object.cc:345
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:353
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:399
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:78
uint32_t GetReferenceCount() const
Get the reference count of the object.
a unique identifier for an interface.
Definition: type-id.h:60
TypeId GetParent() const
Get the parent of this TypeId.
Definition: type-id.cc:959
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition: type-id.cc:935
#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:488
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