<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkOnePlusOneEvolutionaryOptimizer.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef _itkOnePlusOneEvolutionaryOptimizer_cxx
#define _itkOnePlusOneEvolutionaryOptimizer_cxx

#include "itkOnePlusOneEvolutionaryOptimizer.h"
#include "vcl_cmath.h"
#include "vnl/vnl_matrix.h"

namespace itk
{

OnePlusOneEvolutionaryOptimizer
::OnePlusOneEvolutionaryOptimizer()
{
  m_Maximize = false;
  m_Epsilon = (double) 1.5e-4  ;
  m_RandomGenerator = 0 ;

  m_Initialized = false ;
  m_GrowthFactor = 1.05 ;
  m_ShrinkFactor = pow(m_GrowthFactor, -0.25) ;
  m_InitialRadius = 1.01 ;
  m_MaximumIteration = 100 ;
  m_Stop = false ;
  m_CurrentCost = 0;
  m_CurrentIteration = 0;
}

OnePlusOneEvolutionaryOptimizer
::~OnePlusOneEvolutionaryOptimizer()
{
}

void
OnePlusOneEvolutionaryOptimizer
::SetNormalVariateGenerator(NormalVariateGeneratorType* generator)
{
  if ( m_RandomGenerator != generator )
    {
    m_RandomGenerator = generator ;
    this->Modified() ;
    }
}

void
OnePlusOneEvolutionaryOptimizer
::Initialize(double initialRadius, double grow, double shrink)
{
  m_InitialRadius = initialRadius ;

  if (grow == -1)
    m_GrowthFactor = 1.05 ;
  else
    m_GrowthFactor = grow ;

  if (shrink == -1)
    m_ShrinkFactor = pow(m_GrowthFactor, -0.25) ;
  else
    m_ShrinkFactor = shrink ;
}

void
OnePlusOneEvolutionaryOptimizer
::StartOptimization()
{

  if( m_CostFunction.IsNull() )
    {
    return ;
    }

  this->InvokeEvent( StartEvent() );
  m_Stop = false ;

  unsigned int spaceDimension = m_CostFunction->GetNumberOfParameters();
  vnl_matrix<double> A(spaceDimension, spaceDimension) ;
  vnl_vector<double> parent(this->GetInitialPosition());
  vnl_vector<double> f_norm(spaceDimension);
  vnl_vector<double> child(spaceDimension);
  vnl_vector<double> delta(spaceDimension);

  ParametersType parentPosition( spaceDimension );
  ParametersType childPosition(spaceDimension) ;

  for( unsigned int i=0; i<spaceDimension; i++)
    {
    parentPosition[i] = parent[i];
    }

  itkDebugMacro(<< ": initial position: " << parentPosition) ;
  double pvalue = m_CostFunction->GetValue(parentPosition);
  this->SetCurrentPosition(parentPosition) ;
  const Optimizer::ScalesType& scales = this->GetScales() ;

  // Make sure the scales have been set properly
  if (scales.size() != spaceDimension)
    {
    itkExceptionMacro(<< "The size of Scales is "
                      << scales.size()
                      << ", but the NumberOfParameters for the CostFunction is "
                      << spaceDimension
                      << ".");
    }

  A.set_identity() ;
  for(unsigned int i = 0  ; i < spaceDimension ; i++)
    {
    A(i,i) = m_InitialRadius / scales[i] ;
    }
  m_CurrentIteration = 0 ;

  for (unsigned int iter = 0 ; iter < m_MaximumIteration ; iter++)
    {
    if ( m_Stop )
      {
      break ;
      }

    ++m_CurrentIteration ;

    for (unsigned int i=0 ; i < spaceDimension ; i++)
      {
      f_norm[i] = m_RandomGenerator->GetVariate() ;
      }

    delta  = A * f_norm ;
    child  = parent + delta ;

    for( unsigned int i=0; i<spaceDimension; i++)
      {
      childPosition[i] = child[i];
      }

    double cvalue = m_CostFunction->GetValue(childPosition);

    itkDebugMacro(<< iter << ": parent: " << pvalue
                  << " child: "<< cvalue );

    double adjust = m_ShrinkFactor ;
    if(m_Maximize)
      {
      if (cvalue > pvalue)
        {
        pvalue = cvalue ;
        parent.swap(child) ;
        adjust = m_GrowthFactor ;
        for( unsigned int i=0; i<spaceDimension; i++)
          {
          parentPosition[i] = parent[i];
          }
        this->SetCurrentPosition(parentPosition) ;
        }
      }
    else
      {
      if (cvalue < pvalue)
        {
        pvalue = cvalue ;
        parent.swap(child) ;
        adjust = m_GrowthFactor ;
        for( unsigned int i=0; i<spaceDimension; i++)
          {
          parentPosition[i] = parent[i];
          }
        this->SetCurrentPosition(parentPosition) ;
        }
      }

    m_CurrentCost = pvalue ;
    // convergence criterion: f-norm of A < epsilon_A
    // Compute double precision sum of absolute values of
    // a single precision vector
    double fro_norm = A.fro_norm() ;
    itkDebugMacro(<< "A f-norm:" << fro_norm);
    if (fro_norm <= m_Epsilon)
      {
      itkDebugMacro(<< "converges at iteration = " << iter) ;
      break ;
      }

    // A += (adjust - 1)/ (f_norm * f_norm) * A * f_norm * f_norm ;
    // Blas_R1_Update(A, A * f_norm, f_norm,
    //             ((adjust - 1) / Blas_Dot_Prod(f_norm, f_norm)));
    // = DGER(Fortran)
    //   performs the rank 1 operation
    // A := alpha*x*y' + A,
    // where y' = transpose(y)
    // where alpha is a scalar, x is an m element vector, y is an n element
    // vector and A is an m by n matrix.
    // x = A * f_norm , y = f_norm, alpha = (adjust - 1) / Blas_Dot_Prod(
    // f_norm, f_norm)

    //A = A + (adjust - 1.0) * A ;
    double alpha = ((adjust - 1.0) / dot_product(f_norm, f_norm)) ;
    for ( unsigned int c = 0 ; c < spaceDimension ; c++ )
      {
      double temp = alpha * f_norm[c] ;
      if ( f_norm[c] == 0.0 )
        {
        temp = 1.0 ;
        }

      for (unsigned int r = 0 ; r < spaceDimension ; r++)
        {
        A(c, r) += alpha * delta[r] * temp ;
        }
      }

    this->InvokeEvent( IterationEvent() );
    itkDebugMacro(<< "Current position: " << this->GetCurrentPosition()) ;
    }
  this->InvokeEvent( EndEvent() );
}

/**
 *
 */
void
OnePlusOneEvolutionaryOptimizer
::PrintSelf(std::ostream& os, Indent indent) const
{

  Superclass::PrintSelf(os,indent);

  if (m_RandomGenerator)
    {
    os << indent << "Random Generator  " << m_RandomGenerator.GetPointer()  << std::endl;
    }
  else
    {
    os << indent << "Random Generator  " << "(none)" << std::endl;
    }
  os << indent << "Maximum Iteration " << m_MaximumIteration << std::endl;
  os << indent << "Epsilon           " << m_Epsilon          << std::endl;
  os << indent << "Initial Radius    " << m_InitialRadius    << std::endl;
  os << indent << "Growth Fractor    " << m_GrowthFactor     << std::endl;
  os << indent << "Shrink Fractor    " << m_ShrinkFactor     << std::endl;
  os << indent << "Initialized       " << m_Initialized      << std::endl;
  os << indent << "Current Cost      " << m_CurrentCost << std::endl;
  os << indent << "Current Iteration " << m_CurrentIteration << std::endl;

}

} // end of namespace itk
#endif
<commit_msg>FIX: m_Maximize was missing from PrintSelf().<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit
  Module:    itkOnePlusOneEvolutionaryOptimizer.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) Insight Software Consortium. All rights reserved.
  See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.

     This software is distributed WITHOUT ANY WARRANTY; without even
     the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
     PURPOSE.  See the above copyright notices for more information.

=========================================================================*/
#ifndef _itkOnePlusOneEvolutionaryOptimizer_cxx
#define _itkOnePlusOneEvolutionaryOptimizer_cxx

#include "itkOnePlusOneEvolutionaryOptimizer.h"
#include "vcl_cmath.h"
#include "vnl/vnl_matrix.h"

namespace itk
{

OnePlusOneEvolutionaryOptimizer
::OnePlusOneEvolutionaryOptimizer()
{
  m_Maximize = false;
  m_Epsilon = (double) 1.5e-4  ;
  m_RandomGenerator = 0 ;

  m_Initialized = false ;
  m_GrowthFactor = 1.05 ;
  m_ShrinkFactor = pow(m_GrowthFactor, -0.25) ;
  m_InitialRadius = 1.01 ;
  m_MaximumIteration = 100 ;
  m_Stop = false ;
  m_CurrentCost = 0;
  m_CurrentIteration = 0;
}

OnePlusOneEvolutionaryOptimizer
::~OnePlusOneEvolutionaryOptimizer()
{
}

void
OnePlusOneEvolutionaryOptimizer
::SetNormalVariateGenerator(NormalVariateGeneratorType* generator)
{
  if ( m_RandomGenerator != generator )
    {
    m_RandomGenerator = generator ;
    this->Modified() ;
    }
}

void
OnePlusOneEvolutionaryOptimizer
::Initialize(double initialRadius, double grow, double shrink)
{
  m_InitialRadius = initialRadius ;

  if (grow == -1)
    m_GrowthFactor = 1.05 ;
  else
    m_GrowthFactor = grow ;

  if (shrink == -1)
    m_ShrinkFactor = pow(m_GrowthFactor, -0.25) ;
  else
    m_ShrinkFactor = shrink ;
}

void
OnePlusOneEvolutionaryOptimizer
::StartOptimization()
{

  if( m_CostFunction.IsNull() )
    {
    return ;
    }

  this->InvokeEvent( StartEvent() );
  m_Stop = false ;

  unsigned int spaceDimension = m_CostFunction->GetNumberOfParameters();
  vnl_matrix<double> A(spaceDimension, spaceDimension) ;
  vnl_vector<double> parent(this->GetInitialPosition());
  vnl_vector<double> f_norm(spaceDimension);
  vnl_vector<double> child(spaceDimension);
  vnl_vector<double> delta(spaceDimension);

  ParametersType parentPosition( spaceDimension );
  ParametersType childPosition(spaceDimension) ;

  for( unsigned int i=0; i<spaceDimension; i++)
    {
    parentPosition[i] = parent[i];
    }

  itkDebugMacro(<< ": initial position: " << parentPosition) ;
  double pvalue = m_CostFunction->GetValue(parentPosition);
  this->SetCurrentPosition(parentPosition) ;
  const Optimizer::ScalesType& scales = this->GetScales() ;

  // Make sure the scales have been set properly
  if (scales.size() != spaceDimension)
    {
    itkExceptionMacro(<< "The size of Scales is "
                      << scales.size()
                      << ", but the NumberOfParameters for the CostFunction is "
                      << spaceDimension
                      << ".");
    }

  A.set_identity() ;
  for(unsigned int i = 0  ; i < spaceDimension ; i++)
    {
    A(i,i) = m_InitialRadius / scales[i] ;
    }
  m_CurrentIteration = 0 ;

  for (unsigned int iter = 0 ; iter < m_MaximumIteration ; iter++)
    {
    if ( m_Stop )
      {
      break ;
      }

    ++m_CurrentIteration ;

    for (unsigned int i=0 ; i < spaceDimension ; i++)
      {
      f_norm[i] = m_RandomGenerator->GetVariate() ;
      }

    delta  = A * f_norm ;
    child  = parent + delta ;

    for( unsigned int i=0; i<spaceDimension; i++)
      {
      childPosition[i] = child[i];
      }

    double cvalue = m_CostFunction->GetValue(childPosition);

    itkDebugMacro(<< iter << ": parent: " << pvalue
                  << " child: "<< cvalue );

    double adjust = m_ShrinkFactor ;
    if( m_Maximize )
      {
      if (cvalue > pvalue)
        {
        pvalue = cvalue ;
        parent.swap(child) ;
        adjust = m_GrowthFactor ;
        for( unsigned int i=0; i<spaceDimension; i++)
          {
          parentPosition[i] = parent[i];
          }
        this->SetCurrentPosition(parentPosition) ;
        }
      }
    else
      {
      if (cvalue < pvalue)
        {
        pvalue = cvalue ;
        parent.swap(child) ;
        adjust = m_GrowthFactor ;
        for( unsigned int i=0; i<spaceDimension; i++)
          {
          parentPosition[i] = parent[i];
          }
        this->SetCurrentPosition(parentPosition) ;
        }
      }

    m_CurrentCost = pvalue ;
    // convergence criterion: f-norm of A < epsilon_A
    // Compute double precision sum of absolute values of
    // a single precision vector
    double fro_norm = A.fro_norm() ;
    itkDebugMacro(<< "A f-norm:" << fro_norm);
    if (fro_norm <= m_Epsilon)
      {
      itkDebugMacro(<< "converges at iteration = " << iter) ;
      break ;
      }

    // A += (adjust - 1)/ (f_norm * f_norm) * A * f_norm * f_norm ;
    // Blas_R1_Update(A, A * f_norm, f_norm,
    //             ((adjust - 1) / Blas_Dot_Prod(f_norm, f_norm)));
    // = DGER(Fortran)
    //   performs the rank 1 operation
    // A := alpha*x*y' + A,
    // where y' = transpose(y)
    // where alpha is a scalar, x is an m element vector, y is an n element
    // vector and A is an m by n matrix.
    // x = A * f_norm , y = f_norm, alpha = (adjust - 1) / Blas_Dot_Prod(
    // f_norm, f_norm)

    //A = A + (adjust - 1.0) * A ;
    double alpha = ((adjust - 1.0) / dot_product(f_norm, f_norm)) ;
    for ( unsigned int c = 0 ; c < spaceDimension ; c++ )
      {
      double temp = alpha * f_norm[c] ;
      if ( f_norm[c] == 0.0 )
        {
        temp = 1.0 ;
        }

      for (unsigned int r = 0 ; r < spaceDimension ; r++)
        {
        A(c, r) += alpha * delta[r] * temp ;
        }
      }

    this->InvokeEvent( IterationEvent() );
    itkDebugMacro(<< "Current position: " << this->GetCurrentPosition()) ;
    }
  this->InvokeEvent( EndEvent() );
}

/**
 *
 */
void
OnePlusOneEvolutionaryOptimizer
::PrintSelf(std::ostream& os, Indent indent) const
{

  Superclass::PrintSelf(os,indent);

  if (m_RandomGenerator)
    {
    os << indent << "Random Generator  " << m_RandomGenerator.GetPointer()  << std::endl;
    }
  else
    {
    os << indent << "Random Generator  " << "(none)" << std::endl;
    }
  os << indent << "Maximum Iteration " << m_MaximumIteration << std::endl;
  os << indent << "Epsilon           " << m_Epsilon          << std::endl;
  os << indent << "Initial Radius    " << m_InitialRadius    << std::endl;
  os << indent << "Growth Fractor    " << m_GrowthFactor     << std::endl;
  os << indent << "Shrink Fractor    " << m_ShrinkFactor     << std::endl;
  os << indent << "Initialized       " << m_Initialized      << std::endl;
  os << indent << "Current Cost      " << m_CurrentCost      << std::endl;
  os << indent << "Current Iteration " << m_CurrentIteration << std::endl;
  os << indent << "Maximize On/Off   " << m_Maximize         << std::endl;

}

} // end of namespace itk
#endif
<|endoftext|>


<commit_before>/* Copyright (C) 2008-2011 Xavier Pujol.

   This file is part of fplll. fplll 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.

   fplll 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 fplll. If not, see <http://www.gnu.org/licenses/>. */

#include "svpcvp.h"
#include "enumerate.h"
#include "topenum.h"

FPLLL_BEGIN_NAMESPACE

/* Shortest vector problem
   ======================= */

/* Returns i such that the shortest vector of L(b) belongs to
   L(b_0,...,b_(i-1)), assuming that the error on rdiag's is less than 100%.
   If b is LLL-reduced, then for any reasonnable dimension,
   max(rdiag[0],...,rdiag[i-1]) / min(rdiag[0],...,rdiag[i-1])
   is much smaller than numeric_limits<double>::max */
static int lastUsefulIndex(const Matrix<Float>& r) {
  int i;
  Float rdiagMinValue;
  rdiagMinValue.mul_2si(r(0, 0), 1);
  for (i = r.getRows() - 1; i > 0; i--) {
    if (r(i, i) <= rdiagMinValue) break;
  }
  return i + 1;
}

/* Finds the shortest vector of the basis b and returns its squared norm in
   basisMin */
static void getBasisMin(Integer& basisMin, const IntMatrix& b,
                        int first, int last) {
  Integer sqNorm;
  int n = b.getCols();
  sqrNorm(basisMin, b[first], n);

  for (int i = first + 1; i < last; i++) {
    sqrNorm(sqNorm, b[i], n);
    if (sqNorm < basisMin)
      basisMin = sqNorm;
  }
}

static bool enumerateSVP(int d, MatGSO<Integer, Float>& gso, Float& maxDist,
        Evaluator<Float>& evaluator, const vector<double>& pruning,
        int flags) {
  bool dual = (flags & SVP_DUAL);
  if (d == 1 || !pruning.empty() || dual) {
    Enumeration::enumerate(gso, maxDist, 0, evaluator, FloatVect(), FloatVect(),
            0, d, pruning, dual);
  }
  else {
    Enumerator enumerator(d, gso.getMuMatrix(), gso.getRMatrix());
    while (enumerator.enumNext(maxDist)) {
      if (flags & SVP_VERBOSE) {
        evaluator.newSolFlag = false;
        cerr << enumerator.getSubTree();
        if (evaluator.evalMode != EVALMODE_SV)
          cerr << " (count=2*" << evaluator.solCount << ")";
      }

      /* Enumerates short vectors only in enumerator.getSubTree()
        (about maxVolume iterations or less) */
      Enumeration::enumerate(gso, maxDist, 0, evaluator,
        FloatVect(), enumerator.getSubTree(), 0, d, pruning);

      if (flags & SVP_VERBOSE) {
        cerr << "\r" << (char) 27 << "[K";
        if (evaluator.evalMode == EVALMODE_SV && evaluator.newSolFlag)
          cerr << "Solution norm^2=" << evaluator.lastPartialDist
                << " value=" << evaluator.solCoord << endl;
      }
    }
  }
  return !evaluator.solCoord.empty();
}

static int shortestVectorEx(IntMatrix& b, IntVect& solCoord,
        SVPMethod method, const vector<double>& pruning, int flags,
        EvaluatorMode evalMode, const Integer& argIntMaxDist,
        long long& solCount) {
  // d = lattice dimension (note that it might decrease during preprocessing)
  int d = b.getRows();
  // n = dimension of the space
  int n = b.getCols();

  FPLLL_CHECK(d > 0 && n > 0, "shortestVector: empty matrix");
  FPLLL_CHECK(d <= n, "shortestVector: number of vectors > size of the vectors");

  // Sets the floating-point precision
  // Error bounds on GSO are valid if prec >= minprec
  double rho;
  int minPrec = gsoMinPrec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA);
  int prec = max(53, minPrec + 10);
  int oldprec = Float::setprec(prec);

  // Allocates space for vectors and matrices in constructors
  IntMatrix emptyMat;
  MatGSO<Integer, Float> gso(b, emptyMat, emptyMat, GSO_INT_GRAM);
  Float maxDist;
  Integer intMaxDist;
  Integer itmp1;

  // Computes the Gram-Schmidt orthogonalization in floating-point
  gso.updateGSO();
  genZeroVect(solCoord, d);

  // If the last b_i* are too large, removes them to avoid an underflow
  int newD = lastUsefulIndex(gso.getRMatrix());
  if (newD < d) {
    //FPLLL_TRACE("Ignoring the last " << d - newD << " vector(s)");
    d = newD;
  }

  if (flags & SVP_DUAL) {
    maxDist = gso.getRExp(d - 1, d - 1);
    Float one; one = 1.0;
    maxDist.div(one, maxDist);
    if (flags & SVP_VERBOSE) {
      cout << "maxDist = " << maxDist << endl;
    }
  } else {
    if (evalMode == EVALMODE_SV) {
      /* Computes a bound for the enumeration. This bound would work for an
         exact algorithm, but we will increase it later to ensure that the fp
         algorithm finds a solution */
      getBasisMin(intMaxDist, b, 0, d);
    }
    else {
      /* Use the bound given as a parameter */
      intMaxDist = argIntMaxDist;
    }
    maxDist.set_z(intMaxDist, GMP_RNDU);
  }

  // Initializes the evaluator of solutions
  Evaluator<Float>* evaluator;
  if (method == SVPM_FAST) {
    evaluator = new FastEvaluator<Float>(d, gso.getMuMatrix(),
            gso.getRMatrix(), evalMode);
  }
  else if (method == SVPM_PROVED) {
    ExactEvaluator* p = new ExactEvaluator(d, b, gso.getMuMatrix(),
            gso.getRMatrix(), evalMode);
    p->intMaxDist = intMaxDist;
    evaluator = p;
  }
  else {
    FPLLL_ABORT("shortestVector: invalid evaluator type");
  }
  evaluator->initDeltaDef(prec, rho, true);

  if (!(flags & SVP_OVERRIDE_BND) && (evalMode == EVALMODE_SV || method == SVPM_PROVED)) {
    Float ftmp1;
    bool result = evaluator->getMaxErrorAux(maxDist, true, ftmp1);
    FPLLL_CHECK(result, "shortestVector: cannot compute an initial bound");
    if (flags & SVP_DUAL) {
      maxDist.add(maxDist, ftmp1, GMP_RNDU);
    } else {
      maxDist.sub(maxDist, ftmp1, GMP_RNDU);
    }
  }

  // Main loop of the enumeration
  enumerateSVP(d, gso, maxDist, *evaluator, pruning, flags);

  int result = RED_ENUM_FAILURE;
  if (evalMode != EVALMODE_SV) {
    result = RED_SUCCESS;
    solCount = evaluator->solCount * 2;
  }
  else if (!evaluator->solCoord.empty()) {
    /*Float fMaxError;
    validMaxError = evaluator->getMaxError(fMaxError);
    maxError = fMaxError.get_d(GMP_RNDU);*/
    for (int i = 0; i < d; i++) {
      itmp1.set_f(evaluator->solCoord[i]);
      solCoord[i].add(solCoord[i], itmp1);
    }
    result = RED_SUCCESS;
  }

  delete evaluator;
  Float::setprec(oldprec);
  return result;
}

int shortestVector(IntMatrix& b, IntVect& solCoord,
                   SVPMethod method, int flags) {
  long long tmp;
  return shortestVectorEx(b, solCoord, method, vector<double>(), flags,
          EVALMODE_SV, Integer(), tmp);
}

int shortestVectorPruning(IntMatrix& b, IntVect& solCoord,
                   const vector<double>& pruning, Integer& argIntMaxDist, int flags) {
  long long tmp;
  return shortestVectorEx(b, solCoord, SVPM_FAST, pruning, flags,
          EVALMODE_SV, argIntMaxDist, tmp);
}

long long countShortVectors(IntMatrix& b, const Integer& maxSqrNorm,
        SVPMethod method, int flags) {
  long long count;
  IntVect tmp;
  shortestVectorEx(b, tmp, method, vector<double>(), flags,
        EVALMODE_COUNT, maxSqrNorm, count);
  return count;
}

long long printShortVectors(IntMatrix& b, const Integer& maxSqrNorm,
        SVPMethod method) {
  long long count;
  IntVect tmp;
  shortestVectorEx(b, tmp, method, vector<double>(), SVP_DEFAULT,
        EVALMODE_PRINT, maxSqrNorm, count);
  return count;
}

/* Closest vector problem
   ====================== */

static void getGSCoords(const Matrix<Float>& matrix, const Matrix<Float>& mu,
  const Matrix<Float>& r, const FloatVect& v, FloatVect& vcoord) {

  int n = matrix.getRows(), m = matrix.getCols();

  if (static_cast<int>(vcoord.size()) != n) vcoord.resize(n);
  FPLLL_DEBUG_CHECK(mu.getRows() == n && mu.getCols() == n &&
    r.getRows() == n && r.getCols() == n &&
    static_cast<int>(v.size()) == m);

  for (int i = 0; i < n; i++) {
    vcoord[i] = 0.0;
    for (int j = 0; j < m; j++)
      vcoord[i].addmul(v[j], matrix(i, j));
    for (int j = 0; j < i; j++)
      vcoord[i].submul(mu(i, j), vcoord[j]);
  }
  for (int i = 0; i < n; i++) {
    vcoord[i].div(vcoord[i], r(i, i));
  }
}

static void babai(const FloatMatrix& matrix, const Matrix<Float>& mu,
  const Matrix<Float>& r, const FloatVect& target, FloatVect& targetcoord) {

  int d = matrix.getRows();
  getGSCoords(matrix, mu, r, target, targetcoord);
  for (int i = d - 1; i >= 0; i--) {
    targetcoord[i].rnd(targetcoord[i]);
    for (int j = 0; j < i; j++)
      targetcoord[j].submul(mu(i, j), targetcoord[i]);
  }
}

int closestVector(IntMatrix& b, const IntVect& intTarget,
                  IntVect& solCoord, int flags) {
  // d = lattice dimension (note that it might decrease during preprocessing)
  int d = b.getRows();
  // n = dimension of the space
  int n = b.getCols();

  FPLLL_CHECK(d > 0 && n > 0, "closestVector: empty matrix");
  FPLLL_CHECK(d <= n, "closestVector: number of vectors > size of the vectors");

  // Sets the floating-point precision
  // Error bounds on GSO are valid if prec >= minprec
  double rho;
  int minPrec = gsoMinPrec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA);
  int prec = max(53, minPrec + 10);
  int oldprec = Float::setprec(prec);

  // Allocates space for vectors and matrices in constructors
  IntMatrix emptyMat;
  MatGSO<Integer, Float> gso(b, emptyMat, emptyMat, GSO_INT_GRAM);
  FloatVect targetCoord;
  Float maxDist;
  Integer itmp1;

  // Computes the Gram-Schmidt orthogonalization in floating-point
  gso.updateGSO();
  genZeroVect(solCoord, d);

  /* Applies Babai's algorithm. Because we use fp, it might be necessary to
      do it several times (if ||target|| >> ||b_i||) */
  FloatMatrix floatMatrix(d, n);
  FloatVect target(n), babaiSol;
  IntVect intNewTarget = intTarget;

  for (int i = 0; i < d; i++)
    for (int j = 0; j < n; j++)
      floatMatrix(i, j).set_z(b(i, j));

  for (int loopIdx = 0;; loopIdx++) {
    if (loopIdx >= 0x100 && ((loopIdx & (loopIdx - 1)) == 0))
      FPLLL_INFO("warning: possible infinite loop in Babai's algorithm");

    for (int i = 0; i < n; i++) {
      target[i].set_z(intNewTarget[i]);
    }
    babai(floatMatrix, gso.getMuMatrix(), gso.getRMatrix(), target, babaiSol);
    int idx;
    for (idx = 0; idx < d && babaiSol[idx] >= -1 && babaiSol[idx] <= 1;
          idx++) {}
    if (idx == d) break;

    for (int i = 0; i < d; i++) {
      itmp1.set_f(babaiSol[i]);
      solCoord[i].add(solCoord[i], itmp1);
      for (int j = 0; j < n; j++)
        intNewTarget[j].submul(itmp1, b(i, j));
    }
  }
  //FPLLL_TRACE("BabaiSol=" << solCoord);
  getGSCoords(floatMatrix, gso.getMuMatrix(), gso.getRMatrix(), target,
          targetCoord);

  /* Computes a very large bound to make the algorithm work
      until the first solution is found */
  maxDist = 0;
  for (int i = 1; i < d; i++) {
    // getRExp(i, i) = r(i, i) because gso is initialized without GSO_ROW_EXPO
    maxDist.add(maxDist, gso.getRExp(i, i));
  }

  FastEvaluator<Float> evaluator(n, gso.getMuMatrix(), gso.getRMatrix(),
          EVALMODE_CV);

  // Main loop of the enumeration
  Enumeration::enumerate(gso, maxDist, 0, evaluator, targetCoord,
          vector<Float>(), 0, d, vector<double>());

  int result = RED_ENUM_FAILURE;
  if (!evaluator.solCoord.empty()) {
    //FPLLL_TRACE("evaluator.solCoord=" << evaluator.solCoord);
    if (flags & CVP_VERBOSE)
      FPLLL_INFO("maxDist=" << maxDist);
    for (int i = 0; i < d; i++) {
      itmp1.set_f(evaluator.solCoord[i]);
      solCoord[i].add(solCoord[i], itmp1);
    }
    result = RED_SUCCESS;
  }

  Float::setprec(oldprec);
  return result;
}

FPLLL_END_NAMESPACE
<commit_msg>copyright<commit_after>/* Copyright (C) 2008-2011 Xavier Pujol.
    (C) 2015 Michael Walter.

   This file is part of fplll. fplll 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.

   fplll 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 fplll. If not, see <http://www.gnu.org/licenses/>. */

#include "svpcvp.h"
#include "enumerate.h"
#include "topenum.h"

FPLLL_BEGIN_NAMESPACE

/* Shortest vector problem
   ======================= */

/* Returns i such that the shortest vector of L(b) belongs to
   L(b_0,...,b_(i-1)), assuming that the error on rdiag's is less than 100%.
   If b is LLL-reduced, then for any reasonnable dimension,
   max(rdiag[0],...,rdiag[i-1]) / min(rdiag[0],...,rdiag[i-1])
   is much smaller than numeric_limits<double>::max */
static int lastUsefulIndex(const Matrix<Float>& r) {
  int i;
  Float rdiagMinValue;
  rdiagMinValue.mul_2si(r(0, 0), 1);
  for (i = r.getRows() - 1; i > 0; i--) {
    if (r(i, i) <= rdiagMinValue) break;
  }
  return i + 1;
}

/* Finds the shortest vector of the basis b and returns its squared norm in
   basisMin */
static void getBasisMin(Integer& basisMin, const IntMatrix& b,
                        int first, int last) {
  Integer sqNorm;
  int n = b.getCols();
  sqrNorm(basisMin, b[first], n);

  for (int i = first + 1; i < last; i++) {
    sqrNorm(sqNorm, b[i], n);
    if (sqNorm < basisMin)
      basisMin = sqNorm;
  }
}

static bool enumerateSVP(int d, MatGSO<Integer, Float>& gso, Float& maxDist,
        Evaluator<Float>& evaluator, const vector<double>& pruning,
        int flags) {
  bool dual = (flags & SVP_DUAL);
  if (d == 1 || !pruning.empty() || dual) {
    Enumeration::enumerate(gso, maxDist, 0, evaluator, FloatVect(), FloatVect(),
            0, d, pruning, dual);
  }
  else {
    Enumerator enumerator(d, gso.getMuMatrix(), gso.getRMatrix());
    while (enumerator.enumNext(maxDist)) {
      if (flags & SVP_VERBOSE) {
        evaluator.newSolFlag = false;
        cerr << enumerator.getSubTree();
        if (evaluator.evalMode != EVALMODE_SV)
          cerr << " (count=2*" << evaluator.solCount << ")";
      }

      /* Enumerates short vectors only in enumerator.getSubTree()
        (about maxVolume iterations or less) */
      Enumeration::enumerate(gso, maxDist, 0, evaluator,
        FloatVect(), enumerator.getSubTree(), 0, d, pruning);

      if (flags & SVP_VERBOSE) {
        cerr << "\r" << (char) 27 << "[K";
        if (evaluator.evalMode == EVALMODE_SV && evaluator.newSolFlag)
          cerr << "Solution norm^2=" << evaluator.lastPartialDist
                << " value=" << evaluator.solCoord << endl;
      }
    }
  }
  return !evaluator.solCoord.empty();
}

static int shortestVectorEx(IntMatrix& b, IntVect& solCoord,
        SVPMethod method, const vector<double>& pruning, int flags,
        EvaluatorMode evalMode, const Integer& argIntMaxDist,
        long long& solCount) {
  // d = lattice dimension (note that it might decrease during preprocessing)
  int d = b.getRows();
  // n = dimension of the space
  int n = b.getCols();

  FPLLL_CHECK(d > 0 && n > 0, "shortestVector: empty matrix");
  FPLLL_CHECK(d <= n, "shortestVector: number of vectors > size of the vectors");

  // Sets the floating-point precision
  // Error bounds on GSO are valid if prec >= minprec
  double rho;
  int minPrec = gsoMinPrec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA);
  int prec = max(53, minPrec + 10);
  int oldprec = Float::setprec(prec);

  // Allocates space for vectors and matrices in constructors
  IntMatrix emptyMat;
  MatGSO<Integer, Float> gso(b, emptyMat, emptyMat, GSO_INT_GRAM);
  Float maxDist;
  Integer intMaxDist;
  Integer itmp1;

  // Computes the Gram-Schmidt orthogonalization in floating-point
  gso.updateGSO();
  genZeroVect(solCoord, d);

  // If the last b_i* are too large, removes them to avoid an underflow
  int newD = lastUsefulIndex(gso.getRMatrix());
  if (newD < d) {
    //FPLLL_TRACE("Ignoring the last " << d - newD << " vector(s)");
    d = newD;
  }

  if (flags & SVP_DUAL) {
    maxDist = gso.getRExp(d - 1, d - 1);
    Float one; one = 1.0;
    maxDist.div(one, maxDist);
    if (flags & SVP_VERBOSE) {
      cout << "maxDist = " << maxDist << endl;
    }
  } else {
    if (evalMode == EVALMODE_SV) {
      /* Computes a bound for the enumeration. This bound would work for an
         exact algorithm, but we will increase it later to ensure that the fp
         algorithm finds a solution */
      getBasisMin(intMaxDist, b, 0, d);
    }
    else {
      /* Use the bound given as a parameter */
      intMaxDist = argIntMaxDist;
    }
    maxDist.set_z(intMaxDist, GMP_RNDU);
  }

  // Initializes the evaluator of solutions
  Evaluator<Float>* evaluator;
  if (method == SVPM_FAST) {
    evaluator = new FastEvaluator<Float>(d, gso.getMuMatrix(),
            gso.getRMatrix(), evalMode);
  }
  else if (method == SVPM_PROVED) {
    ExactEvaluator* p = new ExactEvaluator(d, b, gso.getMuMatrix(),
            gso.getRMatrix(), evalMode);
    p->intMaxDist = intMaxDist;
    evaluator = p;
  }
  else {
    FPLLL_ABORT("shortestVector: invalid evaluator type");
  }
  evaluator->initDeltaDef(prec, rho, true);

  if (!(flags & SVP_OVERRIDE_BND) && (evalMode == EVALMODE_SV || method == SVPM_PROVED)) {
    Float ftmp1;
    bool result = evaluator->getMaxErrorAux(maxDist, true, ftmp1);
    FPLLL_CHECK(result, "shortestVector: cannot compute an initial bound");
    if (flags & SVP_DUAL) {
      maxDist.add(maxDist, ftmp1, GMP_RNDU);
    } else {
      maxDist.sub(maxDist, ftmp1, GMP_RNDU);
    }
  }

  // Main loop of the enumeration
  enumerateSVP(d, gso, maxDist, *evaluator, pruning, flags);

  int result = RED_ENUM_FAILURE;
  if (evalMode != EVALMODE_SV) {
    result = RED_SUCCESS;
    solCount = evaluator->solCount * 2;
  }
  else if (!evaluator->solCoord.empty()) {
    /*Float fMaxError;
    validMaxError = evaluator->getMaxError(fMaxError);
    maxError = fMaxError.get_d(GMP_RNDU);*/
    for (int i = 0; i < d; i++) {
      itmp1.set_f(evaluator->solCoord[i]);
      solCoord[i].add(solCoord[i], itmp1);
    }
    result = RED_SUCCESS;
  }

  delete evaluator;
  Float::setprec(oldprec);
  return result;
}

int shortestVector(IntMatrix& b, IntVect& solCoord,
                   SVPMethod method, int flags) {
  long long tmp;
  return shortestVectorEx(b, solCoord, method, vector<double>(), flags,
          EVALMODE_SV, Integer(), tmp);
}

int shortestVectorPruning(IntMatrix& b, IntVect& solCoord,
                   const vector<double>& pruning, Integer& argIntMaxDist, int flags) {
  long long tmp;
  return shortestVectorEx(b, solCoord, SVPM_FAST, pruning, flags,
          EVALMODE_SV, argIntMaxDist, tmp);
}

long long countShortVectors(IntMatrix& b, const Integer& maxSqrNorm,
        SVPMethod method, int flags) {
  long long count;
  IntVect tmp;
  shortestVectorEx(b, tmp, method, vector<double>(), flags,
        EVALMODE_COUNT, maxSqrNorm, count);
  return count;
}

long long printShortVectors(IntMatrix& b, const Integer& maxSqrNorm,
        SVPMethod method) {
  long long count;
  IntVect tmp;
  shortestVectorEx(b, tmp, method, vector<double>(), SVP_DEFAULT,
        EVALMODE_PRINT, maxSqrNorm, count);
  return count;
}

/* Closest vector problem
   ====================== */

static void getGSCoords(const Matrix<Float>& matrix, const Matrix<Float>& mu,
  const Matrix<Float>& r, const FloatVect& v, FloatVect& vcoord) {

  int n = matrix.getRows(), m = matrix.getCols();

  if (static_cast<int>(vcoord.size()) != n) vcoord.resize(n);
  FPLLL_DEBUG_CHECK(mu.getRows() == n && mu.getCols() == n &&
    r.getRows() == n && r.getCols() == n &&
    static_cast<int>(v.size()) == m);

  for (int i = 0; i < n; i++) {
    vcoord[i] = 0.0;
    for (int j = 0; j < m; j++)
      vcoord[i].addmul(v[j], matrix(i, j));
    for (int j = 0; j < i; j++)
      vcoord[i].submul(mu(i, j), vcoord[j]);
  }
  for (int i = 0; i < n; i++) {
    vcoord[i].div(vcoord[i], r(i, i));
  }
}

static void babai(const FloatMatrix& matrix, const Matrix<Float>& mu,
  const Matrix<Float>& r, const FloatVect& target, FloatVect& targetcoord) {

  int d = matrix.getRows();
  getGSCoords(matrix, mu, r, target, targetcoord);
  for (int i = d - 1; i >= 0; i--) {
    targetcoord[i].rnd(targetcoord[i]);
    for (int j = 0; j < i; j++)
      targetcoord[j].submul(mu(i, j), targetcoord[i]);
  }
}

int closestVector(IntMatrix& b, const IntVect& intTarget,
                  IntVect& solCoord, int flags) {
  // d = lattice dimension (note that it might decrease during preprocessing)
  int d = b.getRows();
  // n = dimension of the space
  int n = b.getCols();

  FPLLL_CHECK(d > 0 && n > 0, "closestVector: empty matrix");
  FPLLL_CHECK(d <= n, "closestVector: number of vectors > size of the vectors");

  // Sets the floating-point precision
  // Error bounds on GSO are valid if prec >= minprec
  double rho;
  int minPrec = gsoMinPrec(rho, d, LLL_DEF_DELTA, LLL_DEF_ETA);
  int prec = max(53, minPrec + 10);
  int oldprec = Float::setprec(prec);

  // Allocates space for vectors and matrices in constructors
  IntMatrix emptyMat;
  MatGSO<Integer, Float> gso(b, emptyMat, emptyMat, GSO_INT_GRAM);
  FloatVect targetCoord;
  Float maxDist;
  Integer itmp1;

  // Computes the Gram-Schmidt orthogonalization in floating-point
  gso.updateGSO();
  genZeroVect(solCoord, d);

  /* Applies Babai's algorithm. Because we use fp, it might be necessary to
      do it several times (if ||target|| >> ||b_i||) */
  FloatMatrix floatMatrix(d, n);
  FloatVect target(n), babaiSol;
  IntVect intNewTarget = intTarget;

  for (int i = 0; i < d; i++)
    for (int j = 0; j < n; j++)
      floatMatrix(i, j).set_z(b(i, j));

  for (int loopIdx = 0;; loopIdx++) {
    if (loopIdx >= 0x100 && ((loopIdx & (loopIdx - 1)) == 0))
      FPLLL_INFO("warning: possible infinite loop in Babai's algorithm");

    for (int i = 0; i < n; i++) {
      target[i].set_z(intNewTarget[i]);
    }
    babai(floatMatrix, gso.getMuMatrix(), gso.getRMatrix(), target, babaiSol);
    int idx;
    for (idx = 0; idx < d && babaiSol[idx] >= -1 && babaiSol[idx] <= 1;
          idx++) {}
    if (idx == d) break;

    for (int i = 0; i < d; i++) {
      itmp1.set_f(babaiSol[i]);
      solCoord[i].add(solCoord[i], itmp1);
      for (int j = 0; j < n; j++)
        intNewTarget[j].submul(itmp1, b(i, j));
    }
  }
  //FPLLL_TRACE("BabaiSol=" << solCoord);
  getGSCoords(floatMatrix, gso.getMuMatrix(), gso.getRMatrix(), target,
          targetCoord);

  /* Computes a very large bound to make the algorithm work
      until the first solution is found */
  maxDist = 0;
  for (int i = 1; i < d; i++) {
    // getRExp(i, i) = r(i, i) because gso is initialized without GSO_ROW_EXPO
    maxDist.add(maxDist, gso.getRExp(i, i));
  }

  FastEvaluator<Float> evaluator(n, gso.getMuMatrix(), gso.getRMatrix(),
          EVALMODE_CV);

  // Main loop of the enumeration
  Enumeration::enumerate(gso, maxDist, 0, evaluator, targetCoord,
          vector<Float>(), 0, d, vector<double>());

  int result = RED_ENUM_FAILURE;
  if (!evaluator.solCoord.empty()) {
    //FPLLL_TRACE("evaluator.solCoord=" << evaluator.solCoord);
    if (flags & CVP_VERBOSE)
      FPLLL_INFO("maxDist=" << maxDist);
    for (int i = 0; i < d; i++) {
      itmp1.set_f(evaluator.solCoord[i]);
      solCoord[i].add(solCoord[i], itmp1);
    }
    result = RED_SUCCESS;
  }

  Float::setprec(oldprec);
  return result;
}

FPLLL_END_NAMESPACE
<|endoftext|>


<commit_before>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

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

Abaclade 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 General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/collections/map.hxx>

#if ABC_HOST_API_POSIX
   #include <errno.h> // EINTR errno
   #if ABC_HOST_API_DARWIN
      #define _XOPEN_SOURCE
   #endif
   #include <signal.h> // SIGSTKSZ
   #include <ucontext.h>
   #if ABC_HOST_API_BSD
      #include <sys/types.h>
      #include <sys/event.h>
      #include <sys/time.h>
   #elif ABC_HOST_API_LINUX
      #include <sys/epoll.h>
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::coroutine

namespace abc {

class coroutine::context : public noncopyable {
public:
   /*! Constructor

   @param fnMain
      Initial value for m_fnInnerMain.
   */
   context(std::function<void ()> fnMain) :
      m_fnInnerMain(std::move(fnMain)) {
   }

#if ABC_HOST_API_POSIX
   /*! Reinitializes the context for execution.

   @param puctxReturn
      Context to return to upon termination.
   */
   void reset(::ucontext_t * puctxReturn) {
      ABC_TRACE_FUNC(this, puctxReturn);

      if (::getcontext(&m_uctx) < 0) {
         exception::throw_os_error();
      }
      m_uctx.uc_stack.ss_sp = reinterpret_cast<char *>(&m_aiStack);
      m_uctx.uc_stack.ss_size = sizeof m_aiStack;
      m_uctx.uc_link = puctxReturn;
      ::makecontext(&m_uctx, reinterpret_cast<void (*)()>(&outer_main), 1, this);
   }
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   #error "TODO: HOST_API"
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else

#if ABC_HOST_API_POSIX
   /*! Returns a pointer to the internal ::ucontext_t.

   @return
      Pointer to the context’s ::ucontext_t member.
   */
   ::ucontext_t * ucontext_ptr() {
      return &m_uctx;
   }
#endif

private:
   /*! Lower-level wrapper for the coroutine function passed to coroutine::coroutine().

   @param p
      *this.
   */
   static void outer_main(void * p) {
      context * pctx = static_cast<context *>(p);
      try {
         pctx->m_fnInnerMain();
      } catch (std::exception const & x) {
         exception::write_with_scope_trace(nullptr, &x);
         // TODO: maybe support “moving” the exception to the return coroutine context?
      } catch (...) {
         exception::write_with_scope_trace();
         // TODO: maybe support “moving” the exception to the return coroutine context?
      }
   }

private:
#if ABC_HOST_API_POSIX
   //! Low-level context for the coroutine.
   ::ucontext_t m_uctx;
   //! Memory chunk used as stack.
   abc::max_align_t m_aiStack[ABC_ALIGNED_SIZE(SIGSTKSZ)];
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   #error "TODO: HOST_API"
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else
   //! Function to be executed in the coroutine.
   std::function<void ()> m_fnInnerMain;
};

coroutine::coroutine() {
}
/*explicit*/ coroutine::coroutine(std::function<void ()> fnMain) :
   m_pctx(std::make_shared<coroutine::context>(std::move(fnMain))) {
}

coroutine::~coroutine() {
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::coroutine_scheduler

namespace abc {

#if ABC_HOST_API_POSIX

class coroutine_scheduler_impl : public coroutine_scheduler {
public:
   //! Constructor.
   coroutine_scheduler_impl() :
#if ABC_HOST_API_BSD
      m_fdKqueue(::kqueue()) {
      ABC_TRACE_FUNC(this);

      if (!m_fdKqueue) {
         exception::throw_os_error();
      }
      // TODO: set close-on-exec. ::kqueue1() may be available on some systems; investigate that.
#elif ABC_HOST_API_LINUX
      m_fdEpoll(::epoll_create1(EPOLL_CLOEXEC)) {
      ABC_TRACE_FUNC(this);

      if (!m_fdEpoll) {
         exception::throw_os_error();
      }
#else
   #error "TODO: HOST_API"
#endif
   }

   //! Destructor.
   virtual ~coroutine_scheduler_impl() {
      // TODO: verify that m_listStartingCoros and m_mapBlockedCoros are empty.
   }

   //! See coroutine_scheduler::run().
   virtual void run() override {
      ABC_TRACE_FUNC(this);

      while ((m_pcoroctxActive = find_coroutine_to_activate())) {
         if (::swapcontext(&m_uctxReturn, m_pcoroctxActive->ucontext_ptr()) < 0) {
            /* TODO: in case of errors, which should never happen here since all coroutines have the
            same stack size, inject a stack overflow exception in *m_pcoroctxActive. */
         }
      }
      // Release the last coroutine.
      m_pcoroctxActive.reset();
   }

   //! See coroutine_scheduler::yield_while_async_pending().
   virtual void yield_while_async_pending(io::filedesc const & fd, bool bWrite) override {
      ABC_TRACE_FUNC(this, /*fd, */bWrite);

      // Add fd as a new event source.
#if ABC_HOST_API_BSD
      struct ::kevent ke;
      ke.ident = static_cast<std::uintptr_t>(fd.get());
      // Use EV_ONESHOT to avoid waking up multiple threads for the same fd becoming ready.
      ke.flags = EV_ADD | EV_ONESHOT | EV_EOF ;
      ke.filter = bWrite ? EVFILT_WRITE : EVFILT_READ;
      if (::kevent(m_fdKqueue.get(), &ke, 1, nullptr, 0, nullptr) < 0) {
         exception::throw_os_error();
      }
#elif ABC_HOST_API_LINUX
      ::epoll_event ee;
      ee.data.fd = fd.get();
      /* Use EPOLLONESHOT to avoid waking up multiple threads for the same fd becoming ready. This
      means we’d need to then rearm it in find_coroutine_to_activate() when it becomes ready, but
      we’ll remove it instead. */
      ee.events = EPOLLONESHOT | EPOLLPRI | (bWrite ? EPOLLOUT : EPOLLIN);
      if (::epoll_ctl(m_fdEpoll.get(), EPOLL_CTL_ADD, fd.get(), &ee) < 0) {
         exception::throw_os_error();
      }
#else
   #error "TODO: HOST_API"
#endif
      // Deactivate the current coroutine and find one to activate instead.
      coroutine::context * pcoroctxActive = m_pcoroctxActive.get();
      auto itBlockedCoro(
         m_mapBlockedCoros.add_or_assign(fd.get(), std::move(m_pcoroctxActive)).first
      );
      try {
         m_pcoroctxActive = find_coroutine_to_activate();
      } catch (...) {
         // If anything went wrong, restore the coroutine that was active.
         m_pcoroctxActive = m_mapBlockedCoros.extract(itBlockedCoro);
         throw;
      }
      /* If the context changed, i.e. the coroutine that’s ready to run is not the one that was
      active, switch to it. */
      if (m_pcoroctxActive.get() != pcoroctxActive) {
         if (::swapcontext(pcoroctxActive->ucontext_ptr(), m_pcoroctxActive->ucontext_ptr()) < 0) {
            /* TODO: in case of errors, which should never happen here since all coroutines have the
            same stack size, inject a stack overflow exception in *m_pcoroctxActive. */
         }
      }
   }

private:
   /*! Finds a coroutine ready to execute; if none are, but there are blocked coroutines, it blocks
   the current thread until one of them becomes ready.

   @return
      Pointer to the context of a coroutine that’s ready to execute.
   */
   std::shared_ptr<coroutine::context> find_coroutine_to_activate() {
      ABC_TRACE_FUNC(this);

      // This loop will only repeat in case of EINTR from the blocking-wait API.
      for (;;) {
         if (m_listStartingCoros) {
            // There are coroutines that haven’t had a chance to run; remove and schedule the first.
            auto pcoroctx(m_listStartingCoros.pop_front());
            /* TODO: verify how this behaves in a multithreaded scenario: which thread should this
            coroutine return to? */
            pcoroctx->reset(&m_uctxReturn);
            return std::move(pcoroctx);
         } else if (m_mapBlockedCoros) {
            // There are blocked coroutines; wait for the first one to become ready again.
#if ABC_HOST_API_BSD
            struct ::kevent ke;
            if (::kevent(m_fdKqueue.get(), nullptr, 0, &ke, 1, nullptr) < 0) {
#elif ABC_HOST_API_LINUX
            ::epoll_event ee;
            if (::epoll_wait(m_fdEpoll.get(), &ee, 1, -1) < 0) {
#else
   #error "TODO: HOST_API"
#endif
               int iErr = errno;
               if (iErr == EINTR) {
                  continue;
               }
               exception::throw_os_error(iErr);
            }
            io::filedesc_t fd;
#if ABC_HOST_API_BSD
            fd = static_cast<int>(ke.ident);
#elif ABC_HOST_API_LINUX
            fd = ee.data.fd;
            // Remove fd from the epoll. Ignore errors since we wouldn’t know what to do aobut them.
            ::epoll_ctl(m_fdEpoll.get(), EPOLL_CTL_DEL, fd, nullptr);
#endif
            // Remove from m_mapBlockedCoros and return the coroutine that was waiting for fd.
            return m_mapBlockedCoros.extract(fd);
         } else {
            return nullptr;
         }
      }
   }

private:
#if ABC_HOST_API_BSD
   //! File descriptor of the internal kqueue.
   io::filedesc m_fdKqueue;
#elif ABC_HOST_API_LINUX
   //! File descriptor of the internal epoll.
   io::filedesc m_fdEpoll;
#else
   #error "TODO: HOST_API"
#endif
   //! Coroutines that are blocked on a fd wait.
   collections::map<io::filedesc_t, std::shared_ptr<coroutine::context>> m_mapBlockedCoros;
   //! Coroutine context that every coroutine eventually returns to.
   ::ucontext_t m_uctxReturn;
};

#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   #error "TODO: HOST_API"
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else

thread_local_value<std::shared_ptr<coroutine_scheduler>> coroutine_scheduler::sm_pcorosched;

coroutine_scheduler::coroutine_scheduler() :
   m_pcoroctxActive(nullptr) {
}

coroutine_scheduler::~coroutine_scheduler() {
}

void coroutine_scheduler::add_coroutine(coroutine const & coro) {
   ABC_TRACE_FUNC(this);

   // Add the coroutine to those ready to start.
   m_listStartingCoros.push_back(coro.m_pctx);
}

/*static*/ coroutine_scheduler & coroutine_scheduler::attach_to_current_thread(
   std::shared_ptr<coroutine_scheduler> pcorosched /*= nullptr*/
) {
   ABC_TRACE_FUNC(pcorosched);

   if (sm_pcorosched.operator std::shared_ptr<coroutine_scheduler> const &()) {
      // The current thread already has a coroutine scheduler.
      // TODO: use a better exception class.
      ABC_THROW(generic_error, ());
   }
   if (!pcorosched) {
      pcorosched = std::make_shared<coroutine_scheduler_impl>();
   }
   return *(
      sm_pcorosched = std::move(pcorosched)
   ).operator std::shared_ptr<coroutine_scheduler> const &();
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<commit_msg>Minor fix<commit_after>/* -*- coding: utf-8; mode: c++; tab-width: 3; indent-tabs-mode: nil -*-

Copyright 2015
Raffaello D. Di Napoli

This file is part of Abaclade.

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

Abaclade 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 General
Public License for more details.

You should have received a copy of the GNU General Public License along with Abaclade. If not, see
<http://www.gnu.org/licenses/>.
--------------------------------------------------------------------------------------------------*/

#include <abaclade.hxx>
#include <abaclade/coroutine.hxx>
#include <abaclade/collections/map.hxx>

#if ABC_HOST_API_POSIX
   #if ABC_HOST_API_DARWIN
      #define _XOPEN_SOURCE
   #endif
   #include <errno.h> // EINTR errno
   #include <signal.h> // SIGSTKSZ
   #include <ucontext.h>
   #if ABC_HOST_API_BSD
      #include <sys/types.h>
      #include <sys/event.h>
      #include <sys/time.h>
   #elif ABC_HOST_API_LINUX
      #include <sys/epoll.h>
   #endif
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::coroutine

namespace abc {

class coroutine::context : public noncopyable {
public:
   /*! Constructor

   @param fnMain
      Initial value for m_fnInnerMain.
   */
   context(std::function<void ()> fnMain) :
      m_fnInnerMain(std::move(fnMain)) {
   }

#if ABC_HOST_API_POSIX
   /*! Reinitializes the context for execution.

   @param puctxReturn
      Context to return to upon termination.
   */
   void reset(::ucontext_t * puctxReturn) {
      ABC_TRACE_FUNC(this, puctxReturn);

      if (::getcontext(&m_uctx) < 0) {
         exception::throw_os_error();
      }
      m_uctx.uc_stack.ss_sp = reinterpret_cast<char *>(&m_aiStack);
      m_uctx.uc_stack.ss_size = sizeof m_aiStack;
      m_uctx.uc_link = puctxReturn;
      ::makecontext(&m_uctx, reinterpret_cast<void (*)()>(&outer_main), 1, this);
   }
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   #error "TODO: HOST_API"
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else

#if ABC_HOST_API_POSIX
   /*! Returns a pointer to the internal ::ucontext_t.

   @return
      Pointer to the context’s ::ucontext_t member.
   */
   ::ucontext_t * ucontext_ptr() {
      return &m_uctx;
   }
#endif

private:
   /*! Lower-level wrapper for the coroutine function passed to coroutine::coroutine().

   @param p
      *this.
   */
   static void outer_main(void * p) {
      context * pctx = static_cast<context *>(p);
      try {
         pctx->m_fnInnerMain();
      } catch (std::exception const & x) {
         exception::write_with_scope_trace(nullptr, &x);
         // TODO: maybe support “moving” the exception to the return coroutine context?
      } catch (...) {
         exception::write_with_scope_trace();
         // TODO: maybe support “moving” the exception to the return coroutine context?
      }
   }

private:
#if ABC_HOST_API_POSIX
   //! Low-level context for the coroutine.
   ::ucontext_t m_uctx;
   //! Memory chunk used as stack.
   abc::max_align_t m_aiStack[ABC_ALIGNED_SIZE(SIGSTKSZ)];
#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   #error "TODO: HOST_API"
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else
   //! Function to be executed in the coroutine.
   std::function<void ()> m_fnInnerMain;
};

coroutine::coroutine() {
}
/*explicit*/ coroutine::coroutine(std::function<void ()> fnMain) :
   m_pctx(std::make_shared<coroutine::context>(std::move(fnMain))) {
}

coroutine::~coroutine() {
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
// abc::coroutine_scheduler

namespace abc {

#if ABC_HOST_API_POSIX

class coroutine_scheduler_impl : public coroutine_scheduler {
public:
   //! Constructor.
   coroutine_scheduler_impl() :
#if ABC_HOST_API_BSD
      m_fdKqueue(::kqueue()) {
      ABC_TRACE_FUNC(this);

      if (!m_fdKqueue) {
         exception::throw_os_error();
      }
      // TODO: set close-on-exec. ::kqueue1() may be available on some systems; investigate that.
#elif ABC_HOST_API_LINUX
      m_fdEpoll(::epoll_create1(EPOLL_CLOEXEC)) {
      ABC_TRACE_FUNC(this);

      if (!m_fdEpoll) {
         exception::throw_os_error();
      }
#else
   #error "TODO: HOST_API"
#endif
   }

   //! Destructor.
   virtual ~coroutine_scheduler_impl() {
      // TODO: verify that m_listStartingCoros and m_mapBlockedCoros are empty.
   }

   //! See coroutine_scheduler::run().
   virtual void run() override {
      ABC_TRACE_FUNC(this);

      while ((m_pcoroctxActive = find_coroutine_to_activate())) {
         if (::swapcontext(&m_uctxReturn, m_pcoroctxActive->ucontext_ptr()) < 0) {
            /* TODO: in case of errors, which should never happen here since all coroutines have the
            same stack size, inject a stack overflow exception in *m_pcoroctxActive. */
         }
      }
      // Release the last coroutine.
      m_pcoroctxActive.reset();
   }

   //! See coroutine_scheduler::yield_while_async_pending().
   virtual void yield_while_async_pending(io::filedesc const & fd, bool bWrite) override {
      ABC_TRACE_FUNC(this, /*fd, */bWrite);

      // Add fd as a new event source.
#if ABC_HOST_API_BSD
      struct ::kevent ke;
      ke.ident = static_cast<std::uintptr_t>(fd.get());
      // Use EV_ONESHOT to avoid waking up multiple threads for the same fd becoming ready.
      ke.flags = EV_ADD | EV_ONESHOT | EV_EOF ;
      ke.filter = bWrite ? EVFILT_WRITE : EVFILT_READ;
      if (::kevent(m_fdKqueue.get(), &ke, 1, nullptr, 0, nullptr) < 0) {
         exception::throw_os_error();
      }
#elif ABC_HOST_API_LINUX
      ::epoll_event ee;
      ee.data.fd = fd.get();
      /* Use EPOLLONESHOT to avoid waking up multiple threads for the same fd becoming ready. This
      means we’d need to then rearm it in find_coroutine_to_activate() when it becomes ready, but
      we’ll remove it instead. */
      ee.events = EPOLLONESHOT | EPOLLPRI | (bWrite ? EPOLLOUT : EPOLLIN);
      if (::epoll_ctl(m_fdEpoll.get(), EPOLL_CTL_ADD, fd.get(), &ee) < 0) {
         exception::throw_os_error();
      }
#else
   #error "TODO: HOST_API"
#endif
      // Deactivate the current coroutine and find one to activate instead.
      coroutine::context * pcoroctxActive = m_pcoroctxActive.get();
      auto itBlockedCoro(
         m_mapBlockedCoros.add_or_assign(fd.get(), std::move(m_pcoroctxActive)).first
      );
      try {
         m_pcoroctxActive = find_coroutine_to_activate();
      } catch (...) {
         // If anything went wrong, restore the coroutine that was active.
         m_pcoroctxActive = m_mapBlockedCoros.extract(itBlockedCoro);
         throw;
      }
      /* If the context changed, i.e. the coroutine that’s ready to run is not the one that was
      active, switch to it. */
      if (m_pcoroctxActive.get() != pcoroctxActive) {
         if (::swapcontext(pcoroctxActive->ucontext_ptr(), m_pcoroctxActive->ucontext_ptr()) < 0) {
            /* TODO: in case of errors, which should never happen here since all coroutines have the
            same stack size, inject a stack overflow exception in *m_pcoroctxActive. */
         }
      }
   }

private:
   /*! Finds a coroutine ready to execute; if none are, but there are blocked coroutines, it blocks
   the current thread until one of them becomes ready.

   @return
      Pointer to the context of a coroutine that’s ready to execute.
   */
   std::shared_ptr<coroutine::context> find_coroutine_to_activate() {
      ABC_TRACE_FUNC(this);

      // This loop will only repeat in case of EINTR from the blocking-wait API.
      for (;;) {
         if (m_listStartingCoros) {
            // There are coroutines that haven’t had a chance to run; remove and schedule the first.
            auto pcoroctx(m_listStartingCoros.pop_front());
            /* TODO: verify how this behaves in a multithreaded scenario: which thread should this
            coroutine return to? */
            pcoroctx->reset(&m_uctxReturn);
            return std::move(pcoroctx);
         } else if (m_mapBlockedCoros) {
            // There are blocked coroutines; wait for the first one to become ready again.
#if ABC_HOST_API_BSD
            struct ::kevent ke;
            if (::kevent(m_fdKqueue.get(), nullptr, 0, &ke, 1, nullptr) < 0) {
#elif ABC_HOST_API_LINUX
            ::epoll_event ee;
            if (::epoll_wait(m_fdEpoll.get(), &ee, 1, -1) < 0) {
#else
   #error "TODO: HOST_API"
#endif
               int iErr = errno;
               if (iErr == EINTR) {
                  continue;
               }
               exception::throw_os_error(iErr);
            }
            io::filedesc_t fd;
#if ABC_HOST_API_BSD
            fd = static_cast<int>(ke.ident);
#elif ABC_HOST_API_LINUX
            fd = ee.data.fd;
            // Remove fd from the epoll. Ignore errors since we wouldn’t know what to do aobut them.
            ::epoll_ctl(m_fdEpoll.get(), EPOLL_CTL_DEL, fd, nullptr);
#endif
            // Remove from m_mapBlockedCoros and return the coroutine that was waiting for fd.
            return m_mapBlockedCoros.extract(fd);
         } else {
            return nullptr;
         }
      }
   }

private:
#if ABC_HOST_API_BSD
   //! File descriptor of the internal kqueue.
   io::filedesc m_fdKqueue;
#elif ABC_HOST_API_LINUX
   //! File descriptor of the internal epoll.
   io::filedesc m_fdEpoll;
#else
   #error "TODO: HOST_API"
#endif
   //! Coroutines that are blocked on a fd wait.
   collections::map<io::filedesc_t, std::shared_ptr<coroutine::context>> m_mapBlockedCoros;
   //! Coroutine context that every coroutine eventually returns to.
   ::ucontext_t m_uctxReturn;
};

#elif ABC_HOST_API_WIN32 //if ABC_HOST_API_POSIX
   #error "TODO: HOST_API"
#else //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32
   #error "TODO: HOST_API"
#endif //if ABC_HOST_API_POSIX … elif ABC_HOST_API_WIN32 … else

thread_local_value<std::shared_ptr<coroutine_scheduler>> coroutine_scheduler::sm_pcorosched;

coroutine_scheduler::coroutine_scheduler() :
   m_pcoroctxActive(nullptr) {
}

coroutine_scheduler::~coroutine_scheduler() {
}

void coroutine_scheduler::add_coroutine(coroutine const & coro) {
   ABC_TRACE_FUNC(this);

   // Add the coroutine to those ready to start.
   m_listStartingCoros.push_back(coro.m_pctx);
}

/*static*/ coroutine_scheduler & coroutine_scheduler::attach_to_current_thread(
   std::shared_ptr<coroutine_scheduler> pcorosched /*= nullptr*/
) {
   ABC_TRACE_FUNC(pcorosched);

   if (sm_pcorosched.operator std::shared_ptr<coroutine_scheduler> const &()) {
      // The current thread already has a coroutine scheduler.
      // TODO: use a better exception class.
      ABC_THROW(generic_error, ());
   }
   if (!pcorosched) {
      pcorosched = std::make_shared<coroutine_scheduler_impl>();
   }
   return *(
      sm_pcorosched = std::move(pcorosched)
   ).operator std::shared_ptr<coroutine_scheduler> const &();
}

} //namespace abc

////////////////////////////////////////////////////////////////////////////////////////////////////
<|endoftext|>


<commit_before>#include <iostream>
#include <sstream>
#include <vector>
#include <map>
#include <vector>
#include <ostream>
#include <string>
#include "ast.h"
#include "generator.h"
#include "ecc.tab.h"

extern int _yylex(void);

#define YY_NULL (0)

namespace ecc
{
    extern const std::string version = "ecc v0.0alpha"; /**< Version string */
    ast::elist_t MasterList;				/**< Parser places output here */
    ast::enumdef* CurrentEnumDef;			/**< Used during parsing */
}

namespace
{
    /** Holds a pointer to the current input stream, for ecc::input to access */
    std::istream* pStream;

    /** String to print in the event that the command line is malformed */
    const std::string StrMalformed = "Usage: ecc -c <infile> [-o <outfile>]";

}

namespace ecc
{
    /** Provides stream input functionality to the lexer. */
    void input(char* buf, int& result, size_t max_size)
    {
 	if (pStream->peek()==EOF)
 	    result = YY_NULL;
 	else
	{
	    pStream->read(buf,max_size);
	    result = pStream->gcount();
 	}

    }

    typedef enum
    {
	EcOk=0,
	EcBadParams=1
    } exitstatus_t;

}

/**
 * Included for future use
 */
int yylex(void) { return _yylex(); }

/** Parses input options */
static ecc::exitstatus_t parse_options(int argc, char** argv)
{
    // Skip over executable name
    argc--; argv++;

    // Check minimum params
    if (argc<2)
	goto malformed;

    // Loop over param pairs
    while (argc)
    {
	const std::string option(*argv);
	argc--; argv++;
    }

    return ecc::EcOk;

malformed:
    std::cerr << StrMalformed << std::endl;
    return ecc::EcBadParams;
}

/**
 * Main execution loop of the ecc utility
 */
int main(int argc, char** argv)
{
    ecc::exitstatus_t exit_code=ecc::EcOk;

    // Parse the command line parameters
    if (ecc::EcOk!=(exit_code = parse_options(argc,argv)))
	exit(exit_code);

    // Set up example input
    std::stringstream ss;

    ss << "typedef enum { frog=9, tree, banana = 7 } enum_t;"
       << "typedef enum { willow } other_t;";

    // Tell the scanner where to get its input
    pStream = &ss;

    // Parse the stream
    yyparse();

    // Generate the output (defaults to std::cout)
    ecc::generator* pGen = new ecc::defgen();
    pGen->translate( ecc::MasterList );
    delete pGen;

    exit(ecc::EcOk);
}
<commit_msg>Read input from specified file<commit_after>#include <iostream>
#include <fstream>
#include <sstream>
#include <vector>
#include <map>
#include <vector>
#include <ostream>
#include <string>
#include "ast.h"
#include "generator.h"
#include "ecc.tab.h"

extern int _yylex(void);

#define YY_NULL (0)

namespace ecc
{
    extern const std::string version = "ecc v0.0alpha"; /**< Version string */
    ast::elist_t MasterList;				/**< Parser places output here */
    ast::enumdef* CurrentEnumDef;			/**< Used during parsing */
}

namespace
{
    /** Holds a pointer to the current input stream, for ecc::input to access */
    std::istream* pStream;

    /** String to print in the event that the command line is malformed */
    const std::string StrMalformed = "Usage: ecc -c <infile> [-o <outfile>]";
    const std::string StrFilespec = "Input cannot be the same file as the output";

    /** Name of the input file */
    std::string inputFile="";

    /** Name of the output file */
    std::string outputFile="";

}

namespace ecc
{
    /** Provides stream input functionality to the lexer. */
    void input(char* buf, int& result, size_t max_size)
    {
 	if (pStream->peek()==EOF)
 	    result = YY_NULL;
 	else
	{
	    pStream->read(buf,max_size);
	    result = pStream->gcount();
 	}

    }

    typedef enum
    {
	EcOk=0,
	EcBadParams=1
    } exitstatus_t;

}

/**
 * Included for future use
 */
int yylex(void) { return _yylex(); }

/** Parses input options */
static ecc::exitstatus_t parse_options(int argc, char** argv)
{
    // Skip over executable name
    argc--; argv++;

    // Check minimum params
    if (argc<2)
	goto malformed;

    // Loop over param pairs
    while (argc)
    {
	const std::string option(*argv); argc--; argv++;

	if ( (!argc) || (option[0]!='-') ) goto malformed;

	const std::string param(*argv); argc--; argv++;

	switch (option[1])
	{
	case 'c':
	    inputFile = param;
	    break;

	case 'o':
	    outputFile = param;
	    break;

	default:
	    goto malformed;
	}

    }

    // Check that we got mandatory options
    if ( inputFile.length() < 1 )
	goto malformed;

    // If no output file was set, calculate name from input file
    if ( outputFile.length() < 1 )
    {
	size_t index_ext = inputFile.rfind('.');
	size_t index_leaf = inputFile.rfind('/');

	if ( (index_ext == std::string::npos)
	     || ( index_leaf!=std::string::npos && (index_leaf > index_ext) ) )
	{
	    // There's no file extension, simply add one
	    outputFile = inputFile + ".c";
	}
	else
	{
	    // There is a file extension
	    outputFile = inputFile.substr(0,index_ext) + ".c";
	}
    }

    // Check that the input and output files are different
    if ( inputFile==outputFile) goto filespec;

    // All good
    return ecc::EcOk;

malformed:
    std::cerr << StrMalformed << std::endl;
    return ecc::EcBadParams;

filespec:
    std::cerr << StrFilespec << std::endl;
    return ecc::EcBadParams;

}

/**
 * Main execution loop of the ecc utility
 */
int main(int argc, char** argv)
{
    ecc::exitstatus_t exit_code=ecc::EcOk;

    // Parse the command line parameters
    if (ecc::EcOk!=(exit_code = parse_options(argc,argv)))
	exit(exit_code);

    // Set up example input
    std::stringstream ss;

    ss << "typedef enum { frog=9, tree, banana = 7 } enum_t;"
       << "typedef enum { willow } other_t;";

    // Tell the scanner where to get its input
    std::ifstream fs(inputFile);
    pStream = &fs;

    // Parse the stream
    yyparse();

    fs.close();

    // Generate the output (defaults to std::cout)
    ecc::generator* pGen = new ecc::defgen();
    pGen->translate( ecc::MasterList );
    delete pGen;

    exit(ecc::EcOk);
}
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2017 The Android Open Source 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 "cpu_reader.h"

#include <utility>

#include "perfetto/base/logging.h"
#include "perfetto/base/utils.h"
#include "proto_translation_table.h"

#include "perfetto/trace/ftrace/ftrace_event.pbzero.h"
#include "perfetto/trace/ftrace/print.pbzero.h"
#include "perfetto/trace/ftrace/sched_switch.pbzero.h"

#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"

namespace perfetto {

namespace {

bool ReadIntoString(const uint8_t* start,
                    const uint8_t* end,
                    size_t field_id,
                    protozero::ProtoZeroMessage* out) {
  for (const uint8_t* c = start; c < end; c++) {
    if (*c != '\0')
      continue;
    out->AppendBytes(field_id, reinterpret_cast<const char*>(start), c - start);
    return true;
  }
  return false;
}

using BundleHandle =
    protozero::ProtoZeroMessageHandle<protos::pbzero::FtraceEventBundle>;

const std::vector<bool> BuildEnabledVector(const ProtoTranslationTable& table,
                                           const std::set<std::string>& names) {
  std::vector<bool> enabled(table.largest_id() + 1);
  for (const std::string& name : names) {
    const Event* event = table.GetEventByName(name);
    if (!event)
      continue;
    enabled[event->ftrace_event_id] = true;
  }
  return enabled;
}

// For further documentation of these constants see the kernel source:
// linux/include/linux/ring_buffer.h
// Some information about the values of these constants are exposed to user
// space at: /sys/kernel/debug/tracing/events/header_event
const uint32_t kTypeDataTypeLengthMax = 28;
const uint32_t kTypePadding = 29;
const uint32_t kTypeTimeExtend = 30;
const uint32_t kTypeTimeStamp = 31;

struct PageHeader {
  uint64_t timestamp;
  uint32_t size;
  uint32_t : 24;
  uint32_t overwrite : 8;
};

struct EventHeader {
  uint32_t type_or_length : 5;
  uint32_t time_delta : 27;
};

struct TimeStamp {
  uint64_t tv_nsec;
  uint64_t tv_sec;
};

}  // namespace

EventFilter::EventFilter(const ProtoTranslationTable& table,
                         std::set<std::string> names)
    : enabled_ids_(BuildEnabledVector(table, names)),
      enabled_names_(std::move(names)) {}
EventFilter::~EventFilter() = default;

CpuReader::CpuReader(const ProtoTranslationTable* table,
                     size_t cpu,
                     base::ScopedFile fd)
    : table_(table), cpu_(cpu), fd_(std::move(fd)) {}

int CpuReader::GetFileDescriptor() {
  return fd_.get();
}

bool CpuReader::Drain(const std::array<const EventFilter*, kMaxSinks>& filters,
                      const std::array<BundleHandle, kMaxSinks>& bundles) {
  if (!fd_)
    return false;

  uint8_t* buffer = GetBuffer();
  // TOOD(hjd): One read() per page may be too many.
  long bytes = PERFETTO_EINTR(read(fd_.get(), buffer, base::kPageSize));
  if (bytes == -1 && errno == EAGAIN)
    return false;
  if (bytes != base::kPageSize)
    return false;
  PERFETTO_CHECK(static_cast<size_t>(bytes) <= base::kPageSize);

  size_t evt_size = 0;
  for (size_t i = 0; i < kMaxSinks; i++) {
    if (!filters[i])
      break;
    evt_size = ParsePage(cpu_, buffer, filters[i], &*bundles[i], table_);
    PERFETTO_DCHECK(evt_size);
  }

  // TODO(hjd): Introduce enum to distinguish real failures.
  return evt_size > (base::kPageSize / 2);
}

CpuReader::~CpuReader() = default;

uint8_t* CpuReader::GetBuffer() {
  // TODO(primiano): Guard against overflows, like BufferedFrameDeserializer.
  if (!buffer_)
    buffer_ = std::unique_ptr<uint8_t[]>(new uint8_t[base::kPageSize]);
  return buffer_.get();
}

// The structure of a raw trace buffer page is as follows:
// First a page header:
//   8 bytes of timestamp
//   8 bytes of page length TODO(hjd): other fields also defined here?
// // TODO(hjd): Document rest of format.
// Some information about the layout of the page header is available in user
// space at: /sys/kernel/debug/tracing/events/header_event
// This method is deliberately static so it can be tested independently.
size_t CpuReader::ParsePage(size_t cpu,
                            const uint8_t* ptr,
                            const EventFilter* filter,
                            protos::pbzero::FtraceEventBundle* bundle,
                            const ProtoTranslationTable* table) {
  const uint8_t* const start_of_page = ptr;
  const uint8_t* const end_of_page = ptr + base::kPageSize;

  bundle->set_cpu(cpu);

  // TODO(hjd): Read this format dynamically?
  PageHeader page_header;
  if (!ReadAndAdvance(&ptr, end_of_page, &page_header))
    return 0;

  // TODO(hjd): There is something wrong with the page header struct.
  page_header.size = page_header.size & 0xfffful;

  const uint8_t* const end = ptr + page_header.size;
  if (end > end_of_page)
    return 0;

  uint64_t timestamp = page_header.timestamp;

  while (ptr < end) {
    EventHeader event_header;
    if (!ReadAndAdvance(&ptr, end, &event_header))
      return 0;

    timestamp += event_header.time_delta;

    switch (event_header.type_or_length) {
      case kTypePadding: {
        // Left over page padding or discarded event.
        if (event_header.time_delta == 0) {
          // TODO(hjd): Look at the next few bytes for read size;
          PERFETTO_CHECK(false);  // TODO(hjd): Handle
        }
        uint32_t length;
        if (!ReadAndAdvance<uint32_t>(&ptr, end, &length))
          return 0;
        ptr += length;
        break;
      }
      case kTypeTimeExtend: {
        // Extend the time delta.
        uint32_t time_delta_ext;
        if (!ReadAndAdvance<uint32_t>(&ptr, end, &time_delta_ext))
          return 0;
        // See https://goo.gl/CFBu5x
        timestamp += (static_cast<uint64_t>(time_delta_ext)) << 27;
        break;
      }
      case kTypeTimeStamp: {
        // Sync time stamp with external clock.
        TimeStamp time_stamp;
        if (!ReadAndAdvance<TimeStamp>(&ptr, end, &time_stamp))
          return 0;
        // TODO(hjd): Handle.
        break;
      }
      // Data record:
      default: {
        PERFETTO_CHECK(event_header.type_or_length <= kTypeDataTypeLengthMax);
        // type_or_length is <=28 so it represents the length of a data record.
        if (event_header.type_or_length == 0) {
          // TODO(hjd): Look at the next few bytes for real size.
          PERFETTO_CHECK(false);
        }
        const uint8_t* start = ptr;
        const uint8_t* next = ptr + 4 * event_header.type_or_length;

        uint16_t ftrace_event_id;
        if (!ReadAndAdvance<uint16_t>(&ptr, end, &ftrace_event_id))
          return 0;
        if (filter->IsEventEnabled(ftrace_event_id)) {
          protos::pbzero::FtraceEvent* event = bundle->add_event();
          event->set_timestamp(timestamp);
          if (!ParseEvent(ftrace_event_id, start, next, table, event))
            return 0;
        }

        // Jump to next event.
        ptr = next;
      }
    }
  }
  return static_cast<size_t>(ptr - start_of_page);
}

// |start| is the start of the current event.
// |end| is the end of the buffer.
bool CpuReader::ParseEvent(uint16_t ftrace_event_id,
                           const uint8_t* start,
                           const uint8_t* end,
                           const ProtoTranslationTable* table,
                           protozero::ProtoZeroMessage* message) {
  PERFETTO_DCHECK(start < end);
  const size_t length = end - start;

  // TODO(hjd): Rework to work even if the event is unknown.
  const Event& info = *table->GetEventById(ftrace_event_id);

  // TODO(hjd): Test truncated events.
  // If the end of the buffer is before the end of the event give up.
  if (info.size > length) {
    PERFETTO_DCHECK(false);
    return false;
  }

  bool success = true;
  for (const Field& field : table->common_fields())
    success &= ParseField(field, start, end, message);

  protozero::ProtoZeroMessage* nested =
      message->BeginNestedMessage<protozero::ProtoZeroMessage>(
          info.proto_field_id);

  for (const Field& field : info.fields)
    success &= ParseField(field, start, end, nested);

  // This finalizes |nested| automatically.
  message->Finalize();
  return success;
}

// Caller must guarantee that the field fits in the range,
// explicitly: start + field.ftrace_offset + field.ftrace_size <= end
// The only exception is fields with strategy = kCStringToString
// where the total size isn't known up front. In this case ParseField
// will check the string terminates in the bounds and won't read past |end|.
bool CpuReader::ParseField(const Field& field,
                           const uint8_t* start,
                           const uint8_t* end,
                           protozero::ProtoZeroMessage* message) {
  PERFETTO_DCHECK(start + field.ftrace_offset + field.ftrace_size <= end);
  const uint8_t* field_start = start + field.ftrace_offset;
  uint32_t field_id = field.proto_field_id;

  switch (field.strategy) {
    case kUint8ToUint32:
    case kUint16ToUint32:
    case kUint32ToUint32:
    case kUint32ToUint64:
      ReadIntoVarInt<uint32_t>(field_start, field_id, message);
      return true;
    case kUint64ToUint64:
      ReadIntoVarInt<uint64_t>(field_start, field_id, message);
      return true;
    case kInt16ToInt32:
    case kInt32ToInt32:
    case kInt32ToInt64:
      ReadIntoVarInt<int32_t>(field_start, field_id, message);
      return true;
    case kInt64ToInt64:
      ReadIntoVarInt<int64_t>(field_start, field_id, message);
      return true;
    case kFixedCStringToString:
      // TODO(hjd): Add AppendMaxLength string to protozero.
      return ReadIntoString(field_start, field_start + field.ftrace_size,
                            field_id, message);
    case kCStringToString:
      // TODO(hjd): Kernel-dive to check this how size:0 char fields work.
      return ReadIntoString(field_start, end, field.proto_field_id, message);
    case kStringPtrToString:
      // TODO(hjd): Figure out how to read these.
      return true;
    case kBoolToUint32:
      ReadIntoVarInt<uint32_t>(field_start, field_id, message);
      return true;
  }
  // Not reached, for gcc.
  PERFETTO_CHECK(false);
  return false;
}

}  // namespace perfetto
<commit_msg>ftrace_reader: Turn check to dcheck in cpu reader am: 7c73ec35bb<commit_after>/*
 * Copyright (C) 2017 The Android Open Source 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 "cpu_reader.h"

#include <utility>

#include "perfetto/base/logging.h"
#include "perfetto/base/utils.h"
#include "proto_translation_table.h"

#include "perfetto/trace/ftrace/ftrace_event.pbzero.h"
#include "perfetto/trace/ftrace/print.pbzero.h"
#include "perfetto/trace/ftrace/sched_switch.pbzero.h"

#include "perfetto/trace/ftrace/ftrace_event_bundle.pbzero.h"

namespace perfetto {

namespace {

bool ReadIntoString(const uint8_t* start,
                    const uint8_t* end,
                    size_t field_id,
                    protozero::ProtoZeroMessage* out) {
  for (const uint8_t* c = start; c < end; c++) {
    if (*c != '\0')
      continue;
    out->AppendBytes(field_id, reinterpret_cast<const char*>(start), c - start);
    return true;
  }
  return false;
}

using BundleHandle =
    protozero::ProtoZeroMessageHandle<protos::pbzero::FtraceEventBundle>;

const std::vector<bool> BuildEnabledVector(const ProtoTranslationTable& table,
                                           const std::set<std::string>& names) {
  std::vector<bool> enabled(table.largest_id() + 1);
  for (const std::string& name : names) {
    const Event* event = table.GetEventByName(name);
    if (!event)
      continue;
    enabled[event->ftrace_event_id] = true;
  }
  return enabled;
}

// For further documentation of these constants see the kernel source:
// linux/include/linux/ring_buffer.h
// Some information about the values of these constants are exposed to user
// space at: /sys/kernel/debug/tracing/events/header_event
const uint32_t kTypeDataTypeLengthMax = 28;
const uint32_t kTypePadding = 29;
const uint32_t kTypeTimeExtend = 30;
const uint32_t kTypeTimeStamp = 31;

struct PageHeader {
  uint64_t timestamp;
  uint32_t size;
  uint32_t : 24;
  uint32_t overwrite : 8;
};

struct EventHeader {
  uint32_t type_or_length : 5;
  uint32_t time_delta : 27;
};

struct TimeStamp {
  uint64_t tv_nsec;
  uint64_t tv_sec;
};

}  // namespace

EventFilter::EventFilter(const ProtoTranslationTable& table,
                         std::set<std::string> names)
    : enabled_ids_(BuildEnabledVector(table, names)),
      enabled_names_(std::move(names)) {}
EventFilter::~EventFilter() = default;

CpuReader::CpuReader(const ProtoTranslationTable* table,
                     size_t cpu,
                     base::ScopedFile fd)
    : table_(table), cpu_(cpu), fd_(std::move(fd)) {}

int CpuReader::GetFileDescriptor() {
  return fd_.get();
}

bool CpuReader::Drain(const std::array<const EventFilter*, kMaxSinks>& filters,
                      const std::array<BundleHandle, kMaxSinks>& bundles) {
  if (!fd_)
    return false;

  uint8_t* buffer = GetBuffer();
  // TOOD(hjd): One read() per page may be too many.
  long bytes = PERFETTO_EINTR(read(fd_.get(), buffer, base::kPageSize));
  if (bytes == -1 && errno == EAGAIN)
    return false;
  if (bytes != base::kPageSize)
    return false;
  PERFETTO_CHECK(static_cast<size_t>(bytes) <= base::kPageSize);

  size_t evt_size = 0;
  for (size_t i = 0; i < kMaxSinks; i++) {
    if (!filters[i])
      break;
    evt_size = ParsePage(cpu_, buffer, filters[i], &*bundles[i], table_);
    PERFETTO_DCHECK(evt_size);
  }

  // TODO(hjd): Introduce enum to distinguish real failures.
  return evt_size > (base::kPageSize / 2);
}

CpuReader::~CpuReader() = default;

uint8_t* CpuReader::GetBuffer() {
  // TODO(primiano): Guard against overflows, like BufferedFrameDeserializer.
  if (!buffer_)
    buffer_ = std::unique_ptr<uint8_t[]>(new uint8_t[base::kPageSize]);
  return buffer_.get();
}

// The structure of a raw trace buffer page is as follows:
// First a page header:
//   8 bytes of timestamp
//   8 bytes of page length TODO(hjd): other fields also defined here?
// // TODO(hjd): Document rest of format.
// Some information about the layout of the page header is available in user
// space at: /sys/kernel/debug/tracing/events/header_event
// This method is deliberately static so it can be tested independently.
size_t CpuReader::ParsePage(size_t cpu,
                            const uint8_t* ptr,
                            const EventFilter* filter,
                            protos::pbzero::FtraceEventBundle* bundle,
                            const ProtoTranslationTable* table) {
  const uint8_t* const start_of_page = ptr;
  const uint8_t* const end_of_page = ptr + base::kPageSize;

  bundle->set_cpu(cpu);

  // TODO(hjd): Read this format dynamically?
  PageHeader page_header;
  if (!ReadAndAdvance(&ptr, end_of_page, &page_header))
    return 0;

  // TODO(hjd): There is something wrong with the page header struct.
  page_header.size = page_header.size & 0xfffful;

  const uint8_t* const end = ptr + page_header.size;
  if (end > end_of_page)
    return 0;

  uint64_t timestamp = page_header.timestamp;

  while (ptr < end) {
    EventHeader event_header;
    if (!ReadAndAdvance(&ptr, end, &event_header))
      return 0;

    timestamp += event_header.time_delta;

    switch (event_header.type_or_length) {
      case kTypePadding: {
        // Left over page padding or discarded event.
        if (event_header.time_delta == 0) {
          // TODO(hjd): Look at the next few bytes for read size;
          PERFETTO_ELOG("Padding time_delta == 0 not handled.");
          PERFETTO_DCHECK(false);  // TODO(hjd): Handle
          return 0;
        }
        uint32_t length;
        if (!ReadAndAdvance<uint32_t>(&ptr, end, &length))
          return 0;
        ptr += length;
        break;
      }
      case kTypeTimeExtend: {
        // Extend the time delta.
        uint32_t time_delta_ext;
        if (!ReadAndAdvance<uint32_t>(&ptr, end, &time_delta_ext))
          return 0;
        // See https://goo.gl/CFBu5x
        timestamp += (static_cast<uint64_t>(time_delta_ext)) << 27;
        break;
      }
      case kTypeTimeStamp: {
        // Sync time stamp with external clock.
        TimeStamp time_stamp;
        if (!ReadAndAdvance<TimeStamp>(&ptr, end, &time_stamp))
          return 0;
        // TODO(hjd): Handle.
        break;
      }
      // Data record:
      default: {
        PERFETTO_CHECK(event_header.type_or_length <= kTypeDataTypeLengthMax);
        // type_or_length is <=28 so it represents the length of a data record.
        if (event_header.type_or_length == 0) {
          // TODO(hjd): Look at the next few bytes for real size.
          PERFETTO_ELOG("Data type_or_length == 0 not handled.");
          PERFETTO_DCHECK(false);
          return 0;
        }
        const uint8_t* start = ptr;
        const uint8_t* next = ptr + 4 * event_header.type_or_length;

        uint16_t ftrace_event_id;
        if (!ReadAndAdvance<uint16_t>(&ptr, end, &ftrace_event_id))
          return 0;
        if (filter->IsEventEnabled(ftrace_event_id)) {
          protos::pbzero::FtraceEvent* event = bundle->add_event();
          event->set_timestamp(timestamp);
          if (!ParseEvent(ftrace_event_id, start, next, table, event))
            return 0;
        }

        // Jump to next event.
        ptr = next;
      }
    }
  }
  return static_cast<size_t>(ptr - start_of_page);
}

// |start| is the start of the current event.
// |end| is the end of the buffer.
bool CpuReader::ParseEvent(uint16_t ftrace_event_id,
                           const uint8_t* start,
                           const uint8_t* end,
                           const ProtoTranslationTable* table,
                           protozero::ProtoZeroMessage* message) {
  PERFETTO_DCHECK(start < end);
  const size_t length = end - start;

  // TODO(hjd): Rework to work even if the event is unknown.
  const Event& info = *table->GetEventById(ftrace_event_id);

  // TODO(hjd): Test truncated events.
  // If the end of the buffer is before the end of the event give up.
  if (info.size > length) {
    PERFETTO_DCHECK(false);
    return false;
  }

  bool success = true;
  for (const Field& field : table->common_fields())
    success &= ParseField(field, start, end, message);

  protozero::ProtoZeroMessage* nested =
      message->BeginNestedMessage<protozero::ProtoZeroMessage>(
          info.proto_field_id);

  for (const Field& field : info.fields)
    success &= ParseField(field, start, end, nested);

  // This finalizes |nested| automatically.
  message->Finalize();
  return success;
}

// Caller must guarantee that the field fits in the range,
// explicitly: start + field.ftrace_offset + field.ftrace_size <= end
// The only exception is fields with strategy = kCStringToString
// where the total size isn't known up front. In this case ParseField
// will check the string terminates in the bounds and won't read past |end|.
bool CpuReader::ParseField(const Field& field,
                           const uint8_t* start,
                           const uint8_t* end,
                           protozero::ProtoZeroMessage* message) {
  PERFETTO_DCHECK(start + field.ftrace_offset + field.ftrace_size <= end);
  const uint8_t* field_start = start + field.ftrace_offset;
  uint32_t field_id = field.proto_field_id;

  switch (field.strategy) {
    case kUint8ToUint32:
    case kUint16ToUint32:
    case kUint32ToUint32:
    case kUint32ToUint64:
      ReadIntoVarInt<uint32_t>(field_start, field_id, message);
      return true;
    case kUint64ToUint64:
      ReadIntoVarInt<uint64_t>(field_start, field_id, message);
      return true;
    case kInt16ToInt32:
    case kInt32ToInt32:
    case kInt32ToInt64:
      ReadIntoVarInt<int32_t>(field_start, field_id, message);
      return true;
    case kInt64ToInt64:
      ReadIntoVarInt<int64_t>(field_start, field_id, message);
      return true;
    case kFixedCStringToString:
      // TODO(hjd): Add AppendMaxLength string to protozero.
      return ReadIntoString(field_start, field_start + field.ftrace_size,
                            field_id, message);
    case kCStringToString:
      // TODO(hjd): Kernel-dive to check this how size:0 char fields work.
      return ReadIntoString(field_start, end, field.proto_field_id, message);
    case kStringPtrToString:
      // TODO(hjd): Figure out how to read these.
      return true;
    case kBoolToUint32:
      ReadIntoVarInt<uint32_t>(field_start, field_id, message);
      return true;
  }
  // Not reached, for gcc.
  PERFETTO_CHECK(false);
  return false;
}

}  // namespace perfetto
<|endoftext|>


<commit_before>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/renderer_host/resource_message_filter.h"

#include <gtk/gtk.h>

void ResourceMessageFilter::OnGetWindowRect(gfx::NativeViewId window_id,
                                            gfx::Rect* rect) {
  // Ideally this would be gtk_widget_get_window but that's only
  // from gtk 2.14 onwards. :(
  GdkWindow* window = gfx::NativeViewFromId(window_id)->window;
  DCHECK(window);
  gint x, y, width, height;
  // This is the "position of a window in root window coordinates".
  gdk_window_get_origin(window, &x, &y);
  gdk_window_get_size(window, &width, &height);
  *rect = gfx::Rect(x, y, width, height);
}

void ResourceMessageFilter::OnGetRootWindowRect(gfx::NativeViewId window_id,
                                                gfx::Rect* rect) {
  // Windows uses GetAncestor(window, GA_ROOT) here which probably means
  // we want the top level window.
  GdkWindow* window =
  gdk_window_get_toplevel(gfx::NativeViewFromId(window_id)->window);
  DCHECK(window);
  gint x, y, width, height;
  // This is the "position of a window in root window coordinates".
  gdk_window_get_origin(window, &x, &y);
  gdk_window_get_size(window, &width, &height);
  *rect = gfx::Rect(x, y, width, height);
}
<commit_msg>Linux: fix crash when renderer asks for the location of a NULL window<commit_after>// Copyright (c) 2006-2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/renderer_host/resource_message_filter.h"

#include <gtk/gtk.h>

void ResourceMessageFilter::OnGetWindowRect(gfx::NativeViewId window_id,
                                            gfx::Rect* rect) {
  // Ideally this would be gtk_widget_get_window but that's only
  // from gtk 2.14 onwards. :(
  GdkWindow* window = gfx::NativeViewFromId(window_id)->window;
  DCHECK(window);
  gint x, y, width, height;
  // This is the "position of a window in root window coordinates".
  gdk_window_get_origin(window, &x, &y);
  gdk_window_get_size(window, &width, &height);
  *rect = gfx::Rect(x, y, width, height);
}

void ResourceMessageFilter::OnGetRootWindowRect(gfx::NativeViewId window_id,
                                                gfx::Rect* rect) {
  if (!window_id) {
    *rect = gfx::Rect();
    return;
  }

  // Windows uses GetAncestor(window, GA_ROOT) here which probably means
  // we want the top level window.
  GdkWindow* window =
  gdk_window_get_toplevel(gfx::NativeViewFromId(window_id)->window);
  DCHECK(window);
  gint x, y, width, height;
  // This is the "position of a window in root window coordinates".
  gdk_window_get_origin(window, &x, &y);
  gdk_window_get_size(window, &width, &height);
  *rect = gfx::Rect(x, y, width, height);
}
<|endoftext|>


<commit_before>a4f0d73a-ad5b-11e7-bd54-ac87a332f658<commit_msg>I hope I am done<commit_after>a566de82-ad5b-11e7-942c-ac87a332f658<|endoftext|>


<commit_before>a4140368-4b02-11e5-865d-28cfe9171a43<commit_msg>For bobby to integrate at some point<commit_after>a420ef30-4b02-11e5-b350-28cfe9171a43<|endoftext|>