<commit_before>/*
 * #%L
 * %%
 * Copyright (C) 2018 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */
#include <memory>
#include <string>

#include "tests/utils/Gtest.h"
#include "tests/utils/Gmock.h"

#include "joynr/Logger.h"
#include "joynr/exceptions/SubscriptionException.h"
#include "joynr/Future.h"
#include "joynr/SingleThreadedIOService.h"
#include "joynr/UnicastSubscriptionCallback.h"
#include "joynr/MulticastSubscriptionCallback.h"
#include "joynr/SubscriptionPublication.h"
#include "joynr/SubscriptionReply.h"
#include "tests/JoynrTest.h"
#include "tests/mock/MockSubscriptionManager.h"
#include "tests/mock/MockSubscriptionListener.h"
#include "tests/mock/MockMessageRouter.h"

using namespace joynr;
using namespace testing;

template <typename SubscriptionCallbackType>
class SubscriptionCallbackTest : public testing::Test
{
public:
    SubscriptionCallbackTest()
            : subscriptionId("testSubscriptionId"),
              singleThreadIOService(),
              mockMessageRouter(
                      std::make_shared<MockMessageRouter>(singleThreadIOService.getIOService())),
              mockSubscriptionManager(std::make_shared<MockSubscriptionManager>(
                      singleThreadIOService.getIOService(),
                      mockMessageRouter)),
              subscriptionIdFuture(std::make_shared<Future<std::string>>()),
              mockSubscriptionListener(
                      std::make_shared<MockSubscriptionListenerOneType<std::string>>()),
              subscriptionCallback(subscriptionId,
                                   subscriptionIdFuture,
                                   mockSubscriptionManager,
                                   nullptr)
    {
        ON_CALL(*mockSubscriptionManager, getSubscriptionListener(subscriptionId))
                .WillByDefault(Return(mockSubscriptionListener));
        ON_CALL(*mockSubscriptionManager, getMulticastSubscriptionListeners(subscriptionId))
                .WillByDefault(
                        Return(std::forward_list<std::shared_ptr<joynr::ISubscriptionListenerBase>>{
                                mockSubscriptionListener}));
    }

protected:
    const std::string subscriptionId;
    SingleThreadedIOService singleThreadIOService;
    std::shared_ptr<MockMessageRouter> mockMessageRouter;
    std::shared_ptr<MockSubscriptionManager> mockSubscriptionManager;
    std::shared_ptr<Future<std::string>> subscriptionIdFuture;
    std::shared_ptr<MockSubscriptionListenerOneType<std::string>> mockSubscriptionListener;

    SubscriptionCallbackType subscriptionCallback;
};

typedef ::testing::Types<MulticastSubscriptionCallback<std::string>,
                         UnicastSubscriptionCallback<std::string>> SubscriptionCallbackTypes;

TYPED_TEST_SUITE(SubscriptionCallbackTest, SubscriptionCallbackTypes,);

TYPED_TEST(SubscriptionCallbackTest, forwardSubscriptionReplyToFutureAndListener)
{
    SubscriptionReply reply;
    reply.setSubscriptionId(this->subscriptionId);

    EXPECT_CALL(*(this->mockSubscriptionListener), onSubscribed(this->subscriptionId));

    this->subscriptionCallback.execute(reply);

    std::string subscriptionIdFromFuture;
    this->subscriptionIdFuture->get(100, subscriptionIdFromFuture);
    EXPECT_EQ(subscriptionIdFromFuture, this->subscriptionId);
}

TYPED_TEST(SubscriptionCallbackTest, forwardSubscriptionExceptionToFutureAndListener)
{
    SubscriptionReply reply;
    reply.setSubscriptionId(this->subscriptionId);
    auto expectedException =
            std::make_shared<exceptions::SubscriptionException>(this->subscriptionId);
    reply.setError(expectedException);

    EXPECT_CALL(*(this->mockSubscriptionManager), unregisterSubscription(this->subscriptionId));
    EXPECT_CALL(*(this->mockSubscriptionListener), onError(*expectedException)).Times(1);
    EXPECT_CALL(*(this->mockSubscriptionListener), onReceive(_)).Times(0);

    this->subscriptionCallback.execute(reply);

    try {
        std::string subscriptionIdFromFuture;
        this->subscriptionIdFuture->get(100, subscriptionIdFromFuture);
        ADD_FAILURE() << "expected SubscriptionException";
    } catch (const exceptions::SubscriptionException& error) {
        EXPECT_EQ(error, *expectedException);
    }
}

TYPED_TEST(SubscriptionCallbackTest, forwardSubscriptionPublicationToListener)
{
    const std::string response = "testResponse";
    SubscriptionPublication publication;
    publication.setSubscriptionId(this->subscriptionId);
    publication.setResponse(response);

    EXPECT_CALL(*(this->mockSubscriptionListener), onError(_)).Times(0);
    EXPECT_CALL(*(this->mockSubscriptionListener), onReceive(response)).Times(1);

    this->subscriptionCallback.execute(std::move(publication));
}

TYPED_TEST(SubscriptionCallbackTest, forwardSubscriptionPublicationErrorToListener)
{
    auto error = std::make_shared<exceptions::ProviderRuntimeException>("testException");
    SubscriptionPublication publication;
    publication.setSubscriptionId(this->subscriptionId);
    publication.setError(error);

    EXPECT_CALL(*(this->mockSubscriptionListener), onError(*error)).Times(1);
    EXPECT_CALL(*(this->mockSubscriptionListener), onReceive(_)).Times(0);

    this->subscriptionCallback.execute(std::move(publication));
}
<commit_msg>[C++] Fix UBSAN errors<commit_after>/*
 * #%L
 * %%
 * Copyright (C) 2018 BMW Car IT GmbH
 * %%
 * 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.
 * #L%
 */
#include <memory>
#include <string>

#include "tests/utils/Gtest.h"
#include "tests/utils/Gmock.h"

#include "joynr/Future.h"
#include "joynr/Logger.h"
#include "joynr/MulticastPublication.h"
#include "joynr/MulticastSubscriptionCallback.h"
#include "joynr/SingleThreadedIOService.h"
#include "joynr/SubscriptionReply.h"
#include "joynr/UnicastSubscriptionCallback.h"
#include "joynr/exceptions/SubscriptionException.h"
#include "tests/JoynrTest.h"
#include "tests/mock/MockMessageRouter.h"
#include "tests/mock/MockSubscriptionListener.h"
#include "tests/mock/MockSubscriptionManager.h"

using namespace joynr;
using namespace testing;

template <typename SubscriptionCallbackType>
class SubscriptionCallbackTest : public testing::Test
{
public:
    SubscriptionCallbackTest()
            : subscriptionId("testSubscriptionId"),
              singleThreadIOService(),
              mockMessageRouter(
                      std::make_shared<MockMessageRouter>(singleThreadIOService.getIOService())),
              mockSubscriptionManager(std::make_shared<MockSubscriptionManager>(
                      singleThreadIOService.getIOService(),
                      mockMessageRouter)),
              subscriptionIdFuture(std::make_shared<Future<std::string>>()),
              mockSubscriptionListener(
                      std::make_shared<MockSubscriptionListenerOneType<std::string>>()),
              subscriptionCallback(subscriptionId,
                                   subscriptionIdFuture,
                                   mockSubscriptionManager,
                                   nullptr)
    {
        ON_CALL(*mockSubscriptionManager, getSubscriptionListener(subscriptionId))
                .WillByDefault(Return(mockSubscriptionListener));
        ON_CALL(*mockSubscriptionManager, getMulticastSubscriptionListeners(subscriptionId))
                .WillByDefault(
                        Return(std::forward_list<std::shared_ptr<joynr::ISubscriptionListenerBase>>{
                                mockSubscriptionListener}));
    }

protected:
    const std::string subscriptionId;
    SingleThreadedIOService singleThreadIOService;
    std::shared_ptr<MockMessageRouter> mockMessageRouter;
    std::shared_ptr<MockSubscriptionManager> mockSubscriptionManager;
    std::shared_ptr<Future<std::string>> subscriptionIdFuture;
    std::shared_ptr<MockSubscriptionListenerOneType<std::string>> mockSubscriptionListener;

    SubscriptionCallbackType subscriptionCallback;
};

typedef ::testing::Types<MulticastSubscriptionCallback<std::string>,
                         UnicastSubscriptionCallback<std::string>> SubscriptionCallbackTypes;

TYPED_TEST_SUITE(SubscriptionCallbackTest, SubscriptionCallbackTypes,);

TYPED_TEST(SubscriptionCallbackTest, forwardSubscriptionReplyToFutureAndListener)
{
    SubscriptionReply reply;
    reply.setSubscriptionId(this->subscriptionId);

    EXPECT_CALL(*(this->mockSubscriptionListener), onSubscribed(this->subscriptionId));

    this->subscriptionCallback.execute(reply);

    std::string subscriptionIdFromFuture;
    this->subscriptionIdFuture->get(100, subscriptionIdFromFuture);
    EXPECT_EQ(subscriptionIdFromFuture, this->subscriptionId);
}

TYPED_TEST(SubscriptionCallbackTest, forwardSubscriptionExceptionToFutureAndListener)
{
    SubscriptionReply reply;
    reply.setSubscriptionId(this->subscriptionId);
    auto expectedException =
            std::make_shared<exceptions::SubscriptionException>(this->subscriptionId);
    reply.setError(expectedException);

    EXPECT_CALL(*(this->mockSubscriptionManager), unregisterSubscription(this->subscriptionId));
    EXPECT_CALL(*(this->mockSubscriptionListener), onError(*expectedException)).Times(1);
    EXPECT_CALL(*(this->mockSubscriptionListener), onReceive(_)).Times(0);

    this->subscriptionCallback.execute(reply);

    try {
        std::string subscriptionIdFromFuture;
        this->subscriptionIdFuture->get(100, subscriptionIdFromFuture);
        ADD_FAILURE() << "expected SubscriptionException";
    } catch (const exceptions::SubscriptionException& error) {
        EXPECT_EQ(error, *expectedException);
    }
}

TYPED_TEST(SubscriptionCallbackTest, forwardPublicationToListener)
{
    const std::string response = "testResponse";

    EXPECT_CALL(*(this->mockSubscriptionListener), onError(_)).Times(0);
    EXPECT_CALL(*(this->mockSubscriptionListener), onReceive(response)).Times(1);

    if (typeid(this->subscriptionCallback) == typeid(MulticastSubscriptionCallback<std::string>)) {
        MulticastPublication publication;
        publication.setMulticastId(this->subscriptionId);
        publication.setResponse(response);
        this->subscriptionCallback.execute(std::move(publication));
    } else if (typeid(this->subscriptionCallback) ==
               typeid(UnicastSubscriptionCallback<std::string>)) {
        BasePublication publication;
        publication.setResponse(response);
        this->subscriptionCallback.execute(std::move(publication));
    } else {
        FAIL() << "Could not evaluate type";
    }
}

TYPED_TEST(SubscriptionCallbackTest, forwardPublicationErrorToListener)
{
    auto error = std::make_shared<exceptions::ProviderRuntimeException>("testException");

    EXPECT_CALL(*(this->mockSubscriptionListener), onError(*error)).Times(1);
    EXPECT_CALL(*(this->mockSubscriptionListener), onReceive(_)).Times(0);

    if (typeid(this->subscriptionCallback) == typeid(MulticastSubscriptionCallback<std::string>)) {
        MulticastPublication publication;
        publication.setMulticastId(this->subscriptionId);
        publication.setError(error);
        this->subscriptionCallback.execute(std::move(publication));
    } else if (typeid(this->subscriptionCallback) ==
               typeid(UnicastSubscriptionCallback<std::string>)) {
        BasePublication publication;
        publication.setError(error);
        this->subscriptionCallback.execute(std::move(publication));
    } else {
        FAIL() << "Could not evaluate type";
    }
}
<|endoftext|>


<commit_before>/**************************************************************************
**
** Copyright (C) 2011 - 2013 Research In Motion
**
** Contact: Research In Motion (blackberry-qt@qnx.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "blackberryconfigurationmanager.h"
#include "blackberrycertificate.h"
#include "blackberryconfiguration.h"

#include "qnxutils.h"

#include <coreplugin/icore.h>

#include <utils/persistentsettings.h>
#include <utils/hostosinfo.h>

#include <projectexplorer/kit.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/toolchainmanager.h>

#include <qtsupport/qtversionmanager.h>
#include <qtsupport/qtkitinformation.h>

#include <QMessageBox>
#include <QFileInfo>

using namespace ProjectExplorer;

namespace Qnx {
namespace Internal {

namespace {
const QLatin1String SettingsGroup("BlackBerryConfiguration");
const QLatin1String NDKLocationKey("NDKLocation"); // For 10.1 NDK support (< QTC 3.0)
const QLatin1String NDKEnvFileKey("NDKEnvFile");
const QLatin1String CertificateGroup("Certificates");
const QLatin1String ManualNDKsGroup("ManualNDKs");
}

BlackBerryConfigurationManager::BlackBerryConfigurationManager(QObject *parent)
    :QObject(parent)
{
    connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), this, SLOT(saveSettings()));
}

void BlackBerryConfigurationManager::loadCertificates()
{
    QSettings *settings = Core::ICore::settings();

    settings->beginGroup(SettingsGroup);
    settings->beginGroup(CertificateGroup);

    foreach (const QString &certificateId, settings->childGroups()) {
        settings->beginGroup(certificateId);

        BlackBerryCertificate *cert =
                new BlackBerryCertificate(settings->value(QLatin1String(Qnx::Constants::QNX_KEY_PATH)).toString(),
                                          settings->value(QLatin1String(Qnx::Constants::QNX_KEY_AUTHOR)).toString());
        cert->setParent(this);

        if (settings->value(QLatin1String(Qnx::Constants::QNX_KEY_ACTIVE)).toBool())
            m_activeCertificate = cert;

        m_certificates << cert;

        settings->endGroup();
    }

    settings->endGroup();
    settings->endGroup();
}

void BlackBerryConfigurationManager::loadManualConfigurations()
{
    QSettings *settings = Core::ICore::settings();

    settings->beginGroup(SettingsGroup);
    settings->beginGroup(ManualNDKsGroup);

    foreach (const QString &manualNdk, settings->childGroups()) {
        settings->beginGroup(manualNdk);
        QString ndkEnvPath = settings->value(NDKEnvFileKey).toString();
        // For 10.1 NDK support (< QTC 3.0):
        // Since QTC 3.0 BBConfigurations are based on the bbndk-env file
        // to support multiple targets per NDK
        if (ndkEnvPath.isEmpty()) {
            QString ndkPath = settings->value(NDKLocationKey).toString();
            ndkEnvPath = QnxUtils::envFilePath(ndkPath);
        }

        BlackBerryConfiguration *config = new BlackBerryConfiguration(Utils::FileName::fromString(ndkEnvPath),
                                                                      false);
        if (!addConfiguration(config))
            delete config;

        settings->endGroup();
    }

    settings->endGroup();
    settings->endGroup();
}

void BlackBerryConfigurationManager::loadAutoDetectedConfigurations()
{
    foreach (const NdkInstallInformation &ndkInfo, QnxUtils::installedNdks()) {
        QString envFilePath = QnxUtils::envFilePath(ndkInfo.path, ndkInfo.version);
        BlackBerryConfiguration *config = new BlackBerryConfiguration(Utils::FileName::fromString(envFilePath),
                                                                      true, ndkInfo.name);
        if (!addConfiguration(config))
            delete config;
    }
}

void BlackBerryConfigurationManager::saveCertificates()
{
    QSettings *settings = Core::ICore::settings();
    settings->beginGroup(SettingsGroup);
    settings->beginGroup(CertificateGroup);

    settings->remove(QString());

    foreach (const BlackBerryCertificate *cert, m_certificates) {
        settings->beginGroup(cert->id());
        settings->setValue(QLatin1String(Qnx::Constants::QNX_KEY_PATH), cert->fileName());
        settings->setValue(QLatin1String(Qnx::Constants::QNX_KEY_AUTHOR), cert->author());

        if (cert == m_activeCertificate)
            settings->setValue(QLatin1String(Qnx::Constants::QNX_KEY_ACTIVE), true);

        settings->endGroup();
    }

    settings->endGroup();
    settings->endGroup();
}

void BlackBerryConfigurationManager::saveManualConfigurations()
{
    if (manualConfigurations().isEmpty())
        return;

    QSettings *settings = Core::ICore::settings();
    settings->beginGroup(SettingsGroup);
    settings->beginGroup(ManualNDKsGroup);

    foreach (BlackBerryConfiguration *config, manualConfigurations()) {
        settings->beginGroup(config->displayName());
        settings->setValue(NDKEnvFileKey, config->ndkEnvFile().toString());
        settings->endGroup();
    }

    settings->endGroup();
    settings->endGroup();
}

// Remove no longer available 'auo detected' kits
void BlackBerryConfigurationManager::clearInvalidConfigurations()
{
    QList<NdkInstallInformation> autoNdks = QnxUtils::installedNdks();
    foreach (Kit *kit, KitManager::kits()) {
        if (!kit->isAutoDetected())
            continue;

        if (kit->displayName().contains(QLatin1String("BlackBerry"))) {
            // Check if related target is still installed
            bool isValid = false;
            foreach (const NdkInstallInformation &ndkInfo, autoNdks) {
                if (ndkInfo.target == SysRootKitInformation::sysRoot(kit).toString()) {
                    isValid = true;
                    break;
                }
            }

            if (!isValid) {
                QtSupport::QtVersionManager::removeVersion(QtSupport::QtKitInformation::qtVersion(kit));
                ToolChainManager::deregisterToolChain(ToolChainKitInformation::toolChain(kit));
                KitManager::deregisterKit(kit);
            }
        }
    }
}

bool BlackBerryConfigurationManager::addConfiguration(BlackBerryConfiguration *config)
{
    foreach (BlackBerryConfiguration *c, m_configs) {
        if (c->ndkPath() == config->ndkPath()
                && c->targetName() == config->targetName()) {
            if (!config->isAutoDetected())
                QMessageBox::warning(0, tr("NDK Already known"),
                                 tr("The NDK already has a configuration."), QMessageBox::Ok);
            return false;
        }
    }

    if (config->activate()) {
        m_configs.append(config);
        return true;
    }

    return false;
}

void BlackBerryConfigurationManager::removeConfiguration(BlackBerryConfiguration *config)
{
    if (!config)
        return;

    if (config->isActive())
        config->deactivate();

    clearConfigurationSettings(config);

    m_configs.removeAt(m_configs.indexOf(config));
    delete config;
}

QList<BlackBerryConfiguration *> BlackBerryConfigurationManager::configurations() const
{
    return m_configs;
}

QList<BlackBerryConfiguration *> BlackBerryConfigurationManager::manualConfigurations() const
{
    QList<BlackBerryConfiguration*> manuals;
    foreach (BlackBerryConfiguration *config, m_configs) {
        if (!config->isAutoDetected())
            manuals << config;
    }

    return manuals;
}

BlackBerryConfiguration *BlackBerryConfigurationManager::configurationFromEnvFile(const Utils::FileName &envFile) const
{
    foreach (BlackBerryConfiguration *config, m_configs) {
        if (config->ndkEnvFile() == envFile)
            return config;
    }

    return 0;
}

void BlackBerryConfigurationManager::syncCertificates(QList<BlackBerryCertificate*> certificates,
                                                      BlackBerryCertificate *activeCertificate)
{
    m_activeCertificate = activeCertificate;

    foreach (BlackBerryCertificate *cert, certificates) {
        if (!certificates.contains(cert))
            removeCertificate(cert);
    }

    foreach (BlackBerryCertificate *cert, certificates)
        addCertificate(cert);
}

void BlackBerryConfigurationManager::addCertificate(BlackBerryCertificate *certificate)
{
    if (m_certificates.contains(certificate))
        return;

    if (m_certificates.isEmpty())
        m_activeCertificate = certificate;

    certificate->setParent(this);
    m_certificates << certificate;
}

void BlackBerryConfigurationManager::removeCertificate(BlackBerryCertificate *certificate)
{
    if (m_activeCertificate == certificate)
        m_activeCertificate = 0;

    m_certificates.removeAll(certificate);

    delete certificate;
}

QList<BlackBerryCertificate*> BlackBerryConfigurationManager::certificates() const
{
    return m_certificates;
}

BlackBerryCertificate * BlackBerryConfigurationManager::activeCertificate()
{
    return m_activeCertificate;
}

// Returns a valid qnxEnv map from a valid configuration;
// Needed by other classes to get blackberry process path (keys registration, debug token...)
QMultiMap<QString, QString> BlackBerryConfigurationManager::defaultQnxEnv()
{
    foreach (BlackBerryConfiguration *config, m_configs) {
        if (!config->qnxEnv().isEmpty())
            return config->qnxEnv();
    }

    return QMultiMap<QString, QString>();
}

void BlackBerryConfigurationManager::loadSettings()
{
    clearInvalidConfigurations();
    loadAutoDetectedConfigurations();
    loadManualConfigurations();
    loadCertificates();
}

void BlackBerryConfigurationManager::clearConfigurationSettings(BlackBerryConfiguration *config)
{
    if (!config)
        return;

    QSettings *settings = Core::ICore::settings();
    settings->beginGroup(SettingsGroup);
    settings->beginGroup(ManualNDKsGroup);

    foreach (const QString &manualNdk, settings->childGroups()) {
        if (manualNdk == config->displayName()) {
            settings->remove(manualNdk);
            break;
        }
    }

    settings->endGroup();
    settings->endGroup();
}

void BlackBerryConfigurationManager::saveSettings()
{
    saveManualConfigurations();
    saveCertificates();
}

BlackBerryConfigurationManager &BlackBerryConfigurationManager::instance()
{
    if (m_instance == 0)
        m_instance = new BlackBerryConfigurationManager();

    return *m_instance;
}

BlackBerryConfigurationManager::~BlackBerryConfigurationManager()
{
    qDeleteAll(m_configs);
}

QString BlackBerryConfigurationManager::barsignerCskPath() const
{
    return QnxUtils::dataDirPath() + QLatin1String("/barsigner.csk");
}

QString BlackBerryConfigurationManager::barsignerDbPath() const
{
    return QnxUtils::dataDirPath() + QLatin1String("/barsigner.db");
}

QString BlackBerryConfigurationManager::defaultKeystorePath() const
{
    return QnxUtils::dataDirPath() + QLatin1String("/author.p12");
}

QString BlackBerryConfigurationManager::defaultDebugTokenPath() const
{
    return QnxUtils::dataDirPath() + QLatin1String("/debugtoken.bar");
}

BlackBerryConfigurationManager* BlackBerryConfigurationManager::m_instance = 0;

} // namespace Internal
} // namespace Qnx
<commit_msg>Qnx: Remove invalid auto detected kits/qt versions<commit_after>/**************************************************************************
**
** Copyright (C) 2011 - 2013 Research In Motion
**
** Contact: Research In Motion (blackberry-qt@qnx.com)
** Contact: KDAB (info@kdab.com)
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** 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, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/

#include "blackberryconfigurationmanager.h"
#include "blackberrycertificate.h"
#include "blackberryconfiguration.h"

#include "qnxutils.h"

#include <coreplugin/icore.h>

#include <utils/persistentsettings.h>
#include <utils/hostosinfo.h>

#include <projectexplorer/kit.h>
#include <projectexplorer/kitmanager.h>
#include <projectexplorer/kitinformation.h>
#include <projectexplorer/toolchainmanager.h>

#include <qtsupport/qtversionmanager.h>
#include <qtsupport/qtkitinformation.h>

#include <QMessageBox>
#include <QFileInfo>

using namespace ProjectExplorer;

namespace Qnx {
namespace Internal {

namespace {
const QLatin1String SettingsGroup("BlackBerryConfiguration");
const QLatin1String NDKLocationKey("NDKLocation"); // For 10.1 NDK support (< QTC 3.0)
const QLatin1String NDKEnvFileKey("NDKEnvFile");
const QLatin1String CertificateGroup("Certificates");
const QLatin1String ManualNDKsGroup("ManualNDKs");
}

BlackBerryConfigurationManager::BlackBerryConfigurationManager(QObject *parent)
    :QObject(parent)
{
    connect(Core::ICore::instance(), SIGNAL(saveSettingsRequested()), this, SLOT(saveSettings()));
}

void BlackBerryConfigurationManager::loadCertificates()
{
    QSettings *settings = Core::ICore::settings();

    settings->beginGroup(SettingsGroup);
    settings->beginGroup(CertificateGroup);

    foreach (const QString &certificateId, settings->childGroups()) {
        settings->beginGroup(certificateId);

        BlackBerryCertificate *cert =
                new BlackBerryCertificate(settings->value(QLatin1String(Qnx::Constants::QNX_KEY_PATH)).toString(),
                                          settings->value(QLatin1String(Qnx::Constants::QNX_KEY_AUTHOR)).toString());
        cert->setParent(this);

        if (settings->value(QLatin1String(Qnx::Constants::QNX_KEY_ACTIVE)).toBool())
            m_activeCertificate = cert;

        m_certificates << cert;

        settings->endGroup();
    }

    settings->endGroup();
    settings->endGroup();
}

void BlackBerryConfigurationManager::loadManualConfigurations()
{
    QSettings *settings = Core::ICore::settings();

    settings->beginGroup(SettingsGroup);
    settings->beginGroup(ManualNDKsGroup);

    foreach (const QString &manualNdk, settings->childGroups()) {
        settings->beginGroup(manualNdk);
        QString ndkEnvPath = settings->value(NDKEnvFileKey).toString();
        // For 10.1 NDK support (< QTC 3.0):
        // Since QTC 3.0 BBConfigurations are based on the bbndk-env file
        // to support multiple targets per NDK
        if (ndkEnvPath.isEmpty()) {
            QString ndkPath = settings->value(NDKLocationKey).toString();
            ndkEnvPath = QnxUtils::envFilePath(ndkPath);
        }

        BlackBerryConfiguration *config = new BlackBerryConfiguration(Utils::FileName::fromString(ndkEnvPath),
                                                                      false);
        if (!addConfiguration(config))
            delete config;

        settings->endGroup();
    }

    settings->endGroup();
    settings->endGroup();
}

void BlackBerryConfigurationManager::loadAutoDetectedConfigurations()
{
    foreach (const NdkInstallInformation &ndkInfo, QnxUtils::installedNdks()) {
        QString envFilePath = QnxUtils::envFilePath(ndkInfo.path, ndkInfo.version);
        BlackBerryConfiguration *config = new BlackBerryConfiguration(Utils::FileName::fromString(envFilePath),
                                                                      true, ndkInfo.name);
        if (!addConfiguration(config))
            delete config;
    }
}

void BlackBerryConfigurationManager::saveCertificates()
{
    QSettings *settings = Core::ICore::settings();
    settings->beginGroup(SettingsGroup);
    settings->beginGroup(CertificateGroup);

    settings->remove(QString());

    foreach (const BlackBerryCertificate *cert, m_certificates) {
        settings->beginGroup(cert->id());
        settings->setValue(QLatin1String(Qnx::Constants::QNX_KEY_PATH), cert->fileName());
        settings->setValue(QLatin1String(Qnx::Constants::QNX_KEY_AUTHOR), cert->author());

        if (cert == m_activeCertificate)
            settings->setValue(QLatin1String(Qnx::Constants::QNX_KEY_ACTIVE), true);

        settings->endGroup();
    }

    settings->endGroup();
    settings->endGroup();
}

void BlackBerryConfigurationManager::saveManualConfigurations()
{
    if (manualConfigurations().isEmpty())
        return;

    QSettings *settings = Core::ICore::settings();
    settings->beginGroup(SettingsGroup);
    settings->beginGroup(ManualNDKsGroup);

    foreach (BlackBerryConfiguration *config, manualConfigurations()) {
        settings->beginGroup(config->displayName());
        settings->setValue(NDKEnvFileKey, config->ndkEnvFile().toString());
        settings->endGroup();
    }

    settings->endGroup();
    settings->endGroup();
}

// Remove no longer available/valid 'auto detected' BlackBerry kits and qt versions
void BlackBerryConfigurationManager::clearInvalidConfigurations()
{
    // Deregister invalid auto deteted BlackBerry Kits
    foreach (ProjectExplorer::Kit *kit, ProjectExplorer::KitManager::instance()->kits()) {
        if (!kit->isAutoDetected())
            continue;

        if (ProjectExplorer::DeviceTypeKitInformation::deviceTypeId(kit) == Constants::QNX_BB_OS_TYPE
                && !kit->isValid())
       ProjectExplorer::KitManager::instance()->deregisterKit(kit);
    }

    // Remove invalid auto detected BlackBerry qtVerions
    foreach (QtSupport::BaseQtVersion *qtVersion, QtSupport::QtVersionManager::versions()) {
        if (!qtVersion->isAutodetected())
            continue;

        if (qtVersion->platformName() == QLatin1String(Constants::QNX_BB_PLATFORM_NAME)
                && !qtVersion->isValid())
           QtSupport::QtVersionManager::removeVersion(qtVersion);
    }
}

bool BlackBerryConfigurationManager::addConfiguration(BlackBerryConfiguration *config)
{
    foreach (BlackBerryConfiguration *c, m_configs) {
        if (c->ndkPath() == config->ndkPath()
                && c->targetName() == config->targetName()) {
            if (!config->isAutoDetected())
                QMessageBox::warning(0, tr("NDK Already known"),
                                 tr("The NDK already has a configuration."), QMessageBox::Ok);
            return false;
        }
    }

    if (config->activate()) {
        m_configs.append(config);
        return true;
    }

    return false;
}

void BlackBerryConfigurationManager::removeConfiguration(BlackBerryConfiguration *config)
{
    if (!config)
        return;

    if (config->isActive())
        config->deactivate();

    clearConfigurationSettings(config);

    m_configs.removeAt(m_configs.indexOf(config));
    delete config;
}

QList<BlackBerryConfiguration *> BlackBerryConfigurationManager::configurations() const
{
    return m_configs;
}

QList<BlackBerryConfiguration *> BlackBerryConfigurationManager::manualConfigurations() const
{
    QList<BlackBerryConfiguration*> manuals;
    foreach (BlackBerryConfiguration *config, m_configs) {
        if (!config->isAutoDetected())
            manuals << config;
    }

    return manuals;
}

BlackBerryConfiguration *BlackBerryConfigurationManager::configurationFromEnvFile(const Utils::FileName &envFile) const
{
    foreach (BlackBerryConfiguration *config, m_configs) {
        if (config->ndkEnvFile() == envFile)
            return config;
    }

    return 0;
}

void BlackBerryConfigurationManager::syncCertificates(QList<BlackBerryCertificate*> certificates,
                                                      BlackBerryCertificate *activeCertificate)
{
    m_activeCertificate = activeCertificate;

    foreach (BlackBerryCertificate *cert, certificates) {
        if (!certificates.contains(cert))
            removeCertificate(cert);
    }

    foreach (BlackBerryCertificate *cert, certificates)
        addCertificate(cert);
}

void BlackBerryConfigurationManager::addCertificate(BlackBerryCertificate *certificate)
{
    if (m_certificates.contains(certificate))
        return;

    if (m_certificates.isEmpty())
        m_activeCertificate = certificate;

    certificate->setParent(this);
    m_certificates << certificate;
}

void BlackBerryConfigurationManager::removeCertificate(BlackBerryCertificate *certificate)
{
    if (m_activeCertificate == certificate)
        m_activeCertificate = 0;

    m_certificates.removeAll(certificate);

    delete certificate;
}

QList<BlackBerryCertificate*> BlackBerryConfigurationManager::certificates() const
{
    return m_certificates;
}

BlackBerryCertificate * BlackBerryConfigurationManager::activeCertificate()
{
    return m_activeCertificate;
}

// Returns a valid qnxEnv map from a valid configuration;
// Needed by other classes to get blackberry process path (keys registration, debug token...)
QMultiMap<QString, QString> BlackBerryConfigurationManager::defaultQnxEnv()
{
    foreach (BlackBerryConfiguration *config, m_configs) {
        if (!config->qnxEnv().isEmpty())
            return config->qnxEnv();
    }

    return QMultiMap<QString, QString>();
}

void BlackBerryConfigurationManager::loadSettings()
{
    clearInvalidConfigurations();
    loadAutoDetectedConfigurations();
    loadManualConfigurations();
    loadCertificates();
}

void BlackBerryConfigurationManager::clearConfigurationSettings(BlackBerryConfiguration *config)
{
    if (!config)
        return;

    QSettings *settings = Core::ICore::settings();
    settings->beginGroup(SettingsGroup);
    settings->beginGroup(ManualNDKsGroup);

    foreach (const QString &manualNdk, settings->childGroups()) {
        if (manualNdk == config->displayName()) {
            settings->remove(manualNdk);
            break;
        }
    }

    settings->endGroup();
    settings->endGroup();
}

void BlackBerryConfigurationManager::saveSettings()
{
    saveManualConfigurations();
    saveCertificates();
}

BlackBerryConfigurationManager &BlackBerryConfigurationManager::instance()
{
    if (m_instance == 0)
        m_instance = new BlackBerryConfigurationManager();

    return *m_instance;
}

BlackBerryConfigurationManager::~BlackBerryConfigurationManager()
{
    qDeleteAll(m_configs);
}

QString BlackBerryConfigurationManager::barsignerCskPath() const
{
    return QnxUtils::dataDirPath() + QLatin1String("/barsigner.csk");
}

QString BlackBerryConfigurationManager::barsignerDbPath() const
{
    return QnxUtils::dataDirPath() + QLatin1String("/barsigner.db");
}

QString BlackBerryConfigurationManager::defaultKeystorePath() const
{
    return QnxUtils::dataDirPath() + QLatin1String("/author.p12");
}

QString BlackBerryConfigurationManager::defaultDebugTokenPath() const
{
    return QnxUtils::dataDirPath() + QLatin1String("/debugtoken.bar");
}

BlackBerryConfigurationManager* BlackBerryConfigurationManager::m_instance = 0;

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


<commit_before>//===----------------------------------------------------------------------===//
// LLVM 'GCCLD' UTILITY
//
// This utility is intended to be compatible with GCC, and follows standard
// system ld conventions.  As such, the default output file is ./a.out.
// Additionally, this program outputs a shell script that is used to invoke LLI
// to execute the program.  In this manner, the generated executable (a.out for
// example), is directly executable, whereas the bytecode file actually lives in
// the a.out.bc file generated by this program.  Also, Force is on by default.
//
// Note that if someone (or a script) deletes the executable program generated,
// the .bc file will be left around.  Considering that this is a temporary hack,
// I'm not to worried about this.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Linker.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Transforms/SymbolStripping.h"
#include "llvm/Transforms/CleanupGCCOutput.h"
#include "llvm/Transforms/ConstantMerge.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "Support/CommandLine.h"
#include <fstream>
#include <memory>
#include <algorithm>
#include <sys/types.h>     // For FileExists
#include <sys/stat.h>

cl::StringList InputFilenames("", "Load <arg> files, linking them together",
			      cl::OneOrMore);
cl::String OutputFilename("o", "Override output filename", cl::NoFlags,"a.out");
cl::Flag   Verbose       ("v", "Print information about actions taken");
cl::StringList LibPaths  ("L", "Specify a library search path", cl::ZeroOrMore);
cl::StringList Libraries ("l", "Specify libraries to link to", cl::ZeroOrMore);
cl::Flag       Strip     ("s", "Strip symbol info from executable");

// FileExists - Return true if the specified string is an openable file...
static inline bool FileExists(const std::string &FN) {
  struct stat StatBuf;
  return stat(FN.c_str(), &StatBuf) != -1;
}

// LoadFile - Read the specified bytecode file in and return it.  This routine
// searches the link path for the specified file to try to find it...
//
static inline std::auto_ptr<Module> LoadFile(const std::string &FN) {
  std::string Filename = FN;
  std::string ErrorMessage;

  unsigned NextLibPathIdx = 0;
  bool FoundAFile = false;

  while (1) {
    if (Verbose) cerr << "Loading '" << Filename << "'\n";
    if (FileExists(Filename)) FoundAFile = true;
    Module *Result = ParseBytecodeFile(Filename, &ErrorMessage);
    if (Result) return std::auto_ptr<Module>(Result);   // Load successful!

    if (Verbose) {
      cerr << "Error opening bytecode file: '" << Filename << "'";
      if (ErrorMessage.size()) cerr << ": " << ErrorMessage;
      cerr << endl;
    }

    if (NextLibPathIdx == LibPaths.size()) break;
    Filename = LibPaths[NextLibPathIdx++] + "/" + FN;
  }

  if (FoundAFile)
    cerr << "Bytecode file '" << FN << "' corrupt!  "
         << "Use 'gccld -v ...' for more info.\n";
  else
    cerr << "Could not locate bytecode file: '" << FN << "'\n";
  return std::auto_ptr<Module>();
}

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm linker for GCC\n",
			      cl::EnableSingleLetterArgValue |
			      cl::DisableSingleLetterArgGrouping);
  assert(InputFilenames.size() > 0 && "OneOrMore is not working");

  unsigned BaseArg = 0;
  std::string ErrorMessage;

  if (!Libraries.empty()) {
    // Sort libraries list...
    sort(Libraries.begin(), Libraries.end());

    // Remove duplicate libraries entries...
    Libraries.erase(unique(Libraries.begin(), Libraries.end()),
                    Libraries.end());

    // Add all of the libraries to the end of the link line...
    for (unsigned i = 0; i < Libraries.size(); ++i)
      InputFilenames.push_back("lib" + Libraries[i] + ".bc");
  }

  std::auto_ptr<Module> Composite(LoadFile(InputFilenames[BaseArg]));
  if (Composite.get() == 0) return 1;

  for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) {
    std::auto_ptr<Module> M(LoadFile(InputFilenames[i]));
    if (M.get() == 0) return 1;

    if (Verbose) cerr << "Linking in '" << InputFilenames[i] << "'\n";

    if (LinkModules(Composite.get(), M.get(), &ErrorMessage)) {
      cerr << "Error linking in '" << InputFilenames[i] << "': "
	   << ErrorMessage << endl;
      return 1;
    }
  }

  // In addition to just parsing the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  //
  PassManager Passes;

  // Linking modules together can lead to duplicated global constants, only keep
  // one copy of each constant...
  //
  Passes.add(createConstantMergePass());

  // Often if the programmer does not specify proper prototypes for the
  // functions they are calling, they end up calling a vararg version of the
  // function that does not get a body filled in (the real function has typed
  // arguments).  This pass merges the two functions, among other things.
  //
  Passes.add(createCleanupGCCOutputPass());

  // If the -s command line option was specified, strip the symbols out of the
  // resulting program to make it smaller.  -s is a GCC option that we are
  // supporting.
  //
  if (Strip)
    Passes.add(createSymbolStrippingPass());

  // Now that composite has been compiled, scan through the module, looking for
  // a main function.  If main is defined, mark all other functions internal.
  //
  // TODO:

  // Now that we have optimized the program, discard unreachable functions...
  //
  Passes.add(createGlobalDCEPass());

  // Add the pass that writes bytecode to the output file...
  std::ofstream Out((OutputFilename+".bc").c_str());
  if (!Out.good()) {
    cerr << "Error opening '" << OutputFilename << ".bc' for writing!\n";
    return 1;
  }
  Passes.add(new WriteBytecodePass(&Out));        // Write bytecode to file...

  // Run our queue of passes all at once now, efficiently.
  Passes.run(Composite.get());
  Out.close();

  // Output the script to start the program...
  std::ofstream Out2(OutputFilename.c_str());
  if (!Out2.good()) {
    cerr << "Error opening '" << OutputFilename << "' for writing!\n";
    return 1;
  }
  Out2 << "#!/bin/sh\nlli -q $0.bc $*\n";
  Out2.close();

  // Make the script executable...
  chmod(OutputFilename.c_str(), 0755);

  return 0;
}
<commit_msg>* The cleangcc pass is broken into two parts, we only want to   FunctionResolvingPass one. * We run it *after* the symbol stripping pass so that -strip can be   pipelined with the constant merging pass or something else if desired.<commit_after>//===----------------------------------------------------------------------===//
// LLVM 'GCCLD' UTILITY
//
// This utility is intended to be compatible with GCC, and follows standard
// system ld conventions.  As such, the default output file is ./a.out.
// Additionally, this program outputs a shell script that is used to invoke LLI
// to execute the program.  In this manner, the generated executable (a.out for
// example), is directly executable, whereas the bytecode file actually lives in
// the a.out.bc file generated by this program.  Also, Force is on by default.
//
// Note that if someone (or a script) deletes the executable program generated,
// the .bc file will be left around.  Considering that this is a temporary hack,
// I'm not to worried about this.
//
//===----------------------------------------------------------------------===//

#include "llvm/Transforms/Linker.h"
#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Transforms/SymbolStripping.h"
#include "llvm/Transforms/CleanupGCCOutput.h"
#include "llvm/Transforms/ConstantMerge.h"
#include "llvm/Transforms/IPO/GlobalDCE.h"
#include "Support/CommandLine.h"
#include <fstream>
#include <memory>
#include <algorithm>
#include <sys/types.h>     // For FileExists
#include <sys/stat.h>

cl::StringList InputFilenames("", "Load <arg> files, linking them together",
			      cl::OneOrMore);
cl::String OutputFilename("o", "Override output filename", cl::NoFlags,"a.out");
cl::Flag   Verbose       ("v", "Print information about actions taken");
cl::StringList LibPaths  ("L", "Specify a library search path", cl::ZeroOrMore);
cl::StringList Libraries ("l", "Specify libraries to link to", cl::ZeroOrMore);
cl::Flag       Strip     ("s", "Strip symbol info from executable");

// FileExists - Return true if the specified string is an openable file...
static inline bool FileExists(const std::string &FN) {
  struct stat StatBuf;
  return stat(FN.c_str(), &StatBuf) != -1;
}

// LoadFile - Read the specified bytecode file in and return it.  This routine
// searches the link path for the specified file to try to find it...
//
static inline std::auto_ptr<Module> LoadFile(const std::string &FN) {
  std::string Filename = FN;
  std::string ErrorMessage;

  unsigned NextLibPathIdx = 0;
  bool FoundAFile = false;

  while (1) {
    if (Verbose) cerr << "Loading '" << Filename << "'\n";
    if (FileExists(Filename)) FoundAFile = true;
    Module *Result = ParseBytecodeFile(Filename, &ErrorMessage);
    if (Result) return std::auto_ptr<Module>(Result);   // Load successful!

    if (Verbose) {
      cerr << "Error opening bytecode file: '" << Filename << "'";
      if (ErrorMessage.size()) cerr << ": " << ErrorMessage;
      cerr << endl;
    }

    if (NextLibPathIdx == LibPaths.size()) break;
    Filename = LibPaths[NextLibPathIdx++] + "/" + FN;
  }

  if (FoundAFile)
    cerr << "Bytecode file '" << FN << "' corrupt!  "
         << "Use 'gccld -v ...' for more info.\n";
  else
    cerr << "Could not locate bytecode file: '" << FN << "'\n";
  return std::auto_ptr<Module>();
}

int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv, " llvm linker for GCC\n",
			      cl::EnableSingleLetterArgValue |
			      cl::DisableSingleLetterArgGrouping);
  assert(InputFilenames.size() > 0 && "OneOrMore is not working");

  unsigned BaseArg = 0;
  std::string ErrorMessage;

  if (!Libraries.empty()) {
    // Sort libraries list...
    sort(Libraries.begin(), Libraries.end());

    // Remove duplicate libraries entries...
    Libraries.erase(unique(Libraries.begin(), Libraries.end()),
                    Libraries.end());

    // Add all of the libraries to the end of the link line...
    for (unsigned i = 0; i < Libraries.size(); ++i)
      InputFilenames.push_back("lib" + Libraries[i] + ".bc");
  }

  std::auto_ptr<Module> Composite(LoadFile(InputFilenames[BaseArg]));
  if (Composite.get() == 0) return 1;

  for (unsigned i = BaseArg+1; i < InputFilenames.size(); ++i) {
    std::auto_ptr<Module> M(LoadFile(InputFilenames[i]));
    if (M.get() == 0) return 1;

    if (Verbose) cerr << "Linking in '" << InputFilenames[i] << "'\n";

    if (LinkModules(Composite.get(), M.get(), &ErrorMessage)) {
      cerr << "Error linking in '" << InputFilenames[i] << "': "
	   << ErrorMessage << endl;
      return 1;
    }
  }

  // In addition to just linking the input from GCC, we also want to spiff it up
  // a little bit.  Do this now.
  //
  PassManager Passes;

  // Linking modules together can lead to duplicated global constants, only keep
  // one copy of each constant...
  //
  Passes.add(createConstantMergePass());

  // If the -s command line option was specified, strip the symbols out of the
  // resulting program to make it smaller.  -s is a GCC option that we are
  // supporting.
  //
  if (Strip)
    Passes.add(createSymbolStrippingPass());

  // Often if the programmer does not specify proper prototypes for the
  // functions they are calling, they end up calling a vararg version of the
  // function that does not get a body filled in (the real function has typed
  // arguments).  This pass merges the two functions.
  //
  Passes.add(createFunctionResolvingPass());

  // Now that composite has been compiled, scan through the module, looking for
  // a main function.  If main is defined, mark all other functions internal.
  //
  // TODO:

  // Now that we have optimized the program, discard unreachable functions...
  //
  Passes.add(createGlobalDCEPass());

  // Add the pass that writes bytecode to the output file...
  std::ofstream Out((OutputFilename+".bc").c_str());
  if (!Out.good()) {
    cerr << "Error opening '" << OutputFilename << ".bc' for writing!\n";
    return 1;
  }
  Passes.add(new WriteBytecodePass(&Out));        // Write bytecode to file...

  // Run our queue of passes all at once now, efficiently.
  Passes.run(Composite.get());
  Out.close();

  // Output the script to start the program...
  std::ofstream Out2(OutputFilename.c_str());
  if (!Out2.good()) {
    cerr << "Error opening '" << OutputFilename << "' for writing!\n";
    return 1;
  }
  Out2 << "#!/bin/sh\nlli -q $0.bc $*\n";
  Out2.close();

  // Make the script executable...
  chmod(OutputFilename.c_str(), 0755);

  return 0;
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: popmenu.hxx,v $
 *
 *  $Revision: 1.1.1.1 $
 *
 *  last change: $Author: hr $ $Date: 2000-09-18 16:45:00 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_POPMENU_HXX
#define SC_POPMENU_HXX

#ifndef _MENU_HXX //autogen
#include <vcl/menu.hxx>
#endif

class ScPopupMenu : public PopupMenu
{
private:
    USHORT  nSel;
    BOOL    bHit;
protected:
    virtual void Select();
public:
    ScPopupMenu() : nSel(0),bHit(FALSE) {}
    ScPopupMenu(const ResId& rRes) : PopupMenu(rRes),nSel(0),bHit(FALSE) {}
    USHORT  GetSelected() const { return nSel; }
    BOOL    WasHit() const      { return bHit; }
};

#endif

<commit_msg>INTEGRATION: CWS tune03 (1.1.1.1.530); FILE MERGED 2004/07/08 16:45:11 mhu 1.1.1.1.530.1: #i29979# Added SC_DLLPUBLIC/PRIVATE (see scdllapi.h) to exported symbols/classes.<commit_after>/*************************************************************************
 *
 *  $RCSfile: popmenu.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: rt $ $Date: 2004-08-23 09:34:43 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef SC_POPMENU_HXX
#define SC_POPMENU_HXX

#ifndef _MENU_HXX //autogen
#include <vcl/menu.hxx>
#endif

#ifndef INCLUDED_SCDLLAPI_H
#include "scdllapi.h"
#endif

class SC_DLLPUBLIC ScPopupMenu : public PopupMenu
{
private:
    USHORT  nSel;
    BOOL    bHit;
protected:
    virtual void Select();
public:
    ScPopupMenu() : nSel(0),bHit(FALSE) {}
    ScPopupMenu(const ResId& rRes) : PopupMenu(rRes),nSel(0),bHit(FALSE) {}
    USHORT  GetSelected() const { return nSel; }
    BOOL    WasHit() const      { return bHit; }
};

#endif

<|endoftext|>


<commit_before>/*!
 * Copyright (c) 2018 by Contributors
 * \file alter_op_layout.cc
 * \brief Alternate the layouts of operators or replace primitive operators with
          other expressions. This pass can be used for computing convolution in
          custom layouts or other general weight pre-transformation.
 */
#include <tvm/relay/pass.h>
#include <tvm/relay/op_attr_types.h>
#include <tvm/relay/attrs/transform.h>
#include <tvm/tvm.h>
#include <tuple>
#include <vector>
#include <functional>
#include <string>
#include <utility>
#include <unordered_map>

#include "alter_op_layout.h"

namespace tvm {
namespace relay {

namespace alter_op_layout {

// Make a transform CallNode
Expr TransformLayout(Expr raw, Layout src_layout, Layout dst_layout) {
  if (src_layout.Equals(dst_layout)) { return raw; }
  CHECK(src_layout.defined() && dst_layout.defined())
    << "Cannot insert layout transform because there are undefined layouts";
  CHECK(BijectiveLayoutNode::make(src_layout, dst_layout).defined())
    << "Cannot insert layout transform because there are inconvertible layouts: "
    << src_layout << " v.s. " << dst_layout;
  static auto &transform_op = Op::Get("layout_transform");
  NodePtr<LayoutTransformAttrs> attrs = make_node<LayoutTransformAttrs>();
  attrs->src_layout = src_layout.name();
  attrs->dst_layout = dst_layout.name();
  Call transform = CallNode::make(transform_op, {raw}, Attrs{attrs});
  return std::move(transform);
}

// Memorize layout transform so we can reuse internal transformed nodes
class TransformMemorizerNode : public Node {
 public:
  // map from (Expr, src_layout, dst_layout) to transformed Expr
  using TransformKey = std::tuple<const Node*, std::string, std::string>;
  struct key_hash : public std::unary_function<TransformKey , std::size_t> {
    std::size_t operator()(const TransformKey& k) const {
      return dmlc::HashCombine<std::string>(dmlc::HashCombine<std::string>(
              std::hash<const Node*>()(std::get<0>(k)), std::get<1>(k)), (std::get<2>(k)));
    }
  };

  std::unordered_map<TransformKey, Expr, key_hash> memo;
  static constexpr const char *_type_key = "relay.alter_op_layout.TransformMemorizerNode";
  TVM_DECLARE_NODE_TYPE_INFO(TransformMemorizerNode, Node);
};

class TransformMemorizer : public NodeRef {
 public:
  TransformMemorizer() {}
  explicit TransformMemorizer(NodePtr<Node> n) : NodeRef(n) {}

  TransformMemorizerNode* operator->() {
    return static_cast<TransformMemorizerNode*>(node_.get());
  }

  // Transform layout with memorizer
  Expr Transform(Expr raw, const Layout& src_layout, const Layout& dst_layout) {
    if (src_layout.Equals(dst_layout)) { return raw; }

    std::tuple<const Node*, std::string, std::string> key =
        std::make_tuple<>(raw.get(), src_layout.name(), dst_layout.name());
    auto& memo = operator->()->memo;

    auto iter = memo.find(key);
    if (iter != memo.end()) {
      return iter->second;
    } else {
      Expr transform = TransformLayout(raw, src_layout, dst_layout);
      memo[key] = transform;
      return transform;
    }
  }

  using ContainerType = TransformMemorizerNode;
};

// TempExprNode during layout transform
// Instance of this expr will be Realized to normal expr ultimately
class LayoutAlternatedExprNode : public TempExprNode {
 public:
  Expr value;
  Layout old_layout;
  Layout new_layout;
  TransformMemorizer memorizer;

  Expr Realize() const final {
    // NOTE: use a copy to discard the "const" qualifier
    TransformMemorizer tmp_memorizer = memorizer;
    // fallback to old layout
    return tmp_memorizer.Transform(value, new_layout, old_layout);
  }

  void VisitAttrs(AttrVisitor *v) final {
    v->Visit("value", &value);
    v->Visit("old_layout", &old_layout);
    v->Visit("new_layout", &new_layout);
  }

  static constexpr const char *_type_key = "relay.alter_op_layout.LayoutAlternatedExprNode";
  TVM_DECLARE_NODE_TYPE_INFO(LayoutAlternatedExprNode, TempExprNode);
};

RELAY_DEFINE_NODE_REF(LayoutAlternatedExpr, LayoutAlternatedExprNode, TempExpr);

// Call registered FInferCorrectLayout of an op.
// Parameters are the same as the parameters for FInferCorrectLayout
// Returns inferred_input_layout, inferred_output_layout, success
std::tuple<Array<Layout>, Array<Layout>, bool> CallInfer(
    const Call& call,
    const Array<Layout>& new_in_layouts,
    const Array<Layout>& old_in_layouts,
    const Array<Array<IndexExpr> > &old_in_shapes) {
  static auto finfer_layout = Op::GetAttr<FInferCorrectLayout>("FInferCorrectLayout");

  Op op = Downcast<Op>(call->op);
  if (finfer_layout.count(op)) {
    Array<Array<Layout> > inferred_layouts;
    inferred_layouts = finfer_layout[op](call->attrs, new_in_layouts,
                                         old_in_layouts, old_in_shapes);
    CHECK_EQ(inferred_layouts.size(), 2)
      << "FInferCorrectLayout should return an array with size of 2";
    for (auto x : inferred_layouts) {
      for (auto y : x) {
        if (!y.defined()) {  // inference fails
          return std::make_tuple<>(Array<Layout>(nullptr), Array<Layout>(nullptr), false);
        }
      }
    }
    return std::make_tuple<>(inferred_layouts[0], inferred_layouts[1], true);
  } else {
    return std::make_tuple<>(Array<Layout>(nullptr), Array<Layout>(nullptr), false);
  }
}

// Call registered FTVMAlterOpLayout of an op
// Returns the altered expression
Call CallAlter(const Call& ref_call,
               const std::vector<Expr>& new_args) {
  static auto falter_layout = Op::GetAttr<FTVMAlterOpLayout>("FTVMAlterOpLayout");
  Op op = Downcast<Op>(ref_call->op);

  Expr new_e;
  bool modified = false;
  if (falter_layout.count(op)) {
    tvm::Array<tvm::Tensor> tinfos;
    for (auto expr : ref_call->args) {
      auto ttype = expr->type_as<TensorTypeNode>();
      tinfos.push_back(tvm::placeholder(ttype->shape, ttype->dtype));
    }
    Expr altered_value = falter_layout[op](ref_call->attrs, new_args, tinfos);
    if (altered_value.defined()) {
      new_e = altered_value;
      modified = true;
    }
  }
  if (!modified) {
    new_e = CallNode::make(ref_call->op, new_args,
                           ref_call->attrs);
  }

  const CallNode *new_call = new_e.as<CallNode>();
  CHECK(new_call) << "Can only replace the original operator with another call node";
  return GetRef<Call>(new_call);
}

Expr AlterOpLayoutRewrite(const Call &ref_call,
                          const Array<Expr> &new_args,
                          const NodeRef& ctx) {
  std::vector<LayoutAlternatedExpr> inputs;
  std::vector<Expr> normal_new_args;
  Array<Array<IndexExpr> > input_shapes;

  // NOTE: discard the "const" qualifier
  TransformMemorizer memorizer = Downcast<TransformMemorizer>(ctx);

  // fill incomplete state and flatten tuple
  auto push_back_one_arg = [&inputs, memorizer](Expr arg) {
    // We always expect LayoutAlternatedExpr.
    // This is used to convert the normal Expr to LayoutAlternatedExpr.
    if (const LayoutAlternatedExprNode *inp = arg.as<LayoutAlternatedExprNode>()) {
      inputs.push_back(GetRef<LayoutAlternatedExpr>(inp));
      return inp->value;
    } else {
      auto inode = make_node<LayoutAlternatedExprNode>();
      inode->value = arg;
      inode->memorizer = memorizer;
      inputs.push_back(LayoutAlternatedExpr(inode));
      return arg;
    }
  };

  for (auto new_arg : new_args) {
    // NOTE: do not support nested tuple
    if (new_arg->is_type<TupleNode>()) {
      Tuple tuple_new_arg = Downcast<Tuple>(new_arg);
      std::vector<Expr> fields;
      for (auto x : tuple_new_arg->fields) {
        Expr tmp = push_back_one_arg(x);
        fields.push_back(tmp);
      }
      normal_new_args.push_back(TupleNode::make(fields));
    } else {
      Expr tmp = push_back_one_arg(new_arg);
      normal_new_args.push_back(tmp);
    }
  }

  // old_in, new_in = state[inputs]
  Array<Layout> old_in, old_out, new_in, new_out, new_in2;
  for (auto inp : inputs) {
    old_in.push_back(inp->old_layout);
    new_in.push_back(inp->new_layout);
  }

  for (auto arg : ref_call->args) {
    if (arg->is_type<TupleNode>()) {  // flatten tuple
      Tuple tuple_arg = Downcast<Tuple>(arg);
      for (auto x : tuple_arg->fields) {
        input_shapes.push_back(x->type_as<TensorTypeNode>()->shape);
      }
    } else {
      input_shapes.push_back(arg->type_as<TensorTypeNode>()->shape);
    }
  }

  // old_in, old_out = op.infer(old_in)
  bool success = false;
  std::tie(old_in, old_out, success) = CallInfer(ref_call,
                                                 Array<Layout>(nullptr),
                                                 old_in, input_shapes);
  if (!success) { return Expr(nullptr); }
  CHECK_EQ(old_in.size(), new_in.size());

  // if new_in == 'undef':  new_in = old_in
  for (size_t i = 0; i < new_in.size(); ++i) {
    if (!new_in[i].defined()) {
      new_in.Set(i, old_in[i]);
    }
  }

  // new_op = alter(op)
  Call new_call = CallAlter(ref_call, normal_new_args);

  // new_in2, new_out = op.infer(new_in)
  if (new_call->op->is_type<OpNode>()) {
    success = false;
    std::tie(new_in2, new_out, success) = CallInfer(new_call, new_in, old_in, input_shapes);
    if (!success) { return Expr(nullptr); }
  } else {
    return Expr(nullptr);
  }

  CHECK_EQ(new_out.size(), old_out.size())
    << "The number of output nodes should keep the same during alter_op_layout";
  CHECK_EQ(new_in.size(), new_in2.size())
    << "The number of input nodes should keep the same during alter_op_layout";

  // if (new_in != new_in2): insert transform (new_in -> new_in2)
  Array<Expr> transformed_args;
  size_t pt = 0;
  for (auto arg : new_call->args) {
    if (arg->is_type<TupleNode>()) {  // unflatten tuple
      Tuple tuple_arg = Downcast<Tuple>(arg);
      std::vector<Expr> transformed_tuple_arg;
      for (auto arg_item : tuple_arg->fields) {
          transformed_tuple_arg.push_back(
                  memorizer.Transform(arg_item, new_in[pt], new_in2[pt]));
          pt++;
      }
      transformed_args.push_back(TupleNode::make(transformed_tuple_arg));
    } else {
      transformed_args.push_back(
              memorizer.Transform(arg, new_in[pt], new_in2[pt]));
      pt++;
    }
  }
  CHECK_EQ(pt, inputs.size());

  // state[node] = (old_out, new_out)
  // (handle tuple output)
  if (ref_call->checked_type()->is_type<TupleTypeNode>()) {
    Expr tuple_output = CallNode::make(new_call->op, transformed_args,
                                       new_call->attrs);
    Array<Expr> fields;
    for (size_t i = 0; i < new_out.size(); ++i) {
      auto rnode = make_node<LayoutAlternatedExprNode>();
      rnode->value = TupleGetItemNode::make(tuple_output, i);
      rnode->old_layout = old_out[i];
      rnode->new_layout = new_out[i];
      rnode->memorizer = memorizer;
      fields.push_back(Expr(rnode));
    }
    return TupleNode::make(fields);
  } else {
    auto rnode = make_node<LayoutAlternatedExprNode>();
    CHECK_EQ(new_out.size(), 1);
    rnode->value = CallNode::make(new_call->op, transformed_args,
                                  new_call->attrs);
    rnode->old_layout = old_out[0];
    rnode->new_layout = new_out[0];
    rnode->memorizer = memorizer;
    return Expr(rnode);
  }
}

// Limiations:
// 1. the altered op should have the same number of arguments as the previous one
// 2. do not support nested tuple arguments
TVM_REGISTER_API("relay._ir_pass.AlterOpLayout")
.set_body([](TVMArgs args, TVMRetValue *ret) {
  TransformMemorizer transformMemorizer(make_node<TransformMemorizerNode>());
  auto fcontext = [&](const Call& call) -> NodeRef{
    return transformMemorizer;
  };

  *ret = ForwardRewrite(args[0], AlterOpLayoutRewrite, fcontext);
});

}  // namespace alter_op_layout

}  // namespace relay
}  // namespace tvm
<commit_msg>Removed std::unary_function because it is deprecated and removed in newer c++(https://en.cppreference.com/w/cpp/utility/functional/unary_function) (#2962)<commit_after>/*!
 * Copyright (c) 2018 by Contributors
 * \file alter_op_layout.cc
 * \brief Alternate the layouts of operators or replace primitive operators with
          other expressions. This pass can be used for computing convolution in
          custom layouts or other general weight pre-transformation.
 */
#include <tvm/relay/pass.h>
#include <tvm/relay/op_attr_types.h>
#include <tvm/relay/attrs/transform.h>
#include <tvm/tvm.h>
#include <tuple>
#include <vector>
#include <functional>
#include <string>
#include <utility>
#include <unordered_map>

#include "alter_op_layout.h"

namespace tvm {
namespace relay {

namespace alter_op_layout {

// Make a transform CallNode
Expr TransformLayout(Expr raw, Layout src_layout, Layout dst_layout) {
  if (src_layout.Equals(dst_layout)) { return raw; }
  CHECK(src_layout.defined() && dst_layout.defined())
    << "Cannot insert layout transform because there are undefined layouts";
  CHECK(BijectiveLayoutNode::make(src_layout, dst_layout).defined())
    << "Cannot insert layout transform because there are inconvertible layouts: "
    << src_layout << " v.s. " << dst_layout;
  static auto &transform_op = Op::Get("layout_transform");
  NodePtr<LayoutTransformAttrs> attrs = make_node<LayoutTransformAttrs>();
  attrs->src_layout = src_layout.name();
  attrs->dst_layout = dst_layout.name();
  Call transform = CallNode::make(transform_op, {raw}, Attrs{attrs});
  return std::move(transform);
}

// Memorize layout transform so we can reuse internal transformed nodes
class TransformMemorizerNode : public Node {
 public:
  // map from (Expr, src_layout, dst_layout) to transformed Expr
  using TransformKey = std::tuple<const Node*, std::string, std::string>;
struct key_hash : public std::function<std::size_t(TransformKey)> {
    std::size_t operator()(const TransformKey& k) const {
      return dmlc::HashCombine<std::string>(dmlc::HashCombine<std::string>(
              std::hash<const Node*>()(std::get<0>(k)), std::get<1>(k)), (std::get<2>(k)));
    }
  };

  std::unordered_map<TransformKey, Expr, key_hash> memo;
  static constexpr const char *_type_key = "relay.alter_op_layout.TransformMemorizerNode";
  TVM_DECLARE_NODE_TYPE_INFO(TransformMemorizerNode, Node);
};

class TransformMemorizer : public NodeRef {
 public:
  TransformMemorizer() {}
  explicit TransformMemorizer(NodePtr<Node> n) : NodeRef(n) {}

  TransformMemorizerNode* operator->() {
    return static_cast<TransformMemorizerNode*>(node_.get());
  }

  // Transform layout with memorizer
  Expr Transform(Expr raw, const Layout& src_layout, const Layout& dst_layout) {
    if (src_layout.Equals(dst_layout)) { return raw; }

    std::tuple<const Node*, std::string, std::string> key =
        std::make_tuple<>(raw.get(), src_layout.name(), dst_layout.name());
    auto& memo = operator->()->memo;

    auto iter = memo.find(key);
    if (iter != memo.end()) {
      return iter->second;
    } else {
      Expr transform = TransformLayout(raw, src_layout, dst_layout);
      memo[key] = transform;
      return transform;
    }
  }

  using ContainerType = TransformMemorizerNode;
};

// TempExprNode during layout transform
// Instance of this expr will be Realized to normal expr ultimately
class LayoutAlternatedExprNode : public TempExprNode {
 public:
  Expr value;
  Layout old_layout;
  Layout new_layout;
  TransformMemorizer memorizer;

  Expr Realize() const final {
    // NOTE: use a copy to discard the "const" qualifier
    TransformMemorizer tmp_memorizer = memorizer;
    // fallback to old layout
    return tmp_memorizer.Transform(value, new_layout, old_layout);
  }

  void VisitAttrs(AttrVisitor *v) final {
    v->Visit("value", &value);
    v->Visit("old_layout", &old_layout);
    v->Visit("new_layout", &new_layout);
  }

  static constexpr const char *_type_key = "relay.alter_op_layout.LayoutAlternatedExprNode";
  TVM_DECLARE_NODE_TYPE_INFO(LayoutAlternatedExprNode, TempExprNode);
};

RELAY_DEFINE_NODE_REF(LayoutAlternatedExpr, LayoutAlternatedExprNode, TempExpr);

// Call registered FInferCorrectLayout of an op.
// Parameters are the same as the parameters for FInferCorrectLayout
// Returns inferred_input_layout, inferred_output_layout, success
std::tuple<Array<Layout>, Array<Layout>, bool> CallInfer(
    const Call& call,
    const Array<Layout>& new_in_layouts,
    const Array<Layout>& old_in_layouts,
    const Array<Array<IndexExpr> > &old_in_shapes) {
  static auto finfer_layout = Op::GetAttr<FInferCorrectLayout>("FInferCorrectLayout");

  Op op = Downcast<Op>(call->op);
  if (finfer_layout.count(op)) {
    Array<Array<Layout> > inferred_layouts;
    inferred_layouts = finfer_layout[op](call->attrs, new_in_layouts,
                                         old_in_layouts, old_in_shapes);
    CHECK_EQ(inferred_layouts.size(), 2)
      << "FInferCorrectLayout should return an array with size of 2";
    for (auto x : inferred_layouts) {
      for (auto y : x) {
        if (!y.defined()) {  // inference fails
          return std::make_tuple<>(Array<Layout>(nullptr), Array<Layout>(nullptr), false);
        }
      }
    }
    return std::make_tuple<>(inferred_layouts[0], inferred_layouts[1], true);
  } else {
    return std::make_tuple<>(Array<Layout>(nullptr), Array<Layout>(nullptr), false);
  }
}

// Call registered FTVMAlterOpLayout of an op
// Returns the altered expression
Call CallAlter(const Call& ref_call,
               const std::vector<Expr>& new_args) {
  static auto falter_layout = Op::GetAttr<FTVMAlterOpLayout>("FTVMAlterOpLayout");
  Op op = Downcast<Op>(ref_call->op);

  Expr new_e;
  bool modified = false;
  if (falter_layout.count(op)) {
    tvm::Array<tvm::Tensor> tinfos;
    for (auto expr : ref_call->args) {
      auto ttype = expr->type_as<TensorTypeNode>();
      tinfos.push_back(tvm::placeholder(ttype->shape, ttype->dtype));
    }
    Expr altered_value = falter_layout[op](ref_call->attrs, new_args, tinfos);
    if (altered_value.defined()) {
      new_e = altered_value;
      modified = true;
    }
  }
  if (!modified) {
    new_e = CallNode::make(ref_call->op, new_args,
                           ref_call->attrs);
  }

  const CallNode *new_call = new_e.as<CallNode>();
  CHECK(new_call) << "Can only replace the original operator with another call node";
  return GetRef<Call>(new_call);
}

Expr AlterOpLayoutRewrite(const Call &ref_call,
                          const Array<Expr> &new_args,
                          const NodeRef& ctx) {
  std::vector<LayoutAlternatedExpr> inputs;
  std::vector<Expr> normal_new_args;
  Array<Array<IndexExpr> > input_shapes;

  // NOTE: discard the "const" qualifier
  TransformMemorizer memorizer = Downcast<TransformMemorizer>(ctx);

  // fill incomplete state and flatten tuple
  auto push_back_one_arg = [&inputs, memorizer](Expr arg) {
    // We always expect LayoutAlternatedExpr.
    // This is used to convert the normal Expr to LayoutAlternatedExpr.
    if (const LayoutAlternatedExprNode *inp = arg.as<LayoutAlternatedExprNode>()) {
      inputs.push_back(GetRef<LayoutAlternatedExpr>(inp));
      return inp->value;
    } else {
      auto inode = make_node<LayoutAlternatedExprNode>();
      inode->value = arg;
      inode->memorizer = memorizer;
      inputs.push_back(LayoutAlternatedExpr(inode));
      return arg;
    }
  };

  for (auto new_arg : new_args) {
    // NOTE: do not support nested tuple
    if (new_arg->is_type<TupleNode>()) {
      Tuple tuple_new_arg = Downcast<Tuple>(new_arg);
      std::vector<Expr> fields;
      for (auto x : tuple_new_arg->fields) {
        Expr tmp = push_back_one_arg(x);
        fields.push_back(tmp);
      }
      normal_new_args.push_back(TupleNode::make(fields));
    } else {
      Expr tmp = push_back_one_arg(new_arg);
      normal_new_args.push_back(tmp);
    }
  }

  // old_in, new_in = state[inputs]
  Array<Layout> old_in, old_out, new_in, new_out, new_in2;
  for (auto inp : inputs) {
    old_in.push_back(inp->old_layout);
    new_in.push_back(inp->new_layout);
  }

  for (auto arg : ref_call->args) {
    if (arg->is_type<TupleNode>()) {  // flatten tuple
      Tuple tuple_arg = Downcast<Tuple>(arg);
      for (auto x : tuple_arg->fields) {
        input_shapes.push_back(x->type_as<TensorTypeNode>()->shape);
      }
    } else {
      input_shapes.push_back(arg->type_as<TensorTypeNode>()->shape);
    }
  }

  // old_in, old_out = op.infer(old_in)
  bool success = false;
  std::tie(old_in, old_out, success) = CallInfer(ref_call,
                                                 Array<Layout>(nullptr),
                                                 old_in, input_shapes);
  if (!success) { return Expr(nullptr); }
  CHECK_EQ(old_in.size(), new_in.size());

  // if new_in == 'undef':  new_in = old_in
  for (size_t i = 0; i < new_in.size(); ++i) {
    if (!new_in[i].defined()) {
      new_in.Set(i, old_in[i]);
    }
  }

  // new_op = alter(op)
  Call new_call = CallAlter(ref_call, normal_new_args);

  // new_in2, new_out = op.infer(new_in)
  if (new_call->op->is_type<OpNode>()) {
    success = false;
    std::tie(new_in2, new_out, success) = CallInfer(new_call, new_in, old_in, input_shapes);
    if (!success) { return Expr(nullptr); }
  } else {
    return Expr(nullptr);
  }

  CHECK_EQ(new_out.size(), old_out.size())
    << "The number of output nodes should keep the same during alter_op_layout";
  CHECK_EQ(new_in.size(), new_in2.size())
    << "The number of input nodes should keep the same during alter_op_layout";

  // if (new_in != new_in2): insert transform (new_in -> new_in2)
  Array<Expr> transformed_args;
  size_t pt = 0;
  for (auto arg : new_call->args) {
    if (arg->is_type<TupleNode>()) {  // unflatten tuple
      Tuple tuple_arg = Downcast<Tuple>(arg);
      std::vector<Expr> transformed_tuple_arg;
      for (auto arg_item : tuple_arg->fields) {
          transformed_tuple_arg.push_back(
                  memorizer.Transform(arg_item, new_in[pt], new_in2[pt]));
          pt++;
      }
      transformed_args.push_back(TupleNode::make(transformed_tuple_arg));
    } else {
      transformed_args.push_back(
              memorizer.Transform(arg, new_in[pt], new_in2[pt]));
      pt++;
    }
  }
  CHECK_EQ(pt, inputs.size());

  // state[node] = (old_out, new_out)
  // (handle tuple output)
  if (ref_call->checked_type()->is_type<TupleTypeNode>()) {
    Expr tuple_output = CallNode::make(new_call->op, transformed_args,
                                       new_call->attrs);
    Array<Expr> fields;
    for (size_t i = 0; i < new_out.size(); ++i) {
      auto rnode = make_node<LayoutAlternatedExprNode>();
      rnode->value = TupleGetItemNode::make(tuple_output, i);
      rnode->old_layout = old_out[i];
      rnode->new_layout = new_out[i];
      rnode->memorizer = memorizer;
      fields.push_back(Expr(rnode));
    }
    return TupleNode::make(fields);
  } else {
    auto rnode = make_node<LayoutAlternatedExprNode>();
    CHECK_EQ(new_out.size(), 1);
    rnode->value = CallNode::make(new_call->op, transformed_args,
                                  new_call->attrs);
    rnode->old_layout = old_out[0];
    rnode->new_layout = new_out[0];
    rnode->memorizer = memorizer;
    return Expr(rnode);
  }
}

// Limiations:
// 1. the altered op should have the same number of arguments as the previous one
// 2. do not support nested tuple arguments
TVM_REGISTER_API("relay._ir_pass.AlterOpLayout")
.set_body([](TVMArgs args, TVMRetValue *ret) {
  TransformMemorizer transformMemorizer(make_node<TransformMemorizerNode>());
  auto fcontext = [&](const Call& call) -> NodeRef{
    return transformMemorizer;
  };

  *ret = ForwardRewrite(args[0], AlterOpLayoutRewrite, fcontext);
});

}  // namespace alter_op_layout

}  // namespace relay
}  // namespace tvm
<|endoftext|>


<commit_before>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// 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.

#include <cassert>
#include "app/canvas.hh"
#include "bitmap/pattern.hh"
#include "geo/geo-func.hh"
#include "geo/int-rect.hh"
#include "text/formatting.hh"
#include "tools/standard-tool.hh"
#include "tools/tool-actions.hh"
#include "util/pos-info.hh"
#include "util/tool-util.hh"

namespace faint{

static bool should_pick_to_pattern(const PosInfo& info){
  return info.modifiers.Primary();
}

static bool should_anchor_topleft(const PosInfo& info){
  return info.modifiers.Secondary();
}

static Paint pattern_get_hovered_paint(const PosInside& info){
  // Do not pick invisible object insides. Include the floating
  // selection if hovered
  return get_hovered_paint(info,
    include_hidden_fill(false),
    include_floating_selection(true));
}

class PickerTool : public StandardTool {
public:
  PickerTool(ToolActions& actions)
    : StandardTool(ToolId::PICKER, Settings()),
      m_actions(actions)
  {}

  void Draw(FaintDC&, Overlays&, const PosInfo&) override{
  }

  bool DrawBeforeZoom(Layer) const override{
    return false;
  }

  Command* GetCommand() override{
    assert(false);
    return nullptr;
  }

  Cursor GetCursor(const PosInfo& info) const override{
    if (should_pick_to_pattern(info)){
      return should_anchor_topleft(info) ?
        Cursor::PICKER_PATTERN_TOPLEFT : Cursor::PICKER_PATTERN;
    }
    return Cursor::PICKER;
  }

  IntRect GetRefreshRect(const RefreshInfo&) const override{
    return {};
  }

  ToolResult MouseDown(const PosInfo& info) override{
    return inside_canvas(info).Visit(
      [&](const PosInside& info){
        const auto paintSetting = fg_or_bg(info);

        const auto& bg = info->canvas.GetBitmap();
        if (should_pick_to_pattern(info) && bg.IsSet()){
          bool anchorTopLeft = should_anchor_topleft(info);
          IntPoint anchor = anchorTopLeft ?
            IntPoint(0,0) : // Image top left
            floored(info->pos);
          Pattern pattern(bg.Get(),
            anchor, object_aligned_t(!anchorTopLeft));
          m_actions.Set(paintSetting, Paint(pattern));
          return ToolResult::NONE;
        }

        m_actions.Set(paintSetting, pattern_get_hovered_paint(info));
        return ToolResult::NONE;
      },

      [](){
        // Outside
        return ToolResult::NONE;
      });
  }

  ToolResult MouseUp(const PosInfo&) override{
    return ToolResult::NONE;
  }

  ToolResult MouseMove(const PosInfo& info) override{
    inside_canvas(info).Visit(
      [](const PosInside& info){
        // Inside canvas
        if (should_pick_to_pattern(info)){
          info->status.SetMainText("Click to use image as pattern");
          info->status.SetText(should_anchor_topleft(info) ?
            "Anchor: Top Left (0,0)" :
            space_sep("Anchor:", bracketed(str_floor((info->pos)))));
        }
        else{
          Paint paint(pattern_get_hovered_paint(info));
          info->status.SetMainText("");
          info->status.SetText(space_sep(str(paint),
            bracketed(str_floor(info->pos))));
        }
      },
      [&info](){
        // Outside
        info.status.SetMainText("");
        info.status.SetText(bracketed(str_floor(info.pos)));
      });
    return ToolResult::NONE;
  }

  ToolResult Preempt(const PosInfo&) override{
    return ToolResult::NONE;
  }

  ToolActions& m_actions;
};

Tool* picker_tool(ToolActions& actions){
  return new PickerTool(actions);
}

} // namespace
<commit_msg>Simplified picker.<commit_after>// -*- coding: us-ascii-unix -*-
// Copyright 2012 Lukas Kemmer
//
// 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.

#include <cassert>
#include "app/canvas.hh"
#include "bitmap/pattern.hh"
#include "geo/geo-func.hh"
#include "geo/int-rect.hh"
#include "text/formatting.hh"
#include "tools/standard-tool.hh"
#include "tools/tool-actions.hh"
#include "util/pos-info.hh"
#include "util/tool-util.hh"

namespace faint{

static bool should_pick_to_pattern(const PosInfo& info){
  return info.modifiers.Primary();
}

static bool should_anchor_topleft(const PosInfo& info){
  return info.modifiers.Secondary();
}

static Paint pattern_get_hovered_paint(const PosInside& info){
  // Pick either the hovered object fill, the color at the pixel in
  // the background or floating raster selection.
  // Do not pick invisible object insides.
  return get_hovered_paint(info,
    include_hidden_fill(false),
    include_floating_selection(true));
}

static Paint pick_to_pattern(const PosInside& info, const Bitmap& bg){
  // Pick the background bitmap as a pattern, anchored around either
  // the click-point or the top-left corner
  bool anchorTopLeft = should_anchor_topleft(info);
  IntPoint anchor = anchorTopLeft ?
    IntPoint(0,0) : // Image top left
    floored(info->pos);
  Pattern pattern(bg, anchor, object_aligned_t(!anchorTopLeft));
  return Paint(pattern);
}

static ToolResult pick(const PosInside& info, ToolActions& actions){
  const auto& bg = info->canvas.GetBitmap();

  Paint paint = (should_pick_to_pattern(info) && bg.IsSet()) ?
    pick_to_pattern(info, bg.Get()) :
    pattern_get_hovered_paint(info);

  actions.Set(fg_or_bg(info), paint);
  return ToolResult::NONE;
}

class PickerTool : public StandardTool {
public:
  PickerTool(ToolActions& actions)
    : StandardTool(ToolId::PICKER, Settings()),
      m_actions(actions)
  {}

  void Draw(FaintDC&, Overlays&, const PosInfo&) override{
  }

  bool DrawBeforeZoom(Layer) const override{
    return false;
  }

  Command* GetCommand() override{
    assert(false);
    return nullptr;
  }

  Cursor GetCursor(const PosInfo& info) const override{
    if (should_pick_to_pattern(info)){
      return should_anchor_topleft(info) ?
        Cursor::PICKER_PATTERN_TOPLEFT : Cursor::PICKER_PATTERN;
    }
    return Cursor::PICKER;
  }

  IntRect GetRefreshRect(const RefreshInfo&) const override{
    return {};
  }

  ToolResult MouseDown(const PosInfo& info) override{
    return inside_canvas(info).Visit(
      [&](const PosInside& insidePos){
        return pick(insidePos, m_actions);
      },
      otherwise(ToolResult::NONE));
  }

  ToolResult MouseUp(const PosInfo&) override{
    return ToolResult::NONE;
  }

  ToolResult MouseMove(const PosInfo& info) override{
    inside_canvas(info).Visit(
      [](const PosInside& info){
        // Inside canvas
        if (should_pick_to_pattern(info)){
          info->status.SetMainText("Click to use image as pattern");
          info->status.SetText(should_anchor_topleft(info) ?
            "Anchor: Top Left (0,0)" :
            space_sep("Anchor:", bracketed(str_floor((info->pos)))));
        }
        else{
          Paint paint(pattern_get_hovered_paint(info));
          info->status.SetMainText("");
          info->status.SetText(space_sep(str(paint),
            bracketed(str_floor(info->pos))));
        }
      },
      [&info](){
        // Outside
        info.status.SetMainText("");
        info.status.SetText(bracketed(str_floor(info.pos)));
      });
    return ToolResult::NONE;
  }

  ToolResult Preempt(const PosInfo&) override{
    return ToolResult::NONE;
  }

  ToolActions& m_actions;
};

Tool* picker_tool(ToolActions& actions){
  return new PickerTool(actions);
}

} // namespace
<|endoftext|>