<commit_before>
#include "antsUtilities.h"
#include <algorithm>

#include <stdio.h>

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

#include "itkResampleImageFilter.h"

#include "itkConstantBoundaryCondition.h"
#include "itkIdentityTransform.h"
#include "itkBSplineInterpolateImageFunction.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkGaussianInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "itkWindowedSincInterpolateImageFunction.h"
#include "ReadWriteData.h"
#include <string>
#include <vector>

namespace ants
{

template <unsigned int ImageDimension>
int ResampleImage( int argc, char *argv[] )
{
  typedef double                                RealType;
  typedef double                                PixelType;
  typedef itk::Image<PixelType, ImageDimension> ImageType;

  typename ImageType::Pointer image = ITK_NULLPTR;
  ReadImage<ImageType>( image, argv[2] );

  typedef itk::IdentityTransform<RealType, ImageDimension> TransformType;
  typename TransformType::Pointer transform = TransformType::New();
  transform->SetIdentity();

  typedef itk::LinearInterpolateImageFunction<ImageType, RealType>
    LinearInterpolatorType;
  typename LinearInterpolatorType::Pointer interpolator
    = LinearInterpolatorType::New();
  interpolator->SetInputImage( image );

  typedef itk::NearestNeighborInterpolateImageFunction<ImageType, RealType>
    NearestNeighborInterpolatorType;
  typename NearestNeighborInterpolatorType::Pointer nn_interpolator
    = NearestNeighborInterpolatorType::New();
  nn_interpolator->SetInputImage( image );

  typedef itk::BSplineInterpolateImageFunction<ImageType, RealType>
    BSplineInterpolatorType;
  typename BSplineInterpolatorType::Pointer bs_interpolator
    = BSplineInterpolatorType::New();
  bs_interpolator->SetInputImage( image );

  typedef itk::GaussianInterpolateImageFunction<ImageType, RealType>
    GaussianInterpolatorType;
  typename GaussianInterpolatorType::Pointer g_interpolator
    = GaussianInterpolatorType::New();
  g_interpolator->SetInputImage( image );

  typedef itk::WindowedSincInterpolateImageFunction<ImageType, 3> HammingInterpolatorType;
  typename HammingInterpolatorType::Pointer sh_interpolator = HammingInterpolatorType::New();
  sh_interpolator->SetInputImage( image );

  typedef itk::WindowedSincInterpolateImageFunction<ImageType, 3,
                                                    itk::Function::CosineWindowFunction<3> > Sinc1InterpolatorType;
  typename Sinc1InterpolatorType::Pointer sc_interpolator = Sinc1InterpolatorType::New();
  sc_interpolator->SetInputImage( image );

  typedef itk::WindowedSincInterpolateImageFunction<ImageType, 3,
                                                    itk::Function::WelchWindowFunction<3> > Sinc2InterpolatorType;
  typename Sinc2InterpolatorType::Pointer sw_interpolator = Sinc2InterpolatorType::New();
  sw_interpolator->SetInputImage( image );

  typedef itk::WindowedSincInterpolateImageFunction<ImageType, 3,
                                                    itk::Function::LanczosWindowFunction<3> > Sinc3InterpolatorType;
  typename Sinc3InterpolatorType::Pointer sl_interpolator = Sinc3InterpolatorType::New();
  sl_interpolator->SetInputImage( image );

  typename Sinc3InterpolatorType::Pointer sb_interpolator = Sinc3InterpolatorType::New();
  sb_interpolator->SetInputImage( image );

  typedef itk::ResampleImageFilter<ImageType, ImageType, RealType> ResamplerType;
  typename ResamplerType::Pointer resampler = ResamplerType::New();
  typename ResamplerType::SpacingType spacing;
  typename ResamplerType::SizeType size;
  typename ImageType::IndexType oldStartIndex = image->GetLargestPossibleRegion().GetIndex();
typename ImageType::IndexType newStartIndex;
  newStartIndex.Fill(0); // should be "same" as original start index but in new physical space

  std::vector<RealType> sp = ConvertVector<RealType>( std::string( argv[4] ) );

  if( argc <= 5 || atoi( argv[5] ) == 0 )
    {
    if( sp.size() == 1 )
      {
      spacing.Fill( sp[0] );
      }
    else if( sp.size() == ImageDimension )
      {
      for( unsigned int d = 0; d < ImageDimension; d++ )
        {
        spacing[d] = sp[d];
        }
      }
    else
      {
      std::cout << "Invalid spacing." << std::endl;
      }
    for( unsigned int i = 0; i < ImageDimension; i++ )
      {
      RealType spacing_old = image->GetSpacing()[i];
      RealType size_old = image->GetLargestPossibleRegion().GetSize()[i];
      size[i] = static_cast<int>( ( spacing_old * size_old ) / spacing[i] + 0.5 );
      RealType oldstart = static_cast<float>( oldStartIndex[i] );
      newStartIndex[i] = static_cast<int>( ( spacing_old * oldstart ) / spacing[i] + 0.5 );
      }
    }
  else
    {
    if( sp.size() == 1 )
      {
      size.Fill( static_cast<unsigned int>( sp[0] ) );
      }
    else if( sp.size() == ImageDimension )
      {
      for( unsigned int d = 0; d < ImageDimension; d++ )
        {
        size[d] = static_cast<unsigned int>( sp[d] );
        }
      }
    else
      {
      std::cout << "Invalid size." << std::endl;
      }
    for( unsigned int i = 0; i < ImageDimension; i++ )
      {
      RealType spacing_old = image->GetSpacing()[i];
      RealType size_old = image->GetLargestPossibleRegion().GetSize()[i];
      float ratio = static_cast<float>( size_old - 1.0 )
                  / static_cast<float>( size[i] - 1.0 );
      spacing[i] = spacing_old * ratio;
      RealType oldstart = static_cast<float>( oldStartIndex[i] );
      newStartIndex[i] = static_cast<int>( oldstart * ratio + 0.5 );
      }
    }

  char arg7 = '\0';
  if( argc > 7 )
    {
    arg7 = *argv[7];
    }

  resampler->SetTransform( transform );
  resampler->SetInterpolator( interpolator );
  if( argc > 6 && atoi( argv[6] ) )
    {
    switch( atoi( argv[6] ) )
      {
      case 0: default:
        {
        resampler->SetInterpolator( interpolator );
        }
        break;
      case 1:
        {
        resampler->SetInterpolator( nn_interpolator );
        }
        break;
      case 2:
        {
        double sigma[ImageDimension];
        for( unsigned int d = 0; d < ImageDimension; d++ )
          {
          sigma[d] = image->GetSpacing()[d];
          }
        double alpha = 1.0;

        if( argc > 7 )
          {
          std::vector<RealType> sg = ConvertVector<RealType>( std::string( argv[7] ) );
          for( unsigned int d = 0; d < ImageDimension; d++ )
            {
            sigma[d] = sg[d];
            }
          }
        if( argc > 8 )
          {
          alpha = static_cast<double>( atof( argv[8] ) );
          }
        g_interpolator->SetParameters( sigma, alpha );

        resampler->SetInterpolator( g_interpolator );
        }
        break;
      case 3:
        {
        switch( arg7 )
          {
          case 'h': default:
            {
            resampler->SetInterpolator( sh_interpolator );
            }
            break;
          case 'c':
            {
            resampler->SetInterpolator( sc_interpolator );
            }
            break;
          case 'l':
            {
            resampler->SetInterpolator( sl_interpolator );
            }
            break;
          case 'w':
            {
            resampler->SetInterpolator( sw_interpolator );
            }
            break;
          case 'b':
            {
            resampler->SetInterpolator( sb_interpolator );
            }
            break;
          }
        }
      case 4:
        {
        if( argc > 7 && atoi( argv[7] ) >= 0 && atoi( argv[7] ) <= 5 )
          {
          bs_interpolator->SetSplineOrder( atoi( argv[7] ) );
          }
        else
          {
          bs_interpolator->SetSplineOrder( 3 );
          }
        resampler->SetInterpolator( bs_interpolator );
        }
        break;
      }
    }
  resampler->SetInput( image );
  resampler->SetSize( size );
  resampler->SetOutputOrigin( image->GetOrigin() );
  resampler->SetOutputDirection( image->GetDirection() );
  resampler->SetOutputSpacing( spacing );
//  resampler->SetOutputStartIndex( newStartIndex );
  resampler->SetDefaultPixelValue( 0 );
  resampler->Update();
  typename ImageType::Pointer outimage = resampler->GetOutput();
//  typename ImageType::RegionType region = outimage->GetLargestPossibleRegion();
//  region.SetIndex( newStartIndex );
//  outimage->SetLargestPossibleRegion( region );
  WriteImage<ImageType>( outimage , argv[3] );
  return EXIT_SUCCESS;
}

// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int ResampleImage( std::vector<std::string> args, std::ostream* /*out_stream = NULL */ )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "ResampleImage" );

  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = ITK_NULLPTR;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  // antscout->set_stream( out_stream );

  if( argc < 5 )
    {
    std::cout << "Usage: " << argv[0] << " imageDimension inputImage "
             << "outputImage MxNxO [size=1,spacing=0] [interpolate type]" << std::endl;
    std::cout << "  Interpolation type: " << std::endl;
    std::cout << "    0. linear (default)" << std::endl;
    std::cout << "    1. nn " << std::endl;
    std::cout << "    2. gaussian [sigma=imageSpacing] [alpha=1.0]" << std::endl;
    std::cout << "    3. windowedSinc [type = 'c'osine, 'w'elch, 'b'lackman, 'l'anczos, 'h'amming]" << std::endl;
    std::cout << "    4. B-Spline [order=3]" << std::endl;
    if( argc >= 2 &&
        ( std::string( argv[1] ) == std::string("--help") || std::string( argv[1] ) == std::string("-h") ) )
      {
      return EXIT_SUCCESS;
      }
    return EXIT_FAILURE;
    }

  switch( atoi( argv[1] ) )
    {
    case 2:
      {
      return ResampleImage<2>( argc, argv );
      }
      break;
    case 3:
      {
      return ResampleImage<3>( argc, argv );
      }
      break;
    case 4:
      {
      return ResampleImage<4>( argc, argv );
      }
      break;
    default:
      std::cout << "Unsupported dimension" << std::endl;
      return EXIT_FAILURE;
    }
  return EXIT_SUCCESS;
}
} // namespace ants
<commit_msg>ENH: add pixeltype option to resampleImage<commit_after>
#include "antsUtilities.h"
#include <algorithm>

#include <stdio.h>

#include "itkImage.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"

#include "itkResampleImageFilter.h"

#include "itkConstantBoundaryCondition.h"
#include "itkIdentityTransform.h"
#include "itkBSplineInterpolateImageFunction.h"
#include "itkLinearInterpolateImageFunction.h"
#include "itkGaussianInterpolateImageFunction.h"
#include "itkNearestNeighborInterpolateImageFunction.h"
#include "itkWindowedSincInterpolateImageFunction.h"
#include "ReadWriteData.h"
#include <string>
#include <vector>

namespace ants
{

template <unsigned int ImageDimension, class PixelType>
int ResampleImage( int argc, char *argv[] )
{
  typedef double                                RealType;
  typedef itk::Image<PixelType, ImageDimension> ImageType;

  typename ImageType::Pointer image = ITK_NULLPTR;
  ReadImage<ImageType>( image, argv[2] );

  typedef itk::IdentityTransform<RealType, ImageDimension> TransformType;
  typename TransformType::Pointer transform = TransformType::New();
  transform->SetIdentity();

  typedef itk::LinearInterpolateImageFunction<ImageType, RealType>
    LinearInterpolatorType;
  typename LinearInterpolatorType::Pointer interpolator
    = LinearInterpolatorType::New();
  interpolator->SetInputImage( image );

  typedef itk::NearestNeighborInterpolateImageFunction<ImageType, RealType>
    NearestNeighborInterpolatorType;
  typename NearestNeighborInterpolatorType::Pointer nn_interpolator
    = NearestNeighborInterpolatorType::New();
  nn_interpolator->SetInputImage( image );

  typedef itk::BSplineInterpolateImageFunction<ImageType, RealType>
    BSplineInterpolatorType;
  typename BSplineInterpolatorType::Pointer bs_interpolator
    = BSplineInterpolatorType::New();
  bs_interpolator->SetInputImage( image );

  typedef itk::GaussianInterpolateImageFunction<ImageType, RealType>
    GaussianInterpolatorType;
  typename GaussianInterpolatorType::Pointer g_interpolator
    = GaussianInterpolatorType::New();
  g_interpolator->SetInputImage( image );

  typedef itk::WindowedSincInterpolateImageFunction<ImageType, 3> HammingInterpolatorType;
  typename HammingInterpolatorType::Pointer sh_interpolator = HammingInterpolatorType::New();
  sh_interpolator->SetInputImage( image );

  typedef itk::WindowedSincInterpolateImageFunction<ImageType, 3,
                                                    itk::Function::CosineWindowFunction<3> > Sinc1InterpolatorType;
  typename Sinc1InterpolatorType::Pointer sc_interpolator = Sinc1InterpolatorType::New();
  sc_interpolator->SetInputImage( image );

  typedef itk::WindowedSincInterpolateImageFunction<ImageType, 3,
                                                    itk::Function::WelchWindowFunction<3> > Sinc2InterpolatorType;
  typename Sinc2InterpolatorType::Pointer sw_interpolator = Sinc2InterpolatorType::New();
  sw_interpolator->SetInputImage( image );

  typedef itk::WindowedSincInterpolateImageFunction<ImageType, 3,
                                                    itk::Function::LanczosWindowFunction<3> > Sinc3InterpolatorType;
  typename Sinc3InterpolatorType::Pointer sl_interpolator = Sinc3InterpolatorType::New();
  sl_interpolator->SetInputImage( image );

  typename Sinc3InterpolatorType::Pointer sb_interpolator = Sinc3InterpolatorType::New();
  sb_interpolator->SetInputImage( image );

  typedef itk::ResampleImageFilter<ImageType, ImageType, RealType> ResamplerType;
  typename ResamplerType::Pointer resampler = ResamplerType::New();
  typename ResamplerType::SpacingType spacing;
  typename ResamplerType::SizeType size;
  typename ImageType::IndexType oldStartIndex = image->GetLargestPossibleRegion().GetIndex();
typename ImageType::IndexType newStartIndex;
  newStartIndex.Fill(0); // should be "same" as original start index but in new physical space

  std::vector<RealType> sp = ConvertVector<RealType>( std::string( argv[4] ) );

  if( argc <= 5 || atoi( argv[5] ) == 0 )
    {
    if( sp.size() == 1 )
      {
      spacing.Fill( sp[0] );
      }
    else if( sp.size() == ImageDimension )
      {
      for( unsigned int d = 0; d < ImageDimension; d++ )
        {
        spacing[d] = sp[d];
        }
      }
    else
      {
      std::cout << "Invalid spacing." << std::endl;
      }
    for( unsigned int i = 0; i < ImageDimension; i++ )
      {
      RealType spacing_old = image->GetSpacing()[i];
      RealType size_old = image->GetLargestPossibleRegion().GetSize()[i];
      size[i] = static_cast<int>( ( spacing_old * size_old ) / spacing[i] + 0.5 );
      RealType oldstart = static_cast<float>( oldStartIndex[i] );
      newStartIndex[i] = static_cast<int>( ( spacing_old * oldstart ) / spacing[i] + 0.5 );
      }
    }
  else
    {
    if( sp.size() == 1 )
      {
      size.Fill( static_cast<unsigned int>( sp[0] ) );
      }
    else if( sp.size() == ImageDimension )
      {
      for( unsigned int d = 0; d < ImageDimension; d++ )
        {
        size[d] = static_cast<unsigned int>( sp[d] );
        }
      }
    else
      {
      std::cout << "Invalid size." << std::endl;
      }
    for( unsigned int i = 0; i < ImageDimension; i++ )
      {
      RealType spacing_old = image->GetSpacing()[i];
      RealType size_old = image->GetLargestPossibleRegion().GetSize()[i];
      float ratio = static_cast<float>( size_old - 1.0 )
                  / static_cast<float>( size[i] - 1.0 );
      spacing[i] = spacing_old * ratio;
      RealType oldstart = static_cast<float>( oldStartIndex[i] );
      newStartIndex[i] = static_cast<int>( oldstart * ratio + 0.5 );
      }
    }

  char arg7 = '\0';
  if( argc > 7 )
    {
    arg7 = *argv[7];
    }

  resampler->SetTransform( transform );
  resampler->SetInterpolator( interpolator );
  if( argc > 6 && atoi( argv[6] ) )
    {
    switch( atoi( argv[6] ) )
      {
      case 0: default:
        {
        resampler->SetInterpolator( interpolator );
        }
        break;
      case 1:
        {
        resampler->SetInterpolator( nn_interpolator );
        }
        break;
      case 2:
        {
        double sigma[ImageDimension];
        for( unsigned int d = 0; d < ImageDimension; d++ )
          {
          sigma[d] = image->GetSpacing()[d];
          }
        double alpha = 1.0;

        if( argc > 7 )
          {
          std::vector<RealType> sg = ConvertVector<RealType>( std::string( argv[7] ) );
          for( unsigned int d = 0; d < ImageDimension; d++ )
            {
            sigma[d] = sg[d];
            }
          }
        if( argc > 8 )
          {
          alpha = static_cast<double>( atof( argv[8] ) );
          }
        g_interpolator->SetParameters( sigma, alpha );

        resampler->SetInterpolator( g_interpolator );
        }
        break;
      case 3:
        {
        switch( arg7 )
          {
          case 'h': default:
            {
            resampler->SetInterpolator( sh_interpolator );
            }
            break;
          case 'c':
            {
            resampler->SetInterpolator( sc_interpolator );
            }
            break;
          case 'l':
            {
            resampler->SetInterpolator( sl_interpolator );
            }
            break;
          case 'w':
            {
            resampler->SetInterpolator( sw_interpolator );
            }
            break;
          case 'b':
            {
            resampler->SetInterpolator( sb_interpolator );
            }
            break;
          }
        }
      case 4:
        {
        if( argc > 7 && atoi( argv[7] ) >= 0 && atoi( argv[7] ) <= 5 )
          {
          bs_interpolator->SetSplineOrder( atoi( argv[7] ) );
          }
        else
          {
          bs_interpolator->SetSplineOrder( 3 );
          }
        resampler->SetInterpolator( bs_interpolator );
        }
        break;
      }
    }
  resampler->SetInput( image );
  resampler->SetSize( size );
  resampler->SetOutputOrigin( image->GetOrigin() );
  resampler->SetOutputDirection( image->GetDirection() );
  resampler->SetOutputSpacing( spacing );
//  resampler->SetOutputStartIndex( newStartIndex );
  resampler->SetDefaultPixelValue( 0 );
  resampler->Update();
  typename ImageType::Pointer outimage = resampler->GetOutput();
//  typename ImageType::RegionType region = outimage->GetLargestPossibleRegion();
//  region.SetIndex( newStartIndex );
//  outimage->SetLargestPossibleRegion( region );
  WriteImage<ImageType>( outimage , argv[3] );
  return EXIT_SUCCESS;
}

// entry point for the library; parameter 'args' is equivalent to 'argv' in (argc,argv) of commandline parameters to
// 'main()'
int ResampleImage( std::vector<std::string> args, std::ostream* /*out_stream = NULL */ )
{
  // put the arguments coming in as 'args' into standard (argc,argv) format;
  // 'args' doesn't have the command name as first, argument, so add it manually;
  // 'args' may have adjacent arguments concatenated into one argument,
  // which the parser should handle
  args.insert( args.begin(), "ResampleImage" );

  int     argc = args.size();
  char* * argv = new char *[args.size() + 1];
  for( unsigned int i = 0; i < args.size(); ++i )
    {
    // allocate space for the string plus a null character
    argv[i] = new char[args[i].length() + 1];
    std::strncpy( argv[i], args[i].c_str(), args[i].length() );
    // place the null character in the end
    argv[i][args[i].length()] = '\0';
    }
  argv[argc] = ITK_NULLPTR;
  // class to automatically cleanup argv upon destruction
  class Cleanup_argv
  {
public:
    Cleanup_argv( char* * argv_, int argc_plus_one_ ) : argv( argv_ ), argc_plus_one( argc_plus_one_ )
    {
    }

    ~Cleanup_argv()
    {
      for( unsigned int i = 0; i < argc_plus_one; ++i )
        {
        delete[] argv[i];
        }
      delete[] argv;
    }

private:
    char* *      argv;
    unsigned int argc_plus_one;
  };
  Cleanup_argv cleanup_argv( argv, argc + 1 );

  // antscout->set_stream( out_stream );

  if( argc < 5 )
    {
    std::cout << "Usage: " << argv[0] << " imageDimension inputImage "
             << "outputImage MxNxO [size=1,spacing=0] [interpolate type] [pixeltype]" << std::endl;
    std::cout << "  Interpolation type: " << std::endl;
    std::cout << "    0. linear (default)" << std::endl;
    std::cout << "    1. nn " << std::endl;
    std::cout << "    2. gaussian [sigma=imageSpacing] [alpha=1.0]" << std::endl;
    std::cout << "    3. windowedSinc [type = 'c'osine, 'w'elch, 'b'lackman, 'l'anczos, 'h'amming]" << std::endl;
    std::cout << "    4. B-Spline [order=3]" << std::endl;
    std::cout << " pixeltype  :  TYPE " << std::endl;
    std::cout << "  0  :  char   " << std::endl;
    std::cout << "  1  :  unsigned char   " << std::endl;
    std::cout << "  2  :  short   " << std::endl;
    std::cout << "  3  :  unsigned short   " << std::endl;
    std::cout << "  4  :  int   " << std::endl;
    std::cout << "  5  :  unsigned int   " << std::endl;
    std::cout << "  6  :  float (default)  " << std::endl;
    if( argc >= 2 &&
        ( std::string( argv[1] ) == std::string("--help") || std::string( argv[1] ) == std::string("-h") ) )
      {
      return EXIT_SUCCESS;
      }
    return EXIT_FAILURE;
    }

  unsigned int typeoption = 6;
  if( argc > 7 )
    {
    typeoption = atoi(argv[7]);
    }

  switch ( typeoption )
    {
    case 0:
      switch( atoi( argv[1] ) )
        {
        case 2:
          {
          return ResampleImage<2,char>( argc, argv );
          }
          break;
        case 3:
          {
          return ResampleImage<3,char>( argc, argv );
          }
          break;
        case 4:
          {
          return ResampleImage<4,char>( argc, argv );
          }
          break;
        default:
          std::cout << "Unsupported dimension" << std::endl;
          return EXIT_FAILURE;
        }
        break;
    case 1:
      switch( atoi( argv[1] ) )
        {
        case 2:
          {
          return ResampleImage<2,unsigned char>( argc, argv );
          }
          break;
        case 3:
          {
          return ResampleImage<3,unsigned char>( argc, argv );
          }
          break;
        case 4:
          {
          return ResampleImage<4,unsigned char>( argc, argv );
          }
          break;
        default:
          std::cout << "Unsupported dimension" << std::endl;
          return EXIT_FAILURE;
        }
        break;
    //
    case 2:
      switch( atoi( argv[1] ) )
        {
        case 2:
          {
          return ResampleImage<2,short>( argc, argv );
          }
          break;
        case 3:
          {
          return ResampleImage<3,short>( argc, argv );
          }
          break;
        case 4:
          {
          return ResampleImage<4,short>( argc, argv );
          }
          break;
        default:
          std::cout << "Unsupported dimension" << std::endl;
          return EXIT_FAILURE;
        }
    case 3:
      switch( atoi( argv[1] ) )
        {
        case 2:
          {
          return ResampleImage<2,unsigned short>( argc, argv );
          }
          break;
        case 3:
          {
          return ResampleImage<3,unsigned short>( argc, argv );
          }
          break;
        case 4:
          {
          return ResampleImage<4,unsigned short>( argc, argv );
          }
          break;
        default:
          std::cout << "Unsupported dimension" << std::endl;
          return EXIT_FAILURE;
        }
    case 4:
      switch( atoi( argv[1] ) )
        {
        case 2:
          {
          return ResampleImage<2,int>( argc, argv );
          }
          break;
        case 3:
          {
          return ResampleImage<3,int>( argc, argv );
          }
          break;
        case 4:
          {
          return ResampleImage<4,int>( argc, argv );
          }
          break;
        default:
          std::cout << "Unsupported dimension" << std::endl;
          return EXIT_FAILURE;
        }
    case 5:
      switch( atoi( argv[1] ) )
        {
        case 2:
          {
          return ResampleImage<2,unsigned int>( argc, argv );
          }
          break;
        case 3:
          {
          return ResampleImage<3,unsigned int>( argc, argv );
          }
          break;
        case 4:
          {
          return ResampleImage<4,unsigned int>( argc, argv );
          }
          break;
        default:
          std::cout << "Unsupported dimension" << std::endl;
          return EXIT_FAILURE;
        }
    case 6:
      switch( atoi( argv[1] ) )
        {
        case 2:
          {
          return ResampleImage<2,float>( argc, argv );
          }
          break;
        case 3:
          {
          return ResampleImage<3,float>( argc, argv );
          }
          break;
        case 4:
          {
          return ResampleImage<4,float>( argc, argv );
          }
          break;
        default:
          std::cout << "Unsupported dimension" << std::endl;
          return EXIT_FAILURE;
        }
    default:
      std::cout << "Unsupported pixel type" << std::endl;
      return EXIT_FAILURE;
      }
  return EXIT_SUCCESS;
} // end of function
} // namespace ants
<|endoftext|>


<commit_before>#include <VolViz/VolViz.h>

#include <Eigen/Core>
#include <igl/readOBJ.h>
#include <igl/readOFF.h>
#include <igl/readPLY.h>
#include <igl/readSTL.h>

#include <chrono>
#include <fstream>
#include <iostream>
#include <thread>

auto generateVolume();

auto generateVolume() {
  using namespace VolViz;
  using namespace VolViz::literals;
  Size3 const size(256, 256, 128);
  auto const nVoxels = size(0) * size(1) * size(2);

  std::vector<Color> data;
  data.reserve(3 * nVoxels);
  Color c = Colors::Black();
  for (unsigned int z = 0; z < size(2); ++z) {
    c(2) = (static_cast<float>(z) / static_cast<float>(size(2) - 1));
    for (unsigned int y = 0; y < size(1); ++y) {
      c(1) = (static_cast<float>(y) / static_cast<float>(size(1) - 1));
      for (unsigned int x = 0; x < size(0); ++x) {
        c(0) = (static_cast<float>(x) / static_cast<float>(size(0) - 1));
        data.push_back(c);
      }
    }
  }

  VolumeDescriptor v;
  v.size = size;
  v.voxelSize = {{100_um, 100_um, 200_um}};
  v.type = VolumeType::ColorRGB;

  return std::make_pair(v, data);
}

int main(int argc, char **argv) {
  using namespace VolViz;
  using namespace VolViz::literals;
  using Eigen::Vector3d;
  using Vertices = Eigen::MatrixXd;
  using Triangles = Eigen::MatrixXi;

  if (argc != 2) {
    std::cerr << "Usage: " << argv[0] << " meshFile" << std::endl;
    return EXIT_FAILURE;
  }

  auto f = std::ifstream(argv[1]);
  auto const filename = std::string(argv[1]);
  auto const ext = filename.substr(filename.size() - 3, 3);
  std::cout << "Loading mesh " << argv[1] << "... " << std::flush;
  Vertices V;
  Triangles T;
  if (ext == "off")
    igl::readOFF(filename, V, T);
  else if (ext == "ply")
    igl::readPLY(filename, V, T);
  else if (ext == "stl") {
    Vertices N;
    igl::readSTL(filename, V, T, N);
  } else if (ext == "obj")
    igl::readOBJ(filename, V, T);
  else {
    std::cerr << std::endl << "Unrecognized mesh format: " << ext << std::endl;
    return EXIT_FAILURE;
  }
  std::cout << "done." << std::endl;
  std::cout << V.rows() << " vertices, " << T.rows() << " triangles."
            << std::endl;

  Eigen::Vector3d const min = V.colwise().minCoeff();
  Eigen::Vector3d const max = V.colwise().maxCoeff();

  Length meshScale = 5_cm;

  std::cout << "bbox: " << min.transpose() << " - " << max.transpose()
            << std::endl;
  std::cout << "bbox size: "
            << ((max - min).transpose() * static_cast<double>(meshScale / 1_mm))
            << " mm" << std::endl;

  //  Eigen::MatrixXd V(3, 3);
  //  V << 0, 1, 0, -1, -1, 0, 1, -1, 0;
  //  Eigen::MatrixXi T(1, 3);
  //  T << 0, 1, 2;

  auto viewer = Visualizer{};

  // Add mesh
  MeshDescriptor mesh;
  mesh.vertices = V.cast<float>();
  mesh.indices = T.cast<std::uint32_t>();
  mesh.movable = true;
  mesh.scale = 50_mm;
  mesh.color = Colors::White();
  viewer.addGeometry("Mesh", mesh);

  viewer.showGrid = true;

  Light light;
  light.ambientFactor = 1.0f;
  light.color = Colors::White();
  light.position = PositionH(1, 1, 1, 0);

  viewer.addLight(0, light);

  light.position = PositionH(2, 1, 1, 0);
  viewer.addLight(1, light);

  light.position = PositionH(1, 2, 1, 0);
  viewer.addLight(2, light);

  viewer.scale = 1_mm;

  AxisAlignedPlaneDescriptor plane;
  plane.axis = Axis::X;
  // plane.color = Colors::Green();
  plane.color = Colors::White();
  plane.intercept = 0_mm;

  viewer.addGeometry("X-Plane", plane);

  plane.axis = Axis::Y;
  // plane.color = Colors::Blue();
  plane.color = Colors::White();
  plane.intercept = 0_mm;
  viewer.addGeometry("Y-Plane", plane);

  plane.axis = Axis::Z;
  // plane.color = Colors::Red();
  plane.color = Colors::White();
  plane.intercept = 0_mm;
  viewer.addGeometry("Z-Plane", plane);

  std::cout << "Generating volume... " << std::flush;
  auto const vol = generateVolume();
  std::cout << "done." << std::endl;

  viewer.setVolume(vol.first, as_span(vol.second));

  viewer.enableMultithreading();
  std::thread viewerThread([&viewer]() {
    viewer.start();
    viewer.renderAtFPS(60);
  });

  using Clock = std::chrono::steady_clock;
  using namespace std::chrono_literals;
  auto constexpr updateIntervall = 1s / 30.f;
  int count{0};
  while (viewer) {
    auto const t0 = Clock::now();
    mesh.vertices *= count < 10 ? 1.01f : 0.99f;
    viewer.updateGeometry("Mesh", mesh);
    if (++count > 20) count = 0;
    auto const timeLeft = -(Clock::now() - t0) + updateIntervall;
    if (timeLeft > 0s) std::this_thread::sleep_for(timeLeft);
  }

  viewerThread.join();

  return EXIT_SUCCESS;
}
<commit_msg>Let the viewer run on the main thread<commit_after>#include <VolViz/VolViz.h>

#include <Eigen/Core>
#include <igl/readOBJ.h>
#include <igl/readOFF.h>
#include <igl/readPLY.h>
#include <igl/readSTL.h>

#include <chrono>
#include <fstream>
#include <iostream>
#include <thread>

auto generateVolume();

auto generateVolume() {
  using namespace VolViz;
  using namespace VolViz::literals;
  Size3 const size(256, 256, 128);
  auto const nVoxels = size(0) * size(1) * size(2);

  std::vector<Color> data;
  data.reserve(3 * nVoxels);
  Color c = Colors::Black();
  for (unsigned int z = 0; z < size(2); ++z) {
    c(2) = (static_cast<float>(z) / static_cast<float>(size(2) - 1));
    for (unsigned int y = 0; y < size(1); ++y) {
      c(1) = (static_cast<float>(y) / static_cast<float>(size(1) - 1));
      for (unsigned int x = 0; x < size(0); ++x) {
        c(0) = (static_cast<float>(x) / static_cast<float>(size(0) - 1));
        data.push_back(c);
      }
    }
  }

  VolumeDescriptor v;
  v.size = size;
  v.voxelSize = {{100_um, 100_um, 200_um}};
  v.type = VolumeType::ColorRGB;

  return std::make_pair(v, data);
}

int main(int argc, char **argv) {
  using namespace VolViz;
  using namespace VolViz::literals;
  using Eigen::Vector3d;
  using Vertices = Eigen::MatrixXd;
  using Triangles = Eigen::MatrixXi;

  if (argc != 2) {
    std::cerr << "Usage: " << argv[0] << " meshFile" << std::endl;
    return EXIT_FAILURE;
  }

  auto f = std::ifstream(argv[1]);
  auto const filename = std::string(argv[1]);
  auto const ext = filename.substr(filename.size() - 3, 3);
  std::cout << "Loading mesh " << argv[1] << "... " << std::flush;
  Vertices V;
  Triangles T;
  if (ext == "off")
    igl::readOFF(filename, V, T);
  else if (ext == "ply")
    igl::readPLY(filename, V, T);
  else if (ext == "stl") {
    Vertices N;
    igl::readSTL(filename, V, T, N);
  } else if (ext == "obj")
    igl::readOBJ(filename, V, T);
  else {
    std::cerr << std::endl << "Unrecognized mesh format: " << ext << std::endl;
    return EXIT_FAILURE;
  }
  std::cout << "done." << std::endl;
  std::cout << V.rows() << " vertices, " << T.rows() << " triangles."
            << std::endl;

  Eigen::Vector3d const min = V.colwise().minCoeff();
  Eigen::Vector3d const max = V.colwise().maxCoeff();

  Length meshScale = 5_cm;

  std::cout << "bbox: " << min.transpose() << " - " << max.transpose()
            << std::endl;
  std::cout << "bbox size: "
            << ((max - min).transpose() * static_cast<double>(meshScale / 1_mm))
            << " mm" << std::endl;

  //  Eigen::MatrixXd V(3, 3);
  //  V << 0, 1, 0, -1, -1, 0, 1, -1, 0;
  //  Eigen::MatrixXi T(1, 3);
  //  T << 0, 1, 2;

  auto viewer = Visualizer{};

  // Add mesh
  MeshDescriptor mesh;
  mesh.vertices = V.cast<float>();
  mesh.indices = T.cast<std::uint32_t>();
  mesh.movable = true;
  mesh.scale = 50_mm;
  mesh.color = Colors::White();
  viewer.addGeometry("Mesh", mesh);

  viewer.showGrid = true;

  Light light;
  light.ambientFactor = 1.0f;
  light.color = Colors::White();
  light.position = PositionH(1, 1, 1, 0);

  viewer.addLight(0, light);

  light.position = PositionH(2, 1, 1, 0);
  viewer.addLight(1, light);

  light.position = PositionH(1, 2, 1, 0);
  viewer.addLight(2, light);

  viewer.scale = 1_mm;

  AxisAlignedPlaneDescriptor plane;
  plane.axis = Axis::X;
  // plane.color = Colors::Green();
  plane.color = Colors::White();
  plane.intercept = 0_mm;

  viewer.addGeometry("X-Plane", plane);

  plane.axis = Axis::Y;
  // plane.color = Colors::Blue();
  plane.color = Colors::White();
  plane.intercept = 0_mm;
  viewer.addGeometry("Y-Plane", plane);

  plane.axis = Axis::Z;
  // plane.color = Colors::Red();
  plane.color = Colors::White();
  plane.intercept = 0_mm;
  viewer.addGeometry("Z-Plane", plane);

  std::cout << "Generating volume... " << std::flush;
  auto const vol = generateVolume();
  std::cout << "done." << std::endl;

  viewer.setVolume(vol.first, as_span(vol.second));

  viewer.enableMultithreading();
  viewer.start();

  std::thread workerThread([&viewer, &mesh]() {
    using Clock = std::chrono::steady_clock;
    using namespace std::chrono_literals;
    auto constexpr updateIntervall = 1s / 30.f;
    int count{0};
    while (viewer) {
      auto const t0 = Clock::now();
      mesh.vertices *= count < 10 ? 1.01f : 0.99f;
      viewer.updateGeometry("Mesh", mesh);
      if (++count > 20) count = 0;
      auto const timeLeft = -(Clock::now() - t0) + updateIntervall;
      if (timeLeft > 0s) std::this_thread::sleep_for(timeLeft);
    }
  });

  viewer.renderAtFPS(60);

  workerThread.join();

  return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>#define DEBUG 1
/**
 * File    : H.cpp
 * Author  : Kazune Takahashi
 * Created : 2019/12/30 18:11:35
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
// ----- boost -----
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using boost::rational;
using namespace std;
using ll = long long;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{x % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- PrimeNums -----

class PrimeNums
{
  static constexpr ll MAX_SIZE{1000010LL};
  ll N;
  vector<bool> isprime;
  vector<int> prime_nums;

public:
  PrimeNums(ll N = MAX_SIZE) : N{N}, isprime(N, true), prime_nums{}
  {
    isprime[0] = isprime[1] = false;
    for (auto i = 2; i < N; i++)
    {
      if (isprime[i])
      {
        prime_nums.push_back(i);
        for (auto j = 2 * i; j < N; j += i)
        {
          isprime[j] = false;
        }
      }
    }
  }

  bool is_prime(long long x)
  { // 2 \leq x \leq MAX_SIZE^2
    if (x < N)
    {
      return isprime[x];
    }
    for (auto e : prime_nums)
    {
      if (x % e == 0)
        return false;
    }
    return true;
  }

  vector<int> const &primes() const
  {
    return prime_nums;
  }
};

// ----- main() -----
class Solve
{
  int H, W;
  vector<string> S;
  PrimeNums pn;

public:
  Solve(int H, int W, vector<string> const &S) : H{H}, W{W}, S(S), pn{} {}

  int calc()
  {
    int ans{0};
    for (auto i = 0; i < H; i++)
    {
      ans += calc(S[i]);
    }
    return ans;
  };

private:
  int calc(string const &T)
  {
    if (is_zero(T))
    {
      return 0;
    }
    auto V{make_vec(T)};
#if DEBUG == 1
    cerr << "V = {";
    for (auto x : V)
    {
      cerr << x << ", ";
    }
    cerr << "}" << endl;
#endif
    if (is_one(V))
    {
      return 1;
    }
    if (is_two(V))
    {
      return 2;
    }
    return 3;
  }

  bool is_zero(string const &T)
  {
    for (auto x : T)
    {
      if (x == '.')
      {
        return false;
      }
    }
    return true;
  }

  vector<int> make_vec(string const &T)
  {
    int first{-1};
    vector<int> V;
    for (auto i = 0; i < W; i++)
    {
      if (T[i] == '.')
      {
        if (first == -1)
        {
          first = i;
        }
        V.push_back(i - first);
      }
    }
    return V;
  }

  bool is_one(vector<int> const &V)
  {
    if (V.size() < size_t{2})
    {
      return true;
    }
    assert(V[0] == 0);
    int g{V[1]};
    for (auto it = V.begin() + 1; it != V.end(); it++)
    {
      g = gcd(g, *it);
    }
    for (auto i = 0; i < 20; i++)
    {
      if ((g >> i) == 1)
      {
        return false;
      }
    }
    return true;
  }

  bool is_two(vector<int> const &V)
  {
    for (auto it = pn.primes().begin() + 1; it != pn.primes().end(); it++)
    {
      int p{static_cast<int>(*it)};
      int X{static_cast<int>(V.size())};
      if (W / p + 1 < X / 2)
      {
        return false;
      }
      for (auto k = 0; k < 2; k++)
      {
        int m{V[k]};
        int first{-1};
        vector<int> W;
        for (auto x : V)
        {
          if (x - m >= 0 && (x - m) % p == 0)
          {
            continue;
          }
          if (first == -1)
          {
            first = x;
          }
          W.push_back(x - first);
        }
        if (is_one(W))
        {
          return true;
        }
      }
    }
    assert(false);
    return false;
  }
};

int main()
{
  int H, W;
  cin >> H >> W;
  vector<string> S(H);
  for (auto i = 0; i < H; i++)
  {
    cin >> S[i];
  }
  Solve solve(H, W, S);
  cout << solve.calc() << endl;
}
<commit_msg>tried H.cpp to 'H'<commit_after>#define DEBUG 1
/**
 * File    : H.cpp
 * Author  : Kazune Takahashi
 * Created : 2019/12/30 18:11:35
 * Powered by Visual Studio Code
 */
#include <iostream>
#include <iomanip>
#include <algorithm>
#include <vector>
#include <string>
#include <complex>
#include <tuple>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <unordered_map>
#include <unordered_set>
#include <bitset>
#include <functional>
#include <random>
#include <chrono>
#include <cctype>
#include <cassert>
#include <cmath>
#include <cstdio>
#include <cstdlib>
// ----- boost -----
#include <boost/rational.hpp>
// ----- using directives and manipulations -----
using boost::rational;
using namespace std;
using ll = long long;
// ----- constexpr for Mint and Combination -----
constexpr ll MOD{1000000007LL};
// constexpr ll MOD{998244353LL}; // be careful
constexpr ll MAX_SIZE{3000010LL};
// constexpr ll MAX_SIZE{30000010LL}; // if 10^7 is needed
// ----- ch_max and ch_min -----
template <typename T>
void ch_max(T &left, T right)
{
  if (left < right)
  {
    left = right;
  }
}
template <typename T>
void ch_min(T &left, T right)
{
  if (left > right)
  {
    left = right;
  }
}
// ----- Mint -----
template <ll MOD = MOD>
class Mint
{
public:
  ll x;
  Mint() : x{0LL} {}
  Mint(ll x) : x{x % MOD} {}
  Mint operator-() const { return x ? MOD - x : 0; }
  Mint &operator+=(const Mint &a)
  {
    if ((x += a.x) >= MOD)
    {
      x -= MOD;
    }
    return *this;
  }
  Mint &operator-=(const Mint &a) { return *this += -a; }
  Mint &operator*=(const Mint &a)
  {
    (x *= a.x) %= MOD;
    return *this;
  }
  Mint &operator/=(const Mint &a)
  {
    Mint b{a};
    return *this *= b.power(MOD - 2);
  }
  Mint operator+(const Mint &a) const { return Mint(*this) += a; }
  Mint operator-(const Mint &a) const { return Mint(*this) -= a; }
  Mint operator*(const Mint &a) const { return Mint(*this) *= a; }
  Mint operator/(const Mint &a) const { return Mint(*this) /= a; }
  bool operator<(const Mint &a) const { return x < a.x; }
  bool operator<=(const Mint &a) const { return x <= a.x; }
  bool operator>(const Mint &a) const { return x > a.x; }
  bool operator>=(const Mint &a) const { return x >= a.x; }
  bool operator==(const Mint &a) const { return x == a.x; }
  bool operator!=(const Mint &a) const { return !(*this == a); }
  const Mint power(ll N)
  {
    if (N == 0)
    {
      return 1;
    }
    else if (N % 2 == 1)
    {
      return *this * power(N - 1);
    }
    else
    {
      Mint half = power(N / 2);
      return half * half;
    }
  }
};
template <ll MOD>
Mint<MOD> operator+(ll lhs, const Mint<MOD> &rhs)
{
  return rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator-(ll lhs, const Mint<MOD> &rhs)
{
  return -rhs + lhs;
}
template <ll MOD>
Mint<MOD> operator*(ll lhs, const Mint<MOD> &rhs)
{
  return rhs * lhs;
}
template <ll MOD>
Mint<MOD> operator/(ll lhs, const Mint<MOD> &rhs)
{
  return Mint<MOD>{lhs} / rhs;
}
template <ll MOD>
istream &operator>>(istream &stream, Mint<MOD> &a)
{
  return stream >> a.x;
}
template <ll MOD>
ostream &operator<<(ostream &stream, const Mint<MOD> &a)
{
  return stream << a.x;
}
// ----- Combination -----
template <ll MOD = MOD, ll MAX_SIZE = MAX_SIZE>
class Combination
{
public:
  vector<Mint<MOD>> inv, fact, factinv;
  Combination() : inv(MAX_SIZE), fact(MAX_SIZE), factinv(MAX_SIZE)
  {
    inv[1] = 1;
    for (auto i = 2LL; i < MAX_SIZE; i++)
    {
      inv[i] = (-inv[MOD % i]) * (MOD / i);
    }
    fact[0] = factinv[0] = 1;
    for (auto i = 1LL; i < MAX_SIZE; i++)
    {
      fact[i] = Mint<MOD>(i) * fact[i - 1];
      factinv[i] = inv[i] * factinv[i - 1];
    }
  }
  Mint<MOD> operator()(int n, int k)
  {
    if (n >= 0 && k >= 0 && n - k >= 0)
    {
      return fact[n] * factinv[k] * factinv[n - k];
    }
    return 0;
  }
  Mint<MOD> catalan(int x, int y)
  {
    return (*this)(x + y, y) - (*this)(x + y, y - 1);
  }
};
// ----- for C++14 -----
using mint = Mint<MOD>;
using combination = Combination<MOD, MAX_SIZE>;
ll gcd(ll x, ll y) { return y ? gcd(y, x % y) : x; }
// ----- frequently used constexpr -----
// constexpr double epsilon{1e-10};
// constexpr ll infty{1000000000000000LL};
// constexpr int dx[4] = {1, 0, -1, 0};
// constexpr int dy[4] = {0, 1, 0, -1};
// ----- Yes() and No() -----
void Yes()
{
  cout << "Yes" << endl;
  exit(0);
}
void No()
{
  cout << "No" << endl;
  exit(0);
}

// ----- PrimeNums -----

class PrimeNums
{
  static constexpr ll MAX_SIZE{1000010LL};
  ll N;
  vector<bool> isprime;
  vector<int> prime_nums;

public:
  PrimeNums(ll N = MAX_SIZE) : N{N}, isprime(N, true), prime_nums{}
  {
    isprime[0] = isprime[1] = false;
    for (auto i = 2; i < N; i++)
    {
      if (isprime[i])
      {
        prime_nums.push_back(i);
        for (auto j = 2 * i; j < N; j += i)
        {
          isprime[j] = false;
        }
      }
    }
  }

  bool is_prime(long long x)
  { // 2 \leq x \leq MAX_SIZE^2
    if (x < N)
    {
      return isprime[x];
    }
    for (auto e : prime_nums)
    {
      if (x % e == 0)
        return false;
    }
    return true;
  }

  vector<int> const &primes() const
  {
    return prime_nums;
  }
};

// ----- main() -----
class Solve
{
  int H, W;
  vector<string> S;
  PrimeNums pn;

public:
  Solve(int H, int W, vector<string> const &S) : H{H}, W{W}, S(S), pn{} {}

  int calc()
  {
    int ans{0};
    for (auto i = 0; i < H; i++)
    {
      ans += calc(S[i]);
    }
    return ans;
  };

private:
  int calc(string const &T)
  {
    if (is_zero(T))
    {
      return 0;
    }
    auto V{make_vec(T)};
#if DEBUG == 1
    cerr << "V = {";
    for (auto x : V)
    {
      cerr << x << ", ";
    }
    cerr << "}" << endl;
#endif
    if (is_one(V))
    {
      return 1;
    }
    if (is_two(V))
    {
      return 2;
    }
    return 3;
  }

  bool is_zero(string const &T)
  {
    for (auto x : T)
    {
      if (x == '.')
      {
        return false;
      }
    }
    return true;
  }

  vector<int> make_vec(string const &T)
  {
    int first{-1};
    vector<int> V;
    for (auto i = 0; i < W; i++)
    {
      if (T[i] == '.')
      {
        if (first == -1)
        {
          first = i;
        }
        V.push_back(i - first);
      }
    }
    return V;
  }

  bool is_one(vector<int> const &V)
  {
    if (V.size() < size_t{2})
    {
      return true;
    }
    assert(V[0] == 0);
    int g{V[1]};
    for (auto it = V.begin() + 1; it != V.end(); it++)
    {
      g = gcd(g, *it);
    }
    for (auto i = 0; i < 20; i++)
    {
      if ((g >> i) == 1)
      {
        return false;
      }
    }
    return true;
  }

  bool is_two(vector<int> const &V)
  {
    for (auto it = pn.primes().begin() + 1; it != pn.primes().end(); it++)
    {
      int p{static_cast<int>(*it)};
      int X{static_cast<int>(V.size())};
      if (W / p + 1 < X / 2)
      {
        return false;
      }
      for (auto k = 0; k < 2; k++)
      {
        int m{V[k]};
        int first{-1};
        vector<int> W;
        for (auto x : V)
        {
          if ((x - m) % p == 0)
          {
            continue;
          }
          if (first == -1)
          {
            first = x;
          }
          W.push_back(x - first);
        }
#if DEBUG == 1
        cerr << "p = " << p << ", m = " << m << endl;
        cerr << "W = {";
        for (auto x : W)
        {
          cerr << x << ", ";
        }
        cerr << "}" << endl;
#endif
        if (is_one(W))
        {
          return true;
        }
      }
    }
    assert(false);
    return false;
  }
};

int main()
{
  int H, W;
  cin >> H >> W;
  vector<string> S(H);
  for (auto i = 0; i < H; i++)
  {
    cin >> S[i];
  }
  Solve solve(H, W, S);
  cout << solve.calc() << endl;
}
<|endoftext|>


<commit_before>#include "AliReaderAOD.h"
//______________________________________________________________________________
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// class AliReaderAOD                                                         //
//                                                                            //
// Reader and Writer for AOD format.                                          //
// AODs are stored in a tree named by the variable fgkTreeName.               //
// There is stored 1 or 2 branches. Each of them stores AOD objects           //
// First branch is named by the variable fgkReconstructedDataBranchName       //
// ("reconstructed.") and keeps reconstructed data.                           //
// Second branch is called by the variable fgkSimulatedDataBranchName         //
// ("simulated.") and stores Monte carlo truth. If both branches are present  //
// AODs are parallel, i.e. nth particle in one branch corresponds to the nth  //
// particle in the other one.                                                 //
//                                                                            //
// Since we accept different formats of particles that are stored in AODs     //
// reader must take care of that fact: clean buffer if the next file contains //
// different particle type.                                                   //
//                                                                            //
// Piotr.Skowronski@cern.ch                                                   //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

ClassImp(AliReaderAOD)

#include <TError.h>
#include <TFile.h>
#include <TTree.h>
#include <TH1.h>
#include "AliAOD.h"

const TString AliReaderAOD::fgkTreeName("TAOD");
const TString AliReaderAOD::fgkReconstructedDataBranchName("reconstructed.");
const TString AliReaderAOD::fgkSimulatedDataBranchName("simulated.");

AliReaderAOD::AliReaderAOD(const Char_t* aodfilename):
 fFileName(aodfilename),
 fReadSim(kFALSE),
 fReadRec(kTRUE),
 fTree(0x0),
 fFile(0x0),
 fSimBuffer(0x0),
 fRecBuffer(0x0)
{
  //ctor
}
/********************************************************************/

AliReaderAOD::~AliReaderAOD()
{
//dtor
  if (fEventSim == fSimBuffer )
   {
    fEventSim = 0x0;
    fEventRec = 0x0;
   }
  delete fSimBuffer;
  delete fRecBuffer;

  delete fTree;
  delete fFile;
}
/********************************************************************/

void AliReaderAOD::Rewind()
{
//Rewinds reading
  delete fTree;
  fTree = 0x0;
  delete fFile;
  fFile = 0x0;
  fCurrentDir = 0;
  fNEventsRead= 0;
}
/********************************************************************/
Int_t AliReaderAOD::ReadNext()
{
//Reads next event

  Info("ReadNext","Entered");
  do  //do{}while; is OK even if 0 dirs specified. In that case we try to read from "./"
    {
      if (fFile == 0x0)
       {
         Int_t openfailed = OpenFile(fCurrentDir);//rl is opened here
         if (openfailed)
           {
             //Error("ReadNext","Error Occured while opening directory number %d",fCurrentDir);
             fCurrentDir++;
             continue;
           }
         fCurrentEvent = 0;
       }
      //Tree must exist because OpenFile would reuturn error in the other case
      if ( fCurrentEvent >= fTree->GetEntries() )
       {
         delete fTree;
         fTree = 0x0;
         delete fFile;
         fFile = 0x0;
         fSimBuffer = 0x0;
         fRecBuffer = 0x0;
         fCurrentDir++;
         continue;
       }

      Info("ReadNext","Getting event %d",fCurrentEvent);
      fTree->GetEvent(fCurrentEvent);
      Info("ReadNext","Getting event %d Done",fCurrentEvent);

      Int_t retval = 0;
      if (fReadRec && fReadSim)
       {
         retval = ReadRecAndSim();
       }
      else
       {
         if (fReadRec) retval = ReadRec();
         if (fReadSim) retval = ReadSim();
       }

      fCurrentEvent++;
      if (retval == 0) fNEventsRead++;

      return retval;//success -> read one event

    }while(fCurrentDir < GetNumberOfDirs());//end of loop over directories specified in fDirs Obj Array

  return 1; //no more directories to read

}
/********************************************************************/

Int_t AliReaderAOD::ReadRecAndSim()
{
//Reads raconstructed and simulated data

 Info("ReadRecAndSim","Found %d reconstructed tracks and %d simulated particles",
       fRecBuffer->GetNumberOfParticles(),fSimBuffer->GetNumberOfParticles());

 if (fCuts->GetEntriesFast() == 0x0)
  {//if there is no cuts we return pointer to the buffer
    if (fEventRec != fRecBuffer)
     {
       delete fEventRec;
       delete fEventSim;
     }
    fEventRec = fRecBuffer;//fEventRec is the pointer that the user gets when he asks about an event
    fEventSim = fSimBuffer;
  }
 else
  {//if there are cuts specified
    if ( (fEventRec == 0x0) || (fEventRec == fRecBuffer) )
     {//we need to create a new event, if it is not existing  or it is the same as branch buffer
       fEventRec = new AliAOD();
       fEventSim = new AliAOD();

       fEventRec->SetParticleClass( fRecBuffer->GetParticleClass() );
       fEventSim->SetParticleClass( fSimBuffer->GetParticleClass() );
     }
    else
     {//or simply reset it in case it already exists
       fEventRec->Reset();
       fEventSim->Reset();
     }

    Int_t npart = fRecBuffer->GetNumberOfParticles();
    for (Int_t i = 0; i < npart; i++)
     {
       AliVAODParticle* prec = fRecBuffer->GetParticle(i);
       if (Rejected(prec)) continue;//we make cuts only on simulated data

       fEventRec->AddParticle(prec);
       fEventSim->AddParticle( fSimBuffer->GetParticle(i));
     }
  }

 Info("ReadRecAndSim","Read %d reconstructed tracks and %d simulated particles",
       fEventRec->GetNumberOfParticles(),fEventSim->GetNumberOfParticles());

 fTrackCounter->Fill(fEventRec->GetNumberOfParticles());

 return 0;
}
/********************************************************************/

Int_t AliReaderAOD::ReadRec()
{
//Reads reconstructed data only

 Info("ReadRec","Found %d reconstructed tracks",fRecBuffer->GetNumberOfParticles());

 if (fCuts->GetEntriesFast() == 0x0)
  {//if there is no cuts we return pointer to the buffer
    if (fEventRec != fRecBuffer)
     {
       delete fEventRec;
     }
    fEventRec = fRecBuffer;//fEventRec is the pointer that the user gets when he asks about an event
  }
 else
  {//if there are cuts specified
    if ( (fEventRec == 0x0) || (fEventRec == fRecBuffer) )
     {//we need to create a new event, if it is not existing  or it is the same as branch buffer
       fEventRec = new AliAOD();

       fEventRec->SetParticleClass( fRecBuffer->GetParticleClass() );
     }
    else
     {//or simply reset it in case it already exists
       fEventRec->Reset();
     }

    Int_t npart = fRecBuffer->GetNumberOfParticles();
    for (Int_t i = 0; i < npart; i++)
     {
       AliVAODParticle* prec = fRecBuffer->GetParticle(i);
       if (Rejected(prec)) continue;//we make cuts only on simulated data

       fEventRec->AddParticle(prec);
     }
  }

 Info("ReadRec","Read %d reconstructed tracks",fEventRec->GetNumberOfParticles());
 fTrackCounter->Fill(fEventRec->GetNumberOfParticles());

 return 0;
}
/********************************************************************/

Int_t AliReaderAOD::ReadSim()
{
//Reads simulated data only

 Info("ReadSim","Found %d simulated particles",fSimBuffer->GetNumberOfParticles());

 if (fCuts->GetEntriesFast() == 0x0)
  {//if there is no cuts we return pointer to the buffer
    if (fEventSim != fSimBuffer)
     {
       delete fEventSim;
     }
    fEventSim = fSimBuffer;
  }
 else
  {//if there are cuts specified
    if ( (fEventSim == 0x0) || (fEventSim == fSimBuffer) )
     {//we need to create a new event, if it is not existing  or it is the same as branch buffer
       fEventSim = new AliAOD();

       fEventSim->SetParticleClass( fSimBuffer->GetParticleClass() );
     }
    else
     {//or simply reset it in case it already exists
       fEventSim->Reset();
     }

    Int_t npart = fSimBuffer->GetNumberOfParticles();
    for (Int_t i = 0; i < npart; i++)
     {
       AliVAODParticle* prec = fSimBuffer->GetParticle(i);
       if (Rejected(prec)) continue;//we make cuts only on simulated data
       fEventSim->AddParticle(prec);
     }
  }

 Info("ReadSim","Read %d simulated particles",fEventSim->GetNumberOfParticles());
 fTrackCounter->Fill(fEventSim->GetNumberOfParticles());

 return 0;
}
/********************************************************************/

Int_t AliReaderAOD::OpenFile(Int_t n)
{
//opens fFile with  tree

// Info("ReadNext","Opening File %d",n);
 const TString dirname = GetDirName(n);
 if (dirname == "")
  {
    if (AliVAODParticle::GetDebug() > 2 )
      {
        Info("OpenFile","Got empty string as a directory name.");
      }
   return 1;
  }

 TString filename = dirname +"/"+ fFileName;
 fFile = TFile::Open(filename.Data());
 if ( fFile == 0x0)
  {
    Error("OpenFile","Can't open fFile %s",filename.Data());
    return 2;
  }
 if (!fFile->IsOpen())
  {
    Error("OpenFile","Can't open fFile  %s",filename.Data());
    delete fFile;
    fFile = 0x0;
    return 3;
  }

 Info("ReadNext","File Is Opened, Getting the TREE");

 fTree = dynamic_cast<TTree*>(fFile->Get(fgkTreeName));
 if (fTree == 0x0)
  {
    if (AliVAODParticle::GetDebug() > 2 )
      {
        Info("ReadNext","Can not find TTree object named %s",fgkTreeName.Data());
      }
    delete fFile;
    fFile = 0x0;
    return 4;
  }

//  Info("ReadNext","Got TREE, Setting branch addresses");

  if (fReadRec)
   {
     TBranch* branch = fTree->GetBranch(fgkReconstructedDataBranchName);
     if (branch == 0x0)
      {
        Error("OpenFile","Can not find branch %s in file %s",
              fgkReconstructedDataBranchName.Data(),filename.Data());

        delete fTree;
        fTree = 0x0;
        delete fFile;
        fFile = 0x0;
        return 5;
      }
     fTree->SetBranchAddress(fgkReconstructedDataBranchName,&fRecBuffer);
   }

  if (fReadSim)
   {
     TBranch* branch = fTree->GetBranch(fgkSimulatedDataBranchName);
     if (branch == 0x0)
      {
        Error("OpenFile","Can not find branch %s in file %s",
              fgkSimulatedDataBranchName.Data(),filename.Data());

        delete fTree;
        fTree = 0x0;
        delete fFile;
        fFile = 0x0;
        return 6;
      }
     fTree->SetBranchAddress(fgkSimulatedDataBranchName,&fSimBuffer);
   }
//  Info("ReadNext","Got TREE, Addresses are set.");
//  Info("ReadNext","Quitting the method.");

  return 0;

}
/********************************************************************/

Int_t AliReaderAOD::WriteAOD(AliReader* reader, const char* outfilename, const char* pclassname,  Bool_t /*multcheck*/)
{
//reads tracks from runs and writes them to file
  ::Info("AliReaderAOD::Write","________________________________________________________");
  ::Info("AliReaderAOD::Write","________________________________________________________");
  ::Info("AliReaderAOD::Write","________________________________________________________");

  if (reader == 0x0)
   {
     ::Error("AliReaderAOD::Write","Input Reader is NULL");
     return -1;
   }
  TFile *outfile = TFile::Open(outfilename,"recreate");
  if (outfile == 0x0)
   {
     ::Error("AliReaderAOD::Write","Can not open output file %s",outfilename);
     return -1;
   }

  TTree *tree = new TTree(fgkTreeName,"Tree with tracks");

  TBranch *recbranch = 0x0, *simbranch = 0x0;

  AliAOD* eventrec = new AliAOD();//must be created before Branch is called. Otherwise clones array is not splitted
  AliAOD* eventsim = new AliAOD();//AOD together with fParticles clones array knowing exact type of particles

  eventrec->SetParticleClassName(pclassname);
  eventsim->SetParticleClassName(pclassname);

  AliAOD* recbuffer = eventrec;
  AliAOD* simbuffer = eventsim;

  if (reader->ReadsRec()) recbranch = tree->Branch(fgkReconstructedDataBranchName,"AliAOD",&recbuffer,32000,99);
  if (reader->ReadsSim()) simbranch = tree->Branch(fgkSimulatedDataBranchName,"AliAOD",&simbuffer,32000,99);

  reader->Rewind();
  while (reader->Next() == kFALSE)
   {

     if (reader->ReadsRec())
      {//here we can get AOD that has different particle type
        AliAOD* event = reader->GetEventRec();
        if ( eventrec->GetParticleClass() != event->GetParticleClass() )
         {//if class type is not what what we whant we copy particles
           eventrec->CopyData(event);
           recbuffer = eventrec;
         }
        else
         {//else just pointer to event from input reader is passed
           recbuffer = event;
         }
      }

     if (reader->ReadsSim())
      {
        AliAOD* event = reader->GetEventSim();
        if ( eventsim->GetParticleClass() != event->GetParticleClass() )
         {//if class type is not what what we whant we copy particles
           eventsim->CopyData(event);
           simbuffer = eventrec;
         }
        else
         {//else just pointer to event from input reader is passed
           simbuffer = event;
         }
      }
     recbuffer->GetParticle(0)->Print();
     simbuffer->GetParticle(0)->Print();
     tree->Fill();
   }

  ::Info("AliReaderAOD::Write","Written %d events",tree->GetEntries());
  outfile->cd();
  tree->Write();

  delete eventsim;
  delete eventrec;

  delete tree;
  delete outfile;
  return 0;
}

<commit_msg>Bug correction. (C.Finck)<commit_after>#include "AliReaderAOD.h"
//______________________________________________________________________________
////////////////////////////////////////////////////////////////////////////////
//                                                                            //
// class AliReaderAOD                                                         //
//                                                                            //
// Reader and Writer for AOD format.                                          //
// AODs are stored in a tree named by the variable fgkTreeName.               //
// There is stored 1 or 2 branches. Each of them stores AOD objects           //
// First branch is named by the variable fgkReconstructedDataBranchName       //
// ("reconstructed.") and keeps reconstructed data.                           //
// Second branch is called by the variable fgkSimulatedDataBranchName         //
// ("simulated.") and stores Monte carlo truth. If both branches are present  //
// AODs are parallel, i.e. nth particle in one branch corresponds to the nth  //
// particle in the other one.                                                 //
//                                                                            //
// Since we accept different formats of particles that are stored in AODs     //
// reader must take care of that fact: clean buffer if the next file contains //
// different particle type.                                                   //
//                                                                            //
// Piotr.Skowronski@cern.ch                                                   //
//                                                                            //
////////////////////////////////////////////////////////////////////////////////

ClassImp(AliReaderAOD)

#include <TError.h>
#include <TFile.h>
#include <TTree.h>
#include <TH1.h>
#include "AliAOD.h"

const TString AliReaderAOD::fgkTreeName("TAOD");
const TString AliReaderAOD::fgkReconstructedDataBranchName("reconstructed.");
const TString AliReaderAOD::fgkSimulatedDataBranchName("simulated.");

AliReaderAOD::AliReaderAOD(const Char_t* aodfilename):
 fFileName(aodfilename),
 fReadSim(kFALSE),
 fReadRec(kTRUE),
 fTree(0x0),
 fFile(0x0),
 fSimBuffer(0x0),
 fRecBuffer(0x0)
{
  //ctor
}
/********************************************************************/

AliReaderAOD::~AliReaderAOD()
{
//dtor
  if (fEventSim == fSimBuffer )
   {
    fEventSim = 0x0;
    fEventRec = 0x0;
   }
  delete fSimBuffer;
  delete fRecBuffer;

  delete fTree;
  delete fFile;
}
/********************************************************************/

void AliReaderAOD::Rewind()
{
//Rewinds reading
  delete fTree;
  fTree = 0x0;
  delete fFile;
  fFile = 0x0;
  fCurrentDir = 0;
  fNEventsRead= 0;
}
/********************************************************************/
Int_t AliReaderAOD::ReadNext()
{
//Reads next event

  Info("ReadNext","Entered");
  do  //do{}while; is OK even if 0 dirs specified. In that case we try to read from "./"
    {
      if (fFile == 0x0)
       {
         Int_t openfailed = OpenFile(fCurrentDir);//rl is opened here
         if (openfailed)
           {
             //Error("ReadNext","Error Occured while opening directory number %d",fCurrentDir);
             fCurrentDir++;
             continue;
           }
         fCurrentEvent = 0;
       }
      //Tree must exist because OpenFile would reuturn error in the other case
      if ( fCurrentEvent >= fTree->GetEntries() )
       {
         delete fTree;
         fTree = 0x0;
         delete fFile;
         fFile = 0x0;
         fSimBuffer = 0x0;
         fRecBuffer = 0x0;
         fCurrentDir++;
         continue;
       }

      Info("ReadNext","Getting event %d",fCurrentEvent);
      fTree->GetEvent(fCurrentEvent);
      Info("ReadNext","Getting event %d Done",fCurrentEvent);

      Int_t retval = 0;
      if (fReadRec && fReadSim)
       {
         retval = ReadRecAndSim();
       }
      else
       {
         if (fReadRec) retval = ReadRec();
         if (fReadSim) retval = ReadSim();
       }

      fCurrentEvent++;
      if (retval == 0) fNEventsRead++;

      return retval;//success -> read one event

    }while(fCurrentDir < GetNumberOfDirs());//end of loop over directories specified in fDirs Obj Array

  return 1; //no more directories to read

}
/********************************************************************/

Int_t AliReaderAOD::ReadRecAndSim()
{
//Reads raconstructed and simulated data

 Info("ReadRecAndSim","Found %d reconstructed tracks and %d simulated particles",
       fRecBuffer->GetNumberOfParticles(),fSimBuffer->GetNumberOfParticles());

 if (fCuts->GetEntriesFast() == 0x0)
  {//if there is no cuts we return pointer to the buffer
    if (fEventRec != fRecBuffer)
     {
       delete fEventRec;
       delete fEventSim;
     }
    fEventRec = fRecBuffer;//fEventRec is the pointer that the user gets when he asks about an event
    fEventSim = fSimBuffer;
  }
 else
  {//if there are cuts specified
    if ( (fEventRec == 0x0) || (fEventRec == fRecBuffer) )
     {//we need to create a new event, if it is not existing  or it is the same as branch buffer
       fEventRec = new AliAOD();
       fEventSim = new AliAOD();

       fEventRec->SetParticleClass( fRecBuffer->GetParticleClass() );
       fEventSim->SetParticleClass( fSimBuffer->GetParticleClass() );
     }
    else
     {//or simply reset it in case it already exists
       fEventRec->Reset();
       fEventSim->Reset();
     }

    Int_t npart = fRecBuffer->GetNumberOfParticles();
    for (Int_t i = 0; i < npart; i++)
     {
       AliVAODParticle* prec = fRecBuffer->GetParticle(i);
       if (Rejected(prec)) continue;//we make cuts only on simulated data

       fEventRec->AddParticle(prec);
       fEventSim->AddParticle( fSimBuffer->GetParticle(i));
     }
  }

 Info("ReadRecAndSim","Read %d reconstructed tracks and %d simulated particles",
       fEventRec->GetNumberOfParticles(),fEventSim->GetNumberOfParticles());

 fTrackCounter->Fill(fEventRec->GetNumberOfParticles());

 return 0;
}
/********************************************************************/

Int_t AliReaderAOD::ReadRec()
{
//Reads reconstructed data only

 Info("ReadRec","Found %d reconstructed tracks",fRecBuffer->GetNumberOfParticles());

 if (fCuts->GetEntriesFast() == 0x0)
  {//if there is no cuts we return pointer to the buffer
    if (fEventRec != fRecBuffer)
     {
       delete fEventRec;
     }
    fEventRec = fRecBuffer;//fEventRec is the pointer that the user gets when he asks about an event
  }
 else
  {//if there are cuts specified
    if ( (fEventRec == 0x0) || (fEventRec == fRecBuffer) )
     {//we need to create a new event, if it is not existing  or it is the same as branch buffer
       fEventRec = new AliAOD();

       fEventRec->SetParticleClass( fRecBuffer->GetParticleClass() );
     }
    else
     {//or simply reset it in case it already exists
       fEventRec->Reset();
     }

    Int_t npart = fRecBuffer->GetNumberOfParticles();
    for (Int_t i = 0; i < npart; i++)
     {
       AliVAODParticle* prec = fRecBuffer->GetParticle(i);
       if (Rejected(prec)) continue;//we make cuts only on simulated data

       fEventRec->AddParticle(prec);
     }
  }

 Info("ReadRec","Read %d reconstructed tracks",fEventRec->GetNumberOfParticles());
 fTrackCounter->Fill(fEventRec->GetNumberOfParticles());

 return 0;
}
/********************************************************************/

Int_t AliReaderAOD::ReadSim()
{
//Reads simulated data only

 Info("ReadSim","Found %d simulated particles",fSimBuffer->GetNumberOfParticles());

 if (fCuts->GetEntriesFast() == 0x0)
  {//if there is no cuts we return pointer to the buffer
    if (fEventSim != fSimBuffer)
     {
       delete fEventSim;
     }
    fEventSim = fSimBuffer;
  }
 else
  {//if there are cuts specified
    if ( (fEventSim == 0x0) || (fEventSim == fSimBuffer) )
     {//we need to create a new event, if it is not existing  or it is the same as branch buffer
       fEventSim = new AliAOD();

       fEventSim->SetParticleClass( fSimBuffer->GetParticleClass() );
     }
    else
     {//or simply reset it in case it already exists
       fEventSim->Reset();
     }

    Int_t npart = fSimBuffer->GetNumberOfParticles();
    for (Int_t i = 0; i < npart; i++)
     {
       AliVAODParticle* prec = fSimBuffer->GetParticle(i);
       if (Rejected(prec)) continue;//we make cuts only on simulated data
       fEventSim->AddParticle(prec);
     }
  }

 Info("ReadSim","Read %d simulated particles",fEventSim->GetNumberOfParticles());
 fTrackCounter->Fill(fEventSim->GetNumberOfParticles());

 return 0;
}
/********************************************************************/

Int_t AliReaderAOD::OpenFile(Int_t n)
{
//opens fFile with  tree

// Info("ReadNext","Opening File %d",n);
 const TString dirname = GetDirName(n);
 if (dirname == "")
  {
    if (AliVAODParticle::GetDebug() > 2 )
      {
        Info("OpenFile","Got empty string as a directory name.");
      }
   return 1;
  }

 TString filename = dirname +"/"+ fFileName;
 fFile = TFile::Open(filename.Data());
 if ( fFile == 0x0)
  {
    Error("OpenFile","Can't open fFile %s",filename.Data());
    return 2;
  }
 if (!fFile->IsOpen())
  {
    Error("OpenFile","Can't open fFile  %s",filename.Data());
    delete fFile;
    fFile = 0x0;
    return 3;
  }

 Info("ReadNext","File Is Opened, Getting the TREE");

 fTree = dynamic_cast<TTree*>(fFile->Get(fgkTreeName));
 if (fTree == 0x0)
  {
    if (AliVAODParticle::GetDebug() > 2 )
      {
        Info("ReadNext","Can not find TTree object named %s",fgkTreeName.Data());
      }
    delete fFile;
    fFile = 0x0;
    return 4;
  }

//  Info("ReadNext","Got TREE, Setting branch addresses");

  if (fReadRec)
   {
     TBranch* branch = fTree->GetBranch(fgkReconstructedDataBranchName);
     if (branch == 0x0)
      {
        Error("OpenFile","Can not find branch %s in file %s",
              fgkReconstructedDataBranchName.Data(),filename.Data());

        delete fTree;
        fTree = 0x0;
        delete fFile;
        fFile = 0x0;
        return 5;
      }
     fTree->SetBranchAddress(fgkReconstructedDataBranchName,&fRecBuffer);
   }

  if (fReadSim)
   {
     TBranch* branch = fTree->GetBranch(fgkSimulatedDataBranchName);
     if (branch == 0x0)
      {
        Error("OpenFile","Can not find branch %s in file %s",
              fgkSimulatedDataBranchName.Data(),filename.Data());

        delete fTree;
        fTree = 0x0;
        delete fFile;
        fFile = 0x0;
        return 6;
      }
     fTree->SetBranchAddress(fgkSimulatedDataBranchName,&fSimBuffer);
   }
//  Info("ReadNext","Got TREE, Addresses are set.");
//  Info("ReadNext","Quitting the method.");

  return 0;

}
/********************************************************************/

Int_t AliReaderAOD::WriteAOD(AliReader* reader, const char* outfilename, const char* pclassname,  Bool_t /*multcheck*/)
{
//reads tracks from runs and writes them to file
  ::Info("AliReaderAOD::Write","________________________________________________________");
  ::Info("AliReaderAOD::Write","________________________________________________________");
  ::Info("AliReaderAOD::Write","________________________________________________________");

  if (reader == 0x0)
   {
     ::Error("AliReaderAOD::Write","Input Reader is NULL");
     return -1;
   }
  TFile *outfile = TFile::Open(outfilename,"recreate");
  if (outfile == 0x0)
   {
     ::Error("AliReaderAOD::Write","Can not open output file %s",outfilename);
     return -1;
   }

  TTree *tree = new TTree(fgkTreeName,"Tree with tracks");

  TBranch *recbranch = 0x0, *simbranch = 0x0;

  AliAOD* eventrec = new AliAOD();//must be created before Branch is called. Otherwise clones array is not splitted
  AliAOD* eventsim = new AliAOD();//AOD together with fParticles clones array knowing exact type of particles

  eventrec->SetParticleClassName(pclassname);
  eventsim->SetParticleClassName(pclassname);

  AliAOD* recbuffer = eventrec;
  AliAOD* simbuffer = eventsim;

  if (reader->ReadsRec()) recbranch = tree->Branch(fgkReconstructedDataBranchName,"AliAOD",&recbuffer,32000,99);
  if (reader->ReadsSim()) simbranch = tree->Branch(fgkSimulatedDataBranchName,"AliAOD",&simbuffer,32000,99);

  reader->Rewind();
  while (reader->Next() == kFALSE)
   {

     if (reader->ReadsRec())
      {//here we can get AOD that has different particle type
        AliAOD* event = reader->GetEventRec();
        if ( eventrec->GetParticleClass() != event->GetParticleClass() )
         {//if class type is not what what we whant we copy particles
           eventrec->CopyData(event);
           recbuffer = eventrec;
         }
        else
         {//else just pointer to event from input reader is passed
           recbuffer = event;
         }
	recbuffer->GetParticle(0)->Print();
      }

     if (reader->ReadsSim())
      {
        AliAOD* event = reader->GetEventSim();
        if ( eventsim->GetParticleClass() != event->GetParticleClass() )
         {//if class type is not what what we whant we copy particles
           eventsim->CopyData(event);
           simbuffer = eventrec;
         }
        else
         {//else just pointer to event from input reader is passed
           simbuffer = event;
         }
	simbuffer->GetParticle(0)->Print();
      }
     tree->Fill();
   }

  ::Info("AliReaderAOD::Write","Written %d events",tree->GetEntries());
  outfile->cd();
  tree->Write();

  delete eventsim;
  delete eventrec;

  delete tree;
  delete outfile;
  return 0;
}

<|endoftext|>


<commit_before>/*
	This file is part of cpp-ethereum.
	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerModel.cpp
 * @author Yann yann@ethdev.com
 * @date 2014
 * used as a model to debug contract assembly code.
 */

#include <QApplication>
#include <libdevcore/Common.h>
#include <libevm/VM.h>
#include <libethereum/Executive.h>
#include <libethereum/Transaction.h>
#include <libethereum/ExtVM.h>
#include "AppContext.h"
#include "TransactionListModel.h"
#include "AssemblyDebuggerModel.h"
#include "ConstantCompilationModel.h"
#include "DebuggingStateWrapper.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;

AssemblyDebuggerModel::AssemblyDebuggerModel():
	m_userAccount(KeyPair::create()),
	m_baseState(Address(), m_overlayDB, BaseState::Empty)
{
	m_baseState.addBalance(m_userAccount.address(), 10000000 * ether);
	m_executiveState = m_baseState;
	m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, LastHashes(), 0));
}

DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction)
{
	QList<DebuggingState> machineStates;
	m_currentExecution.reset(new Executive(m_executiveState, LastHashes(), 0));
	m_currentExecution->setup(_rawTransaction);
	std::vector<DebuggingState const*> levels;
	bytes code;
	bytesConstRef data;
	bool firstIteration = true;
	auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt)
	{
		VM& vm = *(VM*)voidVM;
		ExtVM const& ext = *(ExtVM const*)voidExt;

		if (firstIteration)
		{
			code = ext.code;
			data = ext.data;
			firstIteration = false;
		}

		if (levels.size() < ext.depth)
			levels.push_back(&machineStates.back());
		else
			levels.resize(ext.depth);

		machineStates.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
									  vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
	};

	m_currentExecution->go(onOp);
	m_currentExecution->finalize(onOp);
	m_executiveState.completeMine();

	DebuggingContent d;
	d.returnValue = m_currentExecution->out().toVector();
	d.machineStates = machineStates;
	d.executionCode = code;
	d.executionData = data;
	d.contentAvailable = true;
	d.message = "ok";
	return d;
}

DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code)
{
	u256 gasPrice = 10000000000000;
	u256 gas = 1000000;
	u256 amount = 100;
	Transaction _tr(amount, gasPrice, min(gas, m_baseState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
	bytes b = _tr.rlp();
	dev::bytesConstRef bytesRef = &b;
	DebuggingContent d = executeTransaction(bytesRef);
	h256 th = sha3(rlpList(_tr.sender(), _tr.nonce()));
	d.contractAddress = right160(th);
	return d;
}

DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)
{
	Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_baseState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
	bytes b = tr.rlp();
	dev::bytesConstRef bytesRef = &b;
	DebuggingContent d = executeTransaction(bytesRef);
	d.contractAddress = tr.receiveAddress();
	return d;
}

void AssemblyDebuggerModel::resetState()
{
	// Reset the state back to our clean premine.
	m_executiveState = m_baseState;
}
<commit_msg>Various fixes. Initial portion of NatSpec integration.<commit_after>/*
	This file is part of cpp-ethereum.
	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.
	cpp-ethereum is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.
	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/** @file AssemblyDebuggerModel.cpp
 * @author Yann yann@ethdev.com
 * @date 2014
 * used as a model to debug contract assembly code.
 */

#include <QApplication>
#include <libdevcore/Common.h>
#include <libevm/VM.h>
#include <libethereum/Executive.h>
#include <libethereum/Transaction.h>
#include <libethereum/ExtVM.h>
#include "AppContext.h"
#include "TransactionListModel.h"
#include "AssemblyDebuggerModel.h"
#include "ConstantCompilationModel.h"
#include "DebuggingStateWrapper.h"
using namespace std;
using namespace dev;
using namespace dev::eth;
using namespace dev::mix;

AssemblyDebuggerModel::AssemblyDebuggerModel():
	m_userAccount(KeyPair::create()),
	m_baseState(Address(), m_overlayDB, BaseState::Empty)
{
	m_baseState.addBalance(m_userAccount.address(), 10000000 * ether);
	m_executiveState = m_baseState;
	m_currentExecution = std::unique_ptr<Executive>(new Executive(m_executiveState, LastHashes(), 0));
}

DebuggingContent AssemblyDebuggerModel::executeTransaction(bytesConstRef const& _rawTransaction)
{
	QList<DebuggingState> machineStates;
	m_currentExecution.reset(new Executive(m_executiveState, LastHashes(), 0));
	m_currentExecution->setup(_rawTransaction);
	std::vector<DebuggingState const*> levels;
	bytes code;
	bytesConstRef data;
	bool firstIteration = true;
	auto onOp = [&](uint64_t steps, Instruction inst, dev::bigint newMemSize, dev::bigint gasCost, void* voidVM, void const* voidExt)
	{
		VM& vm = *(VM*)voidVM;
		ExtVM const& ext = *(ExtVM const*)voidExt;

		if (firstIteration)
		{
			code = ext.code;
			data = ext.data;
			firstIteration = false;
		}

		if (levels.size() < ext.depth)
			levels.push_back(&machineStates.back());
		else
			levels.resize(ext.depth);

		machineStates.append(DebuggingState({steps, ext.myAddress, vm.curPC(), inst, newMemSize, vm.gas(),
									  vm.stack(), vm.memory(), gasCost, ext.state().storage(ext.myAddress), levels}));
	};

	m_currentExecution->go(onOp);
	m_currentExecution->finalize();
	m_executiveState.completeMine();

	DebuggingContent d;
	d.returnValue = m_currentExecution->out().toVector();
	d.machineStates = machineStates;
	d.executionCode = code;
	d.executionData = data;
	d.contentAvailable = true;
	d.message = "ok";
	return d;
}

DebuggingContent AssemblyDebuggerModel::deployContract(bytes const& _code)
{
	u256 gasPrice = 10000000000000;
	u256 gas = 1000000;
	u256 amount = 100;
	Transaction _tr(amount, gasPrice, min(gas, m_baseState.gasLimitRemaining()), _code, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
	bytes b = _tr.rlp();
	dev::bytesConstRef bytesRef = &b;
	DebuggingContent d = executeTransaction(bytesRef);
	h256 th = sha3(rlpList(_tr.sender(), _tr.nonce()));
	d.contractAddress = right160(th);
	return d;
}

DebuggingContent AssemblyDebuggerModel::callContract(Address const& _contract, bytes const& _data, TransactionSettings const& _tr)
{
	Transaction tr = Transaction(_tr.value, _tr.gasPrice, min(_tr.gas, m_baseState.gasLimitRemaining()), _contract, _data, m_executiveState.transactionsFrom(dev::toAddress(m_userAccount.secret())), m_userAccount.secret());
	bytes b = tr.rlp();
	dev::bytesConstRef bytesRef = &b;
	DebuggingContent d = executeTransaction(bytesRef);
	d.contractAddress = tr.receiveAddress();
	return d;
}

void AssemblyDebuggerModel::resetState()
{
	// Reset the state back to our clean premine.
	m_executiveState = m_baseState;
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "AutoPacketFactoryTest.h"
#include "CoreThread.h"

class IssuesPacketWaitsThenQuits:
  public CoreThread
{
public:
  IssuesPacketWaitsThenQuits(void) :
    m_hasQuit(false)
  {
    // Note:  Don't do this in practice.  This only works because we only inject this type
    // into a context that's already running; normally, creating a packet from our ctor can
    // cause an exception if we are being injected before Initiate is called.
    AutoRequired<AutoPacketFactory> factory;
    m_packet = factory->NewPacket();
  }

  bool m_hasQuit;
  std::shared_ptr<AutoPacket> m_packet;

  void Run(void) override {
    // Move the shared pointer here:
    auto packet = std::move(m_packet);
    // After moving the object, reset it to a known state
    m_packet.reset();

    // Just wait a bit, then return, just like we said we would
    this->ThreadSleep(boost::chrono::milliseconds(50));

    // Update our variable and then return out:
    m_hasQuit = true;
  }
};

TEST_F(AutoPacketFactoryTest, VerifyNoIssueWhileNotStarted) {
  AutoRequired<AutoPacketFactory> factory;
  ASSERT_THROW(factory->NewPacket(), autowiring_error) << "Issuing a packet in a context that has not yet been started should throw an exception";
}

TEST_F(AutoPacketFactoryTest, StopReallyStops) {
  AutoCurrentContext()->SignalShutdown();

  AutoRequired<AutoPacketFactory> factory;
  ASSERT_TRUE(factory->ShouldStop()) << "Expected that an attempt to insert a packet factory to an already-stopped context would stop the packet factory";
}

TEST_F(AutoPacketFactoryTest, VerifyNoIssueWhileStopped) {
  AutoCurrentContext()->SignalShutdown();

  AutoRequired<AutoPacketFactory> factory;
  ASSERT_THROW(factory->NewPacket(), autowiring_error) << "Issuing a packet in a context that has already been stopped should throw an exception";
}

TEST_F(AutoPacketFactoryTest, WaitRunsDownAllPackets) {
  AutoCurrentContext()->Initiate();

  // Create a factory in our context, factory had better be started:
  AutoRequired<AutoPacketFactory> factory;
  ASSERT_TRUE(factory->IsRunning()) << "Factory was not started even though it was a member of an initiated context";

  // Make the thread create and hold a packet, and then return
  AutoRequired<IssuesPacketWaitsThenQuits> ipwtq;

  // Shutdown context
  AutoCurrentContext()->SignalShutdown();

  // Now we're going to try to run down the factory:
  factory->Wait();

  // Verify that the thread has quit:
  ASSERT_TRUE(ipwtq->m_hasQuit) << "AutoPacketFactory::Wait returned prematurely";
}

class HoldsAutoPacketFactoryReference {
public:
  HoldsAutoPacketFactoryReference(void):
    m_value(0)
  {}

  AutoRequired<AutoPacketFactory> m_factory;
  int m_value;

  // Just a dummy AutoFilter method so that this class is recognized as an AutoFilter
  void AutoFilter(int value) {
    m_value = value;
  }
};

TEST_F(AutoPacketFactoryTest, AutoPacketFactoryCycle) {
  std::weak_ptr<CoreContext> ctxtWeak;
  std::weak_ptr<HoldsAutoPacketFactoryReference> hapfrWeak;
  std::shared_ptr<AutoPacket> packet;

  {
    // Create a context, fill it up, kick it off:
    AutoCreateContext ctxt;
    AutoRequired<HoldsAutoPacketFactoryReference> hapfr(ctxt);
    ctxt->Initiate();

    // A weak pointer is used to detect object destruction
    ctxtWeak = ctxt;
    hapfrWeak = hapfr;

    // Trivial validation-of-reciept:
    AutoRequired<AutoPacketFactory> factory;
    {
      auto trivial = factory->NewPacket();
      trivial->Decorate((int) 54);
      ASSERT_EQ(54, hapfr->m_value) << "A simple packet was not received as expected by an AutoFilter";
    }

    // Create a packet which will force in a back-reference:
    packet = factory->NewPacket();

    // Terminate the context:
    ctxt->SignalShutdown();
  }

  // Verify that the context went out of scope as expected
  ASSERT_TRUE(ctxtWeak.expired()) << "AutoPacketFactory incorrectly held a cyclic reference even after the context was shut down";

  // Verify that we can still decorate the packet and also that the packet is delivered to the factory:
  packet->Decorate((int) 55);

  // Relock, verify the value was received by the hapfr:
  {
    auto locked = hapfrWeak.lock();
    ASSERT_TRUE(!!locked) << "Failed to lock a shared pointer which should not have been expired yet";
    ASSERT_EQ(55, locked->m_value) << "AutoFilter did not receive a packet as expected";
  }

  // Now we can release the packet and verify that everything gets cleaned up:
  packet.reset();
  ASSERT_TRUE(hapfrWeak.expired()) << "The last packet from a factory was released; this should have resulted in teardown, but it did not";
}<commit_msg>Updating tests to validate packet delivery while the context is still resident<commit_after>#include "stdafx.h"
#include "AutoPacketFactoryTest.h"
#include "CoreThread.h"

class IssuesPacketWaitsThenQuits:
  public CoreThread
{
public:
  IssuesPacketWaitsThenQuits(void) :
    m_hasQuit(false)
  {
    // Note:  Don't do this in practice.  This only works because we only inject this type
    // into a context that's already running; normally, creating a packet from our ctor can
    // cause an exception if we are being injected before Initiate is called.
    AutoRequired<AutoPacketFactory> factory;
    m_packet = factory->NewPacket();
  }

  bool m_hasQuit;
  std::shared_ptr<AutoPacket> m_packet;

  void Run(void) override {
    // Move the shared pointer here:
    auto packet = std::move(m_packet);
    // After moving the object, reset it to a known state
    m_packet.reset();

    // Just wait a bit, then return, just like we said we would
    this->ThreadSleep(boost::chrono::milliseconds(50));

    // Update our variable and then return out:
    m_hasQuit = true;
  }
};

TEST_F(AutoPacketFactoryTest, VerifyNoIssueWhileNotStarted) {
  AutoRequired<AutoPacketFactory> factory;
  ASSERT_THROW(factory->NewPacket(), autowiring_error) << "Issuing a packet in a context that has not yet been started should throw an exception";
}

TEST_F(AutoPacketFactoryTest, StopReallyStops) {
  AutoCurrentContext()->SignalShutdown();

  AutoRequired<AutoPacketFactory> factory;
  ASSERT_TRUE(factory->ShouldStop()) << "Expected that an attempt to insert a packet factory to an already-stopped context would stop the packet factory";
}

TEST_F(AutoPacketFactoryTest, VerifyNoIssueWhileStopped) {
  AutoCurrentContext()->SignalShutdown();

  AutoRequired<AutoPacketFactory> factory;
  ASSERT_THROW(factory->NewPacket(), autowiring_error) << "Issuing a packet in a context that has already been stopped should throw an exception";
}

TEST_F(AutoPacketFactoryTest, WaitRunsDownAllPackets) {
  AutoCurrentContext()->Initiate();

  // Create a factory in our context, factory had better be started:
  AutoRequired<AutoPacketFactory> factory;
  ASSERT_TRUE(factory->IsRunning()) << "Factory was not started even though it was a member of an initiated context";

  // Make the thread create and hold a packet, and then return
  AutoRequired<IssuesPacketWaitsThenQuits> ipwtq;

  // Shutdown context
  AutoCurrentContext()->SignalShutdown();

  // Now we're going to try to run down the factory:
  factory->Wait();

  // Verify that the thread has quit:
  ASSERT_TRUE(ipwtq->m_hasQuit) << "AutoPacketFactory::Wait returned prematurely";
}

class HoldsAutoPacketFactoryReference {
public:
  HoldsAutoPacketFactoryReference(void):
    m_value(0)
  {}

  AutoRequired<AutoPacketFactory> m_factory;
  int m_value;

  // Just a dummy AutoFilter method so that this class is recognized as an AutoFilter
  void AutoFilter(int value) {
    m_value = value;
  }
};

TEST_F(AutoPacketFactoryTest, AutoPacketFactoryCycle) {
  std::weak_ptr<CoreContext> ctxtWeak;
  std::weak_ptr<HoldsAutoPacketFactoryReference> hapfrWeak;
  std::shared_ptr<AutoPacket> packet;

  {
    // Create a context, fill it up, kick it off:
    AutoCreateContext ctxt;
    AutoRequired<HoldsAutoPacketFactoryReference> hapfr(ctxt);
    ctxt->Initiate();

    // A weak pointer is used to detect object destruction
    ctxtWeak = ctxt;
    hapfrWeak = hapfr;

    // Trivial validation-of-reciept:
    AutoRequired<AutoPacketFactory> factory;
    {
      auto trivial = factory->NewPacket();
      trivial->Decorate((int) 54);
      ASSERT_EQ(54, hapfr->m_value) << "A simple packet was not received as expected by an AutoFilter";
    }

    // Create a packet which will force in a back-reference:
    packet = factory->NewPacket();

    // Terminate the context:
    ctxt->SignalShutdown();

    // Verify that we can still decorate the packet and also that the packet is delivered to the factory:
    packet->Decorate((int) 55);

    // Relock, verify the value was received by the hapfr:
    ASSERT_EQ(55, hapfr->m_value) << "AutoFilter did not receive a packet as expected";
  }

  // Verify that the context went out of scope as expected
  ASSERT_TRUE(ctxtWeak.expired()) << "AutoPacketFactory incorrectly held a cyclic reference even after the context was shut down";

  // Now we can release the packet and verify that everything gets cleaned up:
  packet.reset();
  ASSERT_TRUE(hapfrWeak.expired()) << "The last packet from a factory was released; this should have resulted in teardown, but it did not";
}<|endoftext|>