<commit_before>#include <project.h>

double rad(double angle){
    return angle * (PI / 180.0);
}

double stairsLength(double height, double angle){
    double distance = height / sin(rad(angle));
    return sqrt(pow(distance, 2) - pow(height, 2));
}

double circleArea(double radius){
    return PI * pow(radius, 2);
}

double circlePerimeter(double radius){
    return 2 * PI * radius;
}
<commit_msg>Added opSide and adSide of triangle<commit_after>#include <project.h>

double rad(double angle){
    return angle * (PI / 180.0);
}

double stairsLength(double height, double angle){
    double distance = height / sin(rad(angle));
    return sqrt(pow(distance, 2) - pow(height, 2));
}

double circleArea(double radius){
    return PI * pow(radius, 2);
}

double circlePerimeter(double radius){
    return 2 * PI * radius;
}

double triangleOpposite(double hypotenuse, double angle){
    return hypotenuse * sin(rad(angle));
}

double triangleAdjacent(double hypotenuse, double angle){
    return hypotenuse * cos(rad(angle));
}
<|endoftext|>


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

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

  Copyright (c) 2002 Insight 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.

=========================================================================*/
#include "ShapeDetectApp.h"
#include "AppUtility.h"

#include "RawVolumeReader.h"
#include "itkImageRegionIterator.h"
#include "itkImageMapper.h"
#include "itkExceptionObject.h"

#include "itkFastMarchingImageFilter.h"

#include "vnl/vnl_math.h"

#include <string>

ShapeDetectApp
::ShapeDetectApp()
{
  this->Initialize();
}

void
ShapeDetectApp
::Initialize()
{

  m_InputImage = InputImageType::New();
  m_EdgePotentialImage = ImageType::New();
  m_SegmentationMask = ImageType::New();
  m_DetectionFilter = DetectionFilterType::New();

  m_Sigma = 1.0;

  m_DumpPGMFiles = true;

}

void
ShapeDetectApp
::Execute()
{

  char         currentLine[150];
  char         buffer[150];
  unsigned int uNumbers[3];
  float       fValue;
  char         symbol;

  std::cout << std::endl;

  // Get input file name
  while(1)
    {
    std::cout << "Input file name: ";
    std::cin.getline( currentLine, 150);
    if( sscanf( currentLine, "%s", buffer ) >= 1 ) break;
    std::cout << "Error: filename expected." << std::endl;
    }
  m_InputFileName = buffer;

  // Get big endian flag
  while(1)
    {
    std::cout << "Input image big endian? [y|n]: ";
    std::cin.getline( currentLine, 150 );
    if( sscanf( currentLine, "%c", &symbol ) >= 1  &&
        ( symbol == 'y' || symbol == 'n' ) ) break;
    std::cout << "Error: 'y' or 'n' expected." << std::endl;
    }
  if( symbol == 'y' )
    {
    m_InputBigEndian = true;
    }
  else
    {
    m_InputBigEndian = false;
    }

  // Get input file size
  while(1)
    {
    std::cout << "Input image size: ";
    std::cin.getline( currentLine, 150 );
    if( sscanf( currentLine, "%d%d%d", uNumbers, uNumbers+1, uNumbers+2 ) >= 3 ) break;
    std::cout << "Error: three unsigned integers expected." << std::endl;
    }
  for( int j = 0; j < ImageDimension; j++ )
    {
    m_InputSize[j] = uNumbers[j];
    }

  // Read in input image
  if( !this->ReadImage( m_InputFileName.c_str(), m_InputSize,
    m_InputBigEndian, m_InputImage ) )
   {
    std::cout << "Error while reading in input volume: ";
    std::cout << m_InputFileName.c_str() << std::endl;
    return;
   }

  // Get input file name
  while(1)
    {
    std::cout << "PGM output directory: ";
    std::cin.getline( currentLine, 150);
    if( sscanf( currentLine, "%s", buffer ) >= 1 ) break;
    std::cout << "Error: directory name expected." << std::endl;
    }
  m_PGMDirectory = buffer;

  if( m_DumpPGMFiles )
    {
    //dump out the input image
    std::cout << "Writing PGM files of the input volume." << std::endl;
    if( !WritePGMFiles<InputImageType>(
        m_InputImage, m_PGMDirectory.c_str(), "input" ))
      {
      std::cout << "Error while writing PGM files.";
      std::cout << "Please make sure the path is valid." << std::endl;
      return;
      }
    }

  this->ComputeEdgePotentialMap();

  std::cout << std::endl << std::endl;
  // Set the initial seed
  while(1)
    {
    std::cout << "Set initial seed index: ";
    std::cin.getline( currentLine, 150 );
    if( sscanf( currentLine, "%d%d%d", uNumbers, uNumbers+1, uNumbers+2 ) >= 3 ) break;
    std::cout << "Error: three unsigned integers expected." << std::endl;
    }
  for( int j = 0; j < ImageDimension; j++ )
    {
    m_Seed[j] = uNumbers[j];
    }

  // run the filter
  std::cout << "Generating time crossing map." << std::endl;
  this->ComputeTimeCrossingMap();

  while(1)
   {
   std::cout << std::endl << "Command [s|t|d|x]: ";
   std::cin.getline( currentLine, 150 );
   if( sscanf( currentLine, "%s", buffer ) >= 1 )
     {
     // parse the command
     switch ( buffer[0] )
      {
      case 's' :
        if( sscanf( currentLine, "%c%d%d%d", &symbol, uNumbers, uNumbers+1, uNumbers+2 ) != 4 )
          {
          std::cout << "Error: three unsigned integers expected" << std::endl;
          continue;
          }
         for( int j = 0; j < ImageDimension; j++ )
          {
          m_Seed[j] = uNumbers[j];
          }
         std::cout << "Re-generating time crossing map." << std::endl;
         this->ComputeTimeCrossingMap();
         this->ThresholdTimeCrossingMap();
         this->WriteSegmentationImage();
         break;
      case 't' :
        if( sscanf( currentLine, "%c%f", &symbol, &fValue ) != 2 )
          {
          std::cout << "Error: one floating point value expected" << std::endl;
          continue;
          }
         m_Threshold = fValue;;
         std::cout << "Re-thresholding time crossing map." << std::endl;
         this->ThresholdTimeCrossingMap();
         this->WriteSegmentationImage();
         break;
        break;
      case 'd':
        std::cout << "Seed: " << m_Seed << "Threshold: " << m_Threshold << std::endl;
        break;
      case 'x' :
        std::cout << "Goodbye. " << std::endl;
        return;
        break;
      default :
        std::cout << "Not a valid command." << std::endl;
      } //end switch

    }

   } //end while

}

void
ShapeDetectApp
::ComputeTimeCrossingMap()
{

  // connect edge potential map
  m_DetectionFilter->SetSpeedImage( m_EdgePotentialImage );

  // setup trial points
  typedef DetectionFilterType::NodeType NodeType;
  typedef DetectionFilterType::NodeContainer NodeContainer;

  NodeContainer::Pointer trialPoints = NodeContainer::New();

  NodeType node;

  node.SetValue( 0.0 );
  node.SetIndex( m_Seed );
  trialPoints->InsertElement(0, node);

  m_DetectionFilter->SetTrialPoints( trialPoints );

  // specify the size of the output image
  m_DetectionFilter->SetOutputSize( m_InputImage->GetBufferedRegion().GetSize() );

  // update the marcher
  m_DetectionFilter->Update();

}

void
ShapeDetectApp
::ThresholdTimeCrossingMap()
{

  // threshold the time crossing map
  m_SegmentationMask->SetLargestPossibleRegion(
    m_InputImage->GetLargestPossibleRegion() );
  m_SegmentationMask->SetBufferedRegion(
    m_InputImage->GetBufferedRegion() );
  m_SegmentationMask->Allocate();

  typedef itk::ImageRegionIterator<ImageType>
   Iterator;
  Iterator inIter( m_DetectionFilter->GetOutput(),
    m_DetectionFilter->GetOutput()->GetBufferedRegion() );

  Iterator outIter( m_SegmentationMask,
    m_SegmentationMask->GetBufferedRegion() );

  while( !inIter.IsAtEnd() )
    {
    if( inIter.Get() <= m_Threshold )
      {
      outIter.Set( 1 );
      }
    else
      {
      outIter.Set( 0 );
      }
    ++inIter;
    ++outIter;
    }

}

void
ShapeDetectApp
::WriteSegmentationImage()
{

   if( m_DumpPGMFiles )
    {
    //dump out the segmented image
    if( !WritePGMFiles<ImageType>( m_SegmentationMask, m_PGMDirectory.c_str(), "seg" ) )
      {
      std::cout << "Error while writing PGM files.";
      std::cout << "Please make sure the path is valid." << std::endl;
      return;
      }
    }

}

void
ShapeDetectApp
::ComputeEdgePotentialMap()
{

  // compute derivative of the input image
  DerivativeFilterPointer deriv = DerivativeFilterType::New();
  deriv->SetInput( m_InputImage );
  deriv->SetSigma( m_Sigma );
  deriv->Update();

  // allocate memory for the map
  m_EdgePotentialImage->SetLargestPossibleRegion(
    m_InputImage->GetLargestPossibleRegion() );
  m_EdgePotentialImage->SetBufferedRegion(
    m_InputImage->GetBufferedRegion() );
  m_EdgePotentialImage->Allocate();

  //****
  //FIXME - use an itk filter once API are consistent
  //****
  // compute the magnitude
  typedef itk::ImageRegionIterator<DerivativeImageType>
    DerivativeIterator;
  typedef itk::ImageRegionIterator<ImageType>
    ImageIterator;

  DerivativeIterator derivIter( deriv->GetOutput(),
    deriv->GetOutput()->GetBufferedRegion() );
  ImageIterator mapIter( m_EdgePotentialImage,
    m_EdgePotentialImage->GetBufferedRegion() );

  while( !derivIter.IsAtEnd() )
    {

    float accum = 0;
    VectorType grad = derivIter.Get();

    for( int j = 0; j < ImageDimension; j++ )
      {
      accum += vnl_math_sqr( grad[j] );
      }

    accum = vnl_math_sqrt( accum );
//    mapIter.Set( 1.0 / ( 1.0 + accum ) );
    mapIter.Set( exp( -1.0 * accum ) );

    ++derivIter;
    ++mapIter;

    }

  if( m_DumpPGMFiles )
    {
    //dump out the input image
    std::cout << "Writing PGM files of the edge potential map." << std::endl;
    if( !WritePGMFiles<ImageType>(
        m_EdgePotentialImage, m_PGMDirectory.c_str(), "map" ))
      {
      std::cout << "Error while writing PGM files.";
      std::cout << "Please make sure the path is valid." << std::endl;
      return;
      }
    }

}

bool
ShapeDetectApp
::ReadImage(
const char * filename,
const SizeType& size,
bool  bigEndian,
InputImageType::Pointer & imgPtr
)
{

  // Read in a raw volume
  typedef itk::RawVolumeReader<InputPixelType,InputImageType> ReaderType;
  ReaderType::Pointer reader = ReaderType::New();

  reader->SetFileName( filename );
  reader->SetBigEndian( bigEndian );
  reader->SetSize( size );
  reader->Execute();

  imgPtr = reader->GetImage();

  return true;
}

<commit_msg>ENH: Unused #include ImageMapper removed.<commit_after>/*=========================================================================

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

  Copyright (c) 2002 Insight 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.

=========================================================================*/
#include "ShapeDetectApp.h"
#include "AppUtility.h"

#include "RawVolumeReader.h"
#include "itkImageRegionIterator.h"
#include "itkExceptionObject.h"

#include "itkFastMarchingImageFilter.h"

#include "vnl/vnl_math.h"

#include <string>

ShapeDetectApp
::ShapeDetectApp()
{
  this->Initialize();
}

void
ShapeDetectApp
::Initialize()
{

  m_InputImage = InputImageType::New();
  m_EdgePotentialImage = ImageType::New();
  m_SegmentationMask = ImageType::New();
  m_DetectionFilter = DetectionFilterType::New();

  m_Sigma = 1.0;

  m_DumpPGMFiles = true;

}

void
ShapeDetectApp
::Execute()
{

  char         currentLine[150];
  char         buffer[150];
  unsigned int uNumbers[3];
  float       fValue;
  char         symbol;

  std::cout << std::endl;

  // Get input file name
  while(1)
    {
    std::cout << "Input file name: ";
    std::cin.getline( currentLine, 150);
    if( sscanf( currentLine, "%s", buffer ) >= 1 ) break;
    std::cout << "Error: filename expected." << std::endl;
    }
  m_InputFileName = buffer;

  // Get big endian flag
  while(1)
    {
    std::cout << "Input image big endian? [y|n]: ";
    std::cin.getline( currentLine, 150 );
    if( sscanf( currentLine, "%c", &symbol ) >= 1  &&
        ( symbol == 'y' || symbol == 'n' ) ) break;
    std::cout << "Error: 'y' or 'n' expected." << std::endl;
    }
  if( symbol == 'y' )
    {
    m_InputBigEndian = true;
    }
  else
    {
    m_InputBigEndian = false;
    }

  // Get input file size
  while(1)
    {
    std::cout << "Input image size: ";
    std::cin.getline( currentLine, 150 );
    if( sscanf( currentLine, "%d%d%d", uNumbers, uNumbers+1, uNumbers+2 ) >= 3 ) break;
    std::cout << "Error: three unsigned integers expected." << std::endl;
    }
  for( int j = 0; j < ImageDimension; j++ )
    {
    m_InputSize[j] = uNumbers[j];
    }

  // Read in input image
  if( !this->ReadImage( m_InputFileName.c_str(), m_InputSize,
    m_InputBigEndian, m_InputImage ) )
   {
    std::cout << "Error while reading in input volume: ";
    std::cout << m_InputFileName.c_str() << std::endl;
    return;
   }

  // Get input file name
  while(1)
    {
    std::cout << "PGM output directory: ";
    std::cin.getline( currentLine, 150);
    if( sscanf( currentLine, "%s", buffer ) >= 1 ) break;
    std::cout << "Error: directory name expected." << std::endl;
    }
  m_PGMDirectory = buffer;

  if( m_DumpPGMFiles )
    {
    //dump out the input image
    std::cout << "Writing PGM files of the input volume." << std::endl;
    if( !WritePGMFiles<InputImageType>(
        m_InputImage, m_PGMDirectory.c_str(), "input" ))
      {
      std::cout << "Error while writing PGM files.";
      std::cout << "Please make sure the path is valid." << std::endl;
      return;
      }
    }

  this->ComputeEdgePotentialMap();

  std::cout << std::endl << std::endl;
  // Set the initial seed
  while(1)
    {
    std::cout << "Set initial seed index: ";
    std::cin.getline( currentLine, 150 );
    if( sscanf( currentLine, "%d%d%d", uNumbers, uNumbers+1, uNumbers+2 ) >= 3 ) break;
    std::cout << "Error: three unsigned integers expected." << std::endl;
    }
  for( int j = 0; j < ImageDimension; j++ )
    {
    m_Seed[j] = uNumbers[j];
    }

  // run the filter
  std::cout << "Generating time crossing map." << std::endl;
  this->ComputeTimeCrossingMap();

  while(1)
   {
   std::cout << std::endl << "Command [s|t|d|x]: ";
   std::cin.getline( currentLine, 150 );
   if( sscanf( currentLine, "%s", buffer ) >= 1 )
     {
     // parse the command
     switch ( buffer[0] )
      {
      case 's' :
        if( sscanf( currentLine, "%c%d%d%d", &symbol, uNumbers, uNumbers+1, uNumbers+2 ) != 4 )
          {
          std::cout << "Error: three unsigned integers expected" << std::endl;
          continue;
          }
         for( int j = 0; j < ImageDimension; j++ )
          {
          m_Seed[j] = uNumbers[j];
          }
         std::cout << "Re-generating time crossing map." << std::endl;
         this->ComputeTimeCrossingMap();
         this->ThresholdTimeCrossingMap();
         this->WriteSegmentationImage();
         break;
      case 't' :
        if( sscanf( currentLine, "%c%f", &symbol, &fValue ) != 2 )
          {
          std::cout << "Error: one floating point value expected" << std::endl;
          continue;
          }
         m_Threshold = fValue;;
         std::cout << "Re-thresholding time crossing map." << std::endl;
         this->ThresholdTimeCrossingMap();
         this->WriteSegmentationImage();
         break;
        break;
      case 'd':
        std::cout << "Seed: " << m_Seed << "Threshold: " << m_Threshold << std::endl;
        break;
      case 'x' :
        std::cout << "Goodbye. " << std::endl;
        return;
        break;
      default :
        std::cout << "Not a valid command." << std::endl;
      } //end switch

    }

   } //end while

}

void
ShapeDetectApp
::ComputeTimeCrossingMap()
{

  // connect edge potential map
  m_DetectionFilter->SetSpeedImage( m_EdgePotentialImage );

  // setup trial points
  typedef DetectionFilterType::NodeType NodeType;
  typedef DetectionFilterType::NodeContainer NodeContainer;

  NodeContainer::Pointer trialPoints = NodeContainer::New();

  NodeType node;

  node.SetValue( 0.0 );
  node.SetIndex( m_Seed );
  trialPoints->InsertElement(0, node);

  m_DetectionFilter->SetTrialPoints( trialPoints );

  // specify the size of the output image
  m_DetectionFilter->SetOutputSize( m_InputImage->GetBufferedRegion().GetSize() );

  // update the marcher
  m_DetectionFilter->Update();

}

void
ShapeDetectApp
::ThresholdTimeCrossingMap()
{

  // threshold the time crossing map
  m_SegmentationMask->SetLargestPossibleRegion(
    m_InputImage->GetLargestPossibleRegion() );
  m_SegmentationMask->SetBufferedRegion(
    m_InputImage->GetBufferedRegion() );
  m_SegmentationMask->Allocate();

  typedef itk::ImageRegionIterator<ImageType>
   Iterator;
  Iterator inIter( m_DetectionFilter->GetOutput(),
    m_DetectionFilter->GetOutput()->GetBufferedRegion() );

  Iterator outIter( m_SegmentationMask,
    m_SegmentationMask->GetBufferedRegion() );

  while( !inIter.IsAtEnd() )
    {
    if( inIter.Get() <= m_Threshold )
      {
      outIter.Set( 1 );
      }
    else
      {
      outIter.Set( 0 );
      }
    ++inIter;
    ++outIter;
    }

}

void
ShapeDetectApp
::WriteSegmentationImage()
{

   if( m_DumpPGMFiles )
    {
    //dump out the segmented image
    if( !WritePGMFiles<ImageType>( m_SegmentationMask, m_PGMDirectory.c_str(), "seg" ) )
      {
      std::cout << "Error while writing PGM files.";
      std::cout << "Please make sure the path is valid." << std::endl;
      return;
      }
    }

}

void
ShapeDetectApp
::ComputeEdgePotentialMap()
{

  // compute derivative of the input image
  DerivativeFilterPointer deriv = DerivativeFilterType::New();
  deriv->SetInput( m_InputImage );
  deriv->SetSigma( m_Sigma );
  deriv->Update();

  // allocate memory for the map
  m_EdgePotentialImage->SetLargestPossibleRegion(
    m_InputImage->GetLargestPossibleRegion() );
  m_EdgePotentialImage->SetBufferedRegion(
    m_InputImage->GetBufferedRegion() );
  m_EdgePotentialImage->Allocate();

  //****
  //FIXME - use an itk filter once API are consistent
  //****
  // compute the magnitude
  typedef itk::ImageRegionIterator<DerivativeImageType>
    DerivativeIterator;
  typedef itk::ImageRegionIterator<ImageType>
    ImageIterator;

  DerivativeIterator derivIter( deriv->GetOutput(),
    deriv->GetOutput()->GetBufferedRegion() );
  ImageIterator mapIter( m_EdgePotentialImage,
    m_EdgePotentialImage->GetBufferedRegion() );

  while( !derivIter.IsAtEnd() )
    {

    float accum = 0;
    VectorType grad = derivIter.Get();

    for( int j = 0; j < ImageDimension; j++ )
      {
      accum += vnl_math_sqr( grad[j] );
      }

    accum = vnl_math_sqrt( accum );
//    mapIter.Set( 1.0 / ( 1.0 + accum ) );
    mapIter.Set( exp( -1.0 * accum ) );

    ++derivIter;
    ++mapIter;

    }

  if( m_DumpPGMFiles )
    {
    //dump out the input image
    std::cout << "Writing PGM files of the edge potential map." << std::endl;
    if( !WritePGMFiles<ImageType>(
        m_EdgePotentialImage, m_PGMDirectory.c_str(), "map" ))
      {
      std::cout << "Error while writing PGM files.";
      std::cout << "Please make sure the path is valid." << std::endl;
      return;
      }
    }

}

bool
ShapeDetectApp
::ReadImage(
const char * filename,
const SizeType& size,
bool  bigEndian,
InputImageType::Pointer & imgPtr
)
{

  // Read in a raw volume
  typedef itk::RawVolumeReader<InputPixelType,InputImageType> ReaderType;
  ReaderType::Pointer reader = ReaderType::New();

  reader->SetFileName( filename );
  reader->SetBigEndian( bigEndian );
  reader->SetSize( size );
  reader->Execute();

  imgPtr = reader->GetImage();

  return true;
}

<|endoftext|>


<commit_before>#include "csvreader.h"
#include <QFile>
#include <QDateTime>
#include <QString>
#include <QByteArray>
//#include <QTextStream>
#include <QDebug>

//+---------------------------------------------------------------------------+
/*
QTextStream& operator>>( QTextStream &out, Header &header )
{
    QString buffer = out.readLine();
    qDebug() << buffer;
    header.Version = buffer.section( ';', 0, 0 ).toInt();
    for(int i = 0; i < buffer.section( ';', 1, 1 ).size(); i++)
        header.Copyright[i] = (QChar)buffer.section( ';', 1, 1 )[i];
    for(int i = 0; i < buffer.section( ';', 2, 2 ).size(); i++)
        header.Symbol[i] = (QChar)buffer.section( ';', 2, 2 )[i];
    header.Period = buffer.section( ';', 3, 3 ).toInt();
    header.Digits = buffer.section( ';', 4, 4 ).toInt();
    header.TimeSign = QDateTime::fromString( buffer.section( ';', 5, 5 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;
    header.LastSync = QDateTime::fromString( buffer.section( ';', 6, 6 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;

    return out;
}
QTextStream& operator>>( QTextStream &out, History &history )
{
    QString buffer = out.readLine();
    qDebug() << buffer;
    history.Time = QDateTime::fromString( buffer.section( ';', 0, 0 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;
    history.Open =  buffer.section( ';', 1, 1 ).toDouble();
    history.High =  buffer.section( ';', 2, 2 ).toDouble();
    history.Low =   buffer.section( ';', 3, 3 ).toDouble();
    history.Close = buffer.section( ';', 4, 4 ).toDouble();
    history.Volume = buffer.section( ';', 5, 5 ).toInt();

    return out;
} */

//+---------------------------------------------------------------------------+
CsvReader::CsvReader(QObject *parent) : QObject(parent), historySize(0)
{
    header = new Header;
    historyVector = new std::vector<History*>;
}

CsvReader::CsvReader(QString fName) : historySize(0), fileName(fName)
{
    header = new Header;
    historyVector = new std::vector<History*>;
}

CsvReader::~CsvReader()
{
    if( header != nullptr )
        delete header;
    if( (historyVector != nullptr) && !historyVector->empty() )
    {
        for(uint i = 0; i < historySize; i++)
            delete (*historyVector)[i];
        delete historyVector;
    }
}

Header *CsvReader::readHeader(QFile &f)
{
    QByteArray byteArr = f.readLine();
    QString buffer = byteArr.data();
    if( buffer == "")
        return nullptr;

    Header *header = new Header;
    header->Version = buffer.section( ';', 0, 0 ).toInt();
    for(int i = 0; i < buffer.section( ';', 1, 1 ).size(); i++)
        header->Copyright[i] = (QChar)buffer.section( ';', 1, 1 )[i];
    for(int i = 0; i < buffer.section( ';', 2, 2 ).size(); i++)
        header->Symbol[i] = (QChar)buffer.section( ';', 2, 2 )[i];
    header->Period = buffer.section( ';', 3, 3 ).toInt();
    header->Digits = buffer.section( ';', 4, 4 ).toInt();
    header->TimeSign = QDateTime::fromString( buffer.section( ';', 5, 5 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;
    header->LastSync = QDateTime::fromString( buffer.section( ';', 6, 6 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;

    return header;
}

History *CsvReader::readHistory(QFile &f)
{
    QByteArray byteArr = f.readLine();
    QString buffer = byteArr.data();
    if( buffer == "")
        return nullptr;

    History *history = new History;
    history->Time = QDateTime::fromString( buffer.section( ';', 0, 0 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;
    history->Open =  buffer.section( ';', 1, 1 ).toDouble();
    history->High =  buffer.section( ';', 2, 2 ).toDouble();
    history->Low =   buffer.section( ';', 3, 3 ).toDouble();
    history->Close = buffer.section( ';', 4, 4 ).toDouble();
    history->Volume = buffer.section( ';', 5, 5 ).toInt();

    return history;
}

void CsvReader::setFileName(QString fName)
{
    fileName = fName;
}

QString CsvReader::getFileName() const
{
    return fileName;
}

uint CsvReader::getHistorySize() const
{
    return historySize;
}

bool CsvReader::readFromFile()
{
    QFile file(fileName, this);

    if(file.open(QIODevice::ReadOnly))
    {
        fileExists = true;

        //QTextStream input( &file );
        //input.setAutoDetectUnicode( true );
        //input >> header;

        header = readHeader( file );

        History *historyLine = readHistory( file );
        while( historyLine != nullptr )
        {
            historyVector->push_back( historyLine );
            historySize++;
            historyLine = readHistory( file );
        }
        /*
        while( !file.atEnd() )
        {
            History *historyLine = new History;
            input >> *historyLine;
            historyVector->push_back(historyLine);
            historySize++;
        } */

        file.close();
        return fileExists;
    }
    else
    {
        fileExists = false;
        return fileExists;
    }
}

Header *CsvReader::getHeaderStruct()
{
    return header;
}

QString CsvReader::getHeaderString() const
{
    if(fileExists)
        return QString("%1, %2, %3, %4, %5, %6, %7")
                .arg( header->Version )
                .arg( QString(header->Copyright) )
                .arg( QString(header->Symbol) )
                .arg( header->Period )
                .arg( header->Digits )
                .arg( QDateTime::fromTime_t( header->TimeSign )
                      .toString("yyyy.MM.dd hh:mm:ss") )
                .arg( QDateTime::fromTime_t( header->LastSync )
                      .toString("yyyy.MM.dd hh:mm:ss") );
    return "File not exists.";
}

std::vector<History*> *CsvReader::getHistoryVector()
{
    return historyVector;
}

QString CsvReader::getHistoryString(uint numberPosition) const
{
    if( fileExists )
        return QString("%1, %2, %3, %4, %5, %6")
                .arg( QDateTime::fromTime_t( (*historyVector)[numberPosition]->Time )
                      .toString("yyyy.MM.dd hh:mm:ss") )
                .arg( (*historyVector)[numberPosition]->Open  , header->Digits, 'f' )
                .arg( (*historyVector)[numberPosition]->High  , header->Digits, 'f' )
                .arg( (*historyVector)[numberPosition]->Low   , header->Digits, 'f' )
                .arg( (*historyVector)[numberPosition]->Close , header->Digits, 'f' )
                .arg( (*historyVector)[numberPosition]->Volume );
    return "File not exists.";
}
<commit_msg>- update;<commit_after>#include "csvreader.h"
#include <QFile>
#include <QDateTime>
#include <QString>
#include <QByteArray>
//#include <QTextStream>

//+---------------------------------------------------------------------------+
/*
QTextStream& operator>>( QTextStream &out, Header &header )
{
    QString buffer = out.readLine();
    qDebug() << buffer;
    header.Version = buffer.section( ';', 0, 0 ).toInt();
    for(int i = 0; i < buffer.section( ';', 1, 1 ).size(); i++)
        header.Copyright[i] = (QChar)buffer.section( ';', 1, 1 )[i];
    for(int i = 0; i < buffer.section( ';', 2, 2 ).size(); i++)
        header.Symbol[i] = (QChar)buffer.section( ';', 2, 2 )[i];
    header.Period = buffer.section( ';', 3, 3 ).toInt();
    header.Digits = buffer.section( ';', 4, 4 ).toInt();
    header.TimeSign = QDateTime::fromString( buffer.section( ';', 5, 5 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;
    header.LastSync = QDateTime::fromString( buffer.section( ';', 6, 6 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;

    return out;
}
QTextStream& operator>>( QTextStream &out, History &history )
{
    QString buffer = out.readLine();
    qDebug() << buffer;
    history.Time = QDateTime::fromString( buffer.section( ';', 0, 0 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;
    history.Open =  buffer.section( ';', 1, 1 ).toDouble();
    history.High =  buffer.section( ';', 2, 2 ).toDouble();
    history.Low =   buffer.section( ';', 3, 3 ).toDouble();
    history.Close = buffer.section( ';', 4, 4 ).toDouble();
    history.Volume = buffer.section( ';', 5, 5 ).toInt();

    return out;
} */

//+---------------------------------------------------------------------------+
CsvReader::CsvReader(QObject *parent) : QObject(parent), historySize(0)
{
    header = new Header;
    historyVector = new std::vector<History*>;
}

CsvReader::CsvReader(QString fName) : historySize(0), fileName(fName)
{
    header = new Header;
    historyVector = new std::vector<History*>;
}

CsvReader::~CsvReader()
{
    if( header != nullptr )
        delete header;
    if( (historyVector != nullptr) && !historyVector->empty() )
    {
        for(uint i = 0; i < historySize; i++)
            delete (*historyVector)[i];
        delete historyVector;
    }
}

Header *CsvReader::readHeader(QFile &f)
{
    QByteArray byteArr = f.readLine();
    QString buffer = byteArr.data();
    if( buffer == "")
        return nullptr;

    Header *header = new Header;
    header->Version = buffer.section( ';', 0, 0 ).toInt();
    for(int i = 0; i < buffer.section( ';', 1, 1 ).size(); i++)
        header->Copyright[i] = (QChar)buffer.section( ';', 1, 1 )[i];
    for(int i = 0; i < buffer.section( ';', 2, 2 ).size(); i++)
        header->Symbol[i] = (QChar)buffer.section( ';', 2, 2 )[i];
    header->Period = buffer.section( ';', 3, 3 ).toInt();
    header->Digits = buffer.section( ';', 4, 4 ).toInt();
    header->TimeSign = QDateTime::fromString( buffer.section( ';', 5, 5 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;
    header->LastSync = QDateTime::fromString( buffer.section( ';', 6, 6 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;

    return header;
}

History *CsvReader::readHistory(QFile &f)
{
    QByteArray byteArr = f.readLine();
    QString buffer = byteArr.data();
    if( buffer == "")
        return nullptr;

    History *history = new History;
    history->Time = QDateTime::fromString( buffer.section( ';', 0, 0 ), "yyyy.MM.dd hh:mm:ss" ).toMSecsSinceEpoch()/1000;
    history->Open =  buffer.section( ';', 1, 1 ).toDouble();
    history->High =  buffer.section( ';', 2, 2 ).toDouble();
    history->Low =   buffer.section( ';', 3, 3 ).toDouble();
    history->Close = buffer.section( ';', 4, 4 ).toDouble();
    history->Volume = buffer.section( ';', 5, 5 ).toInt();

    return history;
}

void CsvReader::setFileName(QString fName)
{
    fileName = fName;
}

QString CsvReader::getFileName() const
{
    return fileName;
}

uint CsvReader::getHistorySize() const
{
    return historySize;
}

bool CsvReader::readFromFile()
{
    QFile file(fileName, this);

    if(file.open(QIODevice::ReadOnly))
    {
        fileExists = true;

        //QTextStream input( &file );
        //input.setAutoDetectUnicode( true );
        //input >> header;

        header = readHeader( file );

        History *historyLine = readHistory( file );
        while( historyLine != nullptr )
        {
            historyVector->push_back( historyLine );
            historySize++;
            historyLine = readHistory( file );
        }
        /*
        while( !file.atEnd() )
        {
            History *historyLine = new History;
            input >> *historyLine;
            historyVector->push_back(historyLine);
            historySize++;
        } */

        file.close();
        return fileExists;
    }
    else
    {
        fileExists = false;
        return fileExists;
    }
}

Header *CsvReader::getHeaderStruct()
{
    return header;
}

QString CsvReader::getHeaderString() const
{
    if(fileExists)
        return QString("%1, %2, %3, %4, %5, %6, %7")
                .arg( header->Version )
                .arg( QString(header->Copyright) )
                .arg( QString(header->Symbol) )
                .arg( header->Period )
                .arg( header->Digits )
                .arg( QDateTime::fromTime_t( header->TimeSign )
                      .toString("yyyy.MM.dd hh:mm:ss") )
                .arg( QDateTime::fromTime_t( header->LastSync )
                      .toString("yyyy.MM.dd hh:mm:ss") );
    return "File not exists.";
}

std::vector<History*> *CsvReader::getHistoryVector()
{
    return historyVector;
}

QString CsvReader::getHistoryString(uint numberPosition) const
{
    if( fileExists )
        return QString("%1, %2, %3, %4, %5, %6")
                .arg( QDateTime::fromTime_t( (*historyVector)[numberPosition]->Time )
                      .toString("yyyy.MM.dd hh:mm:ss") )
                .arg( (*historyVector)[numberPosition]->Open  , header->Digits, 'f' )
                .arg( (*historyVector)[numberPosition]->High  , header->Digits, 'f' )
                .arg( (*historyVector)[numberPosition]->Low   , header->Digits, 'f' )
                .arg( (*historyVector)[numberPosition]->Close , header->Digits, 'f' )
                .arg( (*historyVector)[numberPosition]->Volume );
    return "File not exists.";
}
<|endoftext|>


<commit_before>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: $                                                             */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2014                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 * @file buffer.H
 * @brief definitions for fapi2 variable integral buffers
 */

#ifndef __FAPI2_INTEGRAL_BUFFER__
#define __FAPI2_INTEGRAL_BUFFER__

#include <buffer_base.H>
#include <return_code.H>

namespace fapi2
{
    /// @brief Class representing a FAPI buffer<T>
    /// @note Buffers support method chaining. So, rather than
    /// this
    /// @code
    /// buffer<T> mask;
    /// mask.setBit<B>();
    /// mask.invert();
    /// my_buffer &= mask;
    /// @endcode
    /// You can do
    /// @code
    /// my_buffer &= buffer<T>().setBit<B>.invert();
    /// @endcode
    template <typename T>
    class buffer : public buffer_base<T>
    {
    public:
        /// Shortcut typedef to map to our traits class
        typedef typename buffer_base<T, buffer>::bits_type bits_type;

        ///
        /// @brief Integral buffer assignment constructor
        /// @param[in] i_value initial value of the buffer
        /// Meaningless for variable types and thus protected.
        ///
        inline buffer(T i_value = 0)
            {
                // Why not an initializer list? That would force buffer_base<T>
                // to have a ctor which took a T, and I want to avoid that in
                // the generic case: this makes it more clear that the two
                // ctor's (integral and container) behave very differently.
                // variable_buffers also have a ctor which takes a single
                // numerical value, and that represents a bit count, not an
                // initial value.
                this->iv_data = i_value;
            }

        /// @name Bit/Word Manipulation Functions
        ///@{

        ///
        /// @brief Return the length of the buffer in bits
        /// @return Length in bits
        ///
        inline constexpr uint32_t getBitLength(void) const
            { return bufferTraits<T>::bit_length(this->iv_data); }

        ///
        /// @brief Return the length of the buffer in OT units
        /// @return Length in OT units rounded up
        /// @tparam OT the type to get the length of. For example, if one
        /// wanted the length in double words, OT would be uint64_t
        /// (getLength<uint64_t>().) Similarly, to get the length in words,
        /// getLength<uin32_t>().
        ///
        template< typename OT >
        inline constexpr uint32_t getLength(void) const
        {
            return bufferTraits<T>::template size<OT>(this->iv_data);
        }

        ///
        /// @brief Templated setBit for integral types
        /// @tparam B the bit number to set.
        /// @return buffer& Useful for method chaining
        /// @note 0 is left-most
        /// @note Example: fapi2::buffer<uint64_t>().setBit<3>();
        ///
        template <bits_type B>
        inline buffer& setBit(void)
        {
            static_assert((B >= 0) &&
                          (B < bufferTraits<T>::bits_per_unit), "failed range check");

            // Force iv_data to be dependent on the template type to force
            // its look up in the second phase
            this->iv_data |= (static_cast<T>(1)) << (bufferTraits<T>::bits_per_unit - B - 1);
            return *this;
        }

        ///
        /// @brief Clear a bit in buffer
        /// @tparam B Bit in buffer to clear.
        /// @return buffer& Useful for method chaining
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template< bits_type B >
        inline buffer& clearBit(void)
        {
            static_assert((B >= 0) &&
                          (B < bufferTraits<T>::bits_per_unit), "failed range check");

            this->iv_data &= buffer<T>().setBit<B>().invert();
            return *this;
        }

        ///
        /// @brief Invert bit
        /// @tparam B Bit in buffer to invert.
        /// @return buffer& Useful for method chaining
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template< bits_type B >
        inline buffer& flipBit(void)
        {
            static_assert((B >= 0) &&
                          (B < bufferTraits<T>::bits_per_unit), "failed range check");

            this->iv_data ^= buffer<T>().setBit<B>();
            return *this;
        }

        ///
        /// @brief Set a bit in the buffer
        /// @param[in] i_bit the bit number to set.
        /// @note 0 is left-most
        /// @return FAPI2_RC_SUCCESS if OK
        ///
        inline fapi2::ReturnCode setBit(const bits_type& i_bit)
            {
                if (i_bit >= bufferTraits<T>::bits_per_unit)
                {
                    return FAPI2_RC_INVALID_PARAMETER;
                }

                // Force iv_data to be dependent on the template type to force
                // its look up in the second phase
                this->iv_data |=
                    (static_cast<T>(1)) << (bufferTraits<T>::bits_per_unit - i_bit - 1);
                return FAPI2_RC_SUCCESS;
            }

        ///
        /// @brief Get the value of a bit in the buffer
        /// @tparam B Bit in buffer to get.
        /// @return true if bit is on, false if bit is off
        ///
        template< bits_type B >
        inline bool getBit(void) const
            {
                return buffer<T>().setBit<B>() & this->iv_data;
            }

        ///@}

        /// @name Buffer Manipulation Functions
        ///@{

        // Note: Many (all?) of these are not needed and the compiler complains
        // as the cast to T yields a better operator. There are here mainly for
        // documenation purposes.

        ///
        /// @brief operator>>()
        ///
#ifdef DOXYGEN
        buffer<T>& operator>>(bits_type i_shiftnum);
#endif

        ///
        /// @brief operator<<()
        ///
#ifdef DOXYGEN
        buffer<T>& operator<<(bits_type i_shiftnum);
#endif

        ///
        /// @brief operator+()
        ///
#ifdef DOXYGEN
        buffer<T>& operator+(const T& rhs);
#endif

        ///
        /// @brief operator+=()
        ///
#ifdef DOXYGEN
        buffer<T>& operator+=(const T& rhs);
#endif

        ///
        /// @brief operator|=()
        ///
#ifdef DOXYGEN
        buffer<T>& operator|=(const T& rhs);
#endif

        ///
        /// @brief operator&=()
        ///
#ifdef DOXYGEN
        buffer<T>& operator&=(const T& rhs);
#endif

        ///
        /// @brief operator|()
        ///
#ifdef DOXYGEN
        buffer<T>& operator|(const T& rhs);
#endif

        ///
        /// @brief operator&()
        ///
#ifdef DOXYGEN
        buffer<T>& operator&(const T& rhs);
#endif

        ///
        /// @brief operator^=()
        ///
#ifdef DOXYGEN
        buffer<T>& operator^=(const T& rhs);
#endif

        ///
        /// @brief operator~()
        ///
#ifdef DOXYGEN
        buffer<T>& operator~(const T& rhs) const;
#endif

        ///
        /// @brief operator==()
        ///
#ifdef DOXYGEN
        bool operator==(const T& rhs) const;
#endif

        ///
        /// @brief operator!=()
        ///
#ifdef DOXYGEN
        bool operator!=(const T& rhs) const;
#endif

        ///
        /// @brief Copy part of a OT into the DataBuffer
        /// @tparam TS Start bit to insert into (target start)
        /// @tparam L Length of bits to insert
        /// @tparam SS Start bit in source
        /// @tparam OT the type of the incoming (origin) data
        /// @param[in] i_datain OT value to copy into DataBuffer
        ///    - data is taken left aligned
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template<bits_type TS, bits_type L, bits_type SS, typename OT>
        inline void insert(const OT i_datain)
        {
            const bits_type target_length = parameterTraits<T>::bit_length;
            const bits_type source_length = parameterTraits<OT>::bit_length;

            // Error if input data don't make sense
            static_assert((TS + L) <= target_length,
                          "insert(): (Target Start + Len) is out of bounds");
            static_assert((SS + L) <= source_length,
                          "insert(): (Source Start + Len) is out of bounds");
            static_assert(TS < target_length,
                          "insert(): Target Start is out of bounds");
            static_assert(SS < source_length,
                          "insert(): Source Start is out of bounds");

            // Get mask value for Target buffer
            // Note: Need "& ((T)-1) because bit shift left for Target buffer doesn't roll off
            T mask =((T(~0) << (target_length - L)) & T(~0)) >> TS;

            // Calculate the equivalent position of the input Source start for the size of the Target buffer.

            // Assume OT is smaller (sizeof(T) > sizeof(OT))
            uint64_t sourceShift = abs(TS - ((target_length - source_length) + SS));
            uint64_t sourceAlign = T(i_datain) << sourceShift;

            if (sizeof(T) == sizeof(OT))
            {
                sourceShift = abs(SS - TS);
                sourceAlign = (SS > TS) ? ((T)i_datain) << sourceShift : ((T)i_datain) >> sourceShift;
            }

            if (sizeof(T) < sizeof(OT))
            {
                sourceShift = source_length - target_length;
                if (SS <= sourceShift)
                {
                    sourceShift = sourceShift +  TS - SS;
                    sourceAlign = ((OT)i_datain) >> sourceShift;
                }

                // (SS > sourceShift)
                else
                {
                    if (sourceShift > TS)
                    {
                        sourceShift = SS - sourceShift - TS;
                        sourceAlign = OT(i_datain) << sourceShift;
                    }
                    else
                    {
                        sourceShift = SS - sourceShift;
                        sourceAlign = (sourceShift < TS) ? OT(i_datain) >> sourceShift : OT(i_datain);
                    }
                }
            }

            this->iv_data = (this->iv_data & ~mask) | (sourceAlign & mask);
            return;
        }

        ///
        /// @brief Copy in a right aligned value
        /// @tparam SB Start bit to insert into
        /// @tparam L Length of bits to insert
        /// @tparam OT the type of the incoming (origin) data
        /// @param[in] i_datain OT value to copy into DataBuffer
        ///    - data is taken right aligned
        /// @note Data is assumed to be aligned on the word boundary of L
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template<bits_type TS, bits_type L, typename OT>
        inline void insertFromRight(const OT i_datain)
        {
            // Error if input data don't make sense
            static_assert(L < parameterTraits<OT>::bit_length,
                          "insertFromRight(): Len >= input buffer");
            static_assert(TS < parameterTraits<T>::bit_length,
                          "insertFromRight(): Target Start is out of bounds");
            static_assert((TS + L) <= parameterTraits<T>::bit_length,
                          "InsertFromRight(): (Target Start + Len) is out of bounds");

            this->insert<TS, L, parameterTraits<OT>::bit_length - L>(i_datain);
            return;
        }

        ///
        /// @brief Copy data from this buffer into an OT
        /// @tparam TS Start bit to insert into (target start)
        /// @tparam L Length of bits to insert
        /// @tparam SS Start bit in source
        /// @tparam OT the type of the outgoing (target)
        /// @param[out] o_out OT to copy into - data is placed left aligned
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template<bits_type TS, bits_type L, bits_type SS, typename OT>
        inline void extract(OT& o_out)
        {
            // Extraction is just an insert into o_out

            buffer<OT> out(o_out);
            out.insert<TS, L, SS>(this->iv_data);
            o_out = out;
            return;
        }

#if 0
        ///
        /// @brief Copy data from this buffer into an OT and right justify
        /// @tparam OT the type of the outgoing data - defaults to T
        /// @tparam SB Start bit to insert into - defaults to 0
        /// @tparam SS Start bit in o_out - default value is zero
        /// @tparam L Length of bits to copy - defaults to sizeof(OT) * 8
        /// @param[out] o_out OT to copy into - data is placed right aligned
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        /// @post Data is copied from specified location to o_out, right
        /// aligned. Data is only right aligned if L < sizeof(bits_type)
        ///
        template< typename OT = T, bits_type L = parameterTraits<OT>::bit_length,
                  bits_type SB = 0, bits_type SS = 0 >
        void extractFromRight(OT& o_out);
#endif
        ///@}
    };
};

#endif
<commit_msg>Add fapi2::buffer<T>::extractToRight()<commit_after>/* IBM_PROLOG_BEGIN_TAG                                                   */
/* This is an automatically generated prolog.                             */
/*                                                                        */
/* $Source: $                                                             */
/*                                                                        */
/* OpenPOWER HostBoot Project                                             */
/*                                                                        */
/* Contributors Listed Below - COPYRIGHT 2012,2014                        */
/* [+] International Business Machines Corp.                              */
/*                                                                        */
/*                                                                        */
/* 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.                         */
/*                                                                        */
/* IBM_PROLOG_END_TAG                                                     */
/**
 * @file buffer.H
 * @brief definitions for fapi2 variable integral buffers
 */

#ifndef __FAPI2_INTEGRAL_BUFFER__
#define __FAPI2_INTEGRAL_BUFFER__

#include <buffer_base.H>
#include <return_code.H>

namespace fapi2
{
    /// @brief Class representing a FAPI buffer<T>
    /// @note Buffers support method chaining. So, rather than
    /// this
    /// @code
    /// buffer<T> mask;
    /// mask.setBit<B>();
    /// mask.invert();
    /// my_buffer &= mask;
    /// @endcode
    /// You can do
    /// @code
    /// my_buffer &= buffer<T>().setBit<B>.invert();
    /// @endcode
    template <typename T>
    class buffer : public buffer_base<T>
    {
    public:
        /// Shortcut typedef to map to our traits class
        typedef typename buffer_base<T, buffer>::bits_type bits_type;

        ///
        /// @brief Integral buffer assignment constructor
        /// @param[in] i_value initial value of the buffer
        /// Meaningless for variable types and thus protected.
        ///
        inline buffer(T i_value = 0)
            {
                // Why not an initializer list? That would force buffer_base<T>
                // to have a ctor which took a T, and I want to avoid that in
                // the generic case: this makes it more clear that the two
                // ctor's (integral and container) behave very differently.
                // variable_buffers also have a ctor which takes a single
                // numerical value, and that represents a bit count, not an
                // initial value.
                this->iv_data = i_value;
            }

        /// @name Bit/Word Manipulation Functions
        ///@{

        ///
        /// @brief Return the length of the buffer in bits
        /// @return Length in bits
        ///
        inline constexpr uint32_t getBitLength(void) const
            { return bufferTraits<T>::bit_length(this->iv_data); }

        ///
        /// @brief Return the length of the buffer in OT units
        /// @return Length in OT units rounded up
        /// @tparam OT the type to get the length of. For example, if one
        /// wanted the length in double words, OT would be uint64_t
        /// (getLength<uint64_t>().) Similarly, to get the length in words,
        /// getLength<uin32_t>().
        ///
        template< typename OT >
        inline constexpr uint32_t getLength(void) const
        {
            return bufferTraits<T>::template size<OT>(this->iv_data);
        }

        ///
        /// @brief Templated setBit for integral types
        /// @tparam B the bit number to set.
        /// @return buffer& Useful for method chaining
        /// @note 0 is left-most
        /// @note Example: fapi2::buffer<uint64_t>().setBit<3>();
        ///
        template <bits_type B>
        inline buffer& setBit(void)
        {
            static_assert((B >= 0) &&
                          (B < bufferTraits<T>::bits_per_unit), "failed range check");

            // Force iv_data to be dependent on the template type to force
            // its look up in the second phase
            this->iv_data |= (static_cast<T>(1)) << (bufferTraits<T>::bits_per_unit - B - 1);
            return *this;
        }

        ///
        /// @brief Clear a bit in buffer
        /// @tparam B Bit in buffer to clear.
        /// @return buffer& Useful for method chaining
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template< bits_type B >
        inline buffer& clearBit(void)
        {
            static_assert((B >= 0) &&
                          (B < bufferTraits<T>::bits_per_unit), "failed range check");

            this->iv_data &= buffer<T>().setBit<B>().invert();
            return *this;
        }

        ///
        /// @brief Invert bit
        /// @tparam B Bit in buffer to invert.
        /// @return buffer& Useful for method chaining
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template< bits_type B >
        inline buffer& flipBit(void)
        {
            static_assert((B >= 0) &&
                          (B < bufferTraits<T>::bits_per_unit), "failed range check");

            this->iv_data ^= buffer<T>().setBit<B>();
            return *this;
        }

        ///
        /// @brief Set a bit in the buffer
        /// @param[in] i_bit the bit number to set.
        /// @note 0 is left-most
        /// @return FAPI2_RC_SUCCESS if OK
        ///
        inline fapi2::ReturnCode setBit(const bits_type& i_bit)
            {
                if (i_bit >= bufferTraits<T>::bits_per_unit)
                {
                    return FAPI2_RC_INVALID_PARAMETER;
                }

                // Force iv_data to be dependent on the template type to force
                // its look up in the second phase
                this->iv_data |=
                    (static_cast<T>(1)) << (bufferTraits<T>::bits_per_unit - i_bit - 1);
                return FAPI2_RC_SUCCESS;
            }

        ///
        /// @brief Get the value of a bit in the buffer
        /// @tparam B Bit in buffer to get.
        /// @return true if bit is on, false if bit is off
        ///
        template< bits_type B >
        inline bool getBit(void) const
            {
                return buffer<T>().setBit<B>() & this->iv_data;
            }

        ///@}

        /// @name Buffer Manipulation Functions
        ///@{

        // Note: Many (all?) of these are not needed and the compiler complains
        // as the cast to T yields a better operator. There are here mainly for
        // documenation purposes.

        ///
        /// @brief operator>>()
        ///
#ifdef DOXYGEN
        buffer<T>& operator>>(bits_type i_shiftnum);
#endif

        ///
        /// @brief operator<<()
        ///
#ifdef DOXYGEN
        buffer<T>& operator<<(bits_type i_shiftnum);
#endif

        ///
        /// @brief operator+()
        ///
#ifdef DOXYGEN
        buffer<T>& operator+(const T& rhs);
#endif

        ///
        /// @brief operator+=()
        ///
#ifdef DOXYGEN
        buffer<T>& operator+=(const T& rhs);
#endif

        ///
        /// @brief operator|=()
        ///
#ifdef DOXYGEN
        buffer<T>& operator|=(const T& rhs);
#endif

        ///
        /// @brief operator&=()
        ///
#ifdef DOXYGEN
        buffer<T>& operator&=(const T& rhs);
#endif

        ///
        /// @brief operator|()
        ///
#ifdef DOXYGEN
        buffer<T>& operator|(const T& rhs);
#endif

        ///
        /// @brief operator&()
        ///
#ifdef DOXYGEN
        buffer<T>& operator&(const T& rhs);
#endif

        ///
        /// @brief operator^=()
        ///
#ifdef DOXYGEN
        buffer<T>& operator^=(const T& rhs);
#endif

        ///
        /// @brief operator~()
        ///
#ifdef DOXYGEN
        buffer<T>& operator~(const T& rhs) const;
#endif

        ///
        /// @brief operator==()
        ///
#ifdef DOXYGEN
        bool operator==(const T& rhs) const;
#endif

        ///
        /// @brief operator!=()
        ///
#ifdef DOXYGEN
        bool operator!=(const T& rhs) const;
#endif

        ///
        /// @brief Copy part of a OT into the DataBuffer
        /// @tparam TS Start bit to insert into (target start)
        /// @tparam L Length of bits to insert
        /// @tparam SS Start bit in source
        /// @tparam OT the type of the incoming (origin) data
        /// @param[in] i_datain OT value to copy into DataBuffer
        ///    - data is taken left aligned
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template<bits_type TS, bits_type L, bits_type SS, typename OT>
        inline void insert(const OT i_datain)
        {
            const bits_type target_length = parameterTraits<T>::bit_length;
            const bits_type source_length = parameterTraits<OT>::bit_length;

            // Error if input data don't make sense
            static_assert((TS + L) <= target_length,
                          "insert(): (Target Start + Len) is out of bounds");
            static_assert((SS + L) <= source_length,
                          "insert(): (Source Start + Len) is out of bounds");
            static_assert(TS < target_length,
                          "insert(): Target Start is out of bounds");
            static_assert(SS < source_length,
                          "insert(): Source Start is out of bounds");

            // Get mask value for Target buffer
            // Note: Need "& ((T)-1) because bit shift left for Target buffer doesn't roll off
            T mask =((T(~0) << (target_length - L)) & T(~0)) >> TS;

            // Calculate the equivalent position of the input Source start for the size of the Target buffer.

            // Assume OT is smaller (sizeof(T) > sizeof(OT))
            uint64_t sourceShift = abs(TS - ((target_length - source_length) + SS));
            uint64_t sourceAlign = T(i_datain) << sourceShift;

            if (sizeof(T) == sizeof(OT))
            {
                sourceShift = abs(SS - TS);
                sourceAlign = (SS > TS) ? ((T)i_datain) << sourceShift : ((T)i_datain) >> sourceShift;
            }

            if (sizeof(T) < sizeof(OT))
            {
                sourceShift = source_length - target_length;
                if (SS <= sourceShift)
                {
                    sourceShift = sourceShift +  TS - SS;
                    sourceAlign = ((OT)i_datain) >> sourceShift;
                }

                // (SS > sourceShift)
                else
                {
                    if (sourceShift > TS)
                    {
                        sourceShift = SS - sourceShift - TS;
                        sourceAlign = OT(i_datain) << sourceShift;
                    }
                    else
                    {
                        sourceShift = SS - sourceShift;
                        sourceAlign = (sourceShift < TS) ? OT(i_datain) >> sourceShift : OT(i_datain);
                    }
                }
            }

            this->iv_data = (this->iv_data & ~mask) | (sourceAlign & mask);
            return;
        }

        ///
        /// @brief Copy in a right aligned value
        /// @tparam SB Start bit to insert into
        /// @tparam L Length of bits to insert
        /// @tparam OT the type of the incoming (origin) data
        /// @param[in] i_datain OT value to copy into DataBuffer
        ///    - data is taken right aligned
        /// @note Data is assumed to be aligned on the word boundary of L
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template<bits_type TS, bits_type L, typename OT>
        inline void insertFromRight(const OT i_datain)
        {
            // Error if input data don't make sense
            static_assert(L < parameterTraits<OT>::bit_length,
                          "insertFromRight(): Len >= input buffer");
            static_assert(TS < parameterTraits<T>::bit_length,
                          "insertFromRight(): Target Start is out of bounds");
            static_assert((TS + L) <= parameterTraits<T>::bit_length,
                          "InsertFromRight(): (Target Start + Len) is out of bounds");

            this->insert<TS, L, parameterTraits<OT>::bit_length - L>(i_datain);
            return;
        }

        ///
        /// @brief Copy data from this buffer into an OT
        /// @tparam TS Start bit to insert into (target start)
        /// @tparam L Length of bits to insert
        /// @tparam SS Start bit in source
        /// @tparam OT the type of the outgoing (target)
        /// @param[out] o_out OT to copy into - data is placed left aligned
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template<bits_type TS, bits_type L, bits_type SS, typename OT>
        inline void extract(OT& o_out)
        {
            // Extraction is just an insert into o_out

            buffer<OT> out(o_out);
            out.insert<TS, L, SS>(this->iv_data);
            o_out = out;
            return;
        }

        ///
        /// @brief Copy data from this buffer into an OT and right justify
        /// @tparam SS Start bit to insert into (source start)
        /// @tparam L Length of bits to insert
        /// @tparam OT the type of the outgoing (target)
        /// @param[out] o_out OT to copy into - data is placed right aligned
        /// @note Asserting that all the parameters are known at
        /// compile time so this can be templated only. If that is not
        /// the case we can add a function parameter version.
        ///
        template<bits_type SS, bits_type L, typename OT>
        inline void extractToRight(OT& o_out)
        {
            extract<parameterTraits<OT>::bit_length - L, L, SS>(o_out);
            return;
        }

        ///@}
    };
};

#endif
<|endoftext|>


<commit_before>#include <sys/types.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>

#include <map>
#include <vector>

#include <common/buffer.h>
#include <common/endian.h>
#include <common/limits.h>
#include <common/timer/timer.h>

#include <xcodec/xcodec.h>
#include <xcodec/xcodec_cache.h>
#include <xcodec/xcodec_decoder.h>
#include <xcodec/xcodec_encoder.h>
#include <xcodec/xcodec_hash.h>

enum FileAction {
	None, Compress, Decompress, Hashes
};

#define	TACK_FLAG_QUIET_OUTPUT		(0x00000001)
#define	TACK_FLAG_CODEC_TIMING		(0x00000002)
#define	TACK_FLAG_BYTE_STATS		(0x00000004)
#define	TACK_FLAG_CODEC_TIMING_EACH	(0x00000008)
#define	TACK_FLAG_CODEC_TIMING_SAMPLES	(0x00000010)

static void compress(const std::string&, int, int, XCodec *, unsigned, Timer *);
static void decompress(const std::string&, int, int, XCodec *, unsigned, Timer *);
static void hashes(int, int, unsigned, Timer *);
static bool fill(int, Buffer *);
static void flush(int, Buffer *);
static void print_ratio(const std::string&, uint64_t, uint64_t);
static void process_file(const std::string&, int, int, FileAction, XCodec *, unsigned, Timer *);
static void process_files(int, char *[], FileAction, XCodec *, unsigned);
static void time_samples(const std::string&, Timer *);
static void time_stats(const std::string&, Timer *);
static void usage(void);

int
main(int argc, char *argv[])
{
	UUID uuid;
	uuid.generate();

	XCodecCache *cache = XCodecCache::lookup(uuid);
	XCodec codec(cache);

	bool verbose;
	FileAction action;
	unsigned flags;
	int ch;

	action = None;
	flags = 0;
	verbose = false;

	while ((ch = getopt(argc, argv, "?cdhsvEQST")) != -1) {
		switch (ch) {
		case 'c':
			action = Compress;
			break;
		case 'd':
			action = Decompress;
			break;
		case 'h':
			action = Hashes;
			break;
		case 's':
			flags |= TACK_FLAG_BYTE_STATS;
			break;
		case 'v':
			verbose = true;
			break;
		case 'E':
			flags |= TACK_FLAG_CODEC_TIMING_EACH;
			break;
		case 'Q':
			flags |= TACK_FLAG_QUIET_OUTPUT;
			break;
		case 'S':
			flags |= TACK_FLAG_CODEC_TIMING_SAMPLES;
			break;
		case 'T':
			flags |= TACK_FLAG_CODEC_TIMING;
			break;
		case '?':
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (action == None)
		usage();

	if (action == Hashes && (flags & TACK_FLAG_BYTE_STATS) != 0)
		usage();

	if ((flags & TACK_FLAG_CODEC_TIMING) == 0 &&
	    (flags & (TACK_FLAG_CODEC_TIMING_EACH | TACK_FLAG_CODEC_TIMING_SAMPLES)) != 0)
		usage();

	if (verbose) {
		Log::mask(".?", Log::Debug);
	} else {
		Log::mask(".?", Log::Info);
	}

	process_files(argc, argv, action, &codec, flags);

	return (0);
}

static void
compress(const std::string& name, int ifd, int ofd, XCodec *codec, unsigned flags, Timer *timer)
{
	XCodecEncoder encoder(codec->cache());
	Buffer input, output;
	uint64_t inbytes, outbytes;

	if ((flags & TACK_FLAG_BYTE_STATS) != 0)
		inbytes = outbytes = 0;

	while (fill(ifd, &input)) {
		if ((flags & TACK_FLAG_BYTE_STATS) != 0)
			inbytes += input.length();
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->start();
		encoder.encode(&output, &input);
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->stop();
		if ((flags & TACK_FLAG_BYTE_STATS) != 0) {
			inbytes -= input.length();
			outbytes += output.length();
		}
		flush(ofd, &output);
	}
	ASSERT(input.empty());
	ASSERT(output.empty());

	if ((flags & TACK_FLAG_BYTE_STATS) != 0)
		print_ratio(name, inbytes, outbytes);
}

static void
decompress(const std::string& name, int ifd, int ofd, XCodec *codec, unsigned flags, Timer *timer)
{
	std::set<uint64_t> unknown_hashes;
	XCodecDecoder decoder(codec->cache());
	Buffer input, output;
	uint64_t inbytes, outbytes;

	if ((flags & TACK_FLAG_BYTE_STATS) != 0)
		inbytes = outbytes = 0;

	while (fill(ifd, &input)) {
		if ((flags & TACK_FLAG_BYTE_STATS) != 0)
			inbytes += input.length();
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->start();
		if (!decoder.decode(&output, &input, unknown_hashes)) {
			ERROR("/decompress") << "Decode failed.";
			return;
		}
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->stop();
		if (!unknown_hashes.empty()) {
			ERROR("/decompress") << "Cannot decode stream with unknown hashes.";
			return;
		}
		if ((flags & TACK_FLAG_BYTE_STATS) != 0) {
			inbytes -= input.length();
			outbytes += output.length();
		}
		flush(ofd, &output);
	}
	ASSERT(input.empty());
	ASSERT(output.empty());

	if ((flags & TACK_FLAG_BYTE_STATS) != 0)
		print_ratio(name, outbytes, inbytes); /* Reverse order of compress().  */
}

static void
hashes(int ifd, int ofd, unsigned flags, Timer *timer)
{
	Buffer input, output;
	BufferSegment *seg;
	unsigned o;

	while (fill(ifd, &input)) {
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->start();
		XCodecHash xcodec_hash;
		o = 0;
		while (!input.empty()) {
			input.moveout(&seg);

			const uint8_t *p = seg->data();
			const uint8_t *q = seg->end();
			for (;;) {
				while (o < XCODEC_SEGMENT_LENGTH && p != q) {
					xcodec_hash.add(*p++);
					o++;
				}
				if (o == XCODEC_SEGMENT_LENGTH) {
					uint64_t hash = xcodec_hash.mix();
					xcodec_hash.reset();
					hash = BigEndian::encode(hash);
					output.append(&hash);
					o = 0;

					if (p == q)
						break;

					continue;
				}
				ASSERT(p == q);
				break;
			}

			seg->unref();
		}
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->stop();
		flush(ofd, &output);
	}
	ASSERT(input.empty());
	ASSERT(output.empty());
}

static bool
fill(int fd, Buffer *input)
{
	uint8_t data[65536];
	ssize_t len;

	len = read(fd, data, sizeof data);
	if (len == -1)
		HALT("/fill") << "read failed.";
	if (len == 0)
		return (false);
	input->append(data, len);
	return (true);
}

static void
flush(int fd, Buffer *output)
{
	ssize_t len;

	if (fd == -1) {
		output->clear();
		return;
	}

	for (;;) {
		Buffer::SegmentIterator iter = output->segments();
		if (iter.end())
			break;

		const BufferSegment *seg = *iter;

		len = write(fd, seg->data(), seg->length());
		if (len != (ssize_t)seg->length())
			HALT("/output") << "write failed.";
		output->skip((size_t)len);
	}
	ASSERT(output->empty());
}

static void
print_ratio(const std::string& name, uint64_t inbytes, uint64_t outbytes)
{
	INFO("/codec_stats") << name << ": " << inbytes << " uncompressed bytes, " << outbytes << " compressed bytes.";
	if (inbytes <= outbytes) {
		INFO("/codec_stats") << name << ": bloat ratio 1:" << ((float)outbytes / inbytes) << " (" << ((float)inbytes / outbytes) << ":1)";
	} else {
		INFO("/codec_stats") << name << ": compression ratio 1:" << ((float)outbytes / inbytes) << " (" << ((float)inbytes / outbytes) << ":1)";
	}
}

static void
process_file(const std::string& name, int ifd, int ofd, FileAction action, XCodec *codec, unsigned flags, Timer *timer)
{
	if ((flags & TACK_FLAG_CODEC_TIMING_EACH) != 0) {
		ASSERT(timer == NULL);

		timer = new Timer();
	}

	switch (action) {
	case Compress:
		compress(name, ifd, ofd, codec, flags, timer);
		break;
	case Decompress:
		decompress(name, ifd, ofd, codec, flags, timer);
		break;
	case Hashes:
		hashes(ifd, ofd, flags, timer);
		break;
	default:
		NOTREACHED();
	}

	if ((flags & TACK_FLAG_CODEC_TIMING_EACH) != 0) {
		if ((flags & TACK_FLAG_CODEC_TIMING_SAMPLES) != 0)
			time_samples(name, timer);
		else
			time_stats(name, timer);
		delete timer;
	}
}

static void
process_files(int argc, char *argv[], FileAction action, XCodec *codec, unsigned flags)
{
	Timer *timer;
	int ifd, ofd;

	if ((flags & TACK_FLAG_CODEC_TIMING) != 0 &&
	    (flags & TACK_FLAG_CODEC_TIMING_EACH) == 0)
		timer = new Timer();
	else
		timer = NULL;

	if (argc == 0) {
		ifd = STDIN_FILENO;
		if ((flags & TACK_FLAG_QUIET_OUTPUT) != 0)
			ofd = -1;
		else
			ofd = STDOUT_FILENO;
		process_file("<stdin>", ifd, ofd, action, codec, flags, timer);
	} else {
		while (argc--) {
			const char *file = *argv++;

			ifd = open(file, O_RDONLY);
			if (ifd == -1) {
				ERROR("/tack") << "Could not open: " << file;
				continue;
			}

			if ((flags & TACK_FLAG_QUIET_OUTPUT) != 0)
				ofd = -1;
			else
				ofd = STDOUT_FILENO;

			process_file(file, ifd, ofd, action, codec, flags, timer);

			close(ifd);
		}
	}

	if ((flags & TACK_FLAG_CODEC_TIMING) != 0 &&
	    (flags & TACK_FLAG_CODEC_TIMING_EACH) == 0) {
		ASSERT(timer != NULL);
		if ((flags & TACK_FLAG_CODEC_TIMING_SAMPLES) != 0)
			time_samples("", timer);
		else
			time_stats("<total>", timer);
		delete timer;
	}
}

static void
time_samples(const std::string& name, Timer *timer)
{
	std::vector<uintmax_t> samples = timer->samples();
	std::vector<uintmax_t>::iterator it;

	if (name == "") {
		for (it = samples.begin(); it != samples.end(); ++it)
			fprintf(stderr, "%ju\n", *it);
	} else {
		for (it = samples.begin(); it != samples.end(); ++it)
			fprintf(stderr, "%s,%ju\n", name.c_str(), *it);
	}
}

static void
time_stats(const std::string& name, Timer *timer)
{
	std::vector<uintmax_t> samples = timer->samples();
	std::vector<uintmax_t>::iterator it;
	LogHandle log("/codec_timer");
	uintmax_t microseconds;

	INFO(log) << name << ": " << samples.size() << " timer samples.";
	microseconds = 0;
	for (it = samples.begin(); it != samples.end(); ++it)
		microseconds += *it;
	INFO(log) << name << ": " << microseconds << " total runtime.";
	INFO(log) << name << ": " << (microseconds / samples.size()) << " mean microseconds/call.";
}

static void
usage(void)
{
	fprintf(stderr,
"usage: tack [-svQ] [-T [-ES]] -c [file ...]\n"
"       tack [-svQ] [-T [-ES]] -d [file ...]\n"
"       tack [-vQ] [-T [-ES]] -h [file ...]\n");
	exit(1);
}
<commit_msg>Don't print stats if we couldn't open anything.<commit_after>#include <sys/types.h>
#include <sys/errno.h>
#include <fcntl.h>
#include <limits.h>
#include <stdio.h>
#include <unistd.h>

#include <map>
#include <vector>

#include <common/buffer.h>
#include <common/endian.h>
#include <common/limits.h>
#include <common/timer/timer.h>

#include <xcodec/xcodec.h>
#include <xcodec/xcodec_cache.h>
#include <xcodec/xcodec_decoder.h>
#include <xcodec/xcodec_encoder.h>
#include <xcodec/xcodec_hash.h>

enum FileAction {
	None, Compress, Decompress, Hashes
};

#define	TACK_FLAG_QUIET_OUTPUT		(0x00000001)
#define	TACK_FLAG_CODEC_TIMING		(0x00000002)
#define	TACK_FLAG_BYTE_STATS		(0x00000004)
#define	TACK_FLAG_CODEC_TIMING_EACH	(0x00000008)
#define	TACK_FLAG_CODEC_TIMING_SAMPLES	(0x00000010)

static void compress(const std::string&, int, int, XCodec *, unsigned, Timer *);
static void decompress(const std::string&, int, int, XCodec *, unsigned, Timer *);
static void hashes(int, int, unsigned, Timer *);
static bool fill(int, Buffer *);
static void flush(int, Buffer *);
static void print_ratio(const std::string&, uint64_t, uint64_t);
static void process_file(const std::string&, int, int, FileAction, XCodec *, unsigned, Timer *);
static void process_files(int, char *[], FileAction, XCodec *, unsigned);
static void time_samples(const std::string&, Timer *);
static void time_stats(const std::string&, Timer *);
static void usage(void);

int
main(int argc, char *argv[])
{
	UUID uuid;
	uuid.generate();

	XCodecCache *cache = XCodecCache::lookup(uuid);
	XCodec codec(cache);

	bool verbose;
	FileAction action;
	unsigned flags;
	int ch;

	action = None;
	flags = 0;
	verbose = false;

	while ((ch = getopt(argc, argv, "?cdhsvEQST")) != -1) {
		switch (ch) {
		case 'c':
			action = Compress;
			break;
		case 'd':
			action = Decompress;
			break;
		case 'h':
			action = Hashes;
			break;
		case 's':
			flags |= TACK_FLAG_BYTE_STATS;
			break;
		case 'v':
			verbose = true;
			break;
		case 'E':
			flags |= TACK_FLAG_CODEC_TIMING_EACH;
			break;
		case 'Q':
			flags |= TACK_FLAG_QUIET_OUTPUT;
			break;
		case 'S':
			flags |= TACK_FLAG_CODEC_TIMING_SAMPLES;
			break;
		case 'T':
			flags |= TACK_FLAG_CODEC_TIMING;
			break;
		case '?':
		default:
			usage();
		}
	}
	argc -= optind;
	argv += optind;

	if (action == None)
		usage();

	if (action == Hashes && (flags & TACK_FLAG_BYTE_STATS) != 0)
		usage();

	if ((flags & TACK_FLAG_CODEC_TIMING) == 0 &&
	    (flags & (TACK_FLAG_CODEC_TIMING_EACH | TACK_FLAG_CODEC_TIMING_SAMPLES)) != 0)
		usage();

	if (verbose) {
		Log::mask(".?", Log::Debug);
	} else {
		Log::mask(".?", Log::Info);
	}

	process_files(argc, argv, action, &codec, flags);

	return (0);
}

static void
compress(const std::string& name, int ifd, int ofd, XCodec *codec, unsigned flags, Timer *timer)
{
	XCodecEncoder encoder(codec->cache());
	Buffer input, output;
	uint64_t inbytes, outbytes;

	if ((flags & TACK_FLAG_BYTE_STATS) != 0)
		inbytes = outbytes = 0;

	while (fill(ifd, &input)) {
		if ((flags & TACK_FLAG_BYTE_STATS) != 0)
			inbytes += input.length();
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->start();
		encoder.encode(&output, &input);
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->stop();
		if ((flags & TACK_FLAG_BYTE_STATS) != 0) {
			inbytes -= input.length();
			outbytes += output.length();
		}
		flush(ofd, &output);
	}
	ASSERT(input.empty());
	ASSERT(output.empty());

	if ((flags & TACK_FLAG_BYTE_STATS) != 0)
		print_ratio(name, inbytes, outbytes);
}

static void
decompress(const std::string& name, int ifd, int ofd, XCodec *codec, unsigned flags, Timer *timer)
{
	std::set<uint64_t> unknown_hashes;
	XCodecDecoder decoder(codec->cache());
	Buffer input, output;
	uint64_t inbytes, outbytes;

	if ((flags & TACK_FLAG_BYTE_STATS) != 0)
		inbytes = outbytes = 0;

	while (fill(ifd, &input)) {
		if ((flags & TACK_FLAG_BYTE_STATS) != 0)
			inbytes += input.length();
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->start();
		if (!decoder.decode(&output, &input, unknown_hashes)) {
			ERROR("/decompress") << "Decode failed.";
			return;
		}
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->stop();
		if (!unknown_hashes.empty()) {
			ERROR("/decompress") << "Cannot decode stream with unknown hashes.";
			return;
		}
		if ((flags & TACK_FLAG_BYTE_STATS) != 0) {
			inbytes -= input.length();
			outbytes += output.length();
		}
		flush(ofd, &output);
	}
	ASSERT(input.empty());
	ASSERT(output.empty());

	if ((flags & TACK_FLAG_BYTE_STATS) != 0)
		print_ratio(name, outbytes, inbytes); /* Reverse order of compress().  */
}

static void
hashes(int ifd, int ofd, unsigned flags, Timer *timer)
{
	Buffer input, output;
	BufferSegment *seg;
	unsigned o;

	while (fill(ifd, &input)) {
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->start();
		XCodecHash xcodec_hash;
		o = 0;
		while (!input.empty()) {
			input.moveout(&seg);

			const uint8_t *p = seg->data();
			const uint8_t *q = seg->end();
			for (;;) {
				while (o < XCODEC_SEGMENT_LENGTH && p != q) {
					xcodec_hash.add(*p++);
					o++;
				}
				if (o == XCODEC_SEGMENT_LENGTH) {
					uint64_t hash = xcodec_hash.mix();
					xcodec_hash.reset();
					hash = BigEndian::encode(hash);
					output.append(&hash);
					o = 0;

					if (p == q)
						break;

					continue;
				}
				ASSERT(p == q);
				break;
			}

			seg->unref();
		}
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0)
			timer->stop();
		flush(ofd, &output);
	}
	ASSERT(input.empty());
	ASSERT(output.empty());
}

static bool
fill(int fd, Buffer *input)
{
	uint8_t data[65536];
	ssize_t len;

	len = read(fd, data, sizeof data);
	if (len == -1)
		HALT("/fill") << "read failed.";
	if (len == 0)
		return (false);
	input->append(data, len);
	return (true);
}

static void
flush(int fd, Buffer *output)
{
	ssize_t len;

	if (fd == -1) {
		output->clear();
		return;
	}

	for (;;) {
		Buffer::SegmentIterator iter = output->segments();
		if (iter.end())
			break;

		const BufferSegment *seg = *iter;

		len = write(fd, seg->data(), seg->length());
		if (len != (ssize_t)seg->length())
			HALT("/output") << "write failed.";
		output->skip((size_t)len);
	}
	ASSERT(output->empty());
}

static void
print_ratio(const std::string& name, uint64_t inbytes, uint64_t outbytes)
{
	INFO("/codec_stats") << name << ": " << inbytes << " uncompressed bytes, " << outbytes << " compressed bytes.";
	if (inbytes <= outbytes) {
		INFO("/codec_stats") << name << ": bloat ratio 1:" << ((float)outbytes / inbytes) << " (" << ((float)inbytes / outbytes) << ":1)";
	} else {
		INFO("/codec_stats") << name << ": compression ratio 1:" << ((float)outbytes / inbytes) << " (" << ((float)inbytes / outbytes) << ":1)";
	}
}

static void
process_file(const std::string& name, int ifd, int ofd, FileAction action, XCodec *codec, unsigned flags, Timer *timer)
{
	if ((flags & TACK_FLAG_CODEC_TIMING_EACH) != 0) {
		ASSERT(timer == NULL);

		timer = new Timer();
	}

	switch (action) {
	case Compress:
		compress(name, ifd, ofd, codec, flags, timer);
		break;
	case Decompress:
		decompress(name, ifd, ofd, codec, flags, timer);
		break;
	case Hashes:
		hashes(ifd, ofd, flags, timer);
		break;
	default:
		NOTREACHED();
	}

	if ((flags & TACK_FLAG_CODEC_TIMING_EACH) != 0) {
		if ((flags & TACK_FLAG_CODEC_TIMING_SAMPLES) != 0)
			time_samples(name, timer);
		else
			time_stats(name, timer);
		delete timer;
	}
}

static void
process_files(int argc, char *argv[], FileAction action, XCodec *codec, unsigned flags)
{
	Timer *timer;
	int ifd, ofd;
	bool opened;

	if ((flags & TACK_FLAG_CODEC_TIMING) != 0 &&
	    (flags & TACK_FLAG_CODEC_TIMING_EACH) == 0)
		timer = new Timer();
	else
		timer = NULL;

	if (argc == 0) {
		opened = true;

		ifd = STDIN_FILENO;
		if ((flags & TACK_FLAG_QUIET_OUTPUT) != 0)
			ofd = -1;
		else
			ofd = STDOUT_FILENO;
		process_file("<stdin>", ifd, ofd, action, codec, flags, timer);
	} else {
		opened = false;

		while (argc--) {
			const char *file = *argv++;

			ifd = open(file, O_RDONLY);
			if (ifd == -1) {
				ERROR("/tack") << "Could not open: " << file;
				continue;
			}

			opened = true;

			if ((flags & TACK_FLAG_QUIET_OUTPUT) != 0)
				ofd = -1;
			else
				ofd = STDOUT_FILENO;

			process_file(file, ifd, ofd, action, codec, flags, timer);

			close(ifd);
		}
	}

	if (opened) {
		if ((flags & TACK_FLAG_CODEC_TIMING) != 0 &&
		    (flags & TACK_FLAG_CODEC_TIMING_EACH) == 0) {
			ASSERT(timer != NULL);
			if ((flags & TACK_FLAG_CODEC_TIMING_SAMPLES) != 0)
				time_samples("", timer);
			else
				time_stats("<total>", timer);
			delete timer;
		}
	}
}

static void
time_samples(const std::string& name, Timer *timer)
{
	std::vector<uintmax_t> samples = timer->samples();
	std::vector<uintmax_t>::iterator it;

	if (name == "") {
		for (it = samples.begin(); it != samples.end(); ++it)
			fprintf(stderr, "%ju\n", *it);
	} else {
		for (it = samples.begin(); it != samples.end(); ++it)
			fprintf(stderr, "%s,%ju\n", name.c_str(), *it);
	}
}

static void
time_stats(const std::string& name, Timer *timer)
{
	std::vector<uintmax_t> samples = timer->samples();
	std::vector<uintmax_t>::iterator it;
	LogHandle log("/codec_timer");
	uintmax_t microseconds;

	INFO(log) << name << ": " << samples.size() << " timer samples.";
	microseconds = 0;
	for (it = samples.begin(); it != samples.end(); ++it)
		microseconds += *it;
	INFO(log) << name << ": " << microseconds << " total runtime.";
	INFO(log) << name << ": " << (microseconds / samples.size()) << " mean microseconds/call.";
}

static void
usage(void)
{
	fprintf(stderr,
"usage: tack [-svQ] [-T [-ES]] -c [file ...]\n"
"       tack [-svQ] [-T [-ES]] -d [file ...]\n"
"       tack [-vQ] [-T [-ES]] -h [file ...]\n");
	exit(1);
}
<|endoftext|>


<commit_before>//===--- FrontendActions.cpp ----------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;

//===----------------------------------------------------------------------===//
// Custom Actions
//===----------------------------------------------------------------------===//

ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
                                               llvm::StringRef InFile) {
  return new ASTConsumer();
}

void InitOnlyAction::ExecuteAction() {
}

//===----------------------------------------------------------------------===//
// AST Consumer Actions
//===----------------------------------------------------------------------===//

ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
                                               llvm::StringRef InFile) {
  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
    return CreateASTPrinter(OS);
  return 0;
}

ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI,
                                                  llvm::StringRef InFile) {
  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml"))
    return CreateASTPrinterXML(OS);
  return 0;
}

ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
                                              llvm::StringRef InFile) {
  return CreateASTDumper();
}

ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
                                              llvm::StringRef InFile) {
  return CreateASTViewer();
}

ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
                                                       llvm::StringRef InFile) {
  return CreateDeclContextPrinter();
}

ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
                                                  llvm::StringRef InFile) {
  const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
  if (CI.getFrontendOpts().RelocatablePCH &&
      Sysroot.empty()) {
    CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot);
    return 0;
  }

  llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile);
  if (!OS)
    return 0;

  if (CI.getFrontendOpts().RelocatablePCH)
    return CreatePCHGenerator(CI.getPreprocessor(), OS,
                              CI.getInvocation().getFrontendOpts().ChainedPCH ?
			          CI.getPCHReader() : 0,
                              Sysroot.c_str());

  return CreatePCHGenerator(CI.getPreprocessor(), OS, CI.getPCHReader());
}

ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI,
                                                      llvm::StringRef InFile) {
  return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance);
}

ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
                                                 llvm::StringRef InFile) {
  return new ASTConsumer();
}

//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//

void DumpRawTokensAction::ExecuteAction() {
  Preprocessor &PP = getCompilerInstance().getPreprocessor();
  SourceManager &SM = PP.getSourceManager();

  // Start lexing the specified input file.
  const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
  Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
  RawLex.SetKeepWhitespaceMode(true);

  Token RawTok;
  RawLex.LexFromRawLexer(RawTok);
  while (RawTok.isNot(tok::eof)) {
    PP.DumpToken(RawTok, true);
    llvm::errs() << "\n";
    RawLex.LexFromRawLexer(RawTok);
  }
}

void DumpTokensAction::ExecuteAction() {
  Preprocessor &PP = getCompilerInstance().getPreprocessor();
  // Start preprocessing the specified input file.
  Token Tok;
  PP.EnterMainSourceFile();
  do {
    PP.Lex(Tok);
    PP.DumpToken(Tok, true);
    llvm::errs() << "\n";
  } while (Tok.isNot(tok::eof));
}

void GeneratePTHAction::ExecuteAction() {
  CompilerInstance &CI = getCompilerInstance();
  if (CI.getFrontendOpts().OutputFile.empty() ||
      CI.getFrontendOpts().OutputFile == "-") {
    // FIXME: Don't fail this way.
    // FIXME: Verify that we can actually seek in the given file.
    llvm::report_fatal_error("PTH requires a seekable file for output!");
  }
  llvm::raw_fd_ostream *OS =
    CI.createDefaultOutputFile(true, getCurrentFile());
  if (!OS) return;

  CacheTokens(CI.getPreprocessor(), OS);
}

void ParseOnlyAction::ExecuteAction() {
  Preprocessor &PP = getCompilerInstance().getPreprocessor();
  llvm::OwningPtr<Action> PA(new MinimalAction(PP));

  Parser P(PP, *PA);
  PP.EnterMainSourceFile();
  P.ParseTranslationUnit();
}

void PreprocessOnlyAction::ExecuteAction() {
  Preprocessor &PP = getCompilerInstance().getPreprocessor();

  // Ignore unknown pragmas.
  PP.AddPragmaHandler(0, new EmptyPragmaHandler());

  Token Tok;
  // Start parsing the specified input file.
  PP.EnterMainSourceFile();
  do {
    PP.Lex(Tok);
  } while (Tok.isNot(tok::eof));
}

void PrintParseAction::ExecuteAction() {
  CompilerInstance &CI = getCompilerInstance();
  Preprocessor &PP = getCompilerInstance().getPreprocessor();
  llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
  if (!OS) return;

  llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));

  Parser P(PP, *PA);
  PP.EnterMainSourceFile();
  P.ParseTranslationUnit();
}

void PrintPreprocessedAction::ExecuteAction() {
  CompilerInstance &CI = getCompilerInstance();
  // Output file needs to be set to 'Binary', to avoid converting Unix style
  // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>).
  llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
  if (!OS) return;

  DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
                           CI.getPreprocessorOutputOpts());
}
<commit_msg>Really respect -chained-pch.<commit_after>//===--- FrontendActions.cpp ----------------------------------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/Frontend/FrontendActions.h"
#include "clang/AST/ASTConsumer.h"
#include "clang/Lex/Pragma.h"
#include "clang/Lex/Preprocessor.h"
#include "clang/Parse/Parser.h"
#include "clang/Basic/FileManager.h"
#include "clang/Frontend/ASTConsumers.h"
#include "clang/Frontend/ASTUnit.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "clang/Frontend/Utils.h"
#include "llvm/ADT/OwningPtr.h"
#include "llvm/Support/raw_ostream.h"
using namespace clang;

//===----------------------------------------------------------------------===//
// Custom Actions
//===----------------------------------------------------------------------===//

ASTConsumer *InitOnlyAction::CreateASTConsumer(CompilerInstance &CI,
                                               llvm::StringRef InFile) {
  return new ASTConsumer();
}

void InitOnlyAction::ExecuteAction() {
}

//===----------------------------------------------------------------------===//
// AST Consumer Actions
//===----------------------------------------------------------------------===//

ASTConsumer *ASTPrintAction::CreateASTConsumer(CompilerInstance &CI,
                                               llvm::StringRef InFile) {
  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile))
    return CreateASTPrinter(OS);
  return 0;
}

ASTConsumer *ASTPrintXMLAction::CreateASTConsumer(CompilerInstance &CI,
                                                  llvm::StringRef InFile) {
  if (llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, InFile, "xml"))
    return CreateASTPrinterXML(OS);
  return 0;
}

ASTConsumer *ASTDumpAction::CreateASTConsumer(CompilerInstance &CI,
                                              llvm::StringRef InFile) {
  return CreateASTDumper();
}

ASTConsumer *ASTViewAction::CreateASTConsumer(CompilerInstance &CI,
                                              llvm::StringRef InFile) {
  return CreateASTViewer();
}

ASTConsumer *DeclContextPrintAction::CreateASTConsumer(CompilerInstance &CI,
                                                       llvm::StringRef InFile) {
  return CreateDeclContextPrinter();
}

ASTConsumer *GeneratePCHAction::CreateASTConsumer(CompilerInstance &CI,
                                                  llvm::StringRef InFile) {
  const std::string &Sysroot = CI.getHeaderSearchOpts().Sysroot;
  if (CI.getFrontendOpts().RelocatablePCH &&
      Sysroot.empty()) {
    CI.getDiagnostics().Report(diag::err_relocatable_without_without_isysroot);
    return 0;
  }

  llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, InFile);
  if (!OS)
    return 0;

  const PCHReader *Chain = CI.getInvocation().getFrontendOpts().ChainedPCH ?
                               CI.getPCHReader() : 0;
  const char *isysroot = CI.getFrontendOpts().RelocatablePCH ?
                             Sysroot.c_str() : 0;
  return CreatePCHGenerator(CI.getPreprocessor(), OS, Chain, isysroot);
}

ASTConsumer *InheritanceViewAction::CreateASTConsumer(CompilerInstance &CI,
                                                      llvm::StringRef InFile) {
  return CreateInheritanceViewer(CI.getFrontendOpts().ViewClassInheritance);
}

ASTConsumer *SyntaxOnlyAction::CreateASTConsumer(CompilerInstance &CI,
                                                 llvm::StringRef InFile) {
  return new ASTConsumer();
}

//===----------------------------------------------------------------------===//
// Preprocessor Actions
//===----------------------------------------------------------------------===//

void DumpRawTokensAction::ExecuteAction() {
  Preprocessor &PP = getCompilerInstance().getPreprocessor();
  SourceManager &SM = PP.getSourceManager();

  // Start lexing the specified input file.
  const llvm::MemoryBuffer *FromFile = SM.getBuffer(SM.getMainFileID());
  Lexer RawLex(SM.getMainFileID(), FromFile, SM, PP.getLangOptions());
  RawLex.SetKeepWhitespaceMode(true);

  Token RawTok;
  RawLex.LexFromRawLexer(RawTok);
  while (RawTok.isNot(tok::eof)) {
    PP.DumpToken(RawTok, true);
    llvm::errs() << "\n";
    RawLex.LexFromRawLexer(RawTok);
  }
}

void DumpTokensAction::ExecuteAction() {
  Preprocessor &PP = getCompilerInstance().getPreprocessor();
  // Start preprocessing the specified input file.
  Token Tok;
  PP.EnterMainSourceFile();
  do {
    PP.Lex(Tok);
    PP.DumpToken(Tok, true);
    llvm::errs() << "\n";
  } while (Tok.isNot(tok::eof));
}

void GeneratePTHAction::ExecuteAction() {
  CompilerInstance &CI = getCompilerInstance();
  if (CI.getFrontendOpts().OutputFile.empty() ||
      CI.getFrontendOpts().OutputFile == "-") {
    // FIXME: Don't fail this way.
    // FIXME: Verify that we can actually seek in the given file.
    llvm::report_fatal_error("PTH requires a seekable file for output!");
  }
  llvm::raw_fd_ostream *OS =
    CI.createDefaultOutputFile(true, getCurrentFile());
  if (!OS) return;

  CacheTokens(CI.getPreprocessor(), OS);
}

void ParseOnlyAction::ExecuteAction() {
  Preprocessor &PP = getCompilerInstance().getPreprocessor();
  llvm::OwningPtr<Action> PA(new MinimalAction(PP));

  Parser P(PP, *PA);
  PP.EnterMainSourceFile();
  P.ParseTranslationUnit();
}

void PreprocessOnlyAction::ExecuteAction() {
  Preprocessor &PP = getCompilerInstance().getPreprocessor();

  // Ignore unknown pragmas.
  PP.AddPragmaHandler(0, new EmptyPragmaHandler());

  Token Tok;
  // Start parsing the specified input file.
  PP.EnterMainSourceFile();
  do {
    PP.Lex(Tok);
  } while (Tok.isNot(tok::eof));
}

void PrintParseAction::ExecuteAction() {
  CompilerInstance &CI = getCompilerInstance();
  Preprocessor &PP = getCompilerInstance().getPreprocessor();
  llvm::raw_ostream *OS = CI.createDefaultOutputFile(false, getCurrentFile());
  if (!OS) return;

  llvm::OwningPtr<Action> PA(CreatePrintParserActionsAction(PP, OS));

  Parser P(PP, *PA);
  PP.EnterMainSourceFile();
  P.ParseTranslationUnit();
}

void PrintPreprocessedAction::ExecuteAction() {
  CompilerInstance &CI = getCompilerInstance();
  // Output file needs to be set to 'Binary', to avoid converting Unix style
  // line feeds (<LF>) to Microsoft style line feeds (<CR><LF>).
  llvm::raw_ostream *OS = CI.createDefaultOutputFile(true, getCurrentFile());
  if (!OS) return;

  DoPrintPreprocessedInput(CI.getPreprocessor(), OS,
                           CI.getPreprocessorOutputOpts());
}
<|endoftext|>