<commit_before>#include <iostream>

#include <gtest/gtest.h>

#include "drake/systems/plants/RigidBodyTree.h"

namespace drake {
namespace systems {
namespace plants {
namespace test {
namespace {

class RigidBodyTreeTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
    // Instantiates the rigid body tree.
    tree = std::unique_ptr<RigidBodyTree>(new RigidBodyTree());

    // Defines a four rigid bodies.
    r1b1 = std::allocate_shared<RigidBody>(
      Eigen::aligned_allocator<RigidBody>());
    r1b1->model_name = "robot1";
    r1b1->linkname = "body1";

    r2b1 = std::allocate_shared<RigidBody>(
      Eigen::aligned_allocator<RigidBody>());
    r2b1->model_name = "robot2";
    r2b1->linkname = "body1";

    r3b1 = std::allocate_shared<RigidBody>(
      Eigen::aligned_allocator<RigidBody>());
    r3b1->model_name = "robot3";
    r3b1->linkname = "body1";

    r4b1 = std::allocate_shared<RigidBody>(
      Eigen::aligned_allocator<RigidBody>());
    r4b1->model_name = "robot4";
    r4b1->linkname = "body1";
  }

 public:
  std::unique_ptr<RigidBodyTree> tree;
  std::shared_ptr<RigidBody> r1b1;
  std::shared_ptr<RigidBody> r2b1;
  std::shared_ptr<RigidBody> r3b1;
  std::shared_ptr<RigidBody> r4b1;
};

TEST_F(RigidBodyTreeTest, TestAddFloatingJointNoOffset) {
  // Adds rigid bodies r1b1 and r2b1 to the rigid body tree and verify they can
  // be found.
  tree->add_rigid_body(r1b1);
  tree->add_rigid_body(r2b1);

  EXPECT_TRUE(tree->findLink("body1", "robot1") != nullptr);
  EXPECT_TRUE(tree->findLink("body1", "robot2") != nullptr);
  EXPECT_TRUE(tree->findLink("body2", "robot1") == nullptr);
  EXPECT_TRUE(tree->findLink("body2", "robot2") == nullptr);

  // Adds floating joints that connect r1b1 and r2b1 to the rigid body tree's
  // world link at zero offset.
  tree->AddFloatingJoint(DrakeJoint::QUATERNION,
                        {r1b1->body_index, r2b1->body_index});

  // Verfies that the two rigid bodies are located in the correct place.
  const DrakeJoint& jointR1B1 = tree->findLink("body1", "robot1")->getJoint();
  EXPECT_TRUE(jointR1B1.isFloating());
  EXPECT_TRUE(jointR1B1.getTransformToParentBody().matrix() ==
              Eigen::Isometry3d::Identity().matrix());

  const DrakeJoint& jointR2B1 = tree->findLink("body1", "robot2")->getJoint();
  EXPECT_TRUE(jointR2B1.isFloating());
  EXPECT_TRUE(jointR2B1.getTransformToParentBody().matrix() ==
              Eigen::Isometry3d::Identity().matrix());
}

TEST_F(RigidBodyTreeTest, TestAddFloatingJointWithOffset) {
  // Adds rigid bodies r1b1 and r2b1 to the rigid body tree.
  tree->add_rigid_body(r1b1);
  tree->add_rigid_body(r2b1);

  // Adds floating joints that connect r1b1 and r2b1 to the rigid body tree's
  // world link at offset x = 1, y = 1, z = 1.
  Eigen::Isometry3d T_r1and2_to_world;
  {
    Eigen::Vector3d xyz, rpy;
    xyz << 1, 1, 1;
    rpy = Eigen::Vector3d::Zero();
    T_r1and2_to_world.matrix() << rpy2rotmat(rpy), xyz, 0, 0, 0, 1;
  }

  auto weld_to_frame = std::allocate_shared<RigidBodyFrame>(
      Eigen::aligned_allocator<RigidBodyFrame>(), "world", nullptr,
      T_r1and2_to_world);

  tree->AddFloatingJoint(DrakeJoint::QUATERNION,
                        {r1b1->body_index, r2b1->body_index}, weld_to_frame);

  // Verfies that the two rigid bodies are located in the correct place.
  const DrakeJoint& jointR1B1 = tree->findLink("body1", "robot1")->getJoint();
  EXPECT_TRUE(jointR1B1.isFloating());
  EXPECT_TRUE(jointR1B1.getTransformToParentBody().matrix() ==
              T_r1and2_to_world.matrix());

  const DrakeJoint& jointR2B1 = tree->findLink("body1", "robot2")->getJoint();
  EXPECT_TRUE(jointR2B1.isFloating());
  EXPECT_TRUE(jointR2B1.getTransformToParentBody().matrix() ==
              T_r1and2_to_world.matrix());
}

TEST_F(RigidBodyTreeTest, TestAddFloatingJointWeldToLink) {
  // Adds rigid body r1b1 to the rigid body tree and welds it to the world with
  // zero offset. Verifies that it is in the correct place.
  tree->add_rigid_body(r1b1);

  tree->AddFloatingJoint(DrakeJoint::QUATERNION, {r1b1->body_index});

  // Adds rigid body r2b1 to the rigid body tree and welds it to r1b1 with
  // offset x = 1, y = 1, z = 1. Verifies that it is in the correct place.
  tree->add_rigid_body(r2b1);

  Eigen::Isometry3d T_r2_to_r1;
  {
    Eigen::Vector3d xyz, rpy;
    xyz << 1, 1, 1;
    rpy = Eigen::Vector3d::Zero();
    T_r2_to_r1.matrix() << rpy2rotmat(rpy), xyz, 0, 0, 0, 1;
  }

  auto r2b1_weld = std::allocate_shared<RigidBodyFrame>(
      Eigen::aligned_allocator<RigidBodyFrame>(), "body1",
      tree->findLink("body1", "robot1"), T_r2_to_r1);

  tree->AddFloatingJoint(DrakeJoint::QUATERNION, {r2b1->body_index}, r2b1_weld);

  // Adds rigid body r3b1 and r4b1 to the rigid body tree and welds it to r2b1
  // with offset x = 2, y = 2, z = 2. Verifies that it is in the correct place.
  tree->add_rigid_body(r3b1);
  tree->add_rigid_body(r4b1);

  Eigen::Isometry3d T_r3_and_r4_to_r2;
  {
    Eigen::Vector3d xyz, rpy;
    xyz << 2, 2, 2;
    rpy = Eigen::Vector3d::Zero();
    T_r3_and_r4_to_r2.matrix() << rpy2rotmat(rpy), xyz, 0, 0, 0, 1;
  }

  auto r3b1_and_r4b1_weld = std::allocate_shared<RigidBodyFrame>(
      Eigen::aligned_allocator<RigidBodyFrame>(), "body1",
      tree->findLink("body1", "robot2"), T_r3_and_r4_to_r2);

  tree->AddFloatingJoint(DrakeJoint::QUATERNION,
                        {r3b1->body_index, r4b1->body_index},
                        r3b1_and_r4b1_weld);

  EXPECT_TRUE(tree->findLink("body1", "robot1")
                  ->getJoint()
                  .getTransformToParentBody()
                  .matrix() == Eigen::Isometry3d::Identity().matrix());

  EXPECT_TRUE(tree->findLink("body1", "robot2")
                  ->getJoint()
                  .getTransformToParentBody()
                  .matrix() == T_r2_to_r1.matrix());

  EXPECT_TRUE(tree->findLink("body1", "robot3")
                  ->getJoint()
                  .getTransformToParentBody()
                  .matrix() == T_r3_and_r4_to_r2.matrix());

  EXPECT_TRUE(tree->findLink("body1", "robot4")
                  ->getJoint()
                  .getTransformToParentBody()
                  .matrix() == T_r3_and_r4_to_r2.matrix());
}

}  // namespace
}  // namespace test
}  // namespace plants
}  // namespace systems
}  // namespace drake
<commit_msg>Grammar fix.<commit_after>#include <iostream>

#include <gtest/gtest.h>

#include "drake/systems/plants/RigidBodyTree.h"

namespace drake {
namespace systems {
namespace plants {
namespace test {
namespace {

class RigidBodyTreeTest : public ::testing::Test {
 protected:
  virtual void SetUp() {
    // Instantiates the rigid body tree.
    tree = std::unique_ptr<RigidBodyTree>(new RigidBodyTree());

    // Defines four rigid bodies.
    r1b1 = std::allocate_shared<RigidBody>(
      Eigen::aligned_allocator<RigidBody>());
    r1b1->model_name = "robot1";
    r1b1->linkname = "body1";

    r2b1 = std::allocate_shared<RigidBody>(
      Eigen::aligned_allocator<RigidBody>());
    r2b1->model_name = "robot2";
    r2b1->linkname = "body1";

    r3b1 = std::allocate_shared<RigidBody>(
      Eigen::aligned_allocator<RigidBody>());
    r3b1->model_name = "robot3";
    r3b1->linkname = "body1";

    r4b1 = std::allocate_shared<RigidBody>(
      Eigen::aligned_allocator<RigidBody>());
    r4b1->model_name = "robot4";
    r4b1->linkname = "body1";
  }

 public:
  std::unique_ptr<RigidBodyTree> tree;
  std::shared_ptr<RigidBody> r1b1;
  std::shared_ptr<RigidBody> r2b1;
  std::shared_ptr<RigidBody> r3b1;
  std::shared_ptr<RigidBody> r4b1;
};

TEST_F(RigidBodyTreeTest, TestAddFloatingJointNoOffset) {
  // Adds rigid bodies r1b1 and r2b1 to the rigid body tree and verify they can
  // be found.
  tree->add_rigid_body(r1b1);
  tree->add_rigid_body(r2b1);

  EXPECT_TRUE(tree->findLink("body1", "robot1") != nullptr);
  EXPECT_TRUE(tree->findLink("body1", "robot2") != nullptr);
  EXPECT_TRUE(tree->findLink("body2", "robot1") == nullptr);
  EXPECT_TRUE(tree->findLink("body2", "robot2") == nullptr);

  // Adds floating joints that connect r1b1 and r2b1 to the rigid body tree's
  // world link at zero offset.
  tree->AddFloatingJoint(DrakeJoint::QUATERNION,
                        {r1b1->body_index, r2b1->body_index});

  // Verfies that the two rigid bodies are located in the correct place.
  const DrakeJoint& jointR1B1 = tree->findLink("body1", "robot1")->getJoint();
  EXPECT_TRUE(jointR1B1.isFloating());
  EXPECT_TRUE(jointR1B1.getTransformToParentBody().matrix() ==
              Eigen::Isometry3d::Identity().matrix());

  const DrakeJoint& jointR2B1 = tree->findLink("body1", "robot2")->getJoint();
  EXPECT_TRUE(jointR2B1.isFloating());
  EXPECT_TRUE(jointR2B1.getTransformToParentBody().matrix() ==
              Eigen::Isometry3d::Identity().matrix());
}

TEST_F(RigidBodyTreeTest, TestAddFloatingJointWithOffset) {
  // Adds rigid bodies r1b1 and r2b1 to the rigid body tree.
  tree->add_rigid_body(r1b1);
  tree->add_rigid_body(r2b1);

  // Adds floating joints that connect r1b1 and r2b1 to the rigid body tree's
  // world link at offset x = 1, y = 1, z = 1.
  Eigen::Isometry3d T_r1and2_to_world;
  {
    Eigen::Vector3d xyz, rpy;
    xyz << 1, 1, 1;
    rpy = Eigen::Vector3d::Zero();
    T_r1and2_to_world.matrix() << rpy2rotmat(rpy), xyz, 0, 0, 0, 1;
  }

  auto weld_to_frame = std::allocate_shared<RigidBodyFrame>(
      Eigen::aligned_allocator<RigidBodyFrame>(), "world", nullptr,
      T_r1and2_to_world);

  tree->AddFloatingJoint(DrakeJoint::QUATERNION,
                        {r1b1->body_index, r2b1->body_index}, weld_to_frame);

  // Verfies that the two rigid bodies are located in the correct place.
  const DrakeJoint& jointR1B1 = tree->findLink("body1", "robot1")->getJoint();
  EXPECT_TRUE(jointR1B1.isFloating());
  EXPECT_TRUE(jointR1B1.getTransformToParentBody().matrix() ==
              T_r1and2_to_world.matrix());

  const DrakeJoint& jointR2B1 = tree->findLink("body1", "robot2")->getJoint();
  EXPECT_TRUE(jointR2B1.isFloating());
  EXPECT_TRUE(jointR2B1.getTransformToParentBody().matrix() ==
              T_r1and2_to_world.matrix());
}

TEST_F(RigidBodyTreeTest, TestAddFloatingJointWeldToLink) {
  // Adds rigid body r1b1 to the rigid body tree and welds it to the world with
  // zero offset. Verifies that it is in the correct place.
  tree->add_rigid_body(r1b1);

  tree->AddFloatingJoint(DrakeJoint::QUATERNION, {r1b1->body_index});

  // Adds rigid body r2b1 to the rigid body tree and welds it to r1b1 with
  // offset x = 1, y = 1, z = 1. Verifies that it is in the correct place.
  tree->add_rigid_body(r2b1);

  Eigen::Isometry3d T_r2_to_r1;
  {
    Eigen::Vector3d xyz, rpy;
    xyz << 1, 1, 1;
    rpy = Eigen::Vector3d::Zero();
    T_r2_to_r1.matrix() << rpy2rotmat(rpy), xyz, 0, 0, 0, 1;
  }

  auto r2b1_weld = std::allocate_shared<RigidBodyFrame>(
      Eigen::aligned_allocator<RigidBodyFrame>(), "body1",
      tree->findLink("body1", "robot1"), T_r2_to_r1);

  tree->AddFloatingJoint(DrakeJoint::QUATERNION, {r2b1->body_index}, r2b1_weld);

  // Adds rigid body r3b1 and r4b1 to the rigid body tree and welds it to r2b1
  // with offset x = 2, y = 2, z = 2. Verifies that it is in the correct place.
  tree->add_rigid_body(r3b1);
  tree->add_rigid_body(r4b1);

  Eigen::Isometry3d T_r3_and_r4_to_r2;
  {
    Eigen::Vector3d xyz, rpy;
    xyz << 2, 2, 2;
    rpy = Eigen::Vector3d::Zero();
    T_r3_and_r4_to_r2.matrix() << rpy2rotmat(rpy), xyz, 0, 0, 0, 1;
  }

  auto r3b1_and_r4b1_weld = std::allocate_shared<RigidBodyFrame>(
      Eigen::aligned_allocator<RigidBodyFrame>(), "body1",
      tree->findLink("body1", "robot2"), T_r3_and_r4_to_r2);

  tree->AddFloatingJoint(DrakeJoint::QUATERNION,
                        {r3b1->body_index, r4b1->body_index},
                        r3b1_and_r4b1_weld);

  EXPECT_TRUE(tree->findLink("body1", "robot1")
                  ->getJoint()
                  .getTransformToParentBody()
                  .matrix() == Eigen::Isometry3d::Identity().matrix());

  EXPECT_TRUE(tree->findLink("body1", "robot2")
                  ->getJoint()
                  .getTransformToParentBody()
                  .matrix() == T_r2_to_r1.matrix());

  EXPECT_TRUE(tree->findLink("body1", "robot3")
                  ->getJoint()
                  .getTransformToParentBody()
                  .matrix() == T_r3_and_r4_to_r2.matrix());

  EXPECT_TRUE(tree->findLink("body1", "robot4")
                  ->getJoint()
                  .getTransformToParentBody()
                  .matrix() == T_r3_and_r4_to_r2.matrix());
}

}  // namespace
}  // namespace test
}  // namespace plants
}  // namespace systems
}  // namespace drake
<|endoftext|>


<commit_before>#include "jss_beautify.h"

namespace JSON
{
    std::string js_beautify(std::string const& str, int pretab)
    {
        std::stringstream sstr;
        int tab = pretab;
        bool was_closed;
        for (auto const& i : str)
        {
            if (i == '{')
            {
                sstr << "\n";
                for (int j = 0; j != tab; ++j) sstr << '\t';
                sstr << "{\n";
                tab++;
                for (int j = 0; j != tab; ++j) sstr << '\t';
                was_closed = false;
            }
            else if (i == '}')
            {
                tab--;
                sstr << "\n";
                for (int j = 0; j != tab; ++j) sstr << '\t';
                sstr << "}\n";
                was_closed = true;
            }
            else if (i == ',')
            {
                if (was_closed)
                {
                    auto temp = sstr.str();
                    sstr.str({});
                    sstr.clear();
                    temp.pop_back();
                    sstr << temp;
                }
                sstr << ",\n";
                for (int j = 0; j != tab; ++j) sstr << '\t';
                was_closed = false;
            }
            else
            {
                sstr << i;
                was_closed = false;
            }
        }
        return sstr.str();
    }
}
<commit_msg>quick fix. NOTE: Redo this VERY DIRTY method<commit_after>#include "jss_beautify.h"

namespace JSON
{
    std::string js_beautify(std::string const& str, int pretab)
    {
        std::stringstream sstr;
        int tab = pretab;
        bool was_closed = false;
        for (auto const& i : str)
        {
            if (i == '{')
            {
                sstr << "\n";
                for (int j = 0; j != tab; ++j) sstr << '\t';
                sstr << "{\n";
                tab++;
                for (int j = 0; j != tab; ++j) sstr << '\t';
                was_closed = false;
            }
            else if (i == '}')
            {
                tab--;
                sstr << "\n";
                for (int j = 0; j != tab; ++j) sstr << '\t';
                sstr << "}\n";
                was_closed = true;
            }
            else if (i == ',')
            {
                if (was_closed)
                {
                    auto temp = sstr.str();
                    sstr.str({});
                    sstr.clear();
                    temp.pop_back();
                    sstr << temp;
                }
                sstr << ",\n";
                for (int j = 0; j != tab; ++j) sstr << '\t';
                was_closed = false;
            }
            else
            {
                sstr << i;
                was_closed = false;
            }
        }
        return sstr.str();
    }
}
<|endoftext|>


<commit_before>/*
 * This file is part of accounts-ui
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "service-selection-page.h"
#include "account-sync-handler.h"
#include "provider-plugin-process.h"
#include "service-settings-widget.h"
#include "accountsmanagersingleton.h"
#include "account-setup-finished-page.h"
#include "provider-plugin-process.h"
#include "basic-header-widget.h"
#include "last-page-actions.h"

//Qt
#include <QStringListModel>
#include <QItemSelection>
#include <QDebug>

//Meegotouch
#include <MLayout>
#include <MList>
#include <MGridLayoutPolicy>
#include <MLinearLayoutPolicy>
#include <MButton>
#include <MWidgetCreator>
#include <MContainer>
#include <MSeparator>
#include <MBasicListItem>
#include <MWidgetAction>
#include <MImageWidget>
#include <MLabel>
#include <MLocale>
#include <MPannableViewport>
#include <MPositionIndicator>

//libAccounts
#include <Accounts/Provider>
#include <Accounts/Manager>

namespace AccountsUI {

M_REGISTER_WIDGET_NO_CREATE(ServiceSelectionPage)

//TODO: write the service plugins
class ServiceSelectionPagePrivate
{
public:
    ServiceSelectionPagePrivate()
        : serviceList(0),
        saveAction(0),
        cancelAction(0),
        context(0),
        syncHandler(0),
        layoutServicePolicy(0)
        {}
    ~ServiceSelectionPagePrivate() {}

    MList *serviceList;
    MAction *saveAction;
    MAction *cancelAction;
    AbstractAccountSetupContext *context;
    QList<AbstractServiceSetupContext*> serviceContextList;
    QList<AbstractSetupContext*> abstractContexts;
    AccountSyncHandler *syncHandler;
    MLinearLayoutPolicy *layoutServicePolicy;
    QString serviceType;
    QMap<QString, bool> serviceStatusMap;
};

ServiceSelectionPage::ServiceSelectionPage(AbstractAccountSetupContext *context,
                                           QList<AbstractServiceSetupContext*>
                                           &serviceContextList,
                                           QGraphicsItem *parent)
        : MApplicationPage(parent),
        d_ptr(new ServiceSelectionPagePrivate())
{
    Q_D(ServiceSelectionPage);
    setStyleName("AccountsUiPage");
    d->context = context;
    d->serviceType = context->serviceType();
    d->context->account()->selectService(NULL);
    d->context->account()->setEnabled(true);
    d->serviceContextList = serviceContextList;
    d->abstractContexts.append(d->context);

    d->syncHandler = new AccountSyncHandler(this);
    connect(d->syncHandler, SIGNAL(syncStateChanged(const SyncState&)),
            this, SLOT(onSyncStateChanged(const SyncState&)));
    pannableViewport()->positionIndicator()->setStyleName("CommonPositionIndicatorInverted");
}

void ServiceSelectionPage::serviceSelected(QModelIndex index)
{
    Q_UNUSED(index);
}

ServiceSelectionPage::~ServiceSelectionPage()
{
    delete d_ptr;
}

void ServiceSelectionPage::createContent()
{
    Q_D(ServiceSelectionPage);

    setComponentsDisplayMode(EscapeButton, MApplicationPageModel::Hide);

    //we need a central widget to get the right layout size under the menubar
    MWidget *centralWidget = new MWidget();
    setCentralWidget(centralWidget);
    MLayout *layout = new MLayout(centralWidget);
    MLinearLayoutPolicy *layoutPolicy = new MLinearLayoutPolicy(layout, Qt::Vertical);
    layoutPolicy->setSpacing(0);

    if (d->context) {
        MWidget *upperWidget = new MWidget(this);
        MLayout *upperLayout = new MLayout(upperWidget);
        MLinearLayoutPolicy *upperLayoutPolicy = new MLinearLayoutPolicy(upperLayout, Qt::Vertical);
        upperLayoutPolicy->setSpacing(0);

        MLayout *topLayout = new MLayout();
        MLinearLayoutPolicy *topLayoutPolicy = new MLinearLayoutPolicy(topLayout, Qt::Vertical);
        topLayoutPolicy->setSpacing(0);

        QString providerName(d->context->account()->providerName());
        // xml file that describes the ui elements for the provider
        Accounts::Provider *provider = AccountsManager::instance()->provider(providerName);
        if (provider) {
            // loading common catalog to show device name string
            MLocale locale;
            QString catalog = "common";
            if (!catalog.isEmpty() && !locale.isInstalledTrCatalog(catalog)) {
                locale.installTrCatalog(catalog);
                MLocale::setDefault(locale);
            }

            // provider info header
            QDomElement root = provider->domDocument().documentElement();
            QDomElement providerIcon = root.firstChildElement("icon");
            QString providerIconId = providerIcon.text();

            BasicHeaderWidget *providerInfoItem = new BasicHeaderWidget(IconWithTitleAndSubTitle, this);
            providerInfoItem->setImage(providerIconId);
            providerInfoItem->setTitle(qtTrId(provider->displayName().toLatin1()));
            providerInfoItem->setSubtitle(qtTrId(d->context->account()->displayName().toLatin1()));
            providerInfoItem->setObjectName("wgServiceSelectionPageBasicListItem");
            topLayoutPolicy->addItem(providerInfoItem, Qt::AlignLeft | Qt::AlignVCenter);

            // account connected message
            QString accountConnectedMessageId;
            QDomElement accountConnectedMessage= root.firstChildElement("account-connected-message");
            if (!accountConnectedMessage.isNull()) {
                // display a account connected message for provider
                accountConnectedMessageId =
                        qtTrId((accountConnectedMessage.text()).toLatin1()).arg(qtTrId("qtn_comm_product_n9"));
            }
            else {
                // default message for service selection.
                accountConnectedMessageId = qtTrId("qtn_acc_enable_services_in_apps");
            }
            MLabel *accountConnectedMessageLabel=
                    new MLabel(accountConnectedMessageId);
            accountConnectedMessageLabel->setWordWrap(1);
            accountConnectedMessageLabel->setStyleName("CommonBodyTextInverted");
            topLayoutPolicy->addItem(accountConnectedMessageLabel, Qt::AlignLeft | Qt::AlignVCenter);
        }

        MSeparator *separatorTop = new MSeparator(this);
        separatorTop->setStyleName("CommonItemDividerInverted");
        separatorTop->setOrientation(Qt::Horizontal);

        upperLayoutPolicy->addItem(topLayout);
        upperLayoutPolicy->addItem(separatorTop);

        layoutPolicy->addItem(upperWidget);
    }

    MWidget *serviceWidget = new MWidget();
    MLayout *serviceSettingLayout = new MLayout(serviceWidget);
    d->layoutServicePolicy = new MLinearLayoutPolicy(serviceSettingLayout, Qt::Vertical);
    d->layoutServicePolicy->setSpacing(0);

    for (int i = 0; i < d->serviceContextList.count(); i++) {
        //ServiceSettingsWidget sets the display widget of the changing settings
        ServiceSettingsWidget *settingsWidget =
            new ServiceSettingsWidget(d->serviceContextList.at(i), serviceWidget,
                                      ServiceSettingsWidget::MandatorySettings |
                                      ServiceSettingsWidget::EnableButton,
                                      true);
        const Accounts::Service *service = d->serviceContextList.at(i)->service();
        emit serviceEnabled(service->name(), true);
        d->serviceStatusMap.insert(service->name(), true);
        d->abstractContexts.append(d->serviceContextList.at(i));
        d->layoutServicePolicy->addItem(settingsWidget, Qt::AlignLeft);
        connect (settingsWidget, SIGNAL(serviceEnabled(const QString&, bool)),
                 this, SIGNAL(serviceEnabled(const QString&, bool)));
        connect (settingsWidget, SIGNAL(serviceEnabled(const QString&, bool)),
                 this, SLOT(setEnabledService(const QString&, bool)));
    }

    layoutPolicy->addItem(serviceWidget, Qt::AlignLeft);

    //% "DONE"
    d->saveAction = new MAction(qtTrId("qtn_comm_command_done"), centralWidget);
    d->saveAction->setLocation(MAction::ToolBarLocation);
    addAction(d->saveAction);

    //% "CANCEL"
    d->cancelAction = new MAction(qtTrId("qtn_comm_cancel"), centralWidget);
    d->cancelAction->setLocation(MAction::ToolBarLocation);
    addAction(d->cancelAction);
    layoutPolicy->addStretch();

    connect(d->saveAction, SIGNAL(triggered()),
            this, SLOT(onAccountInstallButton()));
    connect(d->cancelAction, SIGNAL(triggered()),
            this, SLOT(cancel()));
    connect(d->serviceList, SIGNAL(itemClicked(QModelIndex)),
            this,SLOT(serviceSelected(QModelIndex)));

    connect(this, SIGNAL(backButtonClicked()),
            this, SLOT(close()));
}

void ServiceSelectionPage::onAccountInstallButton()
{
    Q_D(ServiceSelectionPage);

    disconnect(d->saveAction, SIGNAL(triggered()),
               this, SLOT(onAccountInstallButton()));

    setProgressIndicatorVisible(true);
    for (int i = 0; i < d->serviceContextList.count(); i++) {
        const Accounts::Service *service = d->serviceContextList.at(i)->service();
        QMap<QString, bool>::iterator mapIterator =
                d->serviceStatusMap.find(service->name());
        if (mapIterator == d->serviceStatusMap.end())
            continue;
        d->serviceContextList.at(i)->enable(mapIterator.value());
        d->serviceStatusMap.remove(mapIterator.key());
    }
    d->syncHandler->validate(d->abstractContexts);
}

void ServiceSelectionPage::onSyncStateChanged(const SyncState &state)
{
    Q_D(ServiceSelectionPage);

    switch (state) {
        case Validated:
            d->syncHandler->store(d->abstractContexts);
            break;
        case Stored:
            if (ProviderPluginProcess::instance()->lastPageActions().
                serviceActions().isEmpty()) {
                connect(d->context->account(), SIGNAL(synced()),
                        ProviderPluginProcess::instance(), SLOT(quit()));
                d->context->account()->sync();
            } else {
                d->context->account()->sync();
                AccountSetupFinishedPage *page = new AccountSetupFinishedPage(d->context);
                page->appear();
            }
            break;
        default:
            connect(d->saveAction, SIGNAL(triggered()),
                    this, SLOT(onAccountInstallButton()));
            connect(d->cancelAction, SIGNAL(triggered()),
                    this, SLOT(cancel()));
            setProgressIndicatorVisible(false);
            return;
    }
}

void ServiceSelectionPage::setWidget(MWidget *widget)
{
    Q_D(ServiceSelectionPage);

    if (d->layoutServicePolicy && widget)
        d->layoutServicePolicy->addItem(widget);
}

void ServiceSelectionPage::setEnabledService(const QString &serviceName,
                                            bool enabled)
{
    Q_D(ServiceSelectionPage);
    d->serviceStatusMap[serviceName] = enabled;
}

void ServiceSelectionPage::cancel()
{
    ProviderPluginProcess::instance()->setReturnToAccountsList(true);
}

} //namespace
<commit_msg>Fixing: 261426 - Facebook chat option to be turned off by default<commit_after>/*
 * This file is part of accounts-ui
 *
 * Copyright (C) 2009-2010 Nokia Corporation.
 *
 * Contact: Alberto Mardegan <alberto.mardegan@nokia.com>
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA
 */

#include "service-selection-page.h"
#include "account-sync-handler.h"
#include "provider-plugin-process.h"
#include "service-settings-widget.h"
#include "accountsmanagersingleton.h"
#include "account-setup-finished-page.h"
#include "provider-plugin-process.h"
#include "basic-header-widget.h"
#include "last-page-actions.h"

//Qt
#include <QStringListModel>
#include <QItemSelection>
#include <QDebug>

//Meegotouch
#include <MLayout>
#include <MList>
#include <MGridLayoutPolicy>
#include <MLinearLayoutPolicy>
#include <MButton>
#include <MWidgetCreator>
#include <MContainer>
#include <MSeparator>
#include <MBasicListItem>
#include <MWidgetAction>
#include <MImageWidget>
#include <MLabel>
#include <MLocale>
#include <MPannableViewport>
#include <MPositionIndicator>

//libAccounts
#include <Accounts/Provider>
#include <Accounts/Manager>

namespace AccountsUI {

M_REGISTER_WIDGET_NO_CREATE(ServiceSelectionPage)

//TODO: write the service plugins
class ServiceSelectionPagePrivate
{
public:
    ServiceSelectionPagePrivate()
        : serviceList(0),
        saveAction(0),
        cancelAction(0),
        context(0),
        syncHandler(0),
        layoutServicePolicy(0)
        {}
    ~ServiceSelectionPagePrivate() {}

    MList *serviceList;
    MAction *saveAction;
    MAction *cancelAction;
    AbstractAccountSetupContext *context;
    QList<AbstractServiceSetupContext*> serviceContextList;
    QList<AbstractSetupContext*> abstractContexts;
    AccountSyncHandler *syncHandler;
    MLinearLayoutPolicy *layoutServicePolicy;
    QString serviceType;
    QMap<QString, bool> serviceStatusMap;
};

ServiceSelectionPage::ServiceSelectionPage(AbstractAccountSetupContext *context,
                                           QList<AbstractServiceSetupContext*>
                                           &serviceContextList,
                                           QGraphicsItem *parent)
        : MApplicationPage(parent),
        d_ptr(new ServiceSelectionPagePrivate())
{
    Q_D(ServiceSelectionPage);
    setStyleName("AccountsUiPage");
    d->context = context;
    d->serviceType = context->serviceType();
    d->context->account()->selectService(NULL);
    d->context->account()->setEnabled(true);
    d->serviceContextList = serviceContextList;
    d->abstractContexts.append(d->context);

    d->syncHandler = new AccountSyncHandler(this);
    connect(d->syncHandler, SIGNAL(syncStateChanged(const SyncState&)),
            this, SLOT(onSyncStateChanged(const SyncState&)));
    pannableViewport()->positionIndicator()->setStyleName("CommonPositionIndicatorInverted");
}

void ServiceSelectionPage::serviceSelected(QModelIndex index)
{
    Q_UNUSED(index);
}

ServiceSelectionPage::~ServiceSelectionPage()
{
    delete d_ptr;
}

void ServiceSelectionPage::createContent()
{
    Q_D(ServiceSelectionPage);

    setComponentsDisplayMode(EscapeButton, MApplicationPageModel::Hide);

    //we need a central widget to get the right layout size under the menubar
    MWidget *centralWidget = new MWidget();
    setCentralWidget(centralWidget);
    MLayout *layout = new MLayout(centralWidget);
    MLinearLayoutPolicy *layoutPolicy = new MLinearLayoutPolicy(layout, Qt::Vertical);
    layoutPolicy->setSpacing(0);

    if (d->context) {
        MWidget *upperWidget = new MWidget(this);
        MLayout *upperLayout = new MLayout(upperWidget);
        MLinearLayoutPolicy *upperLayoutPolicy = new MLinearLayoutPolicy(upperLayout, Qt::Vertical);
        upperLayoutPolicy->setSpacing(0);

        MLayout *topLayout = new MLayout();
        MLinearLayoutPolicy *topLayoutPolicy = new MLinearLayoutPolicy(topLayout, Qt::Vertical);
        topLayoutPolicy->setSpacing(0);

        QString providerName(d->context->account()->providerName());
        // xml file that describes the ui elements for the provider
        Accounts::Provider *provider = AccountsManager::instance()->provider(providerName);
        if (provider) {
            // loading common catalog to show device name string
            MLocale locale;
            QString catalog = "common";
            if (!catalog.isEmpty() && !locale.isInstalledTrCatalog(catalog)) {
                locale.installTrCatalog(catalog);
                MLocale::setDefault(locale);
            }

            // provider info header
            QDomElement root = provider->domDocument().documentElement();
            QDomElement providerIcon = root.firstChildElement("icon");
            QString providerIconId = providerIcon.text();

            BasicHeaderWidget *providerInfoItem = new BasicHeaderWidget(IconWithTitleAndSubTitle, this);
            providerInfoItem->setImage(providerIconId);
            providerInfoItem->setTitle(qtTrId(provider->displayName().toLatin1()));
            providerInfoItem->setSubtitle(qtTrId(d->context->account()->displayName().toLatin1()));
            providerInfoItem->setObjectName("wgServiceSelectionPageBasicListItem");
            topLayoutPolicy->addItem(providerInfoItem, Qt::AlignLeft | Qt::AlignVCenter);

            // account connected message
            QString accountConnectedMessageId;
            QDomElement accountConnectedMessage= root.firstChildElement("account-connected-message");
            if (!accountConnectedMessage.isNull()) {
                // display a account connected message for provider
                accountConnectedMessageId =
                        qtTrId((accountConnectedMessage.text()).toLatin1()).arg(qtTrId("qtn_comm_product_n9"));
            }
            else {
                // default message for service selection.
                accountConnectedMessageId = qtTrId("qtn_acc_enable_services_in_apps");
            }
            MLabel *accountConnectedMessageLabel=
                    new MLabel(accountConnectedMessageId);
            accountConnectedMessageLabel->setWordWrap(1);
            accountConnectedMessageLabel->setStyleName("CommonBodyTextInverted");
            topLayoutPolicy->addItem(accountConnectedMessageLabel, Qt::AlignLeft | Qt::AlignVCenter);
        }

        MSeparator *separatorTop = new MSeparator(this);
        separatorTop->setStyleName("CommonItemDividerInverted");
        separatorTop->setOrientation(Qt::Horizontal);

        upperLayoutPolicy->addItem(topLayout);
        upperLayoutPolicy->addItem(separatorTop);

        layoutPolicy->addItem(upperWidget);
    }

    MWidget *serviceWidget = new MWidget();
    MLayout *serviceSettingLayout = new MLayout(serviceWidget);
    d->layoutServicePolicy = new MLinearLayoutPolicy(serviceSettingLayout, Qt::Vertical);
    d->layoutServicePolicy->setSpacing(0);

    for (int i = 0; i < d->serviceContextList.count(); i++) {
        bool serviceStatus = true;
        const Accounts::Service *service = d->serviceContextList.at(i)->service();
        QDomElement root = service->domDocument().documentElement();
        QDomElement serviceDefaultStatus = root.firstChildElement("default-status");
        if (serviceDefaultStatus.text() == "false")
            serviceStatus = false;
        //ServiceSettingsWidget sets the display widget of the changing settings
        ServiceSettingsWidget *settingsWidget =
            new ServiceSettingsWidget(d->serviceContextList.at(i), serviceWidget,
                                      ServiceSettingsWidget::MandatorySettings |
                                      ServiceSettingsWidget::EnableButton,
                                      serviceStatus);

        emit serviceEnabled(service->name(), true);
        d->serviceStatusMap.insert(service->name(), true);
        d->abstractContexts.append(d->serviceContextList.at(i));
        d->layoutServicePolicy->addItem(settingsWidget, Qt::AlignLeft);
        connect (settingsWidget, SIGNAL(serviceEnabled(const QString&, bool)),
                 this, SIGNAL(serviceEnabled(const QString&, bool)));
        connect (settingsWidget, SIGNAL(serviceEnabled(const QString&, bool)),
                 this, SLOT(setEnabledService(const QString&, bool)));
    }

    layoutPolicy->addItem(serviceWidget, Qt::AlignLeft);

    //% "DONE"
    d->saveAction = new MAction(qtTrId("qtn_comm_command_done"), centralWidget);
    d->saveAction->setLocation(MAction::ToolBarLocation);
    addAction(d->saveAction);

    //% "CANCEL"
    d->cancelAction = new MAction(qtTrId("qtn_comm_cancel"), centralWidget);
    d->cancelAction->setLocation(MAction::ToolBarLocation);
    addAction(d->cancelAction);
    layoutPolicy->addStretch();

    connect(d->saveAction, SIGNAL(triggered()),
            this, SLOT(onAccountInstallButton()));
    connect(d->cancelAction, SIGNAL(triggered()),
            this, SLOT(cancel()));
    connect(d->serviceList, SIGNAL(itemClicked(QModelIndex)),
            this,SLOT(serviceSelected(QModelIndex)));

    connect(this, SIGNAL(backButtonClicked()),
            this, SLOT(close()));
}

void ServiceSelectionPage::onAccountInstallButton()
{
    Q_D(ServiceSelectionPage);

    disconnect(d->saveAction, SIGNAL(triggered()),
               this, SLOT(onAccountInstallButton()));

    setProgressIndicatorVisible(true);
    for (int i = 0; i < d->serviceContextList.count(); i++) {
        const Accounts::Service *service = d->serviceContextList.at(i)->service();
        QMap<QString, bool>::iterator mapIterator =
                d->serviceStatusMap.find(service->name());
        if (mapIterator == d->serviceStatusMap.end())
            continue;
        d->serviceContextList.at(i)->enable(mapIterator.value());
        d->serviceStatusMap.remove(mapIterator.key());
    }
    d->syncHandler->validate(d->abstractContexts);
}

void ServiceSelectionPage::onSyncStateChanged(const SyncState &state)
{
    Q_D(ServiceSelectionPage);

    switch (state) {
        case Validated:
            d->syncHandler->store(d->abstractContexts);
            break;
        case Stored:
            if (ProviderPluginProcess::instance()->lastPageActions().
                serviceActions().isEmpty()) {
                connect(d->context->account(), SIGNAL(synced()),
                        ProviderPluginProcess::instance(), SLOT(quit()));
                d->context->account()->sync();
            } else {
                d->context->account()->sync();
                AccountSetupFinishedPage *page = new AccountSetupFinishedPage(d->context);
                page->appear();
            }
            break;
        default:
            connect(d->saveAction, SIGNAL(triggered()),
                    this, SLOT(onAccountInstallButton()));
            connect(d->cancelAction, SIGNAL(triggered()),
                    this, SLOT(cancel()));
            setProgressIndicatorVisible(false);
            return;
    }
}

void ServiceSelectionPage::setWidget(MWidget *widget)
{
    Q_D(ServiceSelectionPage);

    if (d->layoutServicePolicy && widget)
        d->layoutServicePolicy->addItem(widget);
}

void ServiceSelectionPage::setEnabledService(const QString &serviceName,
                                            bool enabled)
{
    Q_D(ServiceSelectionPage);
    d->serviceStatusMap[serviceName] = enabled;
}

void ServiceSelectionPage::cancel()
{
    ProviderPluginProcess::instance()->setReturnToAccountsList(true);
}

} //namespace
<|endoftext|>


<commit_before>#include "ScarceMatrixData.h"
#include "Utils/counters.h"

using namespace smurff;

ScarceMatrixData::ScarceMatrixData(Eigen::SparseMatrix<double> Y)
   : MatrixDataTempl<Eigen::SparseMatrix<double> >(Y)
{
   name = "ScarceMatrixData [with NAs]";
}

void ScarceMatrixData::init_pre()
{
   MatrixDataTempl<Eigen::SparseMatrix<double> >::init_pre();

   // check no rows, nor cols withouth data
   for(unsigned mode = 0; mode < nmode(); ++mode)
   {
      auto& m = this->Y(mode);
      auto& count = num_empty[mode];
      for (int j = 0; j < m.cols(); j++)
      {
         if (m.col(j).nonZeros() == 0)
            count++;
      }
   }
}

double ScarceMatrixData::train_rmse(const SubModel& model) const
{
   double se = 0.;
   #pragma omp parallel for schedule(guided) reduction(+:se)
   for(int c = 0; c < Y().cols();++c)
   {
       for (Eigen::SparseMatrix<double>::InnerIterator it(Y(), c); it; ++it)
       {
           se += square(it.value() - predict({(int)it.row(), (int)it.col()}, model));
       }
   }
   return sqrt( se / Y().nonZeros() );
}

std::ostream& ScarceMatrixData::info(std::ostream& os, std::string indent)
{
    MatrixDataTempl<Eigen::SparseMatrix<double> >::info(os, indent);
    if (num_empty[0]) os << indent << "  Warning: " << num_empty[0] << " empty rows\n";
    if (num_empty[1]) os << indent << "  Warning: " << num_empty[1] << " empty cols\n";
    return os;
}

void ScarceMatrixData::get_pnm(const SubModel& model, int mode, int n, Eigen::VectorXd& rr, Eigen::MatrixXd& MM)
{
   COUNTER("get_pnm");
   auto &Y = this->Y(mode);

   const int num_latent = model.nlatent();
   const auto &Vf = model.V(mode);
   const int local_nnz = Y.col(n).nonZeros();
   const int total_nnz = Y.nonZeros();
   const double alpha = noise()->getAlpha();

   bool in_parallel = (local_nnz >10000) || ((double)local_nnz > (double)total_nnz / 100.);
   if (in_parallel) {
       const int task_size = ceil(local_nnz / 100.0);
       auto from = Y.outerIndexPtr()[n];
       auto to = Y.outerIndexPtr()[n+1];
       thread_vector<Eigen::VectorXd> rrs(Eigen::VectorXd::Zero(num_latent));
       thread_vector<Eigen::MatrixXd> MMs(Eigen::MatrixXd::Zero(num_latent, num_latent));
       for(int j=from; j<to; j+=task_size)
       {
           #pragma omp task shared(model,Y,Vf,rrs,MMs)
           {
               auto &my_rr = rrs.local();
               auto &my_MM = MMs.local();

               for(int i=j; i<std::min(j+task_size,to); ++i)
               {
                   auto val = Y.valuePtr()[i];
                   auto idx = Y.innerIndexPtr()[i];
                   const auto &col = model.V(mode).col(idx);
                   my_rr.noalias() += col * val;
                   my_MM.triangularView<Eigen::Lower>() += col * col.transpose();
               }

               // make MM complete
               my_MM.triangularView<Eigen::Upper>() = my_MM.transpose();

           }
       }
       #pragma omp taskwait

       // accumulate + add noise
       MM += MMs.combine() * alpha;
       rr += rrs.combine() * alpha;
   }
   else
   {
      Eigen::VectorXd my_rr = Eigen::VectorXd::Zero(num_latent);
      Eigen::MatrixXd my_MM = Eigen::MatrixXd::Zero(num_latent, num_latent);

      for (Eigen::SparseMatrix<double>::InnerIterator it(Y, n); it; ++it)
      {
         const auto &col = Vf.col(it.row());
         my_rr.noalias() += col * it.value();
         my_MM.triangularView<Eigen::Lower>() += col * col.transpose();
      }

      // make MM complete
      my_MM.triangularView<Eigen::Upper>() = my_MM.transpose();

      //add noise
      my_rr.array() *= alpha;
      my_MM.array() *= alpha;

      // add to global
      rr += my_rr;
      MM += my_MM;
   }
}

void ScarceMatrixData::update_pnm(const SubModel &,int)
{
}

int ScarceMatrixData::nna() const
{
   return size() - nnz();
}
<commit_msg>fix sign warning<commit_after>#include "ScarceMatrixData.h"
#include "Utils/counters.h"

using namespace smurff;

ScarceMatrixData::ScarceMatrixData(Eigen::SparseMatrix<double> Y)
   : MatrixDataTempl<Eigen::SparseMatrix<double> >(Y)
{
   name = "ScarceMatrixData [with NAs]";
}

void ScarceMatrixData::init_pre()
{
   MatrixDataTempl<Eigen::SparseMatrix<double> >::init_pre();

   // check no rows, nor cols withouth data
   for(int mode = 0; mode < nmode(); ++mode)
   {
      auto& m = this->Y(mode);
      auto& count = num_empty[mode];
      for (int j = 0; j < m.cols(); j++)
      {
         if (m.col(j).nonZeros() == 0)
            count++;
      }
   }
}

double ScarceMatrixData::train_rmse(const SubModel& model) const
{
   double se = 0.;
   #pragma omp parallel for schedule(guided) reduction(+:se)
   for(int c = 0; c < Y().cols();++c)
   {
       for (Eigen::SparseMatrix<double>::InnerIterator it(Y(), c); it; ++it)
       {
           se += square(it.value() - predict({(int)it.row(), (int)it.col()}, model));
       }
   }
   return sqrt( se / Y().nonZeros() );
}

std::ostream& ScarceMatrixData::info(std::ostream& os, std::string indent)
{
    MatrixDataTempl<Eigen::SparseMatrix<double> >::info(os, indent);
    if (num_empty[0]) os << indent << "  Warning: " << num_empty[0] << " empty rows\n";
    if (num_empty[1]) os << indent << "  Warning: " << num_empty[1] << " empty cols\n";
    return os;
}

void ScarceMatrixData::get_pnm(const SubModel& model, int mode, int n, Eigen::VectorXd& rr, Eigen::MatrixXd& MM)
{
   COUNTER("get_pnm");
   auto &Y = this->Y(mode);

   const int num_latent = model.nlatent();
   const auto &Vf = model.V(mode);
   const int local_nnz = Y.col(n).nonZeros();
   const int total_nnz = Y.nonZeros();
   const double alpha = noise()->getAlpha();

   bool in_parallel = (local_nnz >10000) || ((double)local_nnz > (double)total_nnz / 100.);
   if (in_parallel) {
       const int task_size = ceil(local_nnz / 100.0);
       auto from = Y.outerIndexPtr()[n];
       auto to = Y.outerIndexPtr()[n+1];
       thread_vector<Eigen::VectorXd> rrs(Eigen::VectorXd::Zero(num_latent));
       thread_vector<Eigen::MatrixXd> MMs(Eigen::MatrixXd::Zero(num_latent, num_latent));
       for(int j=from; j<to; j+=task_size)
       {
           #pragma omp task shared(model,Y,Vf,rrs,MMs)
           {
               auto &my_rr = rrs.local();
               auto &my_MM = MMs.local();

               for(int i=j; i<std::min(j+task_size,to); ++i)
               {
                   auto val = Y.valuePtr()[i];
                   auto idx = Y.innerIndexPtr()[i];
                   const auto &col = model.V(mode).col(idx);
                   my_rr.noalias() += col * val;
                   my_MM.triangularView<Eigen::Lower>() += col * col.transpose();
               }

               // make MM complete
               my_MM.triangularView<Eigen::Upper>() = my_MM.transpose();

           }
       }
       #pragma omp taskwait

       // accumulate + add noise
       MM += MMs.combine() * alpha;
       rr += rrs.combine() * alpha;
   }
   else
   {
      Eigen::VectorXd my_rr = Eigen::VectorXd::Zero(num_latent);
      Eigen::MatrixXd my_MM = Eigen::MatrixXd::Zero(num_latent, num_latent);

      for (Eigen::SparseMatrix<double>::InnerIterator it(Y, n); it; ++it)
      {
         const auto &col = Vf.col(it.row());
         my_rr.noalias() += col * it.value();
         my_MM.triangularView<Eigen::Lower>() += col * col.transpose();
      }

      // make MM complete
      my_MM.triangularView<Eigen::Upper>() = my_MM.transpose();

      //add noise
      my_rr.array() *= alpha;
      my_MM.array() *= alpha;

      // add to global
      rr += my_rr;
      MM += my_MM;
   }
}

void ScarceMatrixData::update_pnm(const SubModel &,int)
{
}

int ScarceMatrixData::nna() const
{
   return size() - nnz();
}
<|endoftext|>


<commit_before>//
//  Oric.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 11/10/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "Oric.hpp"
#include "../MemoryFuzzer.hpp"

using namespace Oric;

Machine::Machine() :
	cycles_since_video_update_(0),
	use_fast_tape_hack_(false),
	typer_delay_(2500000),
	keyboard_read_count_(0),
	keyboard_(new Keyboard),
	ram_top_(0xbfff),
	paged_rom_(rom_)
{
	set_clock_rate(1000000);
	via_.set_interrupt_delegate(this);
	via_.keyboard = keyboard_;
	clear_all_keys();
	via_.tape->set_delegate(this);
	Memory::Fuzz(ram_, sizeof(ram_));
}

void Machine::configure_as_target(const StaticAnalyser::Target &target)
{
	if(target.tapes.size())
	{
		via_.tape->set_tape(target.tapes.front());
	}

	if(target.loadingCommand.length())	// TODO: and automatic loading option enabled
	{
		set_typer_for_string(target.loadingCommand.c_str());
	}

	if(target.oric.has_microdisc)
	{
		microdisc_is_enabled_ = true;
		microdisc_did_change_paging_flags(&microdisc_);
		microdisc_.set_delegate(this);
	}

	if(target.oric.use_atmos_rom)
	{
		memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_)));

		is_using_basic11_ = true;
		tape_get_byte_address_ = 0xe6c9;
		scan_keyboard_address_ = 0xf495;
		tape_speed_address_ = 0x024d;
	}
	else
	{
		memcpy(rom_, basic10_rom_.data(), std::min(basic10_rom_.size(), sizeof(rom_)));

		is_using_basic11_ = false;
		tape_get_byte_address_ = 0xe630;
		scan_keyboard_address_ = 0xf43c;
		tape_speed_address_ = 0x67;
	}
}

void Machine::set_rom(ROM rom, const std::vector<uint8_t> &data)
{
	switch(rom)
	{
		case BASIC11:	basic11_rom_ = std::move(data);		break;
		case BASIC10:	basic10_rom_ = std::move(data);		break;
		case Microdisc:	microdisc_rom_ = std::move(data);	break;
	}
}

unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
{
	if(address > ram_top_)
	{
		if(isReadOperation(operation)) *value = paged_rom_[address - ram_top_ - 1];

		// 024D = 0 => fast; otherwise slow
		// E6C9 = read byte: return byte in A
		if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end())
		{
			uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]);
			set_value_of_register(CPU6502::A, next_byte);
			set_value_of_register(CPU6502::Flags, next_byte ? 0 : CPU6502::Flag::Zero);
			*value = 0x60; // i.e. RTS
		}
	}
	else
	{
		if((address & 0xff00) == 0x0300)
		{
			if(microdisc_is_enabled_ && address >= 0x0310)
			{
				switch(address)
				{
					case 0x0310: case 0x0311: case 0x0312: case 0x0313:
						if(isReadOperation(operation)) *value = microdisc_.get_register(address);
						else microdisc_.set_register(address, *value);
					break;
					case 0x314:
						if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register();
						else microdisc_.set_control_register(*value);
					break;
					case 0x318:
						if(isReadOperation(operation)) *value = microdisc_.get_data_request_register();
					break;
				}
			}
			else
			{
				if(isReadOperation(operation)) *value = via_.get_register(address);
				else via_.set_register(address, *value);
			}
		}
		else
		{
			if(isReadOperation(operation))
				*value = ram_[address];
			else
			{
				if(address >= 0x9800 && address <= 0xc000) { update_video(); typer_delay_ = 0; }
				ram_[address] = *value;
			}
		}
	}

	if(_typer && address == scan_keyboard_address_ && operation == CPU6502::BusOperation::ReadOpcode)
	{
		// the Oric 1 misses any key pressed on the very first entry into the read keyboard routine, so don't
		// do anything until at least the second, regardless of machine
		if(!keyboard_read_count_) keyboard_read_count_++;
		else if(!_typer->type_next_character())
		{
			clear_all_keys();
			_typer.reset();
		}
	}

	via_.run_for_cycles(1);
	cycles_since_video_update_++;
	return 1;
}

void Machine::synchronise()
{
	update_video();
	via_.synchronise();
}

void Machine::update_video()
{
	video_output_->run_for_cycles(cycles_since_video_update_);
	cycles_since_video_update_ = 0;
}

void Machine::setup_output(float aspect_ratio)
{
	video_output_.reset(new VideoOutput(ram_));
	via_.ay8910.reset(new GI::AY38910());
	via_.ay8910->set_clock_rate(1000000);
}

void Machine::close_output()
{
	video_output_.reset();
	via_.ay8910.reset();
}

void Machine::mos6522_did_change_interrupt_status(void *mos6522)
{
	set_interrupt_line();
}

void Machine::set_key_state(uint16_t key, bool isPressed)
{
	if(key == KeyNMI)
	{
		set_nmi_line(isPressed);
	}
	else
	{
		if(isPressed)
			keyboard_->rows[key >> 8] |= (key & 0xff);
		else
			keyboard_->rows[key >> 8] &= ~(key & 0xff);
	}
}

void Machine::clear_all_keys()
{
	memset(keyboard_->rows, 0, sizeof(keyboard_->rows));
}

void Machine::set_use_fast_tape_hack(bool activate)
{
	use_fast_tape_hack_ = activate;
}

void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player)
{
	// set CB1
	via_.set_control_line_input(VIA::Port::B, VIA::Line::One, tape_player->get_input());
}

std::shared_ptr<Outputs::CRT::CRT> Machine::get_crt()
{
	return video_output_->get_crt();
}

std::shared_ptr<Outputs::Speaker> Machine::get_speaker()
{
	return via_.ay8910;
}

void Machine::run_for_cycles(int number_of_cycles)
{
	CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles);
}

#pragma mark - The 6522

Machine::VIA::VIA() :
	MOS::MOS6522<Machine::VIA>(),
	cycles_since_ay_update_(0),
	tape(new TapePlayer) {}

void Machine::VIA::set_control_line_output(Port port, Line line, bool value)
{
	if(line)
	{
		if(port) ay_bdir_ = value; else ay_bc1_ = value;
		update_ay();
	}
}

void Machine::VIA::set_port_output(Port port, uint8_t value, uint8_t direction_mask)
{
	if(port)
	{
		keyboard->row = value;
		tape->set_motor_control(value & 0x40);
	}
	else
	{
		ay8910->set_data_input(value);
	}
}

uint8_t Machine::VIA::get_port_input(Port port)
{
	if(port)
	{
		uint8_t column = ay8910->get_port_output(false) ^ 0xff;
		return (keyboard->rows[keyboard->row & 7] & column) ? 0x08 : 0x00;
	}
	else
	{
		return ay8910->get_data_output();
	}
}

void Machine::VIA::synchronise()
{
	ay8910->run_for_cycles(cycles_since_ay_update_);
	ay8910->flush();
	cycles_since_ay_update_ = 0;
}

void Machine::VIA::run_for_cycles(unsigned int number_of_cycles)
{
	cycles_since_ay_update_ += number_of_cycles;
	MOS::MOS6522<VIA>::run_for_cycles(number_of_cycles);
	tape->run_for_cycles((int)number_of_cycles);
}

void Machine::VIA::update_ay()
{
	ay8910->run_for_cycles(cycles_since_ay_update_);
	cycles_since_ay_update_ = 0;
	ay8910->set_control_lines( (GI::AY38910::ControlLines)((ay_bdir_ ? GI::AY38910::BCDIR : 0) | (ay_bc1_ ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2));
}

#pragma mark - TapePlayer

Machine::TapePlayer::TapePlayer() :
	Storage::Tape::BinaryTapePlayer(1000000)
{}

uint8_t Machine::TapePlayer::get_next_byte(bool fast)
{
	return (uint8_t)parser_.get_next_byte(get_tape(), fast);
}

#pragma mark - Microdisc

void Machine::microdisc_did_change_paging_flags(class Microdisc *microdisc)
{
	int flags = microdisc->get_paging_flags();
	if(!(flags&Microdisc::PagingFlags::BASICDisable))
	{
		ram_top_ = 0xbfff;
		paged_rom_ = rom_;
	}
	else
	{
		if(flags&Microdisc::PagingFlags::MicrodscDisable)
		{
			ram_top_ = 0xffff;
		}
		else
		{
			ram_top_ = 0xdfff;
			paged_rom_ = microdisc_rom_.data();
		}
	}
}

void Machine::wd1770_did_change_interrupt_request_status(WD::WD1770 *wd1770)
{
	set_interrupt_line();
}

void Machine::wd1770_did_change_data_request_status(WD::WD1770 *wd1770)
{
	// Don't care.
}

void Machine::set_interrupt_line()
{
	set_irq_line(
		via_.get_interrupt_line() ||
		(microdisc_is_enabled_ && microdisc_.get_interrupt_request_line()));
}
<commit_msg>Ensured proper default behaviour.<commit_after>//
//  Oric.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 11/10/2016.
//  Copyright © 2016 Thomas Harte. All rights reserved.
//

#include "Oric.hpp"
#include "../MemoryFuzzer.hpp"

using namespace Oric;

Machine::Machine() :
	cycles_since_video_update_(0),
	use_fast_tape_hack_(false),
	typer_delay_(2500000),
	keyboard_read_count_(0),
	keyboard_(new Keyboard),
	ram_top_(0xbfff),
	paged_rom_(rom_),
	microdisc_is_enabled_(false)
{
	set_clock_rate(1000000);
	via_.set_interrupt_delegate(this);
	via_.keyboard = keyboard_;
	clear_all_keys();
	via_.tape->set_delegate(this);
	Memory::Fuzz(ram_, sizeof(ram_));
}

void Machine::configure_as_target(const StaticAnalyser::Target &target)
{
	if(target.tapes.size())
	{
		via_.tape->set_tape(target.tapes.front());
	}

	if(target.loadingCommand.length())	// TODO: and automatic loading option enabled
	{
		set_typer_for_string(target.loadingCommand.c_str());
	}

	if(target.oric.has_microdisc)
	{
		microdisc_is_enabled_ = true;
		microdisc_did_change_paging_flags(&microdisc_);
		microdisc_.set_delegate(this);
	}

	if(target.oric.use_atmos_rom)
	{
		memcpy(rom_, basic11_rom_.data(), std::min(basic11_rom_.size(), sizeof(rom_)));

		is_using_basic11_ = true;
		tape_get_byte_address_ = 0xe6c9;
		scan_keyboard_address_ = 0xf495;
		tape_speed_address_ = 0x024d;
	}
	else
	{
		memcpy(rom_, basic10_rom_.data(), std::min(basic10_rom_.size(), sizeof(rom_)));

		is_using_basic11_ = false;
		tape_get_byte_address_ = 0xe630;
		scan_keyboard_address_ = 0xf43c;
		tape_speed_address_ = 0x67;
	}
}

void Machine::set_rom(ROM rom, const std::vector<uint8_t> &data)
{
	switch(rom)
	{
		case BASIC11:	basic11_rom_ = std::move(data);		break;
		case BASIC10:	basic10_rom_ = std::move(data);		break;
		case Microdisc:	microdisc_rom_ = std::move(data);	break;
	}
}

unsigned int Machine::perform_bus_operation(CPU6502::BusOperation operation, uint16_t address, uint8_t *value)
{
	if(address > ram_top_)
	{
		if(isReadOperation(operation)) *value = paged_rom_[address - ram_top_ - 1];

		// 024D = 0 => fast; otherwise slow
		// E6C9 = read byte: return byte in A
		if(address == tape_get_byte_address_ && paged_rom_ == rom_ && use_fast_tape_hack_ && operation == CPU6502::BusOperation::ReadOpcode && via_.tape->has_tape() && !via_.tape->get_tape()->is_at_end())
		{
			uint8_t next_byte = via_.tape->get_next_byte(!ram_[tape_speed_address_]);
			set_value_of_register(CPU6502::A, next_byte);
			set_value_of_register(CPU6502::Flags, next_byte ? 0 : CPU6502::Flag::Zero);
			*value = 0x60; // i.e. RTS
		}
	}
	else
	{
		if((address & 0xff00) == 0x0300)
		{
			if(microdisc_is_enabled_ && address >= 0x0310)
			{
				switch(address)
				{
					case 0x0310: case 0x0311: case 0x0312: case 0x0313:
						if(isReadOperation(operation)) *value = microdisc_.get_register(address);
						else microdisc_.set_register(address, *value);
					break;
					case 0x314:
						if(isReadOperation(operation)) *value = microdisc_.get_interrupt_request_register();
						else microdisc_.set_control_register(*value);
					break;
					case 0x318:
						if(isReadOperation(operation)) *value = microdisc_.get_data_request_register();
					break;
				}
			}
			else
			{
				if(isReadOperation(operation)) *value = via_.get_register(address);
				else via_.set_register(address, *value);
			}
		}
		else
		{
			if(isReadOperation(operation))
				*value = ram_[address];
			else
			{
				if(address >= 0x9800 && address <= 0xc000) { update_video(); typer_delay_ = 0; }
				ram_[address] = *value;
			}
		}
	}

	if(_typer && address == scan_keyboard_address_ && operation == CPU6502::BusOperation::ReadOpcode)
	{
		// the Oric 1 misses any key pressed on the very first entry into the read keyboard routine, so don't
		// do anything until at least the second, regardless of machine
		if(!keyboard_read_count_) keyboard_read_count_++;
		else if(!_typer->type_next_character())
		{
			clear_all_keys();
			_typer.reset();
		}
	}

	via_.run_for_cycles(1);
	cycles_since_video_update_++;
	return 1;
}

void Machine::synchronise()
{
	update_video();
	via_.synchronise();
}

void Machine::update_video()
{
	video_output_->run_for_cycles(cycles_since_video_update_);
	cycles_since_video_update_ = 0;
}

void Machine::setup_output(float aspect_ratio)
{
	video_output_.reset(new VideoOutput(ram_));
	via_.ay8910.reset(new GI::AY38910());
	via_.ay8910->set_clock_rate(1000000);
}

void Machine::close_output()
{
	video_output_.reset();
	via_.ay8910.reset();
}

void Machine::mos6522_did_change_interrupt_status(void *mos6522)
{
	set_interrupt_line();
}

void Machine::set_key_state(uint16_t key, bool isPressed)
{
	if(key == KeyNMI)
	{
		set_nmi_line(isPressed);
	}
	else
	{
		if(isPressed)
			keyboard_->rows[key >> 8] |= (key & 0xff);
		else
			keyboard_->rows[key >> 8] &= ~(key & 0xff);
	}
}

void Machine::clear_all_keys()
{
	memset(keyboard_->rows, 0, sizeof(keyboard_->rows));
}

void Machine::set_use_fast_tape_hack(bool activate)
{
	use_fast_tape_hack_ = activate;
}

void Machine::tape_did_change_input(Storage::Tape::BinaryTapePlayer *tape_player)
{
	// set CB1
	via_.set_control_line_input(VIA::Port::B, VIA::Line::One, tape_player->get_input());
}

std::shared_ptr<Outputs::CRT::CRT> Machine::get_crt()
{
	return video_output_->get_crt();
}

std::shared_ptr<Outputs::Speaker> Machine::get_speaker()
{
	return via_.ay8910;
}

void Machine::run_for_cycles(int number_of_cycles)
{
	CPU6502::Processor<Machine>::run_for_cycles(number_of_cycles);
}

#pragma mark - The 6522

Machine::VIA::VIA() :
	MOS::MOS6522<Machine::VIA>(),
	cycles_since_ay_update_(0),
	tape(new TapePlayer) {}

void Machine::VIA::set_control_line_output(Port port, Line line, bool value)
{
	if(line)
	{
		if(port) ay_bdir_ = value; else ay_bc1_ = value;
		update_ay();
	}
}

void Machine::VIA::set_port_output(Port port, uint8_t value, uint8_t direction_mask)
{
	if(port)
	{
		keyboard->row = value;
		tape->set_motor_control(value & 0x40);
	}
	else
	{
		ay8910->set_data_input(value);
	}
}

uint8_t Machine::VIA::get_port_input(Port port)
{
	if(port)
	{
		uint8_t column = ay8910->get_port_output(false) ^ 0xff;
		return (keyboard->rows[keyboard->row & 7] & column) ? 0x08 : 0x00;
	}
	else
	{
		return ay8910->get_data_output();
	}
}

void Machine::VIA::synchronise()
{
	ay8910->run_for_cycles(cycles_since_ay_update_);
	ay8910->flush();
	cycles_since_ay_update_ = 0;
}

void Machine::VIA::run_for_cycles(unsigned int number_of_cycles)
{
	cycles_since_ay_update_ += number_of_cycles;
	MOS::MOS6522<VIA>::run_for_cycles(number_of_cycles);
	tape->run_for_cycles((int)number_of_cycles);
}

void Machine::VIA::update_ay()
{
	ay8910->run_for_cycles(cycles_since_ay_update_);
	cycles_since_ay_update_ = 0;
	ay8910->set_control_lines( (GI::AY38910::ControlLines)((ay_bdir_ ? GI::AY38910::BCDIR : 0) | (ay_bc1_ ? GI::AY38910::BC1 : 0) | GI::AY38910::BC2));
}

#pragma mark - TapePlayer

Machine::TapePlayer::TapePlayer() :
	Storage::Tape::BinaryTapePlayer(1000000)
{}

uint8_t Machine::TapePlayer::get_next_byte(bool fast)
{
	return (uint8_t)parser_.get_next_byte(get_tape(), fast);
}

#pragma mark - Microdisc

void Machine::microdisc_did_change_paging_flags(class Microdisc *microdisc)
{
	int flags = microdisc->get_paging_flags();
	if(!(flags&Microdisc::PagingFlags::BASICDisable))
	{
		ram_top_ = 0xbfff;
		paged_rom_ = rom_;
	}
	else
	{
		if(flags&Microdisc::PagingFlags::MicrodscDisable)
		{
			ram_top_ = 0xffff;
		}
		else
		{
			ram_top_ = 0xdfff;
			paged_rom_ = microdisc_rom_.data();
		}
	}
}

void Machine::wd1770_did_change_interrupt_request_status(WD::WD1770 *wd1770)
{
	set_interrupt_line();
}

void Machine::wd1770_did_change_data_request_status(WD::WD1770 *wd1770)
{
	// Don't care.
}

void Machine::set_interrupt_line()
{
	set_irq_line(
		via_.get_interrupt_line() ||
		(microdisc_is_enabled_ && microdisc_.get_interrupt_request_line()));
}
<|endoftext|>


<commit_before>/*
 * A Remote Debugger for SpiderMonkey Java Script engine.
 * Copyright (C) 2014-2015 Sławomir Wojtasiak
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef JAR_SRC_FACADE_H_
#define JAR_SRC_FACADE_H_

#include <string>
#include <map>

#include <utils.hpp>
#include <threads.hpp>
#include <log.hpp>

#define MAX_CLIENT_QUEUE_LENGTH 4096

namespace JSR {

// Holds client related events, which should be
// identified by client's id.
class ClientEvent : public Utils::Event {
public:
    ClientEvent(int code,  int clientId);
    virtual ~ClientEvent();
public:
    int getID() const;
private:
    int _clientId;
};

/**
 * Represents one command.
 */
class Command {
public:
    static const int BROADCAST = -1;
    Command();
    Command( int clientId, int contextId, const std::string &command );
    Command( int clientId, int contextId, char *buffer, int offset, size_t size );
    Command( const Command &command );
    Command& operator =( const Command &command );
    virtual ~Command();
    virtual const std::string& getValue() const;
    virtual int getClientId() const;
    virtual int getContextId() const;
private:
    std::string _command;
    int _clientId;
    int _contextId;
};

typedef Utils::BlockingQueue<Command> command_queue;

/**
 * Default implementation of the client class.
 */
class Client {
public:
    /**
     * Creates client instance for a given ID.
     * @param id Client's ID.
     */
    Client( int id );
    virtual ~Client();
public:
    /**
     * Disconnects the client. This method shouldn't block nor raise
     * any exceptions. If anything failed, just log it inside of this
     * method and return as if nothing happened.
     */
    virtual void disconnect();
    /**
     * Returns true if client is still connected.
     */
    virtual bool isConnected() const;
    /**
     * Gets numeric client ID. No matter what technology is used
     * to handle the client<->server communication we have to provide
     * a numeric client's ID just to identify the client using
     * a primitive value not prone to the memory deallocation.
     * @return Client's ID.
     */
    virtual int getID() const;
    /**
     * Gets input blocking queue.
     */
    virtual Utils::BlockingQueue<Command>& getInQueue();
    /**
     * Gets output blocking queue.
     */
    virtual Utils::BlockingQueue<Command>& getOutQueue();
private:
    // Queue for input commands.
    Utils::BlockingQueue<Command> _inCommands;
    // Queue for output commands.
    Utils::BlockingQueue<Command> _outCommands;
    // Client's ID.
    int _clientID;
};

/**
 * Component responsible for managing all the client
 * used by the server. It's mainly responsible for
 * the disposing procedure.
 */
class ClientManager : public Utils::EventEmitter {
public:
    ClientManager();
    virtual ~ClientManager();
public:
    /**
     * Starts client's manager.
     */
    virtual void start();
    /**
     * Adds client to the manager. It does nothing than
     * just informing the manager that there is a client
     * that should be disposed later, when the manager is shut
     * down.
     * @return Standard JSRDBG error code in case of critical exceptions.
     */
    virtual int addClient( Client *client );
    /**
     * Adds client to the disposing queue. From the time this
     * method has been invoked, client you can forgot about the
     * client. It's manager that is responsible for disposing
     * and freeing everything.
     */
    virtual void removeClient( Client *client );
    /**
     * Sends given command to all registered clients. This
     * is not blocking operation, so if there is no space left
     * in a queue, client is silently ignored when broadcasting.
     * @param command Command to send.
     */
    virtual void broadcast( Command &command );
    /**
     * Sends command to client or client if it's a broadcasting command.
     * If command is destined for concrete client the operation is blocking
     * if client's queue is full.
     * @param command Command to be send.
     * @return True if command has been send successfully, or false otherwise (no client found).
     */
    virtual bool sendCommand( Command &command );
    /**
     * Gets a client for given ID. This method increments
     * internal counter which is then used to prevent the
     * client from being removed, so it's very important to
     * use "returnClient" when client is not needed anymore.
     * @param id Client's ID.
     * @return Client instance or NULL.
     */
    virtual Client* getClient( int id );
    /**
     * Returns the client subtracting internal pointer by one.
     * See 'getClient' above.
     */
    virtual void returnClient( Client *client );
    /**
     * Call periodically in order to execute peding
     * actions if there a re any.
     */
    virtual void periodicCleanup();
    /**
     * Disposes all the clients registered inside the manager.
     */
    virtual int stop();
    /**
     * Gets number of clients managed.
     * @return Number of clients.
     */
    virtual int getClientsCount();
private:
    /**
     * Tries to remove client and marks it as
     * one to be removed if it cannot be removed.
     * @param client Client to be removed.
     * @param eventCode Event's code.
     * @return True if operation succeeded and client has been removed.
     */
    bool tryRemoveClient( Client *client, int &eventCode );
public:
    // Client has been added to the manager.
    static const int EVENT_CODE_CLIENT_ADDED = 1;
    // Client has been removed from the manager.
    static const int EVENT_CODE_CLIENT_REMOVED = 2;
    // Client has been marked to be removed as soon as possible.
    static const int EVENT_CODE_CLIENT_MARKED_TO_REMOVE = 3;
private:
    // Handles the reference counting logic.
    class ClientWrapper {
    public:
        ClientWrapper(Client *client);
        ClientWrapper(const ClientWrapper &cpy);
        Client* getClient();
        void returnClient( Client *client );
        bool isConnected();
        bool isRemovable();
        void markRemove();
        bool isMarkedToRemove();
        void deleteClient();
    private:
        // A pointer to the client itself.
        Client *client;
        // A kind of reference counter.
        int counter;
        // True if client is marked to be removed when possible.
        bool removed;
    };
protected:
    Utils::Logger &_log;
    // Synchronized set of available clients.
    Utils::Mutex _mutex;
    // Map of managed clients.
    std::map<int,ClientWrapper> _clients;
};

/**
 * Holds client's pointer and helps to return it correctly.
 */
template<typename T>
class ClientPtrHolder : public Utils::NonCopyable {
public:
    ClientPtrHolder( ClientManager &manager, int clientId = 0 )
        : _manager(manager) {
        _client = static_cast<T*>(manager.getClient(clientId));
    }
    ~ClientPtrHolder() {
        release();
    }
    ClientPtrHolder& operator=(Client* other) {
        if( other != _client ) {
            _client = static_cast<T*>(other);
        }
        return *this;
    }
    T& operator*() const {
        return *_client;
    }
    T* operator&() const {
        return static_cast<T*>(_client);
    }
    T* operator->() const {
        return static_cast<T*>(_client);
    }
    operator bool() {
        return _client != NULL;
    }
    void release() {
        if( _client ) {
            _manager.returnClient( _client );
            _client = NULL;
        }
    }
private:
    ClientManager &_manager;
    Client *_client;
};

}

#endif /* JAR_SRC_FACADE_H_ */
<commit_msg>Make some c'tors explicit<commit_after>/*
 * A Remote Debugger for SpiderMonkey Java Script engine.
 * Copyright (C) 2014-2015 Sławomir Wojtasiak
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#ifndef JAR_SRC_FACADE_H_
#define JAR_SRC_FACADE_H_

#include <string>
#include <map>

#include <utils.hpp>
#include <threads.hpp>
#include <log.hpp>

#define MAX_CLIENT_QUEUE_LENGTH 4096

namespace JSR {

// Holds client related events, which should be
// identified by client's id.
class ClientEvent : public Utils::Event {
public:
    ClientEvent(int code,  int clientId);
    virtual ~ClientEvent();
public:
    int getID() const;
private:
    int _clientId;
};

/**
 * Represents one command.
 */
class Command {
public:
    static const int BROADCAST = -1;
    Command();
    Command( int clientId, int contextId, const std::string &command );
    Command( int clientId, int contextId, char *buffer, int offset, size_t size );
    Command( const Command &command );
    Command& operator =( const Command &command );
    virtual ~Command();
    virtual const std::string& getValue() const;
    virtual int getClientId() const;
    virtual int getContextId() const;
private:
    std::string _command;
    int _clientId;
    int _contextId;
};

typedef Utils::BlockingQueue<Command> command_queue;

/**
 * Default implementation of the client class.
 */
class Client {
public:
    /**
     * Creates client instance for a given ID.
     * @param id Client's ID.
     */
    explicit Client( int id );
    virtual ~Client();
public:
    /**
     * Disconnects the client. This method shouldn't block nor raise
     * any exceptions. If anything failed, just log it inside of this
     * method and return as if nothing happened.
     */
    virtual void disconnect();
    /**
     * Returns true if client is still connected.
     */
    virtual bool isConnected() const;
    /**
     * Gets numeric client ID. No matter what technology is used
     * to handle the client<->server communication we have to provide
     * a numeric client's ID just to identify the client using
     * a primitive value not prone to the memory deallocation.
     * @return Client's ID.
     */
    virtual int getID() const;
    /**
     * Gets input blocking queue.
     */
    virtual Utils::BlockingQueue<Command>& getInQueue();
    /**
     * Gets output blocking queue.
     */
    virtual Utils::BlockingQueue<Command>& getOutQueue();
private:
    // Queue for input commands.
    Utils::BlockingQueue<Command> _inCommands;
    // Queue for output commands.
    Utils::BlockingQueue<Command> _outCommands;
    // Client's ID.
    int _clientID;
};

/**
 * Component responsible for managing all the client
 * used by the server. It's mainly responsible for
 * the disposing procedure.
 */
class ClientManager : public Utils::EventEmitter {
public:
    ClientManager();
    virtual ~ClientManager();
public:
    /**
     * Starts client's manager.
     */
    virtual void start();
    /**
     * Adds client to the manager. It does nothing than
     * just informing the manager that there is a client
     * that should be disposed later, when the manager is shut
     * down.
     * @return Standard JSRDBG error code in case of critical exceptions.
     */
    virtual int addClient( Client *client );
    /**
     * Adds client to the disposing queue. From the time this
     * method has been invoked, client you can forgot about the
     * client. It's manager that is responsible for disposing
     * and freeing everything.
     */
    virtual void removeClient( Client *client );
    /**
     * Sends given command to all registered clients. This
     * is not blocking operation, so if there is no space left
     * in a queue, client is silently ignored when broadcasting.
     * @param command Command to send.
     */
    virtual void broadcast( Command &command );
    /**
     * Sends command to client or client if it's a broadcasting command.
     * If command is destined for concrete client the operation is blocking
     * if client's queue is full.
     * @param command Command to be send.
     * @return True if command has been send successfully, or false otherwise (no client found).
     */
    virtual bool sendCommand( Command &command );
    /**
     * Gets a client for given ID. This method increments
     * internal counter which is then used to prevent the
     * client from being removed, so it's very important to
     * use "returnClient" when client is not needed anymore.
     * @param id Client's ID.
     * @return Client instance or NULL.
     */
    virtual Client* getClient( int id );
    /**
     * Returns the client subtracting internal pointer by one.
     * See 'getClient' above.
     */
    virtual void returnClient( Client *client );
    /**
     * Call periodically in order to execute peding
     * actions if there a re any.
     */
    virtual void periodicCleanup();
    /**
     * Disposes all the clients registered inside the manager.
     */
    virtual int stop();
    /**
     * Gets number of clients managed.
     * @return Number of clients.
     */
    virtual int getClientsCount();
private:
    /**
     * Tries to remove client and marks it as
     * one to be removed if it cannot be removed.
     * @param client Client to be removed.
     * @param eventCode Event's code.
     * @return True if operation succeeded and client has been removed.
     */
    bool tryRemoveClient( Client *client, int &eventCode );
public:
    // Client has been added to the manager.
    static const int EVENT_CODE_CLIENT_ADDED = 1;
    // Client has been removed from the manager.
    static const int EVENT_CODE_CLIENT_REMOVED = 2;
    // Client has been marked to be removed as soon as possible.
    static const int EVENT_CODE_CLIENT_MARKED_TO_REMOVE = 3;
private:
    // Handles the reference counting logic.
    class ClientWrapper {
    public:
        explicit ClientWrapper(Client *client);
        ClientWrapper(const ClientWrapper &cpy);
        Client* getClient();
        void returnClient( Client *client );
        bool isConnected();
        bool isRemovable();
        void markRemove();
        bool isMarkedToRemove();
        void deleteClient();
    private:
        // A pointer to the client itself.
        Client *client;
        // A kind of reference counter.
        int counter;
        // True if client is marked to be removed when possible.
        bool removed;
    };
protected:
    Utils::Logger &_log;
    // Synchronized set of available clients.
    Utils::Mutex _mutex;
    // Map of managed clients.
    std::map<int,ClientWrapper> _clients;
};

/**
 * Holds client's pointer and helps to return it correctly.
 */
template<typename T>
class ClientPtrHolder : public Utils::NonCopyable {
public:
    explicit ClientPtrHolder( ClientManager &manager, int clientId = 0 )
        : _manager(manager) {
        _client = static_cast<T*>(manager.getClient(clientId));
    }
    ~ClientPtrHolder() {
        release();
    }
    ClientPtrHolder& operator=(Client* other) {
        if( other != _client ) {
            _client = static_cast<T*>(other);
        }
        return *this;
    }
    T& operator*() const {
        return *_client;
    }
    T* operator&() const {
        return static_cast<T*>(_client);
    }
    T* operator->() const {
        return static_cast<T*>(_client);
    }
    operator bool() {
        return _client != NULL;
    }
    void release() {
        if( _client ) {
            _manager.returnClient( _client );
            _client = NULL;
        }
    }
private:
    ClientManager &_manager;
    Client *_client;
};

}

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


<commit_before>//===-- SIAnnotateControlFlow.cpp -  ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Annotates the control flow with hardware specific intrinsics.
//
//===----------------------------------------------------------------------===//

#include "AMDGPU.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"

using namespace llvm;

namespace {

// Complex types used in this pass
typedef std::pair<BasicBlock *, Value *> StackEntry;
typedef SmallVector<StackEntry, 16> StackVector;

// Intrinsic names the control flow is annotated with
static const char *IfIntrinsic = "llvm.SI.if";
static const char *ElseIntrinsic = "llvm.SI.else";
static const char *BreakIntrinsic = "llvm.SI.break";
static const char *IfBreakIntrinsic = "llvm.SI.if.break";
static const char *ElseBreakIntrinsic = "llvm.SI.else.break";
static const char *LoopIntrinsic = "llvm.SI.loop";
static const char *EndCfIntrinsic = "llvm.SI.end.cf";

class SIAnnotateControlFlow : public FunctionPass {

  static char ID;

  Type *Boolean;
  Type *Void;
  Type *Int64;
  Type *ReturnStruct;

  ConstantInt *BoolTrue;
  ConstantInt *BoolFalse;
  UndefValue *BoolUndef;
  Constant *Int64Zero;

  Constant *If;
  Constant *Else;
  Constant *Break;
  Constant *IfBreak;
  Constant *ElseBreak;
  Constant *Loop;
  Constant *EndCf;

  DominatorTree *DT;
  StackVector Stack;
  SSAUpdater PhiInserter;

  bool isTopOfStack(BasicBlock *BB);

  Value *popSaved();

  void push(BasicBlock *BB, Value *Saved);

  bool isElse(PHINode *Phi);

  void eraseIfUnused(PHINode *Phi);

  void openIf(BranchInst *Term);

  void insertElse(BranchInst *Term);

  void handleLoopCondition(Value *Cond);

  void handleLoop(BranchInst *Term);

  void closeControlFlow(BasicBlock *BB);

public:
  SIAnnotateControlFlow():
    FunctionPass(ID) { }

  virtual bool doInitialization(Module &M);

  virtual bool runOnFunction(Function &F);

  virtual const char *getPassName() const {
    return "SI annotate control flow";
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<DominatorTree>();
    AU.addPreserved<DominatorTree>();
    FunctionPass::getAnalysisUsage(AU);
  }

};

} // end anonymous namespace

char SIAnnotateControlFlow::ID = 0;

/// \brief Initialize all the types and constants used in the pass
bool SIAnnotateControlFlow::doInitialization(Module &M) {
  LLVMContext &Context = M.getContext();

  Void = Type::getVoidTy(Context);
  Boolean = Type::getInt1Ty(Context);
  Int64 = Type::getInt64Ty(Context);
  ReturnStruct = StructType::get(Boolean, Int64, (Type *)0);

  BoolTrue = ConstantInt::getTrue(Context);
  BoolFalse = ConstantInt::getFalse(Context);
  BoolUndef = UndefValue::get(Boolean);
  Int64Zero = ConstantInt::get(Int64, 0);

  If = M.getOrInsertFunction(
    IfIntrinsic, ReturnStruct, Boolean, (Type *)0);

  Else = M.getOrInsertFunction(
    ElseIntrinsic, ReturnStruct, Int64, (Type *)0);

  Break = M.getOrInsertFunction(
    BreakIntrinsic, Int64, Int64, (Type *)0);

  IfBreak = M.getOrInsertFunction(
    IfBreakIntrinsic, Int64, Boolean, Int64, (Type *)0);

  ElseBreak = M.getOrInsertFunction(
    ElseBreakIntrinsic, Int64, Int64, Int64, (Type *)0);

  Loop = M.getOrInsertFunction(
    LoopIntrinsic, Boolean, Int64, (Type *)0);

  EndCf = M.getOrInsertFunction(
    EndCfIntrinsic, Void, Int64, (Type *)0);

  return false;
}

/// \brief Is BB the last block saved on the stack ?
bool SIAnnotateControlFlow::isTopOfStack(BasicBlock *BB) {
  return Stack.back().first == BB;
}

/// \brief Pop the last saved value from the control flow stack
Value *SIAnnotateControlFlow::popSaved() {
  return Stack.pop_back_val().second;
}

/// \brief Push a BB and saved value to the control flow stack
void SIAnnotateControlFlow::push(BasicBlock *BB, Value *Saved) {
  Stack.push_back(std::make_pair(BB, Saved));
}

/// \brief Can the condition represented by this PHI node treated like
/// an "Else" block?
bool SIAnnotateControlFlow::isElse(PHINode *Phi) {
  BasicBlock *IDom = DT->getNode(Phi->getParent())->getIDom()->getBlock();
  for (unsigned i = 0, e = Phi->getNumIncomingValues(); i != e; ++i) {
    if (Phi->getIncomingBlock(i) == IDom) {

      if (Phi->getIncomingValue(i) != BoolTrue)
        return false;

    } else {
      if (Phi->getIncomingValue(i) != BoolFalse)
        return false;

    }
  }
  return true;
}

// \brief Erase "Phi" if it is not used any more
void SIAnnotateControlFlow::eraseIfUnused(PHINode *Phi) {
  if (!Phi->hasNUsesOrMore(1))
    Phi->eraseFromParent();
}

/// \brief Open a new "If" block
void SIAnnotateControlFlow::openIf(BranchInst *Term) {
  Value *Ret = CallInst::Create(If, Term->getCondition(), "", Term);
  Term->setCondition(ExtractValueInst::Create(Ret, 0, "", Term));
  push(Term->getSuccessor(1), ExtractValueInst::Create(Ret, 1, "", Term));
}

/// \brief Close the last "If" block and open a new "Else" block
void SIAnnotateControlFlow::insertElse(BranchInst *Term) {
  Value *Ret = CallInst::Create(Else, popSaved(), "", Term);
  Term->setCondition(ExtractValueInst::Create(Ret, 0, "", Term));
  push(Term->getSuccessor(1), ExtractValueInst::Create(Ret, 1, "", Term));
}

/// \brief Recursively handle the condition leading to a loop
void SIAnnotateControlFlow::handleLoopCondition(Value *Cond) {
  if (PHINode *Phi = dyn_cast<PHINode>(Cond)) {

    // Handle all non constant incoming values first
    for (unsigned i = 0, e = Phi->getNumIncomingValues(); i != e; ++i) {
      Value *Incoming = Phi->getIncomingValue(i);
      if (isa<ConstantInt>(Incoming))
        continue;

      Phi->setIncomingValue(i, BoolFalse);
      handleLoopCondition(Incoming);
    }

    BasicBlock *Parent = Phi->getParent();
    BasicBlock *IDom = DT->getNode(Parent)->getIDom()->getBlock();

    for (unsigned i = 0, e = Phi->getNumIncomingValues(); i != e; ++i) {

      Value *Incoming = Phi->getIncomingValue(i);
      if (Incoming != BoolTrue)
        continue;

      BasicBlock *From = Phi->getIncomingBlock(i);
      if (From == IDom) {
        CallInst *OldEnd = dyn_cast<CallInst>(Parent->getFirstInsertionPt());
        if (OldEnd && OldEnd->getCalledFunction() == EndCf) {
          Value *Args[] = {
            OldEnd->getArgOperand(0),
            PhiInserter.GetValueAtEndOfBlock(Parent)
          };
          Value *Ret = CallInst::Create(ElseBreak, Args, "", OldEnd);
          PhiInserter.AddAvailableValue(Parent, Ret);
          continue;
        }
      }

      TerminatorInst *Insert = From->getTerminator();
      Value *Arg = PhiInserter.GetValueAtEndOfBlock(From);
      Value *Ret = CallInst::Create(Break, Arg, "", Insert);
      PhiInserter.AddAvailableValue(From, Ret);
    }
    eraseIfUnused(Phi);

  } else if (Instruction *Inst = dyn_cast<Instruction>(Cond)) {
    BasicBlock *Parent = Inst->getParent();
    TerminatorInst *Insert = Parent->getTerminator();
    Value *Args[] = { Cond, PhiInserter.GetValueAtEndOfBlock(Parent) };
    Value *Ret = CallInst::Create(IfBreak, Args, "", Insert);
    PhiInserter.AddAvailableValue(Parent, Ret);

  } else {
    assert(0 && "Unhandled loop condition!");
  }
}

/// \brief Handle a back edge (loop)
void SIAnnotateControlFlow::handleLoop(BranchInst *Term) {
  BasicBlock *Target = Term->getSuccessor(1);
  PHINode *Broken = PHINode::Create(Int64, 0, "", &Target->front());

  PhiInserter.Initialize(Int64, "");
  PhiInserter.AddAvailableValue(Target, Broken);

  Value *Cond = Term->getCondition();
  Term->setCondition(BoolTrue);
  handleLoopCondition(Cond);

  BasicBlock *BB = Term->getParent();
  Value *Arg = PhiInserter.GetValueAtEndOfBlock(BB);
  for (pred_iterator PI = pred_begin(Target), PE = pred_end(Target);
       PI != PE; ++PI) {

    Broken->addIncoming(*PI == BB ? Arg : Int64Zero, *PI);
  }

  Term->setCondition(CallInst::Create(Loop, Arg, "", Term));
  push(Term->getSuccessor(0), Arg);
}

/// \brief Close the last opened control flow
void SIAnnotateControlFlow::closeControlFlow(BasicBlock *BB) {
  CallInst::Create(EndCf, popSaved(), "", BB->getFirstInsertionPt());
}

/// \brief Annotate the control flow with intrinsics so the backend can
/// recognize if/then/else and loops.
bool SIAnnotateControlFlow::runOnFunction(Function &F) {
  DT = &getAnalysis<DominatorTree>();

  for (df_iterator<BasicBlock *> I = df_begin(&F.getEntryBlock()),
       E = df_end(&F.getEntryBlock()); I != E; ++I) {

    BranchInst *Term = dyn_cast<BranchInst>((*I)->getTerminator());

    if (!Term || Term->isUnconditional()) {
      if (isTopOfStack(*I))
        closeControlFlow(*I);
      continue;
    }

    if (I.nodeVisited(Term->getSuccessor(1))) {
      if (isTopOfStack(*I))
        closeControlFlow(*I);
      handleLoop(Term);
      continue;
    }

    if (isTopOfStack(*I)) {
      PHINode *Phi = dyn_cast<PHINode>(Term->getCondition());
      if (Phi && Phi->getParent() == *I && isElse(Phi)) {
        insertElse(Term);
        eraseIfUnused(Phi);
        continue;
      }
      closeControlFlow(*I);
    }
    openIf(Term);
  }

  assert(Stack.empty());
  return true;
}

/// \brief Create the annotation pass
FunctionPass *llvm::createSIAnnotateControlFlowPass() {
  return new SIAnnotateControlFlow();
}
<commit_msg>R600/SI: Check for empty stack in SIAnnotateControlFlow::isTopOfStack<commit_after>//===-- SIAnnotateControlFlow.cpp -  ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
/// \file
/// Annotates the control flow with hardware specific intrinsics.
//
//===----------------------------------------------------------------------===//

#include "AMDGPU.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
#include "llvm/Transforms/Utils/SSAUpdater.h"

using namespace llvm;

namespace {

// Complex types used in this pass
typedef std::pair<BasicBlock *, Value *> StackEntry;
typedef SmallVector<StackEntry, 16> StackVector;

// Intrinsic names the control flow is annotated with
static const char *IfIntrinsic = "llvm.SI.if";
static const char *ElseIntrinsic = "llvm.SI.else";
static const char *BreakIntrinsic = "llvm.SI.break";
static const char *IfBreakIntrinsic = "llvm.SI.if.break";
static const char *ElseBreakIntrinsic = "llvm.SI.else.break";
static const char *LoopIntrinsic = "llvm.SI.loop";
static const char *EndCfIntrinsic = "llvm.SI.end.cf";

class SIAnnotateControlFlow : public FunctionPass {

  static char ID;

  Type *Boolean;
  Type *Void;
  Type *Int64;
  Type *ReturnStruct;

  ConstantInt *BoolTrue;
  ConstantInt *BoolFalse;
  UndefValue *BoolUndef;
  Constant *Int64Zero;

  Constant *If;
  Constant *Else;
  Constant *Break;
  Constant *IfBreak;
  Constant *ElseBreak;
  Constant *Loop;
  Constant *EndCf;

  DominatorTree *DT;
  StackVector Stack;
  SSAUpdater PhiInserter;

  bool isTopOfStack(BasicBlock *BB);

  Value *popSaved();

  void push(BasicBlock *BB, Value *Saved);

  bool isElse(PHINode *Phi);

  void eraseIfUnused(PHINode *Phi);

  void openIf(BranchInst *Term);

  void insertElse(BranchInst *Term);

  void handleLoopCondition(Value *Cond);

  void handleLoop(BranchInst *Term);

  void closeControlFlow(BasicBlock *BB);

public:
  SIAnnotateControlFlow():
    FunctionPass(ID) { }

  virtual bool doInitialization(Module &M);

  virtual bool runOnFunction(Function &F);

  virtual const char *getPassName() const {
    return "SI annotate control flow";
  }

  virtual void getAnalysisUsage(AnalysisUsage &AU) const {
    AU.addRequired<DominatorTree>();
    AU.addPreserved<DominatorTree>();
    FunctionPass::getAnalysisUsage(AU);
  }

};

} // end anonymous namespace

char SIAnnotateControlFlow::ID = 0;

/// \brief Initialize all the types and constants used in the pass
bool SIAnnotateControlFlow::doInitialization(Module &M) {
  LLVMContext &Context = M.getContext();

  Void = Type::getVoidTy(Context);
  Boolean = Type::getInt1Ty(Context);
  Int64 = Type::getInt64Ty(Context);
  ReturnStruct = StructType::get(Boolean, Int64, (Type *)0);

  BoolTrue = ConstantInt::getTrue(Context);
  BoolFalse = ConstantInt::getFalse(Context);
  BoolUndef = UndefValue::get(Boolean);
  Int64Zero = ConstantInt::get(Int64, 0);

  If = M.getOrInsertFunction(
    IfIntrinsic, ReturnStruct, Boolean, (Type *)0);

  Else = M.getOrInsertFunction(
    ElseIntrinsic, ReturnStruct, Int64, (Type *)0);

  Break = M.getOrInsertFunction(
    BreakIntrinsic, Int64, Int64, (Type *)0);

  IfBreak = M.getOrInsertFunction(
    IfBreakIntrinsic, Int64, Boolean, Int64, (Type *)0);

  ElseBreak = M.getOrInsertFunction(
    ElseBreakIntrinsic, Int64, Int64, Int64, (Type *)0);

  Loop = M.getOrInsertFunction(
    LoopIntrinsic, Boolean, Int64, (Type *)0);

  EndCf = M.getOrInsertFunction(
    EndCfIntrinsic, Void, Int64, (Type *)0);

  return false;
}

/// \brief Is BB the last block saved on the stack ?
bool SIAnnotateControlFlow::isTopOfStack(BasicBlock *BB) {
  return !Stack.empty() && Stack.back().first == BB;
}

/// \brief Pop the last saved value from the control flow stack
Value *SIAnnotateControlFlow::popSaved() {
  return Stack.pop_back_val().second;
}

/// \brief Push a BB and saved value to the control flow stack
void SIAnnotateControlFlow::push(BasicBlock *BB, Value *Saved) {
  Stack.push_back(std::make_pair(BB, Saved));
}

/// \brief Can the condition represented by this PHI node treated like
/// an "Else" block?
bool SIAnnotateControlFlow::isElse(PHINode *Phi) {
  BasicBlock *IDom = DT->getNode(Phi->getParent())->getIDom()->getBlock();
  for (unsigned i = 0, e = Phi->getNumIncomingValues(); i != e; ++i) {
    if (Phi->getIncomingBlock(i) == IDom) {

      if (Phi->getIncomingValue(i) != BoolTrue)
        return false;

    } else {
      if (Phi->getIncomingValue(i) != BoolFalse)
        return false;

    }
  }
  return true;
}

// \brief Erase "Phi" if it is not used any more
void SIAnnotateControlFlow::eraseIfUnused(PHINode *Phi) {
  if (!Phi->hasNUsesOrMore(1))
    Phi->eraseFromParent();
}

/// \brief Open a new "If" block
void SIAnnotateControlFlow::openIf(BranchInst *Term) {
  Value *Ret = CallInst::Create(If, Term->getCondition(), "", Term);
  Term->setCondition(ExtractValueInst::Create(Ret, 0, "", Term));
  push(Term->getSuccessor(1), ExtractValueInst::Create(Ret, 1, "", Term));
}

/// \brief Close the last "If" block and open a new "Else" block
void SIAnnotateControlFlow::insertElse(BranchInst *Term) {
  Value *Ret = CallInst::Create(Else, popSaved(), "", Term);
  Term->setCondition(ExtractValueInst::Create(Ret, 0, "", Term));
  push(Term->getSuccessor(1), ExtractValueInst::Create(Ret, 1, "", Term));
}

/// \brief Recursively handle the condition leading to a loop
void SIAnnotateControlFlow::handleLoopCondition(Value *Cond) {
  if (PHINode *Phi = dyn_cast<PHINode>(Cond)) {

    // Handle all non constant incoming values first
    for (unsigned i = 0, e = Phi->getNumIncomingValues(); i != e; ++i) {
      Value *Incoming = Phi->getIncomingValue(i);
      if (isa<ConstantInt>(Incoming))
        continue;

      Phi->setIncomingValue(i, BoolFalse);
      handleLoopCondition(Incoming);
    }

    BasicBlock *Parent = Phi->getParent();
    BasicBlock *IDom = DT->getNode(Parent)->getIDom()->getBlock();

    for (unsigned i = 0, e = Phi->getNumIncomingValues(); i != e; ++i) {

      Value *Incoming = Phi->getIncomingValue(i);
      if (Incoming != BoolTrue)
        continue;

      BasicBlock *From = Phi->getIncomingBlock(i);
      if (From == IDom) {
        CallInst *OldEnd = dyn_cast<CallInst>(Parent->getFirstInsertionPt());
        if (OldEnd && OldEnd->getCalledFunction() == EndCf) {
          Value *Args[] = {
            OldEnd->getArgOperand(0),
            PhiInserter.GetValueAtEndOfBlock(Parent)
          };
          Value *Ret = CallInst::Create(ElseBreak, Args, "", OldEnd);
          PhiInserter.AddAvailableValue(Parent, Ret);
          continue;
        }
      }

      TerminatorInst *Insert = From->getTerminator();
      Value *Arg = PhiInserter.GetValueAtEndOfBlock(From);
      Value *Ret = CallInst::Create(Break, Arg, "", Insert);
      PhiInserter.AddAvailableValue(From, Ret);
    }
    eraseIfUnused(Phi);

  } else if (Instruction *Inst = dyn_cast<Instruction>(Cond)) {
    BasicBlock *Parent = Inst->getParent();
    TerminatorInst *Insert = Parent->getTerminator();
    Value *Args[] = { Cond, PhiInserter.GetValueAtEndOfBlock(Parent) };
    Value *Ret = CallInst::Create(IfBreak, Args, "", Insert);
    PhiInserter.AddAvailableValue(Parent, Ret);

  } else {
    assert(0 && "Unhandled loop condition!");
  }
}

/// \brief Handle a back edge (loop)
void SIAnnotateControlFlow::handleLoop(BranchInst *Term) {
  BasicBlock *Target = Term->getSuccessor(1);
  PHINode *Broken = PHINode::Create(Int64, 0, "", &Target->front());

  PhiInserter.Initialize(Int64, "");
  PhiInserter.AddAvailableValue(Target, Broken);

  Value *Cond = Term->getCondition();
  Term->setCondition(BoolTrue);
  handleLoopCondition(Cond);

  BasicBlock *BB = Term->getParent();
  Value *Arg = PhiInserter.GetValueAtEndOfBlock(BB);
  for (pred_iterator PI = pred_begin(Target), PE = pred_end(Target);
       PI != PE; ++PI) {

    Broken->addIncoming(*PI == BB ? Arg : Int64Zero, *PI);
  }

  Term->setCondition(CallInst::Create(Loop, Arg, "", Term));
  push(Term->getSuccessor(0), Arg);
}

/// \brief Close the last opened control flow
void SIAnnotateControlFlow::closeControlFlow(BasicBlock *BB) {
  CallInst::Create(EndCf, popSaved(), "", BB->getFirstInsertionPt());
}

/// \brief Annotate the control flow with intrinsics so the backend can
/// recognize if/then/else and loops.
bool SIAnnotateControlFlow::runOnFunction(Function &F) {
  DT = &getAnalysis<DominatorTree>();

  for (df_iterator<BasicBlock *> I = df_begin(&F.getEntryBlock()),
       E = df_end(&F.getEntryBlock()); I != E; ++I) {

    BranchInst *Term = dyn_cast<BranchInst>((*I)->getTerminator());

    if (!Term || Term->isUnconditional()) {
      if (isTopOfStack(*I))
        closeControlFlow(*I);
      continue;
    }

    if (I.nodeVisited(Term->getSuccessor(1))) {
      if (isTopOfStack(*I))
        closeControlFlow(*I);
      handleLoop(Term);
      continue;
    }

    if (isTopOfStack(*I)) {
      PHINode *Phi = dyn_cast<PHINode>(Term->getCondition());
      if (Phi && Phi->getParent() == *I && isElse(Phi)) {
        insertElse(Term);
        eraseIfUnused(Phi);
        continue;
      }
      closeControlFlow(*I);
    }
    openIf(Term);
  }

  assert(Stack.empty());
  return true;
}

/// \brief Create the annotation pass
FunctionPass *llvm::createSIAnnotateControlFlowPass() {
  return new SIAnnotateControlFlow();
}
<|endoftext|>