<commit_before>/*
  context_glib.cpp - wraps a gpgme key context, gpgme-glib-specific functions
  Copyright (C) 2007 Klarälvdalens Datakonsult AB

  This file is part of GPGME++.

  GPGME++ is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  GPGME++ is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with GPGME++; see the file COPYING.LIB.  If not, write to the
  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include <config-gpgme++.h>

#include <gpgme++/global.h>

GIOChannel * GpgME::getGIOChannel( int ) {
#ifdef HAVE_GPGME_GET_FDPTR
    extern "C" GIOChannel * gpgme_get_fdptr( int );
    return gpgme_get_fdptr( fd );
#else
    (void)fd;
    return 0;
#endif
}

QIODevice * GpgME::getQIODevice( int fd ) {
    return 0;
}

<commit_msg>Compile on windows<commit_after>/*
  context_glib.cpp - wraps a gpgme key context, gpgme-glib-specific functions
  Copyright (C) 2007 Klarälvdalens Datakonsult AB

  This file is part of GPGME++.

  GPGME++ is free software; you can redistribute it and/or
  modify it under the terms of the GNU Library General Public
  License as published by the Free Software Foundation; either
  version 2 of the License, or (at your option) any later version.

  GPGME++ is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU Library General Public License for more details.

  You should have received a copy of the GNU Library General Public License
  along with GPGME++; see the file COPYING.LIB.  If not, write to the
  Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
  Boston, MA 02110-1301, USA.
*/

#include <config-gpgme++.h>

#include <gpgme++/global.h>

GIOChannel * GpgME::getGIOChannel( int fd ) {
#ifdef HAVE_GPGME_GET_FDPTR
    extern "C" GIOChannel * gpgme_get_fdptr( int );
    return gpgme_get_fdptr( fd );
#else
    (void)fd;
    return 0;
#endif
}

QIODevice * GpgME::getQIODevice( int fd ) {
    return 0;
}

<|endoftext|>


<commit_before>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "CrankNicolson.h"
#include "NonlinearSystem.h"
#include "FEProblem.h"

template <>
InputParameters
validParams<CrankNicolson>()
{
  InputParameters params = validParams<TimeIntegrator>();

  return params;
}

CrankNicolson::CrankNicolson(const InputParameters & parameters)
  : TimeIntegrator(parameters), _residual_old(_nl.addVector("residual_old", false, GHOSTED))
{
}

void
CrankNicolson::computeTimeDerivatives()
{
  _u_dot = *_solution;
  _u_dot -= _solution_old;
  _u_dot *= 2. / _dt;
  _u_dot.close();

  _du_dot_du = 2. / _dt;
}

void
CrankNicolson::init()
{
  // make sure that time derivative contribution is zero in the first pre-solve step
  _u_dot.zero();
  _u_dot.close();

  _du_dot_du = 0;

  // compute residual for the initial time step
  // Note: we can not directly pass _residual_old in computeResidualType because
  //       the function will call postResidual, which will cause _residual_old
  //       to be added on top of itself prohibited by PETSc.
  _fe_problem.computeResidualType(*_solution, _nl.RHS(), Moose::KT_NONTIME);
  _residual_old = _nl.RHS();
}

void
CrankNicolson::postResidual(NumericVector<Number> & residual)
{
  residual += _Re_time;
  residual += _Re_non_time;
  residual += _residual_old;
}

void
CrankNicolson::postStep()
{
  // shift the residual in time
  _residual_old = _Re_non_time;
}
<commit_msg>do not call FEProblemBase::computeResidualType because objects on initial has been evaluated properly #10699<commit_after>//* This file is part of the MOOSE framework
//* https://www.mooseframework.org
//*
//* All rights reserved, see COPYRIGHT for full restrictions
//* https://github.com/idaholab/moose/blob/master/COPYRIGHT
//*
//* Licensed under LGPL 2.1, please see LICENSE for details
//* https://www.gnu.org/licenses/lgpl-2.1.html

#include "CrankNicolson.h"
#include "NonlinearSystem.h"
#include "FEProblem.h"

template <>
InputParameters
validParams<CrankNicolson>()
{
  InputParameters params = validParams<TimeIntegrator>();

  return params;
}

CrankNicolson::CrankNicolson(const InputParameters & parameters)
  : TimeIntegrator(parameters), _residual_old(_nl.addVector("residual_old", false, GHOSTED))
{
}

void
CrankNicolson::computeTimeDerivatives()
{
  _u_dot = *_solution;
  _u_dot -= _solution_old;
  _u_dot *= 2. / _dt;
  _u_dot.close();

  _du_dot_du = 2. / _dt;
}

void
CrankNicolson::init()
{
  // time derivative is assumed to be zero on initial
  _u_dot.zero();
  _du_dot_du = 0;

  // compute residual for the initial time step
  // Note: we can not directly pass _residual_old in computeResidualType because
  //       the function will call postResidual, which will cause _residual_old
  //       to be added on top of itself prohibited by PETSc.
  //       Objects executed on initial have been executed by FEProblem,
  //       so we can and should directly call NonlinearSystem residual evaluation.
  _nl.computeResidual(_nl.RHS(), Moose::KT_NONTIME);
  _residual_old = _nl.RHS();
}

void
CrankNicolson::postResidual(NumericVector<Number> & residual)
{
  residual += _Re_time;
  residual += _Re_non_time;
  residual += _residual_old;
}

void
CrankNicolson::postStep()
{
  // shift the residual in time
  _residual_old = _Re_non_time;
}
<|endoftext|>


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

#ifndef SIUNITS_HPP
#define SIUNITS_HPP

#include <cmath>
#include <ratio>
#include "units.hpp"

#ifndef UNITSCXX_SI_ARITHMETIC_TYPE
#define UNITSCXX_SI_ARITHMETIC_TYPE double
#endif

namespace unitscxx
{
namespace si
{
#pragma mark - Base units
	enum units
	{
		meter,
		gram, // the actual "base" unit is the kilogram
		second,
		ampere,
		kelvin,
		mole,
		candela,
	};

	template<units U>
	using si_base = unit_base<UNITSCXX_SI_ARITHMETIC_TYPE, units, U>;

	constexpr si_base<units::meter> m(1);
	constexpr si_base<units::gram> g(1);
	constexpr si_base<units::second> s(1);
	constexpr si_base<units::ampere> A(1);
	constexpr si_base<units::kelvin> K(1);
	constexpr si_base<units::mole> mol(1);
	constexpr si_base<units::candela> cd(1);
	// (little bit of cheating here)
	constexpr auto kg = std::kilo() * g;

#pragma mark - Named derived units
	// skipping radian: rad = m / m
	// skipping steradian: sr = (m*m) / (m*m)
	constexpr auto Hz = 1 / s;
	constexpr auto N = kg * m / (s * s);
	constexpr auto Pa = N / (m * m);
	constexpr auto J = N * m;
	constexpr auto W = J / s;
	constexpr auto C = s * A;
	constexpr auto V = W / A;
	constexpr auto F = C / V;
	constexpr auto Ohm = V / A; // for lack of a better Ω replacement
	constexpr auto S = A / V;
	constexpr auto Wb = V * s;
	constexpr auto T = Wb / (m * m);
	constexpr auto H = Wb / A;
	// skipping lumen: lm = (cd * sr)
	constexpr auto lx = cd / (m * m);
	// skipping becquerel: Bq = 1 / s
	constexpr auto Gy = J / kg;
	// skipping sievert: Sv = J / kg
	constexpr auto kat = mol / s;

	// special treatment for Celsius
	constexpr auto Czero = 273.15 * K;
	constexpr decltype(K) C2K(UNITSCXX_SI_ARITHMETIC_TYPE celsiusTemperature)
	{
		return celsiusTemperature * K + Czero;
	}

	constexpr UNITSCXX_SI_ARITHMETIC_TYPE K2C(decltype(K) kelvinTemperature)
	{
		return (kelvinTemperature - Czero) / K;
	}

#pragma mark - Commonly-accepted non-standard units
	namespace detail
	{
		constexpr auto dm = std::deci() * m;
		constexpr auto hm = std::hecto() * m;
	}

	constexpr auto deg = UNITSCXX_SI_ARITHMETIC_TYPE(180) / M_PI;
	constexpr auto ha = detail::hm * detail::hm;
	constexpr auto L = detail::dm * detail::dm * detail::dm;
	constexpr auto t = std::kilo() * kg;
	constexpr auto au = 1.496e11 * m;
}
}

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

#ifndef SIUNITS_HPP
#define SIUNITS_HPP

#define _USE_MATH_DEFINES
#include <cmath>
#include <ratio>
#include "units.hpp"

#ifndef UNITSCXX_SI_ARITHMETIC_TYPE
#define UNITSCXX_SI_ARITHMETIC_TYPE double
#endif

namespace unitscxx
{
namespace si
{
#pragma mark - Base units
	enum units
	{
		meter,
		gram, // the actual "base" unit is the kilogram
		second,
		ampere,
		kelvin,
		mole,
		candela,
	};

	template<units U>
	using si_base = unit_base<UNITSCXX_SI_ARITHMETIC_TYPE, units, U>;

	constexpr si_base<units::meter> m(1);
	constexpr si_base<units::gram> g(1);
	constexpr si_base<units::second> s(1);
	constexpr si_base<units::ampere> A(1);
	constexpr si_base<units::kelvin> K(1);
	constexpr si_base<units::mole> mol(1);
	constexpr si_base<units::candela> cd(1);
	// (little bit of cheating here)
	constexpr auto kg = std::kilo() * g;

#pragma mark - Named derived units
	// skipping radian: rad = m / m
	// skipping steradian: sr = (m*m) / (m*m)
	constexpr auto Hz = 1 / s;
	constexpr auto N = kg * m / (s * s);
	constexpr auto Pa = N / (m * m);
	constexpr auto J = N * m;
	constexpr auto W = J / s;
	constexpr auto C = s * A;
	constexpr auto V = W / A;
	constexpr auto F = C / V;
	constexpr auto Ohm = V / A; // for lack of a better Ω replacement
	constexpr auto S = A / V;
	constexpr auto Wb = V * s;
	constexpr auto T = Wb / (m * m);
	constexpr auto H = Wb / A;
	// skipping lumen: lm = (cd * sr)
	constexpr auto lx = cd / (m * m);
	// skipping becquerel: Bq = 1 / s
	constexpr auto Gy = J / kg;
	// skipping sievert: Sv = J / kg
	constexpr auto kat = mol / s;

	// special treatment for Celsius
	constexpr auto Czero = 273.15 * K;
	constexpr decltype(K) C2K(UNITSCXX_SI_ARITHMETIC_TYPE celsiusTemperature)
	{
		return celsiusTemperature * K + Czero;
	}

	constexpr UNITSCXX_SI_ARITHMETIC_TYPE K2C(decltype(K) kelvinTemperature)
	{
		return (kelvinTemperature - Czero) / K;
	}

#pragma mark - Commonly-accepted non-standard units
	namespace detail
	{
		constexpr auto dm = std::deci() * m;
		constexpr auto hm = std::hecto() * m;
	}

	constexpr auto deg = UNITSCXX_SI_ARITHMETIC_TYPE(M_PI / 180);
	constexpr auto ha = detail::hm * detail::hm;
	constexpr auto L = detail::dm * detail::dm * detail::dm;
	constexpr auto t = std::kilo() * kg;
	constexpr auto au = 1.496e11 * m;
}
}

#endif<|endoftext|>


<commit_before>// Copyright (C) 2013 The Regents of the University of California (Regents).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of The Regents or University of California nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include "theia/sfm/triangulation/triangulation.h"

#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <Eigen/Geometry>
#include <Eigen/QR>
#include <Eigen/SVD>
#include <glog/logging.h>
#include <vector>

#include "theia/matching/feature_correspondence.h"
#include "theia/math/util.h"
#include "theia/sfm/pose/fundamental_matrix_util.h"
#include "theia/sfm/pose/util.h"

namespace theia {
namespace {

using Eigen::Matrix;
using Eigen::MatrixXd;
using Eigen::Matrix3d;
using Eigen::Matrix4d;
using Eigen::Vector2d;
using Eigen::Vector3d;
using Eigen::Vector4d;

// Given either a fundamental or essential matrix and two corresponding images
// points such that ematrix * point2 produces a line in the first image,
// this method finds corrected image points such that
// corrected_point1^t * ematrix * corrected_point2 = 0.
void FindOptimalImagePoints(const Matrix3d& ematrix,
                            const Vector2d& point1,
                            const Vector2d& point2,
                            Vector2d* corrected_point1,
                            Vector2d* corrected_point2) {
  const Vector3d point1_homog = point1.homogeneous();
  const Vector3d point2_homog = point2.homogeneous();

  // A helper matrix to isolate certain coordinates.
  Matrix<double, 2, 3> s_matrix;
  s_matrix <<
      1, 0, 0,
      0, 1, 0;

  const Eigen::Matrix2d e_submatrix = ematrix.topLeftCorner<2, 2>();

  // The epipolar line from one image point in the other image.
  Vector2d epipolar_line1 = s_matrix * ematrix * point2_homog;
  Vector2d epipolar_line2 = s_matrix * ematrix.transpose() * point1_homog;

  const double a = epipolar_line1.transpose() * e_submatrix * epipolar_line2;
  const double b =
      (epipolar_line1.squaredNorm() + epipolar_line2.squaredNorm()) / 2.0;
  const double c = point1_homog.transpose() * ematrix * point2_homog;

  const double d = sqrt(b * b - a * c);

  double lambda = c / (b + d);
  epipolar_line1 -= e_submatrix * lambda * epipolar_line1;
  epipolar_line2 -= e_submatrix.transpose() * lambda * epipolar_line2;

  lambda *=
      (2.0 * d) / (epipolar_line1.squaredNorm() + epipolar_line2.squaredNorm());

  *corrected_point1 = (point1_homog - s_matrix.transpose() * lambda *
                                          epipolar_line1).hnormalized();
  *corrected_point2 = (point2_homog - s_matrix.transpose() * lambda *
                                          epipolar_line2).hnormalized();
}

}  // namespace

// Triangulates 2 posed views
bool Triangulate(const Matrix3x4d& pose1,
                 const Matrix3x4d& pose2,
                 const Vector2d& point1,
                 const Vector2d& point2,
                 Vector4d* triangulated_point) {
  Matrix3d fmatrix;
  FundamentalMatrixFromProjectionMatrices(pose1.data(),
                                          pose2.data(),
                                          fmatrix.data());

  Vector2d corrected_point1, corrected_point2;
  FindOptimalImagePoints(fmatrix, point1, point2,
                         &corrected_point1, &corrected_point2);

  // Now the two points are guaranteed to intersect. We can use the DLT method
  // since it is easy to construct.
  return TriangulateDLT(pose1 ,
                        pose2,
                        corrected_point1,
                        corrected_point2,
                        triangulated_point);
}

// Triangulates a 3D point by determining the closest point between the two
// rays. This method is known to be suboptimal in terms of reprojection error
// but it is extremely fast.
bool TriangulateMidpoint(const std::vector<Vector3d>& ray_origin,
                         const std::vector<Vector3d>& ray_direction,
                         Eigen::Vector4d* triangulated_point) {
  CHECK_NOTNULL(triangulated_point);
  CHECK_GE(ray_origin.size(), 2);
  CHECK_EQ(ray_origin.size(), ray_direction.size());

  Eigen::Matrix4d A;
  A.setZero();
  Eigen::Vector4d b;
  b.setZero();
  for (int i = 0; i < ray_origin.size(); i++) {
    const Eigen::Vector4d ray_direction_homog(ray_direction[i].x(),
                                              ray_direction[i].y(),
                                              ray_direction[i].z(),
                                              0);
    const Eigen::Matrix4d A_term =
        Eigen::Matrix4d::Identity() -
        ray_direction_homog * ray_direction_homog.transpose();
    A += A_term;
    b += A_term * ray_origin[i].homogeneous();
  }

  *triangulated_point = A.colPivHouseholderQr().solve(b);
  return true;
}

// Triangulates 2 posed views
bool TriangulateDLT(const Matrix3x4d& pose1,
                    const Matrix3x4d& pose2,
                    const Vector2d& point1,
                    const Vector2d& point2,
                    Vector4d* triangulated_point) {
  Matrix4d design_matrix;
  design_matrix.row(0) = point1[0] * pose1.row(2) - pose1.row(0);
  design_matrix.row(1) = point1[1] * pose1.row(2) - pose1.row(1);
  design_matrix.row(2) = point2[0] * pose2.row(2) - pose2.row(0);
  design_matrix.row(3) = point2[1] * pose2.row(2) - pose2.row(1);

  // Extract nullspace.
  *triangulated_point =
      design_matrix.jacobiSvd(Eigen::ComputeFullV).matrixV().rightCols<1>();
  return true;
}

// Triangulates N views by computing SVD that minimizes the error.
bool TriangulateNViewSVD(const std::vector<Matrix3x4d>& poses,
                         const std::vector<Vector2d>& points,
                         Vector4d* triangulated_point) {
  CHECK_EQ(poses.size(), points.size());

  MatrixXd design_matrix(3 * points.size(), 4 + points.size());

  for (int i = 0; i < points.size(); i++) {
    design_matrix.block<3, 4>(3 * i, 0) = -poses[i].matrix();
    design_matrix.block<3, 1>(3 * i, 4 + i) = points[i].homogeneous();
  }

  *triangulated_point = design_matrix.jacobiSvd(Eigen::ComputeFullV)
                            .matrixV()
                            .rightCols<1>()
                            .head(4);
  return true;
}

bool TriangulateNView(const std::vector<Matrix3x4d>& poses,
                      const std::vector<Vector2d>& points,
                      Vector4d* triangulated_point) {
  CHECK_EQ(poses.size(), points.size());

  Matrix4d design_matrix = Matrix4d::Zero();
  for (int i = 0; i < points.size(); i++) {
    const Vector3d norm_point = points[i].homogeneous().normalized();
    const Eigen::Matrix<double, 3, 4> cost_term =
        poses[i].matrix() -
        norm_point * norm_point.transpose() * poses[i].matrix();
    design_matrix = design_matrix + cost_term.transpose() * cost_term;
  }

  Eigen::SelfAdjointEigenSolver<Matrix4d> eigen_solver(design_matrix);
  *triangulated_point = eigen_solver.eigenvectors().col(0);
  return eigen_solver.info() == Eigen::Success;
}

bool IsTriangulatedPointInFrontOfCameras(
    const FeatureCorrespondence& correspondence,
    const Matrix3d& rotation,
    const Vector3d& position) {
  const Vector3d dir1 = correspondence.feature1.homogeneous();
  const Vector3d dir2 =
      rotation.transpose() * correspondence.feature2.homogeneous();

  const double dir1_sq = dir1.squaredNorm();
  const double dir2_sq = dir2.squaredNorm();
  const double dir1_dir2 = dir1.dot(dir2);
  const double dir1_pos = dir1.dot(position);
  const double dir2_pos = dir2.dot(position);

  return (dir2_sq * dir1_pos - dir1_dir2 * dir2_pos > 0 &&
          dir1_dir2 * dir1_pos - dir1_sq * dir2_pos > 0);
}

// Returns true if the triangulation angle between any two observations is
// sufficient.
bool SufficientTriangulationAngle(
    const std::vector<Eigen::Vector3d>& ray_directions,
    const double min_triangulation_angle_degrees) {
  // Test that the angle between the rays is sufficient.
  const double cos_of_min_angle =
      cos(DegToRad(min_triangulation_angle_degrees));
  for (int i = 0; i < ray_directions.size(); i++) {
    for (int j = i + 1; j < ray_directions.size(); j++) {
      if (ray_directions[i].dot(ray_directions[j]) < cos_of_min_angle) {
        return true;
      }
    }
  }
  return false;
}

}  // namespace theia
<commit_msg>Proper return value for triangulation<commit_after>// Copyright (C) 2013 The Regents of the University of California (Regents).
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
//     * Redistributions of source code must retain the above copyright
//       notice, this list of conditions and the following disclaimer.
//
//     * Redistributions in binary form must reproduce the above
//       copyright notice, this list of conditions and the following
//       disclaimer in the documentation and/or other materials provided
//       with the distribution.
//
//     * Neither the name of The Regents or University of California nor the
//       names of its contributors may be used to endorse or promote products
//       derived from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS 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.
//
// Please contact the author of this library if you have any questions.
// Author: Chris Sweeney (cmsweeney@cs.ucsb.edu)

#include "theia/sfm/triangulation/triangulation.h"

#include <Eigen/Core>
#include <Eigen/Eigenvalues>
#include <Eigen/Geometry>
#include <Eigen/QR>
#include <Eigen/SVD>
#include <glog/logging.h>
#include <vector>

#include "theia/matching/feature_correspondence.h"
#include "theia/math/util.h"
#include "theia/sfm/pose/fundamental_matrix_util.h"
#include "theia/sfm/pose/util.h"

namespace theia {
namespace {

using Eigen::Matrix;
using Eigen::MatrixXd;
using Eigen::Matrix3d;
using Eigen::Matrix4d;
using Eigen::Vector2d;
using Eigen::Vector3d;
using Eigen::Vector4d;

// Given either a fundamental or essential matrix and two corresponding images
// points such that ematrix * point2 produces a line in the first image,
// this method finds corrected image points such that
// corrected_point1^t * ematrix * corrected_point2 = 0.
void FindOptimalImagePoints(const Matrix3d& ematrix,
                            const Vector2d& point1,
                            const Vector2d& point2,
                            Vector2d* corrected_point1,
                            Vector2d* corrected_point2) {
  const Vector3d point1_homog = point1.homogeneous();
  const Vector3d point2_homog = point2.homogeneous();

  // A helper matrix to isolate certain coordinates.
  Matrix<double, 2, 3> s_matrix;
  s_matrix <<
      1, 0, 0,
      0, 1, 0;

  const Eigen::Matrix2d e_submatrix = ematrix.topLeftCorner<2, 2>();

  // The epipolar line from one image point in the other image.
  Vector2d epipolar_line1 = s_matrix * ematrix * point2_homog;
  Vector2d epipolar_line2 = s_matrix * ematrix.transpose() * point1_homog;

  const double a = epipolar_line1.transpose() * e_submatrix * epipolar_line2;
  const double b =
      (epipolar_line1.squaredNorm() + epipolar_line2.squaredNorm()) / 2.0;
  const double c = point1_homog.transpose() * ematrix * point2_homog;

  const double d = sqrt(b * b - a * c);

  double lambda = c / (b + d);
  epipolar_line1 -= e_submatrix * lambda * epipolar_line1;
  epipolar_line2 -= e_submatrix.transpose() * lambda * epipolar_line2;

  lambda *=
      (2.0 * d) / (epipolar_line1.squaredNorm() + epipolar_line2.squaredNorm());

  *corrected_point1 = (point1_homog - s_matrix.transpose() * lambda *
                                          epipolar_line1).hnormalized();
  *corrected_point2 = (point2_homog - s_matrix.transpose() * lambda *
                                          epipolar_line2).hnormalized();
}

}  // namespace

// Triangulates 2 posed views
bool Triangulate(const Matrix3x4d& pose1,
                 const Matrix3x4d& pose2,
                 const Vector2d& point1,
                 const Vector2d& point2,
                 Vector4d* triangulated_point) {
  Matrix3d fmatrix;
  FundamentalMatrixFromProjectionMatrices(pose1.data(),
                                          pose2.data(),
                                          fmatrix.data());

  Vector2d corrected_point1, corrected_point2;
  FindOptimalImagePoints(fmatrix, point1, point2,
                         &corrected_point1, &corrected_point2);

  // Now the two points are guaranteed to intersect. We can use the DLT method
  // since it is easy to construct.
  return TriangulateDLT(pose1 ,
                        pose2,
                        corrected_point1,
                        corrected_point2,
                        triangulated_point);
}

// Triangulates a 3D point by determining the closest point between the two
// rays. This method is known to be suboptimal in terms of reprojection error
// but it is extremely fast.
bool TriangulateMidpoint(const std::vector<Vector3d>& ray_origin,
                         const std::vector<Vector3d>& ray_direction,
                         Eigen::Vector4d* triangulated_point) {
  CHECK_NOTNULL(triangulated_point);
  CHECK_GE(ray_origin.size(), 2);
  CHECK_EQ(ray_origin.size(), ray_direction.size());

  Eigen::Matrix4d A;
  A.setZero();
  Eigen::Vector4d b;
  b.setZero();
  for (int i = 0; i < ray_origin.size(); i++) {
    const Eigen::Vector4d ray_direction_homog(ray_direction[i].x(),
                                              ray_direction[i].y(),
                                              ray_direction[i].z(),
                                              0);
    const Eigen::Matrix4d A_term =
        Eigen::Matrix4d::Identity() -
        ray_direction_homog * ray_direction_homog.transpose();
    A += A_term;
    b += A_term * ray_origin[i].homogeneous();
  }

  Eigen::ColPivHouseholderQR<Eigen::Matrix4d> qr(A);
  if (qr.info() != Eigen::Success) {
    return false;
  }
  *triangulated_point = qr.solve(b);
  return qr.info() == Eigen::Success;
}

// Triangulates 2 posed views
bool TriangulateDLT(const Matrix3x4d& pose1,
                    const Matrix3x4d& pose2,
                    const Vector2d& point1,
                    const Vector2d& point2,
                    Vector4d* triangulated_point) {
  Matrix4d design_matrix;
  design_matrix.row(0) = point1[0] * pose1.row(2) - pose1.row(0);
  design_matrix.row(1) = point1[1] * pose1.row(2) - pose1.row(1);
  design_matrix.row(2) = point2[0] * pose2.row(2) - pose2.row(0);
  design_matrix.row(3) = point2[1] * pose2.row(2) - pose2.row(1);

  // Extract nullspace.
  *triangulated_point =
      design_matrix.jacobiSvd(Eigen::ComputeFullV).matrixV().rightCols<1>();
  return true;
}

// Triangulates N views by computing SVD that minimizes the error.
bool TriangulateNViewSVD(const std::vector<Matrix3x4d>& poses,
                         const std::vector<Vector2d>& points,
                         Vector4d* triangulated_point) {
  CHECK_EQ(poses.size(), points.size());

  MatrixXd design_matrix(3 * points.size(), 4 + points.size());

  for (int i = 0; i < points.size(); i++) {
    design_matrix.block<3, 4>(3 * i, 0) = -poses[i].matrix();
    design_matrix.block<3, 1>(3 * i, 4 + i) = points[i].homogeneous();
  }

  *triangulated_point = design_matrix.jacobiSvd(Eigen::ComputeFullV)
                            .matrixV()
                            .rightCols<1>()
                            .head(4);
  return true;
}

bool TriangulateNView(const std::vector<Matrix3x4d>& poses,
                      const std::vector<Vector2d>& points,
                      Vector4d* triangulated_point) {
  CHECK_EQ(poses.size(), points.size());

  Matrix4d design_matrix = Matrix4d::Zero();
  for (int i = 0; i < points.size(); i++) {
    const Vector3d norm_point = points[i].homogeneous().normalized();
    const Eigen::Matrix<double, 3, 4> cost_term =
        poses[i].matrix() -
        norm_point * norm_point.transpose() * poses[i].matrix();
    design_matrix = design_matrix + cost_term.transpose() * cost_term;
  }

  Eigen::SelfAdjointEigenSolver<Matrix4d> eigen_solver(design_matrix);
  *triangulated_point = eigen_solver.eigenvectors().col(0);
  return eigen_solver.info() == Eigen::Success;
}

bool IsTriangulatedPointInFrontOfCameras(
    const FeatureCorrespondence& correspondence,
    const Matrix3d& rotation,
    const Vector3d& position) {
  const Vector3d dir1 = correspondence.feature1.homogeneous();
  const Vector3d dir2 =
      rotation.transpose() * correspondence.feature2.homogeneous();

  const double dir1_sq = dir1.squaredNorm();
  const double dir2_sq = dir2.squaredNorm();
  const double dir1_dir2 = dir1.dot(dir2);
  const double dir1_pos = dir1.dot(position);
  const double dir2_pos = dir2.dot(position);

  return (dir2_sq * dir1_pos - dir1_dir2 * dir2_pos > 0 &&
          dir1_dir2 * dir1_pos - dir1_sq * dir2_pos > 0);
}

// Returns true if the triangulation angle between any two observations is
// sufficient.
bool SufficientTriangulationAngle(
    const std::vector<Eigen::Vector3d>& ray_directions,
    const double min_triangulation_angle_degrees) {
  // Test that the angle between the rays is sufficient.
  const double cos_of_min_angle =
      cos(DegToRad(min_triangulation_angle_degrees));
  for (int i = 0; i < ray_directions.size(); i++) {
    for (int j = i + 1; j < ray_directions.size(); j++) {
      if (ray_directions[i].dot(ray_directions[j]) < cos_of_min_angle) {
        return true;
      }
    }
  }
  return false;
}

}  // namespace theia
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 The Android Open foo Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/trace_parser.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "perfetto/trace/trace.pb.h"
#include "perfetto/trace/trace_packet.pb.h"

namespace perfetto {
namespace trace_processor {
namespace {

using ::testing::Args;
using ::testing::ElementsAreArray;
using ::testing::Eq;
using ::testing::Pointwise;
using ::testing::_;

class FakeStringBlobReader : public BlobReader {
 public:
  FakeStringBlobReader(const std::string& data) : data_(data) {}
  ~FakeStringBlobReader() override {}

  uint32_t Read(uint64_t offset, uint32_t len, uint8_t* dst) override {
    PERFETTO_CHECK(offset <= data_.size());
    uint32_t rsize =
        std::min(static_cast<uint32_t>(data_.size() - offset), len);
    memcpy(dst, data_.c_str() + offset, rsize);
    return rsize;
  }

 private:
  std::string data_;
};

class MockTraceStorage : public TraceStorage {
 public:
  MockTraceStorage() : TraceStorage() {}

  MOCK_METHOD7(InsertSchedSwitch,
               void(uint32_t cpu,
                    uint64_t timestamp,
                    uint32_t prev_pid,
                    uint32_t prev_state,
                    const char* prev_comm,
                    size_t prev_comm_len,
                    uint32_t next_pid));
};

TEST(TraceParser, LoadSingleEvent) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName);
  sched_switch->set_next_pid(100);

  MockTraceStorage storage;
  EXPECT_CALL(storage, InsertSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName, sizeof(kProcName) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, LoadMultipleEvents) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, InsertSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  EXPECT_CALL(storage, InsertSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, LoadMultiplePackets) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, InsertSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  EXPECT_CALL(storage, InsertSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, RepeatedLoadSinglePacket) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  // Make the chunk size the size of the first packet.
  uint32_t chunk_size = static_cast<uint32_t>(trace.ByteSize());

  bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, InsertSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, chunk_size);
  parser.ParseNextChunk();

  EXPECT_CALL(storage, InsertSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  parser.ParseNextChunk();
}

}  // namespace
}  // namespace trace_processor
}  // namespace perfetto
<commit_msg>trace_processor: fix failing unittests am: 26189a26e1 am: 9f3fe340f4 am: d6009d0fc6<commit_after>/*
 * Copyright (C) 2017 The Android Open foo Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "src/trace_processor/trace_parser.h"

#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "perfetto/trace/trace.pb.h"
#include "perfetto/trace/trace_packet.pb.h"

namespace perfetto {
namespace trace_processor {
namespace {

using ::testing::Args;
using ::testing::ElementsAreArray;
using ::testing::Eq;
using ::testing::Pointwise;
using ::testing::_;

class FakeStringBlobReader : public BlobReader {
 public:
  FakeStringBlobReader(const std::string& data) : data_(data) {}
  ~FakeStringBlobReader() override {}

  uint32_t Read(uint64_t offset, uint32_t len, uint8_t* dst) override {
    PERFETTO_CHECK(offset <= data_.size());
    uint32_t rsize =
        std::min(static_cast<uint32_t>(data_.size() - offset), len);
    memcpy(dst, data_.c_str() + offset, rsize);
    return rsize;
  }

 private:
  std::string data_;
};

class MockTraceStorage : public TraceStorage {
 public:
  MockTraceStorage() : TraceStorage() {}

  MOCK_METHOD7(PushSchedSwitch,
               void(uint32_t cpu,
                    uint64_t timestamp,
                    uint32_t prev_pid,
                    uint32_t prev_state,
                    const char* prev_comm,
                    size_t prev_comm_len,
                    uint32_t next_pid));
};

TEST(TraceParser, LoadSingleEvent) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName);
  sched_switch->set_next_pid(100);

  MockTraceStorage storage;
  EXPECT_CALL(storage, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName, sizeof(kProcName) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, LoadMultipleEvents) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  EXPECT_CALL(storage, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, LoadMultiplePackets) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  EXPECT_CALL(storage, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, 1024);
  parser.ParseNextChunk();
}

TEST(TraceParser, RepeatedLoadSinglePacket) {
  protos::Trace trace;

  auto* bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  auto* event = bundle->add_event();
  event->set_timestamp(1000);

  static const char kProcName1[] = "proc1";
  auto* sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(10);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName1);
  sched_switch->set_next_pid(100);

  // Make the chunk size the size of the first packet.
  uint32_t chunk_size = static_cast<uint32_t>(trace.ByteSize());

  bundle = trace.add_packet()->mutable_ftrace_events();
  bundle->set_cpu(10);

  event = bundle->add_event();
  event->set_timestamp(1001);

  static const char kProcName2[] = "proc2";
  sched_switch = event->mutable_sched_switch();
  sched_switch->set_prev_pid(100);
  sched_switch->set_prev_state(32);
  sched_switch->set_prev_comm(kProcName2);
  sched_switch->set_next_pid(10);

  MockTraceStorage storage;
  EXPECT_CALL(storage, PushSchedSwitch(10, 1000, 10, 32, _, _, 100))
      .With(Args<4, 5>(ElementsAreArray(kProcName1, sizeof(kProcName1) - 1)));

  FakeStringBlobReader reader(trace.SerializeAsString());
  TraceParser parser(&reader, &storage, chunk_size);
  parser.ParseNextChunk();

  EXPECT_CALL(storage, PushSchedSwitch(10, 1001, 100, 32, _, _, 10))
      .With(Args<4, 5>(ElementsAreArray(kProcName2, sizeof(kProcName2) - 1)));

  parser.ParseNextChunk();
}

}  // namespace
}  // namespace trace_processor
}  // namespace perfetto
<|endoftext|>


<commit_before>//===----------------------------------------------------------------------===//
// LLVM Modular Optimizer Utility: opt
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/PassNameParser.h"
#include "Support/Signals.h"
#include <fstream>
#include <memory>
#include <algorithm>

using std::cerr;
using std::string;

// The OptimizationList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool,
                FilteredPassNameParser<PassInfo::Optimization> >
OptimizationList(cl::desc("Optimizations available:"));

// Other command line options...
//
static cl::opt<string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));

static cl::opt<string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
PrintEachXForm("p", cl::desc("Print module after each transformation"));

static cl::opt<bool>
Quiet("q", cl::desc("Don't print modifying pass names"));

static cl::alias
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));

//===----------------------------------------------------------------------===//
// main for opt
//
int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  // FIXME: This should be parameterizable eventually for different target
  // types...
  TargetData TD("opt target");

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0) {
    cerr << argv[0] << ": bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << argv[0] << ": error opening '" << OutputFilename
           << "': file exists!\n"
           << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
      return 1;
    }

    // Make sure that the Output file gets unlink'd from the disk if we get a
    // SIGINT
    RemoveFileOnSignal(OutputFilename);
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    const PassInfo *Opt = OptimizationList[i];

    if (Opt->getNormalCtor())
      Passes.add(Opt->getNormalCtor()());
    else if (Opt->getDataCtor())
      Passes.add(Opt->getDataCtor()(TD));  // Pass dummy target data...
    else
      cerr << argv[0] << ": cannot create pass: " << Opt->getPassName() << "\n";

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&cerr));
  }

  // Check that the module is well formed on completion of optimization
  Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(*M.get()) && !Quiet)
    cerr << "Program modified.\n";

  return 0;
}
<commit_msg>Change command line option message on -q to make it more accurate<commit_after>//===----------------------------------------------------------------------===//
// LLVM Modular Optimizer Utility: opt
//
// Optimizations may be specified an arbitrary number of times on the command
// line, they are run in the order specified.
//
//===----------------------------------------------------------------------===//

#include "llvm/Module.h"
#include "llvm/PassManager.h"
#include "llvm/Bytecode/Reader.h"
#include "llvm/Bytecode/WriteBytecodePass.h"
#include "llvm/Assembly/PrintModulePass.h"
#include "llvm/Analysis/Verifier.h"
#include "llvm/Target/TargetData.h"
#include "llvm/Support/PassNameParser.h"
#include "Support/Signals.h"
#include <fstream>
#include <memory>
#include <algorithm>

using std::cerr;
using std::string;

// The OptimizationList is automatically populated with registered Passes by the
// PassNameParser.
//
static cl::list<const PassInfo*, bool,
                FilteredPassNameParser<PassInfo::Optimization> >
OptimizationList(cl::desc("Optimizations available:"));

// Other command line options...
//
static cl::opt<string>
InputFilename(cl::Positional, cl::desc("<input bytecode>"), cl::init("-"));

static cl::opt<string>
OutputFilename("o", cl::desc("Override output filename"),
               cl::value_desc("filename"));

static cl::opt<bool>
Force("f", cl::desc("Overwrite output files"));

static cl::opt<bool>
PrintEachXForm("p", cl::desc("Print module after each transformation"));

static cl::opt<bool>
Quiet("q", cl::desc("Don't print 'program modified' message"));

static cl::alias
QuietA("quiet", cl::desc("Alias for -q"), cl::aliasopt(Quiet));

//===----------------------------------------------------------------------===//
// main for opt
//
int main(int argc, char **argv) {
  cl::ParseCommandLineOptions(argc, argv,
			      " llvm .bc -> .bc modular optimizer\n");

  // FIXME: This should be parameterizable eventually for different target
  // types...
  TargetData TD("opt target");

  // Load the input module...
  std::auto_ptr<Module> M(ParseBytecodeFile(InputFilename));
  if (M.get() == 0) {
    cerr << argv[0] << ": bytecode didn't read correctly.\n";
    return 1;
  }

  // Figure out what stream we are supposed to write to...
  std::ostream *Out = &std::cout;  // Default to printing to stdout...
  if (OutputFilename != "") {
    if (!Force && std::ifstream(OutputFilename.c_str())) {
      // If force is not specified, make sure not to overwrite a file!
      cerr << argv[0] << ": error opening '" << OutputFilename
           << "': file exists!\n"
           << "Use -f command line argument to force output\n";
      return 1;
    }
    Out = new std::ofstream(OutputFilename.c_str());

    if (!Out->good()) {
      cerr << argv[0] << ": error opening " << OutputFilename << "!\n";
      return 1;
    }

    // Make sure that the Output file gets unlink'd from the disk if we get a
    // SIGINT
    RemoveFileOnSignal(OutputFilename);
  }

  // Create a PassManager to hold and optimize the collection of passes we are
  // about to build...
  //
  PassManager Passes;

  // Create a new optimization pass for each one specified on the command line
  for (unsigned i = 0; i < OptimizationList.size(); ++i) {
    const PassInfo *Opt = OptimizationList[i];

    if (Opt->getNormalCtor())
      Passes.add(Opt->getNormalCtor()());
    else if (Opt->getDataCtor())
      Passes.add(Opt->getDataCtor()(TD));  // Pass dummy target data...
    else
      cerr << argv[0] << ": cannot create pass: " << Opt->getPassName() << "\n";

    if (PrintEachXForm)
      Passes.add(new PrintModulePass(&cerr));
  }

  // Check that the module is well formed on completion of optimization
  Passes.add(createVerifierPass());

  // Write bytecode out to disk or cout as the last step...
  Passes.add(new WriteBytecodePass(Out, Out != &std::cout));

  // Now that we have all of the passes ready, run them.
  if (Passes.run(*M.get()) && !Quiet)
    cerr << "Program modified.\n";

  return 0;
}
<|endoftext|>


<commit_before>#include "Dependency.h"
#include "Hash.h"
#include "Requirement.h"
#include "Resolver.h"
#include "ToString.h"
#include "Value.h"

#include "TestValue.h"

#include "gtest/gtest.h"

#include <algorithm>
#include <stdexcept>

using namespace Arbiter;
using namespace Testing;

namespace {

ArbiterDependencyList *createEmptyDependencyList (const ArbiterResolver *, const ArbiterProjectIdentifier *, const ArbiterSelectedVersion *, char **)
{
  return new ArbiterDependencyList();
}

ArbiterSelectedVersionList *createEmptyAvailableVersionsList (const ArbiterResolver *, const ArbiterProjectIdentifier *, char **)
{
  return new ArbiterSelectedVersionList();
}

ArbiterSelectedVersionList *createMajorVersionsList (const ArbiterResolver *, const ArbiterProjectIdentifier *, char **)
{
  std::vector<ArbiterSelectedVersion> versions;

  versions.emplace_back(ArbiterSemanticVersion(2, 0, 0), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(3, 0, 0), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(1, 0, 0), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());

  return new ArbiterSelectedVersionList(std::move(versions));
}

ArbiterProjectIdentifier emptyProjectIdentifier ()
{
  return ArbiterProjectIdentifier(makeSharedUserValue<ArbiterProjectIdentifier, EmptyTestValue>());
}

ArbiterProjectIdentifier makeProjectIdentifier (std::string name)
{
  return ArbiterProjectIdentifier(makeSharedUserValue<ArbiterProjectIdentifier, StringTestValue>(std::move(name)));
}

Requirement::Unversioned makeUnversionedRequirement (std::string name)
{
  return Requirement::Unversioned(makeSharedUserValue<ArbiterSelectedVersion, StringTestValue>(std::move(name)));
}

template<typename Req>
Requirement::Prioritized makePrioritizedRequirement (const Req &innerRequirement, int priority)
{
  return Requirement::Prioritized(innerRequirement.cloneRequirement(), priority);
}

ArbiterSelectedVersionList *createVariedVersionsList (const ArbiterResolver *resolver, const ArbiterProjectIdentifier *project, char **error)
{
  if (*project == makeProjectIdentifier("leaf_majors_only")) {
    return createMajorVersionsList(resolver, project, error);
  }

  std::vector<ArbiterSelectedVersion> versions;

  versions.emplace_back(ArbiterSemanticVersion(0, 2, 3), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(1, 0, 1, makeOptional("alpha")), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(1, 0, 1), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(1, 3, 0), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(2, 1, 0, None(), makeOptional("dailybuild")), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());

  return new ArbiterSelectedVersionList(std::move(versions));
}

ArbiterDependencyList *createTransitiveDependencyList (const ArbiterResolver *, const ArbiterProjectIdentifier *project, const ArbiterSelectedVersion *, char **)
{
  std::vector<ArbiterDependency> dependencies;

  if (*project == makeProjectIdentifier("ancestor")) {
    dependencies.emplace_back(makeProjectIdentifier("middle"), Requirement::CompatibleWith(ArbiterSemanticVersion(1, 0, 1), ArbiterRequirementStrictnessStrict));
    dependencies.emplace_back(makeProjectIdentifier("leaf_majors_only"), Requirement::AtLeast(ArbiterSemanticVersion(1, 0, 0)));
    dependencies.emplace_back(makeProjectIdentifier("leaf_dailybuild"), Requirement::AtLeast(ArbiterSemanticVersion(2, 0, 0)));
  } else if (*project == makeProjectIdentifier("middle")) {
    dependencies.emplace_back(makeProjectIdentifier("leaf_majors_only"), Requirement::Exactly(ArbiterSemanticVersion(2, 0, 0)));
    dependencies.emplace_back(makeProjectIdentifier("leaf"), Requirement::CompatibleWith(ArbiterSemanticVersion(0, 2, 0), ArbiterRequirementStrictnessAllowVersionZeroPatches));
  } else if (*project == makeProjectIdentifier("parent")) {
    dependencies.emplace_back(makeProjectIdentifier("leaf"), Requirement::Exactly(ArbiterSemanticVersion(0, 2, 3)));
    dependencies.emplace_back(makeProjectIdentifier("leaf_dailybuild"), Requirement::CompatibleWith(ArbiterSemanticVersion(2, 1, 0), ArbiterRequirementStrictnessStrict));
  }

  return new ArbiterDependencyList(std::move(dependencies));
}

ArbiterSelectedVersion *createSelectedVersionForMetadata (const ArbiterResolver *, const void *metadata)
{
  const auto &testValue = fromUserValue<StringTestValue>(metadata);
  return new ArbiterSelectedVersion(None(), makeSharedUserValue<ArbiterSelectedVersion, StringTestValue>(testValue._str));
}

const ArbiterResolvedDependency &findResolved (const ArbiterResolvedDependencyInstaller &installer, size_t phaseIndex, const std::string &name)
{
  ArbiterProjectIdentifier identifier = makeProjectIdentifier(name);

  const auto &phase = installer._phases.at(phaseIndex);
  auto it = std::find_if(phase.begin(), phase.end(), [&identifier](const ArbiterResolvedDependency &dependency) {
    return dependency._project == identifier;
  });

  if (it == phase.end()) {
    throw std::out_of_range("Dependency " + name + " not found in resolved graph");
  }

  return *it;
}

} // namespace

TEST(ResolverTest, ResolvesEmptyDependencies) {
  ArbiterResolverBehaviors behaviors{&createEmptyDependencyList, &createEmptyAvailableVersionsList, nullptr};

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 0);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_TRUE(installer._phases.empty());
}

TEST(ResolverTest, ResolvesOneDependency) {
  ArbiterResolverBehaviors behaviors{&createEmptyDependencyList, &createMajorVersionsList, nullptr};

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(emptyProjectIdentifier(), Requirement::AtLeast(ArbiterSemanticVersion(2, 0, 0)));

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 1);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 1);
  EXPECT_EQ(installer._phases.front().begin()->_project, emptyProjectIdentifier());
  EXPECT_EQ(installer._phases.front().begin()->_version._semanticVersion, makeOptional(ArbiterSemanticVersion(3, 0, 0)));
}

TEST(ResolverTest, ResolvesMultipleDependencies)
{
  ArbiterResolverBehaviors behaviors{&createEmptyDependencyList, &createMajorVersionsList, nullptr};

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(makeProjectIdentifier("A"), Requirement::AtLeast(ArbiterSemanticVersion(2, 0, 1)));
  dependencies.emplace_back(makeProjectIdentifier("B"), Requirement::CompatibleWith(ArbiterSemanticVersion(2, 0, 0), ArbiterRequirementStrictnessStrict));
  dependencies.emplace_back(makeProjectIdentifier("C"), Requirement::Exactly(ArbiterSemanticVersion(1, 0, 0)));

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 3);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 1);
  EXPECT_EQ(findResolved(installer, 0, "A")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(3, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "B")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "C")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 0, 0)));
}

TEST(ResolverTest, ResolvesTransitiveDependencies)
{
  ArbiterResolverBehaviors behaviors{&createTransitiveDependencyList, &createVariedVersionsList, nullptr};

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(makeProjectIdentifier("ancestor"), Requirement::Exactly(ArbiterSemanticVersion(1, 0, 1, makeOptional("alpha"))));
  dependencies.emplace_back(makeProjectIdentifier("parent"), Requirement::CompatibleWith(ArbiterSemanticVersion(1, 2, 3), ArbiterRequirementStrictnessStrict));

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 6);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 3);
  EXPECT_EQ(findResolved(installer, 2, "ancestor")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 0, 1, makeOptional("alpha"))));
  EXPECT_EQ(findResolved(installer, 1, "middle")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 3, 0)));
  EXPECT_EQ(findResolved(installer, 1, "parent")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 3, 0)));
  EXPECT_EQ(findResolved(installer, 0, "leaf")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(0, 2, 3)));
  EXPECT_EQ(findResolved(installer, 0, "leaf_majors_only")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "leaf_dailybuild")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 1, 0, None(), makeOptional("dailybuild"))));
}

TEST(ResolverTest, ResolvesPrioritizedUnversionedRequirements)
{
  ArbiterResolverBehaviors behaviors{&createTransitiveDependencyList, &createVariedVersionsList, &createSelectedVersionForMetadata};

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(makeProjectIdentifier("ancestor"), makeUnversionedRequirement("ancestor-branch"));
  dependencies.emplace_back(makeProjectIdentifier("middle"), makePrioritizedRequirement(makeUnversionedRequirement("middle-branch"), -1));
  dependencies.emplace_back(makeProjectIdentifier("parent"), makePrioritizedRequirement(Requirement::CompatibleWith(ArbiterSemanticVersion(1, 2, 3), ArbiterRequirementStrictnessStrict), 1));

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 6);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 3);
  EXPECT_EQ(findResolved(installer, 2, "ancestor")._version, ArbiterSelectedVersion(None(), makeSharedUserValue<ArbiterSelectedVersion, StringTestValue>("ancestor-branch")));
  EXPECT_EQ(findResolved(installer, 1, "middle")._version, ArbiterSelectedVersion(None(), makeSharedUserValue<ArbiterSelectedVersion, StringTestValue>("middle-branch")));
  EXPECT_EQ(findResolved(installer, 1, "parent")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 3, 0)));
  EXPECT_EQ(findResolved(installer, 0, "leaf")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(0, 2, 3)));
  EXPECT_EQ(findResolved(installer, 0, "leaf_majors_only")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "leaf_dailybuild")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 1, 0, None(), makeOptional("dailybuild"))));
}

#if 0
TEST(ResolverTest, FailsWhenNoAvailableVersions)
{}

TEST(ResolverTest, FailsWhenNoSatisfyingVersions)
{}

TEST(ResolverTest, FailsWithMutuallyExclusiveRequirements)
{}

TEST(ResolverTest, RethrowsUserDependencyListErrors)
{}

TEST(ResolverTest, RethrowsUserVersionListErrors)
{}
#endif
<commit_msg>Test resolving new dependencies into an existing graph<commit_after>#include "Dependency.h"
#include "Hash.h"
#include "Requirement.h"
#include "Resolver.h"
#include "ToString.h"
#include "Value.h"

#include "TestValue.h"

#include "gtest/gtest.h"

#include <algorithm>
#include <stdexcept>

using namespace Arbiter;
using namespace Testing;

namespace {

ArbiterDependencyList *createEmptyDependencyList (const ArbiterResolver *, const ArbiterProjectIdentifier *, const ArbiterSelectedVersion *, char **)
{
  return new ArbiterDependencyList();
}

ArbiterSelectedVersionList *createEmptyAvailableVersionsList (const ArbiterResolver *, const ArbiterProjectIdentifier *, char **)
{
  return new ArbiterSelectedVersionList();
}

ArbiterSelectedVersionList *createMajorVersionsList (const ArbiterResolver *, const ArbiterProjectIdentifier *, char **)
{
  std::vector<ArbiterSelectedVersion> versions;

  versions.emplace_back(ArbiterSemanticVersion(2, 0, 0), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(3, 0, 0), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(1, 0, 0), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());

  return new ArbiterSelectedVersionList(std::move(versions));
}

ArbiterProjectIdentifier emptyProjectIdentifier ()
{
  return ArbiterProjectIdentifier(makeSharedUserValue<ArbiterProjectIdentifier, EmptyTestValue>());
}

ArbiterProjectIdentifier makeProjectIdentifier (std::string name)
{
  return ArbiterProjectIdentifier(makeSharedUserValue<ArbiterProjectIdentifier, StringTestValue>(std::move(name)));
}

Requirement::Unversioned makeUnversionedRequirement (std::string name)
{
  return Requirement::Unversioned(makeSharedUserValue<ArbiterSelectedVersion, StringTestValue>(std::move(name)));
}

template<typename Req>
Requirement::Prioritized makePrioritizedRequirement (const Req &innerRequirement, int priority)
{
  return Requirement::Prioritized(innerRequirement.cloneRequirement(), priority);
}

ArbiterSelectedVersionList *createVariedVersionsList (const ArbiterResolver *resolver, const ArbiterProjectIdentifier *project, char **error)
{
  if (*project == makeProjectIdentifier("leaf_majors_only")) {
    return createMajorVersionsList(resolver, project, error);
  }

  std::vector<ArbiterSelectedVersion> versions;

  versions.emplace_back(ArbiterSemanticVersion(0, 2, 3), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(1, 0, 1, makeOptional("alpha")), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(1, 0, 1), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(1, 3, 0), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());
  versions.emplace_back(ArbiterSemanticVersion(2, 1, 0, None(), makeOptional("dailybuild")), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>());

  return new ArbiterSelectedVersionList(std::move(versions));
}

ArbiterDependencyList *createTransitiveDependencyList (const ArbiterResolver *, const ArbiterProjectIdentifier *project, const ArbiterSelectedVersion *, char **)
{
  std::vector<ArbiterDependency> dependencies;

  if (*project == makeProjectIdentifier("ancestor")) {
    dependencies.emplace_back(makeProjectIdentifier("middle"), Requirement::CompatibleWith(ArbiterSemanticVersion(1, 0, 1), ArbiterRequirementStrictnessStrict));
    dependencies.emplace_back(makeProjectIdentifier("leaf_majors_only"), Requirement::AtLeast(ArbiterSemanticVersion(1, 0, 0)));
    dependencies.emplace_back(makeProjectIdentifier("leaf_dailybuild"), Requirement::AtLeast(ArbiterSemanticVersion(2, 0, 0)));
  } else if (*project == makeProjectIdentifier("middle")) {
    dependencies.emplace_back(makeProjectIdentifier("leaf_majors_only"), Requirement::Exactly(ArbiterSemanticVersion(2, 0, 0)));
    dependencies.emplace_back(makeProjectIdentifier("leaf"), Requirement::CompatibleWith(ArbiterSemanticVersion(0, 2, 0), ArbiterRequirementStrictnessAllowVersionZeroPatches));
  } else if (*project == makeProjectIdentifier("parent")) {
    dependencies.emplace_back(makeProjectIdentifier("leaf"), Requirement::Exactly(ArbiterSemanticVersion(0, 2, 3)));
    dependencies.emplace_back(makeProjectIdentifier("leaf_dailybuild"), Requirement::CompatibleWith(ArbiterSemanticVersion(2, 1, 0), ArbiterRequirementStrictnessStrict));
  }

  return new ArbiterDependencyList(std::move(dependencies));
}

ArbiterSelectedVersion *createSelectedVersionForMetadata (const ArbiterResolver *, const void *metadata)
{
  const auto &testValue = fromUserValue<StringTestValue>(metadata);
  return new ArbiterSelectedVersion(None(), makeSharedUserValue<ArbiterSelectedVersion, StringTestValue>(testValue._str));
}

const ArbiterResolvedDependency &findResolved (const ArbiterResolvedDependencyInstaller &installer, size_t phaseIndex, const std::string &name)
{
  ArbiterProjectIdentifier identifier = makeProjectIdentifier(name);

  const auto &phase = installer._phases.at(phaseIndex);
  auto it = std::find_if(phase.begin(), phase.end(), [&identifier](const ArbiterResolvedDependency &dependency) {
    return dependency._project == identifier;
  });

  if (it == phase.end()) {
    throw std::out_of_range("Dependency " + name + " not found in resolved graph");
  }

  return *it;
}

} // namespace

TEST(ResolverTest, ResolvesEmptyDependencies) {
  ArbiterResolverBehaviors behaviors{&createEmptyDependencyList, &createEmptyAvailableVersionsList, nullptr};

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 0);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_TRUE(installer._phases.empty());
}

TEST(ResolverTest, ResolvesOneDependency) {
  ArbiterResolverBehaviors behaviors{&createEmptyDependencyList, &createMajorVersionsList, nullptr};

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(emptyProjectIdentifier(), Requirement::AtLeast(ArbiterSemanticVersion(2, 0, 0)));

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 1);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 1);
  EXPECT_EQ(installer._phases.front().begin()->_project, emptyProjectIdentifier());
  EXPECT_EQ(installer._phases.front().begin()->_version._semanticVersion, makeOptional(ArbiterSemanticVersion(3, 0, 0)));
}

TEST(ResolverTest, ResolvesMultipleDependencies)
{
  ArbiterResolverBehaviors behaviors{&createEmptyDependencyList, &createMajorVersionsList, nullptr};

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(makeProjectIdentifier("A"), Requirement::AtLeast(ArbiterSemanticVersion(2, 0, 1)));
  dependencies.emplace_back(makeProjectIdentifier("B"), Requirement::CompatibleWith(ArbiterSemanticVersion(2, 0, 0), ArbiterRequirementStrictnessStrict));
  dependencies.emplace_back(makeProjectIdentifier("C"), Requirement::Exactly(ArbiterSemanticVersion(1, 0, 0)));

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 3);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 1);
  EXPECT_EQ(findResolved(installer, 0, "A")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(3, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "B")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "C")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 0, 0)));
}

TEST(ResolverTest, ResolvesTransitiveDependencies)
{
  ArbiterResolverBehaviors behaviors{&createTransitiveDependencyList, &createVariedVersionsList, nullptr};

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(makeProjectIdentifier("ancestor"), Requirement::Exactly(ArbiterSemanticVersion(1, 0, 1, makeOptional("alpha"))));
  dependencies.emplace_back(makeProjectIdentifier("parent"), Requirement::CompatibleWith(ArbiterSemanticVersion(1, 2, 3), ArbiterRequirementStrictnessStrict));

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 6);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 3);
  EXPECT_EQ(findResolved(installer, 2, "ancestor")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 0, 1, makeOptional("alpha"))));
  EXPECT_EQ(findResolved(installer, 1, "middle")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 3, 0)));
  EXPECT_EQ(findResolved(installer, 1, "parent")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 3, 0)));
  EXPECT_EQ(findResolved(installer, 0, "leaf")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(0, 2, 3)));
  EXPECT_EQ(findResolved(installer, 0, "leaf_majors_only")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "leaf_dailybuild")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 1, 0, None(), makeOptional("dailybuild"))));
}

TEST(ResolverTest, ResolvesPrioritizedUnversionedRequirements)
{
  ArbiterResolverBehaviors behaviors{&createTransitiveDependencyList, &createVariedVersionsList, &createSelectedVersionForMetadata};

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(makeProjectIdentifier("ancestor"), makeUnversionedRequirement("ancestor-branch"));
  dependencies.emplace_back(makeProjectIdentifier("middle"), makePrioritizedRequirement(makeUnversionedRequirement("middle-branch"), -1));
  dependencies.emplace_back(makeProjectIdentifier("parent"), makePrioritizedRequirement(Requirement::CompatibleWith(ArbiterSemanticVersion(1, 2, 3), ArbiterRequirementStrictnessStrict), 1));

  ArbiterResolver resolver(behaviors, ArbiterResolvedDependencyGraph(), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 6);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 3);
  EXPECT_EQ(findResolved(installer, 2, "ancestor")._version, ArbiterSelectedVersion(None(), makeSharedUserValue<ArbiterSelectedVersion, StringTestValue>("ancestor-branch")));
  EXPECT_EQ(findResolved(installer, 1, "middle")._version, ArbiterSelectedVersion(None(), makeSharedUserValue<ArbiterSelectedVersion, StringTestValue>("middle-branch")));
  EXPECT_EQ(findResolved(installer, 1, "parent")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 3, 0)));
  EXPECT_EQ(findResolved(installer, 0, "leaf")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(0, 2, 3)));
  EXPECT_EQ(findResolved(installer, 0, "leaf_majors_only")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "leaf_dailybuild")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 1, 0, None(), makeOptional("dailybuild"))));
}

TEST(ResolverTest, ResolvesIncrementallyFromInitialGraph)
{
  // Purposely selecting a version which isn't available in the list, as we
  // shouldn't be inspecting A during resolution at all.
  auto resolvedA = ArbiterResolvedDependency(makeProjectIdentifier("A"), ArbiterSelectedVersion(ArbiterSemanticVersion(2, 3, 4), makeSharedUserValue<ArbiterSelectedVersion, EmptyTestValue>()));

  ArbiterResolvedDependencyGraph initialGraph;
  initialGraph.addNode(std::move(resolvedA), Requirement::AtLeast(ArbiterSemanticVersion(2, 0, 1)), None());

  std::vector<ArbiterDependency> dependencies;
  dependencies.emplace_back(makeProjectIdentifier("B"), Requirement::CompatibleWith(ArbiterSemanticVersion(2, 0, 0), ArbiterRequirementStrictnessStrict));
  dependencies.emplace_back(makeProjectIdentifier("C"), Requirement::Exactly(ArbiterSemanticVersion(1, 0, 0)));

  ArbiterResolverBehaviors behaviors{&createEmptyDependencyList, &createMajorVersionsList, nullptr};
  ArbiterResolver resolver(behaviors, std::move(initialGraph), ArbiterDependencyList(std::move(dependencies)), nullptr);

  ArbiterResolvedDependencyGraph resolved = resolver.resolve();
  EXPECT_EQ(resolved.nodes().size(), 3);

  ArbiterResolvedDependencyInstaller installer = resolved.createInstaller();
  EXPECT_EQ(installer._phases.size(), 1);
  EXPECT_EQ(findResolved(installer, 0, "A")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 3, 4)));
  EXPECT_EQ(findResolved(installer, 0, "B")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(2, 0, 0)));
  EXPECT_EQ(findResolved(installer, 0, "C")._version._semanticVersion, makeOptional(ArbiterSemanticVersion(1, 0, 0)));
}

#if 0
TEST(ResolverTest, FailsWhenNoAvailableVersions)
{}

TEST(ResolverTest, FailsWhenNoSatisfyingVersions)
{}

TEST(ResolverTest, FailsWithMutuallyExclusiveRequirements)
{}

TEST(ResolverTest, RethrowsUserDependencyListErrors)
{}

TEST(ResolverTest, RethrowsUserVersionListErrors)
{}
#endif
<|endoftext|>


<commit_before>/*!
 * This file is part of CameraPlus.
 *
 * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "cameraresources.h"
#include <dbusconnectioneventloop.h>
#include <QDebug>

#define APPLICATION_CLASS "camera"

CameraResources::CameraResources(QObject *parent) :
  QObject(parent),
  m_worker(new CameraResourcesWorker) {

  m_worker->moveToThread(&m_thread);
  DBUSConnectionEventLoop::getInstance().moveToThread(&m_thread);

  QObject::connect(&m_thread, SIGNAL(started()), m_worker, SLOT(init()));
  m_thread.start();

  qRegisterMetaType<CameraResources::Mode>("CameraResources::Mode");
  qRegisterMetaType<bool *>("bool *");

  QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(acquiredChanged()));
  QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(hijackedChanged()));
  QObject::connect(m_worker, SIGNAL(updated()), this, SIGNAL(updated()));
  QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(scaleAcquisitionChanged()));
  QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(scaleAcquisitionChanged()));
  QObject::connect(m_worker, SIGNAL(updated()), this, SIGNAL(scaleAcquisitionChanged()));
}

CameraResources::~CameraResources() {
  acquire(CameraResources::None);
  m_thread.exit(0);

  while (m_thread.isRunning()) {
    m_thread.wait(10);
  }

  delete m_worker;
  m_worker = 0;
}

bool CameraResources::isResourceGranted(const ResourcePolicy::ResourceType& resource) const {
  bool ok = false;

  QMetaObject::invokeMethod(m_worker, "isResourceGranted", Qt::BlockingQueuedConnection,
			    Q_ARG(bool *, &ok), Q_ARG(int, resource));

  return ok;
}

bool CameraResources::acquire(const Mode& mode) {
  bool ok = false;

  QMetaObject::invokeMethod(m_worker, "acquire", Qt::BlockingQueuedConnection,
			    Q_ARG(bool *, &ok), Q_ARG(CameraResources::Mode, mode));

  return ok;
}

bool CameraResources::acquired() const {
  bool ok = false;

  QMetaObject::invokeMethod(m_worker, "acquired", Qt::BlockingQueuedConnection,
			    Q_ARG(bool *, &ok));

  return ok;
}

bool CameraResources::hijacked() const {
  bool ok = false;

  QMetaObject::invokeMethod(m_worker, "hijacked", Qt::BlockingQueuedConnection,
			    Q_ARG(bool *, &ok));

  return ok;
}

bool CameraResources::isScaleAcquired() const {
  return isResourceGranted(ResourcePolicy::ScaleButtonType);
}

CameraResourcesWorker::CameraResourcesWorker(QObject *parent) :
  QObject(parent),
  m_set(0),
  m_mode(CameraResources::None),
  m_acquired(false),
  m_acquiring(false),
  m_hijacked(false) {

}

CameraResourcesWorker::~CameraResourcesWorker() {

}

void CameraResourcesWorker::init() {
  m_set = new ResourcePolicy::ResourceSet(APPLICATION_CLASS, this);
  m_set->setAlwaysReply();

  QObject::connect(m_set, SIGNAL(resourcesReleased()), this, SLOT(resourcesReleased()));
  QObject::connect(m_set, SIGNAL(lostResources()), this, SLOT(lostResources()));
  QObject::connect(m_set, SIGNAL(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)),
		   this, SLOT(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)));
  QObject::connect(m_set, SIGNAL(resourcesDenied()), this, SLOT(resourcesDenied()));

  if (!m_set->initAndConnect()) {
    qCritical() << "Failed to connect to resource policy engine";
  }
}

void CameraResourcesWorker::resourcesReleased() {
  setHijacked(false);
  setAcquired(false);

  m_acquiring = false;
}

void CameraResourcesWorker::lostResources() {
  setAcquired(false);
  setHijacked(true);

  m_acquiring = false;
}

void CameraResourcesWorker::resourcesGranted(const QList<ResourcePolicy::ResourceType>& optional) {
  Q_UNUSED(optional);

  if (!m_acquiring) {
    // This can happen when:
    // 1) We lose/gain optional resources.
    // 2) A higher priority application releases resources back.
    emit updated();
  }

  m_acquiring = false;

  setAcquired(true);
  setHijacked(false);
}

void CameraResourcesWorker::resourcesDenied() {
  setAcquired(false);
  setHijacked(true);

  m_acquiring = false;
}

QList<ResourcePolicy::ResourceType> CameraResourcesWorker::listSet() {
  QList<ResourcePolicy::Resource *> resources = m_set->resources();

  QList<ResourcePolicy::ResourceType> set;

  foreach (ResourcePolicy::Resource *r, resources) {
    set << r->type();
  }

  return set;
}

void CameraResourcesWorker::acquire(bool *ok, const CameraResources::Mode& mode) {
  if (mode == m_mode) {
    *ok = true;
    return;
  }

  m_mode = mode;

  *ok = false;

  switch (m_mode) {
  case CameraResources::None:
    *ok = release();
    break;

  case CameraResources::Image:
    *ok = updateSet(QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::VideoPlaybackType
		    << ResourcePolicy::VideoRecorderType,
		    QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::ScaleButtonType);
    break;

  case CameraResources::Video:
    *ok = updateSet(QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::VideoPlaybackType
		    << ResourcePolicy::VideoRecorderType,
		    QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::ScaleButtonType);
    break;

  case CameraResources::Recording:
    *ok = updateSet(QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::VideoPlaybackType
		    << ResourcePolicy::VideoRecorderType,
		    QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::ScaleButtonType
		    << ResourcePolicy::AudioRecorderType
		    << ResourcePolicy::AudioPlaybackType);
    break;

  case CameraResources::Player:
    *ok = updateSet(QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::VideoPlaybackType
		    << ResourcePolicy::AudioPlaybackType,
		    QList<ResourcePolicy::ResourceType>());
    break;

  default:
    qWarning() << "Unknown mode" << mode;

    *ok = false;
  }
}

void CameraResourcesWorker::acquired(bool *ok) {
  *ok = m_acquired;
}

void CameraResourcesWorker::hijacked(bool *ok) {
  *ok = m_hijacked;
}

bool CameraResourcesWorker::updateSet(const QList<ResourcePolicy::ResourceType>& required,
				      const QList<ResourcePolicy::ResourceType>& optional) {

  QList<ResourcePolicy::ResourceType> set = listSet();

  foreach (ResourcePolicy::ResourceType r, set) {
    if (required.indexOf(r) != -1) {
      m_set->resource(r)->setOptional(false);
    }
    else if (optional.indexOf(r) != -1) {
      m_set->resource(r)->setOptional(true);
    }
    else {
      m_set->deleteResource(r);
    }
  }

  foreach (ResourcePolicy::ResourceType r, required) {
    m_set->addResource(r);
  }

  foreach (ResourcePolicy::ResourceType r, optional) {
    m_set->addResource(r);
    ResourcePolicy::Resource *res = m_set->resource(r);
    if (res) {
      res->setOptional(true);
    }
  }

  if (m_set->contains(ResourcePolicy::AudioPlaybackType)) {
    bool isOptional = m_set->resource(ResourcePolicy::AudioPlaybackType)->isOptional();

    ResourcePolicy::AudioResource *audio = new ResourcePolicy::AudioResource(APPLICATION_CLASS);
    audio->setProcessID(QCoreApplication::applicationPid());
    audio->setOptional(isOptional);
    m_set->addResourceObject(audio);
  }

  m_acquiring = true;

  m_set->update();
  m_set->acquire();

  while (m_acquiring) {
    QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
  }

  return m_acquired;
}

bool CameraResourcesWorker::release() {
  m_acquiring = true;

  m_set->release();

  while (m_acquiring) {
    QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
  }

  m_mode = CameraResources::None;

  return true;
}

void CameraResourcesWorker::setAcquired(bool acquired) {
  if (m_acquired != acquired) {
    m_acquired = acquired;
    emit acquiredChanged();
  }
}

void CameraResourcesWorker::setHijacked(bool hijacked) {
  if (m_hijacked != hijacked) {
    m_hijacked = hijacked;
    emit hijackedChanged();
  }
}

void CameraResourcesWorker::isResourceGranted(bool *ok, int resource) {

  ResourcePolicy::ResourceType rt = (ResourcePolicy::ResourceType)resource;

  ResourcePolicy::Resource *r = m_set->resource(rt);
  if (r) {
    *ok = r->isGranted();
  }
}
<commit_msg>Fix compile error with latest qt5 libresourceqt<commit_after>/*!
 * This file is part of CameraPlus.
 *
 * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

#include "cameraresources.h"
#if defined(QT4)
#include <dbusconnectioneventloop.h>
#endif
#include <QDebug>

#define APPLICATION_CLASS "camera"

CameraResources::CameraResources(QObject *parent) :
  QObject(parent),
  m_worker(new CameraResourcesWorker) {

  m_worker->moveToThread(&m_thread);

#if defined(QT4)
  DBUSConnectionEventLoop::getInstance().moveToThread(&m_thread);
#endif

  QObject::connect(&m_thread, SIGNAL(started()), m_worker, SLOT(init()));
  m_thread.start();

  qRegisterMetaType<CameraResources::Mode>("CameraResources::Mode");
  qRegisterMetaType<bool *>("bool *");

  QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(acquiredChanged()));
  QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(hijackedChanged()));
  QObject::connect(m_worker, SIGNAL(updated()), this, SIGNAL(updated()));
  QObject::connect(m_worker, SIGNAL(acquiredChanged()), this, SIGNAL(scaleAcquisitionChanged()));
  QObject::connect(m_worker, SIGNAL(hijackedChanged()), this, SIGNAL(scaleAcquisitionChanged()));
  QObject::connect(m_worker, SIGNAL(updated()), this, SIGNAL(scaleAcquisitionChanged()));
}

CameraResources::~CameraResources() {
  acquire(CameraResources::None);
  m_thread.exit(0);

  while (m_thread.isRunning()) {
    m_thread.wait(10);
  }

  delete m_worker;
  m_worker = 0;
}

bool CameraResources::isResourceGranted(const ResourcePolicy::ResourceType& resource) const {
  bool ok = false;

  QMetaObject::invokeMethod(m_worker, "isResourceGranted", Qt::BlockingQueuedConnection,
			    Q_ARG(bool *, &ok), Q_ARG(int, resource));

  return ok;
}

bool CameraResources::acquire(const Mode& mode) {
  bool ok = false;

  QMetaObject::invokeMethod(m_worker, "acquire", Qt::BlockingQueuedConnection,
			    Q_ARG(bool *, &ok), Q_ARG(CameraResources::Mode, mode));

  return ok;
}

bool CameraResources::acquired() const {
  bool ok = false;

  QMetaObject::invokeMethod(m_worker, "acquired", Qt::BlockingQueuedConnection,
			    Q_ARG(bool *, &ok));

  return ok;
}

bool CameraResources::hijacked() const {
  bool ok = false;

  QMetaObject::invokeMethod(m_worker, "hijacked", Qt::BlockingQueuedConnection,
			    Q_ARG(bool *, &ok));

  return ok;
}

bool CameraResources::isScaleAcquired() const {
  return isResourceGranted(ResourcePolicy::ScaleButtonType);
}

CameraResourcesWorker::CameraResourcesWorker(QObject *parent) :
  QObject(parent),
  m_set(0),
  m_mode(CameraResources::None),
  m_acquired(false),
  m_acquiring(false),
  m_hijacked(false) {

}

CameraResourcesWorker::~CameraResourcesWorker() {

}

void CameraResourcesWorker::init() {
  m_set = new ResourcePolicy::ResourceSet(APPLICATION_CLASS, this);
  m_set->setAlwaysReply();

  QObject::connect(m_set, SIGNAL(resourcesReleased()), this, SLOT(resourcesReleased()));
  QObject::connect(m_set, SIGNAL(lostResources()), this, SLOT(lostResources()));
  QObject::connect(m_set, SIGNAL(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)),
		   this, SLOT(resourcesGranted(const QList<ResourcePolicy::ResourceType>&)));
  QObject::connect(m_set, SIGNAL(resourcesDenied()), this, SLOT(resourcesDenied()));

  if (!m_set->initAndConnect()) {
    qCritical() << "Failed to connect to resource policy engine";
  }
}

void CameraResourcesWorker::resourcesReleased() {
  setHijacked(false);
  setAcquired(false);

  m_acquiring = false;
}

void CameraResourcesWorker::lostResources() {
  setAcquired(false);
  setHijacked(true);

  m_acquiring = false;
}

void CameraResourcesWorker::resourcesGranted(const QList<ResourcePolicy::ResourceType>& optional) {
  Q_UNUSED(optional);

  if (!m_acquiring) {
    // This can happen when:
    // 1) We lose/gain optional resources.
    // 2) A higher priority application releases resources back.
    emit updated();
  }

  m_acquiring = false;

  setAcquired(true);
  setHijacked(false);
}

void CameraResourcesWorker::resourcesDenied() {
  setAcquired(false);
  setHijacked(true);

  m_acquiring = false;
}

QList<ResourcePolicy::ResourceType> CameraResourcesWorker::listSet() {
  QList<ResourcePolicy::Resource *> resources = m_set->resources();

  QList<ResourcePolicy::ResourceType> set;

  foreach (ResourcePolicy::Resource *r, resources) {
    set << r->type();
  }

  return set;
}

void CameraResourcesWorker::acquire(bool *ok, const CameraResources::Mode& mode) {
  if (mode == m_mode) {
    *ok = true;
    return;
  }

  m_mode = mode;

  *ok = false;

  switch (m_mode) {
  case CameraResources::None:
    *ok = release();
    break;

  case CameraResources::Image:
    *ok = updateSet(QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::VideoPlaybackType
		    << ResourcePolicy::VideoRecorderType,
		    QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::ScaleButtonType);
    break;

  case CameraResources::Video:
    *ok = updateSet(QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::VideoPlaybackType
		    << ResourcePolicy::VideoRecorderType,
		    QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::ScaleButtonType);
    break;

  case CameraResources::Recording:
    *ok = updateSet(QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::VideoPlaybackType
		    << ResourcePolicy::VideoRecorderType,
		    QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::ScaleButtonType
		    << ResourcePolicy::AudioRecorderType
		    << ResourcePolicy::AudioPlaybackType);
    break;

  case CameraResources::Player:
    *ok = updateSet(QList<ResourcePolicy::ResourceType>()
		    << ResourcePolicy::VideoPlaybackType
		    << ResourcePolicy::AudioPlaybackType,
		    QList<ResourcePolicy::ResourceType>());
    break;

  default:
    qWarning() << "Unknown mode" << mode;

    *ok = false;
  }
}

void CameraResourcesWorker::acquired(bool *ok) {
  *ok = m_acquired;
}

void CameraResourcesWorker::hijacked(bool *ok) {
  *ok = m_hijacked;
}

bool CameraResourcesWorker::updateSet(const QList<ResourcePolicy::ResourceType>& required,
				      const QList<ResourcePolicy::ResourceType>& optional) {

  QList<ResourcePolicy::ResourceType> set = listSet();

  foreach (ResourcePolicy::ResourceType r, set) {
    if (required.indexOf(r) != -1) {
      m_set->resource(r)->setOptional(false);
    }
    else if (optional.indexOf(r) != -1) {
      m_set->resource(r)->setOptional(true);
    }
    else {
      m_set->deleteResource(r);
    }
  }

  foreach (ResourcePolicy::ResourceType r, required) {
    m_set->addResource(r);
  }

  foreach (ResourcePolicy::ResourceType r, optional) {
    m_set->addResource(r);
    ResourcePolicy::Resource *res = m_set->resource(r);
    if (res) {
      res->setOptional(true);
    }
  }

  if (m_set->contains(ResourcePolicy::AudioPlaybackType)) {
    bool isOptional = m_set->resource(ResourcePolicy::AudioPlaybackType)->isOptional();

    ResourcePolicy::AudioResource *audio = new ResourcePolicy::AudioResource(APPLICATION_CLASS);
    audio->setProcessID(QCoreApplication::applicationPid());
    audio->setOptional(isOptional);
    m_set->addResourceObject(audio);
  }

  m_acquiring = true;

  m_set->update();
  m_set->acquire();

  while (m_acquiring) {
    QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
  }

  return m_acquired;
}

bool CameraResourcesWorker::release() {
  m_acquiring = true;

  m_set->release();

  while (m_acquiring) {
    QCoreApplication::processEvents(QEventLoop::WaitForMoreEvents);
  }

  m_mode = CameraResources::None;

  return true;
}

void CameraResourcesWorker::setAcquired(bool acquired) {
  if (m_acquired != acquired) {
    m_acquired = acquired;
    emit acquiredChanged();
  }
}

void CameraResourcesWorker::setHijacked(bool hijacked) {
  if (m_hijacked != hijacked) {
    m_hijacked = hijacked;
    emit hijackedChanged();
  }
}

void CameraResourcesWorker::isResourceGranted(bool *ok, int resource) {

  ResourcePolicy::ResourceType rt = (ResourcePolicy::ResourceType)resource;

  ResourcePolicy::Resource *r = m_set->resource(rt);
  if (r) {
    *ok = r->isGranted();
  }
}
<|endoftext|>