<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cacheline.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: rt $ $Date: 2005-09-08 04:23:13 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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 GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#include "cacheline.hxx"

#ifndef CONFIGMGR_SETNODEACCESS_HXX
#include "setnodeaccess.hxx"
#endif
#ifndef CONFIGMGR_TREEACCESSOR_HXX
#include "treeaccessor.hxx"
#endif
#ifndef CONFIGMGR_BUILDDATA_HXX
#include "builddata.hxx"
#endif

#ifndef CONFIGMGR_TREE_CHANGEFACTORY_HXX
#include "treechangefactory.hxx"
#endif
#ifndef INCLUDED_CONFIGMGR_MERGECHANGE_HXX
#include "mergechange.hxx"
#endif
#ifndef CONFIGMGR_CONFIGEXCEPT_HXX_
#include "configexcept.hxx"
#endif

#ifndef _CONFIGMGR_TRACER_HXX_
#include "tracer.hxx"
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

namespace configmgr
{
// -----------------------------------------------------------------------------
    static inline CacheLine::Name implExtractModuleName(CacheLine::Path const& _aConfigPath)
    {
        return _aConfigPath.getModuleName();
    }

// -----------------------------------------------------------------------------
// class CacheLine
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------

    CacheLine::CacheLine(Name const & _aModuleName, memory::HeapManager & _rHeapImpl)
    : m_storage(_rHeapImpl  )
    , m_base()
    , m_name(_aModuleName)
    , m_nDataRefs(0)
    {
    }
// -----------------------------------------------------------------------------

    CacheLine::CacheLine(Name const & _aModuleName, memory::HeapManager & _rHeapImpl,
                            memory::SegmentAddress const & _aSegment)
    : m_storage(_rHeapImpl,_aSegment.id)
    , m_base( memory::Pointer(_aSegment.base) )
    , m_name(_aModuleName)
    , m_nDataRefs(0)
    {
    }
// -----------------------------------------------------------------------------

    memory::SegmentAddress CacheLine::getDataSegmentAddress() const
    {
        memory::SegmentAddress aResult;

        aResult.id      = m_storage.getId();
        aResult.base    = m_base.addressValue();

        return aResult;
    }

// -----------------------------------------------------------------------------

    void CacheLine::setBase(data::TreeAddress _base)
    {
        OSL_PRECOND(!m_base.is(), "CacheLine: Data base address was already set");
        OSL_PRECOND(  _base.is(), "CacheLine: Cannot set NULL base address");
        m_base = _base;
    }
// -----------------------------------------------------------------------------

    CacheLineRef CacheLine::createAttached( Name const & _aModuleName,
                                            memory::HeapManager & _rHeapImpl,
                                            memory::SegmentAddress const & _aSegment
                                          ) CFG_UNO_THROW_RTE(  )
    {
        if (_aModuleName.isEmpty())
        {
            OSL_ENSURE(false, "Cannot make a cache line without a name");
            return NULL;
        }
        if (_aSegment.isNull())
        {
            OSL_ENSURE(false, "Cannot attach a cache line to a NULL segment");
            return NULL;
        }

        CacheLineRef xResult = new CacheLine(_aModuleName,_rHeapImpl,_aSegment);

        return xResult;
    }
// -----------------------------------------------------------------------------

    CacheLineRef CacheLine::createNew(  Name const & _aModuleName,
                                        memory::HeapManager & _rHeapImpl
                                      ) CFG_UNO_THROW_RTE(  )
    {
        if (_aModuleName.isEmpty())
        {
            OSL_ENSURE(false, "Cannot make a cache line without a name");
            return NULL;
        }

        CacheLineRef xResult = new CacheLine(_aModuleName,_rHeapImpl);

        return xResult;
    }
// -------------------------------------------------------------------------

    CacheLine::Name CacheLine::getModuleName() const
    {
        return m_name;
    }
// -----------------------------------------------------------------------------

    data::TreeAddress CacheLine::getPartialTree(memory::Accessor const & _aAccessor, Path const& aConfigName) const
    {
        data::SetNodeAccess aParentSet( internalGetNode(_aAccessor, aConfigName.getParentPath()) );

        if (aParentSet.isValid())
            return aParentSet.getElementTree(aConfigName.getLocalName().getName()).address();
        else
            return data::TreeAddress();
    }
// -----------------------------------------------------------------------------

    bool CacheLine::hasDefaults(memory::Accessor const & _anAccessor) const
    {
        if ( !m_base.is() ) return false; // cannot get defaults without data

        data::TreeAccessor aModuleTree(_anAccessor, m_base);
        OSL_ASSERT( aModuleTree.isValid());

        return aModuleTree.data().hasDefaultsAvailable();
    }
// -----------------------------------------------------------------------------
    data::NodeAccess CacheLine::internalGetNode(memory::Accessor const & _anAccessor, Path const& aConfigName) const
    {
        OSL_ENSURE( m_base.is(), "Cannot get a node from a dataless module");

        data::TreeAccessor aModuleTree(_anAccessor, m_base);
        OSL_ASSERT( aModuleTree.isValid());

        data::NodeAccess aNode = aModuleTree.getRootNode().toNodeAccess();
        OSL_ENSURE( aNode.isValid(), "CacheLine contains no nodes");

        Path::Iterator it = aConfigName.begin();
        OSL_ENSURE( it != aConfigName.end(), "Empty Path can't match any module");
        OSL_ENSURE( aNode.getName() == it->getInternalName(), "Module part in config path does not match selected CacheLine");

        // find child of node
        // might be done using a visitor
        while(aNode.isValid() && ++it != aConfigName.end())
        {
            aNode = data::getSubnode(aNode,it->getName());
        }
        return aNode;
    }
// -----------------------------------------------------------------------------

    data::NodeAddress CacheLine::getNode(memory::Accessor const & _aAccessor, Path const& aConfigName) const
    {
        data::NodeAccess aNode = internalGetNode(_aAccessor, aConfigName);
        return aNode.address();
    }
// -------------------------------------------------------------------------

    data::TreeAddress CacheLine::setComponentData( memory::UpdateAccessor& _aAccessToken,
                                                           backend::ComponentData const & _aComponentInstance,
                                                           bool _bWithDefaults
                                                         ) CFG_UNO_THROW_RTE(  )
    {
        OSL_PRECOND(_aComponentInstance.data.get(), "CacheLine::insertDefaults: inserting NULL defaults !");
        OSL_PRECOND(_aComponentInstance.name == this->getModuleName(),"Data location does not match module");

        OSL_PRECOND(!base().is(), "Data is already loaded");

        if (!base().is()) // no data yet
        {
            this->setBase( data::buildTree(_aAccessToken, _aComponentInstance.data->getName(), *_aComponentInstance.data, _bWithDefaults) );
        }

        return this->base();
    }
// -----------------------------------------------------------------------------

    data::TreeAddress CacheLine::insertDefaults( memory::UpdateAccessor& _aAccessToken,
                                                 backend::NodeInstance const & _aDefaultInstance
                                               ) CFG_UNO_THROW_RTE(  )
    {
        OSL_PRECOND(_aDefaultInstance.data().get(), "CacheLine::insertDefaults: inserting NULL defaults !");
        OSL_PRECOND(_aDefaultInstance.root().isModuleRoot(), "Should have complete component to fill tree with defaults");
        OSL_PRECOND(_aDefaultInstance.root().getModuleName() == this->getModuleName(),"Data location does not match module");

        OSL_PRECOND(m_base.is(), "Data must already be loaded to insert defaults");

        if (m_base.is())
        {
            data::mergeDefaults(_aAccessToken,m_base,*_aDefaultInstance.data());
        }

        return m_base;
    }
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

    ExtendedCacheLine::ExtendedCacheLine(Name const & _aModuleName, memory::HeapManager & _rHeapImpl)
    : CacheLine(_aModuleName,_rHeapImpl)
    , m_pPending()
    {
    }

// -----------------------------------------------------------------------------

    ExtendedCacheLine::ExtendedCacheLine(Name const & _aModuleName, memory::HeapManager & _rHeapImpl,
                                            memory::SegmentAddress const & _aSegment)
    : CacheLine(_aModuleName,_rHeapImpl,_aSegment)
    , m_pPending()
    {
    }

// -----------------------------------------------------------------------------

    ExtendedCacheLineRef ExtendedCacheLine::createAttached( Name const & _aModuleName,
                                                            memory::HeapManager & _rHeapImpl,
                                                            memory::SegmentAddress const & _aSegment
                                                          ) CFG_UNO_THROW_RTE(  )
    {
        if (_aModuleName.isEmpty())
        {
            OSL_ENSURE(false, "Cannot make a cache line without a name");
            return NULL;
        }
        if (_aSegment.isNull())
        {
            OSL_ENSURE(false, "Cannot attach a cache line to a NULL segment");
            return NULL;
        }

        ExtendedCacheLineRef xResult = new ExtendedCacheLine(_aModuleName,_rHeapImpl,_aSegment);

        return xResult;
    }
// -----------------------------------------------------------------------------

    ExtendedCacheLineRef ExtendedCacheLine::createNew(  Name const & _aModuleName,
                                                        memory::HeapManager & _rHeapImpl
                                                      ) CFG_UNO_THROW_RTE(  )
    {
        if (_aModuleName.isEmpty())
        {
            OSL_ENSURE(false, "Cannot make a cache line without a name");
            return NULL;
        }

        ExtendedCacheLineRef xResult = new ExtendedCacheLine(_aModuleName,_rHeapImpl);

        return xResult;
    }
// -------------------------------------------------------------------------

    void ExtendedCacheLine::addPending(backend::ConstUpdateInstance const & _anUpdate) CFG_UNO_THROW_RTE(  )
    {
        Path aRootLocation = _anUpdate.root().location();

        OSL_PRECOND(!aRootLocation.isRoot(),"Pending change cannot be located at root");
        OSL_PRECOND(aRootLocation.getModuleName() == this->getModuleName(),"Pending change location does not match module");

        OSL_PRECOND(_anUpdate.data() != NULL,"Adding NULL 'pending' change");
        OSL_PRECOND(_anUpdate.data()->getNodeName() == aRootLocation.getLocalName().getName().toString(),
                    "Path to pending change does not match change name");

        using std::auto_ptr;

        // first make the _pSubtreeChange a full tree starting at the module root
        auto_ptr<SubtreeChange> pRootChange;
        SubtreeChange *pExistingEntry = NULL;

        Path::Iterator last = aRootLocation.end();

        OSL_ASSERT(last != aRootLocation.begin());
        --last;

        for (Path::Iterator it = aRootLocation.begin();
             it != last;
             ++it)
        {
            OSL_ASSERT( it   != aRootLocation.end());
            OSL_ASSERT( it+1 != aRootLocation.end());
            // We need to create a new SubtreeChange
            Name const aChangeName      = it->getName();
            Name const aElementTypeName = (it+1)->getTypeName();

            auto_ptr<SubtreeChange> pNewChange =
                        OTreeChangeFactory::createDummyChange(aChangeName, aElementTypeName);

            if (pExistingEntry == NULL)
            {
                OSL_ASSERT(pRootChange.get() == NULL);

                pRootChange     = pNewChange;
                pExistingEntry  = pRootChange.get();
            }
            else
            {
                OSL_ASSERT(pRootChange.get() != NULL);

                pExistingEntry->addChange(base_ptr(pNewChange));

                Change* pChange = pExistingEntry->getChange(aChangeName.toString());
                pExistingEntry = static_cast<SubtreeChange*>(pChange);

                OSL_ENSURE(pChange && pChange->ISA(SubtreeChange), "ERROR: Cannot recover change just added");
            }
        }

        auto_ptr<SubtreeChange> pAddedChange( new SubtreeChange(*_anUpdate.data(), SubtreeChange::DeepChildCopy()) );

        if (aRootLocation.getDepth() > 1)
        {
            OSL_ASSERT(pRootChange.get() != NULL && pExistingEntry != NULL);

            // the _pSubtreeChange did not start at root, so add its clone to the built dummies
            pExistingEntry->addChange(base_ptr(pAddedChange));
        }
        else
        {
            OSL_ASSERT(pRootChange.get() == NULL && pExistingEntry == NULL);

            // the _pSubtreeChange starts at root, so just reset pRootChange
            pRootChange = pAddedChange;
        }
        OSL_ASSERT(pRootChange.get() != NULL);

        if (m_pPending.get() == NULL)
        {
            // no merge is need, because the existing pending changes are empty
            m_pPending = pRootChange;
        }
        else
        {
            try
            {
                // We need to merge the new rebased changes into the m_pPending
                combineUpdates(*pRootChange,*m_pPending);
            }
            catch (configuration::Exception& e)
            {
                OUString sMessage(RTL_CONSTASCII_USTRINGPARAM("Update cache for module: Could not add pending changes at"));

                sMessage += aRootLocation.toString();

                sMessage += OUString(RTL_CONSTASCII_USTRINGPARAM(". Internal Exception:")) + e.message();

                throw uno::RuntimeException(sMessage,0);
            }
        }

        OSL_POSTCOND(m_pPending.get() != NULL, "Could not insert new pending changes");
    }
// -----------------------------------------------------------------------------

} // namespace configmgr

<commit_msg>INTEGRATION: CWS pchfix02 (1.8.60); FILE MERGED 2006/09/01 17:20:46 kaib 1.8.60.1: #i68856# Added header markers and pch files<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: cacheline.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: obo $ $Date: 2006-09-16 15:25:36 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    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 GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_configmgr.hxx"

#include "cacheline.hxx"

#ifndef CONFIGMGR_SETNODEACCESS_HXX
#include "setnodeaccess.hxx"
#endif
#ifndef CONFIGMGR_TREEACCESSOR_HXX
#include "treeaccessor.hxx"
#endif
#ifndef CONFIGMGR_BUILDDATA_HXX
#include "builddata.hxx"
#endif

#ifndef CONFIGMGR_TREE_CHANGEFACTORY_HXX
#include "treechangefactory.hxx"
#endif
#ifndef INCLUDED_CONFIGMGR_MERGECHANGE_HXX
#include "mergechange.hxx"
#endif
#ifndef CONFIGMGR_CONFIGEXCEPT_HXX_
#include "configexcept.hxx"
#endif

#ifndef _CONFIGMGR_TRACER_HXX_
#include "tracer.hxx"
#endif
#ifndef _OSL_DIAGNOSE_H_
#include <osl/diagnose.h>
#endif

namespace configmgr
{
// -----------------------------------------------------------------------------
    static inline CacheLine::Name implExtractModuleName(CacheLine::Path const& _aConfigPath)
    {
        return _aConfigPath.getModuleName();
    }

// -----------------------------------------------------------------------------
// class CacheLine
// -----------------------------------------------------------------------------

// -----------------------------------------------------------------------------

    CacheLine::CacheLine(Name const & _aModuleName, memory::HeapManager & _rHeapImpl)
    : m_storage(_rHeapImpl  )
    , m_base()
    , m_name(_aModuleName)
    , m_nDataRefs(0)
    {
    }
// -----------------------------------------------------------------------------

    CacheLine::CacheLine(Name const & _aModuleName, memory::HeapManager & _rHeapImpl,
                            memory::SegmentAddress const & _aSegment)
    : m_storage(_rHeapImpl,_aSegment.id)
    , m_base( memory::Pointer(_aSegment.base) )
    , m_name(_aModuleName)
    , m_nDataRefs(0)
    {
    }
// -----------------------------------------------------------------------------

    memory::SegmentAddress CacheLine::getDataSegmentAddress() const
    {
        memory::SegmentAddress aResult;

        aResult.id      = m_storage.getId();
        aResult.base    = m_base.addressValue();

        return aResult;
    }

// -----------------------------------------------------------------------------

    void CacheLine::setBase(data::TreeAddress _base)
    {
        OSL_PRECOND(!m_base.is(), "CacheLine: Data base address was already set");
        OSL_PRECOND(  _base.is(), "CacheLine: Cannot set NULL base address");
        m_base = _base;
    }
// -----------------------------------------------------------------------------

    CacheLineRef CacheLine::createAttached( Name const & _aModuleName,
                                            memory::HeapManager & _rHeapImpl,
                                            memory::SegmentAddress const & _aSegment
                                          ) CFG_UNO_THROW_RTE(  )
    {
        if (_aModuleName.isEmpty())
        {
            OSL_ENSURE(false, "Cannot make a cache line without a name");
            return NULL;
        }
        if (_aSegment.isNull())
        {
            OSL_ENSURE(false, "Cannot attach a cache line to a NULL segment");
            return NULL;
        }

        CacheLineRef xResult = new CacheLine(_aModuleName,_rHeapImpl,_aSegment);

        return xResult;
    }
// -----------------------------------------------------------------------------

    CacheLineRef CacheLine::createNew(  Name const & _aModuleName,
                                        memory::HeapManager & _rHeapImpl
                                      ) CFG_UNO_THROW_RTE(  )
    {
        if (_aModuleName.isEmpty())
        {
            OSL_ENSURE(false, "Cannot make a cache line without a name");
            return NULL;
        }

        CacheLineRef xResult = new CacheLine(_aModuleName,_rHeapImpl);

        return xResult;
    }
// -------------------------------------------------------------------------

    CacheLine::Name CacheLine::getModuleName() const
    {
        return m_name;
    }
// -----------------------------------------------------------------------------

    data::TreeAddress CacheLine::getPartialTree(memory::Accessor const & _aAccessor, Path const& aConfigName) const
    {
        data::SetNodeAccess aParentSet( internalGetNode(_aAccessor, aConfigName.getParentPath()) );

        if (aParentSet.isValid())
            return aParentSet.getElementTree(aConfigName.getLocalName().getName()).address();
        else
            return data::TreeAddress();
    }
// -----------------------------------------------------------------------------

    bool CacheLine::hasDefaults(memory::Accessor const & _anAccessor) const
    {
        if ( !m_base.is() ) return false; // cannot get defaults without data

        data::TreeAccessor aModuleTree(_anAccessor, m_base);
        OSL_ASSERT( aModuleTree.isValid());

        return aModuleTree.data().hasDefaultsAvailable();
    }
// -----------------------------------------------------------------------------
    data::NodeAccess CacheLine::internalGetNode(memory::Accessor const & _anAccessor, Path const& aConfigName) const
    {
        OSL_ENSURE( m_base.is(), "Cannot get a node from a dataless module");

        data::TreeAccessor aModuleTree(_anAccessor, m_base);
        OSL_ASSERT( aModuleTree.isValid());

        data::NodeAccess aNode = aModuleTree.getRootNode().toNodeAccess();
        OSL_ENSURE( aNode.isValid(), "CacheLine contains no nodes");

        Path::Iterator it = aConfigName.begin();
        OSL_ENSURE( it != aConfigName.end(), "Empty Path can't match any module");
        OSL_ENSURE( aNode.getName() == it->getInternalName(), "Module part in config path does not match selected CacheLine");

        // find child of node
        // might be done using a visitor
        while(aNode.isValid() && ++it != aConfigName.end())
        {
            aNode = data::getSubnode(aNode,it->getName());
        }
        return aNode;
    }
// -----------------------------------------------------------------------------

    data::NodeAddress CacheLine::getNode(memory::Accessor const & _aAccessor, Path const& aConfigName) const
    {
        data::NodeAccess aNode = internalGetNode(_aAccessor, aConfigName);
        return aNode.address();
    }
// -------------------------------------------------------------------------

    data::TreeAddress CacheLine::setComponentData( memory::UpdateAccessor& _aAccessToken,
                                                           backend::ComponentData const & _aComponentInstance,
                                                           bool _bWithDefaults
                                                         ) CFG_UNO_THROW_RTE(  )
    {
        OSL_PRECOND(_aComponentInstance.data.get(), "CacheLine::insertDefaults: inserting NULL defaults !");
        OSL_PRECOND(_aComponentInstance.name == this->getModuleName(),"Data location does not match module");

        OSL_PRECOND(!base().is(), "Data is already loaded");

        if (!base().is()) // no data yet
        {
            this->setBase( data::buildTree(_aAccessToken, _aComponentInstance.data->getName(), *_aComponentInstance.data, _bWithDefaults) );
        }

        return this->base();
    }
// -----------------------------------------------------------------------------

    data::TreeAddress CacheLine::insertDefaults( memory::UpdateAccessor& _aAccessToken,
                                                 backend::NodeInstance const & _aDefaultInstance
                                               ) CFG_UNO_THROW_RTE(  )
    {
        OSL_PRECOND(_aDefaultInstance.data().get(), "CacheLine::insertDefaults: inserting NULL defaults !");
        OSL_PRECOND(_aDefaultInstance.root().isModuleRoot(), "Should have complete component to fill tree with defaults");
        OSL_PRECOND(_aDefaultInstance.root().getModuleName() == this->getModuleName(),"Data location does not match module");

        OSL_PRECOND(m_base.is(), "Data must already be loaded to insert defaults");

        if (m_base.is())
        {
            data::mergeDefaults(_aAccessToken,m_base,*_aDefaultInstance.data());
        }

        return m_base;
    }
// -----------------------------------------------------------------------------
// -----------------------------------------------------------------------------

    ExtendedCacheLine::ExtendedCacheLine(Name const & _aModuleName, memory::HeapManager & _rHeapImpl)
    : CacheLine(_aModuleName,_rHeapImpl)
    , m_pPending()
    {
    }

// -----------------------------------------------------------------------------

    ExtendedCacheLine::ExtendedCacheLine(Name const & _aModuleName, memory::HeapManager & _rHeapImpl,
                                            memory::SegmentAddress const & _aSegment)
    : CacheLine(_aModuleName,_rHeapImpl,_aSegment)
    , m_pPending()
    {
    }

// -----------------------------------------------------------------------------

    ExtendedCacheLineRef ExtendedCacheLine::createAttached( Name const & _aModuleName,
                                                            memory::HeapManager & _rHeapImpl,
                                                            memory::SegmentAddress const & _aSegment
                                                          ) CFG_UNO_THROW_RTE(  )
    {
        if (_aModuleName.isEmpty())
        {
            OSL_ENSURE(false, "Cannot make a cache line without a name");
            return NULL;
        }
        if (_aSegment.isNull())
        {
            OSL_ENSURE(false, "Cannot attach a cache line to a NULL segment");
            return NULL;
        }

        ExtendedCacheLineRef xResult = new ExtendedCacheLine(_aModuleName,_rHeapImpl,_aSegment);

        return xResult;
    }
// -----------------------------------------------------------------------------

    ExtendedCacheLineRef ExtendedCacheLine::createNew(  Name const & _aModuleName,
                                                        memory::HeapManager & _rHeapImpl
                                                      ) CFG_UNO_THROW_RTE(  )
    {
        if (_aModuleName.isEmpty())
        {
            OSL_ENSURE(false, "Cannot make a cache line without a name");
            return NULL;
        }

        ExtendedCacheLineRef xResult = new ExtendedCacheLine(_aModuleName,_rHeapImpl);

        return xResult;
    }
// -------------------------------------------------------------------------

    void ExtendedCacheLine::addPending(backend::ConstUpdateInstance const & _anUpdate) CFG_UNO_THROW_RTE(  )
    {
        Path aRootLocation = _anUpdate.root().location();

        OSL_PRECOND(!aRootLocation.isRoot(),"Pending change cannot be located at root");
        OSL_PRECOND(aRootLocation.getModuleName() == this->getModuleName(),"Pending change location does not match module");

        OSL_PRECOND(_anUpdate.data() != NULL,"Adding NULL 'pending' change");
        OSL_PRECOND(_anUpdate.data()->getNodeName() == aRootLocation.getLocalName().getName().toString(),
                    "Path to pending change does not match change name");

        using std::auto_ptr;

        // first make the _pSubtreeChange a full tree starting at the module root
        auto_ptr<SubtreeChange> pRootChange;
        SubtreeChange *pExistingEntry = NULL;

        Path::Iterator last = aRootLocation.end();

        OSL_ASSERT(last != aRootLocation.begin());
        --last;

        for (Path::Iterator it = aRootLocation.begin();
             it != last;
             ++it)
        {
            OSL_ASSERT( it   != aRootLocation.end());
            OSL_ASSERT( it+1 != aRootLocation.end());
            // We need to create a new SubtreeChange
            Name const aChangeName      = it->getName();
            Name const aElementTypeName = (it+1)->getTypeName();

            auto_ptr<SubtreeChange> pNewChange =
                        OTreeChangeFactory::createDummyChange(aChangeName, aElementTypeName);

            if (pExistingEntry == NULL)
            {
                OSL_ASSERT(pRootChange.get() == NULL);

                pRootChange     = pNewChange;
                pExistingEntry  = pRootChange.get();
            }
            else
            {
                OSL_ASSERT(pRootChange.get() != NULL);

                pExistingEntry->addChange(base_ptr(pNewChange));

                Change* pChange = pExistingEntry->getChange(aChangeName.toString());
                pExistingEntry = static_cast<SubtreeChange*>(pChange);

                OSL_ENSURE(pChange && pChange->ISA(SubtreeChange), "ERROR: Cannot recover change just added");
            }
        }

        auto_ptr<SubtreeChange> pAddedChange( new SubtreeChange(*_anUpdate.data(), SubtreeChange::DeepChildCopy()) );

        if (aRootLocation.getDepth() > 1)
        {
            OSL_ASSERT(pRootChange.get() != NULL && pExistingEntry != NULL);

            // the _pSubtreeChange did not start at root, so add its clone to the built dummies
            pExistingEntry->addChange(base_ptr(pAddedChange));
        }
        else
        {
            OSL_ASSERT(pRootChange.get() == NULL && pExistingEntry == NULL);

            // the _pSubtreeChange starts at root, so just reset pRootChange
            pRootChange = pAddedChange;
        }
        OSL_ASSERT(pRootChange.get() != NULL);

        if (m_pPending.get() == NULL)
        {
            // no merge is need, because the existing pending changes are empty
            m_pPending = pRootChange;
        }
        else
        {
            try
            {
                // We need to merge the new rebased changes into the m_pPending
                combineUpdates(*pRootChange,*m_pPending);
            }
            catch (configuration::Exception& e)
            {
                OUString sMessage(RTL_CONSTASCII_USTRINGPARAM("Update cache for module: Could not add pending changes at"));

                sMessage += aRootLocation.toString();

                sMessage += OUString(RTL_CONSTASCII_USTRINGPARAM(". Internal Exception:")) + e.message();

                throw uno::RuntimeException(sMessage,0);
            }
        }

        OSL_POSTCOND(m_pPending.get() != NULL, "Could not insert new pending changes");
    }
// -----------------------------------------------------------------------------

} // namespace configmgr

<|endoftext|>


<commit_before>/*
    Copyright 2012 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY JOE HERMASZEWSKI "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
    EVENT SHALL JOE HERMASZEWSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are
    those of the authors and should not be interpreted as representing official
    policies, either expressed or implied, of Joe Hermaszewski.
*/

#include "shader_writer.hpp"

#include <algorithm>
#include <cassert>
#include <map>
#include <memory>
#include <set>
#include <stack>
#include <string>
#include <sstream>
#include <vector>

#include <compiler/complete_type.hpp>
#include <compiler/entry_function.hpp>
#include <compiler/generic_value.hpp>
#include <compiler/function.hpp>
#include <compiler/variable.hpp>
#include <compiler/semantic_info.hpp>
#include <compiler/tokens/expressions/expression.hpp>
#include <compiler/tokens/expressions/postfix_operator.hpp>
#include <joelang/context.hpp>
#include <joelang/shader.hpp>

namespace JoeLang
{
namespace Compiler
{

const std::string ShaderWriter::s_GLSLVersion = "150";

ShaderWriter::ShaderWriter( const Context& context )
    :m_Context( context )
{
    m_Shader.setf( std::ios_base::scientific );
    m_Shader.setf( std::ios_base::boolalpha );
    m_Shader.setf( std::ios_base::showpoint );
}

std::string ShaderWriter::GenerateGLSL( const EntryFunction& entry_function )
{
    GenerateShader( entry_function );

    std::string ret = m_Shader.str();

    // reset things
    m_Shader.str("");

    assert( m_Indentation == 0 && "Unmatched indentations" );

    // return an empty string if we've had an error
    if( m_Good )
        return ret;
    else
        return "";
}

void ShaderWriter::PushIndentation()
{
    ++m_Indentation;
}

void ShaderWriter::PopIndentation()
{
    assert( m_Indentation > 0 && "Trying to pop 0 indentation" );
    --m_Indentation;
}

std::string ShaderWriter::Mangle( const std::string& identifier,
                                  IdentifierType identifier_type )
{
    const static std::map<IdentifierType, std::string> prefix_map
    {
        { IdentifierType::VARIABLE,    "_"  },
        { IdentifierType::IN_VARYING,  "i_"  },
        { IdentifierType::OUT_VARYING, "o_"  },
        { IdentifierType::FUNCTION,    "f_" }
    };
    return prefix_map.at(identifier_type) + identifier;
}

ShaderWriter& ShaderWriter::operator << ( const CompleteType& value )
{
    value.Write( *this );
    return *this;
}

ShaderWriter& ShaderWriter::operator << ( const Expression& value )
{
    value.Write( *this );
    return *this;
}

ShaderWriter& ShaderWriter::operator << ( const Statement& value )
{
    value.Write( *this );
    return *this;
}

ShaderWriter& ShaderWriter::operator << ( const GenericValue& value )
{
    value.Write( *this );
    return *this;
}

void ShaderWriter::GenerateShader( const EntryFunction& entry_function )
{
    WriteGLSLVersion();

    //
    // Get all the functions used by this entry function
    //
    std::set<Function_sp> functions = GatherFunctions(
                                          entry_function.GetFunctionPointer() );

    //
    // Get all the variables used by the functions. We're interested in the
    // inputs and outputs
    //
    std::set<Variable_sp> variables = GatherVariables( functions );
    std::set<Variable_sp> input_variables;
    std::set<Variable_sp> output_variables;

    input_variables = WriteInputVaryings( entry_function, variables );
    NewLine();
    output_variables = WriteOutputVaryings( entry_function, variables );
    NewLine();

    WriteGlobalVariables( variables );
    NewLine();

    WriteFunctionDeclarations( functions );
    NewLine();

    WriteFunctionDefinitions( functions );
    NewLine();

    WriteMainFunction( entry_function, input_variables, output_variables );
}

void ShaderWriter::WriteGLSLVersion()
{
    m_Shader << "#version " << s_GLSLVersion;
    NewLine(2);
}

std::set<Variable_sp> ShaderWriter::WriteInputVaryings(
                                        const EntryFunction& entry_function,
                                        const std::set<Variable_sp>& variables )
{
    std::set<Variable_sp> input_varyings;
    std::set<Variable_sp> input_parameters = GatherParameterVariables(
                                                               entry_function );

    for( const auto& v : variables )
        // Ignore the varying specifier if it's on a parameter to a
        // non-top-level function
        if( v->IsVarying() && v->IsIn() && !v->IsParameter() )
            input_varyings.insert( v );

    for( const auto& v : input_parameters )
        if( v->IsVarying() && v->IsIn() &&
            input_varyings.find( v ) == input_varyings.end() )
        {
            // We only care about input varyings here,
            // and only about ones which are not used elsewhere

            //
            // If this has a builtin don't write the 'in'
            //
            if( !v->GetSemantic().HasBuiltin( entry_function.GetDomain(),
                                              true ) )
                *this << "in ";

            // todo layout information here
            *this << v->GetType() << " " <<
                     Mangle( v->GetName(), IdentifierType::IN_VARYING ) << ";";
            NewLine();
        }

    for( const auto& v : input_varyings )
    {
        //
        // if this has a builtin don't write the layout information
        //
        if( !v->GetSemantic().HasBuiltin( entry_function.GetDomain(), true ) )
            *this << "in ";

        // todo layout information here
        *this << v->GetType() << " " <<
                 Mangle( v->GetName(), IdentifierType::IN_VARYING ) << ";";
        NewLine();
    }

    return input_varyings;
}

std::set<Variable_sp> ShaderWriter::WriteOutputVaryings(
                                        const EntryFunction& entry_function,
                                        const std::set<Variable_sp>& variables )
{
    std::set<Variable_sp> output_varyings;

    //
    // The entry function may have a varying semantic
    //
    if( entry_function.GetFunction().GetSemantic().IsVarying() )
    {
        //
        // If this has a glsl builtin don't create the variable as an 'out'
        //
        if( !entry_function.GetFunction().GetSemantic().HasBuiltin(
                                                     entry_function.GetDomain(),
                                                     false ) )
            *this << "out ";
        // This isn't actually a variable, so just output it now
        *this << entry_function.GetFunction().GetReturnType() <<  " " <<
                 Mangle( entry_function.GetFunction().GetIdentifier(),
                         IdentifierType::OUT_VARYING ) <<  ";";
        NewLine();
    }

    //
    // Add the outputs in the form of function parameters
    //
    for( const auto& v : entry_function.GetFunction().GetParameters() )
        // we only care about varying parameters
        if( v->IsVarying() && v->IsOut() )
            output_varyings.insert( v );

    for( const auto& v : variables )
        // Ignore the varying specifier if it's on a parameter to a
        // non-top-level function
        if( v->IsVarying() && v->IsOut() && !v->IsParameter() )
            output_varyings.insert( v );

    for( const auto& v : output_varyings )
    {
        if( !v->GetSemantic().HasBuiltin( entry_function.GetDomain(), false ) )
            *this << "out ";
        // todo layout information here
        *this << v->GetType() << " " <<
                 Mangle( v->GetName(), IdentifierType::OUT_VARYING ) << ";";
        NewLine();
    }

    return output_varyings;
}

void ShaderWriter::WriteGlobalVariables(
                                        const std::set<Variable_sp>& variables )
{
    for( const auto& v : variables )
        if( v->IsGlobal() )
        {
            v->WriteDeclaration( *this );
            NewLine();
        }
}

void ShaderWriter::WriteFunctionDeclarations(
                                         const std::set<Function_sp> functions )
{
#if !defined(NDEBUG)
    for( const auto& f : functions )
        assert( f && "Null function in WriteFunctionDeclarations" );
#endif

    for( const auto& f : functions )
        f->WriteDeclaration( *this );
}

void ShaderWriter::WriteFunctionDefinitions(
                                         const std::set<Function_sp> functions )
{
#if !defined(NDEBUG)
    for( const auto& f : functions )
        assert( f && "Null function in WriteFunctionDefinitions" );
#endif

    for( const auto& f : functions )
        f->WriteDefinition( *this );
}

void ShaderWriter::WriteMainFunction(
                                 const EntryFunction& entry_function,
                                 const std::set<Variable_sp>& input_variables,
                                 const std::set<Variable_sp>& output_variables )
{
    m_Shader << "void main()";
    NewLine();
    m_Shader << "{";
    PushIndentation();
    NewLine();

    //
    // Gather all the input parameters
    //
    std::set<Variable_sp> input_parameters = GatherParameterVariables(
                                                               entry_function );

    //
    // Copy all the in varyings to the global variables except if they came from
    // a parameter
    //
    for( const auto& v : input_variables )
        // Dont allow input parameters, they have already been assigned to a
        // local variable
        if( v->IsGlobal() )
        {
            *this << Mangle( v->GetName(), IdentifierType::VARIABLE ) <<
                     " = ";
            if( !v->GetSemantic().HasBuiltin( entry_function.GetDomain(),
                                              true ) )
                *this << Mangle( v->GetName(), IdentifierType::IN_VARYING );
            else
                *this << v->GetSemantic().GetBuiltin(
                                                     entry_function.GetDomain(),
                                                     true );
            *this << ";";
            NewLine();
        }

    NewLine();

    //
    // Write all the input parameters
    //
    for( const auto& v : input_parameters )
    {
        *this << v->GetType() << " " <<
                 Mangle( v->GetName(), IdentifierType::VARIABLE ) << " = " <<
                 Mangle( v->GetName(), IdentifierType::IN_VARYING ) << ";";
        NewLine();
    }

    NewLine();

    //
    // Write a call the the entry function and sort out all the output variables
    //
    if( entry_function.GetFunction().GetSemantic().IsVarying() )
        // If we have a varying semantic on this function write to the output
        *this << Mangle( entry_function.GetFunction().GetIdentifier(),
                         IdentifierType::OUT_VARYING ) << " = ";
    *this << Mangle( entry_function.GetFunction().GetIdentifier(),
                     IdentifierType::FUNCTION ) << "(";
    bool first = true;
    for( const auto& argument : entry_function.GetParameters() )
    {
        if( !first )
            *this << ", ";
        else
            first = false;
        *this << *argument;
    }
    *this << ");";

    NewLine();

    //
    // Copy the function's return variable to the builtin if it has one
    //
    if( entry_function.GetFunction().GetSemantic().HasBuiltin(
                                                     entry_function.GetDomain(),
                                                     false ) )
    {
        *this << entry_function.GetFunction().GetSemantic().GetBuiltin(
                                                     entry_function.GetDomain(),
                                                     false ) <<
                 " = " << Mangle( entry_function.GetFunction().GetIdentifier(),
                                  IdentifierType::OUT_VARYING ) << ";";
        NewLine();
    }

    //
    // Copy all the global variables to their out variables or builtins
    //
    for( const auto& v : output_variables )
        if( v->IsGlobal() )
        {
            if( v->GetSemantic().HasBuiltin( entry_function.GetDomain(),
                                             false ) )
                *this << v->GetSemantic().GetBuiltin(
                                                     entry_function.GetDomain(),
                                                     false );
            else
                *this << Mangle( v->GetName(), IdentifierType::OUT_VARYING );

            *this << " = " <<
                     Mangle( v->GetName(), IdentifierType::VARIABLE ) << ";";
            NewLine();
        }

    PopIndentation();
    NewLine();
    m_Shader << "}";
    NewLine(2);
}

std::set<Function_sp> ShaderWriter::GatherFunctions( Function_sp function )
{
    assert( function && "GatherFunctions given null function" );

    std::set<Function_sp> ret =
    {
        function
    };

    //
    // Perform a dfs on the function tree
    //
    std::vector<Function_sp>               call_stack = { function };
    std::stack< std::set<Function_sp> > expanded;
    expanded.push( function->GetCallees() );

    while( !expanded.empty() )
    {
        //
        // If we've exhausted all of the expanded functions we can move up
        //
        if( expanded.top().empty() )
        {
            expanded.pop();
            call_stack.pop_back();
            continue;
        }

        //
        // We still have functions at this level to explore explore the next one
        //
        Function_sp current = *expanded.top().begin();

        const auto& f = std::find( call_stack.begin(), call_stack.end(),
                                   current );
        if( f != call_stack.end() )
        {
            //
            // If this function is in the call stack, error because of recursion
            //
            Error( "Recursion in shader function: " +
                   current->GetSignatureString() );
            return {};
        }

        //
        // Remove this function from the expanded function list
        //
        expanded.top().erase( expanded.top().begin() );

        //
        // Add this function to the call stack and expand it's children
        //
        ret.insert( current );
        call_stack.push_back( current );
        expanded.push( current->GetCallees() );
    }

    return ret;
}

std::set<Variable_sp> ShaderWriter::GatherVariables(
                                        const std::set<Function_sp>& functions )
{
    std::set<Variable_sp> ret;
    for( const auto& f : functions )
    {
        std::set<Variable_sp> v = f->GetVariables();
        ret.insert( v.begin(), v.end() );
    }
    return ret;
}

std::set<Variable_sp> ShaderWriter::GatherParameterVariables(
                                        const EntryFunction& entry_function )
{
    std::set<Variable_sp> ret;
    for( const auto& p : entry_function.GetParameters() )
    {
        std::set<Variable_sp> v = p->GetVariables();
        ret.insert( v.begin(), v.end() );
    }
    return ret;
}

void ShaderWriter::NewLine( unsigned num_lines )
{
    const std::string indent = "    ";
    for( unsigned i = 0; i < num_lines; ++i )
        m_Shader << '\n';
    for( unsigned i = 0; i < m_Indentation; ++i )
        m_Shader << indent;
}

void ShaderWriter::Error( const std::string& error_string )
{
    m_Good = false;
    m_Context.Error( error_string );
}

void ShaderWriter::Warning( const std::string& warning_string )
{
    // todo Context::Warning
    m_Context.Error( "Warning: " + warning_string );
}

} // namespace Compiler
} // namespace JoeLang
<commit_msg>[+] whitespace<commit_after>/*
    Copyright 2012 Joe Hermaszewski. All rights reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions are met:

    1. Redistributions of source code must retain the above copyright notice,
    this list of conditions and the following disclaimer.

    2. Redistributions in binary form must reproduce the above copyright notice,
    this list of conditions and the following disclaimer in the documentation
    and/or other materials provided with the distribution.

    THIS SOFTWARE IS PROVIDED BY JOE HERMASZEWSKI "AS IS" AND ANY EXPRESS OR
    IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
    EVENT SHALL JOE HERMASZEWSKI OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
    LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
    ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
    THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

    The views and conclusions contained in the software and documentation are
    those of the authors and should not be interpreted as representing official
    policies, either expressed or implied, of Joe Hermaszewski.
*/

#include "shader_writer.hpp"

#include <algorithm>
#include <cassert>
#include <map>
#include <memory>
#include <set>
#include <stack>
#include <string>
#include <sstream>
#include <vector>

#include <compiler/complete_type.hpp>
#include <compiler/entry_function.hpp>
#include <compiler/generic_value.hpp>
#include <compiler/function.hpp>
#include <compiler/variable.hpp>
#include <compiler/semantic_info.hpp>
#include <compiler/tokens/expressions/expression.hpp>
#include <compiler/tokens/expressions/postfix_operator.hpp>
#include <joelang/context.hpp>
#include <joelang/shader.hpp>

namespace JoeLang
{
namespace Compiler
{

const std::string ShaderWriter::s_GLSLVersion = "150";

ShaderWriter::ShaderWriter( const Context& context )
    :m_Context( context )
{
    m_Shader.setf( std::ios_base::scientific );
    m_Shader.setf( std::ios_base::boolalpha );
    m_Shader.setf( std::ios_base::showpoint );
}

std::string ShaderWriter::GenerateGLSL( const EntryFunction& entry_function )
{
    GenerateShader( entry_function );

    std::string ret = m_Shader.str();

    // reset things
    m_Shader.str("");

    assert( m_Indentation == 0 && "Unmatched indentations" );

    // return an empty string if we've had an error
    if( m_Good )
        return ret;
    else
        return "";
}

void ShaderWriter::PushIndentation()
{
    ++m_Indentation;
}

void ShaderWriter::PopIndentation()
{
    assert( m_Indentation > 0 && "Trying to pop 0 indentation" );
    --m_Indentation;
}

std::string ShaderWriter::Mangle( const std::string& identifier,
                                  IdentifierType identifier_type )
{
    const static std::map<IdentifierType, std::string> prefix_map
    {
        { IdentifierType::VARIABLE,    "_"  },
        { IdentifierType::IN_VARYING,  "i_"  },
        { IdentifierType::OUT_VARYING, "o_"  },
        { IdentifierType::FUNCTION,    "f_" }
    };
    return prefix_map.at(identifier_type) + identifier;
}

ShaderWriter& ShaderWriter::operator << ( const CompleteType& value )
{
    value.Write( *this );
    return *this;
}

ShaderWriter& ShaderWriter::operator << ( const Expression& value )
{
    value.Write( *this );
    return *this;
}

ShaderWriter& ShaderWriter::operator << ( const Statement& value )
{
    value.Write( *this );
    return *this;
}

ShaderWriter& ShaderWriter::operator << ( const GenericValue& value )
{
    value.Write( *this );
    return *this;
}

void ShaderWriter::GenerateShader( const EntryFunction& entry_function )
{
    WriteGLSLVersion();

    //
    // Get all the functions used by this entry function
    //
    std::set<Function_sp> functions = GatherFunctions(
                                          entry_function.GetFunctionPointer() );

    //
    // Get all the variables used by the functions. We're interested in the
    // inputs and outputs
    //
    std::set<Variable_sp> variables = GatherVariables( functions );
    std::set<Variable_sp> input_variables;
    std::set<Variable_sp> output_variables;

    input_variables = WriteInputVaryings( entry_function, variables );
    NewLine();
    output_variables = WriteOutputVaryings( entry_function, variables );
    NewLine();

    WriteGlobalVariables( variables );
    NewLine();

    WriteFunctionDeclarations( functions );
    NewLine();

    WriteFunctionDefinitions( functions );
    NewLine();

    WriteMainFunction( entry_function, input_variables, output_variables );
}

void ShaderWriter::WriteGLSLVersion()
{
    m_Shader << "#version " << s_GLSLVersion;
    NewLine(2);
}

std::set<Variable_sp> ShaderWriter::WriteInputVaryings(
                                        const EntryFunction& entry_function,
                                        const std::set<Variable_sp>& variables )
{
    std::set<Variable_sp> input_varyings;
    std::set<Variable_sp> input_parameters = GatherParameterVariables(
                                                               entry_function );

    for( const auto& v : variables )
        // Ignore the varying specifier if it's on a parameter to a
        // non-top-level function
        if( v->IsVarying() && v->IsIn() && !v->IsParameter() )
            input_varyings.insert( v );

    for( const auto& v : input_parameters )
        if( v->IsVarying() && v->IsIn() &&
            input_varyings.find( v ) == input_varyings.end() )
        {
            // We only care about input varyings here,
            // and only about ones which are not used elsewhere

            //
            // If this has a builtin don't write the 'in'
            //
            if( !v->GetSemantic().HasBuiltin( entry_function.GetDomain(),
                                              true ) )
                *this << "in ";

            // todo layout information here
            *this << v->GetType() << " " <<
                     Mangle( v->GetName(), IdentifierType::IN_VARYING ) << ";";
            NewLine();
        }

    for( const auto& v : input_varyings )
    {
        //
        // if this has a builtin don't write the layout information
        //
        if( !v->GetSemantic().HasBuiltin( entry_function.GetDomain(), true ) )
            *this << "in ";

        // todo layout information here
        *this << v->GetType() << " " <<
                 Mangle( v->GetName(), IdentifierType::IN_VARYING ) << ";";
        NewLine();
    }

    return input_varyings;
}

std::set<Variable_sp> ShaderWriter::WriteOutputVaryings(
                                        const EntryFunction& entry_function,
                                        const std::set<Variable_sp>& variables )
{
    std::set<Variable_sp> output_varyings;

    //
    // The entry function may have a varying semantic
    //
    if( entry_function.GetFunction().GetSemantic().IsVarying() )
    {
        //
        // If this has a glsl builtin don't create the variable as an 'out'
        //
        if( !entry_function.GetFunction().GetSemantic().HasBuiltin(
                                                     entry_function.GetDomain(),
                                                     false ) )
            *this << "out ";
        // This isn't actually a variable, so just output it now
        *this << entry_function.GetFunction().GetReturnType() <<  " " <<
                 Mangle( entry_function.GetFunction().GetIdentifier(),
                         IdentifierType::OUT_VARYING ) <<  ";";
        NewLine();
    }

    //
    // Add the outputs in the form of function parameters
    //
    for( const auto& v : entry_function.GetFunction().GetParameters() )
        // we only care about varying parameters
        if( v->IsVarying() && v->IsOut() )
            output_varyings.insert( v );

    for( const auto& v : variables )
        // Ignore the varying specifier if it's on a parameter to a
        // non-top-level function
        if( v->IsVarying() && v->IsOut() && !v->IsParameter() )
            output_varyings.insert( v );

    for( const auto& v : output_varyings )
    {
        if( !v->GetSemantic().HasBuiltin( entry_function.GetDomain(), false ) )
            *this << "out ";
        // todo layout information here
        *this << v->GetType() << " " <<
                 Mangle( v->GetName(), IdentifierType::OUT_VARYING ) << ";";
        NewLine();
    }

    return output_varyings;
}

void ShaderWriter::WriteGlobalVariables(
                                        const std::set<Variable_sp>& variables )
{
    for( const auto& v : variables )
        if( v->IsGlobal() )
        {
            v->WriteDeclaration( *this );
            NewLine();
        }
}

void ShaderWriter::WriteFunctionDeclarations(
                                         const std::set<Function_sp> functions )
{
#if !defined(NDEBUG)
    for( const auto& f : functions )
        assert( f && "Null function in WriteFunctionDeclarations" );
#endif

    for( const auto& f : functions )
        f->WriteDeclaration( *this );
}

void ShaderWriter::WriteFunctionDefinitions(
                                         const std::set<Function_sp> functions )
{
#if !defined(NDEBUG)
    for( const auto& f : functions )
        assert( f && "Null function in WriteFunctionDefinitions" );
#endif

    for( const auto& f : functions )
        f->WriteDefinition( *this );
}

void ShaderWriter::WriteMainFunction(
                                 const EntryFunction& entry_function,
                                 const std::set<Variable_sp>& input_variables,
                                 const std::set<Variable_sp>& output_variables )
{
    m_Shader << "void main()";
    NewLine();
    m_Shader << "{";
    PushIndentation();
    NewLine();

    //
    // Gather all the input parameters
    //
    std::set<Variable_sp> input_parameters = GatherParameterVariables(
                                                               entry_function );

    //
    // Copy all the in varyings to the global variables except if they came from
    // a parameter
    //
    for( const auto& v : input_variables )
        // Dont allow input parameters, they have already been assigned to a
        // local variable
        if( v->IsGlobal() )
        {
            *this << Mangle( v->GetName(), IdentifierType::VARIABLE ) <<
                     " = ";
            if( !v->GetSemantic().HasBuiltin( entry_function.GetDomain(),
                                              true ) )
                *this << Mangle( v->GetName(), IdentifierType::IN_VARYING );
            else
                *this << v->GetSemantic().GetBuiltin(
                                                     entry_function.GetDomain(),
                                                     true );
            *this << ";";
            NewLine();
        }

    NewLine();

    //
    // Write all the input parameters
    //
    for( const auto& v : input_parameters )
    {
        *this << v->GetType() << " " <<
                 Mangle( v->GetName(), IdentifierType::VARIABLE ) << " = " <<
                 Mangle( v->GetName(), IdentifierType::IN_VARYING ) << ";";
        NewLine();
    }

    NewLine();

    //
    // Write a call the the entry function and sort out all the output variables
    //
    if( entry_function.GetFunction().GetSemantic().IsVarying() )
        // If we have a varying semantic on this function write to the output
        *this << Mangle( entry_function.GetFunction().GetIdentifier(),
                         IdentifierType::OUT_VARYING ) << " = ";
    *this << Mangle( entry_function.GetFunction().GetIdentifier(),
                     IdentifierType::FUNCTION ) << "(";
    bool first = true;
    for( const auto& argument : entry_function.GetParameters() )
    {
        if( !first )
            *this << ", ";
        else
            first = false;
        *this << *argument;
    }
    *this << ");";

    NewLine();

    //
    // Copy the function's return variable to the builtin if it has one
    //
    if( entry_function.GetFunction().GetSemantic().HasBuiltin(
                                                     entry_function.GetDomain(),
                                                     false ) )
    {
        NewLine();
        *this << entry_function.GetFunction().GetSemantic().GetBuiltin(
                                                     entry_function.GetDomain(),
                                                     false ) <<
                 " = " << Mangle( entry_function.GetFunction().GetIdentifier(),
                                  IdentifierType::OUT_VARYING ) << ";";
    }

    //
    // Copy all the global variables to their out variables or builtins
    //
    for( const auto& v : output_variables )
        if( v->IsGlobal() )
        {
            if( v->GetSemantic().HasBuiltin( entry_function.GetDomain(),
                                             false ) )
                *this << v->GetSemantic().GetBuiltin(
                                                     entry_function.GetDomain(),
                                                     false );
            else
                *this << Mangle( v->GetName(), IdentifierType::OUT_VARYING );

            *this << " = " <<
                     Mangle( v->GetName(), IdentifierType::VARIABLE ) << ";";
            NewLine();
        }

    PopIndentation();
    NewLine();
    m_Shader << "}";
    NewLine(2);
}

std::set<Function_sp> ShaderWriter::GatherFunctions( Function_sp function )
{
    assert( function && "GatherFunctions given null function" );

    std::set<Function_sp> ret =
    {
        function
    };

    //
    // Perform a dfs on the function tree
    //
    std::vector<Function_sp>               call_stack = { function };
    std::stack< std::set<Function_sp> > expanded;
    expanded.push( function->GetCallees() );

    while( !expanded.empty() )
    {
        //
        // If we've exhausted all of the expanded functions we can move up
        //
        if( expanded.top().empty() )
        {
            expanded.pop();
            call_stack.pop_back();
            continue;
        }

        //
        // We still have functions at this level to explore explore the next one
        //
        Function_sp current = *expanded.top().begin();

        const auto& f = std::find( call_stack.begin(), call_stack.end(),
                                   current );
        if( f != call_stack.end() )
        {
            //
            // If this function is in the call stack, error because of recursion
            //
            Error( "Recursion in shader function: " +
                   current->GetSignatureString() );
            return {};
        }

        //
        // Remove this function from the expanded function list
        //
        expanded.top().erase( expanded.top().begin() );

        //
        // Add this function to the call stack and expand it's children
        //
        ret.insert( current );
        call_stack.push_back( current );
        expanded.push( current->GetCallees() );
    }

    return ret;
}

std::set<Variable_sp> ShaderWriter::GatherVariables(
                                        const std::set<Function_sp>& functions )
{
    std::set<Variable_sp> ret;
    for( const auto& f : functions )
    {
        std::set<Variable_sp> v = f->GetVariables();
        ret.insert( v.begin(), v.end() );
    }
    return ret;
}

std::set<Variable_sp> ShaderWriter::GatherParameterVariables(
                                        const EntryFunction& entry_function )
{
    std::set<Variable_sp> ret;
    for( const auto& p : entry_function.GetParameters() )
    {
        std::set<Variable_sp> v = p->GetVariables();
        ret.insert( v.begin(), v.end() );
    }
    return ret;
}

void ShaderWriter::NewLine( unsigned num_lines )
{
    const std::string indent = "    ";
    for( unsigned i = 0; i < num_lines; ++i )
        m_Shader << '\n';
    for( unsigned i = 0; i < m_Indentation; ++i )
        m_Shader << indent;
}

void ShaderWriter::Error( const std::string& error_string )
{
    m_Good = false;
    m_Context.Error( error_string );
}

void ShaderWriter::Warning( const std::string& warning_string )
{
    // todo Context::Warning
    m_Context.Error( "Warning: " + warning_string );
}

} // namespace Compiler
} // namespace JoeLang
<|endoftext|>


<commit_before>//===--- ClangSACheckerProvider.cpp - Clang SA Checkers Provider ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines the CheckerProvider for the checkers defined in
// libclangStaticAnalyzerCheckers.
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckerProvider.h"
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
#include "llvm/ADT/DenseSet.h"

using namespace clang;
using namespace ento;

namespace {

/// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers.
class ClangSACheckerProvider : public CheckerProvider {
public:
  virtual void registerCheckers(CheckerManager &checkerMgr,
                              CheckerOptInfo *checkOpts, unsigned numCheckOpts);
};

}

CheckerProvider *ento::createClangSACheckerProvider() {
  return new ClangSACheckerProvider();
}

namespace {

struct StaticCheckerInfoRec {
  const char *FullName;
  CheckerManager::RegisterFunc RegFunc;
  bool Hidden;
};

} // end anonymous namespace.

static const StaticCheckerInfoRec StaticCheckerInfo[] = {
#define GET_CHECKERS
#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,HIDDEN)    \
  { FULLNAME, register##CLASS, HIDDEN },
#include "Checkers.inc"
  { 0, 0, 0}
#undef CHECKER
#undef GET_CHECKERS
};

namespace {

struct CheckNameOption {
  const char  *Name;
  const short *Members;
  const short *SubGroups;
};

} // end anonymous namespace.

#define GET_MEMBER_ARRAYS
#include "Checkers.inc"
#undef GET_MEMBER_ARRAYS

// The table of check name options, sorted by name for fast binary lookup.
static const CheckNameOption CheckNameTable[] = {
#define GET_CHECKNAME_TABLE
#include "Checkers.inc"
#undef GET_CHECKNAME_TABLE
};
static const size_t
        CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]);

static bool CheckNameOptionCompare(const CheckNameOption &LHS,
                                   const CheckNameOption &RHS) {
  return strcmp(LHS.Name, RHS.Name) < 0;
}

static void collectCheckers(const CheckNameOption *checkName,
                            bool enable,
                         llvm::DenseSet<const StaticCheckerInfoRec *> &checkers,
                            bool collectHidden) {
  if (const short *member = checkName->Members) {
    if (enable) {
      if (collectHidden || !StaticCheckerInfo[*member].Hidden)
        checkers.insert(&StaticCheckerInfo[*member]);
    } else {
      for (; *member != -1; ++member)
        checkers.erase(&StaticCheckerInfo[*member]);
    }
  }

  // Enable/disable all subgroups along with this one.
  if (const short *subGroups = checkName->SubGroups) {
    for (; *subGroups != -1; ++subGroups)
      collectCheckers(&CheckNameTable[*subGroups], enable, checkers,
                      /*don't enable hidden in subgroups*/ false);
  }
}

static void collectCheckers(CheckerOptInfo &opt,
                       llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) {
  const char *optName = opt.getName();
  CheckNameOption key = { optName, 0, 0 };
  const CheckNameOption *found =
  std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key,
                   CheckNameOptionCompare);
  if (found == CheckNameTable + CheckNameTableSize ||
      strcmp(found->Name, optName) != 0)
    return;  // Check name not found.

  opt.claim();
  collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true);
}

#include "llvm/Support/raw_ostream.h"

void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
                             CheckerOptInfo *checkOpts, unsigned numCheckOpts) {
  llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers;
  for (unsigned i = 0; i != numCheckOpts; ++i)
    collectCheckers(checkOpts[i], enabledCheckers);
  for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator
         I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) {
    checkerMgr.addCheckerRegisterFunction((*I)->RegFunc);
  }
}
<commit_msg>Remove left-over #include.<commit_after>//===--- ClangSACheckerProvider.cpp - Clang SA Checkers Provider ----------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// Defines the CheckerProvider for the checkers defined in
// libclangStaticAnalyzerCheckers.
//
//===----------------------------------------------------------------------===//

#include "ClangSACheckerProvider.h"
#include "ClangSACheckers.h"
#include "clang/StaticAnalyzer/Core/CheckerManager.h"
#include "clang/StaticAnalyzer/Core/CheckerProvider.h"
#include "llvm/ADT/DenseSet.h"

using namespace clang;
using namespace ento;

namespace {

/// \brief Provider for all the checkers in libclangStaticAnalyzerCheckers.
class ClangSACheckerProvider : public CheckerProvider {
public:
  virtual void registerCheckers(CheckerManager &checkerMgr,
                              CheckerOptInfo *checkOpts, unsigned numCheckOpts);
};

}

CheckerProvider *ento::createClangSACheckerProvider() {
  return new ClangSACheckerProvider();
}

namespace {

struct StaticCheckerInfoRec {
  const char *FullName;
  CheckerManager::RegisterFunc RegFunc;
  bool Hidden;
};

} // end anonymous namespace.

static const StaticCheckerInfoRec StaticCheckerInfo[] = {
#define GET_CHECKERS
#define CHECKER(FULLNAME,CLASS,DESCFILE,HELPTEXT,HIDDEN)    \
  { FULLNAME, register##CLASS, HIDDEN },
#include "Checkers.inc"
  { 0, 0, 0}
#undef CHECKER
#undef GET_CHECKERS
};

namespace {

struct CheckNameOption {
  const char  *Name;
  const short *Members;
  const short *SubGroups;
};

} // end anonymous namespace.

#define GET_MEMBER_ARRAYS
#include "Checkers.inc"
#undef GET_MEMBER_ARRAYS

// The table of check name options, sorted by name for fast binary lookup.
static const CheckNameOption CheckNameTable[] = {
#define GET_CHECKNAME_TABLE
#include "Checkers.inc"
#undef GET_CHECKNAME_TABLE
};
static const size_t
        CheckNameTableSize = sizeof(CheckNameTable) / sizeof(CheckNameTable[0]);

static bool CheckNameOptionCompare(const CheckNameOption &LHS,
                                   const CheckNameOption &RHS) {
  return strcmp(LHS.Name, RHS.Name) < 0;
}

static void collectCheckers(const CheckNameOption *checkName,
                            bool enable,
                         llvm::DenseSet<const StaticCheckerInfoRec *> &checkers,
                            bool collectHidden) {
  if (const short *member = checkName->Members) {
    if (enable) {
      if (collectHidden || !StaticCheckerInfo[*member].Hidden)
        checkers.insert(&StaticCheckerInfo[*member]);
    } else {
      for (; *member != -1; ++member)
        checkers.erase(&StaticCheckerInfo[*member]);
    }
  }

  // Enable/disable all subgroups along with this one.
  if (const short *subGroups = checkName->SubGroups) {
    for (; *subGroups != -1; ++subGroups)
      collectCheckers(&CheckNameTable[*subGroups], enable, checkers,
                      /*don't enable hidden in subgroups*/ false);
  }
}

static void collectCheckers(CheckerOptInfo &opt,
                       llvm::DenseSet<const StaticCheckerInfoRec *> &checkers) {
  const char *optName = opt.getName();
  CheckNameOption key = { optName, 0, 0 };
  const CheckNameOption *found =
  std::lower_bound(CheckNameTable, CheckNameTable + CheckNameTableSize, key,
                   CheckNameOptionCompare);
  if (found == CheckNameTable + CheckNameTableSize ||
      strcmp(found->Name, optName) != 0)
    return;  // Check name not found.

  opt.claim();
  collectCheckers(found, opt.isEnabled(), checkers, /*collectHidden=*/true);
}

void ClangSACheckerProvider::registerCheckers(CheckerManager &checkerMgr,
                             CheckerOptInfo *checkOpts, unsigned numCheckOpts) {
  llvm::DenseSet<const StaticCheckerInfoRec *> enabledCheckers;
  for (unsigned i = 0; i != numCheckOpts; ++i)
    collectCheckers(checkOpts[i], enabledCheckers);
  for (llvm::DenseSet<const StaticCheckerInfoRec *>::iterator
         I = enabledCheckers.begin(), E = enabledCheckers.end(); I != E; ++I) {
    checkerMgr.addCheckerRegisterFunction((*I)->RegFunc);
  }
}
<|endoftext|>


<commit_before>#include "game/tileview/tile.h"
#include "framework/framework.h"

namespace OpenApoc {

TileMap::TileMap(Framework &fw, Vec3<int> size)
	: fw(fw), size(size)
{
	tiles.reserve(size.z * size.y * size.z);
	for (int z = 0; z < size.z; z++)
	{
		for (int y = 0; y < size.y; y++)
		{
			for (int x = 0; x < size.x; x++)
			{
				tiles.emplace_back(*this, Vec3<int>{x,y,z});
			}
		}
	}
}

void
TileMap::update(unsigned int ticks)
{
	for (auto& object : this->activeObjects)
		object->update(ticks);
	for (auto& object : this->projectiles)
		object->checkProjectileCollision();
}

Tile*
TileMap::getTile(int x, int y, int z)
{
	if (x >= size.x || y >= size.y || z >= size.z)
	{
		LogError("Requesting tile {%d,%d,%d} in map of size {%d,%d,%d}",
			x, y, z, size.x, size.y, size.z);
		return nullptr;
	}
	return &this->tiles[z * size.x * size.y + y * size.x + x];
}

Tile*
TileMap::getTile(Vec3<int> pos)
{
	return getTile(pos.x, pos.y, pos.z);
}

Tile*
TileMap::getTile(Vec3<float> pos)
{
	return getTile(pos.x, pos.y, pos.z);
}

void
TileMap::addObject(std::shared_ptr<TileObject> obj)
{
	if (!obj->getOwningTile())
	{
		LogError("Adding object with no owner");
		assert(0);
	}
	obj->getOwningTile()->ownedObjects.insert(obj);
	if (obj->isActive())
		this->activeObjects.insert(obj);
	if (obj->isVisible())
		obj->getOwningTile()->visibleObjects.insert(obj);
	if (obj->isCollidable())
		obj->addToAffectedTiles();
	if (obj->isProjectile())
		this->projectiles.insert(obj);

}

void
TileMap::removeObject(std::shared_ptr<TileObject> obj)
{
	if (!obj->getOwningTile())
	{
		LogError("Removing object with no owner");
		assert(0);
	}
	if (obj->isActive())
		this->activeObjects.erase(obj);
	if (obj->isProjectile())
	{
		obj->getOwningTile()->ownedProjectiles.erase(obj);
		this->projectiles.erase(obj);
	}
	if (obj->isVisible())
		obj->getOwningTile()->visibleObjects.erase(obj);
	if (obj->isCollidable())
		obj->removeFromAffectedTiles();
	auto count = obj->getOwningTile()->ownedObjects.erase(obj);
	if (count != 1)
	{
		LogError("Removed %u objects from owning tile", (unsigned)count);
	}
}

TileMap::~TileMap()
{
}

Tile::Tile(TileMap &map, Vec3<int> position)
	: map(map), position(position)
{
}

TileObject::TileObject(TileMap &map, Vec3<float> position, bool active, bool collides, bool visible, bool projectile)
	: position(position), owningTile(map.getTile(position)), active(active), collides(collides), visible(visible), projectile(projectile)
{
	//May be called by multiple subclass constructors - don't do anything
	//non-repeatable here
}

TileObject::~TileObject()
{

}

const Vec3<float>&
TileObject::getPosition() const
{
	return this->position;
}

void
TileObject::setPosition(Vec3<float> newPos)
{
	auto thisPtr = shared_from_this();
	this->position = newPos;
	auto &map = this->owningTile->map;
	auto newOwner = map.getTile(this->position);
	if (newOwner != this->owningTile)
	{
		if (this->isVisible())
		{
			this->owningTile->visibleObjects.erase(thisPtr);
			newOwner->visibleObjects.insert(thisPtr);
		}
		if (this->isProjectile())
		{
			this->owningTile->ownedProjectiles.erase(thisPtr);
			newOwner->ownedProjectiles.insert(thisPtr);
		}
		this->owningTile->ownedObjects.erase(thisPtr);
		newOwner->ownedObjects.insert(thisPtr);
		this->owningTile = newOwner;
	}
}

void
TileObject::update(unsigned int ticks)
{
	//Override this for active objects
	LogWarning("Called on non-active object");
	assert(!this->isActive());
	std::ignore = ticks;
}

std::shared_ptr<Image>
TileObject::getSprite()
{
	//Override this for visible objects
	LogWarning("Called on non-visible object");
	assert(!this->isVisible());
	return nullptr;
}

Vec3<float>
TileObject::getDrawPosition() const
{
	//Override this for visible objects
	LogWarning("Called on non-visible object");
	assert(!this->isVisible());
	return this->getPosition();
}

const Vec3<int>&
TileObject::getTileSizeInVoxels() const
{
	static Vec3<int> invalidSize{0,0,0};
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	return invalidSize;
}

const Vec3<int>&
TileObject::getBounds() const
{
	static Vec3<int> invalidSize{0,0,0};
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	return invalidSize;
}

bool
TileObject::hasVoxelAt(const Vec3<float> &worldPosition) const
{
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	std::ignore = worldPosition;
	return false;
}

void
TileObject::handleCollision(const Collision &c)
{
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	std::ignore = c;
	return;
}

void
TileObject::removeFromAffectedTiles()
{
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	return;
}

void
TileObject::addToAffectedTiles()
{
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	return;
}

void
TileObject::checkProjectileCollision()
{
	//Override this for projectile objects
	LogWarning("Called on non-projectile object");
	assert(!this->isProjectile());
	return;
}

void
TileObject::drawProjectile(TileView &v, Renderer &r, Vec2<int> screenPosition)
{
	//Override this for projectile objects
	LogWarning("Called on non-projectile object");
	assert(!this->isProjectile());
	std::ignore = v;
	std::ignore = r;
	std::ignore = screenPosition;
	return;
}

class PathComparer
{
public:
	Vec3<float> dest;
	Vec3<float> origin;
	PathComparer(Vec3<int> d)
		: dest{d.x, d.y, d.z}{}
	bool operator() (Tile* t1, Tile* t2)
	{
		Vec3<float> t1Pos {t1->position.x, t1->position.y, t1->position.z};
		Vec3<float> t2Pos {t2->position.x, t2->position.y, t2->position.z};

		Vec3<float> t1tod  = dest - t1Pos;
		Vec3<float> t2tod  = dest - t2Pos;

		float t1cost = glm::length(t1tod);
		float t2cost = glm::length(t2tod);

		t1cost += glm::length(t1Pos-origin);
		t2cost += glm::length(t2Pos-origin);

		return (t1cost < t2cost);

	}
};

#define THRESHOLD_ITERATIONS 500

static bool findNextNodeOnPath(PathComparer &comparer, TileMap &map, std::list<Tile*> &currentPath, Vec3<int> destination, volatile unsigned long *numIterations)
{
	if (currentPath.back()->position == destination)
		return true;
	if (*numIterations > THRESHOLD_ITERATIONS)
		return false;
	*numIterations = (*numIterations)+1;
	std::vector<Tile*> fringe;
	for (int x = -1; x <= 1; x++)
	{
		for (int y = -1; y <= 1; y++)
		{
			for (int z = -1; z <= 1; z++)
			{
				Vec3<int> currentPosition = currentPath.back()->position;
				if (z == 0 && y == 0 && x == 0)
					continue;
				Vec3<int> nextPosition = currentPosition;
				nextPosition.x += x;
				nextPosition.y += y;
				nextPosition.z += z;
				if (nextPosition.z < 0 || nextPosition.z >= map.size.z
					|| nextPosition.y < 0 || nextPosition.y >= map.size.y
					|| nextPosition.x < 0 || nextPosition.x >= map.size.x)
					continue;
				Tile *tile = map.getTile(nextPosition);
				//FIXME: Make 'blocked' tiles cleverer (e.g. don't plan around objects that will move anyway?)
				if (!tile->collideableObjects.empty())
					continue;
				//Check for diagonal routes that the 'corner' tiles we touch are empty
				Vec3<int> cornerPosition = currentPosition;
				cornerPosition += Vec3<int>{0,y,z};
				if (cornerPosition != currentPosition &&
					!map.getTile(cornerPosition)->ownedObjects.empty())
					continue;
				cornerPosition = currentPosition;
				cornerPosition += Vec3<int>{x,0,z};
				if (cornerPosition != currentPosition &&
					!map.getTile(cornerPosition)->ownedObjects.empty())
					continue;
				cornerPosition = currentPosition;
				cornerPosition += Vec3<int>{x,y,0};
				if (cornerPosition != currentPosition &&
					!map.getTile(cornerPosition)->ownedObjects.empty())
					continue;
				//Already visited this tile
				if (std::find(currentPath.begin(), currentPath.end(), tile) != currentPath.end())
					continue;
				fringe.push_back(tile);
			}
		}
	}
	std::sort(fringe.begin(), fringe.end(), comparer);
	for (auto tile : fringe)
	{
		currentPath.push_back(tile);
		comparer.origin = {tile->position.x, tile->position.y, tile->position.z};
		if (findNextNodeOnPath(comparer, map, currentPath, destination, numIterations))
			return true;
		currentPath.pop_back();
	}
	return false;

}

std::list<Tile*>
TileMap::findShortestPath(Vec3<int> origin, Vec3<int> destination)
{
	volatile unsigned long numIterations = 0;
	std::list<Tile*> path;
	PathComparer pc(destination);
	if (origin.x < 0 || origin.x >= this->size.x
		|| origin.y < 0 || origin.y >= this->size.y
		|| origin.z < 0 || origin.z >= this->size.z)
	{
		LogError("Bad origin {%d,%d,%d}", origin.x, origin.y, origin.z);
		return path;
	}
	if (destination.x < 0 || destination.x >= this->size.x
		|| destination.y < 0 || destination.y >= this->size.y
		|| destination.z < 0 || destination.z >= this->size.z)
	{
		LogError("Bad destination {%d,%d,%d}", destination.x, destination.y, destination.z);
		return path;
	}
	path.push_back(this->getTile(origin));
	if (!findNextNodeOnPath(pc, *this, path, destination, &numIterations))
	{
		LogWarning("No route found from origin {%d,%d,%d} to desination {%d,%d,%d}", origin.x, origin.y, origin.z, destination.x, destination.y, destination.z);
		path.clear();
		return path;
	}
	return path;
}

}; //namespace OpenApoc
<commit_msg>Fix using invalid iterators in Tilemap::Update()<commit_after>#include "game/tileview/tile.h"
#include "framework/framework.h"

namespace OpenApoc {

TileMap::TileMap(Framework &fw, Vec3<int> size)
	: fw(fw), size(size)
{
	tiles.reserve(size.z * size.y * size.z);
	for (int z = 0; z < size.z; z++)
	{
		for (int y = 0; y < size.y; y++)
		{
			for (int x = 0; x < size.x; x++)
			{
				tiles.emplace_back(*this, Vec3<int>{x,y,z});
			}
		}
	}
}

void
TileMap::update(unsigned int ticks)
{
	//Objects may remove themselves from these lists in their update functions.
	//So we can't just use the foreach iterator stuff as we need to
	//store the next iterator before calling update
	auto activeIt = this->activeObjects.begin();
	while (activeIt != this->activeObjects.end())
	{
		//Post-increment to store a copy of the 'next' object iterator
		//before calling the update, as ->update() may destroy the 'current'
		//iterator if it removes the object from the set
		auto objIt = activeIt++;
		(*objIt)->update(ticks);
	}
	auto projIt = this->projectiles.begin();
	while (projIt != this->projectiles.end())
	{
		auto objIt = projIt++;
		(*objIt)->update(ticks);
	}
}

Tile*
TileMap::getTile(int x, int y, int z)
{
	if (x >= size.x || y >= size.y || z >= size.z)
	{
		LogError("Requesting tile {%d,%d,%d} in map of size {%d,%d,%d}",
			x, y, z, size.x, size.y, size.z);
		return nullptr;
	}
	return &this->tiles[z * size.x * size.y + y * size.x + x];
}

Tile*
TileMap::getTile(Vec3<int> pos)
{
	return getTile(pos.x, pos.y, pos.z);
}

Tile*
TileMap::getTile(Vec3<float> pos)
{
	return getTile(pos.x, pos.y, pos.z);
}

void
TileMap::addObject(std::shared_ptr<TileObject> obj)
{
	if (!obj->getOwningTile())
	{
		LogError("Adding object with no owner");
		assert(0);
	}
	obj->getOwningTile()->ownedObjects.insert(obj);
	if (obj->isActive())
		this->activeObjects.insert(obj);
	if (obj->isVisible())
		obj->getOwningTile()->visibleObjects.insert(obj);
	if (obj->isCollidable())
		obj->addToAffectedTiles();
	if (obj->isProjectile())
		this->projectiles.insert(obj);

}

void
TileMap::removeObject(std::shared_ptr<TileObject> obj)
{
	if (!obj->getOwningTile())
	{
		LogError("Removing object with no owner");
		assert(0);
	}
	if (obj->isActive())
		this->activeObjects.erase(obj);
	if (obj->isProjectile())
	{
		obj->getOwningTile()->ownedProjectiles.erase(obj);
		this->projectiles.erase(obj);
	}
	if (obj->isVisible())
		obj->getOwningTile()->visibleObjects.erase(obj);
	if (obj->isCollidable())
		obj->removeFromAffectedTiles();
	auto count = obj->getOwningTile()->ownedObjects.erase(obj);
	if (count != 1)
	{
		LogError("Removed %u objects from owning tile", (unsigned)count);
	}
}

TileMap::~TileMap()
{
}

Tile::Tile(TileMap &map, Vec3<int> position)
	: map(map), position(position)
{
}

TileObject::TileObject(TileMap &map, Vec3<float> position, bool active, bool collides, bool visible, bool projectile)
	: position(position), owningTile(map.getTile(position)), active(active), collides(collides), visible(visible), projectile(projectile)
{
	//May be called by multiple subclass constructors - don't do anything
	//non-repeatable here
}

TileObject::~TileObject()
{

}

const Vec3<float>&
TileObject::getPosition() const
{
	return this->position;
}

void
TileObject::setPosition(Vec3<float> newPos)
{
	auto thisPtr = shared_from_this();
	this->position = newPos;
	auto &map = this->owningTile->map;
	auto newOwner = map.getTile(this->position);
	if (newOwner != this->owningTile)
	{
		if (this->isVisible())
		{
			this->owningTile->visibleObjects.erase(thisPtr);
			newOwner->visibleObjects.insert(thisPtr);
		}
		if (this->isProjectile())
		{
			this->owningTile->ownedProjectiles.erase(thisPtr);
			newOwner->ownedProjectiles.insert(thisPtr);
		}
		this->owningTile->ownedObjects.erase(thisPtr);
		newOwner->ownedObjects.insert(thisPtr);
		this->owningTile = newOwner;
	}
}

void
TileObject::update(unsigned int ticks)
{
	//Override this for active objects
	LogWarning("Called on non-active object");
	assert(!this->isActive());
	std::ignore = ticks;
}

std::shared_ptr<Image>
TileObject::getSprite()
{
	//Override this for visible objects
	LogWarning("Called on non-visible object");
	assert(!this->isVisible());
	return nullptr;
}

Vec3<float>
TileObject::getDrawPosition() const
{
	//Override this for visible objects
	LogWarning("Called on non-visible object");
	assert(!this->isVisible());
	return this->getPosition();
}

const Vec3<int>&
TileObject::getTileSizeInVoxels() const
{
	static Vec3<int> invalidSize{0,0,0};
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	return invalidSize;
}

const Vec3<int>&
TileObject::getBounds() const
{
	static Vec3<int> invalidSize{0,0,0};
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	return invalidSize;
}

bool
TileObject::hasVoxelAt(const Vec3<float> &worldPosition) const
{
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	std::ignore = worldPosition;
	return false;
}

void
TileObject::handleCollision(const Collision &c)
{
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	std::ignore = c;
	return;
}

void
TileObject::removeFromAffectedTiles()
{
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	return;
}

void
TileObject::addToAffectedTiles()
{
	//Override this for collidable objects
	LogWarning("Called on non-collidable object");
	assert(!this->isCollidable());
	return;
}

void
TileObject::checkProjectileCollision()
{
	//Override this for projectile objects
	LogWarning("Called on non-projectile object");
	assert(!this->isProjectile());
	return;
}

void
TileObject::drawProjectile(TileView &v, Renderer &r, Vec2<int> screenPosition)
{
	//Override this for projectile objects
	LogWarning("Called on non-projectile object");
	assert(!this->isProjectile());
	std::ignore = v;
	std::ignore = r;
	std::ignore = screenPosition;
	return;
}

class PathComparer
{
public:
	Vec3<float> dest;
	Vec3<float> origin;
	PathComparer(Vec3<int> d)
		: dest{d.x, d.y, d.z}{}
	bool operator() (Tile* t1, Tile* t2)
	{
		Vec3<float> t1Pos {t1->position.x, t1->position.y, t1->position.z};
		Vec3<float> t2Pos {t2->position.x, t2->position.y, t2->position.z};

		Vec3<float> t1tod  = dest - t1Pos;
		Vec3<float> t2tod  = dest - t2Pos;

		float t1cost = glm::length(t1tod);
		float t2cost = glm::length(t2tod);

		t1cost += glm::length(t1Pos-origin);
		t2cost += glm::length(t2Pos-origin);

		return (t1cost < t2cost);

	}
};

#define THRESHOLD_ITERATIONS 500

static bool findNextNodeOnPath(PathComparer &comparer, TileMap &map, std::list<Tile*> &currentPath, Vec3<int> destination, volatile unsigned long *numIterations)
{
	if (currentPath.back()->position == destination)
		return true;
	if (*numIterations > THRESHOLD_ITERATIONS)
		return false;
	*numIterations = (*numIterations)+1;
	std::vector<Tile*> fringe;
	for (int x = -1; x <= 1; x++)
	{
		for (int y = -1; y <= 1; y++)
		{
			for (int z = -1; z <= 1; z++)
			{
				Vec3<int> currentPosition = currentPath.back()->position;
				if (z == 0 && y == 0 && x == 0)
					continue;
				Vec3<int> nextPosition = currentPosition;
				nextPosition.x += x;
				nextPosition.y += y;
				nextPosition.z += z;
				if (nextPosition.z < 0 || nextPosition.z >= map.size.z
					|| nextPosition.y < 0 || nextPosition.y >= map.size.y
					|| nextPosition.x < 0 || nextPosition.x >= map.size.x)
					continue;
				Tile *tile = map.getTile(nextPosition);
				//FIXME: Make 'blocked' tiles cleverer (e.g. don't plan around objects that will move anyway?)
				if (!tile->collideableObjects.empty())
					continue;
				//Check for diagonal routes that the 'corner' tiles we touch are empty
				Vec3<int> cornerPosition = currentPosition;
				cornerPosition += Vec3<int>{0,y,z};
				if (cornerPosition != currentPosition &&
					!map.getTile(cornerPosition)->ownedObjects.empty())
					continue;
				cornerPosition = currentPosition;
				cornerPosition += Vec3<int>{x,0,z};
				if (cornerPosition != currentPosition &&
					!map.getTile(cornerPosition)->ownedObjects.empty())
					continue;
				cornerPosition = currentPosition;
				cornerPosition += Vec3<int>{x,y,0};
				if (cornerPosition != currentPosition &&
					!map.getTile(cornerPosition)->ownedObjects.empty())
					continue;
				//Already visited this tile
				if (std::find(currentPath.begin(), currentPath.end(), tile) != currentPath.end())
					continue;
				fringe.push_back(tile);
			}
		}
	}
	std::sort(fringe.begin(), fringe.end(), comparer);
	for (auto tile : fringe)
	{
		currentPath.push_back(tile);
		comparer.origin = {tile->position.x, tile->position.y, tile->position.z};
		if (findNextNodeOnPath(comparer, map, currentPath, destination, numIterations))
			return true;
		currentPath.pop_back();
	}
	return false;

}

std::list<Tile*>
TileMap::findShortestPath(Vec3<int> origin, Vec3<int> destination)
{
	volatile unsigned long numIterations = 0;
	std::list<Tile*> path;
	PathComparer pc(destination);
	if (origin.x < 0 || origin.x >= this->size.x
		|| origin.y < 0 || origin.y >= this->size.y
		|| origin.z < 0 || origin.z >= this->size.z)
	{
		LogError("Bad origin {%d,%d,%d}", origin.x, origin.y, origin.z);
		return path;
	}
	if (destination.x < 0 || destination.x >= this->size.x
		|| destination.y < 0 || destination.y >= this->size.y
		|| destination.z < 0 || destination.z >= this->size.z)
	{
		LogError("Bad destination {%d,%d,%d}", destination.x, destination.y, destination.z);
		return path;
	}
	path.push_back(this->getTile(origin));
	if (!findNextNodeOnPath(pc, *this, path, destination, &numIterations))
	{
		LogWarning("No route found from origin {%d,%d,%d} to desination {%d,%d,%d}", origin.x, origin.y, origin.z, destination.x, destination.y, destination.z);
		path.clear();
		return path;
	}
	return path;
}

}; //namespace OpenApoc
<|endoftext|>


<commit_before>#ifndef _SDD_DD_PATH_GENERATOR_HH_
#define _SDD_DD_PATH_GENERATOR_HH_

#include <functional> // bind
#include <cassert>
#include <deque>
#include <memory>

#include <boost/coroutine/coroutine.hpp>

#include "sdd/dd/definition.hh"
#include "sdd/dd/path_generator_fwd.hh"

namespace sdd { namespace dd {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Generate all paths of an SDD.
///
/// It uses coroutines in order to generate them on the fly. For now, it doesn't use the visitor
/// mechanism of mem::variant, but a manual dispatch using variant's indexes.
template <typename C>
void
xpaths_impl( typename path_generator<C>::caller_type& yield
           , SDD<C> sdd, std::shared_ptr<path<C>> p, std::shared_ptr<sdd_stack<C>> stack)
{
  switch(sdd.index())
  {
    case (SDD<C>::hierarchical_node_index) :
    {
      const auto& node = sdd::mem::variant_cast<sdd::hierarchical_node<C>>(*sdd);
      for (const auto& arc : node)
      {
        const auto local_stack = std::make_shared<sdd_stack<C>>(arc.successor(), stack);
        xpaths_impl(yield, arc.valuation(), p, local_stack);
      }
      break;
    }

    case (SDD<C>::flat_node_index) :
    {
      const auto& node = sdd::mem::variant_cast<sdd::flat_node<C>>(*sdd);
      for (const auto& arc : node)
      {
        p->emplace_back(arc.valuation());
        xpaths_impl(yield, arc.successor(), p, stack);
        p->pop_back();
      }
      break;
    }

    case (SDD<C>::one_terminal_index) :
    {
      if (stack)
      {
        xpaths_impl(yield, stack->sdd, p, stack->next);
        return;
      }
      // end of a path
      yield(*p);
      break;
    }

    default /* zero_terminal */ :
    {
      assert(p->empty() && "Non empty path leading to |0|");
      yield(*p);
    }
  }
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace sdd::dd

#endif // _SDD_DD_PATH_GENERATOR_HH_
<commit_msg>Code cleanup (useless headers).<commit_after>#ifndef _SDD_DD_PATH_GENERATOR_HH_
#define _SDD_DD_PATH_GENERATOR_HH_

#include <cassert>
#include <memory>

#include <boost/coroutine/coroutine.hpp>

#include "sdd/dd/definition.hh"
#include "sdd/dd/path_generator_fwd.hh"

namespace sdd { namespace dd {

/*------------------------------------------------------------------------------------------------*/

/// @internal
/// @brief Generate all paths of an SDD.
///
/// It uses coroutines in order to generate them on the fly. For now, it doesn't use the visitor
/// mechanism of mem::variant, but a manual dispatch using variant's indexes.
template <typename C>
void
xpaths_impl( typename path_generator<C>::caller_type& yield
           , SDD<C> sdd, std::shared_ptr<path<C>> p, std::shared_ptr<sdd_stack<C>> stack)
{
  switch(sdd.index())
  {
    case (SDD<C>::hierarchical_node_index) :
    {
      const auto& node = sdd::mem::variant_cast<sdd::hierarchical_node<C>>(*sdd);
      for (const auto& arc : node)
      {
        const auto local_stack = std::make_shared<sdd_stack<C>>(arc.successor(), stack);
        xpaths_impl(yield, arc.valuation(), p, local_stack);
      }
      break;
    }

    case (SDD<C>::flat_node_index) :
    {
      const auto& node = sdd::mem::variant_cast<sdd::flat_node<C>>(*sdd);
      for (const auto& arc : node)
      {
        p->emplace_back(arc.valuation());
        xpaths_impl(yield, arc.successor(), p, stack);
        p->pop_back();
      }
      break;
    }

    case (SDD<C>::one_terminal_index) :
    {
      if (stack)
      {
        xpaths_impl(yield, stack->sdd, p, stack->next);
        return;
      }
      // end of a path
      yield(*p);
      break;
    }

    default /* zero_terminal */ :
    {
      assert(p->empty() && "Non empty path leading to |0|");
      yield(*p);
    }
  }
}

/*------------------------------------------------------------------------------------------------*/

}} // namespace sdd::dd

#endif // _SDD_DD_PATH_GENERATOR_HH_
<|endoftext|>