~ubuntu-branches/ubuntu/oneiric/nux/oneiric

« back to all changes in this revision

Viewing changes to NuxCore/Object.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Sebastien Bacher
  • Date: 2011-08-25 13:42:45 UTC
  • mto: This revision was merged to the branch mainline in revision 43.
  • Revision ID: james.westby@ubuntu.com-20110825134245-kfz5nhs15353wcbl
Tags: upstream-1.4.0
Import upstream version 1.4.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// -*- Mode: C++; indent-tabs-mode: nil; tab-width: 2 -*-
1
2
/*
2
 
 * Copyright 2010 Inalogic® Inc.
 
3
 * Copyright 2010-2011 Inalogic® Inc.
3
4
 *
4
5
 * This program is free software: you can redistribute it and/or modify it
5
6
 * under the terms of the GNU Lesser General Public License, as
19
20
 *
20
21
 */
21
22
 
 
23
#include <iostream>
22
24
#include <sstream>
23
25
 
24
26
#include "NuxCore.h"
37
39
  NUX_IMPLEMENT_OBJECT_TYPE (Object);
38
40
  NUX_IMPLEMENT_GLOBAL_OBJECT (ObjectStats);
39
41
 
40
 
//   int ObjectStats::_total_allocated_size = 0;
41
 
//   int ObjectStats::_number_of_objects = 0;
42
 
//   ObjectStats::AllocationList ObjectStats::_allocation_list;
43
 
 
44
 
  ObjectStats::AllocationList::AllocationList()
45
 
  {
46
 
 
47
 
  }
48
 
 
49
 
  ObjectStats::AllocationList::~AllocationList()
50
 
  {
51
 
 
52
 
  }
53
 
 
54
42
  void ObjectStats::Constructor()
55
43
  {
56
 
    _total_allocated_size = 0;
 
44
    _total_allocated_size= 0;
57
45
    _number_of_objects = 0;
58
46
  }
59
47
 
60
48
  void ObjectStats::Destructor()
61
49
  {
 
50
#if defined(NUX_DEBUG)
62
51
    if (_number_of_objects)
63
52
    {
64
 
      LOG_DEBUG(logger) << _number_of_objects << " undeleted objects.";
 
53
      std::cerr << "[ObjectStats::Destructor] "
 
54
                << _number_of_objects << " undeleted objects.\n\t"
 
55
                << _allocation_list.size() << " items in allocation list.\n";
65
56
    }
66
57
 
67
 
#if defined(NUX_DEBUG)
68
 
    AllocationList::iterator it;
69
 
    for (it = _allocation_list.begin(); it != _allocation_list.end(); it++)
 
58
    int index = 0;
 
59
    for (auto ptr : _allocation_list)
70
60
    {
71
 
      Object* obj = NUX_STATIC_CAST (Object*, (*it));
72
 
      LOG_DEBUG(logger) << "Undeleted object: Type "
73
 
                        << obj->Type().m_Name << ", "
74
 
                        << obj->_allocation_file_name.GetTCharPtr()
75
 
                        << "line " << obj->_allocation_line_number;
 
61
      Object* obj = static_cast<Object*>(ptr);
 
62
      std::cerr << "\t" << ++index << " Undeleted object: Type "
 
63
                << obj->Type().name << ", "
 
64
                << obj->GetAllocationLoation() << "\n";
76
65
    }
77
66
#endif
78
67
  }
200
189
    const void *ptr = dynamic_cast<const void *> (this);
201
190
 
202
191
    // Search for ptr in allocation_list
 
192
#if defined(NUX_OS_WINDOWS) && !defined(NUX_VISUAL_STUDIO_2010)
 
193
    std::list<void*>::iterator i = std::find(GObjectStats._allocation_list.begin(),
 
194
      GObjectStats._allocation_list.end(), ptr);
 
195
#else
203
196
    auto i = std::find(GObjectStats._allocation_list.begin(),
204
197
                       GObjectStats._allocation_list.end(), ptr);
 
198
#endif
205
199
    return i != GObjectStats._allocation_list.end();
206
200
  }
207
201
 
213
207
//////////////////////////////////////////////////////////////////////
214
208
 
215
209
  Object::Object(bool OwnTheReference, NUX_FILE_LINE_DECL)
 
210
    : allocation_file_name_(__Nux_FileName__)
 
211
    , allocation_line_number_(__Nux_LineNumber__)
 
212
    , reference_count_(new NThreadSafeCounter())
 
213
    , objectptr_count_(new NThreadSafeCounter())
216
214
  {
217
 
    _allocation_file_name      = __Nux_FileName__;
218
 
    _allocation_line_number    = __Nux_LineNumber__;
219
 
 
220
 
    _reference_count      = new NThreadSafeCounter();
221
 
    _weak_reference_count = new NThreadSafeCounter();
222
 
    _objectptr_count     = new NThreadSafeCounter();
223
 
    _destroyed            = new bool(false);
224
 
 
225
 
    _reference_count->Set (1);
226
 
    _weak_reference_count->Set (1);
227
 
 
228
 
    SetOwnedReference (OwnTheReference);
 
215
    reference_count_->Set(1);
 
216
    SetOwnedReference(OwnTheReference);
229
217
  }
230
218
 
231
219
  Object::~Object()
232
220
  {
233
 
    *_destroyed = true;
234
 
 
235
 
    if (IsHeapAllocated ())
236
 
    {
237
 
      // If the object has properly been UnReference, it should have gone through Destroy(). if that is the case then
238
 
      // _reference_count should be NULL or its value (returned by GetValue ()) should be equal to 0;
239
 
      // We can use this to detect when delete is called directly on an object.
240
 
      nuxAssertMsg((_reference_count == 0) || (_reference_count && (_reference_count->GetValue () == 0)),
241
 
                   TEXT("[Object::~Object] Invalid object destruction. Make sure to call UnReference or Dispose (if the object has never been referenced) on the object.\nObject allocated at: %s [%d]"),
242
 
                   _allocation_file_name.GetTCharPtr (),
243
 
                   _allocation_line_number);
244
 
      
245
 
      nuxAssertMsg((_weak_reference_count == 0) || (_weak_reference_count && (_weak_reference_count->GetValue () > 0)),
246
 
                   TEXT("[Object::~Object] Invalid value of the weak reference count pointer. Make sure to call UnReference or Dispose (if the object has never been referenced) on the object.\nObject allocated at: %s [%d]"),
247
 
                   _allocation_file_name.GetTCharPtr (),
248
 
                   _allocation_line_number);
249
 
 
250
 
      if ((_reference_count == 0) && (_weak_reference_count == 0))
251
 
      {
252
 
        delete _destroyed;
253
 
      }
254
 
      else
255
 
      {
256
 
        // There is a smart pointer holding a weak reference to this object. It is the responsibility
257
 
        // of the last smart pointer to delete '_destroyed'.
258
 
      }
259
 
    }
260
 
    else
261
 
    {
262
 
      delete _reference_count;
263
 
      delete _weak_reference_count;
264
 
      delete _objectptr_count;
265
 
      delete _destroyed;
266
 
    }
 
221
    if (IsHeapAllocated())
 
222
    {
 
223
      // If the object has properly been UnReference, it should have gone
 
224
      // through Destroy(). if that is the case then _reference_count should
 
225
      // be NULL or its value (returned by GetValue ()) should be equal to 0;
 
226
      // We can use this to detect when delete is called directly on an
 
227
      // object.
 
228
      if (reference_count_->GetValue() > 0)
 
229
      {
 
230
        LOG_WARN(logger) << "Invalid object destruction, still has "
 
231
                         << reference_count_->GetValue() << " references."
 
232
                         << "\nObject allocated at: " << GetAllocationLoation();
 
233
      }
 
234
    }
 
235
    delete reference_count_;
 
236
    delete objectptr_count_;
267
237
  }
268
238
 
269
239
  bool Object::Reference()
270
240
  {
271
 
    if (!IsHeapAllocated ())
272
 
    {
273
 
      LOG_ERROR(logger) << "Trying to reference an object that was not heap allocated. "
274
 
                        << "\nObject allocated at: " << GetAllocationLoation();
275
 
      return false;
276
 
    }
277
 
 
278
 
    if (_reference_count->GetValue() == 0 || *_destroyed)
279
 
    {
280
 
      // If this happens, all bets are off, and this may crash.
281
 
      LOG_ERROR(logger) << "Trying to reference an object that has been deleted."
282
 
                        << "\nObject allocated at: " << GetAllocationLoation();
 
241
    if (!IsHeapAllocated())
 
242
    {
 
243
      LOG_WARN(logger) << "Trying to reference an object that was not heap allocated."
 
244
                       << "\nObject allocated at: " << GetAllocationLoation();
283
245
      return false;
284
246
    }
285
247
 
290
252
      return true;
291
253
    }
292
254
 
293
 
    _reference_count->Increment();
294
 
    _weak_reference_count->Increment();
 
255
    reference_count_->Increment();
295
256
    return true;
296
257
  }
297
258
 
299
260
  {
300
261
    if (!IsHeapAllocated())
301
262
    {
302
 
      LOG_ERROR(logger) << "Trying to un-reference an object that was not heap allocated. "
303
 
                        << "\nObject allocated at: " << GetAllocationLoation();
 
263
      LOG_WARN(logger) << "Trying to un-reference an object that was not heap allocated."
 
264
                       << "\nObject allocated at: " << GetAllocationLoation();
304
265
      return false;
305
266
    }
306
267
 
307
 
    if (_objectptr_count->GetValue() == _reference_count->GetValue())
 
268
    if (objectptr_count_->GetValue() == reference_count_->GetValue())
308
269
    {
309
270
      // There are ObjectPtr's hosting this object. Release all of them to
310
271
      // destroy this object.  This prevent from calling UnReference () many
311
272
      // times and destroying the object when there are ObjectPtr's hosting
312
273
      // it.  This method should not be called directly in that case.
313
 
      LOG_ERROR(logger) << "There are ObjectPtr hosting this object. "
314
 
                        << "Release all of them to destroy this object. "
315
 
                        << "\nObject allocated at: " << GetAllocationLoation();
 
274
      LOG_WARN(logger) << "There are ObjectPtr hosting this object. "
 
275
                       << "Release all of them to destroy this object. "
 
276
                       << "\nObject allocated at: " << GetAllocationLoation();
316
277
      return false;
317
278
    }
318
279
 
319
 
    _reference_count->Decrement();
320
 
    _weak_reference_count->Decrement();
 
280
    reference_count_->Decrement();
321
281
 
322
 
    if (_reference_count->GetValue() == 0)
 
282
    if (reference_count_->GetValue() == 0)
323
283
    {
324
284
      Destroy();
325
285
      return true;
332
292
  {
333
293
    if (!IsHeapAllocated())
334
294
    {
335
 
      LOG_ERROR(logger) << "Trying to sink an object that was not heap allocated. "
336
 
                        << "\nObject allocated at: " << GetAllocationLoation();
 
295
      LOG_WARN(logger) << "Trying to sink an object that was not heap allocated."
 
296
                       << "\nObject allocated at: " << GetAllocationLoation();
337
297
      return false;
338
298
    }
339
299
 
349
309
 
350
310
  bool Object::Dispose()
351
311
  {
352
 
    // The intent of the Dispose call is to destroy objects with a float reference (reference count is equal to 1 and
353
 
    // the '_owns_the_reference' flag is set to false). In Nux, only widgets object can have a floating reference.
354
 
    // And widgets are only visible if added to the widget tree. 
355
 
    // When an object with a floating reference is added to the widget tree, it becomes "owned'. It looses it
356
 
    // floating reference status but it still has a reference count number of 1.
357
 
    // In practice, since widgets must be added to the widget tree, there should never be a need to call Dispose
 
312
    // The intent of the Dispose call is to destroy objects with a float
 
313
    // reference (reference count is equal to 1 and the '_owns_the_reference'
 
314
    // flag is set to false). In Nux, only widgets object can have a floating
 
315
    // reference.  And widgets are only visible if added to the widget tree.
 
316
    // When an object with a floating reference is added to the widget tree,
 
317
    // it becomes "owned'. It looses it floating reference status but it still
 
318
    // has a reference count number of 1.  In practice, since widgets must be
 
319
    // added to the widget tree, there should never be a need to call Dispose
358
320
    // (except in a few cases).
359
321
 
360
 
    // Dispose() was designed to only destroy objects with floating references, while UnReference() destroys objects
361
 
    // that are "owned" . That is now relaxed. Dispose() calls UnReference().
362
 
 
 
322
    // Dispose() was designed to only destroy objects with floating
 
323
    // references, while UnReference() destroys objects that are "owned".
 
324
    // That is now relaxed. Dispose() calls UnReference().
363
325
    return UnReference();
364
326
  }
365
327
 
366
328
  void Object::Destroy()
367
329
  {
368
 
    if (!IsHeapAllocated ())
369
 
    {
370
 
      LOG_ERROR(logger) << "Trying to destroy an object that was not heap allocated. "
371
 
                        << "\nObject allocated at: " << GetAllocationLoation();
372
 
      return;
373
 
    }
374
 
 
375
 
    nuxAssert (_reference_count->GetValue() == 0);
376
 
 
377
 
    if ((_reference_count->GetValue() == 0) && (_weak_reference_count->GetValue() == 0) && (_objectptr_count->GetValue() == 0))
378
 
    {
379
 
      delete _reference_count;
380
 
      delete _weak_reference_count;
381
 
      delete _objectptr_count;
382
 
      _reference_count = 0;
383
 
      _weak_reference_count = 0;
384
 
      _objectptr_count = 0;
385
 
    }
386
 
    else
387
 
    {
388
 
      if ((_weak_reference_count == NULL) && (_objectptr_count->GetValue() == 0))
389
 
      {
390
 
        nuxDebugMsg (TEXT ("[Object::Destroy] Error on object allocated at %s [%d]:")
391
 
        , _allocation_file_name.GetTCharPtr ()
392
 
        , _allocation_line_number);
393
 
        nuxAssertMsg (0, TEXT("[Object::Destroy] Invalid pointer for the weak reference count."));
394
 
      }
395
 
 
396
 
      if ((_weak_reference_count->GetValue() == 0) && (_objectptr_count->GetValue() == 0))
397
 
      {
398
 
        nuxDebugMsg (TEXT ("[Object::Destroy] Error on object allocated at %s [%d]:")
399
 
          , _allocation_file_name.GetTCharPtr ()
400
 
          , _allocation_line_number);
401
 
        nuxAssertMsg (0, TEXT("[Object::Destroy] Invalid value of the weak reference count."));
402
 
      }
403
 
    }
404
 
 
405
330
    static int delete_depth = 0;
406
331
    ++delete_depth;
 
332
    // Weak smart pointers will clear their pointers when they get this signal.
407
333
    object_destroyed.emit(this);
408
 
    std::string obj_type(this->Type().m_Name);
 
334
    const char* obj_type = this->Type().name;
409
335
    LOG_TRACE(logger) << "Depth: " << delete_depth << ", about to delete "
410
336
                      << obj_type << " allocated at " << GetAllocationLoation();
411
337
    delete this;
413
339
    --delete_depth;
414
340
  }
415
341
 
416
 
  void Object::IncrementWeakCounter()
417
 
  {
418
 
    if (!IsHeapAllocated ())
419
 
    {
420
 
      LOG_ERROR(logger) << "Trying to increment weak counter on an object that was not heap allocated. "
421
 
                        << "\nObject allocated at: " << GetAllocationLoation();
422
 
      return;
423
 
    }
424
 
 
425
 
    _weak_reference_count->Increment();
426
 
  }
427
 
 
428
 
  void Object::DecrementWeakCounter()
429
 
  {
430
 
    if (!IsHeapAllocated())
431
 
    {
432
 
      LOG_ERROR(logger) << "Trying to decrement weak counter on an object that was not heap allocated. "
433
 
                        << "\nObject allocated at: " << GetAllocationLoation();
434
 
      return;
435
 
    }
436
 
 
437
 
    _weak_reference_count->Decrement();
438
 
  }
439
 
 
440
342
  int Object::GetReferenceCount() const
441
343
  {
442
 
    return _reference_count->GetValue();
443
 
  }
444
 
 
445
 
  int Object::GetWeakReferenceCount() const
446
 
  {
447
 
    return _weak_reference_count->GetValue();
 
344
    return reference_count_->GetValue();
448
345
  }
449
346
 
450
347
std::string Object::GetAllocationLoation() const
451
348
{
452
349
  std::ostringstream sout;
453
 
  sout << _allocation_file_name.GetTCharPtr()
454
 
       << ":" << _allocation_line_number;
 
350
  sout << allocation_file_name_ << ":" << allocation_line_number_;
455
351
  return sout.str();
456
352
}
457
353