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#include "object-factory.h"
16#include "string.h"
17
18#include <cstdlib>
19#include <cstring>
20#include <sstream>
21#include <vector>
22
23/**
24 * \file
25 * \ingroup object
26 * ns3::Object class implementation.
27 */
28
29namespace ns3
30{
31
33
34/*********************************************************************
35 * The Object implementation
36 *********************************************************************/
37
39
41 : m_object(nullptr),
42 m_current(0)
43{
44 NS_LOG_FUNCTION(this);
45}
46
47bool
49{
50 NS_LOG_FUNCTION(this);
51 return (m_current < m_object->m_aggregates->n) ||
52 (m_uniAggrIter != m_object->m_unidirectionalAggregates.end());
53}
54
57{
58 NS_LOG_FUNCTION(this);
59 if (m_current < m_object->m_aggregates->n)
60 {
61 Object* object = m_object->m_aggregates->buffer[m_current];
62 m_current++;
63 return object;
64 }
65 else if (m_uniAggrIter != m_object->m_unidirectionalAggregates.end())
66 {
67 auto object = *m_uniAggrIter;
68 m_uniAggrIter++;
69 return object;
70 }
71 return nullptr;
72}
73
75 : m_object(object),
76 m_current(0)
77{
78 NS_LOG_FUNCTION(this << object);
79 m_uniAggrIter = object->m_unidirectionalAggregates.begin();
80}
81
84{
85 NS_LOG_FUNCTION(this);
86 return m_tid;
87}
88
91{
92 static TypeId tid = TypeId("ns3::Object").SetParent<ObjectBase>().SetGroupName("Core");
93 return tid;
94}
95
98 m_disposed(false),
99 m_initialized(false),
100 m_aggregates((Aggregates*)std::malloc(sizeof(Aggregates))),
102{
103 NS_LOG_FUNCTION(this);
104 m_aggregates->n = 1;
105 m_aggregates->buffer[0] = this;
106}
107
109{
110 // remove this object from the aggregate list
111 NS_LOG_FUNCTION(this);
113 for (uint32_t i = 0; i < n; i++)
114 {
115 Object* current = m_aggregates->buffer[i];
116 if (current == this)
117 {
118 std::memmove(&m_aggregates->buffer[i],
119 &m_aggregates->buffer[i + 1],
120 sizeof(Object*) * (m_aggregates->n - (i + 1)));
121 m_aggregates->n--;
122 }
123 }
124 // finally, if all objects have been removed from the list,
125 // delete the aggregate list
126 if (m_aggregates->n == 0)
127 {
128 std::free(m_aggregates);
129 }
130 m_aggregates = nullptr;
132}
133
135 : m_tid(o.m_tid),
136 m_disposed(false),
137 m_initialized(false),
138 m_aggregates((Aggregates*)std::malloc(sizeof(Aggregates))),
139 m_getObjectCount(0)
140{
141 m_aggregates->n = 1;
142 m_aggregates->buffer[0] = this;
143}
144
145void
147{
148 NS_LOG_FUNCTION(this << &attributes);
149 ConstructSelf(attributes);
150}
151
154{
155 NS_LOG_FUNCTION(this << tid);
157
158 // First check if the object is in the normal aggregates.
160 TypeId objectTid = Object::GetTypeId();
161 for (uint32_t i = 0; i < n; i++)
162 {
163 Object* current = m_aggregates->buffer[i];
164 TypeId cur = current->GetInstanceTypeId();
165 while (cur != tid && cur != objectTid)
166 {
167 cur = cur.GetParent();
168 }
169 if (cur == tid)
170 {
171 // This is an attempt to 'cache' the result of this lookup.
172 // the idea is that if we perform a lookup for a TypeId on this object,
173 // we are likely to perform the same lookup later so, we make sure
174 // that the aggregate array is sorted by the number of accesses
175 // to each object.
176
177 // first, increment the access count
178 current->m_getObjectCount++;
179 // then, update the sort
181 // finally, return the match
182 return const_cast<Object*>(current);
183 }
184 }
185
186 // Next check if it's a unidirectional aggregate
187 for (auto& uniItem : m_unidirectionalAggregates)
188 {
189 TypeId cur = uniItem->GetInstanceTypeId();
190 while (cur != tid && cur != objectTid)
191 {
192 cur = cur.GetParent();
193 }
194 if (cur == tid)
195 {
196 return uniItem;
197 }
198 }
199 return nullptr;
200}
201
202void
204{
205 /**
206 * Note: the code here is a bit tricky because we need to protect ourselves from
207 * modifications in the aggregate array while DoInitialize is called. The user's
208 * implementation of the DoInitialize method could call GetObject (which could
209 * reorder the array) and it could call AggregateObject which would add an
210 * object at the end of the array. To be safe, we restart iteration over the
211 * array whenever we call some user code, just in case.
212 */
213 NS_LOG_FUNCTION(this);
214restart:
216 for (uint32_t i = 0; i < n; i++)
217 {
218 Object* current = m_aggregates->buffer[i];
219 if (!current->m_initialized)
220 {
221 current->DoInitialize();
222 current->m_initialized = true;
223 goto restart;
224 }
225 }
226
227 // note: no need to restart because unidirectionally aggregated objects
228 // can not change the status of the actual object.
229 for (auto& uniItem : m_unidirectionalAggregates)
230 {
231 if (!uniItem->m_initialized)
232 {
233 uniItem->DoInitialize();
234 uniItem->m_initialized = true;
235 }
236 }
237}
238
239bool
241{
242 NS_LOG_FUNCTION(this);
243 return m_initialized;
244}
245
246void
248{
249 /**
250 * Note: the code here is a bit tricky because we need to protect ourselves from
251 * modifications in the aggregate array while DoDispose is called. The user's
252 * DoDispose implementation could call GetObject (which could reorder the array)
253 * and it could call AggregateObject which would add an object at the end of the array.
254 * So, to be safe, we restart the iteration over the array whenever we call some
255 * user code.
256 */
257 NS_LOG_FUNCTION(this);
258restart:
260 for (uint32_t i = 0; i < n; i++)
261 {
262 Object* current = m_aggregates->buffer[i];
263 if (!current->m_disposed)
264 {
265 current->DoDispose();
266 current->m_disposed = true;
267 goto restart;
268 }
269 }
270
271 // note: no need to restart because unidirectionally aggregated objects
272 // can not change the status of the actual object.
273 for (auto& uniItem : m_unidirectionalAggregates)
274 {
275 if (!uniItem->m_disposed && uniItem->GetReferenceCount() == 1)
276 {
277 uniItem->DoDispose();
278 uniItem->m_disposed = true;
279 }
280 }
281}
282
283void
285{
286 NS_LOG_FUNCTION(this << aggregates << j);
287 while (j > 0 &&
288 aggregates->buffer[j]->m_getObjectCount > aggregates->buffer[j - 1]->m_getObjectCount)
289 {
290 Object* tmp = aggregates->buffer[j - 1];
291 aggregates->buffer[j - 1] = aggregates->buffer[j];
292 aggregates->buffer[j] = tmp;
293 j--;
294 }
295}
296
297void
299{
300 NS_LOG_FUNCTION(this << o);
302 NS_ASSERT(!o->m_disposed);
304 NS_ASSERT(o->CheckLoose());
305
306 Object* other = PeekPointer(o);
307 // first create the new aggregate buffer.
308 uint32_t total = m_aggregates->n + other->m_aggregates->n;
309 auto aggregates = (Aggregates*)std::malloc(sizeof(Aggregates) + (total - 1) * sizeof(Object*));
310 aggregates->n = total;
311
312 // copy our buffer to the new buffer
313 std::memcpy(&aggregates->buffer[0],
314 &m_aggregates->buffer[0],
315 m_aggregates->n * sizeof(Object*));
316
317 // append the other buffer into the new buffer too
318 for (uint32_t i = 0; i < other->m_aggregates->n; i++)
319 {
320 aggregates->buffer[m_aggregates->n + i] = other->m_aggregates->buffer[i];
321 const TypeId typeId = other->m_aggregates->buffer[i]->GetInstanceTypeId();
322 // note: DoGetObject scans also the unidirectional aggregates
323 if (DoGetObject(typeId))
324 {
325 NS_FATAL_ERROR("Object::AggregateObject(): "
326 "Multiple aggregation of objects of type "
327 << other->GetInstanceTypeId() << " on objects of type "
328 << GetInstanceTypeId());
329 }
330 UpdateSortedArray(aggregates, m_aggregates->n + i);
331 }
332
333 // keep track of the old aggregate buffers for the iteration
334 // of NotifyNewAggregates
336 Aggregates* b = other->m_aggregates;
337
338 // Then, assign the new aggregation buffer to every object
339 uint32_t n = aggregates->n;
340 for (uint32_t i = 0; i < n; i++)
341 {
342 Object* current = aggregates->buffer[i];
343 current->m_aggregates = aggregates;
344 }
345
346 // Finally, call NotifyNewAggregate on all the objects aggregates together.
347 // We purposely use the old aggregate buffers to iterate over the objects
348 // because this allows us to assume that they will not change from under
349 // our feet, even if our users call AggregateObject from within their
350 // NotifyNewAggregate method.
351 for (uint32_t i = 0; i < a->n; i++)
352 {
353 Object* current = a->buffer[i];
354 current->NotifyNewAggregate();
355 }
356 for (uint32_t i = 0; i < b->n; i++)
357 {
358 Object* current = b->buffer[i];
359 current->NotifyNewAggregate();
360 }
361
362 // Now that we are done with them, we can free our old aggregate buffers
363 std::free(a);
364 std::free(b);
365}
366
367void
369{
370 NS_LOG_FUNCTION(this << o);
372 NS_ASSERT(!o->m_disposed);
374 NS_ASSERT(o->CheckLoose());
375
376 Object* other = PeekPointer(o);
377
378 const TypeId typeId = other->GetInstanceTypeId();
379 // note: DoGetObject scans also the unidirectional aggregates
380 if (DoGetObject(typeId))
381 {
382 NS_FATAL_ERROR("Object::UnidirectionalAggregateObject(): "
383 "Multiple aggregation of objects of type "
384 << other->GetInstanceTypeId() << " on objects of type "
385 << GetInstanceTypeId());
386 }
387
388 m_unidirectionalAggregates.emplace_back(other);
389
390 // Finally, call NotifyNewAggregate on all the objects aggregates by this object.
391 // We skip the aggregated Object and its aggregates because they are not
392 // mutually aggregated to the others.
393 // Unfortunately, we have to make a copy of the aggregated objects, because
394 // NotifyNewAggregate might change it...
395
396 std::list<Object*> aggregates;
397 for (uint32_t i = 0; i < m_aggregates->n; i++)
398 {
399 aggregates.emplace_back(m_aggregates->buffer[i]);
400 }
401 for (auto& item : aggregates)
402 {
403 item->NotifyNewAggregate();
404 }
405}
406
407/*
408 * This function must be implemented in the stack that needs to notify
409 * other stacks connected to the node of their presence in the node.
410 */
411void
416
419{
420 NS_LOG_FUNCTION(this);
421 return AggregateIterator(this);
422}
423
424void
426{
427 NS_LOG_FUNCTION(this << tid);
428 NS_ASSERT(Check());
429 m_tid = tid;
430}
431
432void
438
439void
445
446bool
448{
449 NS_LOG_FUNCTION(this);
450 return (GetReferenceCount() > 0);
451}
452
453/* In some cases, when an event is scheduled against a subclass of
454 * Object, and if no one owns a reference directly to this object, the
455 * object is alive, has a refcount of zero and the method ran when the
456 * event expires runs against the raw pointer which means that we are
457 * manipulating an object with a refcount of zero. So, instead we
458 * check the aggregate reference count.
459 */
460bool
462{
463 NS_LOG_FUNCTION(this);
464 bool nonZeroRefCount = false;
466 for (uint32_t i = 0; i < n; i++)
467 {
468 Object* current = m_aggregates->buffer[i];
469 if (current->GetReferenceCount())
470 {
471 nonZeroRefCount = true;
472 break;
473 }
474 }
475 return nonZeroRefCount;
476}
477
478void
480{
481 // check if we really need to die
482 NS_LOG_FUNCTION(this);
483 for (uint32_t i = 0; i < m_aggregates->n; i++)
484 {
485 Object* current = m_aggregates->buffer[i];
486 if (current->GetReferenceCount() > 0)
487 {
488 return;
489 }
490 }
491
492 // Now, we know that we are alone to use this aggregate so,
493 // we can dispose and delete everything safely.
494
496 // Ensure we are disposed.
497 for (uint32_t i = 0; i < n; i++)
498 {
499 Object* current = m_aggregates->buffer[i];
500 if (!current->m_disposed)
501 {
502 current->DoDispose();
503 }
504 }
505
506 // Now, actually delete all objects
507 Aggregates* aggregates = m_aggregates;
508 for (uint32_t i = 0; i < n; i++)
509 {
510 // There is a trick here: each time we call delete below,
511 // the deleted object is removed from the aggregate buffer
512 // in the destructor so, the index of the next element to
513 // lookup is always zero
514 Object* current = aggregates->buffer[0];
515 delete current;
516 }
517}
518} // 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:95
std::vector< Ptr< Object > >::const_iterator m_uniAggrIter
Iterator to the unidirectional aggregates.
Definition object.h:130
Ptr< const Object > Next()
Get the next Aggregated Object.
Definition object.cc:56
AggregateIterator()
Default constructor, which has no Object.
Definition object.cc:40
bool HasNext() const
Check if there are more Aggregates to iterate over.
Definition object.cc:48
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:78
Aggregates * m_aggregates
A pointer to an array of 'aggregates'.
Definition object.h:467
void UnidirectionalAggregateObject(Ptr< Object > other)
Aggregate an Object to another Object.
Definition object.cc:368
void Initialize()
Invoke DoInitialize on all Objects aggregated to this one.
Definition object.cc:203
void UpdateSortedArray(Aggregates *aggregates, uint32_t i) const
Keep the list of aggregates in most-recently-used order.
Definition object.cc:284
void Construct(const AttributeConstructionList &attributes)
Initialize all member variables registered as Attributes of this TypeId.
Definition object.cc:146
bool Check() const
Verify that this Object is still live, by checking it's reference count.
Definition object.cc:447
Ptr< Object > DoGetObject(TypeId tid) const
Find an Object of TypeId tid in the aggregates of this Object.
Definition object.cc:153
friend class AggregateIterator
Friends.
Definition object.h:358
bool m_disposed
Set to true when the DoDispose() method of the Object has run, false otherwise.
Definition object.h:454
std::vector< Ptr< Object > > m_unidirectionalAggregates
An array of unidirectional aggregates, i.e., objects that are aggregated to the current object,...
Definition object.h:477
virtual void NotifyNewAggregate()
Notify all Objects aggregated to this one of a new Object being aggregated.
Definition object.cc:412
bool CheckLoose() const
Check if any aggregated Objects have non-zero reference counts.
Definition object.cc:461
~Object() override
Destructor.
Definition object.cc:108
AggregateIterator GetAggregateIterator() const
Get an iterator to the Objects aggregated to this one.
Definition object.cc:418
virtual void DoInitialize()
Initialize() implementation.
Definition object.cc:440
void SetTypeId(TypeId tid)
Set the TypeId of this Object.
Definition object.cc:425
void AggregateObject(Ptr< Object > other)
Aggregate two Objects together.
Definition object.cc:298
TypeId GetInstanceTypeId() const override
Get the most derived TypeId for this Object.
Definition object.cc:83
static TypeId GetTypeId()
Register this type.
Definition object.cc:90
void Dispose()
Dispose of this Object.
Definition object.cc:247
TypeId m_tid
Identifies the type of this Object instance.
Definition object.h:449
Object()
Constructor.
Definition object.cc:96
virtual void DoDispose()
Destructor implementation.
Definition object.cc:433
bool IsInitialized() const
Check if the object has been initialized.
Definition object.cc:240
uint32_t m_getObjectCount
The number of times the Object was accessed with a call to GetObject().
Definition object.h:486
void DoDelete()
Attempt to delete this Object.
Definition object.cc:479
bool m_initialized
Set to true once the DoInitialize() method has run, false otherwise.
Definition object.h:459
Smart pointer class similar to boost::intrusive_ptr.
a unique identifier for an interface.
Definition type-id.h:48
TypeId GetParent() const
Get the parent of this TypeId.
Definition type-id.cc:1025
TypeId SetParent(TypeId tid)
Set the parent TypeId.
Definition type-id.cc:1001
#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:191
#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:443
STL namespace.
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:376
uint32_t n
The number of entries in buffer.
Definition object.h:378
Object * buffer[1]
The array of Objects.
Definition object.h:380