<commit_before>/*!
 * @file InverseKinematicsData.cpp
 * @author Francesco Romano
 * @copyright 2016 iCub Facility - Istituto Italiano di Tecnologia
 *            Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
 * @date 2016
 *
 */

#include "InverseKinematicsData.h"
#include "InverseKinematicsNLP.h"
#include "TransformConstraint.h"
#include <iDynTree/Core/Twist.h>
#include <iDynTree/Core/ClassicalAcc.h>
#include <iDynTree/Core/SpatialAcc.h>
#include <iDynTree/Model/Model.h>

#include <cassert>
#include <private/InverseKinematicsData.h>

namespace internal {
namespace kinematics {

    InverseKinematicsData::InverseKinematicsData(const InverseKinematicsData&) {}
    InverseKinematicsData& InverseKinematicsData::operator=(const InverseKinematicsData&) { return *this; }

    InverseKinematicsData::InverseKinematicsData()
    : m_dofs(0)
    , m_rotationParametrization(iDynTree::InverseKinematicsRotationParametrizationQuaternion)
    , m_targetResolutionMode(iDynTree::InverseKinematicsTreatTargetAsConstraintFull)
    , m_areBaseInitialConditionsSet(false)
    , m_areJointsInitialConditionsSet(false)
    , m_solver(NULL)
    // The default values for the ipopt related parameters are exactly the one of IPOPT,
    // see https://www.coin-or.org/Ipopt/documentation/node41.html
    //     https://www.coin-or.org/Ipopt/documentation/node42.html
    , m_maxIter(3000)
    , m_maxCpuTime(1e6)
    , m_tol(1e-8)
    , m_constrTol(1e-4)
    , m_verbosityLevel(5)
    {
        //These variables are touched only once.
        m_state.worldGravity.zero();
        m_state.worldGravity(3) = -9.81;

        m_state.baseTwist.zero();
    }

    bool InverseKinematicsData::setModel(const iDynTree::Model& model)
    {
        bool result = m_dynamics.loadRobotModel(model);
        if (!result || !m_dynamics.isValid()) {
            std::cerr << "[ERROR] Error loading robot model" << std::endl;
            return false;
        }

        // I don't know if KinDyn can perform some operations on the model
        // For safety I get the model loaded instead of using the input one
        const iDynTree::Model& loadedModel = m_dynamics.model();
        m_dofs = loadedModel.getNrOfDOFs();

        //prepare jiont limits
        m_jointLimits.clear();
        m_jointLimits.resize(m_dofs);
        //TODO to be changed to +_ infinity
        //default: no limits
        m_jointLimits.assign(m_dofs, std::pair<double, double>(-2e+19, 2e+19));

        //for each joint, ask the limits
        for (iDynTree::JointIndex jointIdx = 0; jointIdx < loadedModel.getNrOfJoints(); ++jointIdx) {
            iDynTree::IJointConstPtr joint = loadedModel.getJoint(jointIdx);
            //if the joint does not have limits skip it
            if (!joint->hasPosLimits())
                continue;
            //for each DoF modelled by the joint get the limits
            for (unsigned dof = 0; dof < joint->getNrOfDOFs(); ++dof) {
                if (!joint->getPosLimits(dof,
                                         m_jointLimits[joint->getDOFsOffset() + dof].first,
                                         m_jointLimits[joint->getDOFsOffset() + dof].second))
                    continue;
            }
        }

        //We set a new model, clear the variables
        clearProblem();

        updateRobotConfiguration();

        return true;
    }

    void InverseKinematicsData::clearProblem()
    {
        //resize vectors
        m_jointInitialConditions.resize(m_dofs);
        m_jointInitialConditions.zero();
        m_jointsResults.resize(m_dofs);
        m_jointsResults.zero();
        m_preferredJointsConfiguration.resize(m_dofs);
        m_preferredJointsConfiguration.zero();
        m_preferredJointsWeight = 1e-6;

        m_state.jointsConfiguration.resize(m_dofs);
        m_state.jointsConfiguration.zero();

        m_state.jointsVelocity.resize(m_dofs);
        m_state.jointsVelocity.zero();

        m_state.basePose.setPosition(iDynTree::Position(0, 0, 0));
        m_state.basePose.setRotation(iDynTree::Rotation::Identity());

        m_constraints.clear();
        m_targets.clear();

        m_areBaseInitialConditionsSet = false;
        m_areJointsInitialConditionsSet = false;
    }

    bool InverseKinematicsData::addFrameConstraint(const kinematics::TransformConstraint& frameTransformConstraint)
    {
        int frameIndex = m_dynamics.getFrameIndex(frameTransformConstraint.getFrameName());
        if (frameIndex < 0)
            return false;

        //add the constraint to the set
        std::pair<TransformMap::iterator, bool> result = m_constraints.insert(TransformMap::value_type(frameIndex, frameTransformConstraint));
        return result.second;
    }

    bool InverseKinematicsData::addTarget(const kinematics::TransformConstraint& frameTransform)
    {
        int frameIndex = m_dynamics.getFrameIndex(frameTransform.getFrameName());
        if (frameIndex < 0)
            return false;

        std::pair<TransformMap::iterator, bool> result = m_targets.insert(TransformMap::value_type(frameIndex, frameTransform));
        return result.second;
    }

    TransformMap::iterator InverseKinematicsData::getTargetRefIfItExists(const std::string targetFrameName)
    {
        // The error for this check is already printed in getFrameIndex
        int frameIndex = m_dynamics.getFrameIndex(targetFrameName);
        if (frameIndex == iDynTree::FRAME_INVALID_INDEX)
            return m_targets.end();

        // Find the target (if this fails, it will return m_targets.end()
        return m_targets.find(frameIndex);
    }

    void InverseKinematicsData::updatePositionTarget(TransformMap::iterator target, iDynTree::Position newPos, double newPosWeight)
    {
        assert(target != m_targets.end());
        target->second.setPosition(newPos);
        target->second.setPositionWeight(newPosWeight);
    }

    void InverseKinematicsData::updateRotationTarget(TransformMap::iterator target, iDynTree::Rotation newRot, double newRotWeight)
    {
        assert(target != m_targets.end());
        target->second.setRotation(newRot);
        target->second.setRotationWeight(newRotWeight);
    }

    iDynTree::KinDynComputations& InverseKinematicsData::dynamics() { return m_dynamics; }

    bool InverseKinematicsData::setInitialCondition(const iDynTree::Transform* baseTransform,
                                                    const iDynTree::VectorDynSize* initialJointCondition)
    {
        if (baseTransform) {
            m_baseInitialCondition = *baseTransform;
            m_areBaseInitialConditionsSet = true;
        }
        if (initialJointCondition) {
            m_jointInitialConditions = *initialJointCondition;
            m_areJointsInitialConditionsSet = true;
        }

        return true;
    }

    bool InverseKinematicsData::setRobotConfiguration(const iDynTree::Transform& baseConfiguration,
                                                      const iDynTree::VectorDynSize& jointConfiguration)
    {
        assert(m_state.jointsConfiguration.size() == jointConfiguration.size());
        m_state.jointsConfiguration = jointConfiguration;
        m_state.basePose = baseConfiguration;
        updateRobotConfiguration();
        return true;
    }

    bool InverseKinematicsData::setJointConfiguration(const std::string& jointName, const double jointConfiguration)
    {
        iDynTree::JointIndex jointIndex = m_dynamics.model().getJointIndex(jointName);
        if (jointIndex == iDynTree::JOINT_INVALID_INDEX) return false;
        m_state.jointsConfiguration(jointIndex) = jointConfiguration;
        updateRobotConfiguration();
        return true;
    }

    bool InverseKinematicsData::setDesiredJointConfiguration(const iDynTree::VectorDynSize& desiredJointConfiguration, const double weight)
    {
        assert(m_preferredJointsConfiguration.size() == desiredJointConfiguration.size());
        m_preferredJointsConfiguration = desiredJointConfiguration;
        if( weight >= 0.0 ) {
            m_preferredJointsWeight = weight;
        }
        return true;
    }

    void InverseKinematicsData::setRotationParametrization(enum iDynTree::InverseKinematicsRotationParametrization parametrization)
    {
        m_rotationParametrization = parametrization;
    }

    enum iDynTree::InverseKinematicsRotationParametrization InverseKinematicsData::rotationParametrization() { return m_rotationParametrization; }

    void InverseKinematicsData::updateRobotConfiguration()
    {
        m_dynamics.setRobotState(m_state.basePose,
                                 m_state.jointsConfiguration,
                                 m_state.baseTwist,
                                 m_state.jointsVelocity,
                                 m_state.worldGravity);
    }

    void InverseKinematicsData::prepareForOptimization()
    {
        //Do all stuff needed before starting an optimization problem
        //1) prepare initial condition if not explicitly set
        if (!m_areBaseInitialConditionsSet) {
            m_baseInitialCondition = m_state.basePose;
        }

        if (!m_areJointsInitialConditionsSet) {
            m_jointInitialConditions = m_state.jointsConfiguration;
        }

        //2) Check joint limits.. Is this necessary?
        for (size_t i = 0; i < m_jointInitialConditions.size(); ++i) {
            //check joint to be inside limit
            double &jointValue = m_jointInitialConditions(i);
            if (jointValue < m_jointLimits[i].first || jointValue > m_jointLimits[i].second) {
                std::cerr << "[WARNING] InverseKinematics: joint with DOFIndex " << i << " initial condition is outside the limits " << m_jointLimits[i].first << " " << m_jointLimits[i].second << std::endl;
                //set the initial value to be at the middle of the limits
                jointValue = (m_jointLimits[i].second + m_jointLimits[i].first) / 2.0;
            }
        }

    }

    void InverseKinematicsData::setTargetResolutionMode(enum iDynTree::InverseKinematicsTreatTargetAsConstraint mode)
    {
        m_targetResolutionMode = mode;
    }

    enum iDynTree::InverseKinematicsTreatTargetAsConstraint InverseKinematicsData::targetResolutionMode()
    {
        return m_targetResolutionMode;
    }

    bool InverseKinematicsData::solveProblem()
    {
        Ipopt::ApplicationReturnStatus solverStatus;

        if (Ipopt::IsNull(m_solver)) {
            m_solver = IpoptApplicationFactory();

            //TODO: set options
            //For example, one needed option is the linear solver type
            //Best thing is to wrap the IPOPT options with new structure so as to abstract them
            m_solver->Options()->SetStringValue("hessian_approximation", "limited-memory");
            m_solver->Options()->SetIntegerValue("print_level",m_verbosityLevel);
            m_solver->Options()->SetIntegerValue("max_iter", m_maxIter);
            m_solver->Options()->SetNumericValue("max_cpu_time", m_maxCpuTime);
            m_solver->Options()->SetNumericValue("tol",m_tol);
            m_solver->Options()->SetNumericValue("constr_viol_tol",m_constrTol);
#ifndef NDEBUG
            m_solver->Options()->SetStringValue("derivative_test", "first-order");
#endif

            solverStatus = m_solver->Initialize();
            if (solverStatus != Ipopt::Solve_Succeeded) {
                return false;
            }
        }

        prepareForOptimization();

        //instantiate the IpOpt problem
        internal::kinematics::InverseKinematicsNLP *iKin = new internal::kinematics::InverseKinematicsNLP(*this);
        //Do something (if necessary)
        Ipopt::SmartPtr<Ipopt::TNLP> problem(iKin);

        // Ask Ipopt to solve the problem
        solverStatus = m_solver->OptimizeTNLP(problem);

        if (solverStatus == Ipopt::Solve_Succeeded || solverStatus == Ipopt::Solved_To_Acceptable_Level ) {
            std::cout << "*** The problem solved!\n";
            return true;
        } else {
            return false;
        }
    }

    void InverseKinematicsData::getSolution(iDynTree::Transform & baseTransformSolution,
                                            iDynTree::VectorDynSize & shapeSolution)
    {
        baseTransformSolution = m_baseResults;
        shapeSolution         = m_jointsResults;
    }

}
}
<commit_msg>[inverse-kinematics] Remove out of range vector access <commit_after>/*!
 * @file InverseKinematicsData.cpp
 * @author Francesco Romano
 * @copyright 2016 iCub Facility - Istituto Italiano di Tecnologia
 *            Released under the terms of the LGPLv2.1 or later, see LGPL.TXT
 * @date 2016
 *
 */

#include "InverseKinematicsData.h"
#include "InverseKinematicsNLP.h"
#include "TransformConstraint.h"
#include <iDynTree/Core/Twist.h>
#include <iDynTree/Core/ClassicalAcc.h>
#include <iDynTree/Core/SpatialAcc.h>
#include <iDynTree/Model/Model.h>

#include <cassert>
#include <private/InverseKinematicsData.h>

namespace internal {
namespace kinematics {

    InverseKinematicsData::InverseKinematicsData(const InverseKinematicsData&) {}
    InverseKinematicsData& InverseKinematicsData::operator=(const InverseKinematicsData&) { return *this; }

    InverseKinematicsData::InverseKinematicsData()
    : m_dofs(0)
    , m_rotationParametrization(iDynTree::InverseKinematicsRotationParametrizationQuaternion)
    , m_targetResolutionMode(iDynTree::InverseKinematicsTreatTargetAsConstraintFull)
    , m_areBaseInitialConditionsSet(false)
    , m_areJointsInitialConditionsSet(false)
    , m_solver(NULL)
    // The default values for the ipopt related parameters are exactly the one of IPOPT,
    // see https://www.coin-or.org/Ipopt/documentation/node41.html
    //     https://www.coin-or.org/Ipopt/documentation/node42.html
    , m_maxIter(3000)
    , m_maxCpuTime(1e6)
    , m_tol(1e-8)
    , m_constrTol(1e-4)
    , m_verbosityLevel(5)
    {
        //These variables are touched only once.
        m_state.worldGravity.zero();

        m_state.baseTwist.zero();
    }

    bool InverseKinematicsData::setModel(const iDynTree::Model& model)
    {
        bool result = m_dynamics.loadRobotModel(model);
        if (!result || !m_dynamics.isValid()) {
            std::cerr << "[ERROR] Error loading robot model" << std::endl;
            return false;
        }

        // I don't know if KinDyn can perform some operations on the model
        // For safety I get the model loaded instead of using the input one
        const iDynTree::Model& loadedModel = m_dynamics.model();
        m_dofs = loadedModel.getNrOfDOFs();

        //prepare jiont limits
        m_jointLimits.clear();
        m_jointLimits.resize(m_dofs);
        //TODO to be changed to +_ infinity
        //default: no limits
        m_jointLimits.assign(m_dofs, std::pair<double, double>(-2e+19, 2e+19));

        //for each joint, ask the limits
        for (iDynTree::JointIndex jointIdx = 0; jointIdx < loadedModel.getNrOfJoints(); ++jointIdx) {
            iDynTree::IJointConstPtr joint = loadedModel.getJoint(jointIdx);
            //if the joint does not have limits skip it
            if (!joint->hasPosLimits())
                continue;
            //for each DoF modelled by the joint get the limits
            for (unsigned dof = 0; dof < joint->getNrOfDOFs(); ++dof) {
                if (!joint->getPosLimits(dof,
                                         m_jointLimits[joint->getDOFsOffset() + dof].first,
                                         m_jointLimits[joint->getDOFsOffset() + dof].second))
                    continue;
            }
        }

        //We set a new model, clear the variables
        clearProblem();

        updateRobotConfiguration();

        return true;
    }

    void InverseKinematicsData::clearProblem()
    {
        //resize vectors
        m_jointInitialConditions.resize(m_dofs);
        m_jointInitialConditions.zero();
        m_jointsResults.resize(m_dofs);
        m_jointsResults.zero();
        m_preferredJointsConfiguration.resize(m_dofs);
        m_preferredJointsConfiguration.zero();
        m_preferredJointsWeight = 1e-6;

        m_state.jointsConfiguration.resize(m_dofs);
        m_state.jointsConfiguration.zero();

        m_state.jointsVelocity.resize(m_dofs);
        m_state.jointsVelocity.zero();

        m_state.basePose.setPosition(iDynTree::Position(0, 0, 0));
        m_state.basePose.setRotation(iDynTree::Rotation::Identity());

        m_constraints.clear();
        m_targets.clear();

        m_areBaseInitialConditionsSet = false;
        m_areJointsInitialConditionsSet = false;
    }

    bool InverseKinematicsData::addFrameConstraint(const kinematics::TransformConstraint& frameTransformConstraint)
    {
        int frameIndex = m_dynamics.getFrameIndex(frameTransformConstraint.getFrameName());
        if (frameIndex < 0)
            return false;

        //add the constraint to the set
        std::pair<TransformMap::iterator, bool> result = m_constraints.insert(TransformMap::value_type(frameIndex, frameTransformConstraint));
        return result.second;
    }

    bool InverseKinematicsData::addTarget(const kinematics::TransformConstraint& frameTransform)
    {
        int frameIndex = m_dynamics.getFrameIndex(frameTransform.getFrameName());
        if (frameIndex < 0)
            return false;

        std::pair<TransformMap::iterator, bool> result = m_targets.insert(TransformMap::value_type(frameIndex, frameTransform));
        return result.second;
    }

    TransformMap::iterator InverseKinematicsData::getTargetRefIfItExists(const std::string targetFrameName)
    {
        // The error for this check is already printed in getFrameIndex
        int frameIndex = m_dynamics.getFrameIndex(targetFrameName);
        if (frameIndex == iDynTree::FRAME_INVALID_INDEX)
            return m_targets.end();

        // Find the target (if this fails, it will return m_targets.end()
        return m_targets.find(frameIndex);
    }

    void InverseKinematicsData::updatePositionTarget(TransformMap::iterator target, iDynTree::Position newPos, double newPosWeight)
    {
        assert(target != m_targets.end());
        target->second.setPosition(newPos);
        target->second.setPositionWeight(newPosWeight);
    }

    void InverseKinematicsData::updateRotationTarget(TransformMap::iterator target, iDynTree::Rotation newRot, double newRotWeight)
    {
        assert(target != m_targets.end());
        target->second.setRotation(newRot);
        target->second.setRotationWeight(newRotWeight);
    }

    iDynTree::KinDynComputations& InverseKinematicsData::dynamics() { return m_dynamics; }

    bool InverseKinematicsData::setInitialCondition(const iDynTree::Transform* baseTransform,
                                                    const iDynTree::VectorDynSize* initialJointCondition)
    {
        if (baseTransform) {
            m_baseInitialCondition = *baseTransform;
            m_areBaseInitialConditionsSet = true;
        }
        if (initialJointCondition) {
            m_jointInitialConditions = *initialJointCondition;
            m_areJointsInitialConditionsSet = true;
        }

        return true;
    }

    bool InverseKinematicsData::setRobotConfiguration(const iDynTree::Transform& baseConfiguration,
                                                      const iDynTree::VectorDynSize& jointConfiguration)
    {
        assert(m_state.jointsConfiguration.size() == jointConfiguration.size());
        m_state.jointsConfiguration = jointConfiguration;
        m_state.basePose = baseConfiguration;
        updateRobotConfiguration();
        return true;
    }

    bool InverseKinematicsData::setJointConfiguration(const std::string& jointName, const double jointConfiguration)
    {
        iDynTree::JointIndex jointIndex = m_dynamics.model().getJointIndex(jointName);
        if (jointIndex == iDynTree::JOINT_INVALID_INDEX) return false;
        m_state.jointsConfiguration(jointIndex) = jointConfiguration;
        updateRobotConfiguration();
        return true;
    }

    bool InverseKinematicsData::setDesiredJointConfiguration(const iDynTree::VectorDynSize& desiredJointConfiguration, const double weight)
    {
        assert(m_preferredJointsConfiguration.size() == desiredJointConfiguration.size());
        m_preferredJointsConfiguration = desiredJointConfiguration;
        if( weight >= 0.0 ) {
            m_preferredJointsWeight = weight;
        }
        return true;
    }

    void InverseKinematicsData::setRotationParametrization(enum iDynTree::InverseKinematicsRotationParametrization parametrization)
    {
        m_rotationParametrization = parametrization;
    }

    enum iDynTree::InverseKinematicsRotationParametrization InverseKinematicsData::rotationParametrization() { return m_rotationParametrization; }

    void InverseKinematicsData::updateRobotConfiguration()
    {
        m_dynamics.setRobotState(m_state.basePose,
                                 m_state.jointsConfiguration,
                                 m_state.baseTwist,
                                 m_state.jointsVelocity,
                                 m_state.worldGravity);
    }

    void InverseKinematicsData::prepareForOptimization()
    {
        //Do all stuff needed before starting an optimization problem
        //1) prepare initial condition if not explicitly set
        if (!m_areBaseInitialConditionsSet) {
            m_baseInitialCondition = m_state.basePose;
        }

        if (!m_areJointsInitialConditionsSet) {
            m_jointInitialConditions = m_state.jointsConfiguration;
        }

        //2) Check joint limits.. Is this necessary?
        for (size_t i = 0; i < m_jointInitialConditions.size(); ++i) {
            //check joint to be inside limit
            double &jointValue = m_jointInitialConditions(i);
            if (jointValue < m_jointLimits[i].first || jointValue > m_jointLimits[i].second) {
                std::cerr << "[WARNING] InverseKinematics: joint with DOFIndex " << i << " initial condition is outside the limits " << m_jointLimits[i].first << " " << m_jointLimits[i].second << std::endl;
                //set the initial value to be at the middle of the limits
                jointValue = (m_jointLimits[i].second + m_jointLimits[i].first) / 2.0;
            }
        }

    }

    void InverseKinematicsData::setTargetResolutionMode(enum iDynTree::InverseKinematicsTreatTargetAsConstraint mode)
    {
        m_targetResolutionMode = mode;
    }

    enum iDynTree::InverseKinematicsTreatTargetAsConstraint InverseKinematicsData::targetResolutionMode()
    {
        return m_targetResolutionMode;
    }

    bool InverseKinematicsData::solveProblem()
    {
        Ipopt::ApplicationReturnStatus solverStatus;

        if (Ipopt::IsNull(m_solver)) {
            m_solver = IpoptApplicationFactory();

            //TODO: set options
            //For example, one needed option is the linear solver type
            //Best thing is to wrap the IPOPT options with new structure so as to abstract them
            m_solver->Options()->SetStringValue("hessian_approximation", "limited-memory");
            m_solver->Options()->SetIntegerValue("print_level",m_verbosityLevel);
            m_solver->Options()->SetIntegerValue("max_iter", m_maxIter);
            m_solver->Options()->SetNumericValue("max_cpu_time", m_maxCpuTime);
            m_solver->Options()->SetNumericValue("tol",m_tol);
            m_solver->Options()->SetNumericValue("constr_viol_tol",m_constrTol);
#ifndef NDEBUG
            m_solver->Options()->SetStringValue("derivative_test", "first-order");
#endif

            solverStatus = m_solver->Initialize();
            if (solverStatus != Ipopt::Solve_Succeeded) {
                return false;
            }
        }

        prepareForOptimization();

        //instantiate the IpOpt problem
        internal::kinematics::InverseKinematicsNLP *iKin = new internal::kinematics::InverseKinematicsNLP(*this);
        //Do something (if necessary)
        Ipopt::SmartPtr<Ipopt::TNLP> problem(iKin);

        // Ask Ipopt to solve the problem
        solverStatus = m_solver->OptimizeTNLP(problem);

        if (solverStatus == Ipopt::Solve_Succeeded || solverStatus == Ipopt::Solved_To_Acceptable_Level ) {
            std::cout << "*** The problem solved!\n";
            return true;
        } else {
            return false;
        }
    }

    void InverseKinematicsData::getSolution(iDynTree::Transform & baseTransformSolution,
                                            iDynTree::VectorDynSize & shapeSolution)
    {
        baseTransformSolution = m_baseResults;
        shapeSolution         = m_jointsResults;
    }

}
}
<|endoftext|>


<commit_before>#include <gst/gst.h>
#include "MediaSinkImpl.hpp"
#include "MediaSourceImpl.hpp"
#include <jsonrpc/JsonSerializer.hpp>
#include <KurentoException.hpp>
#include <MediaType.hpp>
#include <gst/gst.h>

#define GST_CAT_DEFAULT kurento_media_source_impl
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "KurentoMediaSourceImpl"

namespace kurento
{

struct tmp_data {
  GMutex mutex;
  std::weak_ptr<MediaSourceImpl> src;
  std::weak_ptr<MediaSinkImpl> sink;
  gulong handler;
};

static void
destroy_tmp_data (gpointer data, GClosure *closure)
{
  struct tmp_data *tmp = (struct tmp_data *) data;

  tmp->src.reset();
  tmp->sink.reset();
  g_mutex_clear (&tmp->mutex);
  g_slice_free (struct tmp_data, tmp);
}

static struct tmp_data *
create_tmp_data (std::shared_ptr<MediaSourceImpl> src,
                 std::shared_ptr<MediaSinkImpl> sink)
{
  struct tmp_data *tmp;

  tmp = g_slice_new0 (struct tmp_data);

  g_mutex_init (&tmp->mutex);

  tmp->src = std::weak_ptr<MediaSourceImpl> (src);
  tmp->sink = std::weak_ptr<MediaSinkImpl> (sink);
  tmp->handler = 0L;

  return tmp;
}

static void
pad_unlinked (GstPad *pad, GstPad *peer, GstElement *parent)
{
  gst_element_release_request_pad (parent, pad);
}

gboolean
link_media_elements (std::shared_ptr<MediaSourceImpl> src,
                     std::shared_ptr<MediaSinkImpl> sink)
{
  std::unique_lock<std::recursive_mutex> lock (src->mutex);
  bool ret = FALSE;
  GstPad *pad;

  pad = gst_element_get_request_pad (src->getGstreamerElement(),
                                     src->getPadName() );

  if (pad == NULL) {
    return FALSE;
  }

  GST_WARNING ("Connecting pad %s", src->getPadName() );

  g_signal_connect_data (G_OBJECT (pad), "unlinked", G_CALLBACK (pad_unlinked),
                         g_object_ref (src->getGstreamerElement() ),
                         (GClosureNotify) g_object_unref, (GConnectFlags) 0);

  if (sink->linkPad (src, pad) ) {
    src->connectedSinks.push_back (std::weak_ptr<MediaSinkImpl> (sink) );
    ret = TRUE;
  } else {
    gst_element_release_request_pad (src->getGstreamerElement(), pad);
    ret = FALSE;
  }

  gst_object_unref (pad);

  return ret;
}

static void
disconnect_handler (GstElement *element, struct tmp_data *data)
{
  g_mutex_lock (&data->mutex);

  if (data->handler != 0) {
    g_signal_handler_disconnect (element, data->handler);
    data->handler = 0;
  }

  g_mutex_unlock (&data->mutex);
}

static void
agnosticbin_added_cb (GstElement *element, gpointer data)
{
  struct tmp_data *tmp = (struct tmp_data *) data;
  std::shared_ptr<MediaSourceImpl> src;
  std::shared_ptr<MediaSinkImpl> sink;

  try {
    src = tmp->src.lock();
    sink = tmp->sink.lock();

    if (src && sink && link_media_elements (src, sink) ) {
      disconnect_handler (element, tmp);
    }
  } catch (const std::bad_weak_ptr &e) {
    GST_WARNING ("Removed before connecting");

    disconnect_handler (element, tmp);
  }
}

MediaSourceImpl::MediaSourceImpl (const boost::property_tree::ptree &config,
                                  std::shared_ptr<MediaType> mediaType,
                                  const std::string &mediaDescription,
                                  std::shared_ptr<MediaObjectImpl> parent) :
  MediaPadImpl (config, parent, mediaType, mediaDescription)
{
}

MediaSourceImpl::~MediaSourceImpl()
{
  std::unique_lock<std::recursive_mutex> lock (mutex);

  for (auto it = connectedSinks.begin(); it != connectedSinks.end(); it++) {
    try {
      std::shared_ptr<MediaSinkImpl> connectedSinkLocked;

      GST_INFO ("connectedSink");
      connectedSinkLocked = it->lock();

      if (connectedSinkLocked != NULL) {
        connectedSinkLocked->unlinkUnchecked (NULL);
      }
    } catch (const std::bad_weak_ptr &e) {
      GST_WARNING ("Got invalid reference while releasing MediaSrc %s",
                   getId().c_str() );
    }
  }
}

const gchar *
MediaSourceImpl::getPadName ()
{
  if ( ( (MediaPadImpl *) this)->getMediaType()->getValue() == MediaType::AUDIO) {
    return (const gchar *) "audio_src_%u";
  } else {
    return (const gchar *) "video_src_%u";
  }
}

void MediaSourceImpl::connect (std::shared_ptr<MediaSink> sink)
{
  std::unique_lock<std::recursive_mutex> lock (mutex);
  std::shared_ptr<MediaSinkImpl> mediaSinkImpl =
    std::dynamic_pointer_cast<MediaSinkImpl> (sink);
  GstPad *pad;
  bool ret;

  GST_INFO ("connect %s to %s", this->getId().c_str(),
            mediaSinkImpl->getId().c_str() );

  pad = gst_element_get_request_pad (getGstreamerElement(), getPadName() );

  if (pad == NULL) {
    struct tmp_data *tmp;

    GST_DEBUG ("Put connection off until agnostic bin is created for pad %s",
               getPadName() );
    tmp = create_tmp_data (std::dynamic_pointer_cast<MediaSourceImpl>
                           (shared_from_this() ), mediaSinkImpl);
    tmp->handler = g_signal_connect_data (getGstreamerElement(),
                                          "agnosticbin-added",
                                          G_CALLBACK (agnosticbin_added_cb),
                                          tmp, destroy_tmp_data,
                                          (GConnectFlags) 0);
    return;
  }

  g_signal_connect_data (G_OBJECT (pad), "unlinked", G_CALLBACK (pad_unlinked),
                         g_object_ref (getGstreamerElement() ),
                         (GClosureNotify) g_object_unref, (GConnectFlags) 0);

  ret = mediaSinkImpl->linkPad (
          std::dynamic_pointer_cast <MediaSourceImpl> (shared_from_this() ), pad);

  if (ret) {
    connectedSinks.push_back (std::weak_ptr<MediaSinkImpl> (mediaSinkImpl) );
  } else {
    gst_element_release_request_pad (getGstreamerElement(), pad);
  }

  g_object_unref (pad);

  if (!ret) {
    throw KurentoException (CONNECT_ERROR, "Cannot link pads");
  }
}

void
MediaSourceImpl::removeSink (MediaSinkImpl *mediaSink)
{
  std::unique_lock<std::recursive_mutex> lock (mutex);
  std::shared_ptr<MediaSinkImpl> sinkLocked;
  std::vector< std::weak_ptr<MediaSinkImpl> >::iterator it;

  it = connectedSinks.begin();

  while (it != connectedSinks.end() ) {
    try {
      sinkLocked = (*it).lock();
    } catch (const std::bad_weak_ptr &e) {
    }

    if (sinkLocked == NULL || sinkLocked->getId() == mediaSink->getId() ) {
      it = connectedSinks.erase (it);
    } else {
      it++;
    }
  }
}

void
MediaSourceImpl::disconnect (MediaSinkImpl *mediaSink)
{
  std::unique_lock<std::recursive_mutex> lock (mutex);

  GST_INFO ("disconnect %s from %s", this->getId().c_str(),
            mediaSink->getId().c_str() );

  mediaSink->unlink (std::dynamic_pointer_cast<MediaSourceImpl>
                     (shared_from_this() ), NULL);
}

std::vector < std::shared_ptr<MediaSink> >
MediaSourceImpl::getConnectedSinks ()
{
  std::unique_lock<std::recursive_mutex> lock (mutex);
  std::vector < std::shared_ptr<MediaSink> > sinks;

  std::shared_ptr<MediaSinkImpl> sinkLocked;
  std::vector< std::weak_ptr<MediaSinkImpl> >::iterator it;

  for ( it = connectedSinks.begin() ; it != connectedSinks.end(); ++it) {
    try {
      sinkLocked = (*it).lock();
    } catch (const std::bad_weak_ptr &e) {
    }

    if (sinkLocked != NULL) {
      sinks.push_back (std::dynamic_pointer_cast<MediaSink> (sinkLocked) );
    }
  }

  return sinks;
}

MediaSourceImpl::StaticConstructor MediaSourceImpl::staticConstructor;

MediaSourceImpl::StaticConstructor::StaticConstructor()
{
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0,
                           GST_DEFAULT_NAME);
}

} /* kurento */
<commit_msg>MediaSource: Reduce log from warning to debug<commit_after>#include <gst/gst.h>
#include "MediaSinkImpl.hpp"
#include "MediaSourceImpl.hpp"
#include <jsonrpc/JsonSerializer.hpp>
#include <KurentoException.hpp>
#include <MediaType.hpp>
#include <gst/gst.h>

#define GST_CAT_DEFAULT kurento_media_source_impl
GST_DEBUG_CATEGORY_STATIC (GST_CAT_DEFAULT);
#define GST_DEFAULT_NAME "KurentoMediaSourceImpl"

namespace kurento
{

struct tmp_data {
  GMutex mutex;
  std::weak_ptr<MediaSourceImpl> src;
  std::weak_ptr<MediaSinkImpl> sink;
  gulong handler;
};

static void
destroy_tmp_data (gpointer data, GClosure *closure)
{
  struct tmp_data *tmp = (struct tmp_data *) data;

  tmp->src.reset();
  tmp->sink.reset();
  g_mutex_clear (&tmp->mutex);
  g_slice_free (struct tmp_data, tmp);
}

static struct tmp_data *
create_tmp_data (std::shared_ptr<MediaSourceImpl> src,
                 std::shared_ptr<MediaSinkImpl> sink)
{
  struct tmp_data *tmp;

  tmp = g_slice_new0 (struct tmp_data);

  g_mutex_init (&tmp->mutex);

  tmp->src = std::weak_ptr<MediaSourceImpl> (src);
  tmp->sink = std::weak_ptr<MediaSinkImpl> (sink);
  tmp->handler = 0L;

  return tmp;
}

static void
pad_unlinked (GstPad *pad, GstPad *peer, GstElement *parent)
{
  gst_element_release_request_pad (parent, pad);
}

gboolean
link_media_elements (std::shared_ptr<MediaSourceImpl> src,
                     std::shared_ptr<MediaSinkImpl> sink)
{
  std::unique_lock<std::recursive_mutex> lock (src->mutex);
  bool ret = FALSE;
  GstPad *pad;

  pad = gst_element_get_request_pad (src->getGstreamerElement(),
                                     src->getPadName() );

  if (pad == NULL) {
    return FALSE;
  }

  GST_DEBUG ("Connecting pad %s", src->getPadName() );

  g_signal_connect_data (G_OBJECT (pad), "unlinked", G_CALLBACK (pad_unlinked),
                         g_object_ref (src->getGstreamerElement() ),
                         (GClosureNotify) g_object_unref, (GConnectFlags) 0);

  if (sink->linkPad (src, pad) ) {
    src->connectedSinks.push_back (std::weak_ptr<MediaSinkImpl> (sink) );
    ret = TRUE;
  } else {
    gst_element_release_request_pad (src->getGstreamerElement(), pad);
    ret = FALSE;
  }

  gst_object_unref (pad);

  return ret;
}

static void
disconnect_handler (GstElement *element, struct tmp_data *data)
{
  g_mutex_lock (&data->mutex);

  if (data->handler != 0) {
    g_signal_handler_disconnect (element, data->handler);
    data->handler = 0;
  }

  g_mutex_unlock (&data->mutex);
}

static void
agnosticbin_added_cb (GstElement *element, gpointer data)
{
  struct tmp_data *tmp = (struct tmp_data *) data;
  std::shared_ptr<MediaSourceImpl> src;
  std::shared_ptr<MediaSinkImpl> sink;

  try {
    src = tmp->src.lock();
    sink = tmp->sink.lock();

    if (src && sink && link_media_elements (src, sink) ) {
      disconnect_handler (element, tmp);
    }
  } catch (const std::bad_weak_ptr &e) {
    GST_WARNING ("Removed before connecting");

    disconnect_handler (element, tmp);
  }
}

MediaSourceImpl::MediaSourceImpl (const boost::property_tree::ptree &config,
                                  std::shared_ptr<MediaType> mediaType,
                                  const std::string &mediaDescription,
                                  std::shared_ptr<MediaObjectImpl> parent) :
  MediaPadImpl (config, parent, mediaType, mediaDescription)
{
}

MediaSourceImpl::~MediaSourceImpl()
{
  std::unique_lock<std::recursive_mutex> lock (mutex);

  for (auto it = connectedSinks.begin(); it != connectedSinks.end(); it++) {
    try {
      std::shared_ptr<MediaSinkImpl> connectedSinkLocked;

      GST_INFO ("connectedSink");
      connectedSinkLocked = it->lock();

      if (connectedSinkLocked != NULL) {
        connectedSinkLocked->unlinkUnchecked (NULL);
      }
    } catch (const std::bad_weak_ptr &e) {
      GST_WARNING ("Got invalid reference while releasing MediaSrc %s",
                   getId().c_str() );
    }
  }
}

const gchar *
MediaSourceImpl::getPadName ()
{
  if ( ( (MediaPadImpl *) this)->getMediaType()->getValue() == MediaType::AUDIO) {
    return (const gchar *) "audio_src_%u";
  } else {
    return (const gchar *) "video_src_%u";
  }
}

void MediaSourceImpl::connect (std::shared_ptr<MediaSink> sink)
{
  std::unique_lock<std::recursive_mutex> lock (mutex);
  std::shared_ptr<MediaSinkImpl> mediaSinkImpl =
    std::dynamic_pointer_cast<MediaSinkImpl> (sink);
  GstPad *pad;
  bool ret;

  GST_INFO ("connect %s to %s", this->getId().c_str(),
            mediaSinkImpl->getId().c_str() );

  pad = gst_element_get_request_pad (getGstreamerElement(), getPadName() );

  if (pad == NULL) {
    struct tmp_data *tmp;

    GST_DEBUG ("Put connection off until agnostic bin is created for pad %s",
               getPadName() );
    tmp = create_tmp_data (std::dynamic_pointer_cast<MediaSourceImpl>
                           (shared_from_this() ), mediaSinkImpl);
    tmp->handler = g_signal_connect_data (getGstreamerElement(),
                                          "agnosticbin-added",
                                          G_CALLBACK (agnosticbin_added_cb),
                                          tmp, destroy_tmp_data,
                                          (GConnectFlags) 0);
    return;
  }

  g_signal_connect_data (G_OBJECT (pad), "unlinked", G_CALLBACK (pad_unlinked),
                         g_object_ref (getGstreamerElement() ),
                         (GClosureNotify) g_object_unref, (GConnectFlags) 0);

  ret = mediaSinkImpl->linkPad (
          std::dynamic_pointer_cast <MediaSourceImpl> (shared_from_this() ), pad);

  if (ret) {
    connectedSinks.push_back (std::weak_ptr<MediaSinkImpl> (mediaSinkImpl) );
  } else {
    gst_element_release_request_pad (getGstreamerElement(), pad);
  }

  g_object_unref (pad);

  if (!ret) {
    throw KurentoException (CONNECT_ERROR, "Cannot link pads");
  }
}

void
MediaSourceImpl::removeSink (MediaSinkImpl *mediaSink)
{
  std::unique_lock<std::recursive_mutex> lock (mutex);
  std::shared_ptr<MediaSinkImpl> sinkLocked;
  std::vector< std::weak_ptr<MediaSinkImpl> >::iterator it;

  it = connectedSinks.begin();

  while (it != connectedSinks.end() ) {
    try {
      sinkLocked = (*it).lock();
    } catch (const std::bad_weak_ptr &e) {
    }

    if (sinkLocked == NULL || sinkLocked->getId() == mediaSink->getId() ) {
      it = connectedSinks.erase (it);
    } else {
      it++;
    }
  }
}

void
MediaSourceImpl::disconnect (MediaSinkImpl *mediaSink)
{
  std::unique_lock<std::recursive_mutex> lock (mutex);

  GST_INFO ("disconnect %s from %s", this->getId().c_str(),
            mediaSink->getId().c_str() );

  mediaSink->unlink (std::dynamic_pointer_cast<MediaSourceImpl>
                     (shared_from_this() ), NULL);
}

std::vector < std::shared_ptr<MediaSink> >
MediaSourceImpl::getConnectedSinks ()
{
  std::unique_lock<std::recursive_mutex> lock (mutex);
  std::vector < std::shared_ptr<MediaSink> > sinks;

  std::shared_ptr<MediaSinkImpl> sinkLocked;
  std::vector< std::weak_ptr<MediaSinkImpl> >::iterator it;

  for ( it = connectedSinks.begin() ; it != connectedSinks.end(); ++it) {
    try {
      sinkLocked = (*it).lock();
    } catch (const std::bad_weak_ptr &e) {
    }

    if (sinkLocked != NULL) {
      sinks.push_back (std::dynamic_pointer_cast<MediaSink> (sinkLocked) );
    }
  }

  return sinks;
}

MediaSourceImpl::StaticConstructor MediaSourceImpl::staticConstructor;

MediaSourceImpl::StaticConstructor::StaticConstructor()
{
  GST_DEBUG_CATEGORY_INIT (GST_CAT_DEFAULT, GST_DEFAULT_NAME, 0,
                           GST_DEFAULT_NAME);
}

} /* kurento */
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2014-2017 Los Alamos National Security, LLC
 *                         All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY 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.
 */

#pragma once

#include "LegionItems.hpp"

#include <deque>
#include <vector>
#include <climits>

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
template<typename TYPE>
struct LogicalArray : public LogicalItem<TYPE> {
public:

    /**
     *
     */
    LogicalArray(void) : LogicalItem<TYPE>() { }

    /**
     * Instantiate from a LogicalRegion.
     */
    LogicalArray(
        const LogicalRegion &lr,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) : LogicalItem<TYPE>(lr, ctx, lrt) { }

    /**
     *
     */
    virtual
    ~LogicalArray(void) = default;

    /**
     *
     */
    void
    allocate(
        const std::string &name,
        int64_t nElems,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) {
        this->mAllocate(name, nElems, ctx, lrt);
    }

    /**
     * Returns whether or not two LogicalArrays are the same (as far as the
     * Legion RT is concerned).
     */
    static bool
    same(
        const LogicalArray &a,
        const LogicalArray &b
    ) {
        return a.mIndexSpaceID == b.mIndexSpaceID &&
               a.mFieldSpaceID == b.mFieldSpaceID &&
               a.mRTreeID      == b.mRTreeID;
    }

    /**
     *
     */
    void
    partition(
        size_t nParts,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) {
        // Only allow even partitioning.
        assert(0 == this->mLength % nParts && "Uneven partitioning requested.");
        //
        int64_t inc = this->mLength / nParts; // the increment
        Rect<1> colorBounds(Point<1>(0), Point<1>(nParts - 1));
        Domain colorDomain = Domain::from_rect<1>(colorBounds);
        //          +
        //          |
        //          |
        //     (x1)-+-+
        //          | |
        //          | m / nSubregions
        //     (x0) + |
        size_t x0 = 0, x1 = inc - 1;
        DomainColoring disjointColoring;
        // a list of sub-grid bounds.
        // provides a task ID to sub-grid bounds mapping.
        std::vector< Rect<1> > subGridBounds;
        for (size_t color = 0; color < nParts; ++color) {
            Rect<1> subRect((Point<1>(x0)), (Point<1>(x1)));
            // cache the subgrid bounds
            subGridBounds.push_back(subRect);
#if 0 // Debug.
            printf("vec disjoint partition: (%d) to (%d)\n",
                    subRect.lo.x[0], subRect.hi.x[0]);
#endif
            disjointColoring[color] = Domain::from_rect<1>(subRect);
            x0 += inc;
            x1 += inc;
        }
        this->indexPartition = lrt->create_index_partition(
            ctx,
            this->mIndexSpace,
            colorDomain,
            disjointColoring,
            true
        );
        // Logical partitions.
        this->logicalPartition = lrt->get_logical_partition(
            ctx,
            this->logicalRegion,
            this->indexPartition
        );
        // Launch domain -- one task per color.
        this->launchDomain = colorDomain;
        //
        this->mAttachNameAtPartition(ctx, lrt);
    }

    /**
     *
     */
    void
    partition(
        const std::vector<local_int_t> &partLens,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) {
        const size_t nParts = partLens.size();
        Rect<1> colorBounds(Point<1>(0), Point<1>(nParts - 1));
        Domain colorDomain = Domain::from_rect<1>(colorBounds);
        //
        size_t parti = 0;
        size_t x0 = 0, x1 = partLens[parti] - 1;
        DomainColoring disjointColoring;
        // provides a task ID to sub-grid bounds mapping.
        std::vector< Rect<1> > subGridBounds;
        for (size_t color = 0; color < nParts; ++color) {
            Rect<1> subRect((Point<1>(x0)), (Point<1>(x1)));
            // cache the subgrid bounds
            subGridBounds.push_back(subRect);
#if 0 // nice debug
            printf("vec len=%ld\n", (long)partLens[parti]);
            printf("vec disjoint partition: (%ld) to (%ld)\n",
                    (long)subRect.lo.x[0], (long)subRect.hi.x[0]);
#endif
            disjointColoring[color] = Domain::from_rect<1>(subRect);
            // slide window
            x0 += partLens[parti];
            x1 = (x0 + partLens[++parti] - 1);
        }
        this->indexPartition = lrt->create_index_partition(
            ctx,
            this->mIndexSpace,
            colorDomain,
            disjointColoring,
            true /* disjoint */
        );
        // Logical partitions.
        this->logicalPartition = lrt->get_logical_partition(
            ctx,
            this->logicalRegion,
            this->indexPartition
        );
        // Launch domain -- one task per color.
        this->launchDomain = colorDomain;
        //
        this->mAttachNameAtPartition(ctx, lrt);
    }

    /**
     * Creates a single, contiguous partition from a BaseExtent instance.
     */
    void
    partition(
        BaseExtent be,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) {
        Rect<1> colorBounds(Point<1>(0), Point<1>(0));
        Domain colorDomain = Domain::from_rect<1>(colorBounds);
        //
        size_t x0 = be.base, x1 = (be.base + be.extent) - 1;
        DomainColoring disjointColoring;
        Rect<1> subGridBounds;
        //
        Rect<1> subRect((Point<1>(x0)), (Point<1>(x1)));
        // Cache the subgrid bounds.
        subGridBounds = subRect;
#if 0 // Debug.
        printf("vec len=%ld\n", (long)be.extent);
        printf("vec disjoint partition: (%ld) to (%ld)\n",
                (long)subRect.lo.x[0], (long)subRect.hi.x[0]);
#endif
        //
        disjointColoring[0] = Domain::from_rect<1>(subRect);
        this->indexPartition = lrt->create_index_partition(
            ctx,
            this->mIndexSpace,
            colorDomain,
            disjointColoring,
            true /* disjoint */
        );
        // Logical partitions.
        this->logicalPartition = lrt->get_logical_partition(
            ctx,
            this->logicalRegion,
            this->indexPartition
        );
        // Launch domain -- one task per color.
        this->launchDomain = colorDomain;
        //
        this->mAttachNameAtPartition(ctx, lrt);
    }
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
template<typename TYPE>
struct Array : public Item<TYPE> {
    //
    std::vector<LogicalArray<TYPE> *> ghosts;

    /**
     *
     */
    Array(
        const PhysicalRegion &physicalRegion,
        Context ctx,
        HighLevelRuntime *runtime
    ) : Item<TYPE>(physicalRegion, ctx, runtime) { }

    /**
     *
     */
    ~Array(void) {
        for (auto *i : ghosts) {
            delete i;
        }
    }

    /**
     *
     */
    size_t
    length(void) const { return this->mLength; }

    /**
     *
     */
    bool
    hasGhosts(void) { return (ghosts.size() > 0); }
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
 * Interprets 1D array as NxM 2D array.
 */
template<typename TYPE>
class Array2D {
protected:
    //
    size_t mNRows = 0;
    //
    size_t mNCols = 0;
    //
    TYPE *mBasePtr = nullptr;
public:
    /**
     *
     */
    Array2D(void) = default;

    /**
     *
     */
    ~Array2D(void) {
        mNRows = 0;
        mNCols = 0;
        // Don't free memory here because we don't know what allocated that
        // memory. Assume that it'll get cleaned up another way.
    }

    /**
     *
     */
    Array2D(
        size_t nRows,
        size_t nCols,
        TYPE *basePtr
    ) : mNRows(nRows)
      , mNCols(nCols)
      , mBasePtr(basePtr) { }

    /**
     *
     */
    const TYPE &
    operator()(size_t row, size_t col) const
    {
        return mBasePtr[(row * mNCols) + col];
    }

    /**
     *
     */
    TYPE &
    operator()(size_t row, size_t col)
    {
        return mBasePtr[(row * mNCols) + col];
    }

    /**
     *
     */
    TYPE *
    operator()(size_t row)
    {
        return (mBasePtr + (row * mNCols));
    }
};
<commit_msg>Silence Valgrind warning.<commit_after>/*
 * Copyright (c) 2014-2017 Los Alamos National Security, LLC
 *                         All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 * this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice,
 * this list of conditions and the following disclaimer in the documentation
 * and/or other materials provided with the distribution.
 *
 * THIS SOFTWARE IS PROVIDED BY 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.
 */

#pragma once

#include "LegionItems.hpp"

#include <deque>
#include <vector>
#include <climits>

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
template<typename TYPE>
struct LogicalArray : public LogicalItem<TYPE> {
public:

    /**
     *
     */
    LogicalArray(void) : LogicalItem<TYPE>() { }

    /**
     * Instantiate from a LogicalRegion.
     */
    LogicalArray(
        const LogicalRegion &lr,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) : LogicalItem<TYPE>(lr, ctx, lrt) { }

    /**
     *
     */
    virtual
    ~LogicalArray(void) = default;

    /**
     *
     */
    void
    allocate(
        const std::string &name,
        int64_t nElems,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) {
        this->mAllocate(name, nElems, ctx, lrt);
    }

    /**
     * Returns whether or not two LogicalArrays are the same (as far as the
     * Legion RT is concerned).
     */
    static bool
    same(
        const LogicalArray &a,
        const LogicalArray &b
    ) {
        return a.mIndexSpaceID == b.mIndexSpaceID &&
               a.mFieldSpaceID == b.mFieldSpaceID &&
               a.mRTreeID      == b.mRTreeID;
    }

    /**
     *
     */
    void
    partition(
        size_t nParts,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) {
        // Only allow even partitioning.
        assert(0 == this->mLength % nParts && "Uneven partitioning requested.");
        //
        int64_t inc = this->mLength / nParts; // the increment
        Rect<1> colorBounds(Point<1>(0), Point<1>(nParts - 1));
        Domain colorDomain = Domain::from_rect<1>(colorBounds);
        //          +
        //          |
        //          |
        //     (x1)-+-+
        //          | |
        //          | m / nSubregions
        //     (x0) + |
        size_t x0 = 0, x1 = inc - 1;
        DomainColoring disjointColoring;
        // a list of sub-grid bounds.
        // provides a task ID to sub-grid bounds mapping.
        std::vector< Rect<1> > subGridBounds;
        for (size_t color = 0; color < nParts; ++color) {
            Rect<1> subRect((Point<1>(x0)), (Point<1>(x1)));
            // cache the subgrid bounds
            subGridBounds.push_back(subRect);
#if 0 // Debug.
            printf("vec disjoint partition: (%d) to (%d)\n",
                    subRect.lo.x[0], subRect.hi.x[0]);
#endif
            disjointColoring[color] = Domain::from_rect<1>(subRect);
            x0 += inc;
            x1 += inc;
        }
        this->indexPartition = lrt->create_index_partition(
            ctx,
            this->mIndexSpace,
            colorDomain,
            disjointColoring,
            true
        );
        // Logical partitions.
        this->logicalPartition = lrt->get_logical_partition(
            ctx,
            this->logicalRegion,
            this->indexPartition
        );
        // Launch domain -- one task per color.
        this->launchDomain = colorDomain;
        //
        this->mAttachNameAtPartition(ctx, lrt);
    }

    /**
     *
     */
    void
    partition(
        const std::vector<local_int_t> &partLens,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) {
        const size_t nParts = partLens.size();
        Rect<1> colorBounds(Point<1>(0), Point<1>(nParts - 1));
        Domain colorDomain = Domain::from_rect<1>(colorBounds);
        //
        size_t x0 = 0, x1 = 0;
        DomainColoring disjointColoring;
        // Provides a task ID to sub-grid bounds mapping.
        std::vector< Rect<1> > subGridBounds;
        for (size_t color = 0; color < nParts; ++color) {
            x1 = x0 + partLens[color] - 1;
            Rect<1> subRect((Point<1>(x0)), (Point<1>(x1)));
            // Cache the subgrid bounds.
            subGridBounds.push_back(subRect);
#if 0 // Debug.
            printf("vec len=%ld\n", (long)partLens[color]);
            printf("vec disjoint partition: (%ld) to (%ld)\n",
                    (long)subRect.lo.x[0], (long)subRect.hi.x[0]);
#endif
            disjointColoring[color] = Domain::from_rect<1>(subRect);
            // Slide window.
            x0 += partLens[color];
        }
        this->indexPartition = lrt->create_index_partition(
            ctx,
            this->mIndexSpace,
            colorDomain,
            disjointColoring,
            true /* disjoint */
        );
        // Logical partitions.
        this->logicalPartition = lrt->get_logical_partition(
            ctx,
            this->logicalRegion,
            this->indexPartition
        );
        // Launch domain -- one task per color.
        this->launchDomain = colorDomain;
        //
        this->mAttachNameAtPartition(ctx, lrt);
    }

    /**
     * Creates a single, contiguous partition from a BaseExtent instance.
     */
    void
    partition(
        BaseExtent be,
        Legion::Context ctx,
        Legion::HighLevelRuntime *lrt
    ) {
        Rect<1> colorBounds(Point<1>(0), Point<1>(0));
        Domain colorDomain = Domain::from_rect<1>(colorBounds);
        //
        size_t x0 = be.base, x1 = (be.base + be.extent) - 1;
        DomainColoring disjointColoring;
        Rect<1> subGridBounds;
        //
        Rect<1> subRect((Point<1>(x0)), (Point<1>(x1)));
        // Cache the subgrid bounds.
        subGridBounds = subRect;
#if 0 // Debug.
        printf("vec len=%ld\n", (long)be.extent);
        printf("vec disjoint partition: (%ld) to (%ld)\n",
                (long)subRect.lo.x[0], (long)subRect.hi.x[0]);
#endif
        //
        disjointColoring[0] = Domain::from_rect<1>(subRect);
        this->indexPartition = lrt->create_index_partition(
            ctx,
            this->mIndexSpace,
            colorDomain,
            disjointColoring,
            true /* disjoint */
        );
        // Logical partitions.
        this->logicalPartition = lrt->get_logical_partition(
            ctx,
            this->logicalRegion,
            this->indexPartition
        );
        // Launch domain -- one task per color.
        this->launchDomain = colorDomain;
        //
        this->mAttachNameAtPartition(ctx, lrt);
    }
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
template<typename TYPE>
struct Array : public Item<TYPE> {
    //
    std::vector<LogicalArray<TYPE> *> ghosts;

    /**
     *
     */
    Array(
        const PhysicalRegion &physicalRegion,
        Context ctx,
        HighLevelRuntime *runtime
    ) : Item<TYPE>(physicalRegion, ctx, runtime) { }

    /**
     *
     */
    ~Array(void) {
        for (auto *i : ghosts) {
            delete i;
        }
    }

    /**
     *
     */
    size_t
    length(void) const { return this->mLength; }

    /**
     *
     */
    bool
    hasGhosts(void) { return (ghosts.size() > 0); }
};

////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////
/**
 * Interprets 1D array as NxM 2D array.
 */
template<typename TYPE>
class Array2D {
protected:
    //
    size_t mNRows = 0;
    //
    size_t mNCols = 0;
    //
    TYPE *mBasePtr = nullptr;
public:
    /**
     *
     */
    Array2D(void) = default;

    /**
     *
     */
    ~Array2D(void) {
        mNRows = 0;
        mNCols = 0;
        // Don't free memory here because we don't know what allocated that
        // memory. Assume that it'll get cleaned up another way.
    }

    /**
     *
     */
    Array2D(
        size_t nRows,
        size_t nCols,
        TYPE *basePtr
    ) : mNRows(nRows)
      , mNCols(nCols)
      , mBasePtr(basePtr) { }

    /**
     *
     */
    const TYPE &
    operator()(size_t row, size_t col) const
    {
        return mBasePtr[(row * mNCols) + col];
    }

    /**
     *
     */
    TYPE &
    operator()(size_t row, size_t col)
    {
        return mBasePtr[(row * mNCols) + col];
    }

    /**
     *
     */
    TYPE *
    operator()(size_t row)
    {
        return (mBasePtr + (row * mNCols));
    }
};
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <fstream>

using namespace std;

typedef string Value;

struct TreeElement
{
    string value;
    TreeElement *leftChild;
    TreeElement *rightChild;
};

int toInt(string str)
{
    int length = static_cast<int>(str.size());
    int sum = 0;
    for (int i = 0; i < length; ++i)
    {
        sum = sum * 10 + static_cast<int>(str[i]) - static_cast<int>('0');
    }
    return sum;
}

TreeElement* createTree(string str)
{
    int length = str.size();
    if (str[0] != '(')
    {
        return new TreeElement{ str, nullptr, nullptr };
    }
    string op = "";
    op = op + str[1];
    string str1 = "";
    string str2 = "";
    if (str[3] != '(')
    {
        int i = 3;
        while (str[i] != ' ')
        {
            str1 = str1 + str[i];
            ++i;
        }
        for (auto j = i + 1; j < length - 1; ++j)
        {
            str2 = str2 + str[j];
        }
    }
    if (str[3] == '(')
    {
        str1 = "(";
        int i = 4;
        int k = 1;
        int l = 0;
        while (k > l)
        {
            if (str[i] == '(')
            {
                ++k;
            }
            else if (str[i] == ')')
            {
                ++l;
            }
            str1 = str1 + str[i];
            ++i;
        }
        for (auto j = i + 1; j < length - 1; ++j)
        {
            str2 = str2 + str[j];
        }
    }
    return new TreeElement{ op, createTree(str1), createTree(str2) };
}

int calculate(TreeElement *root)
{
	if (root->value == "+")
    {
        return calculate(root->leftChild) + calculate(root->rightChild);
    }
    if (root->value == "-")
    {
        return calculate(root->leftChild) - calculate(root->rightChild);
    }
    if (root->value == "*")
    {
        return calculate(root->leftChild) * calculate(root->rightChild);
    }
    if (root->value == "/")
    {
        return calculate(root->leftChild) / calculate(root->rightChild);
    }
    return toInt(root->value);
}

void deleteTree(TreeElement *&root)
{
    if (root)
    {
        deleteTree(root->leftChild);
        deleteTree(root->rightChild);
        delete root;
    }
}

void preorder(TreeElement *root)
{
    if (root)
    {
        bool b = root->value == "+" || root->value == "-" || root->value == "*" || root->value == "/";
        if (b)
        {
            cout << "(";
        }
        cout << root->value << " ";
        preorder(root->leftChild);
        preorder(root->rightChild);
        if (b)
        {
            cout << ") ";
        }
    }
}

void print(TreeElement *tree)
{
    preorder(tree);
    cout << endl;
}

TreeElement *createTreeFromFile()
{
	ifstream file("file.txt");
	if (!file.is_open())
	{
		cout << "error" << endl;
		return nullptr;
	}
	string str = "";
	getline(file, str);
	file.close();
	auto tree = createTree(str);
	return tree;
}

bool test1()
{
    auto tree = createTreeFromFile();
    print(tree);
    cout << endl;
    int b = calculate(tree);
    cout << b << endl;
    deleteTree(tree);
    return b == 4;
}

int main()
{
    cout << test1() << endl;
    return 0;
}
<commit_msg>-исправлены некоторые ошибки<commit_after>#include <iostream>
#include <string>
#include <fstream>

using namespace std;

struct TreeElement
{
	string value;
	TreeElement *leftChild;
	TreeElement *rightChild;
};

int toInt(const string str)
{
	int length = static_cast<int>(str.size());
	int sum = 0;
	for (int i = 0; i < length; ++i)
	{
		sum = sum * 10 + static_cast<int>(str[i]) - static_cast<int>('0');
	}
	return sum;
}

TreeElement* createTree(const string str)
{
	int length = str.size();
	if (str[0] != '(')
	{
		return new TreeElement{ str, nullptr, nullptr };
	}
	string op = "";
	op += str[1];
	string leftOperand = "";
	string rightOperand = "";
	if (str[3] != '(')
	{
		int i = 3;
		while (str[i] != ' ')
		{
			leftOperand += str[i];
			++i;
		}
		for (auto j = i + 1; j < length - 1; ++j)
		{
			rightOperand += str[j];
		}
	}
	if (str[3] == '(')
	{
		leftOperand = "(";
		int i = 4;
		int openingBracketsCount = 1;
		int closingBracketsCount = 0;
		while (openingBracketsCount > closingBracketsCount)
		{
			if (str[i] == '(')
			{
				++openingBracketsCount;
			}
			else if (str[i] == ')')
			{
				++closingBracketsCount;
			}
			leftOperand += str[i];
			++i;
		}
		for (auto j = i + 1; j < length - 1; ++j)
		{
			rightOperand += str[j];
		}
	}
	return new TreeElement{ op, createTree(leftOperand), createTree(rightOperand) };
}

int calculate(TreeElement *root)
{
	if (root->value == "+")
	{
		return calculate(root->leftChild) + calculate(root->rightChild);
	}
	if (root->value == "-")
	{
		return calculate(root->leftChild) - calculate(root->rightChild);
	}
	if (root->value == "*")
	{
		return calculate(root->leftChild) * calculate(root->rightChild);
	}
	if (root->value == "/")
	{
		return calculate(root->leftChild) / calculate(root->rightChild);
	}
	return toInt(root->value);
}

void deleteTree(TreeElement *&root)
{
	if (root)
	{
		deleteTree(root->leftChild);
		deleteTree(root->rightChild);
		delete root;
	}
}

void preorder(TreeElement *root)
{
	if (root)
	{
		bool isOperator = root->value == "+" || root->value == "-" || root->value == "*" || root->value == "/";
		if (isOperator)
		{
			cout << "(";
		}
		cout << root->value << " ";
		preorder(root->leftChild);
		preorder(root->rightChild);
		if (isOperator)
		{
			cout << ") ";
		}
	}
}

void print(TreeElement *tree)
{
	preorder(tree);
	cout << endl;
}

TreeElement *createTreeFromFile()
{
	ifstream file("file.txt");
	if (!file.is_open())
	{
		cout << "error" << endl;
		return nullptr;
	}
	string str = "";
	getline(file, str);
	file.close();
	auto tree = createTree(str);
	return tree;
}

bool test1()
{
	auto tree = createTreeFromFile();
	print(tree);
	cout << endl;
	int b = calculate(tree);
	cout << b << endl;
	deleteTree(tree);
	return b == 4;
}

int main()
{
	cout << test1() << endl;
	return 0;
}
<|endoftext|>


<commit_before>// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DPL_1_D
#include <iostream>
#include <tuple>
#include <set>
using namespace std;

/* 解説を読まずにsetを使って解いた。

   前から単純に貪欲に選ぼうとしても、失敗する。
   後ろでどれだけ「緩やかな増加列」が控えているかはわからない。
   この増加列に接続すると最終的に長さの「逆転」が起こるかもしれない。

   a[0]からa[i-1]まででできる増加列に、a[i]をつなげることを検討する。
   a[i]を検討するまでに持っておく価値がある列は、
   ・列kは tail_k を末尾とするもののうち最長列(の1つ)である。
   ・length_k < length_j \longleftrightarrow tail_k > tail_j をみたしている。
   不等号が崩れる関係になっている k, j があるとすると、どちらかはいらない。

   (tail, length) で標準的に整列する。
   各a[i]に対して次の動作を行う。
   tail < a[i] となっている列に接続できるから、この内tailが一番大きい
   ものを選ぶ(列k)とする。
   ここにa[i]を接続したものを候補に加える(もとの列も残しておく)。
   加えた列は列k+1になる(または、k+2になって、k+1とtail, lengthが同じ)。
   列k+2との関係は、
   ・tail_{k+1} \leq tail_{k+2} は必ずみたされている
   ・length_{k+1} == length_{k+2} となっているかもしれない
   後者が成立している場合は、列 k+2 を考える価値はないので削除する。

   こうやって最後まで行って最長列が求まる。
   setを使うと、各a[i]でやる動作は全て \log時間なので、
   結局時間計算量はO(n \log n)である。
 */

typedef tuple<int, int> seq; // tail, length
const int infty = 1e9+10;

int main () {
  int n;
  cin >> n;
  int a[100010];
  for (auto i=0; i<n; i++) {
    cin >> a[i];
  }
  set<seq> S;
  S.insert(make_tuple(infty, 100010));
  S.insert(make_tuple(-1, 0));
  for (auto i=0; i<n; i++) {
    auto it = S.lower_bound(make_tuple(a[i], -1));
    it--;
    seq temp = *it;
    get<0>(temp) = a[i];
    int tl = ++get<1>(temp);
    S.insert(temp);
    // cerr << "insert: " << get<0>(temp) << " " << get<1>(temp) << endl;
    it++; it++;
    while (it != S.end() && get<1>(*it) <= tl) { // どうせ1個しか削除しない
      // cerr << "erase: " << get<0>(*it) << " " << get<1>(*it) << endl;
      S.erase(it++);
    }
  }
  auto it = S.end();
  it--; it--;
  cout << get<1>(*it) << endl;
}
<commit_msg>解説中の不等号を訂正<commit_after>// http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=DPL_1_D
#include <iostream>
#include <tuple>
#include <set>
using namespace std;

/* 解説を読まずにsetを使って解いた。

   前から単純に貪欲に選ぼうとしても、失敗する。
   後ろでどれだけ「緩やかな増加列」が控えているかはわからない。
   この増加列に接続すると最終的に長さの「逆転」が起こるかもしれない。

   a[0]からa[i-1]まででできる増加列に、a[i]をつなげることを検討する。
   a[i]を検討するまでに持っておく価値がある列は、
   ・列kは tail_k を末尾とするもののうち最長列(の1つ)である。
   ・length_k < length_j \longleftrightarrow tail_k \leq tail_j をみたしている。
   不等号が崩れる関係になっている k, j があるとすると、どちらかはいらない。

   (tail, length) で標準的に整列する。
   各a[i]に対して次の動作を行う。
   tail < a[i] となっている列に接続できるから、この内tailが一番大きい
   もので、lengthも一番大きいものを選ぶ(列k)とする。
   ここにa[i]を接続したものを候補に加える(もとの列も残しておく)。
   加えた列は列k+1になる(または、k+2になって、k+1とtail, lengthが同じ)。
   列k+2との関係は、
   ・tail_{k+1} \leq tail_{k+2} は必ずみたされている
   ・length_{k+1} == length_{k+2} となっているかもしれない
   後者が成立している場合は、列 k+2 を考える価値はないので削除する。

   こうやって最後まで行って最長列が求まる。
   setを使うと、各a[i]でやる動作は全て \log時間なので、
   結局時間計算量はO(n \log n)である。
 */

typedef tuple<int, int> seq; // tail, length
const int infty = 1e9+10;

int main () {
  int n;
  cin >> n;
  int a[100010];
  for (auto i=0; i<n; i++) {
    cin >> a[i];
  }
  set<seq> S;
  S.insert(make_tuple(infty, 100010));
  S.insert(make_tuple(-1, 0));
  for (auto i=0; i<n; i++) {
    auto it = S.lower_bound(make_tuple(a[i], -1));
    it--;
    seq temp = *it;
    get<0>(temp) = a[i];
    int tl = ++get<1>(temp);
    S.insert(temp);
    // cerr << "insert: " << get<0>(temp) << " " << get<1>(temp) << endl;
    it++; it++;
    while (it != S.end() && get<1>(*it) <= tl) { // どうせ1個しか削除しない
      // cerr << "erase: " << get<0>(*it) << " " << get<1>(*it) << endl;
      S.erase(it++);
    }
  }
  auto it = S.end();
  it--; it--;
  cout << get<1>(*it) << endl;
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#define SUITE table_slice

#include "vast/table_slice.hpp"

#include "vast/test/test.hpp"

#include "vast/test/fixtures/table_slices.hpp"

#include <caf/make_copy_on_write.hpp>
#include <caf/test/dsl.hpp>

#include "vast/column_major_matrix_table_slice_builder.hpp"
#include "vast/default_table_slice.hpp"
#include "vast/default_table_slice_builder.hpp"
#include "vast/matrix_table_slice.hpp"
#include "vast/row_major_matrix_table_slice_builder.hpp"
#include "vast/to_events.hpp"

using namespace vast;
using namespace std::string_literals;

namespace {

class rebranded_table_slice : public default_table_slice {
public:
  static constexpr caf::atom_value class_id = caf::atom("test");

  static table_slice_ptr make(table_slice_header header) {
    return caf::make_copy_on_write<rebranded_table_slice>(std::move(header));
  }

  explicit rebranded_table_slice(table_slice_header header)
    : default_table_slice{std::move(header)} {
    // nop
  }

  caf::atom_value implementation_id() const noexcept override {
    return class_id;
  }
};

class rebranded_table_slice_builder : public default_table_slice_builder {
public:
  using super = default_table_slice_builder;

  using table_slice_type = rebranded_table_slice;

  rebranded_table_slice_builder(record_type layout) : super(std::move(layout)) {
    // Eagerly initialize to make sure super does not create slices for us.
    eager_init();
  }

  static table_slice_builder_ptr make(record_type layout) {
    return caf::make_counted<rebranded_table_slice_builder>(std::move(layout));
  }

  table_slice_ptr finish() override {
    auto result = super::finish();
    eager_init();
    return result;
  }

  caf::atom_value implementation_id() const noexcept override {
    return get_implementation_id();
  }

  static caf::atom_value get_implementation_id() noexcept {
    return rebranded_table_slice::class_id;
  }

private:
  void eager_init() {
    table_slice_header header{layout(), rows(), 0};
    slice_.reset(new rebranded_table_slice{std::move(header)});
    row_ = vector(columns());
    col_ = 0;
  }
};

} // namespace <anonymous>

FIXTURE_SCOPE(table_slice_tests, fixtures::table_slices)

TEST_TABLE_SLICE(default_table_slice)
TEST_TABLE_SLICE(row_major_matrix_table_slice)
TEST_TABLE_SLICE(column_major_matrix_table_slice)
TEST_TABLE_SLICE(rebranded_table_slice)

TEST(random integer slices) {
  record_type layout{
    {"i", integer_type{}.attributes({{"default", "uniform(100,200)"}})}};
  layout.name("test");
  auto slices = unbox(make_random_table_slices(10, 10, layout));
  CHECK_EQUAL(slices.size(), 10u);
  CHECK(std::all_of(slices.begin(), slices.end(),
                    [](auto& slice) { return slice->rows() == 10; }));
  std::vector<integer> values;
  for (auto& slice : slices)
    for (size_t row = 0; row < slice->rows(); ++row)
      values.emplace_back(get<integer>(slice->at(row, 0)));
  auto [lowest, highest] = std::minmax_element(values.begin(), values.end());
  CHECK_GREATER_EQUAL(*lowest, 100);
  CHECK_LESS_EQUAL(*highest, 200);
}

TEST(select all) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto select_result = select(sut, make_ids({{100, 200}}));
  REQUIRE_EQUAL(select_result.size(), 1u);
  CHECK_EQUAL(select_result[0], sut);
}

TEST(select none) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto select_result = select(sut, make_ids({{200, 300}}));
  CHECK_EQUAL(select_result.size(), 0u);
}

TEST(select prefix) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto select_result = select(sut, make_ids({{0, 150}}));
  REQUIRE_EQUAL(select_result.size(), 1u);
  CHECK_EQUAL(select_result[0]->rows(), 50u);
  CHECK_EQUAL(to_events(*select_result[0]), to_events(*sut, 0, 50));
}

TEST(select off by one prefix) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto select_result = select(sut, make_ids({{101, 151}}));
  REQUIRE_EQUAL(select_result.size(), 1u);
  CHECK_EQUAL(select_result[0]->rows(), 50u);
  CHECK_EQUAL(to_events(*select_result[0]), to_events(*sut, 1, 50));
}

TEST(select intermediates) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto select_result = select(sut, make_ids({{110, 120}, {170, 180}}));
  REQUIRE_EQUAL(select_result.size(), 2u);
  CHECK_EQUAL(select_result[0]->rows(), 10u);
  CHECK_EQUAL(to_events(*select_result[0]), to_events(*sut, 10, 10));
  CHECK_EQUAL(select_result[1]->rows(), 10u);
  CHECK_EQUAL(to_events(*select_result[1]), to_events(*sut, 70, 10));
}

TEST(select off by one suffix) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto select_result = select(sut, make_ids({{149, 199}}));
  REQUIRE_EQUAL(select_result.size(), 1u);
  CHECK_EQUAL(select_result[0]->rows(), 50u);
  CHECK_EQUAL(to_events(*select_result[0]), to_events(*sut, 49, 50));
}

TEST(select suffix) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto select_result = select(sut, make_ids({{150, 300}}));
  REQUIRE_EQUAL(select_result.size(), 1u);
  CHECK_EQUAL(select_result[0]->rows(), 50u);
  CHECK_EQUAL(to_events(*select_result[0]), to_events(*sut, 50, 50));
}

FIXTURE_SCOPE_END()
<commit_msg>Choose less verbose variable names<commit_after>/******************************************************************************
 *                    _   _____   __________                                  *
 *                   | | / / _ | / __/_  __/     Visibility                   *
 *                   | |/ / __ |_\ \  / /          Across                     *
 *                   |___/_/ |_/___/ /_/       Space and Time                 *
 *                                                                            *
 * This file is part of VAST. It is subject to the license terms in the       *
 * LICENSE file found in the top-level directory of this distribution and at  *
 * http://vast.io/license. No part of VAST, including this file, may be       *
 * copied, modified, propagated, or distributed except according to the terms *
 * contained in the LICENSE file.                                             *
 ******************************************************************************/

#define SUITE table_slice

#include "vast/table_slice.hpp"

#include "vast/test/test.hpp"

#include "vast/test/fixtures/table_slices.hpp"

#include <caf/make_copy_on_write.hpp>
#include <caf/test/dsl.hpp>

#include "vast/column_major_matrix_table_slice_builder.hpp"
#include "vast/default_table_slice.hpp"
#include "vast/default_table_slice_builder.hpp"
#include "vast/matrix_table_slice.hpp"
#include "vast/row_major_matrix_table_slice_builder.hpp"
#include "vast/to_events.hpp"

using namespace vast;
using namespace std::string_literals;

namespace {

class rebranded_table_slice : public default_table_slice {
public:
  static constexpr caf::atom_value class_id = caf::atom("test");

  static table_slice_ptr make(table_slice_header header) {
    return caf::make_copy_on_write<rebranded_table_slice>(std::move(header));
  }

  explicit rebranded_table_slice(table_slice_header header)
    : default_table_slice{std::move(header)} {
    // nop
  }

  caf::atom_value implementation_id() const noexcept override {
    return class_id;
  }
};

class rebranded_table_slice_builder : public default_table_slice_builder {
public:
  using super = default_table_slice_builder;

  using table_slice_type = rebranded_table_slice;

  rebranded_table_slice_builder(record_type layout) : super(std::move(layout)) {
    // Eagerly initialize to make sure super does not create slices for us.
    eager_init();
  }

  static table_slice_builder_ptr make(record_type layout) {
    return caf::make_counted<rebranded_table_slice_builder>(std::move(layout));
  }

  table_slice_ptr finish() override {
    auto result = super::finish();
    eager_init();
    return result;
  }

  caf::atom_value implementation_id() const noexcept override {
    return get_implementation_id();
  }

  static caf::atom_value get_implementation_id() noexcept {
    return rebranded_table_slice::class_id;
  }

private:
  void eager_init() {
    table_slice_header header{layout(), rows(), 0};
    slice_.reset(new rebranded_table_slice{std::move(header)});
    row_ = vector(columns());
    col_ = 0;
  }
};

} // namespace <anonymous>

FIXTURE_SCOPE(table_slice_tests, fixtures::table_slices)

TEST_TABLE_SLICE(default_table_slice)
TEST_TABLE_SLICE(row_major_matrix_table_slice)
TEST_TABLE_SLICE(column_major_matrix_table_slice)
TEST_TABLE_SLICE(rebranded_table_slice)

TEST(random integer slices) {
  record_type layout{
    {"i", integer_type{}.attributes({{"default", "uniform(100,200)"}})}};
  layout.name("test");
  auto slices = unbox(make_random_table_slices(10, 10, layout));
  CHECK_EQUAL(slices.size(), 10u);
  CHECK(std::all_of(slices.begin(), slices.end(),
                    [](auto& slice) { return slice->rows() == 10; }));
  std::vector<integer> values;
  for (auto& slice : slices)
    for (size_t row = 0; row < slice->rows(); ++row)
      values.emplace_back(get<integer>(slice->at(row, 0)));
  auto [lowest, highest] = std::minmax_element(values.begin(), values.end());
  CHECK_GREATER_EQUAL(*lowest, 100);
  CHECK_LESS_EQUAL(*highest, 200);
}

TEST(select all) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto xs = select(sut, make_ids({{100, 200}}));
  REQUIRE_EQUAL(xs.size(), 1u);
  CHECK_EQUAL(xs[0], sut);
}

TEST(select none) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto xs = select(sut, make_ids({{200, 300}}));
  CHECK_EQUAL(xs.size(), 0u);
}

TEST(select prefix) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto xs = select(sut, make_ids({{0, 150}}));
  REQUIRE_EQUAL(xs.size(), 1u);
  CHECK_EQUAL(xs[0]->rows(), 50u);
  CHECK_EQUAL(to_events(*xs[0]), to_events(*sut, 0, 50));
}

TEST(select off by one prefix) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto xs = select(sut, make_ids({{101, 151}}));
  REQUIRE_EQUAL(xs.size(), 1u);
  CHECK_EQUAL(xs[0]->rows(), 50u);
  CHECK_EQUAL(to_events(*xs[0]), to_events(*sut, 1, 50));
}

TEST(select intermediates) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto xs = select(sut, make_ids({{110, 120}, {170, 180}}));
  REQUIRE_EQUAL(xs.size(), 2u);
  CHECK_EQUAL(xs[0]->rows(), 10u);
  CHECK_EQUAL(to_events(*xs[0]), to_events(*sut, 10, 10));
  CHECK_EQUAL(xs[1]->rows(), 10u);
  CHECK_EQUAL(to_events(*xs[1]), to_events(*sut, 70, 10));
}

TEST(select off by one suffix) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto xs = select(sut, make_ids({{149, 199}}));
  REQUIRE_EQUAL(xs.size(), 1u);
  CHECK_EQUAL(xs[0]->rows(), 50u);
  CHECK_EQUAL(to_events(*xs[0]), to_events(*sut, 49, 50));
}

TEST(select suffix) {
  auto sut = zeek_full_conn_log_slices.front();
  sut.unshared().offset(100);
  auto xs = select(sut, make_ids({{150, 300}}));
  REQUIRE_EQUAL(xs.size(), 1u);
  CHECK_EQUAL(xs[0]->rows(), 50u);
  CHECK_EQUAL(to_events(*xs[0]), to_events(*sut, 50, 50));
}

FIXTURE_SCOPE_END()
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "qmlprofilertraceclient.h"

namespace QmlJsDebugClient {

class QmlProfilerTraceClientPrivate {
public:
    QmlProfilerTraceClientPrivate()
        : inProgressRanges(0)
        , maximumTime(0)
        , recording(false)
    {
        ::memset(rangeCount, 0, MaximumQmlEventType * sizeof(int));
    }

    qint64 inProgressRanges;
    QStack<qint64> rangeStartTimes[MaximumQmlEventType];
    QStack<QStringList> rangeDatas[MaximumQmlEventType];
    QStack<Location> rangeLocations[MaximumQmlEventType];
    int rangeCount[MaximumQmlEventType];
    qint64 maximumTime;
    bool recording;
};

} // namespace QmlJsDebugClient

using namespace QmlJsDebugClient;

static const int GAP_TIME = 150;

QmlProfilerTraceClient::QmlProfilerTraceClient(QDeclarativeDebugConnection *client)
    : QDeclarativeDebugClient(QLatin1String("CanvasFrameRate"), client)
    , d(new QmlProfilerTraceClientPrivate)
{
}

QmlProfilerTraceClient::~QmlProfilerTraceClient()
{
    delete d;
}

void QmlProfilerTraceClient::clearData()
{
    ::memset(d->rangeCount, 0, MaximumQmlEventType * sizeof(int));
    emit cleared();
}

bool QmlProfilerTraceClient::isRecording() const
{
    return d->recording;
}

void QmlProfilerTraceClient::setRecording(bool v)
{
    if (v == d->recording)
        return;

    if (status() == Enabled) {
        QByteArray ba;
        QDataStream stream(&ba, QIODevice::WriteOnly);
        stream << v;
        sendMessage(ba);
    }

    d->recording = v;
    emit recordingChanged(v);
}

void QmlProfilerTraceClient::statusChanged(Status status)
{
    if (status == Enabled) {
        d->recording = !d->recording;
        setRecording(!d->recording);
        emit enabled();
    }
}

void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
{
    QByteArray rwData = data;
    QDataStream stream(&rwData, QIODevice::ReadOnly);

    qint64 time;
    int messageType;

    stream >> time >> messageType;

//    qDebug() << __FUNCTION__ << messageType;

    if (messageType >= MaximumMessage)
        return;

    if (time > (d->maximumTime + GAP_TIME) && 0 == d->inProgressRanges)
        emit gap(time);

    if (messageType == Event) {
        int event;
        stream >> event;

        if (event < MaximumEventType) {
            emit this->event((EventType)event, time);
            d->maximumTime = qMax(time, d->maximumTime);
        }
    } else if (messageType == Complete) {
        emit complete();
    } else {
        int range;
        stream >> range;

        if (range >= MaximumQmlEventType)
            return;

        if (messageType == RangeStart) {
            d->rangeStartTimes[range].push(time);
            d->inProgressRanges |= (static_cast<qint64>(1) << range);
            ++d->rangeCount[range];
        } else if (messageType == RangeData) {
            QString data;
            stream >> data;

            int count = d->rangeCount[range];
            if (count > 0) {
                while (d->rangeDatas[range].count() < count)
                    d->rangeDatas[range].push(QStringList());
                d->rangeDatas[range][count-1] << data;
            }

        } else if (messageType == RangeLocation) {
            QString fileName;
            int line;
            stream >> fileName >> line;

            if (d->rangeCount[range] > 0) {
                d->rangeLocations[range].push(Location(fileName, line));
            }
        } else {
            if (d->rangeCount[range] > 0) {
                --d->rangeCount[range];
                if (d->inProgressRanges & (static_cast<qint64>(1) << range))
                    d->inProgressRanges &= ~(static_cast<qint64>(1) << range);

                d->maximumTime = qMax(time, d->maximumTime);
                QStringList data = d->rangeDatas[range].count() ? d->rangeDatas[range].pop() : QStringList();
                Location location = d->rangeLocations[range].count() ? d->rangeLocations[range].pop() : Location();

                qint64 startTime = d->rangeStartTimes[range].pop();
                emit this->range((QmlEventType)range, startTime, time - startTime, data, location.fileName, location.line);
                if (d->rangeCount[range] == 0) {
                    int count = d->rangeDatas[range].count() +
                                d->rangeStartTimes[range].count() +
                                d->rangeLocations[range].count();
                    if (count != 0)
                        qWarning() << "incorrectly nested data";
                }
            }
        }
    }
}
<commit_msg>QmlProfiler: Don't emit recordingChanged signal if service gets enabled<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2011 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** Other Usage
**
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
** If you have questions regarding the use of this file, please contact
** Nokia at info@qt.nokia.com.
**
**************************************************************************/

#include "qmlprofilertraceclient.h"

namespace QmlJsDebugClient {

class QmlProfilerTraceClientPrivate {
public:
    QmlProfilerTraceClientPrivate(QmlProfilerTraceClient *_q)
        : q(_q)
        ,  inProgressRanges(0)
        , maximumTime(0)
        , recording(false)
    {
        ::memset(rangeCount, 0, MaximumQmlEventType * sizeof(int));
    }

    void sendRecordingStatus();

    QmlProfilerTraceClient *q;
    qint64 inProgressRanges;
    QStack<qint64> rangeStartTimes[MaximumQmlEventType];
    QStack<QStringList> rangeDatas[MaximumQmlEventType];
    QStack<Location> rangeLocations[MaximumQmlEventType];
    int rangeCount[MaximumQmlEventType];
    qint64 maximumTime;
    bool recording;
};

} // namespace QmlJsDebugClient

using namespace QmlJsDebugClient;

static const int GAP_TIME = 150;

void QmlProfilerTraceClientPrivate::sendRecordingStatus()
{
    QByteArray ba;
    QDataStream stream(&ba, QIODevice::WriteOnly);
    stream << recording;
    q->sendMessage(ba);
}

QmlProfilerTraceClient::QmlProfilerTraceClient(QDeclarativeDebugConnection *client)
    : QDeclarativeDebugClient(QLatin1String("CanvasFrameRate"), client)
    , d(new QmlProfilerTraceClientPrivate(this))
{
}

QmlProfilerTraceClient::~QmlProfilerTraceClient()
{
    delete d;
}

void QmlProfilerTraceClient::clearData()
{
    ::memset(d->rangeCount, 0, MaximumQmlEventType * sizeof(int));
    emit cleared();
}

bool QmlProfilerTraceClient::isRecording() const
{
    return d->recording;
}

void QmlProfilerTraceClient::setRecording(bool v)
{
    if (v == d->recording)
        return;

    d->recording = v;

    if (status() == Enabled) {
        d->sendRecordingStatus();
    }

    emit recordingChanged(v);
}

void QmlProfilerTraceClient::statusChanged(Status status)
{
    if (status == Enabled) {
        d->sendRecordingStatus();
        emit enabled();
    }
}

void QmlProfilerTraceClient::messageReceived(const QByteArray &data)
{
    QByteArray rwData = data;
    QDataStream stream(&rwData, QIODevice::ReadOnly);

    qint64 time;
    int messageType;

    stream >> time >> messageType;

//    qDebug() << __FUNCTION__ << messageType;

    if (messageType >= MaximumMessage)
        return;

    if (time > (d->maximumTime + GAP_TIME) && 0 == d->inProgressRanges)
        emit gap(time);

    if (messageType == Event) {
        int event;
        stream >> event;

        if (event < MaximumEventType) {
            emit this->event((EventType)event, time);
            d->maximumTime = qMax(time, d->maximumTime);
        }
    } else if (messageType == Complete) {
        emit complete();
    } else {
        int range;
        stream >> range;

        if (range >= MaximumQmlEventType)
            return;

        if (messageType == RangeStart) {
            d->rangeStartTimes[range].push(time);
            d->inProgressRanges |= (static_cast<qint64>(1) << range);
            ++d->rangeCount[range];
        } else if (messageType == RangeData) {
            QString data;
            stream >> data;

            int count = d->rangeCount[range];
            if (count > 0) {
                while (d->rangeDatas[range].count() < count)
                    d->rangeDatas[range].push(QStringList());
                d->rangeDatas[range][count-1] << data;
            }

        } else if (messageType == RangeLocation) {
            QString fileName;
            int line;
            stream >> fileName >> line;

            if (d->rangeCount[range] > 0) {
                d->rangeLocations[range].push(Location(fileName, line));
            }
        } else {
            if (d->rangeCount[range] > 0) {
                --d->rangeCount[range];
                if (d->inProgressRanges & (static_cast<qint64>(1) << range))
                    d->inProgressRanges &= ~(static_cast<qint64>(1) << range);

                d->maximumTime = qMax(time, d->maximumTime);
                QStringList data = d->rangeDatas[range].count() ? d->rangeDatas[range].pop() : QStringList();
                Location location = d->rangeLocations[range].count() ? d->rangeLocations[range].pop() : Location();

                qint64 startTime = d->rangeStartTimes[range].pop();
                emit this->range((QmlEventType)range, startTime, time - startTime, data, location.fileName, location.line);
                if (d->rangeCount[range] == 0) {
                    int count = d->rangeDatas[range].count() +
                                d->rangeStartTimes[range].count() +
                                d->rangeLocations[range].count();
                    if (count != 0)
                        qWarning() << "incorrectly nested data";
                }
            }
        }
    }
}
<|endoftext|>