2005/5/9

     
 

SharedOwning.cpp

artefaktur
// -*- mode:C++; tab-width:2; c-basic-offset:2; indent-tabs-mode:nil -*- 
//
// Copyright (C) 2000-2005 by Roger Rene Kommer / artefaktur, Kassel, Germany.
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Library General Public License (LGPL).
// 
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.	 See the 
// License ACDK-FreeLicense document enclosed in the distribution
// for more for more details.
// This file is part of the Artefaktur Component Development Kit:
//                         ACDK
// 
// Please refer to
// - http://www.acdk.de
// - http://www.artefaktur.com
// - http://acdk.sourceforge.net
// for more information.
// 
// $Header: /cvsroot/acdk/acdk/acdk_core/src/acdk/lang/ref/SharedOwning.cpp,v 1.10 2005/04/21 10:21:07 kommer Exp $

#include <acdk.h>
#include <acdk/lang/Integer.h>
#include <acdk/lang/sys/core_system.h>
#include <acdk/lang/sys/ObjectHeap.h>
#include "SharedOwning.h"
#include <set>

namespace acdk {
namespace lang {
namespace ref {

//#define LOCAL_DEBUG
#if defined(LOCAL_DEBUG)
#define DOUT(msg) do { sys::coreout << msg << sys::eofl; } while(false)
#else
/FONT>
#define DOUT(msg) do { } while(false)
#endif
/FONT>
/*
  void registerSharedObject(acdk::lang::Object* obj, acdk::lang::Object* pointsTo, bool isMaster)
  {
    SharedOwned& sharedOwning = getElement(obj);
    if (sharedOwning._obj == 0)
      NotifyObjectEvent::add(obj, this);
    _sharedElements.push_back(SharedOwned(obj, pointsTo, isMaster));
    if (isMaster == false && pointsTo != 0)
      (*pointsTo)->releaseRef();
  }*/
  
SharedOwning::~SharedOwning()
{
  NotifyObjectEvent::removeListener(this);
}

void 
SharedOwning::registerSharedObject(acdk::lang::Object* obj, acdk::lang::Object* refedBy, bool isMaster)
{
  DOUT("SharedOwning:registerSharedObject: " << (void*)obj << "; refedBy: " << (refedBy != 0 ? (void*)refedBy->impl() : 0));
  SharedOwned& sharedOwning = getElement(obj);
  if (sharedOwning._obj == 0)
    NotifyObjectEvent::add(obj, this);
 _sharedElements.push_back(SharedOwned(obj, refedBy, isMaster));
 if (isMaster == true && refedBy != 0 && refedBy->impl() != 0)
  refedBy->impl()->releaseRef();
}


void 
SharedOwning::registerSharedObjectRefs(acdk::lang::Object* masterRef, acdk::lang::Object* slaveRef)
{
  DOUT("SharedOwning:registerSharedObject: master: " << (void*)masterRef->impl() << "; slave: " << (void*)slaveRef->impl());
  registerSharedObject(masterRef->impl(), masterRef, true);
  registerSharedObject(slaveRef->impl(), slaveRef, false);
}

void 
SharedOwning::unregisterSharedObjectRefs(acdk::lang::Object* masterRef, acdk::lang::Object* slaveRef, bool onDelete)
{
  unregisterSharedObject(masterRef->impl(), slaveRef, onDelete);
  unregisterSharedObject(slaveRef->impl(), masterRef, onDelete);
}

void 
SharedOwning::unregisterAll()
{
  //NotifyObjectEvent::removeListener(this);
  //_sharedElements.resize(0);
  
  for (SharedOwnedVec::iterator it = _sharedElements.begin();
      it < _sharedElements.end();
      ++it)
  {
    if (it->_obj != 0)
    {
      if (it->_isMaster == true)
      {
        
        it->_obj->addRef();
        DOUT("SharedOwn reset: " << (void*)it->_obj << "; rc=" << it->_obj->refCount());
      }
    }
  }
  _sharedElements.resize(0);
}

void 
SharedOwning::setMaster(SharedOwned& shown, bool isMaster) 
{
  if (isMaster == true)
  {
    DOUT("SharedOwning: " << (void*)shown._obj << " now Master");
    shown._isMaster = true;
    shown._obj->releaseRef();
  }
  else
  {
    DOUT("SharedOwning: " << (void*)shown._obj  << " now Slave");
    shown._isMaster = false;
    shown._obj->addRef();
  }
}



bool 
SharedOwning::isNowMaster(SharedOwned& toDel, SharedOwned& el, SharedOwned& oldMaster) 
{
  if (el._obj == 0)
    return false;
  if (el._obj->refCount() > 1)
  {
    setMaster(el, true);
    if (oldMaster._obj != 0)
      setMaster(oldMaster, false);
    else if (toDel._isMaster == true)
    {
      setMaster(toDel, false);
      return true;
    }
    return true;
  }
  /* not correctly working
  else if (toDel._obj != el._obj)
  {
    static std::set<void*> _currentlyInspected;
    if (_currentlyInspected.find((void*)el._obj) != _currentlyInspected.end())
      return false;

    _currentlyInspected.insert((void*)el._obj);
    bool bret = acdk::lang::sys::ObjectHeap::notifyBeforeObjectDestruction(el._obj);
    _currentlyInspected.erase((void*)el._obj);
    if (bret == true)
      return false;
    setMaster(el, true);
    if (oldMaster._obj != 0)
      setMaster(oldMaster, false);
    else if (toDel._isMaster == true)
    {
      setMaster(toDel, false);
      return true;
    }
    return true;
  }*/
  return false;
}


SharedOwned& 
SharedOwning::getMaster() 
{
  for (SharedOwnedVec::iterator it = _sharedElements.begin();
      it < _sharedElements.end();
      ++it)
  {
    if (it->_isMaster == true)
      return *it;
  }
  return _getEmtpySharedOwned();
}

SharedOwned& 
SharedOwning::getElement(acdk::lang::Object* obj) 
{
  for (SharedOwnedVec::iterator it = _sharedElements.begin();
      it < _sharedElements.end();
      ++it)
  {
    if (it->_obj == obj)
      return *it;
  }
  return _getEmtpySharedOwned();
}

bool 
SharedOwning::canRelease(acdk::lang::Object* obj) 
{
  dump("canRelease=?");
  SharedOwned& oldMaster = getMaster();
  SharedOwned& sharedOwning = getElement(obj);
  
  for (SharedOwnedVec::iterator it = _sharedElements.begin();
       it < _sharedElements.end();
        ++it)
  {
    if (isNowMaster(sharedOwning, *it, oldMaster) == true)
    {
      dump("canRelease=false");
      return false;
    }
  }
  if (sharedOwning._isMaster == false && oldMaster._obj != 0)
  {
    oldMaster._obj->addRef();
  }
  dump("canRelease=true");
  removeElement(obj);
  return true;
}

void 
SharedOwning::removeElement(acdk::lang::Object* obj)
{
  int rc  = obj->refCount();
fromBegin:
  for (SharedOwnedVec::iterator it = _sharedElements.begin();
      it < _sharedElements.end();
      ++it)
  {
    if (obj == it->_obj)
    {
      
      if (it->_refedBy != 0)
      {
        //(*it->_refedBy) = Nil;
        it->_refedBy->_reset_ptr();
        rc  = obj->refCount();
      }
      _sharedElements.erase(it);
      goto fromBegin;
      return;
    }
  }
}

void 
SharedOwning::unregisterSharedObject(acdk::lang::Object* obj, acdk::lang::Object* pointsTo, bool onDelete)
{
  removeElement(obj);
}


//static 
SharedOwned& 
SharedOwning::_getEmtpySharedOwned() 
{
  static SharedOwned emptyMaster;
  return emptyMaster;
}

void 
SharedOwning::dump(const char* msg)
{
#if defined(LOCAL_DEBUG)
  if (acdk::lang::sys::core_system::inMain() == false)
    return;
  StringBuffer sb;
  sb << msg << " ";
  for (SharedOwnedVec::iterator it = _sharedElements.begin();
       it < _sharedElements.end();
        ++it)
  {
          sb << Integer::toHexString(int((void*)it->_obj)) << ": " << it->_isMaster << ": " << (it->_obj == 0 ? -1 : it->_obj->refCount()) << /* "; " << (it->_obj == 0 ? RString("Nil") : it->_obj->toString()) << */ "|";
  }
  DOUT(sb.toString()->c_str());
#endif //defined(LOCAL_DEBUG)
}

} // ref
} // lang
} // acdk