<commit_before>// This file is part of the AliceVision project.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

#include "VocabularyTree.hpp"
#include <aliceVision/types.hpp>

#include <map>
#include <cstddef>
#include <string>

namespace aliceVision{
namespace voctree{

/**
 * @brief Struct representing a single database match.
 *
 * \c score is in the range [0,2], where 0 is best and 2 is worst.
 */
struct DocMatch
{
  DocId id;
  float score;

  DocMatch() {}
  DocMatch(DocId _id, float _score)
    : id(_id)
    , score(_score)
  {}

  /// Allows sorting DocMatches in best-to-worst order with std::sort.
  bool operator<(const DocMatch& other) const
  {
    return score < other.score;
  }

  bool operator==(const DocMatch& other) const
  {
    return id == other.id &&
           score == other.score;
  }
  bool operator!=(const DocMatch& other) const
  {
    return !(*this == other);
  }
};

typedef std::vector<DocMatch> DocMatches;

/**
 * @brief Class for efficiently matching a bag-of-words representation of a document (image) against
 * a database of known documents.
 */
class Database
{
public:
  /**
   * @brief Constructor
   *
   * If computing weights for a new vocabulary, \c num_words should be the size of the vocabulary.
   * If calling loadWeights(), it can be left zero.
   */
  Database(uint32_t num_words = 0);

  /**
   * @brief Insert a new document.
   *
   * @param doc_id Unique ID of the new document to insert
   * @param document The set of quantized words in a document/image.
   * \return An ID representing the inserted document.
   */
  DocId insert(DocId doc_id, const SparseHistogram& document);

  /**
   * @brief Perform a sanity check of the database by querying each document
   * of the database and finding its top N matches
   *
   * @param[in] N The number of matches to return.
   * @param[out] matches IDs and scores for the top N matching database documents.
   */
   void sanityCheck(std::size_t N, std::map<std::size_t, DocMatches>& matches) const;

  /**
   * @brief Find the top N matches in the database for the query document.
   *
   * @param[in] document The query document, a set of quantized words.
   * @param[in] N        The number of matches to return.
   * @param[in] distanceMethod distance method (norm L1, etc.)
   * @param[out] matches  IDs and scores for the top N matching database documents.
   */
  void find(const std::vector<Word>& document, std::size_t N, std::vector<DocMatch>& matches, const std::string &distanceMethod = "strongCommonPoints") const;

    /**
   * @brief Find the top N matches in the database for the query document.
   *
   * @param[in] query The query document, a normalized set of quantized words.
   * @param[int] N        The number of matches to return.
   * @param[in] distanceMethod distance method (norm L1, etc.)
   * @param[out] matches  IDs and scores for the top N matching database documents.
   */
  void find(const SparseHistogram& query, std::size_t N, std::vector<DocMatch>& matches, const std::string &distanceMethod = "strongCommonPoints") const;

  /**
   * @brief Compute the TF-IDF weights of all the words. To be called after inserting a corpus of
   * training examples into the database.
   *
   * @param default_weight The default weight of a word that appears in none of the training documents.
   */
  void computeTfIdfWeights(float default_weight = 1.0f);

  /**
   * @brief Return the size of the database in terms of number of documents
   * @return the number of documents
   */
  std::size_t size() const;

  /// Save the vocabulary word weights to a file.
  void saveWeights(const std::string& file) const;
  /// Load the vocabulary word weights from a file.
  void loadWeights(const std::string& file);

  // Save weights and documents
  //void save(const std::string& file) const;
  //void load(const std::string& file);

  const SparseHistogramPerImage& getSparseHistogramPerImage() const
  {
    return database_;
  }

private:

  struct WordFrequency
  {
    DocId id;
    uint32_t count;

    WordFrequency() {}
    WordFrequency(DocId _id, uint32_t _count)
      : id(_id)
      , count(_count)
    {}
  };

  // Stored in increasing order by DocId
  typedef std::vector<WordFrequency> InvertedFile;

  /// @todo Use sorted vector?
  // typedef std::vector< std::pair<Word, float> > DocumentVector;

  friend std::ostream& operator<<(std::ostream& os, const SparseHistogram& dv);

  std::vector<InvertedFile> word_files_;
  std::vector<float> word_weights_;
  SparseHistogramPerImage database_; // Precomputed for inserted documents

  /**
   * Normalize a document vector representing the histogram of visual words for a given image
   * @param[in/out] v the unnormalized histogram of visual words
   */
  void normalize(SparseHistogram& v) const;
};

}//namespace voctree
}//namespace aliceVision
<commit_msg>[voctree] `Database` Constructor fix<commit_after>// This file is part of the AliceVision project.
// This Source Code Form is subject to the terms of the Mozilla Public License,
// v. 2.0. If a copy of the MPL was not distributed with this file,
// You can obtain one at https://mozilla.org/MPL/2.0/.

#pragma once

#include "VocabularyTree.hpp"
#include <aliceVision/types.hpp>

#include <map>
#include <cstddef>
#include <string>

namespace aliceVision{
namespace voctree{

/**
 * @brief Struct representing a single database match.
 *
 * \c score is in the range [0,2], where 0 is best and 2 is worst.
 */
struct DocMatch
{
  DocId id;
  float score;

  DocMatch() = default;
  DocMatch(DocId _id, float _score)
    : id(_id)
    , score(_score)
  {}

  /// Allows sorting DocMatches in best-to-worst order with std::sort.
  bool operator<(const DocMatch& other) const
  {
    return score < other.score;
  }

  bool operator==(const DocMatch& other) const
  {
    return id == other.id &&
           score == other.score;
  }
  bool operator!=(const DocMatch& other) const
  {
    return !(*this == other);
  }
};

typedef std::vector<DocMatch> DocMatches;

/**
 * @brief Class for efficiently matching a bag-of-words representation of a document (image) against
 * a database of known documents.
 */
class Database
{
public:
  /**
   * @brief Constructor
   *
   * If computing weights for a new vocabulary, \c num_words should be the size of the vocabulary.
   * If calling loadWeights(), it can be left zero.
   */
  explicit Database(uint32_t num_words = 0);

  /**
   * @brief Insert a new document.
   *
   * @param doc_id Unique ID of the new document to insert
   * @param document The set of quantized words in a document/image.
   * \return An ID representing the inserted document.
   */
  DocId insert(DocId doc_id, const SparseHistogram& document);

  /**
   * @brief Perform a sanity check of the database by querying each document
   * of the database and finding its top N matches
   *
   * @param[in] N The number of matches to return.
   * @param[out] matches IDs and scores for the top N matching database documents.
   */
   void sanityCheck(std::size_t N, std::map<std::size_t, DocMatches>& matches) const;

  /**
   * @brief Find the top N matches in the database for the query document.
   *
   * @param[in] document The query document, a set of quantized words.
   * @param[in] N        The number of matches to return.
   * @param[in] distanceMethod distance method (norm L1, etc.)
   * @param[out] matches  IDs and scores for the top N matching database documents.
   */
  void find(const std::vector<Word>& document, std::size_t N, std::vector<DocMatch>& matches, const std::string &distanceMethod = "strongCommonPoints") const;

    /**
   * @brief Find the top N matches in the database for the query document.
   *
   * @param[in] query The query document, a normalized set of quantized words.
   * @param[int] N        The number of matches to return.
   * @param[in] distanceMethod distance method (norm L1, etc.)
   * @param[out] matches  IDs and scores for the top N matching database documents.
   */
  void find(const SparseHistogram& query, std::size_t N, std::vector<DocMatch>& matches, const std::string &distanceMethod = "strongCommonPoints") const;

  /**
   * @brief Compute the TF-IDF weights of all the words. To be called after inserting a corpus of
   * training examples into the database.
   *
   * @param default_weight The default weight of a word that appears in none of the training documents.
   */
  void computeTfIdfWeights(float default_weight = 1.0f);

  /**
   * @brief Return the size of the database in terms of number of documents
   * @return the number of documents
   */
  std::size_t size() const;

  /// Save the vocabulary word weights to a file.
  void saveWeights(const std::string& file) const;
  /// Load the vocabulary word weights from a file.
  void loadWeights(const std::string& file);

  // Save weights and documents
  //void save(const std::string& file) const;
  //void load(const std::string& file);

  const SparseHistogramPerImage& getSparseHistogramPerImage() const
  {
    return database_;
  }

private:

  struct WordFrequency
  {
    DocId id;
    uint32_t count;

    WordFrequency() = default;
    WordFrequency(DocId _id, uint32_t _count)
      : id(_id)
      , count(_count)
    {}
  };

  // Stored in increasing order by DocId
  typedef std::vector<WordFrequency> InvertedFile;

  /// @todo Use sorted vector?
  // typedef std::vector< std::pair<Word, float> > DocumentVector;

  friend std::ostream& operator<<(std::ostream& os, const SparseHistogram& dv);

  std::vector<InvertedFile> word_files_;
  std::vector<float> word_weights_;
  SparseHistogramPerImage database_; // Precomputed for inserted documents

  /**
   * Normalize a document vector representing the histogram of visual words for a given image
   * @param[in/out] v the unnormalized histogram of visual words
   */
  void normalize(SparseHistogram& v) const;
};

}//namespace voctree
}//namespace aliceVision
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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.
 */
#ifndef otbTrainSharkKMeans_hxx
#define otbTrainSharkKMeans_hxx

#include "otbLearningApplicationBase.h"
#include "otbSharkKMeansMachineLearningModel.h"
#include "otbStatisticsXMLFileReader.h"

namespace otb
{
namespace Wrapper
{
template<class TInputValue, class TOutputValue>
void LearningApplicationBase<TInputValue, TOutputValue>::InitSharkKMeansParams()
{
  AddChoice( "classifier.sharkkm", "Shark kmeans classifier" );
  SetParameterDescription("classifier.sharkkm", "http://image.diku.dk/shark/sphinx_pages/build/html/rest_sources/tutorials/algorithms/kmeans.html ");

  // MaxNumberOfIterations
  AddParameter(ParameterType_Int, "classifier.sharkkm.maxiter", "Maximum number of iterations for the kmeans algorithm");
  SetParameterInt("classifier.sharkkm.maxiter", 10);
  SetMinimumParameterIntValue("classifier.sharkkm.maxiter", 0);
  SetParameterDescription("classifier.sharkkm.maxiter", "The maximum number of iterations for the kmeans algorithm. 0=unlimited");

  // Number of classes
  AddParameter(ParameterType_Int, "classifier.sharkkm.k", "Number of classes for the kmeans algorithm");
  SetParameterInt("classifier.sharkkm.k", 2);
  SetParameterDescription("classifier.sharkkm.k", "The number of classes used for the kmeans algorithm. Default set to 2 class");
  SetMinimumParameterIntValue("classifier.sharkkm.k", 2);

  AddParameter(ParameterType_InputFilename, "classifier.sharkkm.centroidstats", "Statistics file");
  SetParameterDescription("classifier.sharkkm.centroidstats", "A XML file containing mean and standard deviation to center"
    "and reduce the centroids before classification, produced by ComputeImagesStatistics application.");
  MandatoryOff("classifier.sharkkm.centroidstats");

  // Number of classes
  AddParameter(ParameterType_String, "classifier.sharkkm.centroids", "Number of classes for the kmeans algorithm");
  SetParameterDescription("classifier.sharkkm.centroids", "The number of classes used for the kmeans algorithm. Default set to 2 class");
  MandatoryOff("classifier.sharkkm.centroids");
}

template<class TInputValue, class TOutputValue>
void LearningApplicationBase<TInputValue, TOutputValue>::TrainSharkKMeans(
        typename ListSampleType::Pointer trainingListSample,
        typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath)
{
  unsigned int nbMaxIter = static_cast<unsigned int>(abs( GetParameterInt( "classifier.sharkkm.maxiter" ) ));
  unsigned int k = static_cast<unsigned int>(abs( GetParameterInt( "classifier.sharkkm.k" ) ));

  typedef otb::SharkKMeansMachineLearningModel<InputValueType, OutputValueType> SharkKMeansType;
  typename SharkKMeansType::Pointer classifier = SharkKMeansType::New();
  classifier->SetRegressionMode( this->m_RegressionFlag );
  classifier->SetInputListSample( trainingListSample );
  classifier->SetTargetListSample( trainingLabeledListSample );
  classifier->SetK( k );

  // Initialize centroids from file
  if(HasValue("classifier.sharkkm.centroids"))
  {
    shark::Data<shark::RealVector> centroidData;
    shark::importCSV(centroidData, GetParameterString( "classifier.sharkkm.centroids"), ' ');
    if( HasValue( "classifier.sharkkm.centroidstats" ) )
    {
      auto statisticsReader = otb::StatisticsXMLFileReader< itk::VariableLengthVector<float> >::New();
      statisticsReader->SetFileName(GetParameterString( "classifier.sharkkm.centroidstats" ));
      auto meanMeasurementVector = statisticsReader->GetStatisticVectorByName("mean");
      auto stddevMeasurementVector = statisticsReader->GetStatisticVectorByName("stddev");

      // Convert itk Variable Length Vector to shark Real Vector
      shark::RealVector offsetRV(meanMeasurementVector.Size());
      shark::RealVector stddevMeasurementRV(stddevMeasurementVector.Size());

      assert(meanMeasurementVector.Size()==stddevMeasurementVector.Size());
      for (unsigned int i = 0; i<meanMeasurementVector.Size(); ++i)
      {
        stddevMeasurementRV[i] = stddevMeasurementVector[i];
        // Substract the normalized mean
        offsetRV[i] = - meanMeasurementVector[i]/stddevMeasurementVector[i];
      }

      shark::Normalizer<> normalizer(stddevMeasurementRV, offsetRV);
      centroidData = normalizer(centroidData);
    }

    classifier->SetCentroidsFromData( centroidData);
  }

  classifier->SetMaximumNumberOfIterations( nbMaxIter );
  classifier->Train();
  classifier->Save( modelPath );
}

} //end namespace wrapper
} //end namespace otb

#endif
<commit_msg>BUG: fix scale formula :1/stddev<commit_after>/*
 * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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.
 */
#ifndef otbTrainSharkKMeans_hxx
#define otbTrainSharkKMeans_hxx

#include "otbLearningApplicationBase.h"
#include "otbSharkKMeansMachineLearningModel.h"
#include "otbStatisticsXMLFileReader.h"

namespace otb
{
namespace Wrapper
{
template<class TInputValue, class TOutputValue>
void LearningApplicationBase<TInputValue, TOutputValue>::InitSharkKMeansParams()
{
  AddChoice( "classifier.sharkkm", "Shark kmeans classifier" );
  SetParameterDescription("classifier.sharkkm", "http://image.diku.dk/shark/sphinx_pages/build/html/rest_sources/tutorials/algorithms/kmeans.html ");

  // MaxNumberOfIterations
  AddParameter(ParameterType_Int, "classifier.sharkkm.maxiter", "Maximum number of iterations for the kmeans algorithm");
  SetParameterInt("classifier.sharkkm.maxiter", 10);
  SetMinimumParameterIntValue("classifier.sharkkm.maxiter", 0);
  SetParameterDescription("classifier.sharkkm.maxiter", "The maximum number of iterations for the kmeans algorithm. 0=unlimited");

  // Number of classes
  AddParameter(ParameterType_Int, "classifier.sharkkm.k", "Number of classes for the kmeans algorithm");
  SetParameterInt("classifier.sharkkm.k", 2);
  SetParameterDescription("classifier.sharkkm.k", "The number of classes used for the kmeans algorithm. Default set to 2 class");
  SetMinimumParameterIntValue("classifier.sharkkm.k", 2);

  AddParameter(ParameterType_InputFilename, "classifier.sharkkm.centroidstats", "Statistics file");
  SetParameterDescription("classifier.sharkkm.centroidstats", "A XML file containing mean and standard deviation to center"
    "and reduce the centroids before classification, produced by ComputeImagesStatistics application.");
  MandatoryOff("classifier.sharkkm.centroidstats");

  // Number of classes
  AddParameter(ParameterType_InputFilename, "classifier.sharkkm.centroids", "Number of classes for the kmeans algorithm");
  SetParameterDescription("classifier.sharkkm.centroids", "The number of classes used for the kmeans algorithm. Default set to 2 class");
  MandatoryOff("classifier.sharkkm.centroids");
}

template<class TInputValue, class TOutputValue>
void LearningApplicationBase<TInputValue, TOutputValue>::TrainSharkKMeans(
        typename ListSampleType::Pointer trainingListSample,
        typename TargetListSampleType::Pointer trainingLabeledListSample, std::string modelPath)
{
  unsigned int nbMaxIter = static_cast<unsigned int>(abs( GetParameterInt( "classifier.sharkkm.maxiter" ) ));
  unsigned int k = static_cast<unsigned int>(abs( GetParameterInt( "classifier.sharkkm.k" ) ));

  typedef otb::SharkKMeansMachineLearningModel<InputValueType, OutputValueType> SharkKMeansType;
  typename SharkKMeansType::Pointer classifier = SharkKMeansType::New();
  classifier->SetRegressionMode( this->m_RegressionFlag );
  classifier->SetInputListSample( trainingListSample );
  classifier->SetTargetListSample( trainingLabeledListSample );
  classifier->SetK( k );

  // Initialize centroids from file
  if(IsParameterEnabled("classifier.sharkkm.centroids") && HasValue("classifier.sharkkm.centroids"))
  {
    shark::Data<shark::RealVector> centroidData;
    shark::importCSV(centroidData, GetParameterString( "classifier.sharkkm.centroids"), ' ');
    if( HasValue( "classifier.sharkkm.centroidstats" ) )
    {
      auto statisticsReader = otb::StatisticsXMLFileReader< itk::VariableLengthVector<float> >::New();
      statisticsReader->SetFileName(GetParameterString( "classifier.sharkkm.centroidstats" ));
      auto meanMeasurementVector = statisticsReader->GetStatisticVectorByName("mean");
      auto stddevMeasurementVector = statisticsReader->GetStatisticVectorByName("stddev");

      // Convert itk Variable Length Vector to shark Real Vector
      shark::RealVector offsetRV(meanMeasurementVector.Size());
      shark::RealVector stddevMeasurementRV(stddevMeasurementVector.Size());

      assert(meanMeasurementVector.Size()==stddevMeasurementVector.Size());
      for (unsigned int i = 0; i<meanMeasurementVector.Size(); ++i)
      {
        stddevMeasurementRV[i] = 1/stddevMeasurementVector[i];
        // Substract the normalized mean
        offsetRV[i] = - meanMeasurementVector[i]/stddevMeasurementVector[i];
      }

      shark::Normalizer<> normalizer(stddevMeasurementRV, offsetRV);
      centroidData = normalizer(centroidData);
    }

    classifier->SetCentroidsFromData( centroidData);
  }

  classifier->SetMaximumNumberOfIterations( nbMaxIter );
  classifier->Train();
  classifier->Save( modelPath );
}

} //end namespace wrapper
} //end namespace otb

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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.
 */

#ifndef otbGroundSpacingImageFunction_hxx
#define otbGroundSpacingImageFunction_hxx

#include "otbMath.h"
#include "itkConstNeighborhoodIterator.h"
#include "otbGroundSpacingImageFunction.h"

namespace otb
{

/**
 * Constructor
 */
template <class TInputImage, class TCoordRep>
GroundSpacingImageFunction<TInputImage, TCoordRep>::GroundSpacingImageFunction()
{
  m_R           = 6371000;
  m_Deg2radCoef = CONST_PI / 180;
}

/**
 *
 */
template <class TInputImage, class TCoordRep>
void GroundSpacingImageFunction<TInputImage, TCoordRep>::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  this->Superclass::PrintSelf(os, indent);
}

/**
 *
 */
template <class TInputImage, class TCoordRep>
typename GroundSpacingImageFunction<TInputImage, TCoordRep>::FloatType
GroundSpacingImageFunction<TInputImage, TCoordRep>::EvaluateAtIndex(const IndexType& index) const
{
  FloatType var;

  if (!this->GetInputImage())
  {
    var.Fill(itk::NumericTraits<ValueType>::min());
    return var;
  }

  PointType point = this->GetPixelLocation(index);

  IndexType indexSrcX, indexSrcY;
  indexSrcX[0] =
      static_cast<IndexValueType>(std::fabs(static_cast<ValueType>(this->GetInputImage()->GetLargestPossibleRegion().GetSize()[0] - index[0]))); // x position
  indexSrcX[1] = index[1];                                                                                // y position

  indexSrcY[0] = index[0]; // x position
  indexSrcY[1] = static_cast<IndexValueType>(std::fabs(static_cast<ValueType>(this->GetInputImage()->GetLargestPossibleRegion().GetSize()[1] - index[1])));

  PointType pointSrcX = this->GetPixelLocation(indexSrcX);
  PointType pointSrcY = this->GetPixelLocation(indexSrcY);

  ValueType dLatX = (std::fabs(pointSrcX[1] - point[1])) * m_Deg2radCoef;
  ValueType dLonX = (std::fabs(pointSrcX[0] - point[0])) * m_Deg2radCoef;

  const ValueType One = itk::NumericTraits<ValueType>::One;
  const ValueType Two = One + One;

  ValueType aX = std::sin(dLatX / Two) * std::sin(dLatX / Two) +
                 std::cos(point[1] * m_Deg2radCoef) * std::cos(pointSrcX[1] * m_Deg2radCoef) * std::sin(dLonX / Two) * std::sin(dLonX / Two);
  ValueType cX = Two * std::atan2(std::sqrt(aX), std::sqrt(One - aX));
  ValueType dX = m_R * cX;

  ValueType dLatY = (std::fabs(pointSrcY[1] - point[1])) * m_Deg2radCoef;
  ValueType dLonY = (std::fabs(pointSrcY[0] - point[0])) * m_Deg2radCoef;

  ValueType aY = std::sin(dLatY / Two) * std::sin(dLatY / Two) +
                 std::cos(point[1] * m_Deg2radCoef) * std::cos(pointSrcY[1] * m_Deg2radCoef) * std::sin(dLonY / Two) * std::sin(dLonY / Two);
  ValueType cY = Two * std::atan2(std::sqrt(aY), std::sqrt(One - aY));
  ValueType dY = m_R * cY;

  // FloatType var;
  var[0] = dX / (std::fabs(static_cast<ValueType>(indexSrcX[0] - index[0])));
  var[1] = dY / (std::fabs(static_cast<ValueType>(indexSrcY[1] - index[1])));

  return var;
}

template <class TInputImage, class TCoordRep>
typename GroundSpacingImageFunction<TInputImage, TCoordRep>::PointType
GroundSpacingImageFunction<TInputImage, TCoordRep>::GetPixelLocation(const IndexType& index) const
{
  PointType inputPoint;
  inputPoint[0] = index[0];
  inputPoint[1] = index[1];

  if (!this->GetInputImage())
  {
    itkExceptionMacro(<< "No input image!");
  }

  TransformType::Pointer         transform = TransformType::New();
  transform->SetOutputImageMetadata(&(this->GetInputImage()->GetImageMetadata()));
  transform->SetInputOrigin(this->GetInputImage()->GetOrigin());
  transform->SetInputSpacing(this->GetInputImage()->GetSignedSpacing());

  transform->InstantiateTransform();
  return transform->TransformPoint(inputPoint);
}

} // end namespace otb

#endif
<commit_msg>BUG: fix inverted transform in GroundSpacingImageFunction<commit_after>/*
 * Copyright (C) 2005-2020 Centre National d'Etudes Spatiales (CNES)
 *
 * This file is part of Orfeo Toolbox
 *
 *     https://www.orfeo-toolbox.org/
 *
 * 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.
 */

#ifndef otbGroundSpacingImageFunction_hxx
#define otbGroundSpacingImageFunction_hxx

#include "otbMath.h"
#include "itkConstNeighborhoodIterator.h"
#include "otbGroundSpacingImageFunction.h"

namespace otb
{

/**
 * Constructor
 */
template <class TInputImage, class TCoordRep>
GroundSpacingImageFunction<TInputImage, TCoordRep>::GroundSpacingImageFunction()
{
  m_R           = 6371000;
  m_Deg2radCoef = CONST_PI / 180;
}

/**
 *
 */
template <class TInputImage, class TCoordRep>
void GroundSpacingImageFunction<TInputImage, TCoordRep>::PrintSelf(std::ostream& os, itk::Indent indent) const
{
  this->Superclass::PrintSelf(os, indent);
}

/**
 *
 */
template <class TInputImage, class TCoordRep>
typename GroundSpacingImageFunction<TInputImage, TCoordRep>::FloatType
GroundSpacingImageFunction<TInputImage, TCoordRep>::EvaluateAtIndex(const IndexType& index) const
{
  FloatType var;

  if (!this->GetInputImage())
  {
    var.Fill(itk::NumericTraits<ValueType>::min());
    return var;
  }

  PointType point = this->GetPixelLocation(index);

  IndexType indexSrcX, indexSrcY;
  indexSrcX[0] =
      static_cast<IndexValueType>(std::fabs(static_cast<ValueType>(this->GetInputImage()->GetLargestPossibleRegion().GetSize()[0] - index[0]))); // x position
  indexSrcX[1] = index[1];                                                                                // y position

  indexSrcY[0] = index[0]; // x position
  indexSrcY[1] = static_cast<IndexValueType>(std::fabs(static_cast<ValueType>(this->GetInputImage()->GetLargestPossibleRegion().GetSize()[1] - index[1])));

  PointType pointSrcX = this->GetPixelLocation(indexSrcX);
  PointType pointSrcY = this->GetPixelLocation(indexSrcY);

  ValueType dLatX = (std::fabs(pointSrcX[1] - point[1])) * m_Deg2radCoef;
  ValueType dLonX = (std::fabs(pointSrcX[0] - point[0])) * m_Deg2radCoef;

  const ValueType One = itk::NumericTraits<ValueType>::One;
  const ValueType Two = One + One;

  ValueType aX = std::sin(dLatX / Two) * std::sin(dLatX / Two) +
                 std::cos(point[1] * m_Deg2radCoef) * std::cos(pointSrcX[1] * m_Deg2radCoef) * std::sin(dLonX / Two) * std::sin(dLonX / Two);
  ValueType cX = Two * std::atan2(std::sqrt(aX), std::sqrt(One - aX));
  ValueType dX = m_R * cX;

  ValueType dLatY = (std::fabs(pointSrcY[1] - point[1])) * m_Deg2radCoef;
  ValueType dLonY = (std::fabs(pointSrcY[0] - point[0])) * m_Deg2radCoef;

  ValueType aY = std::sin(dLatY / Two) * std::sin(dLatY / Two) +
                 std::cos(point[1] * m_Deg2radCoef) * std::cos(pointSrcY[1] * m_Deg2radCoef) * std::sin(dLonY / Two) * std::sin(dLonY / Two);
  ValueType cY = Two * std::atan2(std::sqrt(aY), std::sqrt(One - aY));
  ValueType dY = m_R * cY;

  // FloatType var;
  var[0] = dX / (std::fabs(static_cast<ValueType>(indexSrcX[0] - index[0])));
  var[1] = dY / (std::fabs(static_cast<ValueType>(indexSrcY[1] - index[1])));

  return var;
}

template <class TInputImage, class TCoordRep>
typename GroundSpacingImageFunction<TInputImage, TCoordRep>::PointType
GroundSpacingImageFunction<TInputImage, TCoordRep>::GetPixelLocation(const IndexType& index) const
{
  PointType inputPoint;
  inputPoint[0] = index[0];
  inputPoint[1] = index[1];

  if (!this->GetInputImage())
  {
    itkExceptionMacro(<< "No input image!");
  }

  TransformType::Pointer         transform = TransformType::New();
  transform->SetInputImageMetadata(&(this->GetInputImage()->GetImageMetadata()));
  transform->SetInputOrigin(this->GetInputImage()->GetOrigin());
  transform->SetInputSpacing(this->GetInputImage()->GetSignedSpacing());

  transform->InstantiateTransform();

  return transform->TransformPoint(inputPoint);
}

} // end namespace otb

#endif
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2021 Nagisa Sekiguchi
 *
 * 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 <poll.h>

#include <chrono>
#include <fstream>
#include <regex>
#include <thread>

#include <misc/num_util.hpp>

#include "client.h"

namespace ydsh::lsp {

static Result<JSON, std::string> parseJSON(const std::string &fileName, const std::string &content,
                                           unsigned int lineNumOffset) {
  JSONLexer lexer(fileName.c_str(), content.c_str());
  lexer.setLineNumOffset(lineNumOffset);
  JSONParser parser(std::move(lexer));
  auto json = parser(true);
  if (parser.hasError()) {
    return Err(parser.formatError());
  } else {
    return Ok(std::move(json));
  }
}

static bool matchSectionEnd(const std::string &line, std::smatch &match) {
  static std::regex re(R"(^(<<<|---)[ \t]*(\d*)[ \t]*$)", std::regex_constants::ECMAScript);
  return std::regex_match(line, match, re);
}

static bool isSectionEnd(const std::string &line) {
  std::smatch match;
  return matchSectionEnd(line, match);
}

static std::pair<unsigned int, bool> parseNum(const std::string &line) {
  std::smatch match;
  if (matchSectionEnd(line, match) && match.length(2) > 0) {
    auto value = match.str(2);
    return convertToNum<unsigned int>(value.c_str());
  }
  return {0, false};
}

Result<std::vector<ClientRequest>, std::string> loadInputScript(const std::string &fileName) {
  std::ifstream input(fileName);
  if (!input) {
    std::string error = "cannot read: ";
    error += fileName;
    return Err(std::move(error));
  }
  std::vector<ClientRequest> requests;
  std::string content;
  unsigned int lineNum = 0;
  unsigned int lineNumOffset = 0;
  for (std::string line; std::getline(input, line);) {
    lineNum++;
    if (!lineNumOffset) {
      lineNumOffset = lineNum;
    }
    if (line[0] == '#') {
      line = "";
    }
    if (isSectionEnd(line)) {
      auto ret = parseJSON(fileName, content, lineNumOffset);
      if (!ret) {
        return Err(std::move(ret).takeError());
      }
      content = "";
      lineNumOffset = 0;
      if (ret.asOk().isInvalid()) { // skip empty
        continue;
      }
      auto pair = parseNum(line);
      unsigned int n = pair.second ? pair.first : 0;
      requests.emplace_back(std::move(ret).take(), n);
    } else {
      content += line;
      content += '\n';
    }
  }
  if (!content.empty()) {
    auto ret = parseJSON(fileName, content, lineNumOffset);
    if (!ret) {
      return Err(std::move(ret).takeError());
    }
    requests.emplace_back(std::move(ret).take(), 0);
  }
  return Ok(std::move(requests));
}

// ####################
// ##     Client     ##
// ####################

static bool waitReply(FILE *fp, int timeout) {
  int fd = fileno(fp);
  while (true) {
    struct pollfd pollfd[1]{};
    pollfd[0].fd = fd;
    pollfd[0].events = POLLIN;

    int ret = poll(pollfd, 1, timeout);
    if (ret <= 0) {
      if (ret == -1 && errno == EINTR) {
        continue;
      }
      break;
    }
    if (pollfd[0].revents & POLLIN) {
      return true;
    }
    break;
  }
  return false;
}

void Client::run(const std::vector<ClientRequest> &requests) {
  const unsigned int size = requests.size();
  for (unsigned int index = 0; index < size; index++) {
    auto &req = requests[index];
    bool r = this->send(req.request);
    if (!r) {
      this->transport.getLogger()(LogLevel::FATAL, "request sending failed");
    }
    if (req.msec > 0) {
      std::this_thread::sleep_for(std::chrono::milliseconds(req.msec));
    }
    int timeout = index == size - 1 ? 1000 : 50;
    while (waitReply(this->transport.getInput().get(), timeout)) {
      auto ret = this->recv();
      if (!ret.hasValue()) {
        return;
      }
      if (this->replyCallback) {
        if (!this->replyCallback(std::move(ret))) {
          return;
        }
      }
    }
  }
}

bool Client::send(const JSON &json) {
  auto value = json.serialize();
  auto writeSize = this->transport.send(value.size(), value.c_str());
  return writeSize > -1 && static_cast<size_t>(writeSize) >= value.size();
}

rpc::Message Client::recv() {
  ssize_t dataSize = this->transport.recvSize();
  if (dataSize < 0) {
    if (!this->transport.available()) {
      return {};
    }
    std::string error = "may be broken or empty message";
    return rpc::Error(rpc::ErrorCode::InternalError, std::move(error));
  }

  ByteBuffer buf;
  for (ssize_t remainSize = dataSize; remainSize > 0;) {
    char data[256];
    constexpr ssize_t bufSize = std::size(data);
    ssize_t needSize = remainSize < bufSize ? remainSize : bufSize;
    ssize_t recvSize = this->transport.recv(needSize, data);
    if (recvSize < 0) {
      std::string error = "message receiving failed";
      return rpc::Error(rpc::ErrorCode::InternalError, std::move(error));
    }
    buf.append(data, static_cast<unsigned int>(recvSize));
    remainSize -= recvSize;
  }
  return rpc::MessageParser(this->transport.getLogger(), std::move(buf))();
}

} // namespace ydsh::lsp<commit_msg>[LSP] fix timeout msec of test client<commit_after>/*
 * Copyright (C) 2021 Nagisa Sekiguchi
 *
 * 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 <poll.h>

#include <chrono>
#include <fstream>
#include <regex>
#include <thread>

#include <misc/num_util.hpp>

#include "client.h"

namespace ydsh::lsp {

static Result<JSON, std::string> parseJSON(const std::string &fileName, const std::string &content,
                                           unsigned int lineNumOffset) {
  JSONLexer lexer(fileName.c_str(), content.c_str());
  lexer.setLineNumOffset(lineNumOffset);
  JSONParser parser(std::move(lexer));
  auto json = parser(true);
  if (parser.hasError()) {
    return Err(parser.formatError());
  } else {
    return Ok(std::move(json));
  }
}

static bool matchSectionEnd(const std::string &line, std::smatch &match) {
  static std::regex re(R"(^(<<<|---)[ \t]*(\d*)[ \t]*$)", std::regex_constants::ECMAScript);
  return std::regex_match(line, match, re);
}

static bool isSectionEnd(const std::string &line) {
  std::smatch match;
  return matchSectionEnd(line, match);
}

static std::pair<unsigned int, bool> parseNum(const std::string &line) {
  std::smatch match;
  if (matchSectionEnd(line, match) && match.length(2) > 0) {
    auto value = match.str(2);
    return convertToNum<unsigned int>(value.c_str());
  }
  return {0, false};
}

Result<std::vector<ClientRequest>, std::string> loadInputScript(const std::string &fileName) {
  std::ifstream input(fileName);
  if (!input) {
    std::string error = "cannot read: ";
    error += fileName;
    return Err(std::move(error));
  }
  std::vector<ClientRequest> requests;
  std::string content;
  unsigned int lineNum = 0;
  unsigned int lineNumOffset = 0;
  for (std::string line; std::getline(input, line);) {
    lineNum++;
    if (!lineNumOffset) {
      lineNumOffset = lineNum;
    }
    if (line[0] == '#') {
      line = "";
    }
    if (isSectionEnd(line)) {
      auto ret = parseJSON(fileName, content, lineNumOffset);
      if (!ret) {
        return Err(std::move(ret).takeError());
      }
      content = "";
      lineNumOffset = 0;
      if (ret.asOk().isInvalid()) { // skip empty
        continue;
      }
      auto pair = parseNum(line);
      unsigned int n = pair.second ? pair.first : 0;
      requests.emplace_back(std::move(ret).take(), n);
    } else {
      content += line;
      content += '\n';
    }
  }
  if (!content.empty()) {
    auto ret = parseJSON(fileName, content, lineNumOffset);
    if (!ret) {
      return Err(std::move(ret).takeError());
    }
    requests.emplace_back(std::move(ret).take(), 0);
  }
  return Ok(std::move(requests));
}

// ####################
// ##     Client     ##
// ####################

static bool waitReply(FILE *fp, int timeout) {
  int fd = fileno(fp);
  while (true) {
    struct pollfd pollfd[1]{};
    pollfd[0].fd = fd;
    pollfd[0].events = POLLIN;

    int ret = poll(pollfd, 1, timeout);
    if (ret <= 0) {
      if (ret == -1 && errno == EINTR) {
        continue;
      }
      break;
    }
    if (pollfd[0].revents & POLLIN) {
      return true;
    }
    break;
  }
  return false;
}

void Client::run(const std::vector<ClientRequest> &requests) {
  const unsigned int size = requests.size();
  for (unsigned int index = 0; index < size; index++) {
    auto &req = requests[index];
    bool r = this->send(req.request);
    if (!r) {
      this->transport.getLogger()(LogLevel::FATAL, "request sending failed");
    }
    if (req.msec > 0) {
      std::this_thread::sleep_for(std::chrono::milliseconds(req.msec));
    }
    int timeout = index == size - 1 ? 500 : 50;
    while (waitReply(this->transport.getInput().get(), timeout)) {
      auto ret = this->recv();
      if (!ret.hasValue()) {
        return;
      }
      if (this->replyCallback) {
        if (!this->replyCallback(std::move(ret))) {
          return;
        }
      }
    }
  }
}

bool Client::send(const JSON &json) {
  auto value = json.serialize();
  auto writeSize = this->transport.send(value.size(), value.c_str());
  return writeSize > -1 && static_cast<size_t>(writeSize) >= value.size();
}

rpc::Message Client::recv() {
  ssize_t dataSize = this->transport.recvSize();
  if (dataSize < 0) {
    if (!this->transport.available()) {
      return {};
    }
    std::string error = "may be broken or empty message";
    return rpc::Error(rpc::ErrorCode::InternalError, std::move(error));
  }

  ByteBuffer buf;
  for (ssize_t remainSize = dataSize; remainSize > 0;) {
    char data[256];
    constexpr ssize_t bufSize = std::size(data);
    ssize_t needSize = remainSize < bufSize ? remainSize : bufSize;
    ssize_t recvSize = this->transport.recv(needSize, data);
    if (recvSize < 0) {
      std::string error = "message receiving failed";
      return rpc::Error(rpc::ErrorCode::InternalError, std::move(error));
    }
    buf.append(data, static_cast<unsigned int>(recvSize));
    remainSize -= recvSize;
  }
  return rpc::MessageParser(this->transport.getLogger(), std::move(buf))();
}

} // namespace ydsh::lsp<|endoftext|>


<commit_before>#include "NFCMasterNet_WebServerModule.h"
#include "NFComm/NFMessageDefine/NFProtocolDefine.hpp"
#include <thread>

extern "C" int uhStats(UrlHandlerParam* param);
UrlHandler urlHandlerList[] = {
	{ "stats", uhStats, NULL },
	{ NULL },
};

AuthHandler authHandlerList[] = {
	{ "stats", "user", "pass", "group=admin", "" },
	{ NULL }
};

bool NFCMasterNet_WebServerModule::Init()
{
	return true;
}
bool NFCMasterNet_WebServerModule::BeforeShut()
{
	return true;
}
bool NFCMasterNet_WebServerModule::Shut()
{
	// cleanup
	_mwCloseAllConnections(hp);
	SYSLOG(LOG_INFO, "Cleaning up...\n");
	for (i = 0; i < hp->maxClients; i++) {
		if (hp->hsSocketQueue[i].buffer) free(hp->hsSocketQueue[i].buffer);
	}
	for (i = 0; hp->pxUrlHandler[i].pchUrlPrefix; i++) {
		if (hp->pxUrlHandler[i].pfnUrlHandler && hp->pxUrlHandler[i].pfnEventHandler)
			hp->pxUrlHandler[i].pfnEventHandler(MW_UNINIT, &hp->pxUrlHandler[i], hp);
	}
	free(hp->hsSocketQueue);
	hp->hsSocketQueue = 0;

	// clear state vars
	hp->bKillWebserver = FALSE;
	hp->bWebserverRunning = FALSE;
	mwServerShutdown(&httpParam);
	UninitSocket();
	return true;
}

char * NFCMasterNet_WebServerModule::GetLocalAddrString()
{
	return "127.0.0.1";
}

void NFCMasterNet_WebServerModule::GetFullPath(char * buffer, const char * path)
{
	strcpy(buffer, path);
}

bool NFCMasterNet_WebServerModule::AfterInit()
{
	mKernelModule = pPluginManager->FindModule<NFIKernelModule>();
	m_pLogicClassModule = pPluginManager->FindModule<NFIClassModule>();
	m_pElementModule = pPluginManager->FindModule<NFIElementModule>();

	NF_SHARE_PTR<NFIClass> xLogicClass = m_pLogicClassModule->GetElement(NFrame::HttpServer::ThisName());
	if (xLogicClass)
	{
		NFList<std::string>& strIdList = xLogicClass->GetIdList();
		std::string strId;
		for (bool bRet = strIdList.First(strId); bRet; bRet = strIdList.Next(strId))
		{
			nWebPort = m_pElementModule->GetPropertyInt(strId, NFrame::HttpServer::WebPort());
			strWebRootPath = m_pElementModule->GetPropertyString(strId, NFrame::HttpServer::WebRootPath());
		}
	}
	//fill in default settings
	mwInitParam(&httpParam);
	httpParam.maxClients = 50;
	GetFullPath(httpParam.pchWebPath, strWebRootPath.c_str());
	httpParam.httpPort = nWebPort;

	httpParam.pxAuthHandler = authHandlerList;
	httpParam.pxUrlHandler = urlHandlerList;
	httpParam.flags = FLAG_DIR_LISTING;
	httpParam.tmSocketExpireTime = 15;
	{
		int i;
		int error = 0;
		for (i = 0; urlHandlerList[i].pchUrlPrefix; i++) {
			if (urlHandlerList[i].pfnEventHandler) {
				if (urlHandlerList[i].pfnEventHandler(MW_PARSE_ARGS, urlHandlerList[i].pfnEventHandler, &httpParam))
					error++;
			}
		}
		if (error > 0) {
			printf("Error parsing command line options\n");
			return -1;
		}
	}

	InitSocket();

	{
		int n;
		printf("Host: %s:%d\n", GetLocalAddrString(), httpParam.httpPort);
		printf("Web root: %s\n", httpParam.pchWebPath);
		printf("Max clients (per IP): %d (%d)\n", httpParam.maxClients, httpParam.maxClientsPerIP);
		for (n = 0;urlHandlerList[n].pchUrlPrefix;n++);
		printf("URL handlers: %d\n", n);
		if (httpParam.flags & FLAG_DIR_LISTING) printf("Dir listing enabled\n");
		if (httpParam.flags & FLAG_DISABLE_RANGE) printf("Byte-range disabled\n");

		//register page variable substitution callback
		//httpParam[i].pfnSubst=DefaultWebSubstCallback;
		//start server
		if (mwServerStart(&httpParam)) {
			printf("Error starting HTTP server\n");
		}
	}
	return true;
}

bool NFCMasterNet_WebServerModule::Execute()
{
		// main processing loop
		if (!hp->bKillWebserver) {
			time_t tmCurrentTime;
			SOCKET iSelectMaxFds;
			fd_set fdsSelectRead;
			fd_set fdsSelectWrite;

			// clear descriptor sets
			FD_ZERO(&fdsSelectRead);
			FD_ZERO(&fdsSelectWrite);
			FD_SET(hp->listenSocket, &fdsSelectRead);
			iSelectMaxFds = hp->listenSocket;

			// get current time
#ifndef WINCE
			tmCurrentTime = time(NULL);
#else
			tmCurrentTime = GetTickCount() >> 10;
#endif
			// build descriptor sets and close timed out sockets
			for (int i = 0; i < hp->maxClients; i++) {
				phsSocketCur = hp->hsSocketQueue + i;

				// get socket fd
				socket = phsSocketCur->socket;
				if (!socket) continue;

				{
					int iError = 0;
					int iOptSize = sizeof(int);
					if (getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&iError, &iOptSize)) {
						// if a socket contains a error, close it
						SYSLOG(LOG_INFO, "[%d] Socket no longer vaild.\n", socket);
						phsSocketCur->flags = FLAG_CONN_CLOSE;
						_mwCloseSocket(hp, phsSocketCur);
						continue;
					}
				}
				// check expiration timer (for non-listening, in-use sockets)
				if (tmCurrentTime > phsSocketCur->tmExpirationTime) {
					SYSLOG(LOG_INFO, "[%d] Http socket expired\n", phsSocketCur->socket);
					hp->stats.timeOutCount++;
					// close connection
					phsSocketCur->flags = FLAG_CONN_CLOSE;
					_mwCloseSocket(hp, phsSocketCur);
				}
				else {
					if (phsSocketCur->dwResumeTick) {
						// suspended
						if (phsSocketCur->dwResumeTick > GetTickCount())
							continue;
						else
							phsSocketCur->dwResumeTick = 0;
					}
					if (ISFLAGSET(phsSocketCur, FLAG_RECEIVING)) {
						// add to read descriptor set
						FD_SET(socket, &fdsSelectRead);
					}
					if (ISFLAGSET(phsSocketCur, FLAG_SENDING)) {
						// add to write descriptor set
						FD_SET(socket, &fdsSelectWrite);
					}
					// check if new max socket
					if (socket > iSelectMaxFds) {
						iSelectMaxFds = socket;
					}
				}
			}

			{
				struct timeval tvSelectWait;
				// initialize select delay
				tvSelectWait.tv_sec = 1;
				tvSelectWait.tv_usec = 0; // note: using timeval here -> usec not nsec

										  // and check sockets (may take a while!)
				iRc = select(iSelectMaxFds + 1, &fdsSelectRead, &fdsSelectWrite,
					NULL, &tvSelectWait);
			}
			if (iRc < 0) {
				msleep(1000);
				return true;
			}
			if (iRc > 0) {
				// check which sockets are read/write able
				for (i = 0; i < hp->maxClients; i++) {
					BOOL bRead;
					BOOL bWrite;

					phsSocketCur = hp->hsSocketQueue + i;

					// get socket fd
					socket = phsSocketCur->socket;
					if (!socket) continue;

					// get read/write status for socket
					bRead = FD_ISSET(socket, &fdsSelectRead);
					bWrite = FD_ISSET(socket, &fdsSelectWrite);

					if ((bRead | bWrite) != 0) {
						//DBG("socket %d bWrite=%d, bRead=%d\n",phsSocketCur->socket,bWrite,bRead);
						// if readable or writeable then process
						if (bWrite && ISFLAGSET(phsSocketCur, FLAG_SENDING)) {
							iRc = _mwProcessWriteSocket(hp, phsSocketCur);
						}
						else if (bRead && ISFLAGSET(phsSocketCur, FLAG_RECEIVING)) {
							iRc = _mwProcessReadSocket(hp, phsSocketCur);
						}
						else {
							iRc = -1;
							DBG("Invalid socket state (flag: %08x)\n", phsSocketCur->flags);
						}
						if (!iRc) {
							// and reset expiration timer
#ifndef WINCE
							phsSocketCur->tmExpirationTime = time(NULL) + hp->tmSocketExpireTime;
#else
							phsSocketCur->tmExpirationTime = (GetTickCount() >> 10) + hp->tmSocketExpireTime;
#endif
						}
						else {
							SETFLAG(phsSocketCur, FLAG_CONN_CLOSE);
							_mwCloseSocket(hp, phsSocketCur);
						}
					}
				}

				// check if any socket to accept and accept the socket
				if (FD_ISSET(hp->listenSocket, &fdsSelectRead)) {
					// find empty slot
					phsSocketCur = 0;
					for (i = 0; i < hp->maxClients; i++) {
						if (hp->hsSocketQueue[i].socket == 0) {
							phsSocketCur = hp->hsSocketQueue + i;
							break;
						}
					}

					if (!phsSocketCur) {
						DBG("WARNING: clientCount:%d > maxClients:%d\n", hp->stats.clientCount, hp->maxClients);
						_mwDenySocket(hp, &sinaddr);
						return true;
					}

					phsSocketCur->socket = _mwAcceptSocket(hp, &sinaddr);
					if (phsSocketCur->socket == 0) return true;
					phsSocketCur->ipAddr.laddr = ntohl(sinaddr.sin_addr.s_addr);
					SYSLOG(LOG_INFO, "[%d] IP: %d.%d.%d.%d\n",
						phsSocketCur->socket,
						phsSocketCur->ipAddr.caddr[3],
						phsSocketCur->ipAddr.caddr[2],
						phsSocketCur->ipAddr.caddr[1],
						phsSocketCur->ipAddr.caddr[0]);

					hp->stats.clientCount++;

					//fill structure with data
					_mwInitSocketData(phsSocketCur);
					phsSocketCur->request.pucPayload = 0;
#ifndef WINCE
					phsSocketCur->tmAcceptTime = time(NULL);
#else
					phsSocketCur->tmAcceptTime = GetTickCount() >> 10;
#endif
					phsSocketCur->tmExpirationTime = phsSocketCur->tmAcceptTime + hp->tmSocketExpireTime;
					phsSocketCur->iRequestCount = 0;
					DBG("Connected clients: %d\n", hp->stats.clientCount);

					//update max client count
					if (hp->stats.clientCount > hp->stats.clientCountMax) hp->stats.clientCountMax = hp->stats.clientCount;
				}
			}
			else {
				//DBG("Select Timeout\n");
				// select timeout
				// call idle event
				if (hp->pfnIdleCallback) {
					(*hp->pfnIdleCallback)(hp);
				}
			}
		}

	return true;
}
<commit_msg>fixed for compile<commit_after>#include "NFCMasterNet_WebServerModule.h"
#include "NFComm/NFMessageDefine/NFProtocolDefine.hpp"
#include <thread>

extern "C" int uhStats(UrlHandlerParam* param);
UrlHandler urlHandlerList[] = {
	{ "stats", uhStats, NULL },
	{ NULL },
};

AuthHandler authHandlerList[] = {
	{ "stats", "user", "pass", "group=admin", "" },
	{ NULL }
};

bool NFCMasterNet_WebServerModule::Init()
{
	return true;
}
bool NFCMasterNet_WebServerModule::BeforeShut()
{
	return true;
}
bool NFCMasterNet_WebServerModule::Shut()
{
	// cleanup
	_mwCloseAllConnections(hp);
	SYSLOG(LOG_INFO, "Cleaning up...\n");
	for (i = 0; i < hp->maxClients; i++) {
		if (hp->hsSocketQueue[i].buffer) free(hp->hsSocketQueue[i].buffer);
	}
	for (i = 0; hp->pxUrlHandler[i].pchUrlPrefix; i++) {
		if (hp->pxUrlHandler[i].pfnUrlHandler && hp->pxUrlHandler[i].pfnEventHandler)
			hp->pxUrlHandler[i].pfnEventHandler(MW_UNINIT, &hp->pxUrlHandler[i], hp);
	}
	free(hp->hsSocketQueue);
	hp->hsSocketQueue = 0;

	// clear state vars
	hp->bKillWebserver = FALSE;
	hp->bWebserverRunning = FALSE;
	mwServerShutdown(&httpParam);
	UninitSocket();
	return true;
}

char * NFCMasterNet_WebServerModule::GetLocalAddrString()
{
	return "127.0.0.1";
}

void NFCMasterNet_WebServerModule::GetFullPath(char * buffer, const char * path)
{
	strcpy(buffer, path);
}

bool NFCMasterNet_WebServerModule::AfterInit()
{
	mKernelModule = pPluginManager->FindModule<NFIKernelModule>();
	m_pLogicClassModule = pPluginManager->FindModule<NFIClassModule>();
	m_pElementModule = pPluginManager->FindModule<NFIElementModule>();

	NF_SHARE_PTR<NFIClass> xLogicClass = m_pLogicClassModule->GetElement(NFrame::HttpServer::ThisName());
	if (xLogicClass)
	{
		NFList<std::string>& strIdList = xLogicClass->GetIdList();
		std::string strId;
		for (bool bRet = strIdList.First(strId); bRet; bRet = strIdList.Next(strId))
		{
			nWebPort = m_pElementModule->GetPropertyInt(strId, NFrame::HttpServer::WebPort());
			strWebRootPath = m_pElementModule->GetPropertyString(strId, NFrame::HttpServer::WebRootPath());
		}
	}
	//fill in default settings
	mwInitParam(&httpParam);
	httpParam.maxClients = 50;
	GetFullPath(httpParam.pchWebPath, strWebRootPath.c_str());
	httpParam.httpPort = nWebPort;

	httpParam.pxAuthHandler = authHandlerList;
	httpParam.pxUrlHandler = urlHandlerList;
	httpParam.flags = FLAG_DIR_LISTING;
	httpParam.tmSocketExpireTime = 15;
	{
		int i;
		int error = 0;
		for (i = 0; urlHandlerList[i].pchUrlPrefix; i++) {
			if (urlHandlerList[i].pfnEventHandler) {
				if (urlHandlerList[i].pfnEventHandler(MW_PARSE_ARGS, (void*)urlHandlerList[i].pfnEventHandler, &httpParam))
					error++;
			}
		}
		if (error > 0) {
			printf("Error parsing command line options\n");
			return -1;
		}
	}

	InitSocket();

	{
		int n;
		printf("Host: %s:%d\n", GetLocalAddrString(), httpParam.httpPort);
		printf("Web root: %s\n", httpParam.pchWebPath);
		printf("Max clients (per IP): %d (%d)\n", httpParam.maxClients, httpParam.maxClientsPerIP);
		for (n = 0;urlHandlerList[n].pchUrlPrefix;n++);
		printf("URL handlers: %d\n", n);
		if (httpParam.flags & FLAG_DIR_LISTING) printf("Dir listing enabled\n");
		if (httpParam.flags & FLAG_DISABLE_RANGE) printf("Byte-range disabled\n");

		//register page variable substitution callback
		//httpParam[i].pfnSubst=DefaultWebSubstCallback;
		//start server
		if (mwServerStart(&httpParam)) {
			printf("Error starting HTTP server\n");
		}
	}
	return true;
}

bool NFCMasterNet_WebServerModule::Execute()
{
		// main processing loop
		if (!hp->bKillWebserver) {
			time_t tmCurrentTime;
			SOCKET iSelectMaxFds;
			fd_set fdsSelectRead;
			fd_set fdsSelectWrite;

			// clear descriptor sets
			FD_ZERO(&fdsSelectRead);
			FD_ZERO(&fdsSelectWrite);
			FD_SET(hp->listenSocket, &fdsSelectRead);
			iSelectMaxFds = hp->listenSocket;

			// get current time
#ifndef WINCE
			tmCurrentTime = time(NULL);
#else
			tmCurrentTime = GetTickCount() >> 10;
#endif
			// build descriptor sets and close timed out sockets
			for (int i = 0; i < hp->maxClients; i++) {
				phsSocketCur = hp->hsSocketQueue + i;

				// get socket fd
				socket = phsSocketCur->socket;
				if (!socket) continue;

				{
					int iError = 0;
					int iOptSize = sizeof(int);
					if (getsockopt(socket, SOL_SOCKET, SO_ERROR, (char*)&iError, (socklen_t*)&iOptSize)) {
						// if a socket contains a error, close it
						SYSLOG(LOG_INFO, "[%d] Socket no longer vaild.\n", socket);
						phsSocketCur->flags = FLAG_CONN_CLOSE;
						_mwCloseSocket(hp, phsSocketCur);
						continue;
					}
				}
				// check expiration timer (for non-listening, in-use sockets)
				if (tmCurrentTime > phsSocketCur->tmExpirationTime) {
					SYSLOG(LOG_INFO, "[%d] Http socket expired\n", phsSocketCur->socket);
					hp->stats.timeOutCount++;
					// close connection
					phsSocketCur->flags = FLAG_CONN_CLOSE;
					_mwCloseSocket(hp, phsSocketCur);
				}
				else {
					if (phsSocketCur->dwResumeTick) {
						// suspended
						if (phsSocketCur->dwResumeTick > GetTickCount())
							continue;
						else
							phsSocketCur->dwResumeTick = 0;
					}
					if (ISFLAGSET(phsSocketCur, FLAG_RECEIVING)) {
						// add to read descriptor set
						FD_SET(socket, &fdsSelectRead);
					}
					if (ISFLAGSET(phsSocketCur, FLAG_SENDING)) {
						// add to write descriptor set
						FD_SET(socket, &fdsSelectWrite);
					}
					// check if new max socket
					if (socket > iSelectMaxFds) {
						iSelectMaxFds = socket;
					}
				}
			}

			{
				struct timeval tvSelectWait;
				// initialize select delay
				tvSelectWait.tv_sec = 1;
				tvSelectWait.tv_usec = 0; // note: using timeval here -> usec not nsec

										  // and check sockets (may take a while!)
				iRc = select(iSelectMaxFds + 1, &fdsSelectRead, &fdsSelectWrite,
					NULL, &tvSelectWait);
			}
			if (iRc < 0) {
				msleep(1000);
				return true;
			}
			if (iRc > 0) {
				// check which sockets are read/write able
				for (i = 0; i < hp->maxClients; i++) {
					BOOL bRead;
					BOOL bWrite;

					phsSocketCur = hp->hsSocketQueue + i;

					// get socket fd
					socket = phsSocketCur->socket;
					if (!socket) continue;

					// get read/write status for socket
					bRead = FD_ISSET(socket, &fdsSelectRead);
					bWrite = FD_ISSET(socket, &fdsSelectWrite);

					if ((bRead | bWrite) != 0) {
						//DBG("socket %d bWrite=%d, bRead=%d\n",phsSocketCur->socket,bWrite,bRead);
						// if readable or writeable then process
						if (bWrite && ISFLAGSET(phsSocketCur, FLAG_SENDING)) {
							iRc = _mwProcessWriteSocket(hp, phsSocketCur);
						}
						else if (bRead && ISFLAGSET(phsSocketCur, FLAG_RECEIVING)) {
							iRc = _mwProcessReadSocket(hp, phsSocketCur);
						}
						else {
							iRc = -1;
							DBG("Invalid socket state (flag: %08x)\n", phsSocketCur->flags);
						}
						if (!iRc) {
							// and reset expiration timer
#ifndef WINCE
							phsSocketCur->tmExpirationTime = time(NULL) + hp->tmSocketExpireTime;
#else
							phsSocketCur->tmExpirationTime = (GetTickCount() >> 10) + hp->tmSocketExpireTime;
#endif
						}
						else {
							SETFLAG(phsSocketCur, FLAG_CONN_CLOSE);
							_mwCloseSocket(hp, phsSocketCur);
						}
					}
				}

				// check if any socket to accept and accept the socket
				if (FD_ISSET(hp->listenSocket, &fdsSelectRead)) {
					// find empty slot
					phsSocketCur = 0;
					for (i = 0; i < hp->maxClients; i++) {
						if (hp->hsSocketQueue[i].socket == 0) {
							phsSocketCur = hp->hsSocketQueue + i;
							break;
						}
					}

					if (!phsSocketCur) {
						DBG("WARNING: clientCount:%d > maxClients:%d\n", hp->stats.clientCount, hp->maxClients);
						_mwDenySocket(hp, &sinaddr);
						return true;
					}

					phsSocketCur->socket = _mwAcceptSocket(hp, &sinaddr);
					if (phsSocketCur->socket == 0) return true;
					phsSocketCur->ipAddr.laddr = ntohl(sinaddr.sin_addr.s_addr);
					SYSLOG(LOG_INFO, "[%d] IP: %d.%d.%d.%d\n",
						phsSocketCur->socket,
						phsSocketCur->ipAddr.caddr[3],
						phsSocketCur->ipAddr.caddr[2],
						phsSocketCur->ipAddr.caddr[1],
						phsSocketCur->ipAddr.caddr[0]);

					hp->stats.clientCount++;

					//fill structure with data
					_mwInitSocketData(phsSocketCur);
					phsSocketCur->request.pucPayload = 0;
#ifndef WINCE
					phsSocketCur->tmAcceptTime = time(NULL);
#else
					phsSocketCur->tmAcceptTime = GetTickCount() >> 10;
#endif
					phsSocketCur->tmExpirationTime = phsSocketCur->tmAcceptTime + hp->tmSocketExpireTime;
					phsSocketCur->iRequestCount = 0;
					DBG("Connected clients: %d\n", hp->stats.clientCount);

					//update max client count
					if (hp->stats.clientCount > hp->stats.clientCountMax) hp->stats.clientCountMax = hp->stats.clientCount;
				}
			}
			else {
				//DBG("Select Timeout\n");
				// select timeout
				// call idle event
				if (hp->pfnIdleCallback) {
					(*hp->pfnIdleCallback)(hp);
				}
			}
		}

	return true;
}
<|endoftext|>


<commit_before><commit_msg>fix build bustage<commit_after><|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of the Qt Build Suite
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file.
** Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**************************************************************************/
#include "../shared/specialplatformssetup.h"
#include "../../lib/tools/platformglobals.h"

#include <QBuffer>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QProcessEnvironment>

#include <iostream>
#include <cstdlib>

namespace qbs {

class MaddePlatformsSetup : public SpecialPlatformsSetup
{
private:
    QString defaultBaseDirectory() const;
    QString platformTypeName() const { return QLatin1String("MADDE"); }
    QList<PlatformInfo> gatherPlatformInfo();

    QStringList gatherMaddeTargetNames();
    PlatformInfo gatherMaddePlatformInfo(const QString &targetName);

    QString m_maddeBinDir;
};

QString MaddePlatformsSetup::defaultBaseDirectory() const
{
#ifdef Q_OS_WIN
    return QLatin1String("C:/QtSDK/Madde");
#else
    return QDir::homePath() + QLatin1String("/QtSDK/Madde");
#endif
}

QList<SpecialPlatformsSetup::PlatformInfo> MaddePlatformsSetup::gatherPlatformInfo()
{
    m_maddeBinDir = baseDirectory() + QLatin1String("/bin");

    const QStringList &maddeTargetNames = gatherMaddeTargetNames();
    if (maddeTargetNames.isEmpty())
        throw Exception(tr("Error: No targets found."));

    QList<PlatformInfo> platforms;
    foreach (const QString &targetName, maddeTargetNames)
        platforms << gatherMaddePlatformInfo(targetName);
    return platforms;
}

QStringList MaddePlatformsSetup::gatherMaddeTargetNames()
{
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    QString madListCommandLine = m_maddeBinDir + QLatin1String("/mad list");
#ifdef Q_OS_WIN
    const QString pathKey = QLatin1String("PATH");
    const QString oldPath = env.value(pathKey);
    QString newPath = m_maddeBinDir;
    if (!oldPath.isEmpty())
        newPath.append(QLatin1Char(';') + oldPath);
    env.insert(pathKey, newPath);
    madListCommandLine.prepend(m_maddeBinDir + QLatin1String("/sh.exe "));
#endif
    QByteArray madListOutput = runProcess(madListCommandLine, env).trimmed();

    QBuffer buf(&madListOutput);
    buf.open(QIODevice::ReadOnly);
    bool inTargetSection = false;
    QStringList targetNames;
    while (buf.canReadLine()) {
        const QByteArray line = buf.readLine().simplified();
        if (!inTargetSection) {
            if (line == "Targets:")
                inTargetSection = true;
            continue;
        }
        if (line.isEmpty())
            break;
        const QList<QByteArray> lineContents = line.split(' ');
        if (lineContents.count() != 2)
            throw Exception(tr("Unexpected output from command '%1'.").arg(madListCommandLine));
        if (lineContents.at(1) == "(installed)" || lineContents.at(1) == "(default)")
            targetNames << QString::fromLocal8Bit(lineContents.first());
    }
    return targetNames;
}

SpecialPlatformsSetup::PlatformInfo MaddePlatformsSetup::gatherMaddePlatformInfo(const QString &target)
{
    const QString targetDir = baseDirectory() + QLatin1String("/targets/") + target;
    const QString infoFilePath = targetDir + QLatin1String("/information");
    QFile infoFile(infoFilePath);
    if (!infoFile.open(QIODevice::ReadOnly)) {
        throw Exception(tr("Cannot open file '%1': %2.")
            .arg(QDir::toNativeSeparators(infoFilePath), infoFile.errorString()));
    }
    PlatformInfo platformInfo;
    QByteArray fileContent = infoFile.readAll();
    QBuffer buf(&fileContent); // QFile::canReadLine() always returns false. WTF?
    buf.open(QIODevice::ReadOnly);
    while (buf.canReadLine()) {
        const QList<QByteArray> lineContents = buf.readLine().simplified().split(' ');
        if (lineContents.count() != 2)
            continue;
        if (lineContents.first() != "sysroot")
            continue;
        platformInfo.sysrootDir = baseDirectory() + QLatin1String("/sysroots/")
            + QString::fromLocal8Bit(lineContents.at(1));
        break;
    }
    if (platformInfo.sysrootDir.isEmpty())
        throw Exception(tr("Error: No sysroot information found for target '%1'.").arg(target));

    platformInfo.name = target;
    platformInfo.targetOS = QLatin1String("linux");
    platformInfo.targetPlatform << QLatin1String("unix") << QLatin1String("linux");
    if (target.contains(QLatin1String("harmattan")))
        platformInfo.targetPlatform << QLatin1String("meego") << QLatin1String("maemo6");
    platformInfo.toolchainDir = targetDir + QLatin1String("/bin");
    platformInfo.compilerName = QLatin1String("g++");
    platformInfo.qtBinDir = platformInfo.toolchainDir;
    platformInfo.qtIncDir = platformInfo.sysrootDir + QLatin1String("/usr/include/qt4");
    platformInfo.qtMkspecsDir = platformInfo.sysrootDir + QLatin1String("/usr/share/qt4/mkspecs");
    platformInfo.environment.insert(QLatin1String("SYSROOT_DIR"), platformInfo.sysrootDir);
    const QString maddeMadLibDir = baseDirectory() + QLatin1String("/madlib");
    platformInfo.environment.insert(QLatin1String("PERL5LIB"), maddeMadLibDir);

    const QString maddeMadBinDir = baseDirectory() + QLatin1String("/madbin");
    const QString targetBinDir = targetDir + QLatin1String("/bin");

    // !!! The order matters here !!!
    const QChar sep = QLatin1Char(nativePathVariableSeparator);
    const QString pathValue = targetBinDir + sep + m_maddeBinDir + sep + maddeMadLibDir + sep
        + maddeMadBinDir;
    platformInfo.environment.insert(QLatin1String("PATH"), pathValue);

    const QString mangleWhiteList = QLatin1String("/usr") + sep + QLatin1String("/lib") + sep
        + QLatin1String("/opt");
    platformInfo.environment.insert(QLatin1String("GCCWRAPPER_PATHMANGLE"), mangleWhiteList);

    return platformInfo;
}

} // namespace qbs

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    qbs::MaddePlatformsSetup setup;
    try {
        setup.setup();
    } catch (const qbs::SpecialPlatformsSetup::Exception &ex) {
        std::cerr << qPrintable(setup.tr("Error: %1").arg(ex.errorMessage)) << std::endl;
        return EXIT_FAILURE;
    }

    if (setup.helpRequested())
        std::cout << qPrintable(setup.helpString()) << std::endl;
    return EXIT_SUCCESS;
}
<commit_msg>Fixed path to Madde's perl libraries<commit_after>/**************************************************************************
**
** This file is part of the Qt Build Suite
**
** Copyright (c) 2012 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (info@qt.nokia.com)
**
**
** GNU Lesser General Public License Usage
**
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this file.
** Please review the following information to ensure the GNU Lesser General
** Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file.
** Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**************************************************************************/
#include "../shared/specialplatformssetup.h"
#include "../../lib/tools/platformglobals.h"

#include <QBuffer>
#include <QCoreApplication>
#include <QDir>
#include <QFile>
#include <QProcessEnvironment>

#include <iostream>
#include <cstdlib>

namespace qbs {

class MaddePlatformsSetup : public SpecialPlatformsSetup
{
private:
    QString defaultBaseDirectory() const;
    QString platformTypeName() const { return QLatin1String("MADDE"); }
    QList<PlatformInfo> gatherPlatformInfo();

    QStringList gatherMaddeTargetNames();
    PlatformInfo gatherMaddePlatformInfo(const QString &targetName);

    QString m_maddeBinDir;
};

QString MaddePlatformsSetup::defaultBaseDirectory() const
{
#ifdef Q_OS_WIN
    return QLatin1String("C:/QtSDK/Madde");
#else
    return QDir::homePath() + QLatin1String("/QtSDK/Madde");
#endif
}

QList<SpecialPlatformsSetup::PlatformInfo> MaddePlatformsSetup::gatherPlatformInfo()
{
    m_maddeBinDir = baseDirectory() + QLatin1String("/bin");

    const QStringList &maddeTargetNames = gatherMaddeTargetNames();
    if (maddeTargetNames.isEmpty())
        throw Exception(tr("Error: No targets found."));

    QList<PlatformInfo> platforms;
    foreach (const QString &targetName, maddeTargetNames)
        platforms << gatherMaddePlatformInfo(targetName);
    return platforms;
}

QStringList MaddePlatformsSetup::gatherMaddeTargetNames()
{
    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
    QString madListCommandLine = m_maddeBinDir + QLatin1String("/mad list");
#ifdef Q_OS_WIN
    const QString pathKey = QLatin1String("PATH");
    const QString oldPath = env.value(pathKey);
    QString newPath = m_maddeBinDir;
    if (!oldPath.isEmpty())
        newPath.append(QLatin1Char(';') + oldPath);
    env.insert(pathKey, newPath);
    madListCommandLine.prepend(m_maddeBinDir + QLatin1String("/sh.exe "));
#endif
    QByteArray madListOutput = runProcess(madListCommandLine, env).trimmed();

    QBuffer buf(&madListOutput);
    buf.open(QIODevice::ReadOnly);
    bool inTargetSection = false;
    QStringList targetNames;
    while (buf.canReadLine()) {
        const QByteArray line = buf.readLine().simplified();
        if (!inTargetSection) {
            if (line == "Targets:")
                inTargetSection = true;
            continue;
        }
        if (line.isEmpty())
            break;
        const QList<QByteArray> lineContents = line.split(' ');
        if (lineContents.count() != 2)
            throw Exception(tr("Unexpected output from command '%1'.").arg(madListCommandLine));
        if (lineContents.at(1) == "(installed)" || lineContents.at(1) == "(default)")
            targetNames << QString::fromLocal8Bit(lineContents.first());
    }
    return targetNames;
}

SpecialPlatformsSetup::PlatformInfo MaddePlatformsSetup::gatherMaddePlatformInfo(const QString &target)
{
    const QString targetDir = baseDirectory() + QLatin1String("/targets/") + target;
    const QString infoFilePath = targetDir + QLatin1String("/information");
    QFile infoFile(infoFilePath);
    if (!infoFile.open(QIODevice::ReadOnly)) {
        throw Exception(tr("Cannot open file '%1': %2.")
            .arg(QDir::toNativeSeparators(infoFilePath), infoFile.errorString()));
    }
    PlatformInfo platformInfo;
    QByteArray fileContent = infoFile.readAll();
    QBuffer buf(&fileContent); // QFile::canReadLine() always returns false. WTF?
    buf.open(QIODevice::ReadOnly);
    while (buf.canReadLine()) {
        const QList<QByteArray> lineContents = buf.readLine().simplified().split(' ');
        if (lineContents.count() != 2)
            continue;
        if (lineContents.first() != "sysroot")
            continue;
        platformInfo.sysrootDir = baseDirectory() + QLatin1String("/sysroots/")
            + QString::fromLocal8Bit(lineContents.at(1));
        break;
    }
    if (platformInfo.sysrootDir.isEmpty())
        throw Exception(tr("Error: No sysroot information found for target '%1'.").arg(target));

    platformInfo.name = target;
    platformInfo.targetOS = QLatin1String("linux");
    platformInfo.targetPlatform << QLatin1String("unix") << QLatin1String("linux");
    if (target.contains(QLatin1String("harmattan")))
        platformInfo.targetPlatform << QLatin1String("meego") << QLatin1String("maemo6");
    platformInfo.toolchainDir = targetDir + QLatin1String("/bin");
    platformInfo.compilerName = QLatin1String("g++");
    platformInfo.qtBinDir = platformInfo.toolchainDir;
    platformInfo.qtIncDir = platformInfo.sysrootDir + QLatin1String("/usr/include/qt4");
    platformInfo.qtMkspecsDir = platformInfo.sysrootDir + QLatin1String("/usr/share/qt4/mkspecs");
    platformInfo.environment.insert(QLatin1String("SYSROOT_DIR"), platformInfo.sysrootDir);
    const QString maddeMadLibDir = baseDirectory() + QLatin1String("/madlib");
    platformInfo.environment.insert(QLatin1String("PERL5LIB"), maddeMadLibDir + QLatin1String("/perl5"));

    const QString maddeMadBinDir = baseDirectory() + QLatin1String("/madbin");
    const QString targetBinDir = targetDir + QLatin1String("/bin");

    // !!! The order matters here !!!
    const QChar sep = QLatin1Char(nativePathVariableSeparator);
    const QString pathValue = targetBinDir + sep + m_maddeBinDir + sep + maddeMadLibDir + sep
        + maddeMadBinDir;
    platformInfo.environment.insert(QLatin1String("PATH"), pathValue);

    const QString mangleWhiteList = QLatin1String("/usr") + sep + QLatin1String("/lib") + sep
        + QLatin1String("/opt");
    platformInfo.environment.insert(QLatin1String("GCCWRAPPER_PATHMANGLE"), mangleWhiteList);

    return platformInfo;
}

} // namespace qbs

int main(int argc, char *argv[])
{
    QCoreApplication app(argc, argv);
    qbs::MaddePlatformsSetup setup;
    try {
        setup.setup();
    } catch (const qbs::SpecialPlatformsSetup::Exception &ex) {
        std::cerr << qPrintable(setup.tr("Error: %1").arg(ex.errorMessage)) << std::endl;
        return EXIT_FAILURE;
    }

    if (setup.helpRequested())
        std::cout << qPrintable(setup.helpString()) << std::endl;
    return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "AutoPacketFactory.h"
#include "AutoPacket.h"
#include "thread_specific_ptr.h"

AutoPacketFactory::AutoPacketFactory(void):
  ContextMember("AutoPacketFactory"),
  m_parent(GetContext()->GetParentContext()),
  m_wasStopped(false),
  m_packets(AutoPacket::CreateObjectPool(*this, m_outstanding))
{}

AutoPacketFactory::~AutoPacketFactory() {
  // Invalidate the pool and recursively invalidate all parents
  Invalidate();
}

std::shared_ptr<AutoPacket> AutoPacketFactory::NewPacket(void) {
  if(ShouldStop())
    throw autowiring_error("Attempted to create a packet on an AutoPacketFactory that was already terminated");
  if(!IsRunning())
    throw autowiring_error("Cannot create a packet until the AutoPacketFactory is started");

  // Obtain a packet, return it
  std::shared_ptr<AutoPacket> retVal;
  m_packets(retVal);

  // Done, return
  return retVal;
}

bool AutoPacketFactory::Start(std::shared_ptr<Object> outstanding) {
  std::lock_guard<std::mutex> lk(m_lock);
  if(m_wasStopped)
    // Cannot start if already stopped
    return false;

  m_outstanding = outstanding;
  m_stateCondition.notify_all();
  return true;
}

void AutoPacketFactory::Stop(bool graceful) {
  // Return optimization
  if(m_wasStopped)
    return;

  // Kill the object pool
  m_packets.SetOutstandingLimit(0);
  Invalidate();

  // Queue of local variables to be destroyed when leaving scope
  std::shared_ptr<Object> outstanding;
  t_autoFilterSet autoFilters;

  // Lock destruction precedes local variables
  std::lock_guard<std::mutex> lk(m_lock);

  // Swap outstanding count into a local var, so we can reset outside of a lock
  outstanding.swap(m_outstanding);

  // Same story with the AutoFilters
  autoFilters.swap(m_autoFilters);

  // Now we can lock, update state, and notify any listeners
  m_wasStopped = true;
  m_stateCondition.notify_all();
}

void AutoPacketFactory::Clear(void) {
  // Simple handoff to Stop is sufficient
  Stop(false);
}

void AutoPacketFactory::Wait(void) {
  {
    std::unique_lock<std::mutex> lk(m_lock);
    m_stateCondition.wait(lk, [this]{ return ShouldStop(); });
  }

  // Now we need to block until all packets come back to the object pool:
  m_packets.Rundown();
}

void AutoPacketFactory::Invalidate(void) {
  m_packets.ClearCachedEntities();
  if(m_parent)
    m_parent->Invalidate();
}

void AutoPacketFactory::AddSubscriber(const AutoFilterDescriptor& rhs) {
  (std::lock_guard<std::mutex>)m_lock,
  m_autoFilters.insert(rhs);

  // Trigger object pool reset after releasing the lock.  While it's possible that some
  // packets may be issued between lock reset and object pool reset, these packets will
  // not be specifically invalid; they will simply result in late delivery to certain
  // recipients.  Eventually, all packets will be reset and released.
  Invalidate();
}

void AutoPacketFactory::RemoveSubscriber(const AutoFilterDescriptor& autoFilter) {
  // Trivial removal from the autofilter set:
  {
    std::lock_guard<std::mutex> lk(m_lock);
    m_autoFilters.erase(autoFilter);
  }

  // Regeneration of the packet pool for the same reason as described in AddSubscriber
  Invalidate();
}

AutoFilterDescriptor AutoPacketFactory::GetTypeDescriptorUnsafe(const std::type_info* nodeType) {
  AutoFilterDescriptor descriptor;
  //ASSUME: type_info uniquely specifies descriptor
  for (auto& af : m_autoFilters) {
    if (af.GetAutoFilterTypeInfo() == nodeType) {
      descriptor = af;
      break;
    }
  }
  //NOTE: If descriptor was not found descriptor.GetAutoFilterTypeInfo() == nullptr
  return descriptor;
}

void AutoPacketFactory::BroadcastOneDataOut(const std::type_info* nodeType, const std::type_info* dataType, bool enable) {
  {
    if (IsAutoPacketType(*dataType)) {
      // AutoPacket is always broacast to the entire context
      return;
    }

    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy the AutoFilterDescriptor instance.
    AutoFilterDescriptor update = GetTypeDescriptorUnsafe(nodeType);
    if (!update.GetAutoFilterTypeInfo())
      return;

    const AutoFilterDescriptorInput* argDescriptor = update.GetArgumentType(dataType);
    if (!argDescriptor ||
        !argDescriptor->isOutput()) {
      std::stringstream ss;
      ss << "Attempted to transmit broadcasts of a type " << dataType->name()
      << " that is not an output of " << nodeType->name();
      throw std::runtime_error(ss.str());
    }

    // Extract, modify and insert the broadcast state
    m_autoFilters.erase(update);
    update.Broadcast(dataType, enable);
    m_autoFilters.insert(update);
  }
  Invalidate();
}

void AutoPacketFactory::BroadcastAllDataOut(const std::type_info* nodeType, bool enable) {
  {
    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy the AutoFilterDescriptor instance.
    AutoFilterDescriptor update = GetTypeDescriptorUnsafe(nodeType);
    if (!update.GetAutoFilterTypeInfo())
      return;

    // Extract, modify and insert the broadcast state
    m_autoFilters.erase(update);
    // All input data types accept broadcasts
    // NOTE: Iteration is over a static array terminated with nullptr
    for (const AutoFilterDescriptorInput* pArg = update.GetAutoFilterInput(); *pArg; ++pArg) {
      if (pArg->isOutput())
        update.Broadcast(pArg->ti, enable);
    }
    m_autoFilters.insert(update);
  }
  Invalidate();
}

void AutoPacketFactory::BroadcastOneDataIn(const std::type_info* nodeType, const std::type_info* dataType, bool enable) {
  {
    if (IsAutoPacketType(*dataType)) {
      // AutoPacket is always broacast to the entire context
      return;
    }

    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy the AutoFilterDescriptor instance.
    AutoFilterDescriptor update = GetTypeDescriptorUnsafe(nodeType);
    if (!update.GetAutoFilterTypeInfo())
      return;

    const AutoFilterDescriptorInput* argDescriptor = update.GetArgumentType(dataType);
    if (!argDescriptor ||
        !argDescriptor->isInput()) {
      std::stringstream ss;
      ss << "Attempted to receive broadcasts of a type " << dataType->name()
      << " that is not an input to " << nodeType->name();
      throw std::runtime_error(ss.str());
    }

    // Extract, modify and insert the broadcast state
    m_autoFilters.erase(update);
    update.Broadcast(dataType, enable);
    m_autoFilters.insert(update);
  }
  Invalidate();
}

void AutoPacketFactory::BroadcastAllDataIn(const std::type_info* nodeType, bool enable) {
  {
    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy the AutoFilterDescriptor instance.
    AutoFilterDescriptor update = GetTypeDescriptorUnsafe(nodeType);
    if (!update.GetAutoFilterTypeInfo())
      return;

    // Extract, modify and insert the broadcast state
    m_autoFilters.erase(update);
    // All input data types accept broadcasts
    // NOTE: Iteration is over a static array terminated with nullptr
    for (const AutoFilterDescriptorInput* pArg = update.GetAutoFilterInput(); *pArg; ++pArg) {
      if (pArg->isInput() &&
          !IsAutoPacketType(*pArg->ti))
        update.Broadcast(pArg->ti, enable);
    }
    m_autoFilters.insert(update);
  }
  Invalidate();
}

void AutoPacketFactory::PipeOneData(const std::type_info* nodeOutType, const std::type_info* nodeInType, const std::type_info* dataType, bool enable) {
  if (IsAutoPacketType(*dataType)) {
    // AutoPacket is always broacast to the entire context
    return;
  }

  {
    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy both AutoFilterDescriptor instances.
    AutoFilterDescriptor updateOut = GetTypeDescriptorUnsafe(nodeOutType);
    AutoFilterDescriptor updateIn = GetTypeDescriptorUnsafe(nodeInType);
    if (!updateOut.GetAutoFilterTypeInfo() ||
        !updateIn.GetAutoFilterTypeInfo())
      return;

    // Check for AutoPacket& (or const AutoPacket&) arguments
    bool allOut =
      updateOut.GetArgumentType(&typeid(subscriber_traits<AutoPacket&>::type));
    bool allIn =
      updateIn.GetArgumentType(&typeid(subscriber_traits<AutoPacket&>::type)) ||
      updateIn.GetArgumentType(&typeid(subscriber_traits<const AutoPacket&>::type));

    // Find both data types
    const AutoFilterDescriptorInput* argOutDescriptor = updateOut.GetArgumentType(dataType);
    const AutoFilterDescriptorInput* argInDescriptor = updateIn.GetArgumentType(dataType);
    if (!(allOut || (argOutDescriptor && argOutDescriptor->isOutput())) ||
        !(allIn || (argInDescriptor && argInDescriptor->isInput()))) {
      std::stringstream ss;
      ss << "Attempted to pipe data of a type " << dataType->name()
      << " that is not an ouput of " << nodeOutType->name()
      << " and an input to " << nodeInType->name();
      throw std::runtime_error(ss.str());
    }

    // Extract, modify and insert the half-pipes
    m_autoFilters.erase(updateOut);
    m_autoFilters.erase(updateIn);
    updateOut.HalfPipe(dataType, nodeInType, enable);
    updateIn.HalfPipe(dataType, nodeOutType, enable);
    m_autoFilters.insert(updateOut);
    m_autoFilters.insert(updateIn);
  }
  Invalidate();
}

void AutoPacketFactory::PipeAllData(const std::type_info* nodeOutType, const std::type_info* nodeInType, bool enable) {
  {
    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy both AutoFilterDescriptor instances.
    AutoFilterDescriptor updateOut = GetTypeDescriptorUnsafe(nodeOutType);
    AutoFilterDescriptor updateIn = GetTypeDescriptorUnsafe(nodeInType);
    if (!updateOut.GetAutoFilterTypeInfo() ||
        !updateIn.GetAutoFilterTypeInfo())
      return;

    // Check for AutoPacket& (or const AutoPacket&) arguments
    bool allOut =
      updateOut.GetArgumentType(&typeid(subscriber_traits<AutoPacket&>::type));
    bool allIn =
      updateIn.GetArgumentType(&typeid(subscriber_traits<AutoPacket&>::type)) ||
      updateIn.GetArgumentType(&typeid(subscriber_traits<const AutoPacket&>::type));

    // List all correctly oriented arguments
    std::unordered_set<const std::type_info*> dataOutTypes;
    std::unordered_set<const std::type_info*> dataInTypes;
    dataOutTypes.reserve(updateOut.GetArity());
    for (const AutoFilterDescriptorInput* pArg = updateOut.GetAutoFilterInput(); *pArg; ++pArg) {
      if (IsAutoPacketType(*pArg->ti))
        continue;
      if (allOut || pArg->isOutput()) {
        dataOutTypes.insert(pArg->ti);
        if (allIn)
          dataInTypes.insert(pArg->ti);
      }
    }
    dataInTypes.reserve(updateIn.GetArity());
    for (const AutoFilterDescriptorInput* pArg = updateIn.GetAutoFilterInput(); *pArg; ++pArg) {
      if (IsAutoPacketType(*pArg->ti))
        continue;
      if (allIn || pArg->isInput()) {
        // Include only output types
        if (allOut ||
            dataOutTypes.find(pArg->ti) != dataOutTypes.end()) {
          dataInTypes.insert(pArg->ti);
          if (allOut)
            dataInTypes.insert(pArg->ti);
        }
      }
    }

    // Extract, modify and insert the half-pipes
    m_autoFilters.erase(updateOut);
    m_autoFilters.erase(updateIn);
    for (const std::type_info* dataType : dataInTypes) {
      updateOut.HalfPipe(dataType, nodeInType, enable);
      updateIn.HalfPipe(dataType, nodeOutType, enable);
    }
    m_autoFilters.insert(updateOut);
    m_autoFilters.insert(updateIn);
  }
  Invalidate();
}
<commit_msg>Correcting MSVC warning C4800<commit_after>// Copyright (C) 2012-2014 Leap Motion, Inc. All rights reserved.
#include "stdafx.h"
#include "AutoPacketFactory.h"
#include "AutoPacket.h"
#include "thread_specific_ptr.h"

AutoPacketFactory::AutoPacketFactory(void):
  ContextMember("AutoPacketFactory"),
  m_parent(GetContext()->GetParentContext()),
  m_wasStopped(false),
  m_packets(AutoPacket::CreateObjectPool(*this, m_outstanding))
{}

AutoPacketFactory::~AutoPacketFactory() {
  // Invalidate the pool and recursively invalidate all parents
  Invalidate();
}

std::shared_ptr<AutoPacket> AutoPacketFactory::NewPacket(void) {
  if(ShouldStop())
    throw autowiring_error("Attempted to create a packet on an AutoPacketFactory that was already terminated");
  if(!IsRunning())
    throw autowiring_error("Cannot create a packet until the AutoPacketFactory is started");

  // Obtain a packet, return it
  std::shared_ptr<AutoPacket> retVal;
  m_packets(retVal);

  // Done, return
  return retVal;
}

bool AutoPacketFactory::Start(std::shared_ptr<Object> outstanding) {
  std::lock_guard<std::mutex> lk(m_lock);
  if(m_wasStopped)
    // Cannot start if already stopped
    return false;

  m_outstanding = outstanding;
  m_stateCondition.notify_all();
  return true;
}

void AutoPacketFactory::Stop(bool graceful) {
  // Return optimization
  if(m_wasStopped)
    return;

  // Kill the object pool
  m_packets.SetOutstandingLimit(0);
  Invalidate();

  // Queue of local variables to be destroyed when leaving scope
  std::shared_ptr<Object> outstanding;
  t_autoFilterSet autoFilters;

  // Lock destruction precedes local variables
  std::lock_guard<std::mutex> lk(m_lock);

  // Swap outstanding count into a local var, so we can reset outside of a lock
  outstanding.swap(m_outstanding);

  // Same story with the AutoFilters
  autoFilters.swap(m_autoFilters);

  // Now we can lock, update state, and notify any listeners
  m_wasStopped = true;
  m_stateCondition.notify_all();
}

void AutoPacketFactory::Clear(void) {
  // Simple handoff to Stop is sufficient
  Stop(false);
}

void AutoPacketFactory::Wait(void) {
  {
    std::unique_lock<std::mutex> lk(m_lock);
    m_stateCondition.wait(lk, [this]{ return ShouldStop(); });
  }

  // Now we need to block until all packets come back to the object pool:
  m_packets.Rundown();
}

void AutoPacketFactory::Invalidate(void) {
  m_packets.ClearCachedEntities();
  if(m_parent)
    m_parent->Invalidate();
}

void AutoPacketFactory::AddSubscriber(const AutoFilterDescriptor& rhs) {
  (std::lock_guard<std::mutex>)m_lock,
  m_autoFilters.insert(rhs);

  // Trigger object pool reset after releasing the lock.  While it's possible that some
  // packets may be issued between lock reset and object pool reset, these packets will
  // not be specifically invalid; they will simply result in late delivery to certain
  // recipients.  Eventually, all packets will be reset and released.
  Invalidate();
}

void AutoPacketFactory::RemoveSubscriber(const AutoFilterDescriptor& autoFilter) {
  // Trivial removal from the autofilter set:
  {
    std::lock_guard<std::mutex> lk(m_lock);
    m_autoFilters.erase(autoFilter);
  }

  // Regeneration of the packet pool for the same reason as described in AddSubscriber
  Invalidate();
}

AutoFilterDescriptor AutoPacketFactory::GetTypeDescriptorUnsafe(const std::type_info* nodeType) {
  AutoFilterDescriptor descriptor;
  //ASSUME: type_info uniquely specifies descriptor
  for (auto& af : m_autoFilters) {
    if (af.GetAutoFilterTypeInfo() == nodeType) {
      descriptor = af;
      break;
    }
  }
  //NOTE: If descriptor was not found descriptor.GetAutoFilterTypeInfo() == nullptr
  return descriptor;
}

void AutoPacketFactory::BroadcastOneDataOut(const std::type_info* nodeType, const std::type_info* dataType, bool enable) {
  {
    if (IsAutoPacketType(*dataType)) {
      // AutoPacket is always broacast to the entire context
      return;
    }

    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy the AutoFilterDescriptor instance.
    AutoFilterDescriptor update = GetTypeDescriptorUnsafe(nodeType);
    if (!update.GetAutoFilterTypeInfo())
      return;

    const AutoFilterDescriptorInput* argDescriptor = update.GetArgumentType(dataType);
    if (!argDescriptor ||
        !argDescriptor->isOutput()) {
      std::stringstream ss;
      ss << "Attempted to transmit broadcasts of a type " << dataType->name()
      << " that is not an output of " << nodeType->name();
      throw std::runtime_error(ss.str());
    }

    // Extract, modify and insert the broadcast state
    m_autoFilters.erase(update);
    update.Broadcast(dataType, enable);
    m_autoFilters.insert(update);
  }
  Invalidate();
}

void AutoPacketFactory::BroadcastAllDataOut(const std::type_info* nodeType, bool enable) {
  {
    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy the AutoFilterDescriptor instance.
    AutoFilterDescriptor update = GetTypeDescriptorUnsafe(nodeType);
    if (!update.GetAutoFilterTypeInfo())
      return;

    // Extract, modify and insert the broadcast state
    m_autoFilters.erase(update);
    // All input data types accept broadcasts
    // NOTE: Iteration is over a static array terminated with nullptr
    for (const AutoFilterDescriptorInput* pArg = update.GetAutoFilterInput(); *pArg; ++pArg) {
      if (pArg->isOutput())
        update.Broadcast(pArg->ti, enable);
    }
    m_autoFilters.insert(update);
  }
  Invalidate();
}

void AutoPacketFactory::BroadcastOneDataIn(const std::type_info* nodeType, const std::type_info* dataType, bool enable) {
  {
    if (IsAutoPacketType(*dataType)) {
      // AutoPacket is always broacast to the entire context
      return;
    }

    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy the AutoFilterDescriptor instance.
    AutoFilterDescriptor update = GetTypeDescriptorUnsafe(nodeType);
    if (!update.GetAutoFilterTypeInfo())
      return;

    const AutoFilterDescriptorInput* argDescriptor = update.GetArgumentType(dataType);
    if (!argDescriptor ||
        !argDescriptor->isInput()) {
      std::stringstream ss;
      ss << "Attempted to receive broadcasts of a type " << dataType->name()
      << " that is not an input to " << nodeType->name();
      throw std::runtime_error(ss.str());
    }

    // Extract, modify and insert the broadcast state
    m_autoFilters.erase(update);
    update.Broadcast(dataType, enable);
    m_autoFilters.insert(update);
  }
  Invalidate();
}

void AutoPacketFactory::BroadcastAllDataIn(const std::type_info* nodeType, bool enable) {
  {
    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy the AutoFilterDescriptor instance.
    AutoFilterDescriptor update = GetTypeDescriptorUnsafe(nodeType);
    if (!update.GetAutoFilterTypeInfo())
      return;

    // Extract, modify and insert the broadcast state
    m_autoFilters.erase(update);
    // All input data types accept broadcasts
    // NOTE: Iteration is over a static array terminated with nullptr
    for (const AutoFilterDescriptorInput* pArg = update.GetAutoFilterInput(); *pArg; ++pArg) {
      if (pArg->isInput() &&
          !IsAutoPacketType(*pArg->ti))
        update.Broadcast(pArg->ti, enable);
    }
    m_autoFilters.insert(update);
  }
  Invalidate();
}

void AutoPacketFactory::PipeOneData(const std::type_info* nodeOutType, const std::type_info* nodeInType, const std::type_info* dataType, bool enable) {
  if (IsAutoPacketType(*dataType)) {
    // AutoPacket is always broacast to the entire context
    return;
  }

  {
    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy both AutoFilterDescriptor instances.
    AutoFilterDescriptor updateOut = GetTypeDescriptorUnsafe(nodeOutType);
    AutoFilterDescriptor updateIn = GetTypeDescriptorUnsafe(nodeInType);
    if (!updateOut.GetAutoFilterTypeInfo() ||
        !updateIn.GetAutoFilterTypeInfo())
      return;

    // Check for AutoPacket& (or const AutoPacket&) arguments
    bool allOut =
      !!updateOut.GetArgumentType(&typeid(subscriber_traits<AutoPacket&>::type));
    bool allIn =
      updateIn.GetArgumentType(&typeid(subscriber_traits<AutoPacket&>::type)) ||
      updateIn.GetArgumentType(&typeid(subscriber_traits<const AutoPacket&>::type));

    // Find both data types
    const AutoFilterDescriptorInput* argOutDescriptor = updateOut.GetArgumentType(dataType);
    const AutoFilterDescriptorInput* argInDescriptor = updateIn.GetArgumentType(dataType);
    if (!(allOut || (argOutDescriptor && argOutDescriptor->isOutput())) ||
        !(allIn || (argInDescriptor && argInDescriptor->isInput()))) {
      std::stringstream ss;
      ss << "Attempted to pipe data of a type " << dataType->name()
      << " that is not an ouput of " << nodeOutType->name()
      << " and an input to " << nodeInType->name();
      throw std::runtime_error(ss.str());
    }

    // Extract, modify and insert the half-pipes
    m_autoFilters.erase(updateOut);
    m_autoFilters.erase(updateIn);
    updateOut.HalfPipe(dataType, nodeInType, enable);
    updateIn.HalfPipe(dataType, nodeOutType, enable);
    m_autoFilters.insert(updateOut);
    m_autoFilters.insert(updateIn);
  }
  Invalidate();
}

void AutoPacketFactory::PipeAllData(const std::type_info* nodeOutType, const std::type_info* nodeInType, bool enable) {
  {
    std::lock_guard<std::mutex> guard(m_lock);

    // Find and copy both AutoFilterDescriptor instances.
    AutoFilterDescriptor updateOut = GetTypeDescriptorUnsafe(nodeOutType);
    AutoFilterDescriptor updateIn = GetTypeDescriptorUnsafe(nodeInType);
    if (!updateOut.GetAutoFilterTypeInfo() ||
        !updateIn.GetAutoFilterTypeInfo())
      return;

    // Check for AutoPacket& (or const AutoPacket&) arguments
    bool allOut =
      !!updateOut.GetArgumentType(&typeid(subscriber_traits<AutoPacket&>::type));
    bool allIn =
      updateIn.GetArgumentType(&typeid(subscriber_traits<AutoPacket&>::type)) ||
      updateIn.GetArgumentType(&typeid(subscriber_traits<const AutoPacket&>::type));

    // List all correctly oriented arguments
    std::unordered_set<const std::type_info*> dataOutTypes;
    std::unordered_set<const std::type_info*> dataInTypes;
    dataOutTypes.reserve(updateOut.GetArity());
    for (const AutoFilterDescriptorInput* pArg = updateOut.GetAutoFilterInput(); *pArg; ++pArg) {
      if (IsAutoPacketType(*pArg->ti))
        continue;
      if (allOut || pArg->isOutput()) {
        dataOutTypes.insert(pArg->ti);
        if (allIn)
          dataInTypes.insert(pArg->ti);
      }
    }
    dataInTypes.reserve(updateIn.GetArity());
    for (const AutoFilterDescriptorInput* pArg = updateIn.GetAutoFilterInput(); *pArg; ++pArg) {
      if (IsAutoPacketType(*pArg->ti))
        continue;
      if (allIn || pArg->isInput()) {
        // Include only output types
        if (allOut ||
            dataOutTypes.find(pArg->ti) != dataOutTypes.end()) {
          dataInTypes.insert(pArg->ti);
          if (allOut)
            dataInTypes.insert(pArg->ti);
        }
      }
    }

    // Extract, modify and insert the half-pipes
    m_autoFilters.erase(updateOut);
    m_autoFilters.erase(updateIn);
    for (const std::type_info* dataType : dataInTypes) {
      updateOut.HalfPipe(dataType, nodeInType, enable);
      updateIn.HalfPipe(dataType, nodeOutType, enable);
    }
    m_autoFilters.insert(updateOut);
    m_autoFilters.insert(updateIn);
  }
  Invalidate();
}
<|endoftext|>