<commit_before>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Creator.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "maemoruncontrol.h"
#include "maemosshthread.h"
#include "maemorunconfiguration.h"

#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <debugger/debuggermanager.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/toolchain.h>
#include <utils/qtcassert.h>

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QFuture>
#include <QtCore/QProcess>
#include <QtCore/QStringBuilder>

#include <QtGui/QMessageBox>

namespace Qt4ProjectManager {
namespace Internal {

using ProjectExplorer::RunConfiguration;
using ProjectExplorer::ToolChain;

AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc)
    : RunControl(rc)
    , m_runConfig(qobject_cast<MaemoRunConfiguration *>(rc))
    , m_devConfig(m_runConfig ? m_runConfig->deviceConfig() : MaemoDeviceConfig())
{
}

AbstractMaemoRunControl::~AbstractMaemoRunControl()
{
}

void AbstractMaemoRunControl::start()
{
    m_stoppedByUser = false;
    emit started();
    startInitialCleanup();
}

void AbstractMaemoRunControl::startInitialCleanup()
{
    emit addToOutputWindow(this, tr("Cleaning up remote leftovers first ..."));
    const QStringList appsToKill
        = QStringList() << executableFileName() << QLatin1String("gdbserver");
    killRemoteProcesses(appsToKill, true);
}

void AbstractMaemoRunControl::stop()
{
    m_stoppedByUser = true;
    if (isCleaning())
        m_initialCleaner->stop();
    else if (isDeploying())
        m_sshDeployer->stop();
    else
        stopInternal();
}

void AbstractMaemoRunControl::handleInitialCleanupFinished()
{
    if (m_stoppedByUser) {
        emit addToOutputWindow(this, tr("Initial cleanup canceled by user."));
        emit finished();
    } else if (m_initialCleaner->hasError()) {
        handleError(tr("Error running initial cleanup: %1.")
                    .arg(m_initialCleaner->error()));
        emit finished();
    } else {
        emit addToOutputWindow(this, tr("Initial cleanup done."));
        startInternal();
    }
}

void AbstractMaemoRunControl::startDeployment(bool forDebugging)
{
    QTC_ASSERT(m_runConfig, return);

    if (!m_devConfig.isValid()) {
        handleError(tr("No device configuration set for run configuration."));
        emit finished();
    } else if (m_stoppedByUser) {
        emit finished();
    } else {
        m_deployables.clear();
        if (m_runConfig->currentlyNeedsDeployment(m_devConfig.host)) {
            m_deployables.append(Deployable(executableFileName(),
                QFileInfo(executableOnHost()).canonicalPath(),
                &MaemoRunConfiguration::wasDeployed));
        }
        if (forDebugging
            && m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.host)) {
            const QFileInfo &info(m_runConfig->dumperLib());
            m_deployables.append(Deployable(info.fileName(), info.canonicalPath(),
                &MaemoRunConfiguration::debuggingHelpersDeployed));
        }

        deploy();
    }
}

void AbstractMaemoRunControl::deploy()
{
    Core::ICore::instance()->progressManager()
        ->addTask(m_progress.future(), tr("Deploying"),
                  QLatin1String("Maemo.Deploy"));
    if (!m_deployables.isEmpty()) {
        QList<SshDeploySpec> deploySpecs;
        QStringList files;
        foreach (const Deployable &deployable, m_deployables) {
            const QString srcFilePath
                = deployable.dir % QDir::separator() % deployable.fileName;
            const QString tgtFilePath
                = remoteDir() % QDir::separator() % deployable.fileName;
            files << srcFilePath;
            deploySpecs << SshDeploySpec(srcFilePath, tgtFilePath);
        }
        emit addToOutputWindow(this, tr("Files to deploy: %1.").arg(files.join(" ")));
        m_sshDeployer.reset(new MaemoSshDeployer(m_devConfig, deploySpecs));
        connect(m_sshDeployer.data(), SIGNAL(finished()),
                this, SLOT(handleDeployThreadFinished()));
        connect(m_sshDeployer.data(), SIGNAL(fileCopied(QString)),
                this, SLOT(handleFileCopied()));
        m_progress.setProgressRange(0, m_deployables.count());
        m_progress.setProgressValue(0);
        m_progress.reportStarted();
        m_sshDeployer->start();
    } else {
        m_progress.reportFinished();
        startExecution();
    }
}

void AbstractMaemoRunControl::handleFileCopied()
{
    Deployable deployable = m_deployables.takeFirst();
    (m_runConfig->*deployable.updateTimestamp)(m_devConfig.host);
    m_progress.setProgressValue(m_progress.progressValue() + 1);
}

bool AbstractMaemoRunControl::isDeploying() const
{
    return m_sshDeployer && m_sshDeployer->isRunning();
}

bool AbstractMaemoRunControl::isCleaning() const
{
    return m_initialCleaner && m_initialCleaner->isRunning();
}

void AbstractMaemoRunControl::startExecution()
{
    m_sshRunner.reset(new MaemoSshRunner(m_devConfig, remoteCall()));
    connect(m_sshRunner.data(), SIGNAL(finished()),
            this, SLOT(handleRunThreadFinished()));
    connect(m_sshRunner.data(), SIGNAL(remoteOutput(QString)),
            this, SLOT(handleRemoteOutput(QString)));
    emit addToOutputWindow(this, tr("Starting remote application."));
    m_sshRunner->start();
}

bool AbstractMaemoRunControl::isRunning() const
{
    return isDeploying() || (m_sshRunner && m_sshRunner->isRunning());
}

void AbstractMaemoRunControl::stopRunning(bool forDebugging)
{
    if (m_sshRunner && m_sshRunner->isRunning()) {
        m_sshRunner->stop();
        QStringList apps(executableFileName());
        if (forDebugging)
            apps << QLatin1String("gdbserver");
        killRemoteProcesses(apps, false);
    }
}

void AbstractMaemoRunControl::killRemoteProcesses(const QStringList &apps,
                                                  bool initialCleanup)
{
    QString niceKill;
    QString brutalKill;
    foreach (const QString &app, apps) {
        niceKill += QString::fromLocal8Bit("pkill -x %1;").arg(app);
        brutalKill += QString::fromLocal8Bit("pkill -x -9 %1;").arg(app);
    }
    const QString remoteCall
        = niceKill + QLatin1String("sleep 1; ") + brutalKill;
    QScopedPointer<MaemoSshRunner> &runner
        = initialCleanup ? m_initialCleaner : m_sshStopper;
    runner.reset(new MaemoSshRunner(m_devConfig, remoteCall));
    if (initialCleanup)
        connect(runner.data(), SIGNAL(finished()),
                this, SLOT(handleInitialCleanupFinished()));
    runner->start();
}

void AbstractMaemoRunControl::handleDeployThreadFinished()
{
    bool cancel;
    if (m_stoppedByUser) {
        emit addToOutputWindow(this, tr("Deployment canceled by user."));
        cancel = true;
    } else if (m_sshDeployer->hasError()) {
        handleError(tr("Deployment failed: %1").arg(m_sshDeployer->error()));
        cancel = true;
    } else {
        emit addToOutputWindow(this, tr("Deployment finished."));
        cancel = false;
    }

    if (cancel) {
        m_progress.reportCanceled();
        m_progress.reportFinished();
        emit finished();
    } else {
        m_progress.reportFinished();
        startExecution();
    }
}

void AbstractMaemoRunControl::handleRunThreadFinished()
{
    if (m_stoppedByUser) {
        emit addToOutputWindow(this,
                 tr("Remote execution canceled due to user request."));
    } else if (m_sshRunner->hasError()) {
        emit addToOutputWindow(this, tr("Error running remote process: %1")
                                         .arg(m_sshRunner->error()));
    } else {
        emit addToOutputWindow(this, tr("Finished running remote process."));
    }
    emit finished();
}

const QString AbstractMaemoRunControl::executableOnHost() const
{
    qDebug("runconfig->executable: %s", qPrintable(m_runConfig->executable()));
    return m_runConfig->executable();
}

const QString AbstractMaemoRunControl::sshPort() const
{
    return m_devConfig.type == MaemoDeviceConfig::Physical
        ? QString::number(m_devConfig.sshPort)
        : m_runConfig->simulatorSshPort();
}

const QString AbstractMaemoRunControl::executableFileName() const
{
    return QFileInfo(executableOnHost()).fileName();
}

const QString AbstractMaemoRunControl::remoteDir() const
{
    return homeDirOnDevice(m_devConfig.uname);
}

const QStringList AbstractMaemoRunControl::options() const
{
    const bool usePassword
        = m_devConfig.authentication == MaemoDeviceConfig::Password;
    const QLatin1String opt("-o");
    QStringList optionList;
    if (!usePassword)
        optionList << QLatin1String("-i") << m_devConfig.keyFile;
    return optionList << opt
        << QString::fromLatin1("PasswordAuthentication=%1").
            arg(usePassword ? "yes" : "no") << opt
        << QString::fromLatin1("PubkeyAuthentication=%1").
            arg(usePassword ? "no" : "yes") << opt
        << QString::fromLatin1("ConnectTimeout=%1").arg(m_devConfig.timeout)
        << opt << QLatin1String("CheckHostIP=no")
        << opt << QLatin1String("StrictHostKeyChecking=no");
}

const QString AbstractMaemoRunControl::executableOnTarget() const
{
    return QString::fromLocal8Bit("%1/%2").arg(remoteDir()).
        arg(executableFileName());
}

const QString AbstractMaemoRunControl::targetCmdLinePrefix() const
{
    return QString::fromLocal8Bit("chmod u+x %1; source /etc/profile; ").
        arg(executableOnTarget());
}

void AbstractMaemoRunControl::handleError(const QString &errString)
{
    QMessageBox::critical(0, tr("Remote Execution Failure"), errString);
    emit error(this, errString);
}

MaemoRunControl::MaemoRunControl(RunConfiguration *runConfiguration)
    : AbstractMaemoRunControl(runConfiguration)
{
}

MaemoRunControl::~MaemoRunControl()
{
    stop();
}

void MaemoRunControl::startInternal()
{
    startDeployment(false);
}

QString MaemoRunControl::remoteCall() const
{
    return QString::fromLocal8Bit("%1 %2 %3")
        .arg(targetCmdLinePrefix()).arg(executableOnTarget())
        .arg(m_runConfig->arguments().join(" "));
}

void MaemoRunControl::stopInternal()
{
    AbstractMaemoRunControl::stopRunning(false);
}

void MaemoRunControl::handleRemoteOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output);
}

MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration)
    : AbstractMaemoRunControl(runConfiguration)
    , m_debuggerManager(ExtensionSystem::PluginManager::instance()
                      ->getObject<Debugger::DebuggerManager>())
    , m_startParams(new Debugger::DebuggerStartParameters)
{
    QTC_ASSERT(m_debuggerManager != 0, return);
    m_startParams->startMode = Debugger::StartRemote;
    m_startParams->executable = executableOnHost();
    m_startParams->remoteChannel
        = m_devConfig.host % QLatin1Char(':') % gdbServerPort();
    m_startParams->remoteArchitecture = QLatin1String("arm");
    m_startParams->sysRoot = m_runConfig->sysRoot();
    m_startParams->toolChainType = ToolChain::GCC_MAEMO;
    m_startParams->debuggerCommand = m_runConfig->gdbCmd();
    m_startParams->dumperLibrary = m_runConfig->dumperLib();
    m_startParams->remoteDumperLib = QString::fromLocal8Bit("%1/%2")
        .arg(remoteDir()).arg(QFileInfo(m_runConfig->dumperLib()).fileName());

    connect(m_debuggerManager, SIGNAL(debuggingFinished()), this,
        SLOT(debuggingFinished()), Qt::QueuedConnection);
    connect(m_debuggerManager, SIGNAL(applicationOutputAvailable(QString)),
        this, SLOT(debuggerOutput(QString)), Qt::QueuedConnection);
}

MaemoDebugRunControl::~MaemoDebugRunControl()
{
    disconnect(SIGNAL(addToOutputWindow(RunControl*,QString)));
    disconnect(SIGNAL(addToOutputWindowInline(RunControl*,QString)));
    stop();
    debuggingFinished();
}

void MaemoDebugRunControl::startInternal()
{
    m_inferiorPid = -1;
    startDeployment(true);
}

QString MaemoDebugRunControl::remoteCall() const
{
    return QString::fromLocal8Bit("%1 gdbserver :%2 %3 %4")
        .arg(targetCmdLinePrefix()).arg(gdbServerPort())
        .arg(executableOnTarget()).arg(m_runConfig->arguments().join(" "));
}

void MaemoDebugRunControl::handleRemoteOutput(const QString &output)
{
    qDebug("gdbserver's stderr output: %s", output.toLatin1().data());
    if (m_inferiorPid != -1)
        return;
    const QString searchString("pid = ");
    const int searchStringLength = searchString.length();
    int pidStartPos = output.indexOf(searchString);
    const int pidEndPos = output.indexOf("\n", pidStartPos + searchStringLength);
    if (pidStartPos == -1 || pidEndPos == -1)
        return; // gdbserver has not started yet.
    pidStartPos += searchStringLength;
    QString pidString = output.mid(pidStartPos, pidEndPos - pidStartPos);
    qDebug("pidString = %s", pidString.toLatin1().data());
    bool ok;
    const int pid = pidString.toInt(&ok);
    if (!ok) {
        handleError(tr("Debugging failed: Could not parse gdbserver output."));
        m_debuggerManager->exitDebugger();
    } else {
        m_inferiorPid = pid;
        startDebugging();
    }
}

void MaemoDebugRunControl::startDebugging()
{
    m_debuggerManager->startNewDebugger(m_startParams);
}

void MaemoDebugRunControl::stopInternal()
{
    m_debuggerManager->exitDebugger();
}

bool MaemoDebugRunControl::isRunning() const
{
    return AbstractMaemoRunControl::isRunning()
        || m_debuggerManager->state() != Debugger::DebuggerNotReady;
}

void MaemoDebugRunControl::debuggingFinished()
{
    AbstractMaemoRunControl::stopRunning(true);
}

void MaemoDebugRunControl::debuggerOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output);
}

QString MaemoDebugRunControl::gdbServerPort() const
{
    return m_devConfig.type == MaemoDeviceConfig::Physical
        ? QString::number(m_devConfig.gdbServerPort)
        : m_runConfig->simulatorGdbServerPort();
}

} // namespace Internal
} // namespace Qt4ProjectManager
<commit_msg>Maemo: Do check for valid device confuguration earlier.<commit_after>/****************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Creator.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights.  These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** If you have questions regarding the use of this file, please contact
** Nokia at qt-info@nokia.com.
**
** $QT_END_LICENSE$
**
****************************************************************************/

#include "maemoruncontrol.h"
#include "maemosshthread.h"
#include "maemorunconfiguration.h"

#include <coreplugin/icore.h>
#include <coreplugin/progressmanager/progressmanager.h>
#include <debugger/debuggermanager.h>
#include <extensionsystem/pluginmanager.h>
#include <projectexplorer/toolchain.h>
#include <utils/qtcassert.h>

#include <QtCore/QDir>
#include <QtCore/QFileInfo>
#include <QtCore/QFuture>
#include <QtCore/QProcess>
#include <QtCore/QStringBuilder>

#include <QtGui/QMessageBox>

namespace Qt4ProjectManager {
namespace Internal {

using ProjectExplorer::RunConfiguration;
using ProjectExplorer::ToolChain;

AbstractMaemoRunControl::AbstractMaemoRunControl(RunConfiguration *rc)
    : RunControl(rc)
    , m_runConfig(qobject_cast<MaemoRunConfiguration *>(rc))
    , m_devConfig(m_runConfig ? m_runConfig->deviceConfig() : MaemoDeviceConfig())
{
}

AbstractMaemoRunControl::~AbstractMaemoRunControl()
{
}

void AbstractMaemoRunControl::start()
{
    m_stoppedByUser = false;
    if (!m_devConfig.isValid()) {
        handleError(tr("No device configuration set for run configuration."));
    } else {
        emit started();
        startInitialCleanup();
    }
}

void AbstractMaemoRunControl::startInitialCleanup()
{
    emit addToOutputWindow(this, tr("Cleaning up remote leftovers first ..."));
    const QStringList appsToKill
        = QStringList() << executableFileName() << QLatin1String("gdbserver");
    killRemoteProcesses(appsToKill, true);
}

void AbstractMaemoRunControl::stop()
{
    m_stoppedByUser = true;
    if (isCleaning())
        m_initialCleaner->stop();
    else if (isDeploying())
        m_sshDeployer->stop();
    else
        stopInternal();
}

void AbstractMaemoRunControl::handleInitialCleanupFinished()
{
    if (m_stoppedByUser) {
        emit addToOutputWindow(this, tr("Initial cleanup canceled by user."));
        emit finished();
    } else if (m_initialCleaner->hasError()) {
        handleError(tr("Error running initial cleanup: %1.")
                    .arg(m_initialCleaner->error()));
        emit finished();
    } else {
        emit addToOutputWindow(this, tr("Initial cleanup done."));
        startInternal();
    }
}

void AbstractMaemoRunControl::startDeployment(bool forDebugging)
{
    QTC_ASSERT(m_runConfig, return);

    if (m_stoppedByUser) {
        emit finished();
    } else {
        m_deployables.clear();
        if (m_runConfig->currentlyNeedsDeployment(m_devConfig.host)) {
            m_deployables.append(Deployable(executableFileName(),
                QFileInfo(executableOnHost()).canonicalPath(),
                &MaemoRunConfiguration::wasDeployed));
        }
        if (forDebugging
            && m_runConfig->debuggingHelpersNeedDeployment(m_devConfig.host)) {
            const QFileInfo &info(m_runConfig->dumperLib());
            m_deployables.append(Deployable(info.fileName(), info.canonicalPath(),
                &MaemoRunConfiguration::debuggingHelpersDeployed));
        }

        deploy();
    }
}

void AbstractMaemoRunControl::deploy()
{
    Core::ICore::instance()->progressManager()
        ->addTask(m_progress.future(), tr("Deploying"),
                  QLatin1String("Maemo.Deploy"));
    if (!m_deployables.isEmpty()) {
        QList<SshDeploySpec> deploySpecs;
        QStringList files;
        foreach (const Deployable &deployable, m_deployables) {
            const QString srcFilePath
                = deployable.dir % QDir::separator() % deployable.fileName;
            const QString tgtFilePath
                = remoteDir() % QDir::separator() % deployable.fileName;
            files << srcFilePath;
            deploySpecs << SshDeploySpec(srcFilePath, tgtFilePath);
        }
        emit addToOutputWindow(this, tr("Files to deploy: %1.").arg(files.join(" ")));
        m_sshDeployer.reset(new MaemoSshDeployer(m_devConfig, deploySpecs));
        connect(m_sshDeployer.data(), SIGNAL(finished()),
                this, SLOT(handleDeployThreadFinished()));
        connect(m_sshDeployer.data(), SIGNAL(fileCopied(QString)),
                this, SLOT(handleFileCopied()));
        m_progress.setProgressRange(0, m_deployables.count());
        m_progress.setProgressValue(0);
        m_progress.reportStarted();
        m_sshDeployer->start();
    } else {
        m_progress.reportFinished();
        startExecution();
    }
}

void AbstractMaemoRunControl::handleFileCopied()
{
    Deployable deployable = m_deployables.takeFirst();
    (m_runConfig->*deployable.updateTimestamp)(m_devConfig.host);
    m_progress.setProgressValue(m_progress.progressValue() + 1);
}

bool AbstractMaemoRunControl::isDeploying() const
{
    return m_sshDeployer && m_sshDeployer->isRunning();
}

bool AbstractMaemoRunControl::isCleaning() const
{
    return m_initialCleaner && m_initialCleaner->isRunning();
}

void AbstractMaemoRunControl::startExecution()
{
    m_sshRunner.reset(new MaemoSshRunner(m_devConfig, remoteCall()));
    connect(m_sshRunner.data(), SIGNAL(finished()),
            this, SLOT(handleRunThreadFinished()));
    connect(m_sshRunner.data(), SIGNAL(remoteOutput(QString)),
            this, SLOT(handleRemoteOutput(QString)));
    emit addToOutputWindow(this, tr("Starting remote application."));
    m_sshRunner->start();
}

bool AbstractMaemoRunControl::isRunning() const
{
    return isDeploying() || (m_sshRunner && m_sshRunner->isRunning());
}

void AbstractMaemoRunControl::stopRunning(bool forDebugging)
{
    if (m_sshRunner && m_sshRunner->isRunning()) {
        m_sshRunner->stop();
        QStringList apps(executableFileName());
        if (forDebugging)
            apps << QLatin1String("gdbserver");
        killRemoteProcesses(apps, false);
    }
}

void AbstractMaemoRunControl::killRemoteProcesses(const QStringList &apps,
                                                  bool initialCleanup)
{
    QString niceKill;
    QString brutalKill;
    foreach (const QString &app, apps) {
        niceKill += QString::fromLocal8Bit("pkill -x %1;").arg(app);
        brutalKill += QString::fromLocal8Bit("pkill -x -9 %1;").arg(app);
    }
    const QString remoteCall
        = niceKill + QLatin1String("sleep 1; ") + brutalKill;
    QScopedPointer<MaemoSshRunner> &runner
        = initialCleanup ? m_initialCleaner : m_sshStopper;
    runner.reset(new MaemoSshRunner(m_devConfig, remoteCall));
    if (initialCleanup)
        connect(runner.data(), SIGNAL(finished()),
                this, SLOT(handleInitialCleanupFinished()));
    runner->start();
}

void AbstractMaemoRunControl::handleDeployThreadFinished()
{
    bool cancel;
    if (m_stoppedByUser) {
        emit addToOutputWindow(this, tr("Deployment canceled by user."));
        cancel = true;
    } else if (m_sshDeployer->hasError()) {
        handleError(tr("Deployment failed: %1").arg(m_sshDeployer->error()));
        cancel = true;
    } else {
        emit addToOutputWindow(this, tr("Deployment finished."));
        cancel = false;
    }

    if (cancel) {
        m_progress.reportCanceled();
        m_progress.reportFinished();
        emit finished();
    } else {
        m_progress.reportFinished();
        startExecution();
    }
}

void AbstractMaemoRunControl::handleRunThreadFinished()
{
    if (m_stoppedByUser) {
        emit addToOutputWindow(this,
                 tr("Remote execution canceled due to user request."));
    } else if (m_sshRunner->hasError()) {
        emit addToOutputWindow(this, tr("Error running remote process: %1")
                                         .arg(m_sshRunner->error()));
    } else {
        emit addToOutputWindow(this, tr("Finished running remote process."));
    }
    emit finished();
}

const QString AbstractMaemoRunControl::executableOnHost() const
{
    qDebug("runconfig->executable: %s", qPrintable(m_runConfig->executable()));
    return m_runConfig->executable();
}

const QString AbstractMaemoRunControl::sshPort() const
{
    return m_devConfig.type == MaemoDeviceConfig::Physical
        ? QString::number(m_devConfig.sshPort)
        : m_runConfig->simulatorSshPort();
}

const QString AbstractMaemoRunControl::executableFileName() const
{
    return QFileInfo(executableOnHost()).fileName();
}

const QString AbstractMaemoRunControl::remoteDir() const
{
    return homeDirOnDevice(m_devConfig.uname);
}

const QStringList AbstractMaemoRunControl::options() const
{
    const bool usePassword
        = m_devConfig.authentication == MaemoDeviceConfig::Password;
    const QLatin1String opt("-o");
    QStringList optionList;
    if (!usePassword)
        optionList << QLatin1String("-i") << m_devConfig.keyFile;
    return optionList << opt
        << QString::fromLatin1("PasswordAuthentication=%1").
            arg(usePassword ? "yes" : "no") << opt
        << QString::fromLatin1("PubkeyAuthentication=%1").
            arg(usePassword ? "no" : "yes") << opt
        << QString::fromLatin1("ConnectTimeout=%1").arg(m_devConfig.timeout)
        << opt << QLatin1String("CheckHostIP=no")
        << opt << QLatin1String("StrictHostKeyChecking=no");
}

const QString AbstractMaemoRunControl::executableOnTarget() const
{
    return QString::fromLocal8Bit("%1/%2").arg(remoteDir()).
        arg(executableFileName());
}

const QString AbstractMaemoRunControl::targetCmdLinePrefix() const
{
    return QString::fromLocal8Bit("chmod u+x %1; source /etc/profile; ").
        arg(executableOnTarget());
}

void AbstractMaemoRunControl::handleError(const QString &errString)
{
    QMessageBox::critical(0, tr("Remote Execution Failure"), errString);
    emit error(this, errString);
}

MaemoRunControl::MaemoRunControl(RunConfiguration *runConfiguration)
    : AbstractMaemoRunControl(runConfiguration)
{
}

MaemoRunControl::~MaemoRunControl()
{
    stop();
}

void MaemoRunControl::startInternal()
{
    startDeployment(false);
}

QString MaemoRunControl::remoteCall() const
{
    return QString::fromLocal8Bit("%1 %2 %3")
        .arg(targetCmdLinePrefix()).arg(executableOnTarget())
        .arg(m_runConfig->arguments().join(" "));
}

void MaemoRunControl::stopInternal()
{
    AbstractMaemoRunControl::stopRunning(false);
}

void MaemoRunControl::handleRemoteOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output);
}

MaemoDebugRunControl::MaemoDebugRunControl(RunConfiguration *runConfiguration)
    : AbstractMaemoRunControl(runConfiguration)
    , m_debuggerManager(ExtensionSystem::PluginManager::instance()
                      ->getObject<Debugger::DebuggerManager>())
    , m_startParams(new Debugger::DebuggerStartParameters)
{
    QTC_ASSERT(m_debuggerManager != 0, return);
    m_startParams->startMode = Debugger::StartRemote;
    m_startParams->executable = executableOnHost();
    m_startParams->remoteChannel
        = m_devConfig.host % QLatin1Char(':') % gdbServerPort();
    m_startParams->remoteArchitecture = QLatin1String("arm");
    m_startParams->sysRoot = m_runConfig->sysRoot();
    m_startParams->toolChainType = ToolChain::GCC_MAEMO;
    m_startParams->debuggerCommand = m_runConfig->gdbCmd();
    m_startParams->dumperLibrary = m_runConfig->dumperLib();
    m_startParams->remoteDumperLib = QString::fromLocal8Bit("%1/%2")
        .arg(remoteDir()).arg(QFileInfo(m_runConfig->dumperLib()).fileName());

    connect(m_debuggerManager, SIGNAL(debuggingFinished()), this,
        SLOT(debuggingFinished()), Qt::QueuedConnection);
    connect(m_debuggerManager, SIGNAL(applicationOutputAvailable(QString)),
        this, SLOT(debuggerOutput(QString)), Qt::QueuedConnection);
}

MaemoDebugRunControl::~MaemoDebugRunControl()
{
    disconnect(SIGNAL(addToOutputWindow(RunControl*,QString)));
    disconnect(SIGNAL(addToOutputWindowInline(RunControl*,QString)));
    stop();
    debuggingFinished();
}

void MaemoDebugRunControl::startInternal()
{
    m_inferiorPid = -1;
    startDeployment(true);
}

QString MaemoDebugRunControl::remoteCall() const
{
    return QString::fromLocal8Bit("%1 gdbserver :%2 %3 %4")
        .arg(targetCmdLinePrefix()).arg(gdbServerPort())
        .arg(executableOnTarget()).arg(m_runConfig->arguments().join(" "));
}

void MaemoDebugRunControl::handleRemoteOutput(const QString &output)
{
    qDebug("gdbserver's stderr output: %s", output.toLatin1().data());
    if (m_inferiorPid != -1)
        return;
    const QString searchString("pid = ");
    const int searchStringLength = searchString.length();
    int pidStartPos = output.indexOf(searchString);
    const int pidEndPos = output.indexOf("\n", pidStartPos + searchStringLength);
    if (pidStartPos == -1 || pidEndPos == -1)
        return; // gdbserver has not started yet.
    pidStartPos += searchStringLength;
    QString pidString = output.mid(pidStartPos, pidEndPos - pidStartPos);
    qDebug("pidString = %s", pidString.toLatin1().data());
    bool ok;
    const int pid = pidString.toInt(&ok);
    if (!ok) {
        handleError(tr("Debugging failed: Could not parse gdbserver output."));
        m_debuggerManager->exitDebugger();
    } else {
        m_inferiorPid = pid;
        startDebugging();
    }
}

void MaemoDebugRunControl::startDebugging()
{
    m_debuggerManager->startNewDebugger(m_startParams);
}

void MaemoDebugRunControl::stopInternal()
{
    m_debuggerManager->exitDebugger();
}

bool MaemoDebugRunControl::isRunning() const
{
    return AbstractMaemoRunControl::isRunning()
        || m_debuggerManager->state() != Debugger::DebuggerNotReady;
}

void MaemoDebugRunControl::debuggingFinished()
{
    AbstractMaemoRunControl::stopRunning(true);
}

void MaemoDebugRunControl::debuggerOutput(const QString &output)
{
    emit addToOutputWindowInline(this, output);
}

QString MaemoDebugRunControl::gdbServerPort() const
{
    return m_devConfig.type == MaemoDeviceConfig::Physical
        ? QString::number(m_devConfig.gdbServerPort)
        : m_runConfig->simulatorGdbServerPort();
}

} // namespace Internal
} // namespace Qt4ProjectManager
<|endoftext|>


<commit_before>#include <system/System.h>
#include <utils/Bytes.h>
#include <map>

namespace lime {

	static int id_b;
	static int id_length;
	static bool init = false;
	static bool useBuffer = false;
	static std::map<Bytes*, bool> usingValue;

	inline void _initializeBytes () {

		if (!init) {

			id_b = val_id ("b");
			id_length = val_id ("length");

			buffer _buffer = alloc_buffer_len (1);

			if (buffer_data (_buffer)) {

				useBuffer = true;

			}

			init = true;

		}

	}

	Bytes::Bytes () {

		_initializeBytes ();

		b = 0;
		length = 0;

	}

	Bytes::Bytes (value bytes) {

		_initializeBytes ();

		b = 0;
		length = 0;

		Set (bytes);

	}

	Bytes::~Bytes () {

		if (usingValue.find (this) != usingValue.end ()) {

			usingValue.erase (this);

		}

	}

	void Bytes::ReadFile (const char* path) {

		FILE_HANDLE *file = lime::fopen (path, "rb");

		if (!file) {

			return;

		}

		lime::fseek (file, 0, SEEK_END);
		int size = lime::ftell (file);
		lime::fseek (file, 0, SEEK_SET);

		if (size > 0) {

			Resize (size);
			int status = lime::fread (b, 1, size, file);

		}

		lime::fclose (file);

	}

	void Bytes::Resize (int size) {

		if (size != length) {

			if (size <= 0) {

				if (b) {

					if (usingValue.find (this) != usingValue.end ()) {

						usingValue.erase (this);

					} else {

						free (b);

					}

					b = 0;
					length = 0;

				}

			} else {

				unsigned char* data = (unsigned char*)malloc (sizeof (char) * size);

				if (b) {

					if (length) {

						memcpy (data, b, length < size ? length : size);

					}

					if (usingValue.find (this) != usingValue.end ()) {

						usingValue.erase (this);

					} else {

						free (b);

					}

				}

				b = data;
				length = size;

			}

		}

	}

	void Bytes::Set (value bytes) {

		if (val_is_null (bytes)) {

			if (usingValue.find (this) != usingValue.end ()) {

				usingValue.erase (this);

			}

			length = 0;
			b = 0;

		} else {

			usingValue[this] = true;

			length = val_int (val_field (bytes, id_length));

			if (length > 0) {

				value _b = val_field (bytes, id_b);

				if (val_is_string (_b)) {

					b = (unsigned char*)val_string (_b);

				} else {

					b = (unsigned char*)buffer_data (val_to_buffer (_b));

				}

			} else {

				b = 0;

			}

		}

	}

	void Bytes::Set (const QuickVec<unsigned char> data) {

		int size = data.size ();

		if (size > 0) {

			Resize (size);
			memcpy (b, &data[0], length);

		} else {

			if (usingValue.find (this) != usingValue.end ()) {

				usingValue.erase (this);

			}

			b = 0;
			length = 0;

		}

	}

	value Bytes::Value () {

		return alloc_null ();

	}

	value Bytes::Value (value bytes) {

		if (val_is_null (bytes)) {

			return alloc_null ();

		} else {

			alloc_field (bytes, id_length, alloc_int (length));

			if (useBuffer) {

				value _buffer = val_field (bytes, id_b);

				if (val_is_null (_buffer) || (char*)b != buffer_data (val_to_buffer (_buffer))) {

					alloc_field (bytes, id_b, buffer_val (alloc_buffer ((const char*)b)));

				}

			} else {

				value _string = val_field (bytes, id_b);

				if (val_is_null (_string) || (const char*)b != val_string (_string)) {

					value data = alloc_raw_string (length);
					memcpy ((void*)val_string (data), b, length);
					alloc_field (bytes, id_b, data);

				}

			}

			return bytes;

		}

	}

}<commit_msg>Bytes fixes<commit_after>#include <system/System.h>
#include <utils/Bytes.h>
#include <map>

namespace lime {

	static int id_b;
	static int id_length;
	static bool init = false;
	static bool useBuffer = false;
	static std::map<Bytes*, bool> usingValue;

	inline void _initializeBytes () {

		if (!init) {

			id_b = val_id ("b");
			id_length = val_id ("length");

			buffer _buffer = alloc_buffer_len (1);

			if (buffer_data (_buffer)) {

				useBuffer = true;

			}

			init = true;

		}

	}

	Bytes::Bytes () {

		_initializeBytes ();

		b = 0;
		length = 0;

	}

	Bytes::Bytes (value bytes) {

		_initializeBytes ();

		b = 0;
		length = 0;

		Set (bytes);

	}

	Bytes::~Bytes () {

		if (usingValue.find (this) != usingValue.end ()) {

			usingValue.erase (this);

		}

	}

	void Bytes::ReadFile (const char* path) {

		FILE_HANDLE *file = lime::fopen (path, "rb");

		if (!file) {

			return;

		}

		lime::fseek (file, 0, SEEK_END);
		int size = lime::ftell (file);
		lime::fseek (file, 0, SEEK_SET);

		if (size > 0) {

			Resize (size);
			int status = lime::fread (b, 1, size, file);

		}

		lime::fclose (file);

	}

	void Bytes::Resize (int size) {

		if (size != length) {

			if (size <= 0) {

				if (b) {

					if (usingValue.find (this) != usingValue.end ()) {

						usingValue.erase (this);

					} else {

						free (b);

					}

					b = 0;
					length = 0;

				}

			} else {

				unsigned char* data = (unsigned char*)malloc (sizeof (char) * size);

				if (b) {

					if (length) {

						memcpy (data, b, length < size ? length : size);

					}

					if (usingValue.find (this) != usingValue.end ()) {

						usingValue.erase (this);

					} else {

						free (b);

					}

				}

				b = data;
				length = size;

			}

		}

	}

	void Bytes::Set (value bytes) {

		if (val_is_null (bytes)) {

			if (usingValue.find (this) != usingValue.end ()) {

				usingValue.erase (this);

			}

			length = 0;
			b = 0;

		} else {

			usingValue[this] = true;

			length = val_int (val_field (bytes, id_length));

			if (length > 0) {

				value _b = val_field (bytes, id_b);

				if (val_is_string (_b)) {

					b = (unsigned char*)val_string (_b);

				} else {

					b = (unsigned char*)buffer_data (val_to_buffer (_b));

				}

			} else {

				b = 0;

			}

		}

	}

	void Bytes::Set (const QuickVec<unsigned char> data) {

		int size = data.size ();

		if (size > 0) {

			Resize (size);
			memcpy (b, &data[0], length);

		} else {

			if (usingValue.find (this) != usingValue.end ()) {

				usingValue.erase (this);

			}

			b = 0;
			length = 0;

		}

	}

	value Bytes::Value () {

		return alloc_null ();

	}

	value Bytes::Value (value bytes) {

		if (val_is_null (bytes) || !b) {

			return alloc_null ();

		} else {

			alloc_field (bytes, id_length, alloc_int (length));

			if (useBuffer) {

				value _buffer = val_field (bytes, id_b);

				if (val_is_null (_buffer) || (char*)b != buffer_data (val_to_buffer (_buffer))) {

					buffer bufferValue = alloc_buffer_len (length);
					_buffer = buffer_val (bufferValue);
					memcpy ((unsigned char*)buffer_data (bufferValue), b, length);
					alloc_field (bytes, id_b, _buffer);

				}

			} else {

				value _string = val_field (bytes, id_b);

				if (val_is_null (_string) || (const char*)b != val_string (_string)) {

					value data = alloc_raw_string (length);
					memcpy ((void*)val_string (data), b, length);
					alloc_field (bytes, id_b, data);

				}

			}

			free (b);
			b = NULL;

			return bytes;

		}

	}

}<|endoftext|>


<commit_before><commit_msg>Add only_track_persisted feature<commit_after><|endoftext|>


<commit_before>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_STREAM_BUFFEREDINPUTSTREAM_HPP
#define CATS_CORECAT_STREAM_BUFFEREDINPUTSTREAM_HPP

#include <algorithm>
#include <stdexcept>

#include "InputStream.hpp"

namespace Cats {
namespace Corecat {
namespace Stream {

template <typename T>
class BufferedInputStream : public InputStream<T> {

private:

    InputStream<T>* is;
    std::vector<T> data;
    std::size_t offset = 0;
    std::size_t size = 0;

public:

    BufferedInputStream(InputStream<T>& is_) : is(&is_), data(4096) {}
    BufferedInputStream(const BufferedInputStream& src) = delete;
    BufferedInputStream(BufferedInputStream&& src) : is(src.is), data(std::move(src.data)) { src.is = nullptr; }
    ~BufferedInputStream() override = default;

    BufferedInputStream& operator =(const BufferedInputStream& src) = delete;
    BufferedInputStream& operator =(BufferedInputStream&& src) { /* TODO */ return *this; }

    T read() override { T t; if(read(&t, 1)) return t; else throw std::runtime_error("End of stream"); }
    std::size_t read(T* buffer, std::size_t count) override {

        if(count <= size) {

            std::copy(data.data() + offset, data.data() + offset + count, buffer);
            offset += count, size -= count;
            return count;

        } else {

            if(size) std::copy(data.data() + offset, data.data() + offset + size, buffer);
            if(count < data.size() / 2) {

                std::size_t x = is->read(data.data(), count - size);
                if(x <= count - size) {

                    std::copy(data.data(), data.data() + x, buffer + size);
                    x += size;
                    size = 0;
                    return x;

                } else {

                    std::copy(data.data(), data.data() + count - size, buffer + size);
                    offset = count - size;
                    size = x - offset;
                    return count;

                }

            } else {

                std::size_t x = size + is->read(buffer + size, count - size);
                size = 0;
                return x;

            }

        }

    }
    void skip() override { skip(1); }
    void skip(std::size_t count) override {

        if(count <= size) offset += count, size -= count;
        else is->skip(count - size), size = 0;
    }

};

template <typename T>
inline BufferedInputStream<T> createBufferedInputStream(InputStream<T>& is) { return BufferedInputStream<T>(is); }

}
}
}

#endif
<commit_msg>Update BufferedInputStream<commit_after>/*
 *
 * MIT License
 *
 * Copyright (c) 2016-2017 The Cats Project
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 *
 */

#ifndef CATS_CORECAT_STREAM_BUFFEREDINPUTSTREAM_HPP
#define CATS_CORECAT_STREAM_BUFFEREDINPUTSTREAM_HPP

#include <algorithm>
#include <stdexcept>

#include "InputStream.hpp"

namespace Cats {
namespace Corecat {
namespace Stream {

template <typename T>
class BufferedInputStream : public InputStream<T> {

private:

    InputStream<T>* is;
    std::vector<T> data;
    std::size_t offset = 0;
    std::size_t size = 0;

public:

    BufferedInputStream(InputStream<T>& is_) : is(&is_), data(2096) {}
    BufferedInputStream(const BufferedInputStream& src) = delete;
    BufferedInputStream(BufferedInputStream&& src) : is(src.is), data(std::move(src.data)) { src.is = nullptr; }
    ~BufferedInputStream() override = default;

    BufferedInputStream& operator =(const BufferedInputStream& src) = delete;
    BufferedInputStream& operator =(BufferedInputStream&& src) { /* TODO */ return *this; }

    T read() override { T t; if(read(&t, 1)) return t; else throw std::runtime_error("End of stream"); }
    std::size_t read(T* buffer, std::size_t count) override {

        if(size) {

            std::size_t x = std::min(count, size);
            std::copy(data.data() + offset, data.data() + offset + x, buffer);
            offset += x, size -= x;
            return x;

        } else {

            if(count < data.size() / 2) {

                size = is->read(data.data(), data.size());
                offset = std::min(count, size);
                std::copy(data.data(), data.data() + offset, buffer);
                size -= offset;
                return offset;

            } else return is->read(buffer, count);

        }

    }
    void skip() override { skip(1); }
    void skip(std::size_t count) override {

        if(count <= size) offset += count, size -= count;
        else is->skip(count - size), size = 0;
    }

};

template <typename T>
inline BufferedInputStream<T> createBufferedInputStream(InputStream<T>& is) { return BufferedInputStream<T>(is); }

}
}
}

#endif
<|endoftext|>


<commit_before>/*
 * CollisionDetector.hpp
 *
 *      Author: Marcel Veltman
 */

#ifndef COLLISIONDETECTOR_HPP_
#define COLLISIONDETECTOR_HPP_

#include <typeinfo>

#include "scene/collisiondetection/BoundingSphere.hpp"
#include "scene/collisiondetection/BoundingVolume.hpp"

namespace scene {

	namespace collisiondetection {

		bool intersects(BoundingVolume& a, BoundingVolume& b) {
			bool collision = false;
			std::type_info typeA = typeid(a);
			std::type_info typeB = typeid(b);
			if(typeA == typeid(BoundingSphere) && typeB == typeid(BoundingSphere)) {
				BoundingSphere& bsa = static_cast<BoundingSphere&>(a);
				BoundingSphere& bsb = static_cast<BoundingSphere&>(b);
				collision = _intersects(bsa, bsb);
			} else if(typeA == typeid(AxisAlignedBoundingCuboid) && typeB == typeid(AxisAlignedBoundingCuboid)) {
				AxisAlignedBoundingCuboid& aabca = static_cast<AxisAlignedBoundingCuboid&>(a);
				AxisAlignedBoundingCuboid& aabcb = static_cast<AxisAlignedBoundingCuboid&>(b);
				collision = _intersects(aabca, aabcb);
			}
			return collision;
		}

		bool _intersects(BoundingSphere& a, BoundingSphere& b) {
			bool collision = false;

			float xSquare = (a.getLocation().x-b.getLocation().x)*(a.getLocation().x-b.getLocation().x);
			float ySquare = (a.getLocation().y-b.getLocation().y)*(a.getLocation().y-b.getLocation().y);
			float zSquare = (a.getLocation().z-b.getLocation().z)*(a.getLocation().z-b.getLocation().z);

			float centreDistance = std::sqrt(xSquare+ySquare+zSquare);
			collision = centreDistance <= (a.getRadius() + b.getRadius());

			return collision;
		}

		bool _intersects(AxisAlignedBoundingCuboid& a, AxisAlignedBoundingCuboid& b) {
			bool collision = true;

			if(a.getMinX() > b.getMaxX() || a.getMaxX() < b.getMinX()) {
				collision = false;
			} else if(a.getMinY() > b.getMaxY() || a.getMaxY() < b.getMinY()) {
				collision = false;
			} else if(a.getMinZ() > b.getMaxZ() || a.getMaxZ() < b.getMinZ()) {
				collision = false;
			}

			return collision;
		}
	}
}

#endif /* COLLISIONDETECTOR_HPP_ */
<commit_msg>more collision detection (Sphere&AABC)<commit_after>/*
 * CollisionDetector.hpp
 *
 *      @author: Marcel Veltman
 */

#ifndef COLLISIONDETECTOR_HPP_
#define COLLISIONDETECTOR_HPP_

#include <typeinfo>
#include <glm/glm.hpp>

#include "scene/collisiondetection/BoundingSphere.hpp"
#include "scene/collisiondetection/BoundingVolume.hpp"

namespace scene {

	namespace collisiondetection {

		/**
		 * Returns true when the bounding volumes collide.
		 */
		bool intersects(BoundingVolume& a, BoundingVolume& b) {
			bool collision = false;
			std::type_info typeA = typeid(a);
			std::type_info typeB = typeid(b);
			if(typeA == typeid(BoundingSphere) && typeB == typeid(BoundingSphere)) {
				BoundingSphere& bsa = static_cast<BoundingSphere&>(a);
				BoundingSphere& bsb = static_cast<BoundingSphere&>(b);
				collision = _intersects(bsa, bsb);
			} else if(typeA == typeid(AxisAlignedBoundingCuboid) && typeB == typeid(AxisAlignedBoundingCuboid)) {
				AxisAlignedBoundingCuboid& aabca = static_cast<AxisAlignedBoundingCuboid&>(a);
				AxisAlignedBoundingCuboid& aabcb = static_cast<AxisAlignedBoundingCuboid&>(b);
				collision = _intersects(aabca, aabcb);
			} else if(typeA == typeid(AxisAlignedBoundingCuboid) && typeB == typeid(BoundingSphere)) {
				AxisAlignedBoundingCuboid& cuboid = static_cast<AxisAlignedBoundingCuboid&>(a);
				BoundingSphere& sphere = static_cast<BoundingSphere&>(b);
				collision = _intersects(cuboid, sphere);
			} else if(typeA == typeid(BoundingSphere) && typeB == typeid(AxisAlignedBoundingCuboid)) {
				BoundingSphere& sphere = static_cast<BoundingSphere&>(a);
				AxisAlignedBoundingCuboid& cuboid = static_cast<AxisAlignedBoundingCuboid&>(b);
				collision = _intersects(cuboid, sphere);
			}
			return collision;
		}

		bool _intersects(BoundingSphere& a, BoundingSphere& b) {
			bool collision = false;

			float xSquare = (a.getLocation().x-b.getLocation().x)*(a.getLocation().x-b.getLocation().x);
			float ySquare = (a.getLocation().y-b.getLocation().y)*(a.getLocation().y-b.getLocation().y);
			float zSquare = (a.getLocation().z-b.getLocation().z)*(a.getLocation().z-b.getLocation().z);

			float centreDistance = std::sqrt(xSquare+ySquare+zSquare);
			collision = centreDistance <= (a.getRadius() + b.getRadius());

			return collision;
		}

		bool _intersects(AxisAlignedBoundingCuboid& a, AxisAlignedBoundingCuboid& b) {
			bool collision = true;

			if(a.getMinX() > b.getMaxX() || a.getMaxX() < b.getMinX()) {
				collision = false;
			} else if(a.getMinY() > b.getMaxY() || a.getMaxY() < b.getMinY()) {
				collision = false;
			} else if(a.getMinZ() > b.getMaxZ() || a.getMaxZ() < b.getMinZ()) {
				collision = false;
			}

			return collision;
		}

		bool _intersects(AxisAlignedBoundingCuboid& cuboid, BoundingSphere& sphere) {
			bool collision = false;
			glm::vec3 closestPoint;

			if(sphere.getLocation().x < cuboid.getMinX()) {
				closestPoint.x = cuboid.getMinX();
			} else if(sphere.getLocation().x > cuboid.getMaxX()) {
				closestPoint.x = cuboid.getMaxX();
			} else {
				closestPoint.x = sphere.getLocation().x;
			}

			if(sphere.getLocation().y < cuboid.getMinY()) {
				closestPoint.y = cuboid.getMinY();
			} else if(sphere.getLocation().y > cuboid.getMaxY()) {
				closestPoint.y = cuboid.getMaxY();
			} else {
				closestPoint.y = sphere.getLocation().y;
			}

			if(sphere.getLocation().z < cuboid.getMinZ()) {
				closestPoint.z = cuboid.getMinZ();
			} else if(sphere.getLocation().z > cuboid.getMaxZ()) {
				closestPoint.z = cuboid.getMaxZ();
			} else {
				closestPoint.z = sphere.getLocation().z;
			}

			float xSquare = closestPoint.x*closestPoint.x;
			float ySquare = closestPoint.y*closestPoint.y;
			float zSquare = closestPoint.z*closestPoint.z;
			float distanceToCentre = std::sqrt(xSquare+ySquare+zSquare);
			collision = distanceToCentre < sphere.getRadius();

			return collision;
		}
	}
}

#endif /* COLLISIONDETECTOR_HPP_ */
<|endoftext|>


<commit_before>#if  not defined( WRP_WONDERLAND_SUBSYSTEM_GLFW3 ) \
 and not defined( WRP_WONDERLAND_SUBSYSTEM_GLFW2 ) \
 and not defined( WRP_WONDERLAND_SUBSYSTEM_SDL2 ) \
 and not defined( WRP_WONDERLAND_SUBSYSTEM_SDL1 )
  #ifndef EMSCRIPTEN
    #define WRP_WONDERLAND_SUBSYSTEM_GLFW3
  #else
    #define WRP_WONDERLAND_SUBSYSTEM_GLFW2
  #endif
#endif

#include <boost/scope_exit.hpp>

#include "wonderland.subsystem.detail/key.hxx"
#include "wonderland.subsystem.detail/key_helper.hxx"
#include "wonderland.subsystem.detail/subsystem_base.hxx"

#ifdef WRP_WONDERLAND_SUBSYSTEM_GLFW3
  #include "wonderland.subsystem.detail/glfw3.hxx"
#elif defined(WRP_WONDERLAND_SUBSYSTEM_GLFW2)
  #include "wonderland.subsystem.detail/glfw2.hxx"
#elif defined(WRP_WONDERLAND_SUBSYSTEM_SDL2)
  #include "wonderland.subsystem.detail/sdl2.hxx"
#elif defined(WRP_WONDERLAND_SUBSYSTEM_SDL1)
  #include "wonderland.subsystem.detail/sdl1.hxx"
#endif
<commit_msg>fix up for GLFW>=2.7.8<commit_after>#if  not defined( WRP_WONDERLAND_SUBSYSTEM_GLFW3 ) \
 and not defined( WRP_WONDERLAND_SUBSYSTEM_GLFW2 ) \
 and not defined( WRP_WONDERLAND_SUBSYSTEM_SDL2 ) \
 and not defined( WRP_WONDERLAND_SUBSYSTEM_SDL1 )
  #ifndef EMSCRIPTEN
    #define WRP_WONDERLAND_SUBSYSTEM_GLFW3
  #else
    #define WRP_WONDERLAND_SUBSYSTEM_GLFW2
  #endif
#endif

#include <boost/scope_exit.hpp>

#include "wonderland.subsystem.detail/key.hxx"
#include "wonderland.subsystem.detail/key_helper.hxx"
#include "wonderland.subsystem.detail/subsystem_base.hxx"

#ifdef WRP_WONDERLAND_SUBSYSTEM_GLFW3
  #include "wonderland.subsystem.detail/glfw3.hxx"
#elif defined(WRP_WONDERLAND_SUBSYSTEM_GLFW2)
  #define GLFW_NO_GLU
  #include "wonderland.subsystem.detail/glfw2.hxx"
#elif defined(WRP_WONDERLAND_SUBSYSTEM_SDL2)
  #include "wonderland.subsystem.detail/sdl2.hxx"
#elif defined(WRP_WONDERLAND_SUBSYSTEM_SDL1)
  #include "wonderland.subsystem.detail/sdl1.hxx"
#endif
<|endoftext|>


<commit_before>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file stochastic_gradient_descent.hpp
 * \brief Stochastic Gradient Descent (SGD) Implementation for neural networks
 *
 * This implementations supports fully-connected layers, convolutional layers,
 * RBM layers, CRBM layers, transform layers and pooling layers.
 */

#pragma once

#include "cpp_utils/static_if.hpp"

#include "dll/trainer/sgd_context.hpp" //Context for SGD
#include "dll/util/batch.hpp"          // Create batches
#include "dll/util/checks.hpp"         // For NaN checks
#include "dll/util/timers.hpp"         // For auto_timer

namespace dll {

template <typename DBN>
struct sgd_trainer {
    using dbn_t     = DBN;
    using weight    = typename dbn_t::weight;
    using this_type = sgd_trainer<dbn_t>;

    static constexpr const auto layers     = dbn_t::layers;
    static constexpr const auto batch_size = dbn_t::batch_size;

    bool ae_training = false;

    dbn_t& dbn;

    /*!
     * \brief Indicates if the model is being trained as an auto-encoder (true) or not (false)
     */
    void set_autoencoder(bool ae){
        this->ae_training = ae;;
    }

    template<std::size_t Layer, typename Enable = void>
    struct input_layer_t {
        static constexpr const std::size_t L = Layer;
    };

    template<std::size_t Layer>
    struct input_layer_t<Layer, std::enable_if_t< decay_layer_traits<typename dbn_t::template layer_type<Layer>>::is_transform_layer() >> {
        static constexpr const std::size_t L = input_layer_t<Layer + 1>::L;
    };

    // Some Transform layers need to inherit dimensions from back

    template<typename L1, typename L2, cpp_enable_if(decay_layer_traits<L1>::is_transform_layer())>
    static void inherit_from_back(L1& l1, L2& l2){
        auto& ctx1 = l1.template get_sgd_context<dbn_t>();
        auto& ctx2 = l2.template get_sgd_context<dbn_t>();

        if (ctx1.errors.size() == 0) {
            ctx1.output = ctx2.input;
            ctx1.errors = ctx2.input;
            ctx1.input  = ctx2.input;
        }
    }

    template<typename L1, typename L2, cpp_disable_if(decay_layer_traits<L1>::is_transform_layer())>
    static void inherit_from_back(L1& /*l1*/, L2& /*l2*/){ }

    // Some Transform layers need to inherit dimensions from back

    template<typename L1, typename L2, cpp_enable_if(decay_layer_traits<L2>::is_transform_layer())>
    static void inherit_from_front(L1& l1, L2& l2){
        auto& ctx1 = l1.template get_sgd_context<dbn_t>();
        auto& ctx2 = l2.template get_sgd_context<dbn_t>();

        if (ctx2.errors.size() == 0) {
            ctx2.output = ctx1.output;
            ctx2.errors = ctx1.output;
            ctx2.input  = ctx1.output;
        }
    }

    template<typename L1, typename L2, cpp_disable_if(decay_layer_traits<L2>::is_transform_layer())>
    static void inherit_from_front(L1& /*l1*/, L2& /*l2*/){ }

    explicit sgd_trainer(dbn_t& dbn) : dbn(dbn) {
        // Initialize all the SGD contexts
        dbn.for_each_layer([](auto& layer) {
            layer.template init_sgd_context<dbn_t>();
        });

        // Inherit dimensions from back

        dbn.for_each_layer_rpair([](auto& l1, auto& l2) {
            constexpr bool l1_transform = decay_layer_traits<decltype(l1)>::is_transform_layer();
            constexpr bool l2_transform = decay_layer_traits<decltype(l2)>::is_transform_layer();

            if (l1_transform && (!l2_transform || l2.template get_sgd_context<dbn_t>().errors.size())) {
                this_type::inherit_from_back(l1, l2);
            }
        });

        // Inherit dimensions from front

        dbn.for_each_layer_pair([](auto& l1, auto& l2) {
            constexpr bool l2_transform = decay_layer_traits<decltype(l2)>::is_transform_layer();

            if (l2_transform) {
                this_type::inherit_from_front(l1, l2);
            }
        });
    }

    void init_training(std::size_t) {}

    template <typename D, typename It>
    void copy_inputs(D& dest, It first, It last) {
        std::size_t i = 0;

        while (first != last) {
            dest(i++) = *first++;
        }
    }

    template <typename D, typename It, cpp_enable_if(etl::decay_traits<D>::dimensions() == 2)>
    void copy_labels(D& dest, It first, It last) {
        //TODO How does that work in auto encoder mode ?

        std::size_t i = 0;

        while (first != last) {
            for (std::size_t l = 0; l < etl::dim<1>(dest); ++l) {
                dest(i, l) = (*first)[l];
            }
            ++i;
            ++first;
        }
    }

    template <typename D, typename It, cpp_enable_if(etl::decay_traits<D>::dimensions() == 4)>
    void copy_labels(D& dest, It first, It last) {
        //TODO How does that work in auto encoder mode ?

        std::size_t i = 0;

        while (first != last) {
            dest(i++) = *first++;
        }
    }

    // TODO: There are way too many copies going in this function

    template <typename Inputs, typename Labels, typename InputTransformer>
    std::pair<double, double> train_batch(std::size_t /*epoch*/, const Inputs& inputs, const Labels& labels, InputTransformer input_transformer) {
        dll::auto_timer timer("sgd::train_batch");

        // Ensure that the data batch and the label batch are of the same size
        cpp_assert(etl::dim<0>(inputs) == etl::dim<0>(labels), "Invalid sizes");

        const auto n = etl::dim<0>(inputs);

        decltype(auto) first_layer = dbn.template layer_get<0>();
        decltype(auto) first_ctx = first_layer.template get_sgd_context<dbn_t>();

        decltype(auto) last_layer = dbn.template layer_get<layers - 1>();
        decltype(auto) last_ctx = last_layer.template get_sgd_context<dbn_t>();

        const bool full_batch = etl::dim<0>(inputs) == etl::dim<0>(first_ctx.input);

        //Copy inputs into suitable data structure

        auto tilde_inputs = inputs;
        for(size_t i = 0; i < etl::dim<0>(tilde_inputs); ++i){
            input_transformer(tilde_inputs(i));
        }

        //Feedforward pass

        {
            dll::auto_timer timer("sgd::forward");

            if(cpp_unlikely(!full_batch)){
                first_ctx.input = 0;

                for (size_t i = 0; i < etl::dim<0>(inputs); ++i) {
                    first_ctx.input(i) = tilde_inputs(i);
                }
            } else {
                first_ctx.input = tilde_inputs;
            }

            first_layer.batch_activate_hidden(first_ctx.output, first_ctx.input);

            dbn.for_each_layer_pair([](auto& layer_1, auto& layer_2) {
                auto& ctx1 = layer_1.template get_sgd_context<dbn_t>();
                auto& ctx2 = layer_2.template get_sgd_context<dbn_t>();

                ctx2.input = ctx1.output;
                layer_2.batch_activate_hidden(ctx2.output, ctx2.input);
            });
        }

        //Compute the errors of the last layer

        if (cpp_unlikely(!full_batch)) {
            first_ctx.input = 0;

            for (size_t i = 0; i < etl::dim<0>(inputs); ++i) {
                last_ctx.errors(i) = labels(i) - last_ctx.output(i);
            }
        } else {
            last_ctx.errors = labels - last_ctx.output;
        }

        // Backpropagate the error

        {
            dll::auto_timer timer("sgd::backward");

            dbn.for_each_layer_rpair([](auto& r1, auto& r2) {
                auto& ctx1 = r1.template get_sgd_context<dbn_t>();
                auto& ctx2 = r2.template get_sgd_context<dbn_t>();

                r2.adapt_errors(ctx2);
                r2.backward_batch(ctx1.errors, ctx2);
                });

            first_layer.adapt_errors(first_ctx);
        }

        // Compute and apply the gradients

        {
            dll::auto_timer timer("sgd::grad");

            dbn.for_each_layer([this, n](auto& layer) {
                // Compute the gradients
                layer.compute_gradients(layer.template get_sgd_context<dbn_t>());

                // Apply the gradients
                this->apply_gradients(layer, n);
            });
        }

        // Compute error and loss

        double error = 0.0;
        double loss = 0.0;

        {
            dll::auto_timer timer("sgd::error");

            auto& out = last_ctx.output;

            if (cpp_unlikely(!full_batch)) {
                error = etl::mean(etl::abs(labels - slice(out, 0, etl::dim<0>(inputs))));

                if (ae_training) {
                    // Reconstruction Cross-Entropy Loss
                    loss = -sum((labels >> log(slice(out, 0, etl::dim<0>(inputs)))) + ((1.0 - labels) >> log(1 - slice(out, 0, etl::dim<0>(inputs))))) / double(n);
                } else {
                    // Cross-Entropy Loss
                    loss = -sum(log(slice(out, 0, etl::dim<0>(inputs))) >> labels) / double(n);
                }
            } else {
                error = etl::mean(etl::abs(labels - out));

                if (ae_training) {
                    // Reconstruction Cross-Entropy Loss
                    loss = -sum((labels >> log(out)) + ((1.0 - labels) >> log(1 - out))) / double(n);
                } else {
                    // Cross-Entropy Loss
                    loss = -sum(log(out) >> labels) / double(n);
                }
            }
        }

        return std::make_pair(error, loss);
    }

    template <typename L, cpp_enable_if(decay_layer_traits<L>::is_neural_layer())>
    void apply_gradients(L& layer, std::size_t n) {
        dll::auto_timer timer("sgd::apply_grad");

        auto& context = layer.template get_sgd_context<dbn_t>();

        //Update the gradients
        this->update_grad(layer.w, context.w_grad, w_decay(dbn_traits<dbn_t>::decay()), 0.0);
        this->update_grad(layer.b, context.b_grad, b_decay(dbn_traits<dbn_t>::decay()), 0.0);

        //Update with momentum and learning rate
        if (dbn_traits<dbn_t>::has_momentum()) {
            auto momentum = dbn.momentum;
            auto eps      = dbn.learning_rate;

            context.w_inc = momentum * context.w_inc + (eps / n) * context.w_grad;
            context.b_inc = momentum * context.b_inc + (eps / n) * context.b_grad;

            layer.w += context.w_inc;
            layer.b += context.b_inc;
        } else {
            auto eps = dbn.learning_rate;

            layer.w += (eps / n) * context.w_grad;
            layer.b += (eps / n) * context.b_grad;
        }

        nan_check_deep(layer.w);
        nan_check_deep(layer.b);
    }

    template <typename L, cpp_disable_if(decay_layer_traits<L>::is_neural_layer())>
    void apply_gradients(L&, std::size_t) {
        //Pooling and transform layers have no weights, therefore no
        //gradients
    }

    template <typename V, typename G>
    void update_grad(const V& value, G& grad, decay_type decay, double penalty) {
        if (decay == decay_type::L1) {
            grad = grad - dbn.l1_weight_cost * abs(value) - penalty;
        } else if (decay == decay_type::L2) {
            grad = grad - dbn.l2_weight_cost * value - penalty;
        } else if (decay == decay_type::L1L2) {
            grad = grad - dbn.l1_weight_cost * abs(value) - dbn.l2_weight_cost * value - penalty;
        } else {
            grad = grad - penalty;
        }
    }

    static std::string name() {
        return "Stochastic Gradient Descent";
    }
};

} //end of dll namespace
<commit_msg>Fix training for partial batches<commit_after>//=======================================================================
// Copyright (c) 2014-2017 Baptiste Wicht
// Distributed under the terms of the MIT License.
// (See accompanying file LICENSE or copy at
//  http://opensource.org/licenses/MIT)
//=======================================================================

/*!
 * \file stochastic_gradient_descent.hpp
 * \brief Stochastic Gradient Descent (SGD) Implementation for neural networks
 *
 * This implementations supports fully-connected layers, convolutional layers,
 * RBM layers, CRBM layers, transform layers and pooling layers.
 */

#pragma once

#include "cpp_utils/static_if.hpp"

#include "dll/trainer/sgd_context.hpp" //Context for SGD
#include "dll/util/batch.hpp"          // Create batches
#include "dll/util/checks.hpp"         // For NaN checks
#include "dll/util/timers.hpp"         // For auto_timer

namespace dll {

template <typename DBN>
struct sgd_trainer {
    using dbn_t     = DBN;
    using weight    = typename dbn_t::weight;
    using this_type = sgd_trainer<dbn_t>;

    static constexpr const auto layers     = dbn_t::layers;
    static constexpr const auto batch_size = dbn_t::batch_size;

    bool ae_training = false;

    dbn_t& dbn;

    /*!
     * \brief Indicates if the model is being trained as an auto-encoder (true) or not (false)
     */
    void set_autoencoder(bool ae){
        this->ae_training = ae;;
    }

    template<std::size_t Layer, typename Enable = void>
    struct input_layer_t {
        static constexpr const std::size_t L = Layer;
    };

    template<std::size_t Layer>
    struct input_layer_t<Layer, std::enable_if_t< decay_layer_traits<typename dbn_t::template layer_type<Layer>>::is_transform_layer() >> {
        static constexpr const std::size_t L = input_layer_t<Layer + 1>::L;
    };

    // Some Transform layers need to inherit dimensions from back

    template<typename L1, typename L2, cpp_enable_if(decay_layer_traits<L1>::is_transform_layer())>
    static void inherit_from_back(L1& l1, L2& l2){
        auto& ctx1 = l1.template get_sgd_context<dbn_t>();
        auto& ctx2 = l2.template get_sgd_context<dbn_t>();

        if (ctx1.errors.size() == 0) {
            ctx1.output = ctx2.input;
            ctx1.errors = ctx2.input;
            ctx1.input  = ctx2.input;
        }
    }

    template<typename L1, typename L2, cpp_disable_if(decay_layer_traits<L1>::is_transform_layer())>
    static void inherit_from_back(L1& /*l1*/, L2& /*l2*/){ }

    // Some Transform layers need to inherit dimensions from back

    template<typename L1, typename L2, cpp_enable_if(decay_layer_traits<L2>::is_transform_layer())>
    static void inherit_from_front(L1& l1, L2& l2){
        auto& ctx1 = l1.template get_sgd_context<dbn_t>();
        auto& ctx2 = l2.template get_sgd_context<dbn_t>();

        if (ctx2.errors.size() == 0) {
            ctx2.output = ctx1.output;
            ctx2.errors = ctx1.output;
            ctx2.input  = ctx1.output;
        }
    }

    template<typename L1, typename L2, cpp_disable_if(decay_layer_traits<L2>::is_transform_layer())>
    static void inherit_from_front(L1& /*l1*/, L2& /*l2*/){ }

    explicit sgd_trainer(dbn_t& dbn) : dbn(dbn) {
        // Initialize all the SGD contexts
        dbn.for_each_layer([](auto& layer) {
            layer.template init_sgd_context<dbn_t>();
        });

        // Inherit dimensions from back

        dbn.for_each_layer_rpair([](auto& l1, auto& l2) {
            constexpr bool l1_transform = decay_layer_traits<decltype(l1)>::is_transform_layer();
            constexpr bool l2_transform = decay_layer_traits<decltype(l2)>::is_transform_layer();

            if (l1_transform && (!l2_transform || l2.template get_sgd_context<dbn_t>().errors.size())) {
                this_type::inherit_from_back(l1, l2);
            }
        });

        // Inherit dimensions from front

        dbn.for_each_layer_pair([](auto& l1, auto& l2) {
            constexpr bool l2_transform = decay_layer_traits<decltype(l2)>::is_transform_layer();

            if (l2_transform) {
                this_type::inherit_from_front(l1, l2);
            }
        });
    }

    void init_training(std::size_t) {}

    template <typename D, typename It>
    void copy_inputs(D& dest, It first, It last) {
        std::size_t i = 0;

        while (first != last) {
            dest(i++) = *first++;
        }
    }

    template <typename D, typename It, cpp_enable_if(etl::decay_traits<D>::dimensions() == 2)>
    void copy_labels(D& dest, It first, It last) {
        //TODO How does that work in auto encoder mode ?

        std::size_t i = 0;

        while (first != last) {
            for (std::size_t l = 0; l < etl::dim<1>(dest); ++l) {
                dest(i, l) = (*first)[l];
            }
            ++i;
            ++first;
        }
    }

    template <typename D, typename It, cpp_enable_if(etl::decay_traits<D>::dimensions() == 4)>
    void copy_labels(D& dest, It first, It last) {
        //TODO How does that work in auto encoder mode ?

        std::size_t i = 0;

        while (first != last) {
            dest(i++) = *first++;
        }
    }

    // TODO: There are way too many copies going in this function

    template <typename Inputs, typename Labels, typename InputTransformer>
    std::pair<double, double> train_batch(std::size_t /*epoch*/, const Inputs& inputs, const Labels& labels, InputTransformer input_transformer) {
        dll::auto_timer timer("sgd::train_batch");

        // Ensure that the data batch and the label batch are of the same size
        cpp_assert(etl::dim<0>(inputs) == etl::dim<0>(labels), "Invalid sizes");

        const auto n = etl::dim<0>(inputs);

        decltype(auto) first_layer = dbn.template layer_get<0>();
        decltype(auto) first_ctx = first_layer.template get_sgd_context<dbn_t>();

        decltype(auto) last_layer = dbn.template layer_get<layers - 1>();
        decltype(auto) last_ctx = last_layer.template get_sgd_context<dbn_t>();

        const bool full_batch = etl::dim<0>(inputs) == etl::dim<0>(first_ctx.input);

        //Copy inputs into suitable data structure

        auto tilde_inputs = inputs;
        for(size_t i = 0; i < etl::dim<0>(tilde_inputs); ++i){
            input_transformer(tilde_inputs(i));
        }

        //Feedforward pass

        {
            dll::auto_timer timer("sgd::forward");

            if(cpp_unlikely(!full_batch)){
                first_ctx.input  = 0;
                first_ctx.output = 0;

                for (size_t i = 0; i < etl::dim<0>(inputs); ++i) {
                    first_ctx.input(i) = tilde_inputs(i);
                }
            } else {
                first_ctx.input = tilde_inputs;
            }

            first_layer.batch_activate_hidden(first_ctx.output, first_ctx.input);

            dbn.for_each_layer_pair([](auto& layer_1, auto& layer_2) {
                auto& ctx1 = layer_1.template get_sgd_context<dbn_t>();
                auto& ctx2 = layer_2.template get_sgd_context<dbn_t>();

                ctx2.input = ctx1.output;
                layer_2.batch_activate_hidden(ctx2.output, ctx2.input);
            });
        }

        //Compute the errors of the last layer

        if (cpp_unlikely(!full_batch)) {
            first_ctx.input = 0;
            last_ctx.errors = 0;

            for (size_t i = 0; i < etl::dim<0>(inputs); ++i) {
                last_ctx.errors(i) = labels(i) - last_ctx.output(i);
            }
        } else {
            last_ctx.errors = labels - last_ctx.output;
        }

        // Backpropagate the error

        {
            dll::auto_timer timer("sgd::backward");

            dbn.for_each_layer_rpair([](auto& r1, auto& r2) {
                auto& ctx1 = r1.template get_sgd_context<dbn_t>();
                auto& ctx2 = r2.template get_sgd_context<dbn_t>();

                r2.adapt_errors(ctx2);
                r2.backward_batch(ctx1.errors, ctx2);
                });

            first_layer.adapt_errors(first_ctx);
        }

        // Compute and apply the gradients

        {
            dll::auto_timer timer("sgd::grad");

            dbn.for_each_layer([this, n](auto& layer) {
                // Compute the gradients
                layer.compute_gradients(layer.template get_sgd_context<dbn_t>());

                // Apply the gradients
                this->apply_gradients(layer, n);
            });
        }

        // Compute error and loss

        double error = 0.0;
        double loss = 0.0;

        {
            dll::auto_timer timer("sgd::error");

            auto& out = last_ctx.output;

            if (cpp_unlikely(!full_batch)) {
                error = etl::mean(etl::abs(labels - slice(out, 0, etl::dim<0>(inputs))));

                if (ae_training) {
                    // Reconstruction Cross-Entropy Loss
                    loss = -sum((labels >> log(slice(out, 0, etl::dim<0>(inputs)))) + ((1.0 - labels) >> log(1 - slice(out, 0, etl::dim<0>(inputs))))) / double(n);
                } else {
                    // Cross-Entropy Loss
                    loss = -sum(log(slice(out, 0, etl::dim<0>(inputs))) >> labels) / double(n);
                }
            } else {
                error = etl::mean(etl::abs(labels - out));

                if (ae_training) {
                    // Reconstruction Cross-Entropy Loss
                    loss = -sum((labels >> log(out)) + ((1.0 - labels) >> log(1 - out))) / double(n);
                } else {
                    // Cross-Entropy Loss
                    loss = -sum(log(out) >> labels) / double(n);
                }
            }
        }

        return std::make_pair(error, loss);
    }

    template <typename L, cpp_enable_if(decay_layer_traits<L>::is_neural_layer())>
    void apply_gradients(L& layer, std::size_t n) {
        dll::auto_timer timer("sgd::apply_grad");

        auto& context = layer.template get_sgd_context<dbn_t>();

        //Update the gradients
        this->update_grad(layer.w, context.w_grad, w_decay(dbn_traits<dbn_t>::decay()), 0.0);
        this->update_grad(layer.b, context.b_grad, b_decay(dbn_traits<dbn_t>::decay()), 0.0);

        //Update with momentum and learning rate
        if (dbn_traits<dbn_t>::has_momentum()) {
            auto momentum = dbn.momentum;
            auto eps      = dbn.learning_rate;

            context.w_inc = momentum * context.w_inc + (eps / n) * context.w_grad;
            context.b_inc = momentum * context.b_inc + (eps / n) * context.b_grad;

            layer.w += context.w_inc;
            layer.b += context.b_inc;
        } else {
            auto eps = dbn.learning_rate;

            layer.w += (eps / n) * context.w_grad;
            layer.b += (eps / n) * context.b_grad;
        }

        nan_check_deep(layer.w);
        nan_check_deep(layer.b);
    }

    template <typename L, cpp_disable_if(decay_layer_traits<L>::is_neural_layer())>
    void apply_gradients(L&, std::size_t) {
        //Pooling and transform layers have no weights, therefore no
        //gradients
    }

    template <typename V, typename G>
    void update_grad(const V& value, G& grad, decay_type decay, double penalty) {
        if (decay == decay_type::L1) {
            grad = grad - dbn.l1_weight_cost * abs(value) - penalty;
        } else if (decay == decay_type::L2) {
            grad = grad - dbn.l2_weight_cost * value - penalty;
        } else if (decay == decay_type::L1L2) {
            grad = grad - dbn.l1_weight_cost * abs(value) - dbn.l2_weight_cost * value - penalty;
        } else {
            grad = grad - penalty;
        }
    }

    static std::string name() {
        return "Stochastic Gradient Descent";
    }
};

} //end of dll namespace
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_memdiag.C $  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_memdiag.C
/// @brief Mainstore pattern testing
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP FW Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include "p9_mss_memdiag.H"

using fapi2::TARGET_TYPE_MCBIST;

extern "C"
{
///
/// @brief Pattern test the DRAM
/// @param[in] i_target, the McBIST of the ports of the dram you're training
/// @return FAPI2_RC_SUCCESS iff ok
///
    fapi2::ReturnCode p9_mss_memdiag( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
    {
        FAPI_INF("Start memdiag");
        FAPI_INF("End memdiag");
        return fapi2::FAPI2_RC_SUCCESS;
    }
}
<commit_msg>Initial commit of memory subsystem<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: src/import/chips/p9/procedures/hwp/memory/p9_mss_memdiag.C $  */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2015,2019                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* Licensed under the Apache License, Version 2.0 (the "License");        */
/* you may not use this file except in compliance with the License.       */
/* You may obtain a copy of the License at                                */
/*                                                                        */
/*     http://www.apache.org/licenses/LICENSE-2.0                         */
/*                                                                        */
/* Unless required by applicable law or agreed to in writing, software    */
/* distributed under the License is distributed on an "AS IS" BASIS,      */
/* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or        */
/* implied. See the License for the specific language governing           */
/* permissions and limitations under the License.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */

///
/// @file p9_mss_memdiag.C
/// @brief Mainstore pattern testing
///
// *HWP HWP Owner: Brian Silver <bsilver@us.ibm.com>
// *HWP HWP Backup: Andre Marin <aamarin@us.ibm.com>
// *HWP Team: Memory
// *HWP Level: 1
// *HWP Consumed by: FSP:HB

#include <fapi2.H>
#include "p9_mss_memdiag.H"

using fapi2::TARGET_TYPE_MCBIST;

extern "C"
{
///
/// @brief Pattern test the DRAM
/// @param[in] i_target, the McBIST of the ports of the dram you're training
/// @return FAPI2_RC_SUCCESS iff ok
///
    fapi2::ReturnCode p9_mss_memdiag( const fapi2::Target<TARGET_TYPE_MCBIST>& i_target )
    {
        FAPI_INF("Start memdiag");
        FAPI_INF("End memdiag");
        return fapi2::FAPI2_RC_SUCCESS;
    }
}
<|endoftext|>


<commit_before><commit_msg>Run tests faster.<commit_after><|endoftext|>


<commit_before>/*

Copyright (c) 2003, Magnus Jonsson
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.

*/

#ifndef TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED
#define TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED

#include <map>
#include <utility>

#include <boost/shared_ptr.hpp>

#include "libtorrent/resource_request.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/size_type.hpp"

namespace libtorrent
{

	int saturated_add(int a, int b);

	namespace aux
	{
		// give num_resources to r,
		// return how how many were actually accepted.
		inline int give(resource_request& r, int num_resources)
		{
			assert(num_resources >= 0);
			assert(r.given <= r.max);

			int accepted = std::min(num_resources, r.max - r.given);
			assert(accepted >= 0);

			r.given += accepted;
			assert(r.given <= r.max);

			return accepted;
		}

#ifndef NDEBUG

		template<class It, class T>
		class allocate_resources_contract_check
		{
			int m_resources;
			It m_start;
			It m_end;
			resource_request T::* m_res;

		public:
			allocate_resources_contract_check(
				int resources
				, It start
				, It end
				, resource_request T::* res)
				: m_resources(resources)
				, m_start(start)
				, m_end(end)
				, m_res(res)
			{
				assert(m_resources >= 0);
				for (It i = m_start, end(m_end); i != end; ++i)
				{
					assert(((*i).*m_res).max >= 0);
					assert(((*i).*m_res).given >= 0);
				}
			}

			~allocate_resources_contract_check()
			{
				int sum_given = 0;
				int sum_max = 0;
				int sum_min = 0;
				for (It i = m_start, end(m_end); i != end; ++i)
				{
					assert(((*i).*m_res).max >= 0);
					assert(((*i).*m_res).min >= 0);
					assert(((*i).*m_res).max >= ((*i).*m_res).min);
					assert(((*i).*m_res).given >= 0);
					assert(((*i).*m_res).given <= ((*i).*m_res).max);

					sum_given = saturated_add(sum_given, ((*i).*m_res).given);
					sum_max = saturated_add(sum_max, ((*i).*m_res).max);
					sum_min = saturated_add(sum_min, ((*i).*m_res).min);
				}
				assert(sum_given == std::min(std::max(m_resources, sum_min), sum_max));
			}
		};

#endif

		template<class It, class T>
		void allocate_resources_impl(
			int resources
			, It start
			, It end
			, resource_request T::* res)
		{
			assert(resources >= 0);
	#ifndef NDEBUG
			allocate_resources_contract_check<It, T> contract_check(
				resources
				, start
				, end
				, res);
	#endif

			if (resources == resource_request::inf)
			{
				// No competition for resources.
				// Just give everyone what they want.
				for (It i = start; i != end; ++i)
				{
					((*i).*res).given = ((*i).*res).max;
				}
				return;
			}

			// Resources are scarce

			int sum_max = 0;
			int sum_min = 0;
			for (It i = start; i != end; ++i)
			{
				sum_max = saturated_add(sum_max, ((*i).*res).max);
				assert(((*i).*res).min < resource_request::inf);
				assert(((*i).*res).min >= 0);
				assert(((*i).*res).min <= ((*i).*res).max);
				sum_min += ((*i).*res).min;
				((*i).*res).given = ((*i).*res).min;
			}

			if (resources == 0 || sum_max == 0)
				return;

			resources = std::max(resources, sum_min);
			int resources_to_distribute = std::min(resources, sum_max) - sum_min;
			assert(resources_to_distribute >= 0);
#ifndef NDEBUG
			int prev_resources_to_distribute = resources_to_distribute;
#endif
			while (resources_to_distribute > 0)
			{
				size_type total_used = 0;
				size_type max_used = 0;
				for (It i = start; i != end; ++i)
				{
					resource_request& r = (*i).*res;
					if(r.given == r.max) continue;

					assert(r.given < r.max);

					max_used = std::max(max_used, (size_type)r.used + 1);
					total_used += (size_type)r.used + 1;
				}

				size_type kNumer = resources_to_distribute;
				size_type kDenom = total_used;
				assert(kNumer >= 0);
				assert(kDenom >= 0);
				assert(kNumer <= std::numeric_limits<int>::max());
				assert(total_used < std::numeric_limits<int>::max());

				if (kNumer * max_used <= kDenom)
				{
					kNumer = 1;
					kDenom = max_used;
					assert(kDenom >= 0);
					assert(kDenom <= std::numeric_limits<int>::max());
				}

				for (It i = start; i != end && resources_to_distribute > 0; ++i)
				{
					resource_request& r = (*i).*res;
					if (r.given == r.max) continue;

					assert(r.given < r.max);

					size_type used = (size_type)r.used + 1;
					if (used < 1) used = 1;
					size_type to_give = used * kNumer / kDenom;
					if (to_give > resources_to_distribute)
						to_give = resources_to_distribute;
					assert(to_give >= 0);
					assert(to_give <= resources_to_distribute);
					resources_to_distribute -= give(r, (int)to_give);
					assert(resources_to_distribute >= 0);
				}

				assert(resources_to_distribute >= 0);
				assert(resources_to_distribute < prev_resources_to_distribute);
#ifndef NDEBUG
				prev_resources_to_distribute = resources_to_distribute;
#endif
			}
		}

	} // namespace libtorrent::aux
}

#endif
<commit_msg>added msvc workarounds<commit_after>/*

Copyright (c) 2003, Magnus Jonsson
All rights reserved.

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

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * 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.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT OWNER 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.

*/

#ifndef TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED
#define TORRENT_ALLOCATE_RESOURCES_IMPL_HPP_INCLUDED

#include <map>
#include <utility>

#include <boost/shared_ptr.hpp>

#include "libtorrent/resource_request.hpp"
#include "libtorrent/peer_id.hpp"
#include "libtorrent/socket.hpp"
#include "libtorrent/size_type.hpp"

#ifdef min
#undef min
#endif

#ifdef max
#undef max
#endif

namespace libtorrent
{

	int saturated_add(int a, int b);

	namespace aux
	{
		// give num_resources to r,
		// return how how many were actually accepted.
		inline int give(resource_request& r, int num_resources)
		{
			assert(num_resources >= 0);
			assert(r.given <= r.max);

			int accepted = (std::min)(num_resources, r.max - r.given);
			assert(accepted >= 0);

			r.given += accepted;
			assert(r.given <= r.max);

			return accepted;
		}

#ifndef NDEBUG

		template<class It, class T>
		class allocate_resources_contract_check
		{
			int m_resources;
			It m_start;
			It m_end;
			resource_request T::* m_res;

		public:
			allocate_resources_contract_check(
				int resources
				, It start
				, It end
				, resource_request T::* res)
				: m_resources(resources)
				, m_start(start)
				, m_end(end)
				, m_res(res)
			{
				assert(m_resources >= 0);
				for (It i = m_start, end(m_end); i != end; ++i)
				{
					assert(((*i).*m_res).max >= 0);
					assert(((*i).*m_res).given >= 0);
				}
			}

			~allocate_resources_contract_check()
			{
				int sum_given = 0;
				int sum_max = 0;
				int sum_min = 0;
				for (It i = m_start, end(m_end); i != end; ++i)
				{
					assert(((*i).*m_res).max >= 0);
					assert(((*i).*m_res).min >= 0);
					assert(((*i).*m_res).max >= ((*i).*m_res).min);
					assert(((*i).*m_res).given >= 0);
					assert(((*i).*m_res).given <= ((*i).*m_res).max);

					sum_given = saturated_add(sum_given, ((*i).*m_res).given);
					sum_max = saturated_add(sum_max, ((*i).*m_res).max);
					sum_min = saturated_add(sum_min, ((*i).*m_res).min);
				}
				assert(sum_given == (std::min)(std::max(m_resources, sum_min), sum_max));
			}
		};

#endif

		template<class It, class T>
		void allocate_resources_impl(
			int resources
			, It start
			, It end
			, resource_request T::* res)
		{
			assert(resources >= 0);
	#ifndef NDEBUG
			allocate_resources_contract_check<It, T> contract_check(
				resources
				, start
				, end
				, res);
	#endif

			if (resources == resource_request::inf)
			{
				// No competition for resources.
				// Just give everyone what they want.
				for (It i = start; i != end; ++i)
				{
					((*i).*res).given = ((*i).*res).max;
				}
				return;
			}

			// Resources are scarce

			int sum_max = 0;
			int sum_min = 0;
			for (It i = start; i != end; ++i)
			{
				sum_max = saturated_add(sum_max, ((*i).*res).max);
				assert(((*i).*res).min < resource_request::inf);
				assert(((*i).*res).min >= 0);
				assert(((*i).*res).min <= ((*i).*res).max);
				sum_min += ((*i).*res).min;
				((*i).*res).given = ((*i).*res).min;
			}

			if (resources == 0 || sum_max == 0)
				return;

			resources = (std::max)(resources, sum_min);
			int resources_to_distribute = (std::min)(resources, sum_max) - sum_min;
			assert(resources_to_distribute >= 0);
#ifndef NDEBUG
			int prev_resources_to_distribute = resources_to_distribute;
#endif
			while (resources_to_distribute > 0)
			{
				size_type total_used = 0;
				size_type max_used = 0;
				for (It i = start; i != end; ++i)
				{
					resource_request& r = (*i).*res;
					if(r.given == r.max) continue;

					assert(r.given < r.max);

					max_used = (std::max)(max_used, (size_type)r.used + 1);
					total_used += (size_type)r.used + 1;
				}

				size_type kNumer = resources_to_distribute;
				size_type kDenom = total_used;
				assert(kNumer >= 0);
				assert(kDenom >= 0);
				assert(kNumer <= (std::numeric_limits<int>::max)());
				assert(total_used < (std::numeric_limits<int>::max)());

				if (kNumer * max_used <= kDenom)
				{
					kNumer = 1;
					kDenom = max_used;
					assert(kDenom >= 0);
					assert(kDenom <= (std::numeric_limits<int>::max)());
				}

				for (It i = start; i != end && resources_to_distribute > 0; ++i)
				{
					resource_request& r = (*i).*res;
					if (r.given == r.max) continue;

					assert(r.given < r.max);

					size_type used = (size_type)r.used + 1;
					if (used < 1) used = 1;
					size_type to_give = used * kNumer / kDenom;
					if (to_give > resources_to_distribute)
						to_give = resources_to_distribute;
					assert(to_give >= 0);
					assert(to_give <= resources_to_distribute);
					resources_to_distribute -= give(r, (int)to_give);
					assert(resources_to_distribute >= 0);
				}

				assert(resources_to_distribute >= 0);
				assert(resources_to_distribute < prev_resources_to_distribute);
#ifndef NDEBUG
				prev_resources_to_distribute = resources_to_distribute;
#endif
			}
		}

	} // namespace libtorrent::aux
}

#endif
<|endoftext|>