<commit_before>#ifndef STORAGE_HH
#define STORAGE_HH

#include <fstream>
#include "khmer.hh"
#include "ktable.hh"
#include "hashtable.hh"

namespace khmer {
  class ReadMaskTable;
  unsigned long long output_filtered_fasta_file(const std::string &inputfile,
					  const std::string &outputfile,
					  ReadMaskTable * readmask,
					  CallbackFn callback = NULL,
					  void * callback_data = NULL);

  class ReadMaskTable {
  protected:
    const unsigned long long _tablesize;
    unsigned char * _mask;

    void _allocate(bool initialize=true) {
      _mask = new unsigned char[_tablesize];
      if (initialize) {
	for (unsigned long long i = 0; i < _tablesize; i++) {
	  _mask[i] = 1;
	}
      }
    }

  public:
    ReadMaskTable(unsigned long long tablesize) :
      _tablesize(tablesize), _mask(NULL) {
      _allocate();
    }

    ~ReadMaskTable() {
      if (_mask) { delete _mask; _mask = NULL; }
    }

    const unsigned long long get_tablesize() const {
      return _tablesize;
    }

    const unsigned long long n_kept() const {
      unsigned long long n = 0;
      for (unsigned long long i = 0; i < _tablesize; i++) {
	if (_mask[i]) { n++; }
      }
      return n;
    }

    const bool get(unsigned long long index) const {
      if (index >= _tablesize) { return false; } // @CTB throw?

      return _mask[index];
    }

    void set(unsigned long long index, bool keep) {
      if (index >= _tablesize) { return; } // @CTB throw?

#ifdef KHMER_THREADED
      __sync_add_and_fetch( _mask + index, (unsigned char)keep );
#else
      //_mask[index] = keep ? 1 : 0;
      _mask[index] = (unsigned char)keep;
#endif
    }

    void merge(ReadMaskTable &other) {
      if (this ->_tablesize != other._tablesize) { return; } // @CTB throw?

      for (unsigned long long i = 0; i < _tablesize; i++) {
	_mask[i] = _mask[i] && other._mask[i] ? 1 : 0;
      }
    }

    void invert() {
      for (unsigned long long i = 0; i < _tablesize; i++) {
	_mask[i] = !_mask[i];
      }
    }

    void save(const std::string &outputfile) {
      std::ofstream outfile;
      outfile.open(outputfile.c_str(), std::ofstream::binary);

      outfile.write((const char *) &_tablesize, sizeof(_tablesize));
      outfile.write((const char *) _mask, _tablesize);
      outfile.close();
    }

    void load(const std::string &inputfile) {
      std::ifstream infile;
      infile.open(inputfile.c_str(), std::ifstream::binary);

      infile.read((char *) &_tablesize, sizeof(_tablesize));
      _allocate(false);
      infile.read((char *) _mask, _tablesize);

      infile.close();
    }

    unsigned long long filter_fasta_file(const std::string &inputfile,
				   const std::string &outputfile,
				   CallbackFn callback = NULL,
				   void * callback_data = NULL) {
      return output_filtered_fasta_file(inputfile, outputfile, this,
					callback, callback_data);
    }
  };

  // ** //

  typedef struct {
    BoundedCounterType min_val;
    BoundedCounterType max_val;
  } MinMaxValue;

  class MinMaxTable {
  protected:
    const unsigned long long _tablesize;
    MinMaxValue * _table;

    void _allocate(bool initialize=true) {
      _table = new MinMaxValue[_tablesize];
      if (initialize) {
	memset(_table, 0, sizeof(MinMaxValue) * _tablesize);
      }
    }

  public:
    MinMaxTable(unsigned long long tablesize) :
      _tablesize(tablesize), _table(NULL) {
      _allocate();
    }

    ~MinMaxTable() {
      if (_table) { delete _table; _table = NULL; }
    }

    const unsigned long long get_tablesize() const {
      return _tablesize;
    }

    const BoundedCounterType get_min(unsigned long long index) const {
      assert(index < _tablesize);
      return _table[index].min_val;
    }

    const BoundedCounterType get_max(unsigned long long index) const {
      assert(index < _tablesize);
      return _table[index].max_val;
    }

    BoundedCounterType add_max(unsigned long long index, unsigned int val) {
      assert(index < _tablesize);

      if (val > MAX_COUNT) { val = MAX_COUNT; }

      MinMaxValue * mmv = &_table[index];

      if (val > mmv->max_val) {
	mmv->max_val = (unsigned char) val;
      }

      return mmv->max_val;
    }

    BoundedCounterType add_min(unsigned long long index, unsigned int val) {
      assert(index < _tablesize);

      if (val > MAX_COUNT) { val = MAX_COUNT; }

      MinMaxValue * mmv = &_table[index];

      if (val == 0) {
	;
      } else if (mmv->min_val == 0) {
	mmv->min_val = (unsigned char) val;
      } else if (val < mmv->min_val) {
	mmv->min_val = (unsigned char) val;
      }

      return mmv->min_val;
    }

    void clear(unsigned long long index) {
      assert(index < _tablesize);

      MinMaxValue * mmv = &_table[index];
      mmv->min_val = mmv->max_val = 0;
    }

    void merge(MinMaxTable &other) {
      assert(this->_tablesize == other._tablesize);
      for (unsigned long long i = 0; i < _tablesize; i++) {
	this->add_min(i, other.get_min(i));
	this->add_max(i, other.get_max(i));
      }
    }

    void save(const std::string &outputfile) const {
      std::ofstream outfile;
      outfile.open(outputfile.c_str(), std::ofstream::binary);

      outfile.write((const char *) &_tablesize, sizeof(_tablesize));
      outfile.write((const char *) _table, _tablesize * sizeof(MinMaxValue));
      outfile.close();
    }

    void load(const std::string &inputfile) {
      std::ifstream infile;
      infile.open(inputfile.c_str(), std::ifstream::binary);

      infile.read((char *) &_tablesize, sizeof(_tablesize));
      _allocate(false);
      infile.read((char *) _table, _tablesize * sizeof(MinMaxValue));

      infile.close();
    }
  };

}

#endif // STORAGE_HH

// vim: set sts=2 sw=2:
<commit_msg>Fix bug in thread-safe readmask setter. (Doh! It helps to use the atomic operation you intended (compare-and-swap) rather than the one your fingers actually wrote (add).) (Adding 0 to a variable having a value of 1 is not the same as setting that variable to 0. :-) The entire automated test suite now passes with the threaded code.<commit_after>#ifndef STORAGE_HH
#define STORAGE_HH

#include <fstream>
#include "khmer.hh"
#include "ktable.hh"
#include "hashtable.hh"

namespace khmer {
  class ReadMaskTable;
  unsigned long long output_filtered_fasta_file(const std::string &inputfile,
					  const std::string &outputfile,
					  ReadMaskTable * readmask,
					  CallbackFn callback = NULL,
					  void * callback_data = NULL);

  class ReadMaskTable {
  protected:
    const unsigned long long _tablesize;
    unsigned char * _mask;

    void _allocate(bool initialize=true) {
      _mask = new unsigned char[_tablesize];
      if (initialize) {
	for (unsigned long long i = 0; i < _tablesize; i++) {
	  _mask[i] = 1;
	}
      }
    }

  public:
    ReadMaskTable(unsigned long long tablesize) :
      _tablesize(tablesize), _mask(NULL) {
      _allocate();
    }

    ~ReadMaskTable() {
      if (_mask) { delete _mask; _mask = NULL; }
    }

    const unsigned long long get_tablesize() const {
      return _tablesize;
    }

    const unsigned long long n_kept() const {
      unsigned long long n = 0;
      for (unsigned long long i = 0; i < _tablesize; i++) {
	if (_mask[i]) { n++; }
      }
      return n;
    }

    const bool get(unsigned long long index) const {
      if (index >= _tablesize) { return false; } // @CTB throw?

      return _mask[index];
    }

    void set(unsigned long long index, bool keep) {
      if (index >= _tablesize) { return; } // @CTB throw?

#ifdef KHMER_THREADED
      __sync_val_compare_and_swap( _mask + index, (unsigned char)(!keep), (unsigned char)keep );
#else
      //_mask[index] = keep ? 1 : 0;
      _mask[index] = (unsigned char)keep;
#endif
    }

    void merge(ReadMaskTable &other) {
      if (this ->_tablesize != other._tablesize) { return; } // @CTB throw?

      for (unsigned long long i = 0; i < _tablesize; i++) {
	_mask[i] = _mask[i] && other._mask[i] ? 1 : 0;
      }
    }

    void invert() {
      for (unsigned long long i = 0; i < _tablesize; i++) {
	_mask[i] = !_mask[i];
      }
    }

    void save(const std::string &outputfile) {
      std::ofstream outfile;
      outfile.open(outputfile.c_str(), std::ofstream::binary);

      outfile.write((const char *) &_tablesize, sizeof(_tablesize));
      outfile.write((const char *) _mask, _tablesize);
      outfile.close();
    }

    void load(const std::string &inputfile) {
      std::ifstream infile;
      infile.open(inputfile.c_str(), std::ifstream::binary);

      infile.read((char *) &_tablesize, sizeof(_tablesize));
      _allocate(false);
      infile.read((char *) _mask, _tablesize);

      infile.close();
    }

    unsigned long long filter_fasta_file(const std::string &inputfile,
				   const std::string &outputfile,
				   CallbackFn callback = NULL,
				   void * callback_data = NULL) {
      return output_filtered_fasta_file(inputfile, outputfile, this,
					callback, callback_data);
    }
  };

  // ** //

  typedef struct {
    BoundedCounterType min_val;
    BoundedCounterType max_val;
  } MinMaxValue;

  class MinMaxTable {
  protected:
    const unsigned long long _tablesize;
    MinMaxValue * _table;

    void _allocate(bool initialize=true) {
      _table = new MinMaxValue[_tablesize];
      if (initialize) {
	memset(_table, 0, sizeof(MinMaxValue) * _tablesize);
      }
    }

  public:
    MinMaxTable(unsigned long long tablesize) :
      _tablesize(tablesize), _table(NULL) {
      _allocate();
    }

    ~MinMaxTable() {
      if (_table) { delete _table; _table = NULL; }
    }

    const unsigned long long get_tablesize() const {
      return _tablesize;
    }

    const BoundedCounterType get_min(unsigned long long index) const {
      assert(index < _tablesize);
      return _table[index].min_val;
    }

    const BoundedCounterType get_max(unsigned long long index) const {
      assert(index < _tablesize);
      return _table[index].max_val;
    }

    BoundedCounterType add_max(unsigned long long index, unsigned int val) {
      assert(index < _tablesize);

      if (val > MAX_COUNT) { val = MAX_COUNT; }

      MinMaxValue * mmv = &_table[index];

      if (val > mmv->max_val) {
	mmv->max_val = (unsigned char) val;
      }

      return mmv->max_val;
    }

    BoundedCounterType add_min(unsigned long long index, unsigned int val) {
      assert(index < _tablesize);

      if (val > MAX_COUNT) { val = MAX_COUNT; }

      MinMaxValue * mmv = &_table[index];

      if (val == 0) {
	;
      } else if (mmv->min_val == 0) {
	mmv->min_val = (unsigned char) val;
      } else if (val < mmv->min_val) {
	mmv->min_val = (unsigned char) val;
      }

      return mmv->min_val;
    }

    void clear(unsigned long long index) {
      assert(index < _tablesize);

      MinMaxValue * mmv = &_table[index];
      mmv->min_val = mmv->max_val = 0;
    }

    void merge(MinMaxTable &other) {
      assert(this->_tablesize == other._tablesize);
      for (unsigned long long i = 0; i < _tablesize; i++) {
	this->add_min(i, other.get_min(i));
	this->add_max(i, other.get_max(i));
      }
    }

    void save(const std::string &outputfile) const {
      std::ofstream outfile;
      outfile.open(outputfile.c_str(), std::ofstream::binary);

      outfile.write((const char *) &_tablesize, sizeof(_tablesize));
      outfile.write((const char *) _table, _tablesize * sizeof(MinMaxValue));
      outfile.close();
    }

    void load(const std::string &inputfile) {
      std::ifstream infile;
      infile.open(inputfile.c_str(), std::ifstream::binary);

      infile.read((char *) &_tablesize, sizeof(_tablesize));
      _allocate(false);
      infile.read((char *) _table, _tablesize * sizeof(MinMaxValue));

      infile.close();
    }
  };

}

#endif // STORAGE_HH

// vim: set sts=2 sw=2:
<|endoftext|>


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

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

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

 =========================================================================*/

// Includes
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

#include "otbMultiToMonoChannelExtractROI.h"
#include "otbGenericRSResampleImageFilter.h"
#include "otbGridResampleImageFilter.h"
#include "otbImportGeoInformationImageFilter.h"
#include "otbBCOInterpolateImageFunction.h"
#include "otbSimpleRcsPanSharpeningFusionImageFilter.h"
#include "itkFixedArray.h"
// Elevation handler
//#include "otbWrapperElevationParametersHandler.h"
#include "otbPleiadesPToXSAffineTransformCalculator.h"

#include "otbMPIConfig.h"

#include <cstdlib>
#include <iostream>
#include <boost/chrono/thread_clock.hpp>

// Test
int otbMPIBundleToPerfectSensorTest(int argc, char* argv[])
{
  // Mono-thread execution
  itk::MultiThreader::SetGlobalMaximumNumberOfThreads(1);
  itk::MultiThreader::SetGlobalDefaultNumberOfThreads(1);

  // Start chrono
  boost::chrono::thread_clock::time_point startTimer = boost::chrono::thread_clock::now();

  // MPI Initialization
  typedef otb::mpi::MPIConfig    MPIConfigType;
  MPIConfigType::Pointer config = MPIConfigType::New();
  config->Init(argc,argv,true);

  // Verify the number of parameters in the command line
  if (argc != 4)
  {
    std::stringstream message;
    message << "Usage: " << std::endl;
    message << argv[0] << " PANInputImageFile XSInputImageFile OutputImageFile " << std::endl;
    config->logError(message.str());
    config->abort(EXIT_FAILURE);
  }

  // Image types
  typedef float FloatPixelType;
  const unsigned int Dimension = 2;
  typedef otb::VectorImage<FloatPixelType,Dimension>  FloatVectorImageType;

  // Reader
  typedef otb::ImageFileReader<FloatVectorImageType>  ReaderType;

  // PAN Reader
  ReaderType::Pointer panReader = ReaderType::New();

  // PAN Reader configuration
  std::string panInputFilename = std::string(argv[1]);
  panReader->SetFileName(panInputFilename);
  FloatVectorImageType* panchroV = panReader->GetOutput();
  panReader->UpdateOutputInformation();
  if ( panchroV->GetNumberOfComponentsPerPixel() != 1 )
  {
    config->logError("The panchromatic image must be a single channel image");
	config->abort(EXIT_FAILURE);
  }

  // XS Reader
  ReaderType::Pointer xsReader = ReaderType::New();

  // XS Reader configuration
  std::string xsInputFilename = std::string(argv[2]);
  xsReader->SetFileName(xsInputFilename);
  FloatVectorImageType* xs = xsReader->GetOutput();
  xsReader->UpdateOutputInformation();

  // Transform the PAN image to otb::Image
  typedef otb::Image<FloatVectorImageType::InternalPixelType> InternalImageType;
  typedef otb::MultiToMonoChannelExtractROI<float,float> ExtractFilterType;
  ExtractFilterType::Pointer channelSelect = ExtractFilterType::New();
  channelSelect->SetChannel(1);
  channelSelect->SetInput(panchroV);
  channelSelect->UpdateOutputInformation();
  InternalImageType::Pointer panchro = channelSelect->GetOutput();

  typedef otb::BCOInterpolateImageFunction<FloatVectorImageType> InterpolatorType;
  typedef otb::GenericRSResampleImageFilter<FloatVectorImageType, FloatVectorImageType>  ResamplerType;
  typedef otb::GridResampleImageFilter<FloatVectorImageType, FloatVectorImageType>  BasicResamplerType;
  typedef otb::ImportGeoInformationImageFilter<FloatVectorImageType,InternalImageType> ImportGeoInformationFilterType;
  typedef otb::SimpleRcsPanSharpeningFusionImageFilter<InternalImageType, FloatVectorImageType, FloatVectorImageType> FusionFilterType;

  // Resample filter
  ResamplerType::Pointer    resampler = ResamplerType::New();
  BasicResamplerType::Pointer basicResampler = BasicResamplerType::New();
  ImportGeoInformationFilterType::Pointer geoImport = ImportGeoInformationFilterType::New();
  InterpolatorType::Pointer interpolator = InterpolatorType::New();
  resampler->SetInterpolator(interpolator);
  basicResampler->SetInterpolator(interpolator);

  // Fusion filter
  FusionFilterType::Pointer  fusionFilter = FusionFilterType::New();
  fusionFilter->SetPanInput(panchro);

  // Setup the DEM Handler
  //otb::Wrapper::ElevationParametersHandler::SetupDEMHandlerFromElevationParameters(this,"elev");

  // Set up output image information
  FloatVectorImageType::SpacingType spacing = panchro->GetSpacing();
  FloatVectorImageType::IndexType   start = panchro->GetLargestPossibleRegion().GetIndex();
  FloatVectorImageType::SizeType    size = panchro->GetLargestPossibleRegion().GetSize();
  FloatVectorImageType::PointType   origin = panchro->GetOrigin();
  FloatVectorImageType::PixelType defaultValue;
  itk::NumericTraits<FloatVectorImageType::PixelType>::SetLength(defaultValue, xs->GetNumberOfComponentsPerPixel());

  otb::PleiadesPToXSAffineTransformCalculator::TransformType::OffsetType offset
        = otb::PleiadesPToXSAffineTransformCalculator::ComputeOffset(panchro,xs);

  origin+=offset;
  origin[0]=origin[0]/4;
  origin[1]=origin[1]/4;

  basicResampler->SetOutputOrigin(origin);
  basicResampler->SetInput(xs);
  basicResampler->SetOutputOrigin(origin);

  FloatVectorImageType::SpacingType xsSpacing = xs->GetSpacing();
  xsSpacing*=0.25;

  basicResampler->SetOutputSpacing(xsSpacing);
  basicResampler->SetOutputSize(size);
  basicResampler->SetOutputStartIndex(start);
  basicResampler->SetEdgePaddingValue(defaultValue);

  geoImport->SetInput(basicResampler->GetOutput());
  geoImport->SetSource(panchro);

  fusionFilter->SetXsInput(geoImport->GetOutput());

  // Update MPI Pipeline
  std::string outputFilename = std::string(argv[3]);
  config->UpdateMPI(fusionFilter->GetOutput(),outputFilename, false, true);

  // End chrono
  boost::chrono::thread_clock::time_point stopTimer = boost::chrono::thread_clock::now();
  std::stringstream message;
  message << "Duration = " << boost::chrono::duration_cast<boost::chrono::milliseconds>(stopTimer-startTimer).count() <<" ms\n";
  config->logInfo(message.str());

  return EXIT_SUCCESS;
}

<commit_msg>Correct BundleToPerfectSensorTest<commit_after>/*=========================================================================

 Program:   ORFEO Toolbox
 Language:  C++
 Date:      $Date$
 Version:   $Revision$

 Copyright (c) Centre National d'Etudes Spatiales. All rights reserved.
 See OTBCopyright.txt for details.

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

 =========================================================================*/

// Includes
#include "otbVectorImage.h"
#include "otbImageFileReader.h"
#include "otbImageFileWriter.h"

#include "otbMultiToMonoChannelExtractROI.h"
#include "otbGenericRSResampleImageFilter.h"
#include "otbGridResampleImageFilter.h"
#include "otbImportGeoInformationImageFilter.h"
#include "otbBCOInterpolateImageFunction.h"
#include "otbSimpleRcsPanSharpeningFusionImageFilter.h"
#include "itkFixedArray.h"
// Elevation handler
//#include "otbWrapperElevationParametersHandler.h"
#include "otbPleiadesPToXSAffineTransformCalculator.h"

#include "otbMPIConfig.h"

#include <cstdlib>
#include <iostream>
#include <boost/chrono/thread_clock.hpp>

// Test
int otbMPIBundleToPerfectSensorTest(int argc, char* argv[])
{
  // Mono-thread execution
  itk::MultiThreader::SetGlobalMaximumNumberOfThreads(1);
  itk::MultiThreader::SetGlobalDefaultNumberOfThreads(1);

  // Start chrono
  boost::chrono::thread_clock::time_point startTimer = boost::chrono::thread_clock::now();

  // MPI Initialization
  typedef otb::mpi::MPIConfig    MPIConfigType;
  MPIConfigType::Pointer config = MPIConfigType::New();
  config->Init(argc,argv,true);

  // Verify the number of parameters in the command line
  if (argc != 4)
  {
    std::stringstream message;
    message << "Usage: " << std::endl;
    message << argv[0] << " PANInputImageFile XSInputImageFile OutputImageFile " << std::endl;
    config->logError(message.str());
    config->abort(EXIT_FAILURE);
  }

  // Image types
  typedef float FloatPixelType;
  const unsigned int Dimension = 2;
  typedef otb::VectorImage<FloatPixelType,Dimension>  FloatVectorImageType;

  // Reader
  typedef otb::ImageFileReader<FloatVectorImageType>  ReaderType;

  // PAN Reader
  ReaderType::Pointer panReader = ReaderType::New();

  // PAN Reader configuration
  std::string panInputFilename = std::string(argv[1]);
  panReader->SetFileName(panInputFilename);
  FloatVectorImageType* panchroV = panReader->GetOutput();
  panReader->UpdateOutputInformation();
  if ( panchroV->GetNumberOfComponentsPerPixel() != 1 )
  {
    config->logError("The panchromatic image must be a single channel image");
	config->abort(EXIT_FAILURE);
  }

  // XS Reader
  ReaderType::Pointer xsReader = ReaderType::New();

  // XS Reader configuration
  std::string xsInputFilename = std::string(argv[2]);
  xsReader->SetFileName(xsInputFilename);
  FloatVectorImageType* xs = xsReader->GetOutput();
  xsReader->UpdateOutputInformation();

  // Transform the PAN image to otb::Image
  typedef otb::Image<FloatVectorImageType::InternalPixelType> InternalImageType;
  typedef otb::MultiToMonoChannelExtractROI<float,float> ExtractFilterType;
  ExtractFilterType::Pointer channelSelect = ExtractFilterType::New();
  channelSelect->SetChannel(1);
  channelSelect->SetInput(panchroV);
  channelSelect->UpdateOutputInformation();
  InternalImageType::Pointer panchro = channelSelect->GetOutput();

  typedef otb::BCOInterpolateImageFunction<FloatVectorImageType> InterpolatorType;
  typedef otb::GenericRSResampleImageFilter<FloatVectorImageType, FloatVectorImageType>  ResamplerType;
  typedef otb::GridResampleImageFilter<FloatVectorImageType, FloatVectorImageType>  BasicResamplerType;
  typedef otb::ImportGeoInformationImageFilter<FloatVectorImageType,InternalImageType> ImportGeoInformationFilterType;
  typedef otb::SimpleRcsPanSharpeningFusionImageFilter<InternalImageType, FloatVectorImageType, FloatVectorImageType> FusionFilterType;

  // Resample filter
  ResamplerType::Pointer    resampler = ResamplerType::New();
  BasicResamplerType::Pointer basicResampler = BasicResamplerType::New();
  ImportGeoInformationFilterType::Pointer geoImport = ImportGeoInformationFilterType::New();
  InterpolatorType::Pointer interpolator = InterpolatorType::New();
  resampler->SetInterpolator(interpolator);
  basicResampler->SetInterpolator(interpolator);

  // Fusion filter
  FusionFilterType::Pointer  fusionFilter = FusionFilterType::New();
  fusionFilter->SetPanInput(panchro);

  // Setup the DEM Handler
  //otb::Wrapper::ElevationParametersHandler::SetupDEMHandlerFromElevationParameters(this,"elev");

  // Set up output image information
  FloatVectorImageType::SpacingType spacing = panchro->GetSpacing();
  FloatVectorImageType::IndexType   start = panchro->GetLargestPossibleRegion().GetIndex();
  FloatVectorImageType::SizeType    size = panchro->GetLargestPossibleRegion().GetSize();
  FloatVectorImageType::PointType   origin = panchro->GetOrigin();
  FloatVectorImageType::PixelType defaultValue;
  itk::NumericTraits<FloatVectorImageType::PixelType>::SetLength(defaultValue, xs->GetNumberOfComponentsPerPixel());

  otb::PleiadesPToXSAffineTransformCalculator::TransformType::OffsetType offset
        = otb::PleiadesPToXSAffineTransformCalculator::ComputeOffset(panchroV,xs);

  origin+=offset;
  origin[0]=origin[0]/4;
  origin[1]=origin[1]/4;

  basicResampler->SetOutputOrigin(origin);
  basicResampler->SetInput(xs);
  basicResampler->SetOutputOrigin(origin);

  FloatVectorImageType::SpacingType xsSpacing = xs->GetSpacing();
  xsSpacing*=0.25;

  basicResampler->SetOutputSpacing(xsSpacing);
  basicResampler->SetOutputSize(size);
  basicResampler->SetOutputStartIndex(start);
  basicResampler->SetEdgePaddingValue(defaultValue);

  geoImport->SetInput(basicResampler->GetOutput());
  geoImport->SetSource(panchro);

  fusionFilter->SetXsInput(geoImport->GetOutput());

  // Update MPI Pipeline
  std::string outputFilename = std::string(argv[3]);
  config->UpdateMPI(fusionFilter->GetOutput(),outputFilename, false, true);

  // End chrono
  boost::chrono::thread_clock::time_point stopTimer = boost::chrono::thread_clock::now();
  std::stringstream message;
  message << "Duration = " << boost::chrono::duration_cast<boost::chrono::milliseconds>(stopTimer-startTimer).count() <<" ms\n";
  config->logInfo(message.str());

  return EXIT_SUCCESS;
}

<|endoftext|>


<commit_before>#include "adapters/net.hpp"

#include <cerrno>
#include <cstdio>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <utility>

#include <linux/ethtool.h>
#include <linux/if_link.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <climits>
#include <csignal>

#ifdef inline
#undef inline
#endif

#include "common.hpp"
#include "config.hpp"
#include "utils/command.hpp"
#include "utils/file.hpp"
#include "utils/string.hpp"

POLYBAR_NS

namespace net {
  /**
   * Test if interface with given name is a wireless device
   */
  bool is_wireless_interface(const string& ifname) {
    return file_util::exists("/sys/class/net/" + ifname + "/wireless");
  }

  // class : network {{{

  /**
   * Construct network interface
   */
  network::network(string interface) : m_interface(move(interface)) {
    if (if_nametoindex(m_interface.c_str()) == 0) {
      throw network_error("Invalid network interface \"" + m_interface + "\"");
    }
    if ((m_socketfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
      throw network_error("Failed to open socket");
    }
    check_tuntap();
  }

  /**
   * Destruct network interface
   */
  network::~network() {
    if (m_socketfd != -1) {
      close(m_socketfd);
    }
  }

  /**
   * Query device driver for information
   */
  bool network::query(bool accumulate) {
    struct ifaddrs* ifaddr;

    if (getifaddrs(&ifaddr) == -1 || ifaddr == nullptr) {
      return false;
    }

    m_status.previous = m_status.current;
    m_status.current.transmitted = 0;
    m_status.current.received = 0;
    m_status.current.time = chrono::system_clock::now();

    for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
      if (ifa->ifa_addr == nullptr) {
        continue;
      }

      if (m_interface.compare(0, m_interface.length(), ifa->ifa_name) != 0) {
        if (!accumulate || (ifa->ifa_data == nullptr && ifa->ifa_addr->sa_family != AF_PACKET)) {
          continue;
        }
      }

      switch (ifa->ifa_addr->sa_family) {
        case AF_INET:
          char ip_buffer[NI_MAXHOST];
          getnameinfo(ifa->ifa_addr, sizeof(sockaddr_in), ip_buffer, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST);
          m_status.ip = string{ip_buffer};
          break;

        case AF_PACKET:
          if (ifa->ifa_data == nullptr) {
            continue;
          }
          struct rtnl_link_stats* link_state = reinterpret_cast<decltype(link_state)>(ifa->ifa_data);
          if (link_state == nullptr) {
            continue;
          }
          m_status.current.transmitted += link_state->tx_bytes;
          m_status.current.received += link_state->rx_bytes;
          break;
      }
    }

    freeifaddrs(ifaddr);

    return true;
  }

  /**
   * Run ping command to test internet connectivity
   */
  bool network::ping() const {
    try {
      auto exec = "ping -c 2 -W 2 -I " + m_interface + " " + string(CONNECTION_TEST_IP);
      auto ping = command_util::make_command(exec);
      return ping && ping->exec(true) == EXIT_SUCCESS;
    } catch (const std::exception& err) {
      return false;
    }
  }

  /**
   * Get interface ip address
   */
  string network::ip() const {
    return m_status.ip;
  }

  /**
   * Get download speed rate
   */
  string network::downspeed(int minwidth) const {
    float bytes_diff = m_status.current.received - m_status.previous.received;
    return format_speedrate(bytes_diff, minwidth);
  }

  /**
   * Get upload speed rate
   */
  string network::upspeed(int minwidth) const {
    float bytes_diff = m_status.current.transmitted - m_status.previous.transmitted;
    return format_speedrate(bytes_diff, minwidth);
  }

  /**
   * Query driver info to check if the
   * interface is a TUN/TAP device
   */
  void network::check_tuntap() {
    struct ethtool_drvinfo driver;
    struct ifreq request;

    driver.cmd = ETHTOOL_GDRVINFO;

    strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 0);

    request.ifr_data = reinterpret_cast<caddr_t>(&driver);

    if (ioctl(m_socketfd, SIOCETHTOOL, &request) == -1) {
      return;
    }

    // Check if it's a TUN/TAP device
    if (strncmp(driver.bus_info, "tun", 3) == 0) {
      m_tuntap = true;
    } else if (strncmp(driver.bus_info, "tap", 3) == 0) {
      m_tuntap = true;
    } else {
      m_tuntap = false;
    }
  }

  /**
   * Test if the network interface is in a valid state
   */
  bool network::test_interface() const {
    auto operstate = file_util::get_contents("/sys/class/net/" + m_interface + "/operstate");
    return operstate.compare(0, 2, "up") == 0;
  }

  /**
   * Format up- and download speed
   */
  string network::format_speedrate(float bytes_diff, int minwidth) const {
    const auto duration = m_status.current.time - m_status.previous.time;
    float time_diff = chrono::duration_cast<chrono::seconds>(duration).count();
    float speedrate = bytes_diff / (time_diff ? time_diff : 1);

    vector<string> suffixes{"GB", "MB"};
    string suffix{"KB"};

    while ((speedrate /= 1000) > 999) {
      suffix = suffixes.back();
      suffixes.pop_back();
    }

    return string_util::from_stream(stringstream() << std::setw(minwidth) << std::setfill(' ') << std::setprecision(0)
                                                   << std::fixed << speedrate << " " << suffix << "/s");
  }

  // }}}
  // class : wired_network {{{

  /**
   * Query device driver for information
   */
  bool wired_network::query(bool accumulate) {
    if (m_tuntap) {
      return true;
    } else if (!network::query(accumulate)) {
      return false;
    }

    struct ifreq request;
    struct ethtool_cmd data;

    strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
    data.cmd = ETHTOOL_GSET;
    request.ifr_data = reinterpret_cast<caddr_t>(&data);

    if (ioctl(m_socketfd, SIOCETHTOOL, &request) == -1) {
      return false;
    }

    m_linkspeed = data.speed;

    return true;
  }

  /**
   * Check current connection state
   */
  bool wired_network::connected() const {
    if (!m_tuntap && !network::test_interface()) {
      return false;
    }

    struct ethtool_value data;
    struct ifreq request;

    strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
    data.cmd = ETHTOOL_GLINK;
    request.ifr_data = reinterpret_cast<caddr_t>(&data);

    if (ioctl(m_socketfd, SIOCETHTOOL, &request) == -1) {
      return false;
    }

    return data.data != 0;
  }

  /**
   *
   * about the current connection
   */
  string wired_network::linkspeed() const {
    return (m_linkspeed == 0 ? "???" : to_string(m_linkspeed)) + " Mbit/s";
  }

  // }}}
  // class : wireless_network {{{

  /**
   * Query the wireless device for information
   * about the current connection
   */
  bool wireless_network::query(bool accumulate) {
    if (!network::query(accumulate)) {
      return false;
    }

    auto socket_fd = iw_sockets_open();

    if (socket_fd == -1) {
      return false;
    }

    struct iwreq req;

    if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWMODE, &req) == -1) {
      return false;
    }

    // Ignore interfaces in ad-hoc mode
    if (req.u.mode == IW_MODE_ADHOC) {
      return false;
    }

    query_essid(socket_fd);
    query_quality(socket_fd);

    iw_sockets_close(socket_fd);

    return true;
  }

  /**
   * Check current connection state
   */
  bool wireless_network::connected() const {
    if (!network::test_interface()) {
      return false;
    }
    return !m_essid.empty();
  }

  /**
   * ESSID reported by last query
   */
  string wireless_network::essid() const {
    return m_essid;
  }

  /**
   * Signal strength percentage reported by last query
   */
  int wireless_network::signal() const {
    return m_signalstrength.percentage();
  }

  /**
   * Link quality percentage reported by last query
   */
  int wireless_network::quality() const {
    return m_linkquality.percentage();
  }

  /**
   * Query for ESSID
   */
  void wireless_network::query_essid(const int& socket_fd) {
    char essid[IW_ESSID_MAX_SIZE + 1];

    struct iwreq req;
    req.u.essid.pointer = &essid;
    req.u.essid.length = sizeof(essid);
    req.u.essid.flags = 0;

    if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWESSID, &req) != -1) {
      m_essid = string{essid};
    } else {
      m_essid.clear();
    }
  }

  /**
   * Query for device driver quality values
   */
  void wireless_network::query_quality(const int& socket_fd) {
    iwrange range;
    iwstats stats;

    // Fill range
    if (iw_get_range_info(socket_fd, m_interface.c_str(), &range) == -1) {
      return;
    }
    // Fill stats
    if (iw_get_stats(socket_fd, m_interface.c_str(), &stats, &range, 1) == -1) {
      return;
    }

    // Check if the driver supplies the quality value
    if (stats.qual.updated & IW_QUAL_QUAL_INVALID) {
      return;
    }
    // Check if the driver supplies the quality level value
    if (stats.qual.updated & IW_QUAL_LEVEL_INVALID) {
      return;
    }

    // Check if the link quality has been uodated
    if (stats.qual.updated & IW_QUAL_QUAL_UPDATED) {
      m_linkquality.val = stats.qual.qual;
      m_linkquality.max = range.max_qual.qual;
    }

    // Check if the signal strength has been uodated
    if (stats.qual.updated & IW_QUAL_LEVEL_UPDATED) {
      m_signalstrength.val = stats.qual.level;
      m_signalstrength.max = range.max_qual.level;

      // Check if the values are defined in dBm
      if (stats.qual.level > range.max_qual.level) {
        m_signalstrength.val -= 0x100;
        m_signalstrength.max -= 0x100;
      }
    }
  }

  // }}}
}

POLYBAR_NS_END
<commit_msg>fix(net): Initialize request struct<commit_after>#include "adapters/net.hpp"

#include <cerrno>
#include <cstdio>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <utility>

#include <linux/ethtool.h>
#include <linux/if_link.h>
#include <linux/sockios.h>
#include <net/if.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <climits>
#include <csignal>

#ifdef inline
#undef inline
#endif

#include "common.hpp"
#include "config.hpp"
#include "utils/command.hpp"
#include "utils/file.hpp"
#include "utils/string.hpp"

POLYBAR_NS

namespace net {
  /**
   * Test if interface with given name is a wireless device
   */
  bool is_wireless_interface(const string& ifname) {
    return file_util::exists("/sys/class/net/" + ifname + "/wireless");
  }

  // class : network {{{

  /**
   * Construct network interface
   */
  network::network(string interface) : m_interface(move(interface)) {
    if (if_nametoindex(m_interface.c_str()) == 0) {
      throw network_error("Invalid network interface \"" + m_interface + "\"");
    }
    if ((m_socketfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
      throw network_error("Failed to open socket");
    }
    check_tuntap();
  }

  /**
   * Destruct network interface
   */
  network::~network() {
    if (m_socketfd != -1) {
      close(m_socketfd);
    }
  }

  /**
   * Query device driver for information
   */
  bool network::query(bool accumulate) {
    struct ifaddrs* ifaddr;

    if (getifaddrs(&ifaddr) == -1 || ifaddr == nullptr) {
      return false;
    }

    m_status.previous = m_status.current;
    m_status.current.transmitted = 0;
    m_status.current.received = 0;
    m_status.current.time = chrono::system_clock::now();

    for (auto ifa = ifaddr; ifa != nullptr; ifa = ifa->ifa_next) {
      if (ifa->ifa_addr == nullptr) {
        continue;
      }

      if (m_interface.compare(0, m_interface.length(), ifa->ifa_name) != 0) {
        if (!accumulate || (ifa->ifa_data == nullptr && ifa->ifa_addr->sa_family != AF_PACKET)) {
          continue;
        }
      }

      switch (ifa->ifa_addr->sa_family) {
        case AF_INET:
          char ip_buffer[NI_MAXHOST];
          getnameinfo(ifa->ifa_addr, sizeof(sockaddr_in), ip_buffer, NI_MAXHOST, nullptr, 0, NI_NUMERICHOST);
          m_status.ip = string{ip_buffer};
          break;

        case AF_PACKET:
          if (ifa->ifa_data == nullptr) {
            continue;
          }
          struct rtnl_link_stats* link_state = reinterpret_cast<decltype(link_state)>(ifa->ifa_data);
          if (link_state == nullptr) {
            continue;
          }
          m_status.current.transmitted += link_state->tx_bytes;
          m_status.current.received += link_state->rx_bytes;
          break;
      }
    }

    freeifaddrs(ifaddr);

    return true;
  }

  /**
   * Run ping command to test internet connectivity
   */
  bool network::ping() const {
    try {
      auto exec = "ping -c 2 -W 2 -I " + m_interface + " " + string(CONNECTION_TEST_IP);
      auto ping = command_util::make_command(exec);
      return ping && ping->exec(true) == EXIT_SUCCESS;
    } catch (const std::exception& err) {
      return false;
    }
  }

  /**
   * Get interface ip address
   */
  string network::ip() const {
    return m_status.ip;
  }

  /**
   * Get download speed rate
   */
  string network::downspeed(int minwidth) const {
    float bytes_diff = m_status.current.received - m_status.previous.received;
    return format_speedrate(bytes_diff, minwidth);
  }

  /**
   * Get upload speed rate
   */
  string network::upspeed(int minwidth) const {
    float bytes_diff = m_status.current.transmitted - m_status.previous.transmitted;
    return format_speedrate(bytes_diff, minwidth);
  }

  /**
   * Query driver info to check if the
   * interface is a TUN/TAP device
   */
  void network::check_tuntap() {
    struct ethtool_drvinfo driver;
    struct ifreq request;

    driver.cmd = ETHTOOL_GDRVINFO;

    memset(&request, 0, sizeof(request));
    strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 0);

    request.ifr_data = reinterpret_cast<caddr_t>(&driver);

    if (ioctl(m_socketfd, SIOCETHTOOL, &request) == -1) {
      return;
    }

    // Check if it's a TUN/TAP device
    if (strncmp(driver.bus_info, "tun", 3) == 0) {
      m_tuntap = true;
    } else if (strncmp(driver.bus_info, "tap", 3) == 0) {
      m_tuntap = true;
    } else {
      m_tuntap = false;
    }
  }

  /**
   * Test if the network interface is in a valid state
   */
  bool network::test_interface() const {
    auto operstate = file_util::get_contents("/sys/class/net/" + m_interface + "/operstate");
    return operstate.compare(0, 2, "up") == 0;
  }

  /**
   * Format up- and download speed
   */
  string network::format_speedrate(float bytes_diff, int minwidth) const {
    const auto duration = m_status.current.time - m_status.previous.time;
    float time_diff = chrono::duration_cast<chrono::seconds>(duration).count();
    float speedrate = bytes_diff / (time_diff ? time_diff : 1);

    vector<string> suffixes{"GB", "MB"};
    string suffix{"KB"};

    while ((speedrate /= 1000) > 999) {
      suffix = suffixes.back();
      suffixes.pop_back();
    }

    return string_util::from_stream(stringstream() << std::setw(minwidth) << std::setfill(' ') << std::setprecision(0)
                                                   << std::fixed << speedrate << " " << suffix << "/s");
  }

  // }}}
  // class : wired_network {{{

  /**
   * Query device driver for information
   */
  bool wired_network::query(bool accumulate) {
    if (m_tuntap) {
      return true;
    } else if (!network::query(accumulate)) {
      return false;
    }

    struct ifreq request;
    struct ethtool_cmd data;

    memset(&request, 0, sizeof(request));
    strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
    data.cmd = ETHTOOL_GSET;
    request.ifr_data = reinterpret_cast<caddr_t>(&data);

    if (ioctl(m_socketfd, SIOCETHTOOL, &request) == -1) {
      return false;
    }

    m_linkspeed = data.speed;

    return true;
  }

  /**
   * Check current connection state
   */
  bool wired_network::connected() const {
    if (!m_tuntap && !network::test_interface()) {
      return false;
    }

    struct ethtool_value data;
    struct ifreq request;

    memset(&request, 0, sizeof(request));
    strncpy(request.ifr_name, m_interface.c_str(), IFNAMSIZ - 1);
    data.cmd = ETHTOOL_GLINK;
    request.ifr_data = reinterpret_cast<caddr_t>(&data);

    if (ioctl(m_socketfd, SIOCETHTOOL, &request) == -1) {
      return false;
    }

    return data.data != 0;
  }

  /**
   *
   * about the current connection
   */
  string wired_network::linkspeed() const {
    return (m_linkspeed == 0 ? "???" : to_string(m_linkspeed)) + " Mbit/s";
  }

  // }}}
  // class : wireless_network {{{

  /**
   * Query the wireless device for information
   * about the current connection
   */
  bool wireless_network::query(bool accumulate) {
    if (!network::query(accumulate)) {
      return false;
    }

    auto socket_fd = iw_sockets_open();

    if (socket_fd == -1) {
      return false;
    }

    struct iwreq req;

    if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWMODE, &req) == -1) {
      return false;
    }

    // Ignore interfaces in ad-hoc mode
    if (req.u.mode == IW_MODE_ADHOC) {
      return false;
    }

    query_essid(socket_fd);
    query_quality(socket_fd);

    iw_sockets_close(socket_fd);

    return true;
  }

  /**
   * Check current connection state
   */
  bool wireless_network::connected() const {
    if (!network::test_interface()) {
      return false;
    }
    return !m_essid.empty();
  }

  /**
   * ESSID reported by last query
   */
  string wireless_network::essid() const {
    return m_essid;
  }

  /**
   * Signal strength percentage reported by last query
   */
  int wireless_network::signal() const {
    return m_signalstrength.percentage();
  }

  /**
   * Link quality percentage reported by last query
   */
  int wireless_network::quality() const {
    return m_linkquality.percentage();
  }

  /**
   * Query for ESSID
   */
  void wireless_network::query_essid(const int& socket_fd) {
    char essid[IW_ESSID_MAX_SIZE + 1];

    struct iwreq req;
    req.u.essid.pointer = &essid;
    req.u.essid.length = sizeof(essid);
    req.u.essid.flags = 0;

    if (iw_get_ext(socket_fd, m_interface.c_str(), SIOCGIWESSID, &req) != -1) {
      m_essid = string{essid};
    } else {
      m_essid.clear();
    }
  }

  /**
   * Query for device driver quality values
   */
  void wireless_network::query_quality(const int& socket_fd) {
    iwrange range;
    iwstats stats;

    // Fill range
    if (iw_get_range_info(socket_fd, m_interface.c_str(), &range) == -1) {
      return;
    }
    // Fill stats
    if (iw_get_stats(socket_fd, m_interface.c_str(), &stats, &range, 1) == -1) {
      return;
    }

    // Check if the driver supplies the quality value
    if (stats.qual.updated & IW_QUAL_QUAL_INVALID) {
      return;
    }
    // Check if the driver supplies the quality level value
    if (stats.qual.updated & IW_QUAL_LEVEL_INVALID) {
      return;
    }

    // Check if the link quality has been uodated
    if (stats.qual.updated & IW_QUAL_QUAL_UPDATED) {
      m_linkquality.val = stats.qual.qual;
      m_linkquality.max = range.max_qual.qual;
    }

    // Check if the signal strength has been uodated
    if (stats.qual.updated & IW_QUAL_LEVEL_UPDATED) {
      m_signalstrength.val = stats.qual.level;
      m_signalstrength.max = range.max_qual.level;

      // Check if the values are defined in dBm
      if (stats.qual.level > range.max_qual.level) {
        m_signalstrength.val -= 0x100;
        m_signalstrength.max -= 0x100;
      }
    }
  }

  // }}}
}

POLYBAR_NS_END
<|endoftext|>


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

#include <algorithm>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include <utility>

#include "amxcallstack.h"
#include "amxdebuginfo.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

static bool IsFunctionArgument(const AMXDebugInfo::Symbol &symbol, ucell functionAddress) {
	return symbol.IsLocal() && symbol.GetCodeStartAddress() == functionAddress;
}

class IsArgumentOf : public std::unary_function<AMXDebugInfo::Symbol, bool> {
public:
	IsArgumentOf(ucell function) : function_(function) {}

	bool operator()(AMXDebugInfo::Symbol symbol) const {
		return symbol.IsLocal() && symbol.GetCodeStartAddress() == function_;
	}

private:
	ucell function_;
};

static inline bool CompareArguments(const AMXDebugInfo::Symbol &left, const AMXDebugInfo::Symbol &right) {
	return left.GetAddress() < right.GetAddress();
}

class IsFunctionAt : public std::unary_function<const AMXDebugInfo::Symbol&, bool> {
public:
	IsFunctionAt(ucell address) : address_(address) {}

	bool operator()(const AMXDebugInfo::Symbol &symbol) const {
		return symbol.IsFunction() && symbol.GetAddress() == address_;
	}

private:
	ucell address_;
};

static inline const char *GetPublicFunctionName(AMX *amx, ucell address) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

	AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);
	AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

	for (AMX_FUNCSTUBNT *p = publics; p < natives; ++p) {
		if (p->address == address) {
			return reinterpret_cast<const char*>(p->nameofs + amx->base);
		}
	}

	return 0;
}

static inline bool IsPublicFunction(AMX *amx, ucell address) {
	return GetPublicFunctionName(amx, address) != 0;
}

AMXStackFrame::AMXStackFrame(AMX *amx, ucell frameAddress, const AMXDebugInfo &debugInfo)
	: isPublic_(false)
	, frameAddress_(frameAddress)
	, callAddress_(0)
	, functionAddress_(0)
{
	if (IsOnStack(frameAddress_, amx)) {
		AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

		ucell data = reinterpret_cast<ucell>(amx->base + hdr->dat);
		ucell code = reinterpret_cast<ucell>(amx->base) + hdr->cod;

		callAddress_ = *(reinterpret_cast<ucell*>(data + frameAddress_) + 1) - 2*sizeof(cell);
		if (callAddress_ >= 0 && callAddress_ < static_cast<ucell>(hdr->dat - hdr->cod)) {
			functionAddress_ = *reinterpret_cast<ucell*>(callAddress_ + sizeof(cell) + code) - code;
			Init(amx, debugInfo);
		} else {
			callAddress_ = 0;
		}
	}
}

AMXStackFrame::AMXStackFrame(AMX *amx, ucell frameAddress, ucell callAddress,
		ucell functionAddress, const AMXDebugInfo &debugInfo)
	: isPublic_(false)
	, frameAddress_(frameAddress)
	, callAddress_(callAddress)
	, functionAddress_(functionAddress)
{
	Init(amx, debugInfo);
}

static inline char ToASCII(char c) {
	if (c >= 32 && c <= 126) {
		return c;
	}
	return '\0';
}

static inline char ToASCII(cell c) {
	return ToASCII(static_cast<char>(c & 0xFF));
}

static inline std::string GetPackedAMXString(AMX *amx, cell *string, std::size_t size) {
	std::string s;
	for (std::size_t i = 0; i < size; i++) {
		cell cp = string[i / sizeof(cell)] >> ((sizeof(cell) - i % sizeof(cell) - 1) * 8);
		char cu = ToASCII(cp);
		if (cu == '\0') {
			break;
		}
		s.push_back(cu);
	}

	return s;
}

static inline std::string GetUnpackedAMXString(AMX *amx, cell *string, std::size_t size) {
	std::string s;
	for (std::size_t i = 0; i < size; i++) {
		char c = ToASCII(string[i]);
		if (c == '\0') {
			break;
		}
		s.push_back(c);
	}
	return s;
}

static std::pair<std::string, bool> GetAMXString(AMX *amx, cell address, std::size_t size) {
	std::pair<std::string, bool> result = std::make_pair("", false);

	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

	if (address < 0 || address >= hdr->hea - hdr->dat) {
		// The address is not inside the data section...
		return result;
	}

	cell *cstr = reinterpret_cast<cell*>(amx->base + hdr->dat + address);

	if (size == 0) {
		// Size is unknown, copy up to the end of data.
		size = hdr->hea - address;
	}

	if (*reinterpret_cast<ucell*>(cstr) > UNPACKEDMAX) {
		result.first = GetPackedAMXString(amx, cstr, size);
		result.second = true;
	} else {
		result.first = GetUnpackedAMXString(amx, cstr, size);
		result.second = false;
	}

	return result;
}

void AMXStackFrame::Init(AMX *amx, const AMXDebugInfo &debugInfo) {
	isPublic_ = IsPublicFunction(amx, functionAddress_);

	if (debugInfo.IsLoaded()) {
		if (callAddress_ != 0) {
			fileName_ = debugInfo.GetFileName(callAddress_);
			lineNumber_ = debugInfo.GetLineNumber(callAddress_);
		} else {
			// Entry point
			fileName_ = debugInfo.GetFileName(functionAddress_);
			lineNumber_ = debugInfo.GetLineNumber(functionAddress_);
		}

		// Get function return value tag
		AMXDebugInfo::SymbolTable::const_iterator it = std::find_if(
			debugInfo.GetSymbols().begin(),
			debugInfo.GetSymbols().end(),
			IsFunctionAt(functionAddress_)
		);
		if (it != debugInfo.GetSymbols().end()) {
			functionResultTag_ = debugInfo.GetTagName((*it).GetTag()) + ":";
			if (functionResultTag_ == "_:") {
				functionResultTag_.clear();
			}
		}

		// Get function name
		functionName_ = debugInfo.GetFunctionName(functionAddress_);

		// Get parameters
		std::remove_copy_if(
			debugInfo.GetSymbols().begin(),
			debugInfo.GetSymbols().end(),
			std::back_inserter(arguments_),
			std::not1(IsArgumentOf(functionAddress_))
		);

		// Order them by address
		std::sort(arguments_.begin(), arguments_.end(), CompareArguments);

		// Build a comma-separated list of arguments and their values
		std::stringstream argStream;
		for (std::vector<AMXDebugInfo::Symbol>::const_iterator arg = arguments_.begin();
				arg != arguments_.end(); ++arg) {
			if (arg != arguments_.begin()) {
				argStream << ", ";
			}

			// For reference parameters, print the '&' sign in front of their tag
			if (arg->IsReference()) {
				argStream << "&";
			}

			// Get parameter's tag
			std::string tag = debugInfo.GetTag(arg->GetTag()).GetName() + ":";
			if (tag != "_:") {
				argStream << tag;
			}

			// Get parameter name
			argStream << arg->GetName();

			cell value = arg->GetValue(amx);
			if (arg->IsVariable()) {
				if (tag == "bool:") {
					argStream << "=" << value ? "true" : "false";
				} else if (tag == "Float:") {
					argStream << "=" << std::fixed << std::setprecision(5) << amx_ctof(value);
				} else {
					argStream << "=" << value;
				}
			} else {
				std::vector<AMXDebugInfo::SymbolDim> dims = arg->GetDims();
				if (arg->IsArray() || arg->IsArrayRef()) {
					for (std::size_t i = 0; i < dims.size(); ++i) {
						if (dims[i].GetSize() == 0) {
							argStream << "[]";
						} else {
							std::string tag = debugInfo.GetTagName(dims[i].GetTag()) + ":";
							if (tag == "_:") tag.clear();
							argStream << "[" << tag << dims[i].GetSize() << "]";
						}
					}
				}
				argStream << "=@0x" << std::hex << std::setw(8)
						<< std::setfill('0') << value << std::dec;
				if (dims.size() == 1) {
					std::pair<std::string, bool> s = GetAMXString(amx, value, dims[0].GetSize());
					argStream << " ";
					if (s.second) {
						argStream << "!"; // packed string
					}
					if (s.first.length() > kMaxString) {
						// test is too long
						s.first.replace(kMaxString, s.first.length() - kMaxString, "...");
					}
					argStream << "\"" << s.first << "\"";
				}
			}
		}

		// The function prototype is of the following form:
		// [public ][tag:]name([arg1=value1[, arg2=value2, [...]]])
		if (IsPublic()) {
			functionPrototype_.append("public ");
		}
		functionPrototype_
			.append(functionResultTag_)
			.append(functionName_)
			.append("(")
			.append(argStream.str())
			.append(")");
	} else {
		// No debug info available...
		const char *name = GetPublicFunctionName(amx, functionAddress_);
		if (name != 0) {
			functionName_.assign(name);
		}
	}
}

AMXCallStack::AMXCallStack(AMX *amx, const AMXDebugInfo &debugInfo, ucell topFrame) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	ucell data = reinterpret_cast<ucell>(amx->base + hdr->dat);

	ucell frm = topFrame;
	if (frm == 0) {
		frm = amx->frm;
	}

	while (frm > static_cast<ucell>(amx->stk)) {
		AMXStackFrame frame(amx, frm, debugInfo);
		frames_.push_back(frame);
		if (frame.GetFunctionAddress() == 0) {
			// Invalid frame address
			break;
		}
		frm = *reinterpret_cast<ucell*>(data + frm);
	}

	// Correct entry point address (it's not on the stack)
	if (debugInfo.IsLoaded()) {
		if (frames_.size() > 1) {
			ucell epAddr = debugInfo.GetFunctionStartAddress(frames_[frames_.size() - 2].GetCallAddress());
			frames_.back() = AMXStackFrame(amx, frames_.back().GetFrameAddress(), 0, epAddr, debugInfo);
		} else if (frames_.size() != 0) {
			ucell epAddr = debugInfo.GetFunctionStartAddress(amx->cip);
			frames_.back() = AMXStackFrame(amx, frames_.back().GetFrameAddress(), 0, epAddr, debugInfo);
		}
	} else {
		// Can't fetch the address
		frames_.back() = AMXStackFrame(amx, 0, 0, 0);
	}
}
<commit_msg>amxcallstack: More accurate argument type detection<commit_after>// Copyright (c) 2011 Zeex
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <algorithm>
#include <functional>
#include <iomanip>
#include <iostream>
#include <iterator>
#include <sstream>
#include <string>
#include <vector>
#include <utility>

#include "amxcallstack.h"
#include "amxdebuginfo.h"

#include "amx/amx.h"
#include "amx/amxdbg.h"

static bool IsFunctionArgument(const AMXDebugInfo::Symbol &symbol, ucell functionAddress) {
	return symbol.IsLocal() && symbol.GetCodeStartAddress() == functionAddress;
}

class IsArgumentOf : public std::unary_function<AMXDebugInfo::Symbol, bool> {
public:
	IsArgumentOf(ucell function) : function_(function) {}

	bool operator()(AMXDebugInfo::Symbol symbol) const {
		return symbol.IsLocal() && symbol.GetCodeStartAddress() == function_;
	}

private:
	ucell function_;
};

static inline bool CompareArguments(const AMXDebugInfo::Symbol &left, const AMXDebugInfo::Symbol &right) {
	return left.GetAddress() < right.GetAddress();
}

class IsFunctionAt : public std::unary_function<const AMXDebugInfo::Symbol&, bool> {
public:
	IsFunctionAt(ucell address) : address_(address) {}

	bool operator()(const AMXDebugInfo::Symbol &symbol) const {
		return symbol.IsFunction() && symbol.GetAddress() == address_;
	}

private:
	ucell address_;
};

static inline const char *GetPublicFunctionName(AMX *amx, ucell address) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

	AMX_FUNCSTUBNT *publics = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->publics);
	AMX_FUNCSTUBNT *natives = reinterpret_cast<AMX_FUNCSTUBNT*>(amx->base + hdr->natives);

	for (AMX_FUNCSTUBNT *p = publics; p < natives; ++p) {
		if (p->address == address) {
			return reinterpret_cast<const char*>(p->nameofs + amx->base);
		}
	}

	return 0;
}

static inline bool IsPublicFunction(AMX *amx, ucell address) {
	return GetPublicFunctionName(amx, address) != 0;
}

AMXStackFrame::AMXStackFrame(AMX *amx, ucell frameAddress, const AMXDebugInfo &debugInfo)
	: isPublic_(false)
	, frameAddress_(frameAddress)
	, callAddress_(0)
	, functionAddress_(0)
{
	if (IsOnStack(frameAddress_, amx)) {
		AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

		ucell data = reinterpret_cast<ucell>(amx->base + hdr->dat);
		ucell code = reinterpret_cast<ucell>(amx->base) + hdr->cod;

		callAddress_ = *(reinterpret_cast<ucell*>(data + frameAddress_) + 1) - 2*sizeof(cell);
		if (callAddress_ >= 0 && callAddress_ < static_cast<ucell>(hdr->dat - hdr->cod)) {
			functionAddress_ = *reinterpret_cast<ucell*>(callAddress_ + sizeof(cell) + code) - code;
			Init(amx, debugInfo);
		} else {
			callAddress_ = 0;
		}
	}
}

AMXStackFrame::AMXStackFrame(AMX *amx, ucell frameAddress, ucell callAddress,
		ucell functionAddress, const AMXDebugInfo &debugInfo)
	: isPublic_(false)
	, frameAddress_(frameAddress)
	, callAddress_(callAddress)
	, functionAddress_(functionAddress)
{
	Init(amx, debugInfo);
}

static inline char ToASCII(char c) {
	if (c >= 32 && c <= 126) {
		return c;
	}
	return '\0';
}

static inline char ToASCII(cell c) {
	return ToASCII(static_cast<char>(c & 0xFF));
}

static inline std::string GetPackedAMXString(AMX *amx, cell *string, std::size_t size) {
	std::string s;
	for (std::size_t i = 0; i < size; i++) {
		cell cp = string[i / sizeof(cell)] >> ((sizeof(cell) - i % sizeof(cell) - 1) * 8);
		char cu = ToASCII(cp);
		if (cu == '\0') {
			break;
		}
		s.push_back(cu);
	}

	return s;
}

static inline std::string GetUnpackedAMXString(AMX *amx, cell *string, std::size_t size) {
	std::string s;
	for (std::size_t i = 0; i < size; i++) {
		char c = ToASCII(string[i]);
		if (c == '\0') {
			break;
		}
		s.push_back(c);
	}
	return s;
}

static std::pair<std::string, bool> GetAMXString(AMX *amx, cell address, std::size_t size) {
	std::pair<std::string, bool> result = std::make_pair("", false);

	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);

	if (address < 0 || address >= hdr->hea - hdr->dat) {
		// The address is not inside the data section...
		return result;
	}

	cell *cstr = reinterpret_cast<cell*>(amx->base + hdr->dat + address);

	if (size == 0) {
		// Size is unknown, copy up to the end of data.
		size = hdr->hea - address;
	}

	if (*reinterpret_cast<ucell*>(cstr) > UNPACKEDMAX) {
		result.first = GetPackedAMXString(amx, cstr, size);
		result.second = true;
	} else {
		result.first = GetUnpackedAMXString(amx, cstr, size);
		result.second = false;
	}

	return result;
}

void AMXStackFrame::Init(AMX *amx, const AMXDebugInfo &debugInfo) {
	isPublic_ = IsPublicFunction(amx, functionAddress_);

	if (debugInfo.IsLoaded()) {
		if (callAddress_ != 0) {
			fileName_ = debugInfo.GetFileName(callAddress_);
			lineNumber_ = debugInfo.GetLineNumber(callAddress_);
		} else {
			// Entry point
			fileName_ = debugInfo.GetFileName(functionAddress_);
			lineNumber_ = debugInfo.GetLineNumber(functionAddress_);
		}

		// Get function return value tag
		AMXDebugInfo::SymbolTable::const_iterator it = std::find_if(
			debugInfo.GetSymbols().begin(),
			debugInfo.GetSymbols().end(),
			IsFunctionAt(functionAddress_)
		);
		if (it != debugInfo.GetSymbols().end()) {
			functionResultTag_ = debugInfo.GetTagName((*it).GetTag()) + ":";
			if (functionResultTag_ == "_:") {
				functionResultTag_.clear();
			}
		}

		// Get function name
		functionName_ = debugInfo.GetFunctionName(functionAddress_);

		// Get parameters
		std::remove_copy_if(
			debugInfo.GetSymbols().begin(),
			debugInfo.GetSymbols().end(),
			std::back_inserter(arguments_),
			std::not1(IsArgumentOf(functionAddress_))
		);

		// Order them by address
		std::sort(arguments_.begin(), arguments_.end(), CompareArguments);

		// Build a comma-separated list of arguments and their values
		std::stringstream argStream;
		for (std::vector<AMXDebugInfo::Symbol>::const_iterator arg = arguments_.begin();
				arg != arguments_.end(); ++arg) {
			if (arg != arguments_.begin()) {
				argStream << ", ";
			}

			// For reference parameters, print the '&' sign in front of their tag
			if (arg->IsReference()) {
				argStream << "&";
			}

			// Get parameter's tag
			std::string tag = debugInfo.GetTag(arg->GetTag()).GetName() + ":";
			if (tag != "_:") {
				argStream << tag;
			}

			// Get parameter name
			argStream << arg->GetName();

			cell value = arg->GetValue(amx);
			if (arg->IsVariable()) {
				// Value arguments
				if (tag == "bool:") {
					argStream << "=" << value ? "true" : "false";
				} else if (tag == "Float:") {
					argStream << "=" << std::fixed << std::setprecision(5) << amx_ctof(value);
				} else {
					argStream << "=" << value;
				}
			} else {
				// Reference arguments
				std::vector<AMXDebugInfo::SymbolDim> dims = arg->GetDims();

				// Show array dimensions
				if (arg->IsArray() || arg->IsArrayRef()) {
					for (std::size_t i = 0; i < dims.size(); ++i) {
						if (dims[i].GetSize() == 0) {
							argStream << "[]";
						} else {
							std::string tag = debugInfo.GetTagName(dims[i].GetTag()) + ":";
							if (tag == "_:") tag.clear();
							argStream << "[" << tag << dims[i].GetSize() << "]";
						}
					}
				}

				argStream << "=@0x" << std::hex << std::setw(8) << std::setfill('0') << value << std::dec;

				// If this is a string argument, get the text
				if (arg->IsArray() || arg->IsArrayRef()
						&& dims.size() == 1
						&& tag == "_:"
						&& debugInfo.GetTagName(dims[0].GetTag()) == "_")
				{
					std::pair<std::string, bool> s = GetAMXString(amx, value, dims[0].GetSize());
					argStream << " ";
					if (s.second) {
						argStream << "!"; // packed string
					}
					if (s.first.length() > kMaxString) {
						// The text is too long.
						s.first.replace(kMaxString, s.first.length() - kMaxString, "...");
					}
					argStream << "\"" << s.first << "\"";
				}
			}
		}

		// The function prototype is of the following form:
		// [public ][tag:]name([arg1=value1[, arg2=value2, [...]]])
		if (IsPublic()) {
			functionPrototype_.append("public ");
		}
		functionPrototype_
			.append(functionResultTag_)
			.append(functionName_)
			.append("(")
			.append(argStream.str())
			.append(")");
	} else {
		// No debug info available...
		const char *name = GetPublicFunctionName(amx, functionAddress_);
		if (name != 0) {
			functionName_.assign(name);
		}
	}
}

AMXCallStack::AMXCallStack(AMX *amx, const AMXDebugInfo &debugInfo, ucell topFrame) {
	AMX_HEADER *hdr = reinterpret_cast<AMX_HEADER*>(amx->base);
	ucell data = reinterpret_cast<ucell>(amx->base + hdr->dat);

	ucell frm = topFrame;
	if (frm == 0) {
		frm = amx->frm;
	}

	while (frm > static_cast<ucell>(amx->stk)) {
		AMXStackFrame frame(amx, frm, debugInfo);
		frames_.push_back(frame);
		if (frame.GetFunctionAddress() == 0) {
			// Invalid frame address
			break;
		}
		frm = *reinterpret_cast<ucell*>(data + frm);
	}

	// Correct entry point address (it's not on the stack)
	if (debugInfo.IsLoaded()) {
		if (frames_.size() > 1) {
			ucell epAddr = debugInfo.GetFunctionStartAddress(frames_[frames_.size() - 2].GetCallAddress());
			frames_.back() = AMXStackFrame(amx, frames_.back().GetFrameAddress(), 0, epAddr, debugInfo);
		} else if (frames_.size() != 0) {
			ucell epAddr = debugInfo.GetFunctionStartAddress(amx->cip);
			frames_.back() = AMXStackFrame(amx, frames_.back().GetFrameAddress(), 0, epAddr, debugInfo);
		}
	} else {
		// Can't fetch the address
		frames_.back() = AMXStackFrame(amx, 0, 0, 0);
	}
}
<|endoftext|>


<commit_before>#include "condor_common.h"
#include "condor_config.h"
#include "subsystem_info.h"
#include "match_prefix.h"
#include "daemon.h"
#include "dc_annexd.h"

int
main( int argc, char ** argv ) {
	config();
	set_mySubSystem( "TOOL", SUBSYSTEM_TYPE_TOOL );

	const char * pool = NULL;
	const char * name = NULL;
	for( int i = 1; i < argc; ++i ) {
		if( is_dash_arg_prefix( argv[i], "pool", 1 ) ) {
			++i;
			if( argv[i] != NULL ) {
				pool = argv[i];
				continue;
			} else {
				fprintf( stderr, "%s: -pool requires an argument.\n", argv[0] );
				exit( 1 );
			}
		} else if( is_dash_arg_prefix( argv[i], "name", 1 ) ) {
			++i;
			if( argv[i] != NULL ) {
				name = argv[i];
				continue;
			} else {
				fprintf( stderr, "%s: -name requires an argument.\n", argv[0] );
				exit( 1 );
			}
		} else if( is_dash_arg_prefix( argv[i], "debug", 1 ) ) {
			dprintf_set_tool_debug( "TOOL", 0 );
			continue;
		} else {
			fprintf( stderr, "%s: unrecognized option '%s'.\n", argv[0], argv[i] );
			exit( 1 );
		}
	}

	std::string annexDaemonName;
	param( annexDaemonName, "ANNEXD_NAME" );
	if( name == NULL ) { name = annexDaemonName.c_str(); }
	DCAnnexd annexd( name, pool );
	annexd.setSubsystem( "GENERIC" );

	ClassAd spotFleetRequest;
	CondorClassAdFileIterator ccafi;
	if(! ccafi.begin( stdin, false, CondorClassAdFileParseHelper::Parse_json )) {
		fprintf( stderr, "Failed to start parsing spot fleet request.\n" );
		return 1;
	} else {
		int numAttrs = ccafi.next( spotFleetRequest );
		if( numAttrs <= 0 ) {
			fprintf( stderr, "Failed to parse spot fleet request, found no attributes.\n" );
			return 1;
		} else if( numAttrs > 11 ) {
			fprintf( stderr, "Failed to parse spot fleet reqeust, found too many attributes.\n" );
			return 1;
		}
	}

	if(! annexd.locate( Daemon::LOCATE_FOR_LOOKUP )) {
		char * error = annexd.error();
		if( error && error[0] != '\0' ) {
			fprintf( stderr, "%s: Can't locate annex daemon (%s).\n", argv[0], error );
		} else {
			fprintf( stderr, "%s: Can't locate annex daemon.\n", argv[0] );
		}
		return 2;
	}
	dprintf( D_FULLDEBUG, "Found annex daemon at '%s'.\n", annexd.addr() );

	ClassAd reply;
	fprintf( stdout, "Sending bulk request command to daemon...\n" );
	if(! annexd.sendBulkRequest( & spotFleetRequest, & reply )) {
		char * error = annexd.error();
		if( error && error[0] != '\0' ) {
			fprintf( stderr, "Failed to send bulk request to daemon: '%s'.\n", error );
		} else {
			fprintf( stderr, "Failed to send bulk request to daemon.\n" );
		}
		return 3;
	}

	int requestVersion = -1;
	reply.LookupInteger( "RequestVersion", requestVersion );
	if( requestVersion != 1 ) {
		fprintf( stderr, "Daemon's reply had missing or unknown RequestVersion (%d).\n", requestVersion );
		return 4;
	}

	std::string bulkRequestID;
	reply.LookupString( "BulkRequestID", bulkRequestID );
	if( bulkRequestID.empty() ) {
		fprintf( stderr, "Daemon's reply did not include bulk request ID.\n" );
		return 4;
	} else {
		fprintf( stdout, "%s\n", bulkRequestID.c_str() );
	}

	return 0;
}
<commit_msg>(#5816)  Require the user to specify a filename (or - for stdin) from which to read, so we don't just (mysteriously) block on stdin.<commit_after>#include "condor_common.h"
#include "condor_config.h"
#include "subsystem_info.h"
#include "match_prefix.h"
#include "daemon.h"
#include "dc_annexd.h"

int
main( int argc, char ** argv ) {
	config();
	set_mySubSystem( "TOOL", SUBSYSTEM_TYPE_TOOL );

	const char * pool = NULL;
	const char * name = NULL;
	const char * fileName = NULL;
	for( int i = 1; i < argc; ++i ) {
		if( is_dash_arg_prefix( argv[i], "pool", 1 ) ) {
			++i;
			if( argv[i] != NULL ) {
				pool = argv[i];
				continue;
			} else {
				fprintf( stderr, "%s: -pool requires an argument.\n", argv[0] );
				return 1;
			}
		} else if( is_dash_arg_prefix( argv[i], "name", 1 ) ) {
			++i;
			if( argv[i] != NULL ) {
				name = argv[i];
				continue;
			} else {
				fprintf( stderr, "%s: -name requires an argument.\n", argv[0] );
				return 1;
			}
		} else if( is_dash_arg_prefix( argv[i], "debug", 1 ) ) {
			dprintf_set_tool_debug( "TOOL", 0 );
			continue;
		} else if( argv[i][0] == '-') {
			fprintf( stderr, "%s: unrecognized option '%s'.\n", argv[0], argv[i] );
			return 1;
		} else {
			fileName = argv[i];
			continue;
		}
	}

	if( fileName == NULL ) {
		fprintf( stderr, "%s: you must specify a file containing an annex specification.\n", argv[0] );
		return 1;
	}

	FILE * file = NULL;
	bool closeFile = true;
	if( strcmp( fileName, "-" ) == 0 ) {
		file = stdin;
		closeFile = false;
	} else {
		file = safe_fopen_wrapper_follow( fileName, "r" );
		if( file == NULL ) {
			fprintf( stderr, "Unable to open annex specification file '%s'.\n", fileName );
			return 1;
		}
	}

	std::string annexDaemonName;
	param( annexDaemonName, "ANNEXD_NAME" );
	if( name == NULL ) { name = annexDaemonName.c_str(); }
	DCAnnexd annexd( name, pool );
	annexd.setSubsystem( "GENERIC" );

	ClassAd spotFleetRequest;
	CondorClassAdFileIterator ccafi;
	if(! ccafi.begin( file, closeFile, CondorClassAdFileParseHelper::Parse_json )) {
		fprintf( stderr, "Failed to start parsing spot fleet request.\n" );
		return 2;
	} else {
		int numAttrs = ccafi.next( spotFleetRequest );
		if( numAttrs <= 0 ) {
			fprintf( stderr, "Failed to parse spot fleet request, found no attributes.\n" );
			return 2;
		} else if( numAttrs > 11 ) {
			fprintf( stderr, "Failed to parse spot fleet reqeust, found too many attributes.\n" );
			return 2;
		}
	}

	if(! annexd.locate( Daemon::LOCATE_FOR_LOOKUP )) {
		char * error = annexd.error();
		if( error && error[0] != '\0' ) {
			fprintf( stderr, "%s: Can't locate annex daemon (%s).\n", argv[0], error );
		} else {
			fprintf( stderr, "%s: Can't locate annex daemon.\n", argv[0] );
		}
		return 3;
	}
	dprintf( D_FULLDEBUG, "Found annex daemon at '%s'.\n", annexd.addr() );

	ClassAd reply;
	fprintf( stdout, "Sending bulk request command to daemon...\n" );
	if(! annexd.sendBulkRequest( & spotFleetRequest, & reply )) {
		char * error = annexd.error();
		if( error && error[0] != '\0' ) {
			fprintf( stderr, "Failed to send bulk request to daemon: '%s'.\n", error );
		} else {
			fprintf( stderr, "Failed to send bulk request to daemon.\n" );
		}
		return 4;
	}

	int requestVersion = -1;
	reply.LookupInteger( "RequestVersion", requestVersion );
	if( requestVersion != 1 ) {
		fprintf( stderr, "Daemon's reply had missing or unknown RequestVersion (%d).\n", requestVersion );
		return 5;
	}

	std::string bulkRequestID;
	reply.LookupString( "BulkRequestID", bulkRequestID );
	if( bulkRequestID.empty() ) {
		fprintf( stderr, "Daemon's reply did not include bulk request ID.\n" );
		return 5;
	} else {
		fprintf( stdout, "%s\n", bulkRequestID.c_str() );
	}

	return 0;
}
<|endoftext|>


<commit_before>
#ifndef __ARCH_MOCK_IO_HPP__
#define __ARCH_MOCK_IO_HPP__

#include "containers/segmented_vector.hpp"
#include "utils2.hpp"
#include "arch/random_delay.hpp"
#include <stdlib.h>

struct mock_iocallback_t {
    virtual void on_io_complete() = 0;
    virtual ~mock_iocallback_t() {}
};

#define DEFAULT_DISK_ACCOUNT NULL

template<class inner_io_config_t>
class mock_file_t
{
    int mode;

public:
    enum mode_t {
        mode_read = 1 << 0,
        mode_write = 1 << 1,
        mode_create = 1 << 2
    };

    struct account_t {
        account_t(UNUSED mock_file_t *f, UNUSED int p, UNUSED int outstanding_requests_limit = UNLIMITED_OUTSTANDING_REQUESTS) { }
    };

protected:
    mock_file_t(const char *path, int mode, const typename inner_io_config_t::io_backend_t io_backend = (typename inner_io_config_t::io_backend_t)-1)
        : mode(mode)
    {
        int mode2 = 0;
        if (mode & mode_read) mode2 |= inner_io_config_t::file_t::mode_read;
        // We always enable writing because the mock layer does
        // truncation on exit
        mode2 |= inner_io_config_t::file_t::mode_write;
        if (mode & mode_create) mode2 |= inner_io_config_t::file_t::mode_create;

        if (io_backend == (typename inner_io_config_t::io_backend_t)-1)
            inner_file = new typename inner_io_config_t::nondirect_file_t(path, mode2);
        else
            inner_file = new typename inner_io_config_t::nondirect_file_t(path, mode2, io_backend);

        if (inner_file->is_block_device()) {
            fail_due_to_user_error(
                "Using mock_file_t with a block device is a really bad idea because it "
                "reads the entire contents of the underlying file into memory, which could be "
                "a lot for a block device.");
        }

        set_size(inner_file->get_size());
        for (unsigned i = 0; i < get_size() / DEVICE_BLOCK_SIZE; i++) {
            inner_file->read_blocking(i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE, blocks[i].data);
        }
    }

    bool exists() {
        return inner_file->exists();
    }

    bool is_block_device() {
        return false;
    }

    uint64_t get_size() {
        return blocks.get_size() * DEVICE_BLOCK_SIZE;
    }

    void set_size(size_t size) {
        rassert(size % DEVICE_BLOCK_SIZE == 0);
        blocks.set_size(size / DEVICE_BLOCK_SIZE);
    }

    void set_size_at_least(size_t size) {
        if (get_size() < size) {
            size_t actual_size = size + randint(10) * DEVICE_BLOCK_SIZE;
            set_size(actual_size);
        }
    }

    /* These always return 'false'; the reason they return bool instead of void
    is for consistency with other asynchronous-callback methods */
    bool read_async(size_t offset, size_t length, void *buf, UNUSED account_t *account, mock_iocallback_t *cb) {
        rassert(mode & mode_read);
        read_blocking(offset, length, buf);
        random_delay(cb, &mock_iocallback_t::on_io_complete);
        return false;
    }

    bool write_async(size_t offset, size_t length, const void *buf, UNUSED account_t *account, mock_iocallback_t *cb) {
        rassert(mode & mode_write);
        write_blocking(offset, length, buf);
        random_delay(cb, &mock_iocallback_t::on_io_complete);
        return false;
    }

    void read_blocking(size_t offset, size_t length, void *buf) {
        rassert(mode & mode_read);
        verify(offset, length, buf);
        for (unsigned i = 0; i < length / DEVICE_BLOCK_SIZE; i += 1) {
            memcpy((char*)buf + i*DEVICE_BLOCK_SIZE, blocks[offset/DEVICE_BLOCK_SIZE + i].data, DEVICE_BLOCK_SIZE);
        }
    }

    void write_blocking(size_t offset, size_t length, const void *buf) {
        rassert(mode & mode_write);
        verify(offset, length, buf);
        for (unsigned i = 0; i < length / DEVICE_BLOCK_SIZE; i += 1) {
            memcpy(blocks[offset/DEVICE_BLOCK_SIZE + i].data, (char*)buf + i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE);
        }
    }

    ~mock_file_t() {
        if (mode & mode_write) {
            if(exists()) {
                inner_file->set_size(get_size());
            }
            // This is horrible. We write every single block of the file, sequentially, in a
            // blocking fashion. There must be a better way to do this...
            for (unsigned i = 0; i < get_size() / DEVICE_BLOCK_SIZE; i++) {
                inner_file->write_blocking(i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE, blocks[i].data);
            }
        }

        delete inner_file;
    }

private:
    typename inner_io_config_t::nondirect_file_t *inner_file;

    struct block_t {
        char *data;

        block_t() {
            data = (char*)malloc_aligned(DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE);

            // Initialize to either random data or zeroes, choosing at random
            char d = randint(2) ? 0 : randint(0x100);
            memset(data, d, DEVICE_BLOCK_SIZE);
        }

        ~block_t() {
            free((void*)data);
        }
    };
    segmented_vector_t<block_t, 10*GIGABYTE/DEVICE_BLOCK_SIZE> blocks;

    void verify(UNUSED size_t offset, UNUSED size_t length, UNUSED const void *buf) {
        rassert(buf);
        rassert(offset + length <= get_size());
        rassert((intptr_t)buf % DEVICE_BLOCK_SIZE == 0);
        rassert(offset % DEVICE_BLOCK_SIZE == 0);
        rassert(length % DEVICE_BLOCK_SIZE == 0);
    }

    DISABLE_COPYING(mock_file_t);
};

template <class inner_io_config_t>
class mock_direct_file_t : public mock_file_t<inner_io_config_t> {
public:
    using mock_file_t<inner_io_config_t>::exists;
    using mock_file_t<inner_io_config_t>::is_block_device;
    using mock_file_t<inner_io_config_t>::get_size;
    using mock_file_t<inner_io_config_t>::set_size;
    using mock_file_t<inner_io_config_t>::set_size_at_least;
    using mock_file_t<inner_io_config_t>::read_async;
    using mock_file_t<inner_io_config_t>::write_async;
    using mock_file_t<inner_io_config_t>::read_blocking;
    using mock_file_t<inner_io_config_t>::write_blocking;

    mock_direct_file_t(const char *path, int mode, const typename inner_io_config_t::io_backend_t io_backend = (typename inner_io_config_t::io_backend_t)-1) : mock_file_t<inner_io_config_t>(path, mode, io_backend) { }

private:
    DISABLE_COPYING(mock_direct_file_t);
};

template <class inner_io_config_t>
class mock_nondirect_file_t : private mock_file_t<inner_io_config_t> {
public:
    using mock_file_t<inner_io_config_t>::exists;
    using mock_file_t<inner_io_config_t>::is_block_device;
    using mock_file_t<inner_io_config_t>::get_size;
    using mock_file_t<inner_io_config_t>::set_size;
    using mock_file_t<inner_io_config_t>::set_size_at_least;
    using mock_file_t<inner_io_config_t>::read_async;
    using mock_file_t<inner_io_config_t>::write_async;
    using mock_file_t<inner_io_config_t>::read_blocking;
    using mock_file_t<inner_io_config_t>::write_blocking;

    mock_nondirect_file_t(const char *path, int mode, const typename inner_io_config_t::io_backend_t io_backend = (typename inner_io_config_t::io_backend_t)-1) : mock_file_t<inner_io_config_t>(path, mode, io_backend) { }

private:
    DISABLE_COPYING(mock_nondirect_file_t);
};

#endif /* __ARCH_MOCK_IO_HPP__ */
<commit_msg>Fixed format errors in mock IO layer.<commit_after>
#ifndef __ARCH_MOCK_IO_HPP__
#define __ARCH_MOCK_IO_HPP__

#include "containers/segmented_vector.hpp"
#include "utils2.hpp"
#include "arch/random_delay.hpp"
#include <stdlib.h>

struct mock_iocallback_t {
    virtual void on_io_complete() = 0;
    virtual ~mock_iocallback_t() {}
};

#define DEFAULT_DISK_ACCOUNT NULL

template<class inner_io_config_t>
class mock_file_t
{
    int mode;

public:
    enum mode_t {
        mode_read = 1 << 0,
        mode_write = 1 << 1,
        mode_create = 1 << 2
    };

    struct account_t {
        account_t(UNUSED mock_file_t *f, UNUSED int p, UNUSED int outstanding_requests_limit = UNLIMITED_OUTSTANDING_REQUESTS) { }
    };

protected:
    mock_file_t(const char *path, int mode, const typename inner_io_config_t::io_backend_t io_backend = (typename inner_io_config_t::io_backend_t)-1)
        : mode(mode)
    {
        int mode2 = 0;
        if (mode & mode_read) mode2 |= inner_io_config_t::file_t::mode_read;
        // We always enable writing because the mock layer does
        // truncation on exit
        mode2 |= inner_io_config_t::file_t::mode_write;
        if (mode & mode_create) mode2 |= inner_io_config_t::file_t::mode_create;

        if (io_backend == (typename inner_io_config_t::io_backend_t)-1)
            inner_file = new typename inner_io_config_t::nondirect_file_t(path, mode2);
        else
            inner_file = new typename inner_io_config_t::nondirect_file_t(path, mode2, io_backend);

        if (inner_file->is_block_device()) {
            fail_due_to_user_error(
                "Using mock_file_t with a block device is a really bad idea because it "
                "reads the entire contents of the underlying file into memory, which could be "
                "a lot for a block device.");
        }

        set_size(inner_file->get_size());
        for (unsigned i = 0; i < get_size() / DEVICE_BLOCK_SIZE; i++) {
            inner_file->read_blocking(i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE, blocks[i].data);
        }
    }

    bool exists() {
        return inner_file->exists();
    }

    bool is_block_device() {
        return false;
    }

    uint64_t get_size() {
        return blocks.get_size() * DEVICE_BLOCK_SIZE;
    }

    void set_size(size_t size) {
#ifndef NDEBUG
        {
            bool modcmp = size % DEVICE_BLOCK_SIZE == 0;
            rassert(modcmp);
        }
#endif
        blocks.set_size(size / DEVICE_BLOCK_SIZE);
    }

    void set_size_at_least(size_t size) {
        if (get_size() < size) {
            size_t actual_size = size + randint(10) * DEVICE_BLOCK_SIZE;
            set_size(actual_size);
        }
    }

    /* These always return 'false'; the reason they return bool instead of void
    is for consistency with other asynchronous-callback methods */
    bool read_async(size_t offset, size_t length, void *buf, UNUSED account_t *account, mock_iocallback_t *cb) {
        rassert(mode & mode_read);
        read_blocking(offset, length, buf);
        random_delay(cb, &mock_iocallback_t::on_io_complete);
        return false;
    }

    bool write_async(size_t offset, size_t length, const void *buf, UNUSED account_t *account, mock_iocallback_t *cb) {
        rassert(mode & mode_write);
        write_blocking(offset, length, buf);
        random_delay(cb, &mock_iocallback_t::on_io_complete);
        return false;
    }

    void read_blocking(size_t offset, size_t length, void *buf) {
        rassert(mode & mode_read);
        verify(offset, length, buf);
        for (unsigned i = 0; i < length / DEVICE_BLOCK_SIZE; i += 1) {
            memcpy((char*)buf + i*DEVICE_BLOCK_SIZE, blocks[offset/DEVICE_BLOCK_SIZE + i].data, DEVICE_BLOCK_SIZE);
        }
    }

    void write_blocking(size_t offset, size_t length, const void *buf) {
        rassert(mode & mode_write);
        verify(offset, length, buf);
        for (unsigned i = 0; i < length / DEVICE_BLOCK_SIZE; i += 1) {
            memcpy(blocks[offset/DEVICE_BLOCK_SIZE + i].data, (char*)buf + i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE);
        }
    }

    ~mock_file_t() {
        if (mode & mode_write) {
            if(exists()) {
                inner_file->set_size(get_size());
            }
            // This is horrible. We write every single block of the file, sequentially, in a
            // blocking fashion. There must be a better way to do this...
            for (unsigned i = 0; i < get_size() / DEVICE_BLOCK_SIZE; i++) {
                inner_file->write_blocking(i*DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE, blocks[i].data);
            }
        }

        delete inner_file;
    }

private:
    typename inner_io_config_t::nondirect_file_t *inner_file;

    struct block_t {
        char *data;

        block_t() {
            data = (char*)malloc_aligned(DEVICE_BLOCK_SIZE, DEVICE_BLOCK_SIZE);

            // Initialize to either random data or zeroes, choosing at random
            char d = randint(2) ? 0 : randint(0x100);
            memset(data, d, DEVICE_BLOCK_SIZE);
        }

        ~block_t() {
            free((void*)data);
        }
    };
    segmented_vector_t<block_t, 10*GIGABYTE/DEVICE_BLOCK_SIZE> blocks;

    void verify(UNUSED size_t offset, UNUSED size_t length, UNUSED const void *buf) {
#ifndef NDEBUG
        rassert(buf);
        rassert(offset + length <= get_size());
        bool modbuf = (intptr_t)buf % DEVICE_BLOCK_SIZE == 0;
        rassert(modbuf);
        bool modoff = offset % DEVICE_BLOCK_SIZE == 0;
        rassert(modoff);
        bool modlength = length % DEVICE_BLOCK_SIZE == 0;
        rassert(modlength);
#endif
    }

    DISABLE_COPYING(mock_file_t);
};

template <class inner_io_config_t>
class mock_direct_file_t : public mock_file_t<inner_io_config_t> {
public:
    using mock_file_t<inner_io_config_t>::exists;
    using mock_file_t<inner_io_config_t>::is_block_device;
    using mock_file_t<inner_io_config_t>::get_size;
    using mock_file_t<inner_io_config_t>::set_size;
    using mock_file_t<inner_io_config_t>::set_size_at_least;
    using mock_file_t<inner_io_config_t>::read_async;
    using mock_file_t<inner_io_config_t>::write_async;
    using mock_file_t<inner_io_config_t>::read_blocking;
    using mock_file_t<inner_io_config_t>::write_blocking;

    mock_direct_file_t(const char *path, int mode, const typename inner_io_config_t::io_backend_t io_backend = (typename inner_io_config_t::io_backend_t)-1) : mock_file_t<inner_io_config_t>(path, mode, io_backend) { }

private:
    DISABLE_COPYING(mock_direct_file_t);
};

template <class inner_io_config_t>
class mock_nondirect_file_t : private mock_file_t<inner_io_config_t> {
public:
    using mock_file_t<inner_io_config_t>::exists;
    using mock_file_t<inner_io_config_t>::is_block_device;
    using mock_file_t<inner_io_config_t>::get_size;
    using mock_file_t<inner_io_config_t>::set_size;
    using mock_file_t<inner_io_config_t>::set_size_at_least;
    using mock_file_t<inner_io_config_t>::read_async;
    using mock_file_t<inner_io_config_t>::write_async;
    using mock_file_t<inner_io_config_t>::read_blocking;
    using mock_file_t<inner_io_config_t>::write_blocking;

    mock_nondirect_file_t(const char *path, int mode, const typename inner_io_config_t::io_backend_t io_backend = (typename inner_io_config_t::io_backend_t)-1) : mock_file_t<inner_io_config_t>(path, mode, io_backend) { }

private:
    DISABLE_COPYING(mock_nondirect_file_t);
};

#endif /* __ARCH_MOCK_IO_HPP__ */
<|endoftext|>


<commit_before>#include <float.h>

#include <common/Math.h>

#include "random.hpp"
#include "aiactor.hpp"
#include "aistatic.hpp"

class Steering {
	public:
		Steering(const WorldMap* wmap, const SoldierPhysics* phys);
		void seek(const Common::Vector3& tgt);
		void avoidWalls();
		void avoidTrees();
		void turnTowards(float tgt);
		void turnTowards(const Common::Vector3& tgt);
		void lookWhereYoureGoing();
		const Common::Vector3& getAcceleration() const;
		float getRotation() const;

	private:
		float accelLeft() const;
		void addAcceleration(const Common::Vector3& acc);
		void maximiseAcceleration();

		const SoldierPhysics* mPhys;
		const WorldMap* mMap;
		Common::Vector3 mAcceleration;
		float mRotation = 0.0f;
};

Steering::Steering(const WorldMap* wmap, const SoldierPhysics* phys)
	: mPhys(phys),
	mMap(wmap)
{
}

void Steering::seek(const Common::Vector3& tgt)
{
	auto diff = tgt - mPhys->getPosition();
	addAcceleration(diff.normalized() * SoldierPhysics::RunAcceleration);
}

void Steering::avoidWalls()
{
	static const float LookAhead = 5.0f; // meters

	auto rayVec = Common::Vector2(mPhys->getVelocity().x, mPhys->getVelocity().z);
	if(rayVec.null())
		return;

	rayVec.normalize();
	rayVec *= LookAhead;

	Common::Vector2 feelers[] = {
		rayVec,
		Common::Math::rotate2D(rayVec, QUARTER_PI),
		Common::Math::rotate2D(rayVec, -QUARTER_PI),
	};

	const auto& pos = mPhys->getPosition();

	bool added = false;
	for(auto& f : feelers) {
		auto f3 = mMap->pointToVec(f.x, f.y) + Common::Vector3(0.0f, 1.0f, 0.0f);
		auto coll = AIStatic::getWallCollision(pos, pos + f3);

		if(!coll.Found)
			continue;

		auto thisdist = coll.Position.distance(pos);
		auto overshoot = LookAhead - thisdist;
		auto acc = Common::Vector3(coll.Normal.x, 0.0f, coll.Normal.y) * overshoot * overshoot;
		mAcceleration += acc;
		added = true;
	}
	if(added)
		maximiseAcceleration();
}

void Steering::avoidTrees()
{
	auto myvel = Common::Vector2(mPhys->getVelocity().x, mPhys->getVelocity().z);
	auto speed = myvel.length();
	if(speed < 0.02f)
		return;

	auto mypos = Common::Vector2(mPhys->getPosition().x, mPhys->getPosition().z);
	auto trees = mMap->getTreesAt(mypos.x, mypos.y, 5.0f + speed);

	bool added = false;
	for(const auto& tree : trees) {
		auto relpos = Common::Vector2(tree.Position.x - mypos.x, tree.Position.z - mypos.y);
		auto dist = relpos.length();
		if(dist > tree.Radius + 5.0f)
			continue;

		mAcceleration += Common::Vector3(-relpos.x, 0.0f, -relpos.y).normalized() * (tree.Radius + 5.0f - dist);
		added = true;
	}

	if(added)
		maximiseAcceleration();
}

void Steering::turnTowards(float tgtyaw)
{
	auto currdir = Common::Math::rotate3D(Scene::WorldForward, mPhys->getOrientation());
	auto curryaw = atan2(currdir.z, currdir.x);
	auto diffyaw = curryaw - tgtyaw;
	if(diffyaw < -PI)
		diffyaw += TWO_PI;
	if(diffyaw > PI)
		diffyaw -= TWO_PI;
	mRotation += diffyaw;
}

void Steering::turnTowards(const Common::Vector3& tgt)
{
	auto tgtvec = tgt - mPhys->getPosition();
	auto tgtyaw = atan2(tgtvec.z, tgtvec.x);
	turnTowards(tgtyaw);
}

void Steering::lookWhereYoureGoing()
{
	turnTowards(mPhys->getPosition() + mAcceleration);
}

const Common::Vector3& Steering::getAcceleration() const
{
	return mAcceleration;
}

float Steering::getRotation() const
{
	return mRotation;
}

void Steering::addAcceleration(const Common::Vector3& acc)
{
	auto acc2 = acc;
	acc2.y = 0.0f;
	acc2.truncate(accelLeft());
	mAcceleration += acc2;
}

void Steering::maximiseAcceleration()
{
	mAcceleration.normalize();
	mAcceleration *= SoldierPhysics::RunAcceleration;
}

float Steering::accelLeft() const
{
	return SoldierPhysics::RunAcceleration - mAcceleration.length();
}

AIActor::AIActor(const WorldMap* wmap, SoldierPhysics* phys, ShooterComponent* shooter, float shootingSkill, unsigned int id)
	: mMap(wmap),
	mPhys(phys),
	mShooter(shooter),
	mID(id)
{
	shootingSkill = Common::clamp(0.0f, shootingSkill, 1.0f);
	mVariation = (1.0f - shootingSkill) * 0.3f;
}

void AIActor::execute(const AITask& t)
{
	switch(t.Type) {
		case AITask::Type::Idle:
			mPhys->setAiming(false);
			break;

		case AITask::Type::Move:
			{
				mPhys->setAiming(false);
				Steering st(mMap, mPhys);
				st.seek(t.Vec);
				st.avoidWalls();
				st.avoidTrees();
				st.lookWhereYoureGoing();
				auto accel = st.getAcceleration();
				AIStatic::Debug::drawLine(mID, "Moving",
						mPhys->getPosition() + Common::Vector3(0.0f, 1.5f, 0.0f),
						mPhys->getPosition() + accel + Common::Vector3(0.0f, 1.5f, 0.0f),
						Common::Color::Blue);
				if(accel.length() > 0.1f) {
					mPhys->addMovementAcceleration(accel);
				}
				auto rot = st.getRotation();
				if(fabs(rot) > 0.01f) {
					mPhys->addRotation(rot, 0.0f);
				}
			}
			break;

		case AITask::Type::Shoot:
			{
				mPhys->setAiming(true);
				// yaw
				auto tgtvec = t.Vec - mPhys->getPosition();
				auto tgtyaw = atan2(tgtvec.z, tgtvec.x);
				Steering st(mMap, mPhys);
				st.turnTowards(tgtyaw + Random::clamped(Random::SourceAI) * mVariation);
				auto diffyaw = st.getRotation();

				// pitch
				auto currdir = Common::Math::rotate3D(Scene::WorldForward, mPhys->getOrientation() * mPhys->getAimPitch());
				auto currpitch = atan2(currdir.y, 1.0f);
				auto tgtpitch = atan2(tgtvec.normalized().y, 1.0f) + Random::clamped(Random::SourceAI) * mVariation;
				auto diffpitch = -(currpitch - tgtpitch);

				mPhys->addRotation(0.2f * diffyaw, 0.2f * diffpitch);
				if(fabs(diffyaw) < mVariation * 0.2f + 0.05f && fabs(diffpitch) < mVariation * 0.2f + 0.05f) {
					mShooter->shoot();
				}
			}
			break;
	}
}

<commit_msg>ai: do not jitter when shooting skill < 1.0<commit_after>#include <float.h>

#include <common/Math.h>

#include "random.hpp"
#include "aiactor.hpp"
#include "aistatic.hpp"

class Steering {
	public:
		Steering(const WorldMap* wmap, const SoldierPhysics* phys);
		void seek(const Common::Vector3& tgt);
		void avoidWalls();
		void avoidTrees();
		void turnTowards(float tgt);
		void turnTowards(const Common::Vector3& tgt);
		void lookWhereYoureGoing();
		const Common::Vector3& getAcceleration() const;
		float getRotation() const;

	private:
		float accelLeft() const;
		void addAcceleration(const Common::Vector3& acc);
		void maximiseAcceleration();

		const SoldierPhysics* mPhys;
		const WorldMap* mMap;
		Common::Vector3 mAcceleration;
		float mRotation = 0.0f;
};

Steering::Steering(const WorldMap* wmap, const SoldierPhysics* phys)
	: mPhys(phys),
	mMap(wmap)
{
}

void Steering::seek(const Common::Vector3& tgt)
{
	auto diff = tgt - mPhys->getPosition();
	addAcceleration(diff.normalized() * SoldierPhysics::RunAcceleration);
}

void Steering::avoidWalls()
{
	static const float LookAhead = 5.0f; // meters

	auto rayVec = Common::Vector2(mPhys->getVelocity().x, mPhys->getVelocity().z);
	if(rayVec.null())
		return;

	rayVec.normalize();
	rayVec *= LookAhead;

	Common::Vector2 feelers[] = {
		rayVec,
		Common::Math::rotate2D(rayVec, QUARTER_PI),
		Common::Math::rotate2D(rayVec, -QUARTER_PI),
	};

	const auto& pos = mPhys->getPosition();

	bool added = false;
	for(auto& f : feelers) {
		auto f3 = mMap->pointToVec(f.x, f.y) + Common::Vector3(0.0f, 1.0f, 0.0f);
		auto coll = AIStatic::getWallCollision(pos, pos + f3);

		if(!coll.Found)
			continue;

		auto thisdist = coll.Position.distance(pos);
		auto overshoot = LookAhead - thisdist;
		auto acc = Common::Vector3(coll.Normal.x, 0.0f, coll.Normal.y) * overshoot * overshoot;
		mAcceleration += acc;
		added = true;
	}
	if(added)
		maximiseAcceleration();
}

void Steering::avoidTrees()
{
	auto myvel = Common::Vector2(mPhys->getVelocity().x, mPhys->getVelocity().z);
	auto speed = myvel.length();
	if(speed < 0.02f)
		return;

	auto mypos = Common::Vector2(mPhys->getPosition().x, mPhys->getPosition().z);
	auto trees = mMap->getTreesAt(mypos.x, mypos.y, 5.0f + speed);

	bool added = false;
	for(const auto& tree : trees) {
		auto relpos = Common::Vector2(tree.Position.x - mypos.x, tree.Position.z - mypos.y);
		auto dist = relpos.length();
		if(dist > tree.Radius + 5.0f)
			continue;

		mAcceleration += Common::Vector3(-relpos.x, 0.0f, -relpos.y).normalized() * (tree.Radius + 5.0f - dist);
		added = true;
	}

	if(added)
		maximiseAcceleration();
}

void Steering::turnTowards(float tgtyaw)
{
	auto currdir = Common::Math::rotate3D(Scene::WorldForward, mPhys->getOrientation());
	auto curryaw = atan2(currdir.z, currdir.x);
	auto diffyaw = curryaw - tgtyaw;
	if(diffyaw < -PI)
		diffyaw += TWO_PI;
	if(diffyaw > PI)
		diffyaw -= TWO_PI;
	mRotation += diffyaw;
}

void Steering::turnTowards(const Common::Vector3& tgt)
{
	auto tgtvec = tgt - mPhys->getPosition();
	auto tgtyaw = atan2(tgtvec.z, tgtvec.x);
	turnTowards(tgtyaw);
}

void Steering::lookWhereYoureGoing()
{
	turnTowards(mPhys->getPosition() + mAcceleration);
}

const Common::Vector3& Steering::getAcceleration() const
{
	return mAcceleration;
}

float Steering::getRotation() const
{
	return mRotation;
}

void Steering::addAcceleration(const Common::Vector3& acc)
{
	auto acc2 = acc;
	acc2.y = 0.0f;
	acc2.truncate(accelLeft());
	mAcceleration += acc2;
}

void Steering::maximiseAcceleration()
{
	mAcceleration.normalize();
	mAcceleration *= SoldierPhysics::RunAcceleration;
}

float Steering::accelLeft() const
{
	return SoldierPhysics::RunAcceleration - mAcceleration.length();
}

AIActor::AIActor(const WorldMap* wmap, SoldierPhysics* phys, ShooterComponent* shooter, float shootingSkill, unsigned int id)
	: mMap(wmap),
	mPhys(phys),
	mShooter(shooter),
	mID(id)
{
	shootingSkill = Common::clamp(0.0f, shootingSkill, 1.0f);
	mVariation = (1.0f - shootingSkill) * 0.3f;
}

void AIActor::execute(const AITask& t)
{
	switch(t.Type) {
		case AITask::Type::Idle:
			mPhys->setAiming(false);
			break;

		case AITask::Type::Move:
			{
				mPhys->setAiming(false);
				Steering st(mMap, mPhys);
				st.seek(t.Vec);
				st.avoidWalls();
				st.avoidTrees();
				st.lookWhereYoureGoing();
				auto accel = st.getAcceleration();
				AIStatic::Debug::drawLine(mID, "Moving",
						mPhys->getPosition() + Common::Vector3(0.0f, 1.5f, 0.0f),
						mPhys->getPosition() + accel + Common::Vector3(0.0f, 1.5f, 0.0f),
						Common::Color::Blue);
				if(accel.length() > 0.1f) {
					mPhys->addMovementAcceleration(accel);
				}
				auto rot = st.getRotation();
				if(fabs(rot) > 0.01f) {
					mPhys->addRotation(rot, 0.0f);
				}
			}
			break;

		case AITask::Type::Shoot:
			{
				mPhys->setAiming(true);
				// yaw
				auto tgtvec = t.Vec - mPhys->getPosition();
				auto tgtyaw = atan2(tgtvec.z, tgtvec.x);
				Steering st(mMap, mPhys);
				st.turnTowards(tgtyaw);
				auto diffyaw = st.getRotation();

				// pitch
				auto currdir = Common::Math::rotate3D(Scene::WorldForward, mPhys->getOrientation() * mPhys->getAimPitch());
				auto currpitch = atan2(currdir.y, 1.0f);
				auto tgtpitch = atan2(tgtvec.normalized().y, 1.0f);
				auto diffpitch = -(currpitch - tgtpitch);

				mPhys->addRotation(0.5f * (mVariation + 0.5f) * diffyaw, 0.5f * (mVariation + 0.5f) * diffpitch);
				if(fabs(diffyaw) < mVariation * 0.2f + 0.05f && fabs(diffpitch) < mVariation * 0.2f + 0.05f) {
					mShooter->shoot();
				}
			}
			break;
	}
}

<|endoftext|>