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