A Discrete-Event Network Simulator
API
Loading...
Searching...
No Matches
object.cc
Go to the documentation of this file.
1/*
2 * Copyright (c) 2007 INRIA, Gustavo Carneiro
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 * Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
7 * Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
8 */
9
10#include "object.h"
11
12#include "assert.h"
13#include "attribute.h"
14#include "log.h"
15
16#include <cstdlib>
17#include <cstring>
18#include <vector>
19
20/**
21 * @file
22 * @ingroup object
23 * ns3::Object class implementation.
24 */
25
26namespace ns3
27{
28
30
31/*********************************************************************
32 * The Object implementation
33 *********************************************************************/
34
36
43
44bool
46{
47 NS_LOG_FUNCTION(this);
48 return (m_current < m_object->m_aggregates->n) ||
49 (m_uniAggrIter != m_object->m_unidirectionalAggregates.end());
50}
51
54{
55 NS_LOG_FUNCTION(this);
56 if (m_current < m_object->m_aggregates->n)
57 {
58 Object* object = m_object->m_aggregates->buffer[m_current];
59 m_current++;
60 return object;
61 }
62 else if (m_uniAggrIter != m_object->m_unidirectionalAggregates.end())
63 {
64 auto object = *m_uniAggrIter;
66 return object;
67 }
68 return nullptr;
69}
70
73 m_current(0)
74{
75 NS_LOG_FUNCTION(this << object);
76 m_uniAggrIter = object->m_unidirectionalAggregates.begin();
77}
78
81{
82 NS_LOG_FUNCTION(this);
83 return m_tid;
84}
85
88{
89 static TypeId tid = TypeId("ns3::Object").SetParent<ObjectBase>().SetGroupName("Core");
90 return tid;
91}
92
95 m_disposed(false),
96 m_initialized(false),
97 m_aggregates((Aggregates*)std::malloc(sizeof(Aggregates))),
99{
100 NS_LOG_FUNCTION(this);
101 m_aggregates->n = 1;
102 m_aggregates->buffer[0] = this;
103}
104
106{
107 // remove this object from the aggregate list
108 NS_LOG_FUNCTION(this);
109 uint32_t n = m_aggregates->n;
110 for (uint32_t i = 0; i < n; i++)
111 {
112 Object* current = m_aggregates->buffer[i];
113 if (current == this)
114 {
115 std::memmove(&m_aggregates->buffer[i],
116 &m_aggregates->buffer[i + 1],
117 sizeof(Object*) * (m_aggregates->n - (i + 1)));
118 m_aggregates->n--;
119 }
120 }
121 // finally, if all objects have been removed from the list,
122 // delete the aggregate list
123 if (m_aggregates->n == 0)
124 {
125 std::free(m_aggregates);
126 }
127 m_aggregates = nullptr;
129}
130
132 : m_tid(o.m_tid),
133 m_disposed(false),
134 m_initialized(false),
135 m_aggregates((Aggregates*)std::malloc(sizeof(Aggregates))),
137{
138 m_aggregates->n = 1;
139 m_aggregates->buffer[0] = this;
140}
141
142void
144{
145 NS_LOG_FUNCTION(this << &attributes);
146 ConstructSelf(attributes);
147}
148
151{
152 NS_LOG_FUNCTION(this << tid);
154
155 // First check if the object is in the normal aggregates.
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
183 // Next check if it's a unidirectional aggregate
184 for (auto& uniItem : m_unidirectionalAggregates)
185 {
186 TypeId cur = uniItem->GetInstanceTypeId();
187 while (cur != tid && cur != objectTid)
188 {
189 cur = cur.GetParent();
190 }
191 if (cur == tid)
192 {
193 return uniItem;
194 }
195 }
196 return nullptr;
197}
198
199void
201{
202 /**
203 * Note: the code here is a bit tricky because we need to protect ourselves from
204 * modifications in the aggregate array while DoInitialize is called. The user's
205 * implementation of the DoInitialize method could call GetObject (which could
206 * reorder the array) and it could call AggregateObject which would add an
207 * object at the end of the array. To be safe, we restart iteration over the
208 * array whenever we call some user code, just in case.
209 */
210 NS_LOG_FUNCTION(this);
211restart:
212 uint32_t n = m_aggregates->n;
213 for (uint32_t i = 0; i < n; i++)
214 {
215 Object* current = m_aggregates->buffer[i];
216 if (!current->m_initialized)
217 {
218 current->DoInitialize();
219 current->m_initialized = true;
220 goto restart;
221 }
222 }
223
224 // note: no need to restart because unidirectionally aggregated objects
225 // can not change the status of the actual object.
226 for (auto& uniItem : m_unidirectionalAggregates)
227 {
228 if (!uniItem->m_initialized)
229 {
230 uniItem->DoInitialize();
231 uniItem->m_initialized = true;
232 }
233 }
234}
235
236bool
238{
239 NS_LOG_FUNCTION(this);
240 return m_initialized;
241}
242
243void
245{
246 /**
247 * Note: the code here is a bit tricky because we need to protect ourselves from
248 * modifications in the aggregate array while DoDispose is called. The user's
249 * DoDispose implementation could call GetObject (which could reorder the array)
250 * and it could call AggregateObject which would add an object at the end of the array.
251 * So, to be safe, we restart the iteration over the array whenever we call some
252 * user code.
253 */
254 NS_LOG_FUNCTION(this);
255restart:
256 uint32_t n = m_aggregates->n;
257 for (uint32_t i = 0; i < n; i++)
258 {
259 Object* current = m_aggregates->buffer[i];
260 if (!current->m_disposed)
261 {
262 current->DoDispose();
263 current->m_disposed = true;
264 goto restart;
265 }
266 }
267
268 // note: no need to restart because unidirectionally aggregated objects
269 // can not change the status of the actual object.
270 for (auto& uniItem : m_unidirectionalAggregates)
271 {
272 if (!uniItem->m_disposed && uniItem->GetReferenceCount() == 1)
273 {
274 uniItem->DoDispose();
275 uniItem->m_disposed = true;
276 }
277 }
278}
279
280void
282{
283 NS_LOG_FUNCTION(this << aggregates << j);
284 while (j > 0 &&
285 aggregates->buffer[j]->m_getObjectCount > aggregates->buffer[j - 1]->m_getObjectCount)
286 {
287 Object* tmp = aggregates->buffer[j - 1];
288 aggregates->buffer[j - 1] = aggregates->buffer[j];
289 aggregates->buffer[j] = tmp;
290 j--;
291 }
292}
293
294void
296{
297 NS_LOG_FUNCTION(this << o);
299 NS_ASSERT(!o->m_disposed);
301 NS_ASSERT(o->CheckLoose());
302
303 Object* other = PeekPointer(o);
304 // first create the new aggregate buffer.
305 uint32_t total = m_aggregates->n + other->m_aggregates->n;
306 auto aggregates = (Aggregates*)std::malloc(sizeof(Aggregates) + (total - 1) * sizeof(Object*));
307 aggregates->n = total;
308
309 // copy our buffer to the new buffer
310 std::memcpy(&aggregates->buffer[0],
311 &m_aggregates->buffer[0],
312 m_aggregates->n * sizeof(Object*));
313
314 // append the other buffer into the new buffer too
315 for (uint32_t i = 0; i < other->m_aggregates->n; i++)
316 {
317 aggregates->buffer[m_aggregates->n + i] = other->m_aggregates->buffer[i];
318 const TypeId typeId = other->m_aggregates->buffer[i]->GetInstanceTypeId();
319 // note: DoGetObject scans also the unidirectional aggregates
320 if (DoGetObject(typeId))
321 {
322 NS_FATAL_ERROR("Object::AggregateObject(): "
323 "Multiple aggregation of objects of type "
324 << other->GetInstanceTypeId() << " on objects of type "
325 << GetInstanceTypeId());
326 }
327 UpdateSortedArray(aggregates, m_aggregates->n + i);
328 }
329
330 // keep track of the old aggregate buffers for the iteration
331 // of NotifyNewAggregates
333 Aggregates* b = other->m_aggregates;
334
335 // Then, assign the new aggregation buffer to every object
336 uint32_t n = aggregates->n;
337 for (uint32_t i = 0; i < n; i++)
338 {
339 Object* current = aggregates->buffer[i];
340 current->m_aggregates = aggregates;
341 }
342
343 // Finally, call NotifyNewAggregate on all the objects aggregates together.
344 // We purposely use the old aggregate buffers to iterate over the objects
345 // because this allows us to assume that they will not change from under
346 // our feet, even if our users call AggregateObject from within their
347 // NotifyNewAggregate method.
348 for (uint32_t i = 0; i < a->n; i++)
349 {
350 Object* current = a->buffer[i];
351 current->NotifyNewAggregate();
352 }
353 for (uint32_t i = 0; i < b->n; i++)
354 {
355 Object* current = b->buffer[i];
356 current->NotifyNewAggregate();
357 }
358
359 // Now that we are done with them, we can free our old aggregate buffers
360 std::free(a);
361 std::free(b);
362}
363
364void
366{
367 NS_LOG_FUNCTION(this << o);
369 NS_ASSERT(!o->m_disposed);
371 NS_ASSERT(o->CheckLoose());
372
373 Object* other = PeekPointer(o);
374
375 const TypeId typeId = other->GetInstanceTypeId();
376 // note: DoGetObject scans also the unidirectional aggregates
377 if (DoGetObject(typeId))
378 {
379 NS_FATAL_ERROR("Object::UnidirectionalAggregateObject(): "
380 "Multiple aggregation of objects of type "
381 << other->GetInstanceTypeId() << " on objects of type "
382 << GetInstanceTypeId());
383 }
384
385 m_unidirectionalAggregates.emplace_back(other);
386
387 // Finally, call NotifyNewAggregate on all the objects aggregates by this object.
388 // We skip the aggregated Object and its aggregates because they are not
389 // mutually aggregated to the others.
390 // Unfortunately, we have to make a copy of the aggregated objects, because
391 // NotifyNewAggregate might change it...
392
393 std::list<Object*> aggregates;
394 for (uint32_t i = 0; i < m_aggregates->n; i++)
395 {
396 aggregates.emplace_back(m_aggregates->buffer[i]);
397 }
398 for (auto& item : aggregates)
399 {
400 item->NotifyNewAggregate();
401 }
402}
403
404/*
405 * This function must be implemented in the stack that needs to notify
406 * other stacks connected to the node of their presence in the node.
407 */
408void
413
416{
417 NS_LOG_FUNCTION(this);
418 return AggregateIterator(this);
419}
420
421void
423{
424 NS_LOG_FUNCTION(this << tid);
425 NS_ASSERT(Check());
426 m_tid = tid;
427}
428
429void
435
436void
442
443bool
445{
446 NS_LOG_FUNCTION(this);
447 return (GetReferenceCount() > 0);
448}
449
450/* In some cases, when an event is scheduled against a subclass of
451 * Object, and if no one owns a reference directly to this object, the
452 * object is alive, has a refcount of zero and the method ran when the
453 * event expires runs against the raw pointer which means that we are
454 * manipulating an object with a refcount of zero. So, instead we
455 * check the aggregate reference count.
456 */
457bool
459{
460 NS_LOG_FUNCTION(this);
461 bool nonZeroRefCount = false;
462 uint32_t n = m_aggregates->n;
463 for (uint32_t i = 0; i < n; i++)
464 {
465 Object* current = m_aggregates->buffer[i];
466 if (current->GetReferenceCount())
467 {
468 nonZeroRefCount = true;
469 break;
470 }
471 }
472 return nonZeroRefCount;
473}
474
475void
477{
478 // check if we really need to die
479 NS_LOG_FUNCTION(this);
480 for (uint32_t i = 0; i < m_aggregates->n; i++)
481 {
482 Object* current = m_aggregates->buffer[i];
483 if (current->GetReferenceCount() > 0)
484 {
485 return;
486 }
487 }
488
489 // Now, we know that we are alone to use this aggregate so,
490 // we can dispose and delete everything safely.
491
492 uint32_t n = m_aggregates->n;
493 // Ensure we are disposed.
494 for (uint32_t i = 0; i < n; i++)
495 {
496 Object* current = m_aggregates->buffer[i];
497 if (!current->m_disposed)
498 {
499 current->DoDispose();
500 }
501 }
502
503 // Now, actually delete all objects
504 Aggregates* aggregates = m_aggregates;
505 for (uint32_t i = 0; i < n; i++)
506 {
507 // There is a trick here: each time we call delete below,
508 // the deleted object is removed from the aggregate buffer
509 // in the destructor so, the index of the next element to
510 // lookup is always zero
511 Object* current = aggregates->buffer[0];
512 delete current;
513 }
514}
515} // 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:98
friend class Object
Object needs access.
Definition object.h:120
std::vector< Ptr< Object > >::const_iterator m_uniAggrIter
Iterator to the unidirectional aggregates.
Definition object.h:133
Ptr< const Object > Next()
Get the next Aggregated Object.
Definition object.cc:53
Ptr< const Object > m_object
Parent Object.
Definition object.h:130
AggregateIterator()
Default constructor, which has no Object.
Definition object.cc:37
uint32_t m_current
Current position in parent's aggregates.
Definition object.h:131
bool HasNext() const
Check if there are more Aggregates to iterate over.
Definition object.cc:45
Anchor the ns-3 type and attribute system.
void ConstructSelf(const AttributeConstructionList &attributes)
Complete construction of ObjectBase; invoked by derived classes.
A base class which provides memory management and object aggregation.
Definition object.h:81
Aggregates * m_aggregates
A pointer to an array of 'aggregates'.
Definition object.h:474
void UnidirectionalAggregateObject(Ptr< Object > other)
Aggregate an Object to another Object.
Definition object.cc:365
TypeId GetInstanceTypeId() const final
Get the most derived TypeId for this Object.
Definition object.cc:80
void Initialize()
Invoke DoInitialize on all Objects aggregated to this one.
Definition object.cc:200
void UpdateSortedArray(Aggregates *aggregates, uint32_t i) const
Keep the list of aggregates in most-recently-used order.
Definition object.cc:281
void Construct(const AttributeConstructionList &attributes)
Initialize all member variables registered as Attributes of this TypeId.
Definition object.cc:143
bool Check() const
Verify that this Object is still live, by checking it's reference count.
Definition object.cc:444
Ptr< Object > DoGetObject(TypeId tid) const
Find an Object of TypeId tid in the aggregates of this Object.
Definition object.cc:150
friend class AggregateIterator
Friends.
Definition object.h:365
bool m_disposed
Set to true when the DoDispose() method of the Object has run, false otherwise.
Definition object.h:461
std::vector< Ptr< Object > > m_unidirectionalAggregates
An array of unidirectional aggregates, i.e., objects that are aggregated to the current object,...
Definition object.h:484
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition object.cc:409
bool CheckLoose() const
Check if any aggregated Objects have non-zero reference counts.
Definition object.cc:458
~Object() override
Destructor.
Definition object.cc:105
AggregateIterator GetAggregateIterator() const
Get an iterator to the Objects aggregated to this one.
Definition object.cc:415
virtual void DoInitialize()
Initialize() implementation.
Definition object.cc:437
void SetTypeId(TypeId tid)
Set the TypeId of this Object.
Definition object.cc:422
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition object.cc:295
static TypeId GetTypeId()
Register this type.
Definition object.cc:87
void Dispose()
Dispose of this Object.
Definition object.cc:244
TypeId m_tid
Identifies the type of this Object instance.
Definition object.h:456
Object()
Caller graph was not generated because of its size.
Definition object.cc:93
virtual void DoDispose()
Destructor implementation.
Definition object.cc:430
bool IsInitialized() const
Check if the object has been initialized.
Definition object.cc:237
uint32_t m_getObjectCount
The number of times the Object was accessed with a call to GetObject().
Definition object.h:493
void DoDelete()
Attempt to delete this Object.
Definition object.cc:476
bool m_initialized
Set to true once the DoInitialize() method has run, false otherwise.
Definition object.h:466
Smart pointer class similar to boost::intrusive_ptr.
Definition ptr.h:70
a unique identifier for an interface.
Definition type-id.h:49
TypeId GetParent() const
Get the parent of this TypeId.
Definition type-id.cc:1023
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:999
#define NS_ASSERT(condition)
At runtime, in debugging builds, if this condition is not true, the program prints the source file,...
Definition assert.h:55
#define NS_FATAL_ERROR(msg)
Report a fatal error with a message and terminate.
#define NS_LOG_COMPONENT_DEFINE(name)
Define a Log component with a specific name.
Definition log.h:194
#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:35
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:463
STL namespace.
ns3::Object class declaration, which is the root of the Object hierarchy and Aggregation.
The list of Objects aggregated to this one.
Definition object.h:383
uint32_t n
The number of entries in buffer.
Definition object.h:385
Object * buffer[1]
The array of Objects.
Definition object.h:387