src/core/object.cc
author Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
Sat, 04 Jul 2009 08:15:48 +0200
changeset 4654 2eaebe77d66b
parent 3871 c6f693de286d
permissions -rw-r--r--
Added tag ns-3.5 for changeset c975274c9707
mathieu@699
     1
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
mathieu@699
     2
/*
mathieu@699
     3
 * Copyright (c) 2007 INRIA, Gustavo Carneiro
mathieu@699
     4
 *
mathieu@699
     5
 * This program is free software; you can redistribute it and/or modify
mathieu@699
     6
 * it under the terms of the GNU General Public License version 2 as
mathieu@699
     7
 * published by the Free Software Foundation;
mathieu@699
     8
 *
mathieu@699
     9
 * This program is distributed in the hope that it will be useful,
mathieu@699
    10
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
mathieu@699
    11
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
mathieu@699
    12
 * GNU General Public License for more details.
mathieu@699
    13
 *
mathieu@699
    14
 * You should have received a copy of the GNU General Public License
mathieu@699
    15
 * along with this program; if not, write to the Free Software
mathieu@699
    16
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
mathieu@699
    17
 *
mathieu@699
    18
 * Authors: Gustavo Carneiro <gjcarneiro@gmail.com>,
mathieu@699
    19
 *          Mathieu Lacage <mathieu.lacage@sophia.inria.fr>
mathieu@699
    20
 */
mathieu@706
    21
#include "object.h"
mathieu@699
    22
#include "assert.h"
mathieu@699
    23
#include "singleton.h"
mathieu@2438
    24
#include "attribute.h"
craigdo@1504
    25
#include "log.h"
mathieu@2502
    26
#include "string.h"
mathieu@699
    27
#include <vector>
mathieu@2372
    28
#include <sstream>
mathieu@699
    29
craigdo@1504
    30
NS_LOG_COMPONENT_DEFINE ("Object");
mathieu@1374
    31
mathieu@699
    32
namespace ns3 {
mathieu@699
    33
mathieu@2233
    34
/*********************************************************************
mathieu@2233
    35
 *         The Object implementation
mathieu@2233
    36
 *********************************************************************/
mathieu@2233
    37
mathieu@2247
    38
NS_OBJECT_ENSURE_REGISTERED (Object);
mathieu@2247
    39
mathieu@2937
    40
Object::AggregateIterator::AggregateIterator ()
mathieu@2937
    41
  : m_first (0),
mathieu@2937
    42
    m_current (0)
mathieu@2937
    43
{}
mathieu@2937
    44
mathieu@2937
    45
bool 
mathieu@2937
    46
Object::AggregateIterator::HasNext (void) const
mathieu@2937
    47
{
mathieu@2937
    48
  if (m_current != 0 && m_current->m_next != PeekPointer (m_first))
mathieu@2937
    49
    {
mathieu@2937
    50
      return true;
mathieu@2937
    51
    }
mathieu@2937
    52
  return false;
mathieu@2937
    53
}
mathieu@2937
    54
Ptr<const Object> 
mathieu@2937
    55
Object::AggregateIterator::Next (void)
mathieu@2937
    56
{
mathieu@2938
    57
  m_current = m_current->m_next;
mathieu@2937
    58
  return m_current;
mathieu@2937
    59
}
mathieu@2937
    60
Object::AggregateIterator::AggregateIterator (Ptr<const Object> first)
mathieu@2937
    61
  : m_first (first),
mathieu@2938
    62
    m_current (first)
mathieu@2937
    63
{}
mathieu@2937
    64
mathieu@2937
    65
mathieu@2250
    66
TypeId 
mathieu@2634
    67
Object::GetInstanceTypeId (void) const
mathieu@2634
    68
{
mathieu@2636
    69
  return m_tid;
mathieu@2634
    70
}
mathieu@2634
    71
mathieu@2634
    72
TypeId 
mathieu@2251
    73
Object::GetTypeId (void)
mathieu@2232
    74
{
mathieu@2637
    75
  static TypeId tid = TypeId ("ns3::Object")
mathieu@2637
    76
    .SetParent<ObjectBase> ()
mathieu@2637
    77
    ;
mathieu@2252
    78
  return tid;
mathieu@2232
    79
}
mathieu@699
    80
mathieu@699
    81
mathieu@706
    82
Object::Object ()
mathieu@699
    83
  : m_count (1),
mathieu@2252
    84
    m_tid (Object::GetTypeId ()),
mathieu@713
    85
    m_disposed (false),
mathieu@702
    86
    m_next (this)
mathieu@699
    87
{}
mathieu@706
    88
Object::~Object () 
mathieu@706
    89
{
mathieu@706
    90
  m_next = 0;
mathieu@706
    91
}
mathieu@2667
    92
Object::Object (const Object &o)
mathieu@2667
    93
  : m_count (1),
mathieu@2667
    94
    m_tid (o.m_tid),
mathieu@2667
    95
    m_disposed (false),
mathieu@2667
    96
    m_next (this)
mathieu@2667
    97
{}
mathieu@3394
    98
uint32_t
mathieu@3394
    99
Object::GetReferenceCount (void) const
mathieu@3394
   100
{
mathieu@3394
   101
  return m_count;
mathieu@3394
   102
}
mathieu@2372
   103
void
mathieu@2459
   104
Object::Construct (const AttributeList &attributes)
mathieu@2372
   105
{
mathieu@2637
   106
  ConstructSelf (attributes);
mathieu@2569
   107
}
mathieu@2463
   108
mathieu@706
   109
Ptr<Object>
mathieu@2257
   110
Object::DoGetObject (TypeId tid) const
mathieu@699
   111
{
gjc@1534
   112
  NS_ASSERT (CheckLoose ());
mathieu@709
   113
  const Object *currentObject = this;
mathieu@3871
   114
  TypeId objectTid = Object::GetTypeId ();
mathieu@702
   115
  do {
mathieu@702
   116
    NS_ASSERT (currentObject != 0);
mathieu@3397
   117
    TypeId cur = currentObject->GetInstanceTypeId ();
mathieu@3871
   118
    while (cur != tid && cur != objectTid)
mathieu@702
   119
      {
mathieu@2235
   120
        cur = cur.GetParent ();
mathieu@702
   121
      }
mathieu@2252
   122
    if (cur == tid)
mathieu@702
   123
      {
mathieu@709
   124
        return const_cast<Object *> (currentObject);
mathieu@702
   125
      }
mathieu@702
   126
    currentObject = currentObject->m_next;
mathieu@702
   127
  } while (currentObject != this);
mathieu@699
   128
  return 0;
mathieu@699
   129
}
mathieu@699
   130
void 
mathieu@706
   131
Object::Dispose (void)
mathieu@699
   132
{
mathieu@706
   133
  Object *current = this;
mathieu@702
   134
  do {
mathieu@702
   135
    NS_ASSERT (current != 0);
mathieu@713
   136
    NS_ASSERT (!current->m_disposed);
mathieu@702
   137
    current->DoDispose ();
mathieu@713
   138
    current->m_disposed = true;
mathieu@702
   139
    current = current->m_next;
mathieu@702
   140
  } while (current != this);
mathieu@699
   141
}
mathieu@699
   142
void 
mathieu@2258
   143
Object::AggregateObject (Ptr<Object> o)
mathieu@699
   144
{
mathieu@718
   145
  NS_ASSERT (!m_disposed);
mathieu@718
   146
  NS_ASSERT (!o->m_disposed);
gjc@1534
   147
  NS_ASSERT (CheckLoose ());
gjc@1534
   148
  NS_ASSERT (o->CheckLoose ());
craigdo@2902
   149
mathieu@3397
   150
  if (DoGetObject (o->GetInstanceTypeId ()))
craigdo@2902
   151
    {
craigdo@2902
   152
      NS_FATAL_ERROR ("Object::AggregateObject(): "
mathieu@3397
   153
                      "Multiple aggregation of objects of type " << 
mathieu@3397
   154
                      o->GetInstanceTypeId ().GetName ());
craigdo@2902
   155
    }
craigdo@2902
   156
mathieu@706
   157
  Object *other = PeekPointer (o);
mathieu@706
   158
  Object *next = m_next;
mathieu@702
   159
  m_next = other->m_next;
mathieu@702
   160
  other->m_next = next;
gjc@1534
   161
  NS_ASSERT (CheckLoose ());
gjc@1534
   162
  NS_ASSERT (o->CheckLoose ());
tomh@4472
   163
  // call NotifyNewAggregate in the listed chain
tomh@4472
   164
  Object *currentObject = this;
tomh@4472
   165
  do 
tomh@4472
   166
    {
tomh@4472
   167
      // the NotifyNewAggregate of the current object implementation
tomh@4472
   168
      // should be called on the next object in the linked chain
tomh@4472
   169
      currentObject->NotifyNewAggregate ();
tomh@4472
   170
      currentObject = currentObject->m_next;
tomh@4472
   171
    } while (currentObject != this);
tomh@4472
   172
}
tomh@4472
   173
/**
tomh@4472
   174
 * This function must be implemented in the stack that needs to notify
tomh@4472
   175
 * other stacks connected to the node of their presence in the node.
tomh@4472
   176
 */
tomh@4472
   177
void
tomh@4472
   178
Object::NotifyNewAggregate ()
tomh@4472
   179
{
tomh@4472
   180
mathieu@699
   181
}
mathieu@699
   182
mathieu@2937
   183
Object::AggregateIterator 
mathieu@2937
   184
Object::GetAggregateIterator (void) const
mathieu@2937
   185
{
mathieu@2937
   186
  return AggregateIterator (this);
mathieu@2937
   187
}
mathieu@2937
   188
mathieu@699
   189
void 
mathieu@2252
   190
Object::SetTypeId (TypeId tid)
mathieu@699
   191
{
mathieu@699
   192
  NS_ASSERT (Check ());
mathieu@2252
   193
  m_tid = tid;
mathieu@699
   194
}
mathieu@699
   195
mathieu@699
   196
void
mathieu@706
   197
Object::DoDispose (void)
mathieu@713
   198
{
mathieu@713
   199
  NS_ASSERT (!m_disposed);
mathieu@713
   200
}
mathieu@699
   201
mathieu@1336
   202
mathieu@699
   203
bool 
mathieu@706
   204
Object::Check (void) const
mathieu@699
   205
{
mathieu@701
   206
  return (m_count > 0);
mathieu@701
   207
}
mathieu@701
   208
gjc@1534
   209
/* In some cases, when an event is scheduled against a subclass of
gjc@1534
   210
 * Object, and if no one owns a reference directly to this object, the
gjc@1534
   211
 * object is alive, has a refcount of zero and the method ran when the
gjc@1534
   212
 * event expires runs against the raw pointer which means that we are
gjc@1534
   213
 * manipulating an object with a refcount of zero.  So, instead we
gjc@1534
   214
 * check the aggregate reference count.
gjc@1534
   215
 */
gjc@1534
   216
bool 
gjc@1534
   217
Object::CheckLoose (void) const
gjc@1534
   218
{
gjc@1534
   219
  uint32_t refcount = 0;
gjc@1534
   220
  const Object *current = this;
gjc@1534
   221
  do
gjc@1534
   222
    {
gjc@1534
   223
      refcount += current->m_count;
gjc@1534
   224
      current = current->m_next;
gjc@1534
   225
    }
gjc@1534
   226
  while (current != this);
gjc@1534
   227
gjc@1534
   228
  return (refcount > 0);
gjc@1534
   229
}
gjc@1534
   230
mathieu@701
   231
void
mathieu@706
   232
Object::MaybeDelete (void) const
mathieu@701
   233
{
mathieu@702
   234
  // First, check if any of the attached
mathieu@702
   235
  // Object has a non-zero count.
mathieu@706
   236
  const Object *current = this;
mathieu@702
   237
  do {
mathieu@702
   238
    NS_ASSERT (current != 0);
mathieu@702
   239
    if (current->m_count != 0)
mathieu@702
   240
      {
mathieu@702
   241
        return;
mathieu@702
   242
      }
mathieu@702
   243
    current = current->m_next;
mathieu@702
   244
  } while (current != this);
mathieu@702
   245
mathieu@2529
   246
  // Ensure we are disposed.
mathieu@2529
   247
  Object *tmp = const_cast<Object *> (this);
mathieu@2529
   248
  const Object *end = this;
mathieu@2529
   249
  do {
mathieu@2529
   250
    NS_ASSERT (current != 0);
mathieu@2529
   251
    Object *next = tmp->m_next;
mathieu@2529
   252
    if (!tmp->m_disposed)
mathieu@2529
   253
      {
mathieu@2529
   254
        tmp->DoDispose ();
mathieu@2529
   255
      }
mathieu@2529
   256
    tmp = next;
mathieu@2529
   257
  } while (tmp != end);
mathieu@2529
   258
mathieu@702
   259
  // all attached objects have a zero count so, 
mathieu@702
   260
  // we can delete all attached objects.
mathieu@702
   261
  current = this;
mathieu@702
   262
  do {
mathieu@702
   263
    NS_ASSERT (current != 0);
mathieu@706
   264
    Object *next = current->m_next;
mathieu@702
   265
    delete current;
mathieu@702
   266
    current = next;
mathieu@702
   267
  } while (current != end);
mathieu@699
   268
}
mathieu@699
   269
mathieu@699
   270
} // namespace ns3
mathieu@699
   271
mathieu@699
   272
mathieu@699
   273
#ifdef RUN_SELF_TESTS
mathieu@699
   274
mathieu@699
   275
#include "test.h"
mathieu@2631
   276
#include "object-factory.h"
mathieu@699
   277
mathieu@699
   278
namespace {
mathieu@699
   279
mathieu@706
   280
class BaseA : public ns3::Object
mathieu@699
   281
{
mathieu@699
   282
public:
mathieu@2251
   283
  static ns3::TypeId GetTypeId (void) {
mathieu@2252
   284
    static ns3::TypeId tid = ns3::TypeId ("BaseA")
mathieu@2251
   285
      .SetParent (Object::GetTypeId ())
mathieu@2602
   286
      .HideFromDocumentation ()
mathieu@2237
   287
      .AddConstructor<BaseA> ();
mathieu@2252
   288
    return tid;
mathieu@2232
   289
  }
mathieu@699
   290
  BaseA ()
mathieu@2230
   291
  {}
mathieu@699
   292
  virtual void Dispose (void) {}
mathieu@699
   293
};
mathieu@699
   294
mathieu@699
   295
class DerivedA : public BaseA
mathieu@699
   296
{
mathieu@699
   297
public:
mathieu@2251
   298
  static ns3::TypeId GetTypeId (void) {
mathieu@2252
   299
    static ns3::TypeId tid = ns3::TypeId ("DerivedA")
mathieu@2251
   300
      .SetParent (BaseA::GetTypeId ())
mathieu@2602
   301
      .HideFromDocumentation ()
mathieu@2372
   302
      .AddConstructor<DerivedA> ();
mathieu@2252
   303
    return tid;
mathieu@2232
   304
  }
mathieu@2372
   305
  DerivedA ()
mathieu@2230
   306
  {}
mathieu@699
   307
  virtual void Dispose (void) {
mathieu@699
   308
    BaseA::Dispose ();
mathieu@699
   309
  }
mathieu@699
   310
};
mathieu@699
   311
mathieu@706
   312
class BaseB : public ns3::Object
mathieu@699
   313
{
mathieu@699
   314
public:
mathieu@2251
   315
  static ns3::TypeId GetTypeId (void) {
mathieu@2252
   316
    static ns3::TypeId tid = ns3::TypeId ("BaseB")
mathieu@2251
   317
      .SetParent (Object::GetTypeId ())
mathieu@2602
   318
      .HideFromDocumentation ()
mathieu@2237
   319
      .AddConstructor<BaseB> ();
mathieu@2252
   320
    return tid;
mathieu@2232
   321
  }
mathieu@699
   322
  BaseB ()
mathieu@2230
   323
  {}
mathieu@699
   324
  virtual void Dispose (void) {}
mathieu@699
   325
};
mathieu@699
   326
mathieu@699
   327
class DerivedB : public BaseB
mathieu@699
   328
{
mathieu@699
   329
public:
mathieu@2251
   330
  static ns3::TypeId GetTypeId (void) {
mathieu@2252
   331
    static ns3::TypeId tid = ns3::TypeId ("DerivedB")
mathieu@2251
   332
      .SetParent (BaseB::GetTypeId ())
mathieu@2602
   333
      .HideFromDocumentation ()
mathieu@2372
   334
      .AddConstructor<DerivedB> ();
mathieu@2252
   335
    return tid;
mathieu@2232
   336
  }
mathieu@2372
   337
  DerivedB ()
mathieu@2243
   338
  {}
mathieu@699
   339
  virtual void Dispose (void) {
mathieu@699
   340
    BaseB::Dispose ();
mathieu@699
   341
  }
mathieu@699
   342
};
mathieu@699
   343
mathieu@2247
   344
NS_OBJECT_ENSURE_REGISTERED (BaseA);
mathieu@2247
   345
NS_OBJECT_ENSURE_REGISTERED (DerivedA);
mathieu@2247
   346
NS_OBJECT_ENSURE_REGISTERED (BaseB);
mathieu@2247
   347
NS_OBJECT_ENSURE_REGISTERED (DerivedB);
mathieu@2247
   348
mathieu@699
   349
} // namespace anonymous
mathieu@699
   350
mathieu@699
   351
namespace ns3 {
mathieu@699
   352
mathieu@706
   353
class ObjectTest : public Test
mathieu@699
   354
{
mathieu@699
   355
public:
mathieu@706
   356
  ObjectTest ();
mathieu@699
   357
  virtual bool RunTests (void);
mathieu@699
   358
};
mathieu@699
   359
mathieu@706
   360
ObjectTest::ObjectTest ()
mathieu@706
   361
  : Test ("Object")
mathieu@699
   362
{}
mathieu@1351
   363
mathieu@699
   364
bool 
mathieu@706
   365
ObjectTest::RunTests (void)
mathieu@699
   366
{
mathieu@1349
   367
  bool result = true;
mathieu@699
   368
mathieu@2230
   369
  Ptr<BaseA> baseA = CreateObject<BaseA> ();
mathieu@2257
   370
  NS_TEST_ASSERT_EQUAL (baseA->GetObject<BaseA> (), baseA);
mathieu@2257
   371
  NS_TEST_ASSERT_EQUAL (baseA->GetObject<BaseA> (DerivedA::GetTypeId ()), 0);
mathieu@2257
   372
  NS_TEST_ASSERT_EQUAL (baseA->GetObject<DerivedA> (), 0);
mathieu@2372
   373
  baseA = CreateObject<DerivedA> ();
mathieu@2257
   374
  NS_TEST_ASSERT_EQUAL (baseA->GetObject<BaseA> (), baseA);
mathieu@2257
   375
  NS_TEST_ASSERT_EQUAL (baseA->GetObject<BaseA> (DerivedA::GetTypeId ()), baseA);
mathieu@2257
   376
  NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<DerivedA> (), 0);
mathieu@699
   377
mathieu@2230
   378
  baseA = CreateObject<BaseA> ();
mathieu@2230
   379
  Ptr<BaseB> baseB = CreateObject<BaseB> ();
mathieu@699
   380
  Ptr<BaseB> baseBCopy = baseB;
mathieu@2258
   381
  baseA->AggregateObject (baseB);
mathieu@2257
   382
  NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<BaseA> (), 0);
mathieu@2257
   383
  NS_TEST_ASSERT_EQUAL (baseA->GetObject<DerivedA> (), 0);
mathieu@2257
   384
  NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<BaseB> (), 0);
mathieu@2257
   385
  NS_TEST_ASSERT_EQUAL (baseA->GetObject<DerivedB> (), 0);
mathieu@2257
   386
  NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseB> (), 0);
mathieu@2257
   387
  NS_TEST_ASSERT_EQUAL (baseB->GetObject<DerivedB> (), 0);
mathieu@2257
   388
  NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseA> (), 0);
mathieu@2257
   389
  NS_TEST_ASSERT_EQUAL (baseB->GetObject<DerivedA> (), 0);
mathieu@2257
   390
  NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<BaseA> (), 0);
mathieu@699
   391
mathieu@2372
   392
  baseA = CreateObject<DerivedA> ();
mathieu@2372
   393
  baseB = CreateObject<DerivedB> ();
mathieu@699
   394
  baseBCopy = baseB;
mathieu@2258
   395
  baseA->AggregateObject (baseB);
mathieu@2257
   396
  NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<DerivedB> (), 0);
mathieu@2257
   397
  NS_TEST_ASSERT_UNEQUAL (baseA->GetObject<BaseB> (), 0);
mathieu@2257
   398
  NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<DerivedA> (), 0);
mathieu@2257
   399
  NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseA> (), 0);
mathieu@2257
   400
  NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<DerivedA> (), 0);
mathieu@2257
   401
  NS_TEST_ASSERT_UNEQUAL (baseBCopy->GetObject<BaseA> (), 0);
mathieu@2257
   402
  NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<DerivedB> (), 0);
mathieu@3033
   403
  NS_TEST_ASSERT_UNEQUAL (baseB->GetObject<BaseB> (), 0);
mathieu@699
   404
mathieu@2230
   405
  baseA = CreateObject<BaseA> ();
mathieu@2230
   406
  baseB = CreateObject<BaseB> ();
mathieu@2258
   407
  baseA->AggregateObject (baseB);
mathieu@701
   408
  baseA = 0;
mathieu@2257
   409
  baseA = baseB->GetObject<BaseA> ();
mathieu@699
   410
mathieu@1351
   411
mathieu@2250
   412
  // Test the object creation code of TypeId
mathieu@2631
   413
  ObjectFactory factory;
mathieu@2631
   414
  factory.SetTypeId (BaseA::GetTypeId ());
mathieu@2631
   415
  Ptr<Object> a = factory.Create ();
mathieu@2257
   416
  NS_TEST_ASSERT_EQUAL (a->GetObject<BaseA> (), a);
mathieu@2257
   417
  NS_TEST_ASSERT_EQUAL (a->GetObject<BaseA> (DerivedA::GetTypeId ()), 0);
mathieu@2257
   418
  NS_TEST_ASSERT_EQUAL (a->GetObject<DerivedA> (), 0);
mathieu@2631
   419
  factory.SetTypeId (DerivedA::GetTypeId ());
mathieu@2631
   420
  a = factory.Create ();
mathieu@2257
   421
  NS_TEST_ASSERT_EQUAL (a->GetObject<BaseA> (), a);
mathieu@2257
   422
  NS_TEST_ASSERT_EQUAL (a->GetObject<BaseA> (DerivedA::GetTypeId ()), a);
mathieu@2257
   423
  NS_TEST_ASSERT_UNEQUAL (a->GetObject<DerivedA> (), 0);
mathieu@2237
   424
mathieu@2237
   425
mathieu@1349
   426
  return result;
mathieu@699
   427
}
mathieu@699
   428
mathieu@706
   429
static ObjectTest g_interfaceObjectTests;
mathieu@699
   430
mathieu@699
   431
mathieu@699
   432
} // namespace ns3
mathieu@699
   433
mathieu@699
   434
#endif /* RUN_SELF_TESTS */
mathieu@699
   435
mathieu@699
   436