<commit_before>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "DockerExecutor.h"

#include "DockerUtilities.h"
#include "ProgressDialog.h"
#include "Utilities.h"

namespace tomviz {

DockerPipelineExecutor::DockerPipelineExecutor(Pipeline* pipeline)
  : ExternalPipelineExecutor(pipeline), m_statusCheckTimer(new QTimer(this))
{
  m_statusCheckTimer->setInterval(5000);
  connect(m_statusCheckTimer, &QTimer::timeout, this,
          &DockerPipelineExecutor::checkContainerStatus);
}

DockerPipelineExecutor::~DockerPipelineExecutor() = default;

docker::DockerRunInvocation* DockerPipelineExecutor::run(
  const QString& image, const QStringList& args,
  const QMap<QString, QString>& bindMounts)
{
  auto runInvocation = docker::run(image, QString(), args, bindMounts);
  connect(runInvocation, &docker::DockerRunInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(runInvocation, &docker::DockerRunInvocation::finished, runInvocation,
          [this, runInvocation](int exitCode, QProcess::ExitStatus exitStatus) {
            Q_UNUSED(exitStatus)
            if (exitCode) {
              displayError("Docker Error",
                           QString("Docker run failed with: %1\n\n%2")
                             .arg(exitCode)
                             .arg(runInvocation->stdErr()));
              return;
            } else {
              m_containerId = runInvocation->containerId();
              // Start to monitor the status of the container
              m_statusCheckTimer->start();
            }
            runInvocation->deleteLater();
          });

  return runInvocation;
}

void DockerPipelineExecutor::remove(const QString& containerId, bool force)
{
  auto removeInvocation = docker::remove(containerId, force);
  connect(removeInvocation, &docker::DockerRunInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(
    removeInvocation, &docker::DockerRunInvocation::finished, removeInvocation,
    [this, removeInvocation](int exitCode, QProcess::ExitStatus exitStatus) {
      Q_UNUSED(exitStatus)
      if (exitCode) {
        displayError("Docker Error",
                     QString("Docker remove failed with: %1\n\n%2")
                       .arg(exitCode)
                       .arg(removeInvocation->stdErr()));
      }
      removeInvocation->deleteLater();
    });
}

docker::DockerStopInvocation* DockerPipelineExecutor::stop(
  const QString& containerId)
{
  auto stopInvocation = docker::stop(containerId, 0);
  connect(stopInvocation, &docker::DockerStopInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(
    stopInvocation, &docker::DockerStopInvocation::finished, stopInvocation,
    [this, stopInvocation](int exitCode, QProcess::ExitStatus exitStatus) {
      Q_UNUSED(exitStatus)
      if (exitCode) {
        displayError("Docker Error",
                     QString("Docker stop failed with: %1\n\n%2")
                       .arg(exitCode)
                       .arg(stopInvocation->stdErr()));
        stopInvocation->deleteLater();
        return;
      }

      PipelineSettings settings;
      if (settings.dockerRemove() && !m_containerId.isEmpty()) {
        // Remove the container
        remove(m_containerId, true);
      }

      stopInvocation->deleteLater();
    });

  return stopInvocation;
}

Pipeline::Future* DockerPipelineExecutor::execute(vtkDataObject* data,
                                                  QList<Operator*> operators,
                                                  int start, int end)
{

  auto future = ExternalPipelineExecutor::execute(data, operators, start, end);

  // We are now ready to run the pipeline
  auto args = executorArgs(start);
  QMap<QString, QString> bindMounts;
  bindMounts[m_temporaryDir->path()] = CONTAINER_MOUNT;

  PipelineSettings settings;
  QString image = settings.dockerImage();
  auto startContainer = [this, image, args, bindMounts]() {
    auto msg = QString("Starting docker container.");
    auto progress = new ProgressDialog("Docker run", msg, tomviz::mainWidget());
    progress->show();
    auto runInvocation = run(image, args, bindMounts);
    connect(runInvocation, &docker::DockerPullInvocation::finished,
            runInvocation,
            [progress](int exitCode, QProcess::ExitStatus exitStatus) {
              Q_UNUSED(exitCode)
              Q_UNUSED(exitStatus)
              progress->hide();
              progress->deleteLater();
            });
  };

  // Pull the latest version of the image, if haven't already
  if (settings.dockerPull() && m_pullImage) {
    auto msg = QString("Pulling docker image: %1").arg(image);
    auto progress =
      new ProgressDialog("Docker Pull", msg, tomviz::mainWidget());
    progress->show();
    m_pullImage = false;
    auto pullInvocation = docker::pull(image);
    connect(pullInvocation, &docker::DockerPullInvocation::error, this,
            &DockerPipelineExecutor::error);
    connect(pullInvocation, &docker::DockerPullInvocation::finished,
            pullInvocation,
            [this, image, args, bindMounts, pullInvocation, progress,
             startContainer](int exitCode, QProcess::ExitStatus exitStatus) {
              Q_UNUSED(exitStatus)
              progress->hide();
              progress->deleteLater();
              if (exitCode) {
                displayError("Docker Error",
                             QString("Docker pull failed with: %1\n\n%2")
                               .arg(exitCode)
                               .arg(pullInvocation->stdErr()));
              } else {
                startContainer();
              }
              pullInvocation->deleteLater();
            });
  } else {
    startContainer();
  }

  return future;
}

void DockerPipelineExecutor::cancel(std::function<void()> canceled)
{
  // Call reset to stop progress updates, status checking and clean
  // update state.
  reset();
  auto stopInvocation = stop(m_containerId);
  connect(stopInvocation, &docker::DockerStopInvocation::finished,
          stopInvocation,
          [this, canceled](int exitCode, QProcess::ExitStatus exitStatus) {
            Q_UNUSED(exitStatus)
            if (!exitCode) {
              canceled();
            }
          });
}

bool DockerPipelineExecutor::cancel(Operator* op)
{
  Q_UNUSED(op);

  if (m_containerId.isEmpty()) {
    return false;
  }

  // Cancel status checks
  m_statusCheckTimer->stop();

  // Stop the progress reader
  m_progressReader->stop();

  // Simply stop the container.
  stop(m_containerId);

  // Clean update state.
  reset();

  // We can't cancel an individual operator so we return false, so the caller
  // knows
  return false;
}

bool DockerPipelineExecutor::isRunning()
{
  return !m_containerId.isEmpty();
}

void DockerPipelineExecutor::error(QProcess::ProcessError error)
{
  auto invocation = qobject_cast<docker::DockerInvocation*>(sender());
  displayError("Execution Error",
               QString("An error occurred executing '%1', '%2'")
                 .arg(invocation->commandLine())
                 .arg(error));
}

void DockerPipelineExecutor::containerError(int containerExitCode)
{
  auto logsInvocation = docker::logs(m_containerId);
  connect(logsInvocation, &docker::DockerRunInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(logsInvocation, &docker::DockerRunInvocation::finished,
          logsInvocation, [this, logsInvocation, containerExitCode](
                            int exitCode, QProcess::ExitStatus exitStatus) {
            Q_UNUSED(exitStatus)
            if (exitCode) {
              displayError("Docker Error",
                           QString("Docker logs failed with: %1\n\n%2")
                             .arg(exitCode)
                             .arg(logsInvocation->stdErr()));
              return;
            } else {
              auto logs = logsInvocation->logs();
              displayError(
                "Pipeline Error",
                QString("Docker container exited with non-zero exit code: %1."
                        "\n\nSee message logs for Docker logs.")
                  .arg(containerExitCode));
              qCritical() << logs;
            }
            logsInvocation->deleteLater();
            PipelineSettings settings;
            if (settings.dockerRemove() && !m_containerId.isEmpty()) {
              remove(m_containerId);
            }
          });
}

void DockerPipelineExecutor::checkContainerStatus()
{
  auto inspectInvocation = docker::inspect(m_containerId);
  connect(inspectInvocation, &docker::DockerInspectInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(inspectInvocation, &docker::DockerInspectInvocation::finished,
          inspectInvocation, [this, inspectInvocation](
                               int exitCode, QProcess::ExitStatus exitStatus) {
            Q_UNUSED(exitStatus)
            if (exitCode) {
              displayError("Docker Error",
                           QString("Docker inspect failed with: %1\n\n%2")
                             .arg(exitCode)
                             .arg(inspectInvocation->stdErr()));
              return;
            } else {
              // Check we haven't exited with an error.
              auto status = inspectInvocation->status();
              if (status == "exited") {
                if (inspectInvocation->exitCode()) {
                  containerError(inspectInvocation->exitCode());
                }
                // Cancel the status checks we are done.
                m_statusCheckTimer->stop();
              }
            }
            inspectInvocation->deleteLater();
          });
}

void DockerPipelineExecutor::pipelineStarted()
{
  qDebug("Pipeline started in docker container!");
}

void DockerPipelineExecutor::reset()
{
  // Cancel status checks
  m_statusCheckTimer->stop();

  ExternalPipelineExecutor::reset();

  PipelineSettings settings;
  if (settings.dockerRemove() && !m_containerId.isEmpty()) {
    // Remove the container
    remove(m_containerId, true);
  }

  m_containerId = QString();
}

QString DockerPipelineExecutor::executorWorkingDir()
{
  return CONTAINER_MOUNT;
}

} // namespace tomviz
<commit_msg>Fix a few memory leaks in DockerExecutor<commit_after>/* This source file is part of the Tomviz project, https://tomviz.org/.
   It is released under the 3-Clause BSD License, see "LICENSE". */

#include "DockerExecutor.h"

#include "DockerUtilities.h"
#include "ProgressDialog.h"
#include "Utilities.h"

namespace tomviz {

DockerPipelineExecutor::DockerPipelineExecutor(Pipeline* pipeline)
  : ExternalPipelineExecutor(pipeline), m_statusCheckTimer(new QTimer(this))
{
  m_statusCheckTimer->setInterval(5000);
  connect(m_statusCheckTimer, &QTimer::timeout, this,
          &DockerPipelineExecutor::checkContainerStatus);
}

DockerPipelineExecutor::~DockerPipelineExecutor() = default;

docker::DockerRunInvocation* DockerPipelineExecutor::run(
  const QString& image, const QStringList& args,
  const QMap<QString, QString>& bindMounts)
{
  auto runInvocation = docker::run(image, QString(), args, bindMounts);
  connect(runInvocation, &docker::DockerRunInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(runInvocation, &docker::DockerRunInvocation::finished, runInvocation,
          [this, runInvocation](int exitCode, QProcess::ExitStatus exitStatus) {
            Q_UNUSED(exitStatus)
            if (exitCode) {
              displayError("Docker Error",
                           QString("Docker run failed with: %1\n\n%2")
                             .arg(exitCode)
                             .arg(runInvocation->stdErr()));
            } else {
              m_containerId = runInvocation->containerId();
              // Start to monitor the status of the container
              m_statusCheckTimer->start();
            }
            runInvocation->deleteLater();
          });

  return runInvocation;
}

void DockerPipelineExecutor::remove(const QString& containerId, bool force)
{
  auto removeInvocation = docker::remove(containerId, force);
  connect(removeInvocation, &docker::DockerRunInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(
    removeInvocation, &docker::DockerRunInvocation::finished, removeInvocation,
    [this, removeInvocation](int exitCode, QProcess::ExitStatus exitStatus) {
      Q_UNUSED(exitStatus)
      if (exitCode) {
        displayError("Docker Error",
                     QString("Docker remove failed with: %1\n\n%2")
                       .arg(exitCode)
                       .arg(removeInvocation->stdErr()));
      }
      removeInvocation->deleteLater();
    });
}

docker::DockerStopInvocation* DockerPipelineExecutor::stop(
  const QString& containerId)
{
  auto stopInvocation = docker::stop(containerId, 0);
  connect(stopInvocation, &docker::DockerStopInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(
    stopInvocation, &docker::DockerStopInvocation::finished, stopInvocation,
    [this, stopInvocation](int exitCode, QProcess::ExitStatus exitStatus) {
      Q_UNUSED(exitStatus)
      if (exitCode) {
        displayError("Docker Error",
                     QString("Docker stop failed with: %1\n\n%2")
                       .arg(exitCode)
                       .arg(stopInvocation->stdErr()));
        stopInvocation->deleteLater();
        return;
      }

      PipelineSettings settings;
      if (settings.dockerRemove() && !m_containerId.isEmpty()) {
        // Remove the container
        remove(m_containerId, true);
      }

      stopInvocation->deleteLater();
    });

  return stopInvocation;
}

Pipeline::Future* DockerPipelineExecutor::execute(vtkDataObject* data,
                                                  QList<Operator*> operators,
                                                  int start, int end)
{

  auto future = ExternalPipelineExecutor::execute(data, operators, start, end);

  // We are now ready to run the pipeline
  auto args = executorArgs(start);
  QMap<QString, QString> bindMounts;
  bindMounts[m_temporaryDir->path()] = CONTAINER_MOUNT;

  PipelineSettings settings;
  QString image = settings.dockerImage();
  auto startContainer = [this, image, args, bindMounts]() {
    auto msg = QString("Starting docker container.");
    auto progress = new ProgressDialog("Docker run", msg, tomviz::mainWidget());
    progress->show();
    auto runInvocation = run(image, args, bindMounts);
    connect(runInvocation, &docker::DockerPullInvocation::finished,
            runInvocation,
            [progress](int exitCode, QProcess::ExitStatus exitStatus) {
              Q_UNUSED(exitCode)
              Q_UNUSED(exitStatus)
              progress->hide();
              progress->deleteLater();
            });
  };

  // Pull the latest version of the image, if haven't already
  if (settings.dockerPull() && m_pullImage) {
    auto msg = QString("Pulling docker image: %1").arg(image);
    auto progress =
      new ProgressDialog("Docker Pull", msg, tomviz::mainWidget());
    progress->show();
    m_pullImage = false;
    auto pullInvocation = docker::pull(image);
    connect(pullInvocation, &docker::DockerPullInvocation::error, this,
            &DockerPipelineExecutor::error);
    connect(pullInvocation, &docker::DockerPullInvocation::finished,
            pullInvocation,
            [this, image, args, bindMounts, pullInvocation, progress,
             startContainer](int exitCode, QProcess::ExitStatus exitStatus) {
              Q_UNUSED(exitStatus)
              progress->hide();
              progress->deleteLater();
              if (exitCode) {
                displayError("Docker Error",
                             QString("Docker pull failed with: %1\n\n%2")
                               .arg(exitCode)
                               .arg(pullInvocation->stdErr()));
              } else {
                startContainer();
              }
              pullInvocation->deleteLater();
            });
  } else {
    startContainer();
  }

  return future;
}

void DockerPipelineExecutor::cancel(std::function<void()> canceled)
{
  // Call reset to stop progress updates, status checking and clean
  // update state.
  reset();
  auto stopInvocation = stop(m_containerId);
  connect(stopInvocation, &docker::DockerStopInvocation::finished,
          stopInvocation,
          [this, canceled](int exitCode, QProcess::ExitStatus exitStatus) {
            Q_UNUSED(exitStatus)
            if (!exitCode) {
              canceled();
            }
          });
}

bool DockerPipelineExecutor::cancel(Operator* op)
{
  Q_UNUSED(op);

  if (m_containerId.isEmpty()) {
    return false;
  }

  // Cancel status checks
  m_statusCheckTimer->stop();

  // Stop the progress reader
  m_progressReader->stop();

  // Simply stop the container.
  stop(m_containerId);

  // Clean update state.
  reset();

  // We can't cancel an individual operator so we return false, so the caller
  // knows
  return false;
}

bool DockerPipelineExecutor::isRunning()
{
  return !m_containerId.isEmpty();
}

void DockerPipelineExecutor::error(QProcess::ProcessError error)
{
  auto invocation = qobject_cast<docker::DockerInvocation*>(sender());
  displayError("Execution Error",
               QString("An error occurred executing '%1', '%2'")
                 .arg(invocation->commandLine())
                 .arg(error));
}

void DockerPipelineExecutor::containerError(int containerExitCode)
{
  auto logsInvocation = docker::logs(m_containerId);
  connect(logsInvocation, &docker::DockerRunInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(logsInvocation, &docker::DockerRunInvocation::finished,
          logsInvocation, [this, logsInvocation, containerExitCode](
                            int exitCode, QProcess::ExitStatus exitStatus) {
            Q_UNUSED(exitStatus)
            if (exitCode) {
              displayError("Docker Error",
                           QString("Docker logs failed with: %1\n\n%2")
                             .arg(exitCode)
                             .arg(logsInvocation->stdErr()));
              logsInvocation->deleteLater();
              return;
            } else {
              auto logs = logsInvocation->logs();
              displayError(
                "Pipeline Error",
                QString("Docker container exited with non-zero exit code: %1."
                        "\n\nSee message logs for Docker logs.")
                  .arg(containerExitCode));
              qCritical() << logs;
            }
            logsInvocation->deleteLater();
            PipelineSettings settings;
            if (settings.dockerRemove() && !m_containerId.isEmpty()) {
              remove(m_containerId);
            }
          });
}

void DockerPipelineExecutor::checkContainerStatus()
{
  auto inspectInvocation = docker::inspect(m_containerId);
  connect(inspectInvocation, &docker::DockerInspectInvocation::error, this,
          &DockerPipelineExecutor::error);
  connect(inspectInvocation, &docker::DockerInspectInvocation::finished,
          inspectInvocation, [this, inspectInvocation](
                               int exitCode, QProcess::ExitStatus exitStatus) {
            Q_UNUSED(exitStatus)
            if (exitCode) {
              displayError("Docker Error",
                           QString("Docker inspect failed with: %1\n\n%2")
                             .arg(exitCode)
                             .arg(inspectInvocation->stdErr()));
            } else {
              // Check we haven't exited with an error.
              auto status = inspectInvocation->status();
              if (status == "exited") {
                if (inspectInvocation->exitCode()) {
                  containerError(inspectInvocation->exitCode());
                }
                // Cancel the status checks we are done.
                m_statusCheckTimer->stop();
              }
            }
            inspectInvocation->deleteLater();
          });
}

void DockerPipelineExecutor::pipelineStarted()
{
  qDebug("Pipeline started in docker container!");
}

void DockerPipelineExecutor::reset()
{
  // Cancel status checks
  m_statusCheckTimer->stop();

  ExternalPipelineExecutor::reset();

  PipelineSettings settings;
  if (settings.dockerRemove() && !m_containerId.isEmpty()) {
    // Remove the container
    remove(m_containerId, true);
  }

  m_containerId = QString();
}

QString DockerPipelineExecutor::executorWorkingDir()
{
  return CONTAINER_MOUNT;
}

} // namespace tomviz
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2008, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <OgreSceneNode.h>
#include <OgreSceneManager.h>

#include <urdf/model.h>

#include "rviz/display_context.h"
#include "rviz/robot/robot.h"
#include "rviz/robot/tf_link_updater.h"
#include "rviz/properties/float_property.h"
#include "rviz/properties/property.h"
#include "rviz/properties/string_property.h"

#include "robot_model_display.h"

namespace rviz
{

void linkUpdaterStatusFunction( StatusProperty::Level level,
                                const std::string& link_name,
                                const std::string& text,
                                RobotModelDisplay* display )
{
  display->setStatus( level, QString::fromStdString( link_name ), QString::fromStdString( text ));
}

RobotModelDisplay::RobotModelDisplay()
  : Display()
  , has_new_transforms_( false )
  , time_since_last_transform_( 0.0f )
{
  visual_enabled_property_ = new Property( "Visual Enabled", true,
                                           "Whether to display the visual representation of the robot.",
                                           this, SLOT( updateVisualVisible() ));

  collision_enabled_property_ = new Property( "Collision Enabled", false,
                                              "Whether to display the collision representation of the robot.",
                                              this, SLOT( updateCollisionVisible() ));

  update_rate_property_ = new FloatProperty( "Update Interval", 0,
                                             "Interval at which to update the links, in seconds. "
                                             " 0 means to update every update cycle.",
                                             this );
  update_rate_property_->setMin( 0 );

  alpha_property_ = new FloatProperty( "Alpha", 1,
                                       "Amount of transparency to apply to the links.",
                                       this, SLOT( updateAlpha() ));
  alpha_property_->setMin( 0.0 );
  alpha_property_->setMax( 1.0 );

  robot_description_property_ = new StringProperty( "Robot Description", "robot_description",
                                                    "Name of the parameter to search for to load the robot description.",
                                                    this, SLOT( updateRobotDescription() ));

  tf_prefix_property_ = new StringProperty( "TF Prefix", "",
                                            "Robot Model normally assumes the link name is the same as the tf frame name. "
                                            " This option allows you to set a prefix.  Mainly useful for multi-robot situations.",
                                            this, SLOT( updateTfPrefix() ));
}

RobotModelDisplay::~RobotModelDisplay()
{
  if ( initialized() )
  {
    delete robot_;
  }
}

void RobotModelDisplay::onInitialize()
{
  robot_ = new Robot( scene_node_, context_, "Robot: " + getName().toStdString(), this );

  updateVisualVisible();
  updateCollisionVisible();
  updateAlpha();
}

void RobotModelDisplay::updateAlpha()
{
  robot_->setAlpha( alpha_property_->getFloat() );
  context_->queueRender();
}

void RobotModelDisplay::updateRobotDescription()
{
  if( isEnabled() )
  {
    load();
    context_->queueRender();
  }
}

void RobotModelDisplay::updateVisualVisible()
{
  robot_->setVisualVisible( visual_enabled_property_->getValue().toBool() );
  context_->queueRender();
}

void RobotModelDisplay::updateCollisionVisible()
{
  robot_->setCollisionVisible( collision_enabled_property_->getValue().toBool() );
  context_->queueRender();
}

void RobotModelDisplay::updateTfPrefix()
{
  clearStatuses();
  context_->queueRender();
}

void RobotModelDisplay::load()
{
  clearStatuses();

  std::string content;
  if( !update_nh_.getParam( robot_description_property_->getStdString(), content ))
  {
    std::string loc;
    if( update_nh_.searchParam( robot_description_property_->getStdString(), loc ))
    {
      update_nh_.getParam( loc, content );
    }
    else
    {
      clear();
      setStatus( StatusProperty::Error, "URDF",
                 "Parameter [" + robot_description_property_->getString()
                 + "] does not exist, and was not found by searchParam()" );
      return;
    }
  }

  if( content.empty() )
  {
    clear();
    setStatus( StatusProperty::Error, "URDF", "URDF is empty" );
    return;
  }

  if( content == robot_description_ )
  {
    return;
  }

  robot_description_ = content;

  urdf::Model descr;
  if( !descr.initString(robot_description_))
  {
    clear();
    setStatus( StatusProperty::Error, "URDF", "Failed to parse URDF model" );
    return;
  }

  setStatus( StatusProperty::Ok, "URDF", "URDF parsed OK" );
  robot_->load( descr );
  robot_->update( TFLinkUpdater( context_->getFrameManager(),
                                 boost::bind( linkUpdaterStatusFunction, _1, _2, _3, this ),
                                 tf_prefix_property_->getStdString() ));
}

void RobotModelDisplay::onEnable()
{
  load();
  robot_->setVisible( true );
}

void RobotModelDisplay::onDisable()
{
  robot_->setVisible( false );
  clear();
}

void RobotModelDisplay::update( float wall_dt, float ros_dt )
{
  time_since_last_transform_ += wall_dt;
  float rate = update_rate_property_->getFloat();
  bool update = rate < 0.0001f || time_since_last_transform_ >= rate;

  if( has_new_transforms_ || update )
  {
    robot_->update( TFLinkUpdater( context_->getFrameManager(),
                                   boost::bind( linkUpdaterStatusFunction, _1, _2, _3, this ),
                                   tf_prefix_property_->getStdString() ));
    context_->queueRender();

    has_new_transforms_ = false;
    time_since_last_transform_ = 0.0f;
  }
}

void RobotModelDisplay::fixedFrameChanged()
{
  has_new_transforms_ = true;
}

void RobotModelDisplay::clear()
{
  robot_->clear();
  clearStatuses();
  robot_description_.clear();
}

void RobotModelDisplay::reset()
{
  Display::reset();
  has_new_transforms_ = true;
}

} // namespace rviz

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS( rviz::RobotModelDisplay, rviz::Display )
<commit_msg>RobotModelDisplay: Poll robot_description at 1Hz until found<commit_after>/*
 * Copyright (c) 2008, Willow Garage, Inc.
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the Willow Garage, Inc. nor the names of its
 *       contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 * POSSIBILITY OF SUCH DAMAGE.
 */

#include <OgreSceneNode.h>
#include <OgreSceneManager.h>
#include <QTimer>

#include <urdf/model.h>

#include "rviz/display_context.h"
#include "rviz/robot/robot.h"
#include "rviz/robot/tf_link_updater.h"
#include "rviz/properties/float_property.h"
#include "rviz/properties/property.h"
#include "rviz/properties/string_property.h"

#include "robot_model_display.h"

namespace rviz
{

void linkUpdaterStatusFunction( StatusProperty::Level level,
                                const std::string& link_name,
                                const std::string& text,
                                RobotModelDisplay* display )
{
  display->setStatus( level, QString::fromStdString( link_name ), QString::fromStdString( text ));
}

RobotModelDisplay::RobotModelDisplay()
  : Display()
  , has_new_transforms_( false )
  , time_since_last_transform_( 0.0f )
{
  visual_enabled_property_ = new Property( "Visual Enabled", true,
                                           "Whether to display the visual representation of the robot.",
                                           this, SLOT( updateVisualVisible() ));

  collision_enabled_property_ = new Property( "Collision Enabled", false,
                                              "Whether to display the collision representation of the robot.",
                                              this, SLOT( updateCollisionVisible() ));

  update_rate_property_ = new FloatProperty( "Update Interval", 0,
                                             "Interval at which to update the links, in seconds. "
                                             " 0 means to update every update cycle.",
                                             this );
  update_rate_property_->setMin( 0 );

  alpha_property_ = new FloatProperty( "Alpha", 1,
                                       "Amount of transparency to apply to the links.",
                                       this, SLOT( updateAlpha() ));
  alpha_property_->setMin( 0.0 );
  alpha_property_->setMax( 1.0 );

  robot_description_property_ = new StringProperty( "Robot Description", "robot_description",
                                                    "Name of the parameter to search for to load the robot description.",
                                                    this, SLOT( updateRobotDescription() ));

  tf_prefix_property_ = new StringProperty( "TF Prefix", "",
                                            "Robot Model normally assumes the link name is the same as the tf frame name. "
                                            " This option allows you to set a prefix.  Mainly useful for multi-robot situations.",
                                            this, SLOT( updateTfPrefix() ));
}

RobotModelDisplay::~RobotModelDisplay()
{
  if ( initialized() )
  {
    delete robot_;
  }
}

void RobotModelDisplay::onInitialize()
{
  robot_ = new Robot( scene_node_, context_, "Robot: " + getName().toStdString(), this );

  updateVisualVisible();
  updateCollisionVisible();
  updateAlpha();
}

void RobotModelDisplay::updateAlpha()
{
  robot_->setAlpha( alpha_property_->getFloat() );
  context_->queueRender();
}

void RobotModelDisplay::updateRobotDescription()
{
  if( isEnabled() )
    load();
}

void RobotModelDisplay::updateVisualVisible()
{
  robot_->setVisualVisible( visual_enabled_property_->getValue().toBool() );
  context_->queueRender();
}

void RobotModelDisplay::updateCollisionVisible()
{
  robot_->setCollisionVisible( collision_enabled_property_->getValue().toBool() );
  context_->queueRender();
}

void RobotModelDisplay::updateTfPrefix()
{
  clearStatuses();
  context_->queueRender();
}

void RobotModelDisplay::load()
{
  clearStatuses();
  context_->queueRender();

  std::string content;
  if( !update_nh_.getParam( robot_description_property_->getStdString(), content ))
  {
    std::string loc;
    if( update_nh_.searchParam( robot_description_property_->getStdString(), loc ))
    {
      update_nh_.getParam( loc, content );
    }
    else
    {
      clear();
      setStatus( StatusProperty::Error, "URDF",
                 "Parameter [" + robot_description_property_->getString()
                 + "] does not exist, and was not found by searchParam()" );
      // try again in a second
      QTimer::singleShot(1000, this, SLOT(updateRobotDescription()));
      return;
    }
  }

  if( content.empty() )
  {
    clear();
    setStatus( StatusProperty::Error, "URDF", "URDF is empty" );
    return;
  }

  if( content == robot_description_ )
  {
    return;
  }

  robot_description_ = content;

  urdf::Model descr;
  if( !descr.initString(robot_description_))
  {
    clear();
    setStatus( StatusProperty::Error, "URDF", "Failed to parse URDF model" );
    return;
  }

  setStatus( StatusProperty::Ok, "URDF", "URDF parsed OK" );
  robot_->load( descr );
  robot_->update( TFLinkUpdater( context_->getFrameManager(),
                                 boost::bind( linkUpdaterStatusFunction, _1, _2, _3, this ),
                                 tf_prefix_property_->getStdString() ));
}

void RobotModelDisplay::onEnable()
{
  load();
  robot_->setVisible( true );
}

void RobotModelDisplay::onDisable()
{
  robot_->setVisible( false );
  clear();
}

void RobotModelDisplay::update( float wall_dt, float ros_dt )
{
  time_since_last_transform_ += wall_dt;
  float rate = update_rate_property_->getFloat();
  bool update = rate < 0.0001f || time_since_last_transform_ >= rate;

  if( has_new_transforms_ || update )
  {
    robot_->update( TFLinkUpdater( context_->getFrameManager(),
                                   boost::bind( linkUpdaterStatusFunction, _1, _2, _3, this ),
                                   tf_prefix_property_->getStdString() ));
    context_->queueRender();

    has_new_transforms_ = false;
    time_since_last_transform_ = 0.0f;
  }
}

void RobotModelDisplay::fixedFrameChanged()
{
  has_new_transforms_ = true;
}

void RobotModelDisplay::clear()
{
  robot_->clear();
  clearStatuses();
  robot_description_.clear();
}

void RobotModelDisplay::reset()
{
  Display::reset();
  has_new_transforms_ = true;
}

} // namespace rviz

#include <pluginlib/class_list_macros.hpp>
PLUGINLIB_EXPORT_CLASS( rviz::RobotModelDisplay, rviz::Display )
<|endoftext|>


<commit_before>/**
 * Definition for Directed graph.
 * struct DirectedGraphNode {
 *     int label;
 *     vector<DirectedGraphNode *> neighbors;
 *     DirectedGraphNode(int x) : label(x) {};
 * };
 */
class Solution {
public:
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */
    vector<DirectedGraphNode*> topSort(vector<DirectedGraphNode*> graph) {
        // write your code here

    }
};<commit_msg>Sovling 127<commit_after>/**
 * Definition for Directed graph.
 * struct DirectedGraphNode {
 *     int label;
 *     vector<DirectedGraphNode *> neighbors;
 *     DirectedGraphNode(int x) : label(x) {};
 * };
 */
class Solution {
public:
    /**
     * @param graph: A list of Directed graph node
     * @return: Any topological order for the given graph.
     */
    std::map<int, DirectedGraphNode*> mapNumToNode;
    std::vector<DirectedGraphNode> rt_route;
    int f[1111][1111];

    vector<DirectedGraphNode*> topSort(vector<DirectedGraphNode*> graph) {
        // write your code here

        deque<UndirectedGraphNode *> neighborsInProcess;

        if (graph == NULL) return NULL;
        memset(f,sizeof(f),0);

        neighborsInProcess.push_back(graph);
        mapNumToNode[graph->label]=graph;

        while (neighborsInProcess.size()>0){

        	ori_top=neighborsInProcess.front();

        	for (const auto s: ori_top->neighbors){
        			mapNumToNode[s->label]=s;
        			neighborsInProcess.push_back(s);
        			f[ori_top->label][s->label]=1;

        	}

        	neighborsInProcess.pop_front();

        }

    }
};<|endoftext|>


<commit_before>#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

#include "seadsa/Global.hh"
#include "seadsa/Graph.hh"
#include "seadsa/InitializePasses.hh"

#include "transforms/utils/CallPromotionUtils.hh"

#include <memory>
#include <vector>

namespace previrt {
namespace transforms {

/*
Transform a call "foo(fptr, ....)" where fptr is a function pointer to:
      if (fptr == fn_1) {
         foo(fn_1, ...);
      } else if (fptr == fn_2) {
         foo(fn_2, ...);
      }  else {
         foo(fn_N, ...);
      }

where fn_1,fn_2,...,fn_N are the possible function addresses to
      which ptr might point to.
*/
class SpecializeCallFunctionPtrArg {
  seadsa::GlobalAnalysis &m_seadsa;
  bool m_onlyExternalCalls;

public:
  SpecializeCallFunctionPtrArg(seadsa::GlobalAnalysis &dsa,
                               bool onlyExternalCalls)
      : m_seadsa(dsa), m_onlyExternalCalls(onlyExternalCalls) {}

  bool runOnModule(llvm::Module &M);
};

class SpecializeCallFunctionPtrArgPass : public llvm::ModulePass {
public:
  static char ID;
  SpecializeCallFunctionPtrArgPass();
  bool runOnModule(llvm::Module &M) override;
  void getAnalysisUsage(llvm::AnalysisUsage &AU) const override;
};

class SpecializeExternCallFunctionPtrArgPass : public llvm::ModulePass {
public:
  static char ID;
  SpecializeExternCallFunctionPtrArgPass();
  bool runOnModule(llvm::Module &M) override;
  void getAnalysisUsage(llvm::AnalysisUsage &AU) const override;
};

} // namespace transforms
} // namespace previrt

namespace previrt {
namespace transforms {

using namespace llvm;
using namespace seadsa;

static bool isFunctionPtrType(const Type *ty) {
  if (const PointerType *PTy = dyn_cast<PointerType>(ty)) {
    return isa<FunctionType>(PTy->getElementType());
  }
  return false;
}

bool SpecializeCallFunctionPtrArg::runOnModule(Module &M) {
  // When this pass is called, -Pdevirt has been already called.

  if (M.empty()) {
    return false;
  }

  std::vector<std::pair<llvm::Instruction *, unsigned>> worklist;

  // Add in the worklist any callsite whose parameter is a function
  // pointer.
  for (auto &F : M) {
    for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
      CallSite CS(&*I);
      if (CS.getInstruction() && !CS.isIndirectCall()) {

        if (m_onlyExternalCalls) {
          if (Function *calleeF = CS.getCalledFunction()) {
            if (!calleeF->isDeclaration() || calleeF->isIntrinsic()) {
              continue;
            }
          }
        }

        for (unsigned i = 0, num_args = CS.arg_size(); i < num_args; ++i) {
          if (isFunctionPtrType(CS.getArgument(i)->getType())) {
            errs() << "[SpecializeCallFunctionPtrArg] Added "
                   << *CS.getInstruction() << " to the worklist\n";
            worklist.push_back({CS.getInstruction(), i});
          }
        }
      }
    }
  }

  // Process the worklist
  bool Change = false;
  while (!worklist.empty()) {
    auto p = worklist.back();
    worklist.pop_back();
    CallSite CS(p.first);
    Value *ArgV = CS.getArgument(p.second);

    // Ask m_seadsa the possible allocation sites associated to the
    // function pointer
    Function &FParent = *(p.first->getParent()->getParent());
    if (m_seadsa.hasGraph(FParent)) {
      seadsa::Graph &G = m_seadsa.getGraph(FParent);
      if (G.hasCell(*ArgV)) {
        const seadsa::Cell &C = G.getCell(*ArgV);
        std::vector<Function *> Callees;
        for (const Value *AS : C.getNode()->getAllocSites()) {
          if (const Function *F = dyn_cast<const Function>(AS)) {
            // XXX: remove constness
            Callees.push_back(const_cast<Function *>(F));
          }
        }

        errs() << "[SpecializeCallFunctionPtrArg] Callsite= "
               << *(CS.getInstruction()) << " Argument=" << p.second
               << "\n Possible values=\n";
        for (Function *callee : Callees) {
          errs() << "\t" << callee->getName();
        }
        errs() << "\n";

        specializeCallFunctionPtrArg(CS, p.second, Callees);
        Change = true;
      }
    }
  }
  return Change;
}

/** Begin SpecializeCallFunctionPtrArgPass **/
void SpecializeCallFunctionPtrArgPass::getAnalysisUsage(
    AnalysisUsage &AU) const {
  AU.addRequired<seadsa::BottomUpTopDownGlobalPass>();
}

bool SpecializeCallFunctionPtrArgPass::runOnModule(Module &M) {
  auto &seadsa = getAnalysis<BottomUpTopDownGlobalPass>().getGlobalAnalysis();
  SpecializeCallFunctionPtrArg SCFA(seadsa, false /* specialize all calls */);
  return SCFA.runOnModule(M);
}

SpecializeCallFunctionPtrArgPass::SpecializeCallFunctionPtrArgPass()
    : ModulePass(ID) {
  auto &Registry = *llvm::PassRegistry::getPassRegistry();
  llvm::initializeDsaAnalysisPass(Registry);
  llvm::initializeCompleteCallGraphPass(Registry);
}

char SpecializeCallFunctionPtrArgPass::ID = 0;

/** End SpecializeCallFunctionPtrArgPass **/

/** Begin SpecializeExternCallFunctionPtrArgPass **/
void SpecializeExternCallFunctionPtrArgPass::getAnalysisUsage(
    AnalysisUsage &AU) const {
  AU.addRequired<seadsa::BottomUpTopDownGlobalPass>();
}

bool SpecializeExternCallFunctionPtrArgPass::runOnModule(Module &M) {
  auto &seadsa = getAnalysis<BottomUpTopDownGlobalPass>().getGlobalAnalysis();
  SpecializeCallFunctionPtrArg SCFA(seadsa,
                                    true /* specialize only external calls */);
  return SCFA.runOnModule(M);
}

SpecializeExternCallFunctionPtrArgPass::SpecializeExternCallFunctionPtrArgPass()
    : ModulePass(ID) {
  auto &Registry = *llvm::PassRegistry::getPassRegistry();
  llvm::initializeDsaAnalysisPass(Registry);
  llvm::initializeCompleteCallGraphPass(Registry);
}

char SpecializeExternCallFunctionPtrArgPass::ID = 0;

/** End SpecializeExternCallFunctionPtrArgPass **/

} // namespace transforms
} // namespace previrt

static llvm::RegisterPass<previrt::transforms::SpecializeCallFunctionPtrArgPass>
    X("Pspecialize-call-function-ptr-arg",
      "Specialize all direct callsites with function pointer parameters");

static llvm::RegisterPass<
    previrt::transforms::SpecializeExternCallFunctionPtrArgPass>
    Y("Pspecialize-extern-call-function-ptr-arg",
      "Specialize external calls with function pointer parameters");
<commit_msg>refactor: do nothing if function pointer already known<commit_after>#include "llvm/Analysis/CallGraph.h"
#include "llvm/Analysis/LoopInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/CallSite.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstIterator.h"
#include "llvm/IR/Module.h"
#include "llvm/Pass.h"
#include "llvm/Support/raw_ostream.h"

#include "seadsa/Global.hh"
#include "seadsa/Graph.hh"
#include "seadsa/InitializePasses.hh"

#include "transforms/utils/CallPromotionUtils.hh"

#include <memory>
#include <vector>

namespace previrt {
namespace transforms {

/*
Transform a call "foo(fptr, ....)" where fptr is a function pointer to:
      if (fptr == fn_1) {
         foo(fn_1, ...);
      } else if (fptr == fn_2) {
         foo(fn_2, ...);
      }  else {
         foo(fn_N, ...);
      }

where fn_1,fn_2,...,fn_N are the possible function addresses to
      which ptr might point to.
*/
class SpecializeCallFunctionPtrArg {
  seadsa::GlobalAnalysis &m_seadsa;
  bool m_onlyExternalCalls;

public:
  SpecializeCallFunctionPtrArg(seadsa::GlobalAnalysis &dsa,
                               bool onlyExternalCalls)
      : m_seadsa(dsa), m_onlyExternalCalls(onlyExternalCalls) {}

  bool runOnModule(llvm::Module &M);
};

class SpecializeCallFunctionPtrArgPass : public llvm::ModulePass {
public:
  static char ID;
  SpecializeCallFunctionPtrArgPass();
  bool runOnModule(llvm::Module &M) override;
  void getAnalysisUsage(llvm::AnalysisUsage &AU) const override;
};

class SpecializeExternCallFunctionPtrArgPass : public llvm::ModulePass {
public:
  static char ID;
  SpecializeExternCallFunctionPtrArgPass();
  bool runOnModule(llvm::Module &M) override;
  void getAnalysisUsage(llvm::AnalysisUsage &AU) const override;
};

} // namespace transforms
} // namespace previrt

namespace previrt {
namespace transforms {

using namespace llvm;
using namespace seadsa;

static bool isFunctionPtrType(const Type *ty) {
  if (const PointerType *PTy = dyn_cast<PointerType>(ty)) {
    return isa<FunctionType>(PTy->getElementType());
  }
  return false;
}

bool SpecializeCallFunctionPtrArg::runOnModule(Module &M) {
  // When this pass is called, -Pdevirt has been already called.

  if (M.empty()) {
    return false;
  }

  std::vector<std::pair<llvm::Instruction *, unsigned>> worklist;

  // Add in the worklist any callsite whose parameter is a function
  // pointer.
  for (auto &F : M) {
    for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
      CallSite CS(&*I);
      if (CS.getInstruction() && !CS.isIndirectCall()) {

        if (m_onlyExternalCalls) {
          if (Function *calleeF = CS.getCalledFunction()) {
            if (!calleeF->isDeclaration() || calleeF->isIntrinsic()) {
              continue;
            }
          }
        }

        for (unsigned i = 0, num_args = CS.arg_size(); i < num_args; ++i) {
          if (isFunctionPtrType(CS.getArgument(i)->getType())) {
	    if (!isa<Function>(CS.getArgument(i))) {
	      // if already a known function we skip it.
	      errs() << "[SpecializeCallFunctionPtrArg] Added "
		     << *CS.getInstruction() << " to the worklist\n";
	      worklist.push_back({CS.getInstruction(), i});
	    } else {
	      errs() << " [SpecializeCallFunctionPtrArg] argument " << i << " of "
		     << *CS.getInstruction() << " already known\n";
	    }
          }
        }
      }
    }
  }

  // Process the worklist
  bool Change = false;
  while (!worklist.empty()) {
    auto p = worklist.back();
    worklist.pop_back();
    CallSite CS(p.first);
    Value *ArgV = CS.getArgument(p.second);

    // Ask m_seadsa the possible allocation sites associated to the
    // function pointer
    Function &FParent = *(p.first->getParent()->getParent());
    if (m_seadsa.hasGraph(FParent)) {
      seadsa::Graph &G = m_seadsa.getGraph(FParent);
      if (G.hasCell(*ArgV)) {
        const seadsa::Cell &C = G.getCell(*ArgV);
        std::vector<Function *> Callees;
        for (const Value *AS : C.getNode()->getAllocSites()) {
          if (const Function *F = dyn_cast<const Function>(AS)) {
            // XXX: remove constness
            Callees.push_back(const_cast<Function *>(F));
          }
        }

        errs() << "[SpecializeCallFunctionPtrArg] Callsite= "
               << *(CS.getInstruction()) << " Argument=" << p.second
               << "\n Possible values=\n";
        for (Function *callee : Callees) {
          errs() << "\t" << callee->getName();
        }
        errs() << "\n";

        specializeCallFunctionPtrArg(CS, p.second, Callees);
        Change = true;
      }
    }
  }
  return Change;
}

/** Begin SpecializeCallFunctionPtrArgPass **/
void SpecializeCallFunctionPtrArgPass::getAnalysisUsage(
    AnalysisUsage &AU) const {
  AU.addRequired<seadsa::BottomUpTopDownGlobalPass>();
}

bool SpecializeCallFunctionPtrArgPass::runOnModule(Module &M) {
  auto &seadsa = getAnalysis<BottomUpTopDownGlobalPass>().getGlobalAnalysis();
  SpecializeCallFunctionPtrArg SCFA(seadsa, false /* specialize all calls */);
  return SCFA.runOnModule(M);
}

SpecializeCallFunctionPtrArgPass::SpecializeCallFunctionPtrArgPass()
    : ModulePass(ID) {
  auto &Registry = *llvm::PassRegistry::getPassRegistry();
  llvm::initializeDsaAnalysisPass(Registry);
  llvm::initializeCompleteCallGraphPass(Registry);
}

char SpecializeCallFunctionPtrArgPass::ID = 0;

/** End SpecializeCallFunctionPtrArgPass **/

/** Begin SpecializeExternCallFunctionPtrArgPass **/
void SpecializeExternCallFunctionPtrArgPass::getAnalysisUsage(
    AnalysisUsage &AU) const {
  AU.addRequired<seadsa::BottomUpTopDownGlobalPass>();
}

bool SpecializeExternCallFunctionPtrArgPass::runOnModule(Module &M) {
  auto &seadsa = getAnalysis<BottomUpTopDownGlobalPass>().getGlobalAnalysis();
  SpecializeCallFunctionPtrArg SCFA(seadsa,
                                    true /* specialize only external calls */);
  return SCFA.runOnModule(M);
}

SpecializeExternCallFunctionPtrArgPass::SpecializeExternCallFunctionPtrArgPass()
    : ModulePass(ID) {
  auto &Registry = *llvm::PassRegistry::getPassRegistry();
  llvm::initializeDsaAnalysisPass(Registry);
  llvm::initializeCompleteCallGraphPass(Registry);
}

char SpecializeExternCallFunctionPtrArgPass::ID = 0;

/** End SpecializeExternCallFunctionPtrArgPass **/

} // namespace transforms
} // namespace previrt

static llvm::RegisterPass<previrt::transforms::SpecializeCallFunctionPtrArgPass>
    X("Pspecialize-call-function-ptr-arg",
      "Specialize all direct callsites with function pointer parameters");

static llvm::RegisterPass<
    previrt::transforms::SpecializeExternCallFunctionPtrArgPass>
    Y("Pspecialize-extern-call-function-ptr-arg",
      "Specialize external calls with function pointer parameters");
<|endoftext|>


<commit_before>class Solution {
public:
    int arrangeCoins(int n) {
        if(n==0) return 0;
        if(n==1) return 1;
        long long f=1,r=n,mid;
        while(f<=r){
            mid=(f+r)/2;
            if(mid*(mid+1)/2<=n){
                f=mid+1;
            }else{
                r=mid-1;
            }
        }
        return f-1;
    }
};
<commit_msg>Arranging Coins<commit_after>class Solution {
public:
    int arrangeCoins(int n) {
        if(n == 0) return 0;
        if(n == 1) return 1;
        long long f = 1, r = n, mid;
        while(f <= r){
            mid = (f + r)/2;
            if(mid*(mid+1)/2 <= n){
                f = mid + 1;
            }else{
                r = mid - 1;
            }
        }
        return f-1;
    }
};
<|endoftext|>


<commit_before>#include "CPU.h"
#include "Emulator.h"
#include "Types.h"
#include "Log.h"
#include "Random.h"
#include "Font.h"

#include <cassert>

namespace
{
using namespace Chip8;

inline int regX(const opcode_t &opcode)
{
	return ((opcode >> 8) & 0xF);
}
inline int regY(const opcode_t &opcode)
{
	return ((opcode >> 4) & 0xF);
}
}

namespace Chip8
{
CPU::CPU(Emulator *emu) : emu(emu)
{
	assert(emu != nullptr);
	reset();
}
CPU::~CPU()
{
}

void CPU::reset()
{
	pc = Memory::ROM_START;
	sp = 0;

	for (int i = 0; i < STACK_SIZE; ++i)
	{
		stack[i] = 0;
	}

	delayTimer = 0;
	soundTimer = 0;
	timeKeep = 0.f;

	I = 0;
	for (int i = 0x0; i <= 0xF; ++i)
	{
		V[i] = 0;
	}
}

void CPU::step(float seconds)
{
	parseOpcode();
	tickTimers(seconds);

	emu->getSound().setInput(soundTimer > 0);
}

void CPU::parseOpcode()
{
	Memory &memory = emu->getMemory();

	opcode_t opcode = memory.read(pc);
	opcode <<= sizeof(byte_t)*8;
	opcode |= memory.read(pc+1);

	pc += sizeof(opcode_t);

	switch ((opcode >> 12) & 0xF)
	{
	case 0x0:
		switch (opcode & 0x0FFF)
		{
		case 0x0E0: emu->getDisplay().clear(); break;
		case 0x0EE: pc = pop(); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0x1: pc = (opcode & 0x0FFF); break;
	case 0x2: callSubroutine(opcode & 0x0FFF); break;
	case 0x3: if (V[regX(opcode)] == (opcode & 0x00FF)) skipInstruction(); break;
	case 0x4: if (V[regX(opcode)] != (opcode & 0x00FF)) skipInstruction(); break;
	case 0x5: if (V[regX(opcode)] == V[regY(opcode)]) skipInstruction(); break;
	case 0x6: V[regX(opcode)] = (opcode & 0x00FF); break;
	case 0x7: V[regX(opcode)] += (opcode & 0x00FF); break;
	case 0x8:
		switch (opcode & 0x000F)
		{
		case 0x0: V[regX(opcode)] = V[regY(opcode)]; break;
		case 0x1: V[regX(opcode)] |= V[regY(opcode)]; break;
		case 0x2: V[regX(opcode)] &= V[regY(opcode)]; break;
		case 0x3: V[regX(opcode)] ^= V[regY(opcode)]; break;
		case 0x4: V[regX(opcode)] = addSetCarry(V[regX(opcode)], V[regY(opcode)]); break;
		case 0x5: V[regX(opcode)] = subtractSetCarry(V[regX(opcode)], V[regY(opcode)]); break;
		case 0x6: V[regX(opcode)] = shiftRightSetCarry(V[regX(opcode)], 1); break;
		case 0x7: V[regX(opcode)] = subtractSetCarry(V[regY(opcode)], V[regX(opcode)]); break;
		case 0xE: V[regX(opcode)] = shiftLeftSetCarry(V[regX(opcode)], 1); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0x9: if (V[regX(opcode)] != V[regY(opcode)]) skipInstruction(); break;
	case 0xA: I = (opcode & 0x0FFF); break;
	case 0xB: pc = ((opcode & 0x0FFF) + V[0x0]); break;
	case 0xC: V[regX(opcode)] = Random::get() & (opcode & 0x00FF); break;
	case 0xD: V[0xF] = emu->getDisplay().drawSprite(V[regX(opcode)], V[regY(opcode)], emu->getMemory().get(I), (opcode & 0xF)) ? 1 : 0; break;
	case 0xE:
		switch (opcode & 0x00FF)
		{
		case 0x9E: if (emu->getInput().isPressed(V[regX(opcode)])) skipInstruction(); break;
		case 0xA1: if (!emu->getInput().isPressed(V[regX(opcode)])) skipInstruction(); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0xF:
		switch (opcode & 0x00FF)
		{
		case 0x07: V[regX(opcode)] = delayTimer; break;
		case 0x0A: if (emu->getInput().isAnyPressed()) V[regX(opcode)] = emu->getInput().getFirstPressed(); else repeatInstruction(); break;
		case 0x15: delayTimer = V[regX(opcode)]; break;
		case 0x18: soundTimer = V[regX(opcode)]; break;
		case 0x1E: I = addSetOverflow(I, V[regX(opcode)]); break;
		case 0x29: I = Memory::FONT_START + (V[regX(opcode)] * Font::SIZE); break;
		case 0x33: storeDecimal(I, V[regX(opcode)]); break;
		case 0x55: storeRegisters(I, regX(opcode)); break;
		case 0x65: fillRegisters(I, regX(opcode)); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	default: unknownOpcode(opcode); break;
	}
}
void CPU::tickTimers(float seconds)
{
	timeKeep += seconds;

	static const float SECONDS_PER_TICK = (1.f / (float)TIMER_HZ);
	while (timeKeep >= SECONDS_PER_TICK)
	{
		timeKeep -= SECONDS_PER_TICK;
		if (delayTimer > 0)
			--delayTimer;
		if (soundTimer > 0)
			--soundTimer;
	}
}

void CPU::push(address_t address)
{
	if (sp >= STACK_SIZE)
	{
		Log::error() << "Stack overflow" << std::endl;
	}
	else
	{
		stack[sp] = address;
		++sp;
	}
}
address_t CPU::pop()
{
	if (sp <= 0)
	{
		Log::error() << "Stack underflow" << std::endl;
		return 0;
	}
	else
	{
		--sp;
		return stack[sp];
	}
}

void CPU::storeRegisters(address_t address, int maxReg)
{
	Memory &memory = emu->getMemory();
	for (int i = 0x0; i <= maxReg; ++i)
	{
		memory.write(address + i, V[i]);
	}
}
void CPU::fillRegisters(address_t address, int maxReg)
{
	Memory &memory = emu->getMemory();
	for (int i = 0x0; i <= maxReg; ++i)
	{
		V[i] = memory.read(address + i);
	}
}

void CPU::storeDecimal(address_t address, byte_t byte)
{
	Memory &memory = emu->getMemory();
	byte_t hundreds = byte / 100;
	byte -= hundreds * 100;
	byte_t tens = byte / 10;
	byte -= tens * 10;
	byte_t ones = byte;
	memory.write(address + 0, hundreds);
	memory.write(address + 1, tens);
	memory.write(address + 2, ones);
}

void CPU::skipInstruction()
{
	pc += sizeof(opcode_t);
}
void CPU::repeatInstruction()
{
	pc -= sizeof(opcode_t);
}
void CPU::callSubroutine(address_t address)
{
	push(pc + sizeof(opcode_t));
	pc = address;
}

byte_t CPU::addSetCarry(byte_t v1, byte_t v2)
{
	int result = static_cast<int>(v1) + static_cast<int>(v2);
	V[0xF] = (result > 0xFF ? 1 : 0);
	return static_cast<byte_t>(result);
}
byte_t CPU::subtractSetCarry(byte_t v1, byte_t v2)
{
	V[0xF] = (v1 >= v2 ? 1 : 0);
	return v1 - v2;
}

address_t CPU::addSetOverflow(address_t v1, address_t v2)
{
	int result = static_cast<int>(v1) + static_cast<int>(v2);
	V[0xF] = (result > 0xFFF ? 1 : 0);
	return static_cast<address_t>(result);
}

byte_t CPU::shiftRightSetCarry(byte_t v, int steps)
{
	V[0xF] = (v & 0x1);
	return (v >> steps);
}
byte_t CPU::shiftLeftSetCarry(byte_t v, int steps)
{
	V[0xF] = ((v >> 7) & 0x1);
	return (v << steps);
}

void CPU::unknownOpcode(opcode_t opcode)
{
	Log::error() << "Unknown opcode 0x" << std::hex << opcode << std::endl;
}
}
<commit_msg>Returning from subroutine would skip an instruction<commit_after>#include "CPU.h"
#include "Emulator.h"
#include "Types.h"
#include "Log.h"
#include "Random.h"
#include "Font.h"

#include <cassert>

namespace
{
using namespace Chip8;

inline int regX(const opcode_t &opcode)
{
	return ((opcode >> 8) & 0xF);
}
inline int regY(const opcode_t &opcode)
{
	return ((opcode >> 4) & 0xF);
}
}

namespace Chip8
{
CPU::CPU(Emulator *emu) : emu(emu)
{
	assert(emu != nullptr);
	reset();
}
CPU::~CPU()
{
}

void CPU::reset()
{
	pc = Memory::ROM_START;
	sp = 0;

	for (int i = 0; i < STACK_SIZE; ++i)
	{
		stack[i] = 0;
	}

	delayTimer = 0;
	soundTimer = 0;
	timeKeep = 0.f;

	I = 0;
	for (int i = 0x0; i <= 0xF; ++i)
	{
		V[i] = 0;
	}
}

void CPU::step(float seconds)
{
	parseOpcode();
	tickTimers(seconds);

	emu->getSound().setInput(soundTimer > 0);
}

void CPU::parseOpcode()
{
	Memory &memory = emu->getMemory();

	opcode_t opcode = memory.read(pc);
	opcode <<= sizeof(byte_t)*8;
	opcode |= memory.read(pc+1);

	pc += sizeof(opcode_t);

	switch ((opcode >> 12) & 0xF)
	{
	case 0x0:
		switch (opcode & 0x0FFF)
		{
		case 0x0E0: emu->getDisplay().clear(); break;
		case 0x0EE: pc = pop(); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0x1: pc = (opcode & 0x0FFF); break;
	case 0x2: callSubroutine(opcode & 0x0FFF); break;
	case 0x3: if (V[regX(opcode)] == (opcode & 0x00FF)) skipInstruction(); break;
	case 0x4: if (V[regX(opcode)] != (opcode & 0x00FF)) skipInstruction(); break;
	case 0x5: if (V[regX(opcode)] == V[regY(opcode)]) skipInstruction(); break;
	case 0x6: V[regX(opcode)] = (opcode & 0x00FF); break;
	case 0x7: V[regX(opcode)] += (opcode & 0x00FF); break;
	case 0x8:
		switch (opcode & 0x000F)
		{
		case 0x0: V[regX(opcode)] = V[regY(opcode)]; break;
		case 0x1: V[regX(opcode)] |= V[regY(opcode)]; break;
		case 0x2: V[regX(opcode)] &= V[regY(opcode)]; break;
		case 0x3: V[regX(opcode)] ^= V[regY(opcode)]; break;
		case 0x4: V[regX(opcode)] = addSetCarry(V[regX(opcode)], V[regY(opcode)]); break;
		case 0x5: V[regX(opcode)] = subtractSetCarry(V[regX(opcode)], V[regY(opcode)]); break;
		case 0x6: V[regX(opcode)] = shiftRightSetCarry(V[regX(opcode)], 1); break;
		case 0x7: V[regX(opcode)] = subtractSetCarry(V[regY(opcode)], V[regX(opcode)]); break;
		case 0xE: V[regX(opcode)] = shiftLeftSetCarry(V[regX(opcode)], 1); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0x9: if (V[regX(opcode)] != V[regY(opcode)]) skipInstruction(); break;
	case 0xA: I = (opcode & 0x0FFF); break;
	case 0xB: pc = ((opcode & 0x0FFF) + V[0x0]); break;
	case 0xC: V[regX(opcode)] = Random::get() & (opcode & 0x00FF); break;
	case 0xD: V[0xF] = emu->getDisplay().drawSprite(V[regX(opcode)], V[regY(opcode)], emu->getMemory().get(I), (opcode & 0xF)) ? 1 : 0; break;
	case 0xE:
		switch (opcode & 0x00FF)
		{
		case 0x9E: if (emu->getInput().isPressed(V[regX(opcode)])) skipInstruction(); break;
		case 0xA1: if (!emu->getInput().isPressed(V[regX(opcode)])) skipInstruction(); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	case 0xF:
		switch (opcode & 0x00FF)
		{
		case 0x07: V[regX(opcode)] = delayTimer; break;
		case 0x0A: if (emu->getInput().isAnyPressed()) V[regX(opcode)] = emu->getInput().getFirstPressed(); else repeatInstruction(); break;
		case 0x15: delayTimer = V[regX(opcode)]; break;
		case 0x18: soundTimer = V[regX(opcode)]; break;
		case 0x1E: I = addSetOverflow(I, V[regX(opcode)]); break;
		case 0x29: I = Memory::FONT_START + (V[regX(opcode)] * Font::SIZE); break;
		case 0x33: storeDecimal(I, V[regX(opcode)]); break;
		case 0x55: storeRegisters(I, regX(opcode)); break;
		case 0x65: fillRegisters(I, regX(opcode)); break;
		default: unknownOpcode(opcode); break;
		}
		break;
	default: unknownOpcode(opcode); break;
	}
}
void CPU::tickTimers(float seconds)
{
	timeKeep += seconds;

	static const float SECONDS_PER_TICK = (1.f / (float)TIMER_HZ);
	while (timeKeep >= SECONDS_PER_TICK)
	{
		timeKeep -= SECONDS_PER_TICK;
		if (delayTimer > 0)
			--delayTimer;
		if (soundTimer > 0)
			--soundTimer;
	}
}

void CPU::push(address_t address)
{
	if (sp >= STACK_SIZE)
	{
		Log::error() << "Stack overflow" << std::endl;
	}
	else
	{
		stack[sp] = address;
		++sp;
	}
}
address_t CPU::pop()
{
	if (sp <= 0)
	{
		Log::error() << "Stack underflow" << std::endl;
		return 0;
	}
	else
	{
		--sp;
		return stack[sp];
	}
}

void CPU::storeRegisters(address_t address, int maxReg)
{
	Memory &memory = emu->getMemory();
	for (int i = 0x0; i <= maxReg; ++i)
	{
		memory.write(address + i, V[i]);
	}
}
void CPU::fillRegisters(address_t address, int maxReg)
{
	Memory &memory = emu->getMemory();
	for (int i = 0x0; i <= maxReg; ++i)
	{
		V[i] = memory.read(address + i);
	}
}

void CPU::storeDecimal(address_t address, byte_t byte)
{
	Memory &memory = emu->getMemory();
	byte_t hundreds = byte / 100;
	byte -= hundreds * 100;
	byte_t tens = byte / 10;
	byte -= tens * 10;
	byte_t ones = byte;
	memory.write(address + 0, hundreds);
	memory.write(address + 1, tens);
	memory.write(address + 2, ones);
}

void CPU::skipInstruction()
{
	pc += sizeof(opcode_t);
}
void CPU::repeatInstruction()
{
	pc -= sizeof(opcode_t);
}
void CPU::callSubroutine(address_t address)
{
	push(pc);
	pc = address;
}

byte_t CPU::addSetCarry(byte_t v1, byte_t v2)
{
	int result = static_cast<int>(v1) + static_cast<int>(v2);
	V[0xF] = (result > 0xFF ? 1 : 0);
	return static_cast<byte_t>(result);
}
byte_t CPU::subtractSetCarry(byte_t v1, byte_t v2)
{
	V[0xF] = (v1 >= v2 ? 1 : 0);
	return v1 - v2;
}

address_t CPU::addSetOverflow(address_t v1, address_t v2)
{
	int result = static_cast<int>(v1) + static_cast<int>(v2);
	V[0xF] = (result > 0xFFF ? 1 : 0);
	return static_cast<address_t>(result);
}

byte_t CPU::shiftRightSetCarry(byte_t v, int steps)
{
	V[0xF] = (v & 0x1);
	return (v >> steps);
}
byte_t CPU::shiftLeftSetCarry(byte_t v, int steps)
{
	V[0xF] = ((v >> 7) & 0x1);
	return (v << steps);
}

void CPU::unknownOpcode(opcode_t opcode)
{
	Log::error() << "Unknown opcode 0x" << std::hex << opcode << std::endl;
}
}
<|endoftext|>


<commit_before>#include <stdio.h>
#include <mpi.h>
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include <vector>
#include <list>
using namespace std;

int MTemp[2][7] = 	//adjacency matrix
	{
		// {0,1,1,1,0,0,0},
		// {1,0,1,0,0,0,0},
		{1,1,0,1,1,0,0},
		{1,0,1,0,1,0,0}//,
		// {0,0,1,1,0,0,0},
		// {0,0,0,0,0,0,1},
		// {0,0,0,0,0,1,0}
	};
vector<vector<int> > connectedComponents;

int vertices = 7;
int *visited = new int[vertices];
int minRankIndex = 2;
int maxRankIndex = 3;
int rows = maxRankIndex-minRankIndex+1;

void bfs(int u, int ccCounter) {
	list<int> queue;
	visited[u] = true;
	queue.push_back(u);
	while(!queue.empty()) {
		int s=queue.front();
		connectedComponents[ccCounter].push_back(s);
		queue.pop_front();
		for(int i=0;i<rows; i++) {
			if(MTemp[i][s] && !visited[i+minRankIndex]) {
				visited[i+minRankIndex]=1;
				queue.push_back(i+minRankIndex);
			}
		}
		for(int i=0;i<vertices;i++){
			if(s>=minRankIndex && s<=maxRankIndex && MTemp[s-minRankIndex][i] && !visited[i]) {
				visited[i]=1;
				queue.push_back(i);
			}
		}
	}
	// for(int v=0; v<vertices; v++) {
	// 	cout<<"CC: "<<ccCounter<<" u: "<<u<<" v: "<<v<<" seen?: "<<seen[v]<<endl;
	// 	if(!seen[v] && u<split && MTemp[u][v]) {
	// 		dfs(v, ccCounter);
	// 	}
	// }
}

int main(int argc, char** argv) {
	int ccCounter = -1;
	for(int i=0; i<vertices; i++) {
	visited[i]=0;
	}
	for(int i=0; i<vertices; i++) {
		if(!visited[i]) {
			ccCounter += 1;
			vector<int> temp;
			connectedComponents.push_back(temp);
			bfs(i, ccCounter);
		}
	}
	for(int i=0; i<connectedComponents.size(); i++){
		cout<<"CC "<<i<<" - ";
		for(int j=0; j<connectedComponents[i].size(); j++) {
			cout<<connectedComponents[i][j]+1<<", ";
		}
		cout<<endl;
	}
	return 0;
}
<commit_msg>use adj lists instead of adj matrix<commit_after>#include <stdio.h>
#include <mpi.h>
#include <iostream>
#include <string>
#include <map>
#include <set>
#include <algorithm>
#include <vector>
#include <list>

std::map<int, std::set<int> > g_adj_list;
//sample testing adj_list
int foo1[] = {2,3,4};
int foo2[] = {1,3};
int foo3[] = {1,2,4,5};
int foo4[] = {1,3,5};
int foo5[] = {3,4};
int foo6[] = {7};
int foo7[] = {6};

std::set<int> mySet1(foo1, foo1+3);
std::set<int> mySet2(foo2, foo2+2);
std::set<int> mySet3(foo3, foo3+4);
std::set<int> mySet4(foo4, foo4+3);
std::set<int> mySet5(foo5, foo5+2);
std::set<int> mySet6(foo6, foo6+1);
std::set<int> mySet7(foo7, foo7+1);

std::map<int, bool> visited;
std::vector<std::vector<int> > connectedComponents;

// int vertices = 7;
// int *visited = new int[vertices];
// int minRankIndex = 0;
// int maxRankIndex = 2;
// int rows = maxRankIndex-minRankIndex+1;

void bfs(int u, int ccCounter) {
	std::list<int> queue;
	visited[u] = true;
	queue.push_back(u);
	while(!queue.empty()) {
		int s=queue.front();
		visited[s]=true;
		std::cout<<"Queue: ";
		connectedComponents[ccCounter].push_back(s);
		for(std::list<int>::iterator itr = queue.begin(); itr!=queue.end(); itr++) {
			std::cout<<*itr<<" ";
		}
		std::cout<<std::endl;
		queue.pop_front();
		std::map<int, std::set<int> >::iterator adj_list_itr;
		adj_list_itr = g_adj_list.find(s);
		if(adj_list_itr != g_adj_list.end()) {
			for(std::set<int>::iterator itr = adj_list_itr->second.begin(); itr != adj_list_itr->second.end(); itr++) {
				if(!visited[*itr]){
					if(find(queue.begin(), queue.end(),*itr)!=queue.end()) {
						continue;
					}
					else{
						queue.push_back(*itr);
					}
				}
			}
		}
	}
}

int main(int argc, char** argv) {
	//testing example
	// g_adj_list[1]=mySet1;
	// g_adj_list[2]=mySet2;
	// g_adj_list[3]=mySet3;
	// g_adj_list[4]=mySet4;
	// g_adj_list[5]=mySet5;
	// g_adj_list[6]=mySet6;
	// g_adj_list[7]=mySet7;
	int ccCounter = -1;
	for(std::map<int, std::set<int> >::iterator itr = g_adj_list.begin(); itr!=g_adj_list.end(); itr++) {
		visited[itr->first]=false;
	}
	for(std::map<int, bool>::iterator itr =visited.begin(); itr!=visited.end(); itr++) {
		if(!visited[itr->first]) {
			ccCounter += 1;
			std::vector<int> temp;
			connectedComponents.push_back(temp);
			bfs(itr->first, ccCounter);
		}
	}
	for(int i=0; i<connectedComponents.size(); i++){
		std::cout<<"CC "<<i<<" - ";
		for(int j=0; j<connectedComponents[i].size(); j++) {
			std::cout<<connectedComponents[i][j]<<", ";
		}
		std::cout<<std::endl;
	}
	return 0;
}
<|endoftext|>


<commit_before>/******************************************************************
  DHT Temperature & Humidity Sensor library for Arduino.

  Features:
  - Support for DHT11 and DHT22/AM2302/RHT03
  - Auto detect sensor model
  - Very low memory footprint
  - Very small code

  http://www.github.com/markruys/arduino-DHT

  Written by Mark Ruys, mark@paracas.nl.

  BSD license, check license.txt for more information.
  All text above must be included in any redistribution.

  Datasheets:
  - http://www.micro4you.com/files/sensor/DHT11.pdf
  - http://www.adafruit.com/datasheets/DHT22.pdf
  - http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/Weather/RHT03.pdf
  - http://meteobox.tk/files/AM2302.pdf

  Changelog:
   2013-06-10: Initial version
   2013-06-12: Refactored code
 ******************************************************************/

#include "DHT.h"

void DHT::setup(int pin, DHT_MODEL_t model)
{
  DHT::pin = pin;
  DHT::model = model;
  DHT::lastReadTime = millis() - 3000; // Make sure we do read the sensor in the next readSensor()

  if ( model == AUTO_DETECT) {
    DHT::model = DHT22;
    readSensor();
    if ( error == ERROR_TIMEOUT ) {
      DHT::model = DHT11;
      delay(18); // ignore bits we might get
    }
  }
}

DHT::DHT_MODEL_t DHT::getModel()
{
  return model;
}

int DHT::getMinimumSamplingPeriod()
{
  return model == DHT11 ? 1001 : 2001;
}

float DHT::getHumidity()
{
  readSensor();
  return humidity;
}

float DHT::getTemperature()
{
  readSensor();
  return temperature;
}

DHT::DHT_ERROR_t DHT::getStatus()
{
  return error;
}

#ifndef OPTIMIZE_SRAM_SIZE

const char* DHT::getStatusString()
{
  switch ( error ) {
    case DHT::ERROR_TIMEOUT:
      return "TIMEOUT";

    case DHT::ERROR_CHECKSUM:
      return "CHECKSUM";

    default:
      return "OK";
  }
}

#else

// At the expense of 26 bytes of extra PROGMEM, we save 11 bytes of
// SRAM by using the following method:

prog_char P_OK[]       PROGMEM = "OK";
prog_char P_TIMEOUT[]  PROGMEM = "TIMEOUT";
prog_char P_CHECKSUM[] PROGMEM = "CHECKSUM";

const char *DHT::getStatusString() {
  prog_char *c;
  switch ( error ) {
    case DHT::ERROR_CHECKSUM:
      c = P_CHECKSUM; break;

    case DHT::ERROR_TIMEOUT:
      c = P_TIMEOUT; break;

    default:
      c = P_OK; break;
  }

  static char buffer[9];
  strcpy_P(buffer, c);

  return buffer;
}

#endif

void DHT::readSensor()
{
  // Make sure we don't poll the sensor too often
  // - Max sample rate DHT11 is 1 Hz   (duty cicle 1000 ms)
  // - Max sample rate DHT22 is 0.5 Hz (duty cicle 2000 ms)
  unsigned long startTime = millis();
  if ( (unsigned long)(startTime - lastReadTime) < (model == DHT11 ? 1000L : 2000L) ) {
    return;
  }
  lastReadTime = startTime;

  temperature = NAN;
  humidity = NAN;

  // Request sample

  digitalWrite(pin, LOW); // Send start signal
  pinMode(pin, OUTPUT);
  if ( model == DHT11 ) {
    delay(18);
  }
  else {
    // This will fail for a DHT11 - that's how we can detect such a device
    delayMicroseconds(800);
  }

  pinMode(pin, INPUT);
  digitalWrite(pin, HIGH); // Switch bus to receive data

  // We're going to read 83 edges:
  // - First a FALLING, RISING, and FALLING edge for the start bit
  // - Then 40 bits: RISING and then a FALLING edge per bit
  // To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long

  word rawHumidity;
  word rawTemperature;
  word data;

  for ( int8_t i = -3 ; i < 2 * 40; i++ ) {
    byte age;
    startTime = micros();

    do {
      age = (unsigned long)(micros() - startTime);
      if ( age > 90 ) {
        error = ERROR_TIMEOUT;
        return;
      }
    }
    while ( digitalRead(pin) == (i & 1) ? HIGH : LOW );

    if ( i >= 0 && (i & 1) ) {
      // Now we are being fed our 40 bits
      data <<= 1;

      // A zero max 30 usecs, a one at least 68 usecs.
      if ( age > 30 ) {
        data |= 1; // we got a one
      }
    }

    switch ( i ) {
      case 31:
        rawHumidity = data;
        break;
      case 63:
        rawTemperature = data;
        data = 0;
        break;
    }
  }

  // Verify checksum

  if ( (byte)(((byte)rawHumidity) + (rawHumidity >> 8) + ((byte)rawTemperature) + (rawTemperature >> 8)) != data ) {
    error = ERROR_CHECKSUM;
    return;
  }

  // Store readings

  if ( model == DHT11 ) {
    humidity = rawHumidity >> 8;
    temperature = rawTemperature >> 8;
  }
  else {
    humidity = rawHumidity * 0.1;

    if ( rawTemperature & 0x8000 ) {
      rawTemperature = -(int16_t)(rawTemperature & 0x7FFF);
    }
    temperature = ((int16_t)rawTemperature) * 0.1;
  }

  error = ERROR_NONE;
}

float DHT::toFahrenheit(float fromCelcius)
{
  return 1.8 * fromCelcius + 32.0;
}

float DHT::toCelsius(float fromFahrenheit)
{
  return 0.5555556 * (fromFahrenheit - 32.0);
}
<commit_msg>Remove delay(18) when auto detecting a DHT11 - you should wait 1000 msec before polling anyway<commit_after>/******************************************************************
  DHT Temperature & Humidity Sensor library for Arduino.

  Features:
  - Support for DHT11 and DHT22/AM2302/RHT03
  - Auto detect sensor model
  - Very low memory footprint
  - Very small code

  http://www.github.com/markruys/arduino-DHT

  Written by Mark Ruys, mark@paracas.nl.

  BSD license, check license.txt for more information.
  All text above must be included in any redistribution.

  Datasheets:
  - http://www.micro4you.com/files/sensor/DHT11.pdf
  - http://www.adafruit.com/datasheets/DHT22.pdf
  - http://dlnmh9ip6v2uc.cloudfront.net/datasheets/Sensors/Weather/RHT03.pdf
  - http://meteobox.tk/files/AM2302.pdf

  Changelog:
   2013-06-10: Initial version
   2013-06-12: Refactored code
 ******************************************************************/

#include "DHT.h"

void DHT::setup(int pin, DHT_MODEL_t model)
{
  DHT::pin = pin;
  DHT::model = model;
  DHT::lastReadTime = millis() - 3000; // Make sure we do read the sensor in the next readSensor()

  if ( model == AUTO_DETECT) {
    DHT::model = DHT22;
    readSensor();
    if ( error == ERROR_TIMEOUT ) {
      DHT::model = DHT11;
      // Warning: in case we auto detect a DHT11, you should wait at least 1000 msec
      // before your first read request. Otherwise you will get a time out error.
    }
  }
}

DHT::DHT_MODEL_t DHT::getModel()
{
  return model;
}

int DHT::getMinimumSamplingPeriod()
{
  return model == DHT11 ? 1001 : 2001;
}

float DHT::getHumidity()
{
  readSensor();
  return humidity;
}

float DHT::getTemperature()
{
  readSensor();
  return temperature;
}

DHT::DHT_ERROR_t DHT::getStatus()
{
  return error;
}

#ifndef OPTIMIZE_SRAM_SIZE

const char* DHT::getStatusString()
{
  switch ( error ) {
    case DHT::ERROR_TIMEOUT:
      return "TIMEOUT";

    case DHT::ERROR_CHECKSUM:
      return "CHECKSUM";

    default:
      return "OK";
  }
}

#else

// At the expense of 26 bytes of extra PROGMEM, we save 11 bytes of
// SRAM by using the following method:

prog_char P_OK[]       PROGMEM = "OK";
prog_char P_TIMEOUT[]  PROGMEM = "TIMEOUT";
prog_char P_CHECKSUM[] PROGMEM = "CHECKSUM";

const char *DHT::getStatusString() {
  prog_char *c;
  switch ( error ) {
    case DHT::ERROR_CHECKSUM:
      c = P_CHECKSUM; break;

    case DHT::ERROR_TIMEOUT:
      c = P_TIMEOUT; break;

    default:
      c = P_OK; break;
  }

  static char buffer[9];
  strcpy_P(buffer, c);

  return buffer;
}

#endif

void DHT::readSensor()
{
  // Make sure we don't poll the sensor too often
  // - Max sample rate DHT11 is 1 Hz   (duty cicle 1000 ms)
  // - Max sample rate DHT22 is 0.5 Hz (duty cicle 2000 ms)
  unsigned long startTime = millis();
  if ( (unsigned long)(startTime - lastReadTime) < (model == DHT11 ? 1000L : 2000L) ) {
    return;
  }
  lastReadTime = startTime;

  temperature = NAN;
  humidity = NAN;

  // Request sample

  digitalWrite(pin, LOW); // Send start signal
  pinMode(pin, OUTPUT);
  if ( model == DHT11 ) {
    delay(18);
  }
  else {
    // This will fail for a DHT11 - that's how we can detect such a device
    delayMicroseconds(800);
  }

  pinMode(pin, INPUT);
  digitalWrite(pin, HIGH); // Switch bus to receive data

  // We're going to read 83 edges:
  // - First a FALLING, RISING, and FALLING edge for the start bit
  // - Then 40 bits: RISING and then a FALLING edge per bit
  // To keep our code simple, we accept any HIGH or LOW reading if it's max 85 usecs long

  word rawHumidity;
  word rawTemperature;
  word data;

  for ( int8_t i = -3 ; i < 2 * 40; i++ ) {
    byte age;
    startTime = micros();

    do {
      age = (unsigned long)(micros() - startTime);
      if ( age > 90 ) {
        error = ERROR_TIMEOUT;
        return;
      }
    }
    while ( digitalRead(pin) == (i & 1) ? HIGH : LOW );

    if ( i >= 0 && (i & 1) ) {
      // Now we are being fed our 40 bits
      data <<= 1;

      // A zero max 30 usecs, a one at least 68 usecs.
      if ( age > 30 ) {
        data |= 1; // we got a one
      }
    }

    switch ( i ) {
      case 31:
        rawHumidity = data;
        break;
      case 63:
        rawTemperature = data;
        data = 0;
        break;
    }
  }

  // Verify checksum

  if ( (byte)(((byte)rawHumidity) + (rawHumidity >> 8) + ((byte)rawTemperature) + (rawTemperature >> 8)) != data ) {
    error = ERROR_CHECKSUM;
    return;
  }

  // Store readings

  if ( model == DHT11 ) {
    humidity = rawHumidity >> 8;
    temperature = rawTemperature >> 8;
  }
  else {
    humidity = rawHumidity * 0.1;

    if ( rawTemperature & 0x8000 ) {
      rawTemperature = -(int16_t)(rawTemperature & 0x7FFF);
    }
    temperature = ((int16_t)rawTemperature) * 0.1;
  }

  error = ERROR_NONE;
}

float DHT::toFahrenheit(float fromCelcius)
{
  return 1.8 * fromCelcius + 32.0;
}

float DHT::toCelsius(float fromFahrenheit)
{
  return 0.5555556 * (fromFahrenheit - 32.0);
}
<|endoftext|>