<commit_before>#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/dpm.hpp>
#include <opencv2/tracking.hpp>

#include <cstring>
#include <fstream>
#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace cv::dpm;
using namespace std;

void drawDPMBoxes(Mat &frame,
                  vector<DPMDetector::ObjectDetection> ds,
                  Scalar color,
                  string text);

void drawKCFBoxes(Mat &frame,
                  Rect rect,
                  Scalar color,
                  string text);

bool write_count(int count);

static const int LOW_PASS = 0;
static const string CLEAR_FILE = "/opt/mz-bicycle-commuter/reset";
static const string LEFT_OUTPUT_FILE = "/opt/mz-bicycle-commuter/left.count";

int main( int argc, char** argv )
{
    bool ENTER_LEAVE = true;
    bool FRAMES_FIRST = true;

    Mat frame;
    Mat image;
    const char* keys =
    {
        "{@model_path    | | Path of the DPM cascade model}"
        "{@video_source    | | Video Source}"
    };

    CommandLineParser parser(argc, argv, keys);
    string model_path(parser.get<string>(0));

    // init DPM
    Ptr<DPMDetector> detector = \
    DPMDetector::create(vector<string>(1, model_path));
    vector<DPMDetector::ObjectDetection> ds;

    // init KCF
    Ptr<Tracker> tracker;
    Rect2d roi;
    Rect result; // Tracker results
    int count = 0;
    //use web camera
    VideoCapture capture(0);
    capture.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480);

    if( model_path.empty() )
    {
        cerr << "Fail to open model file!" << endl;
        return -1;
    }

    if ( !capture.isOpened() )
    {
        cerr << "Fail to open default camera (0)!" << endl;
        return -1;
    }

    // create window
    namedWindow("tracker", 1);

    while (true){
        //get the frame
        capture >> frame;

        if ( frame.empty() ){
            cerr << "Fail to get video!" << endl;
            break;
        }

        //DPM detection
        if( ENTER_LEAVE )
        {
            double t = (double) getTickCount(); //start time

            frame.copyTo(image);

            // detection
            detector->detect(image, ds);

            ds.erase(std::remove_if(ds.begin(),
                                    ds.end(),
                                    [&](const DPMDetector::ObjectDetection& o)
                                    {return o.score<LOW_PASS;}
                                    ),
                     ds.end());
            if (!ds.empty())
            {
                for (const auto i: ds)
                    std::cout << i.score << ' ';
                cout << endl;

                ENTER_LEAVE = false;
                FRAMES_FIRST = true;

            }

            t = ((double) getTickCount() - t)/getTickFrequency(); //elapsed time
            string text = format("%0.1f fps", 1.0/t); //calculate fps

            // draw the tracked object
            Scalar color(0,0,255);
            drawDPMBoxes(frame, ds, color, text);
        } else {

            //KCF tracking
            double t = (double) getTickCount(); //start time
            if ( FRAMES_FIRST )
            {
                // get bounding box
                roi = ds[0].rect;

                // initialize the tracker
                tracker = Tracker::create("KCF");
                bool success = tracker->init(frame,roi);

                FRAMES_FIRST = !success ;
            }

            // Update
            else{

                // update the tracking result
                bool was_successful = tracker->update(frame,roi);

                if (!was_successful) {
                    continue;
                }
                result = roi;
                //DPM model detect UAV's leave
                int x_value = 640 - result.x + result.width/2;
                int y_value = 480 - result.y + result.height/2;
                if (!(result.x > 0 && result.y > 0 && x_value > 0 && y_value > 0)){
                    ENTER_LEAVE = true;
                    count++;
                    bool reset_count = write_count(count);
                     string count_text;
                    if (reset_count) {
                        count = 0;
                        count_text = "Count was reset";
                    } else {
                        count_text  = format("%ld bicycles!", count);
                    }

                    cout << count_text << endl;

                }
            }
            t = ((double) getTickCount() - t)/getTickFrequency(); //elapsed time
            string text = format("%0.1f fps", 1.0/t); //calculate fps

            // draw the tracked object
            Scalar color(0,0,255);
            drawKCFBoxes(frame, roi, color, text);
        }

        // show image with the tracked object
        imshow("tracker",frame);
        if(waitKey(1)==27)break;
    }
    return 0;
}

bool write_count(int count)
{
    ofstream resultsFile;
    bool should_clear = std::ifstream(CLEAR_FILE).good();

    int file_count = should_clear ? 1 : count;
    resultsFile.open(LEFT_OUTPUT_FILE);
    resultsFile << file_count  << endl;
    resultsFile.close();
    if(should_clear) {
        remove(CLEAR_FILE.c_str());
    }

    return should_clear;
}

void drawDPMBoxes(Mat &frame,
                  vector<DPMDetector::ObjectDetection> ds,
                  Scalar color,
                  string text)
{
    for (unsigned int i = 0; i < ds.size(); i++)
    {
        rectangle(frame, ds[i].rect, color, 2);
    }

    // draw text on image
    Scalar textColor(255,0,0);
    putText(frame, text, Point(10,50), FONT_HERSHEY_PLAIN, 2, textColor, 2);
}

void drawKCFBoxes(Mat &frame,
                  Rect rect,
                  Scalar color,
                  string text)
{
    rectangle(frame, rect, color, 2);

    // draw text on image
    Scalar textColor(255,0,0);
    putText(frame, text, Point(10,50), FONT_HERSHEY_PLAIN, 2, textColor, 2);
}
<commit_msg>Remove colors from input<commit_after>#include <opencv2/core.hpp>
#include <opencv2/core/utility.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/videoio.hpp>
#include <opencv2/dpm.hpp>
#include <opencv2/tracking.hpp>

#include <cstring>
#include <fstream>
#include <iostream>
#include <stdio.h>

using namespace cv;
using namespace cv::dpm;
using namespace std;

void drawDPMBoxes(Mat &frame,
                  vector<DPMDetector::ObjectDetection> ds,
                  Scalar color,
                  string text);

void drawKCFBoxes(Mat &frame,
                  Rect rect,
                  Scalar color,
                  string text);

bool write_count(int count);

static const int LOW_PASS = 0;
static const string CLEAR_FILE = "/opt/mz-bicycle-commuter/reset";
static const string LEFT_OUTPUT_FILE = "/opt/mz-bicycle-commuter/left.count";

int main( int argc, char** argv )
{
    bool ENTER_LEAVE = true;
    bool FRAMES_FIRST = true;

    Mat frame;
    Mat image;
    const char* keys =
    {
        "{@model_path    | | Path of the DPM cascade model}"
        "{@video_source    | | Video Source}"
    };

    CommandLineParser parser(argc, argv, keys);
    string model_path(parser.get<string>(0));

    // init DPM
    Ptr<DPMDetector> detector = \
    DPMDetector::create(vector<string>(1, model_path));
    vector<DPMDetector::ObjectDetection> ds;

    // init KCF
    Ptr<Tracker> tracker;
    Rect2d roi;
    Rect result; // Tracker results
    int count = 0;
    //use web camera
    VideoCapture capture(0);
    capture.set(CV_CAP_PROP_FRAME_WIDTH, 640);
    capture.set(CV_CAP_PROP_FRAME_HEIGHT, 480);
    capture.set(CV_CAP_PROP_CONVERT_RGB, false);
    double fps = capture.get(CAP_PROP_FPS);

     cout << fps << endl;

    if( model_path.empty() )
    {
        cerr << "Fail to open model file!" << endl;
        return -1;
    }

    if ( !capture.isOpened() )
    {
        cerr << "Fail to open default camera (0)!" << endl;
        return -1;
    }

    // create window
//    namedWindow("tracker", 1);

    while (true){
        //get the frame
        capture >> frame;

        if ( frame.empty() ){
            cerr << "Fail to get video!" << endl;
            break;
        }

        //DPM detection
        if( ENTER_LEAVE )
        {
            double t = (double) getTickCount(); //start time

            frame.copyTo(image);

            // detection
            detector->detect(image, ds);

            ds.erase(std::remove_if(ds.begin(),
                                    ds.end(),
                                    [&](const DPMDetector::ObjectDetection& o)
                                    {return o.score<LOW_PASS;}
                                    ),
                     ds.end());
            if (!ds.empty())
            {
                for (const auto i: ds)
                    std::cout << i.score << ' ';
                cout << endl;

                ENTER_LEAVE = false;
                FRAMES_FIRST = true;

            }

            t = ((double) getTickCount() - t)/getTickFrequency(); //elapsed time
            string text = format("%0.1f fps", 1.0/t); //calculate fps

            // draw the tracked object
            Scalar color(0,0,255);
            drawDPMBoxes(frame, ds, color, text);
        } else {

            //KCF tracking
            double t = (double) getTickCount(); //start time
            if ( FRAMES_FIRST )
            {
                // get bounding box
                roi = ds[0].rect;

                // initialize the tracker
                tracker = Tracker::create("KCF");
                bool success = tracker->init(frame,roi);

                FRAMES_FIRST = !success ;
            }

            // Update
            else{

                // update the tracking result
                bool was_successful = tracker->update(frame,roi);

                if (!was_successful) {
                    continue;
                }
                result = roi;
                //DPM model detect UAV's leave
                int x_value = 640 - result.x + result.width/2;
                int y_value = 480 - result.y + result.height/2;
                if (!(result.x > 0 && result.y > 0 && x_value > 0 && y_value > 0)){
                    ENTER_LEAVE = true;
                    count++;
                    bool reset_count = write_count(count);
                     string count_text;
                    if (reset_count) {
                        count = 0;
                        count_text = "Count was reset";
                    } else {
                        count_text  = format("%ld bicycles!", count);
                    }

                    cout << count_text << endl;

                }
            }
            t = ((double) getTickCount() - t)/getTickFrequency(); //elapsed time
            string text = format("%0.1f fps", 1.0/t); //calculate fps

            // draw the tracked object
            Scalar color(0,0,255);
            drawKCFBoxes(frame, roi, color, text);
        }

        // show image with the tracked object
//        imshow("tracker",frame);
        if(waitKey(1)==27)break;
    }
    return 0;
}

bool write_count(int count)
{
    ofstream resultsFile;
    bool should_clear = std::ifstream(CLEAR_FILE).good();

    int file_count = should_clear ? 1 : count;
    resultsFile.open(LEFT_OUTPUT_FILE);
    resultsFile << file_count  << endl;
    resultsFile.close();
    if(should_clear) {
        remove(CLEAR_FILE.c_str());
    }

    return should_clear;
}

void drawDPMBoxes(Mat &frame,
                  vector<DPMDetector::ObjectDetection> ds,
                  Scalar color,
                  string text)
{
    for (unsigned int i = 0; i < ds.size(); i++)
    {
        rectangle(frame, ds[i].rect, color, 2);
    }

    // draw text on image
    Scalar textColor(255,0,0);
    putText(frame, text, Point(10,50), FONT_HERSHEY_PLAIN, 2, textColor, 2);
}

void drawKCFBoxes(Mat &frame,
                  Rect rect,
                  Scalar color,
                  string text)
{
    rectangle(frame, rect, color, 2);

    // draw text on image
    Scalar textColor(255,0,0);
    putText(frame, text, Point(10,50), FONT_HERSHEY_PLAIN, 2, textColor, 2);
}
<|endoftext|>


<commit_before>// vim:tabstop=2
/***********************************************************************
 Moses - factored phrase-based language decoder
 Copyright (C) 2010 Hieu Hoang

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

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 ***********************************************************************/

#include "ChartTrellisNode.h"

#include "ChartHypothesis.h"
#include "ChartTrellisDetour.h"
#include "ChartTrellisPath.h"
#include "StaticData.h"

namespace Moses
{

ChartTrellisNode::ChartTrellisNode(const ChartHypothesis &hypo)
  : m_hypo(hypo)
{
  CreateChildren();
}

ChartTrellisNode::ChartTrellisNode(const ChartTrellisDetour &detour,
                                   ChartTrellisNode *&deviationPoint)
  : m_hypo((&detour.GetBasePath().GetFinalNode() == &detour.GetSubstitutedNode())
           ? detour.GetReplacementHypo()
           : detour.GetBasePath().GetFinalNode().GetHypothesis())
{
  if (&m_hypo == &detour.GetReplacementHypo()) {
    deviationPoint = this;
    CreateChildren();
  } else {
    CreateChildren(detour.GetBasePath().GetFinalNode(),
                   detour.GetSubstitutedNode(), detour.GetReplacementHypo(),
                   deviationPoint);
  }
}

ChartTrellisNode::ChartTrellisNode(const ChartTrellisNode &root,
                                   const ChartTrellisNode &substitutedNode,
                                   const ChartHypothesis &replacementHypo,
                                   ChartTrellisNode *&deviationPoint)
  : m_hypo((&root == &substitutedNode)
           ? replacementHypo
           : root.GetHypothesis())
{
  if (&root == &substitutedNode) {
    deviationPoint = this;
    CreateChildren();
  } else {
    CreateChildren(root, substitutedNode, replacementHypo, deviationPoint);
  }
}

ChartTrellisNode::~ChartTrellisNode()
{
  RemoveAllInColl(m_children);
}

Phrase ChartTrellisNode::GetOutputPhrase() const
{
  // exactly like same fn in hypothesis, but use trellis nodes instead of prevHypos pointer
  Phrase ret(ARRAY_SIZE_INCR);

  const Phrase &currTargetPhrase = m_hypo.GetCurrTargetPhrase();
  const AlignmentInfo::NonTermIndexMap &nonTermIndexMap =
    m_hypo.GetCurrTargetPhrase().GetAlignNonTerm().GetNonTermIndexMap();
  for (size_t pos = 0; pos < currTargetPhrase.GetSize(); ++pos) {
    const Word &word = currTargetPhrase.GetWord(pos);
    if (word.IsNonTerminal()) {
      // non-term. fill out with prev hypo
      size_t nonTermInd = nonTermIndexMap[pos];
      const ChartTrellisNode &childNode = GetChild(nonTermInd);
      Phrase childPhrase = childNode.GetOutputPhrase();
      ret.Append(childPhrase);
    } else {
      ret.AddWord(word);
    }
  }

  return ret;
}

void ChartTrellisNode::CreateChildren()
{
  CHECK(m_children.empty());
  const std::vector<const ChartHypothesis*> &prevHypos = m_hypo.GetPrevHypos();
  m_children.reserve(prevHypos.size());
  for (size_t ind = 0; ind < prevHypos.size(); ++ind) {
    const ChartHypothesis *prevHypo = prevHypos[ind];
    ChartTrellisNode *child = new ChartTrellisNode(*prevHypo);
    m_children.push_back(child);
  }
}

void ChartTrellisNode::CreateChildren(const ChartTrellisNode &rootNode,
                                      const ChartTrellisNode &substitutedNode,
                                      const ChartHypothesis &replacementHypo,
                                      ChartTrellisNode *&deviationPoint)
{
  CHECK(m_children.empty());
  const NodeChildren &children = rootNode.GetChildren();
  m_children.reserve(children.size());
  for (size_t ind = 0; ind < children.size(); ++ind) {
    const ChartTrellisNode *origChild = children[ind];
    ChartTrellisNode *child = new ChartTrellisNode(*origChild, substitutedNode,
        replacementHypo,
        deviationPoint);
    m_children.push_back(child);
  }
}

}
<commit_msg>placeholder for chart decoding in nbest list<commit_after>// vim:tabstop=2
/***********************************************************************
 Moses - factored phrase-based language decoder
 Copyright (C) 2010 Hieu Hoang

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

 This library is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 Lesser General Public License for more details.

 You should have received a copy of the GNU Lesser General Public
 License along with this library; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 ***********************************************************************/

#include "ChartTrellisNode.h"

#include "ChartHypothesis.h"
#include "ChartTrellisDetour.h"
#include "ChartTrellisPath.h"
#include "StaticData.h"

namespace Moses
{

ChartTrellisNode::ChartTrellisNode(const ChartHypothesis &hypo)
  : m_hypo(hypo)
{
  CreateChildren();
}

ChartTrellisNode::ChartTrellisNode(const ChartTrellisDetour &detour,
                                   ChartTrellisNode *&deviationPoint)
  : m_hypo((&detour.GetBasePath().GetFinalNode() == &detour.GetSubstitutedNode())
           ? detour.GetReplacementHypo()
           : detour.GetBasePath().GetFinalNode().GetHypothesis())
{
  if (&m_hypo == &detour.GetReplacementHypo()) {
    deviationPoint = this;
    CreateChildren();
  } else {
    CreateChildren(detour.GetBasePath().GetFinalNode(),
                   detour.GetSubstitutedNode(), detour.GetReplacementHypo(),
                   deviationPoint);
  }
}

ChartTrellisNode::ChartTrellisNode(const ChartTrellisNode &root,
                                   const ChartTrellisNode &substitutedNode,
                                   const ChartHypothesis &replacementHypo,
                                   ChartTrellisNode *&deviationPoint)
  : m_hypo((&root == &substitutedNode)
           ? replacementHypo
           : root.GetHypothesis())
{
  if (&root == &substitutedNode) {
    deviationPoint = this;
    CreateChildren();
  } else {
    CreateChildren(root, substitutedNode, replacementHypo, deviationPoint);
  }
}

ChartTrellisNode::~ChartTrellisNode()
{
  RemoveAllInColl(m_children);
}

Phrase ChartTrellisNode::GetOutputPhrase() const
{
  FactorType placeholderFactor = StaticData::Instance().GetPlaceholderFactor();

  // exactly like same fn in hypothesis, but use trellis nodes instead of prevHypos pointer
  Phrase ret(ARRAY_SIZE_INCR);

  const Phrase &currTargetPhrase = m_hypo.GetCurrTargetPhrase();
  const AlignmentInfo::NonTermIndexMap &nonTermIndexMap =
    m_hypo.GetCurrTargetPhrase().GetAlignNonTerm().GetNonTermIndexMap();
  for (size_t pos = 0; pos < currTargetPhrase.GetSize(); ++pos) {
    const Word &word = currTargetPhrase.GetWord(pos);
    if (word.IsNonTerminal()) {
      // non-term. fill out with prev hypo
      size_t nonTermInd = nonTermIndexMap[pos];
      const ChartTrellisNode &childNode = GetChild(nonTermInd);
      Phrase childPhrase = childNode.GetOutputPhrase();
      ret.Append(childPhrase);
    } else {
      ret.AddWord(word);

      if (placeholderFactor != NOT_FOUND) {
    	  std::set<size_t> sourcePosSet = m_hypo.GetCurrTargetPhrase().GetAlignTerm().GetAlignmentsForTarget(pos);
    	  if (sourcePosSet.size() == 1) {
    		  const std::vector<const Word*> *ruleSourceFromInputPath = m_hypo.GetTranslationOption().GetSourceRuleFromInputPath();
    		  CHECK(ruleSourceFromInputPath);

    	      size_t sourcePos = *sourcePosSet.begin();
    		  const Word *sourceWord = ruleSourceFromInputPath->at(sourcePos);
    		  CHECK(sourceWord);
    		  const Factor *factor = sourceWord->GetFactor(placeholderFactor);
    		  if (factor) {
    			  ret.Back()[0] = factor;
    		  }
     	  }
      }
    }
  }

  return ret;
}

void ChartTrellisNode::CreateChildren()
{
  CHECK(m_children.empty());
  const std::vector<const ChartHypothesis*> &prevHypos = m_hypo.GetPrevHypos();
  m_children.reserve(prevHypos.size());
  for (size_t ind = 0; ind < prevHypos.size(); ++ind) {
    const ChartHypothesis *prevHypo = prevHypos[ind];
    ChartTrellisNode *child = new ChartTrellisNode(*prevHypo);
    m_children.push_back(child);
  }
}

void ChartTrellisNode::CreateChildren(const ChartTrellisNode &rootNode,
                                      const ChartTrellisNode &substitutedNode,
                                      const ChartHypothesis &replacementHypo,
                                      ChartTrellisNode *&deviationPoint)
{
  CHECK(m_children.empty());
  const NodeChildren &children = rootNode.GetChildren();
  m_children.reserve(children.size());
  for (size_t ind = 0; ind < children.size(); ++ind) {
    const ChartTrellisNode *origChild = children[ind];
    ChartTrellisNode *child = new ChartTrellisNode(*origChild, substitutedNode,
        replacementHypo,
        deviationPoint);
    m_children.push_back(child);
  }
}

}
<|endoftext|>


<commit_before>#include "commandline_parser.h"

using namespace std;

namespace parser
{

// class OptionError

OptionError::OptionError(const string& msg)
        : _msg(msg) {

}

const char* OptionError::what() const throw() {
  string msg;
  msg.append("Command line parse error: ").append(_msg).push_back('.');
  return msg.c_str();
}

OptionError::~OptionError() throw() {

}

// class CCParseItem

CParseItem::CParseItem(const string& val)
        : _val(val) {

}

CParseItem* CParser::get(const string& key) {
  if (pr_->find(key) != pr_->end()) {
    return (*pr_)[key];
  }
  return nullptr;
}

string CParseItem::val() const {
  return _val;
}

// class CParser

CParser::CParser()
        : chain_(nullptr), pr_(nullptr) {

}

CParser::~CParser() {
  this->cleanup();
}

CParser::ParseResult* CParser::parse(const int argc, const char** argv) {
  if (!this->init(argc, argv)) {
    return nullptr;
  }
  auto ibegin = args_.begin() + 1; // ignore the first cmd name
  auto iend = args_.end();
  auto it = ibegin;

  string block;
  string previous(*ibegin);

  for (; it != iend; ++it) {
    block.assign(*it);

    switch (block.size()) {
      case 1:
        if (block == "-") {
          throw OptionError("single '-' is not allowed");
        }
        break;
      case 2:
        if (block[0] == '-') {
          if (block[1] == '-') {
            throw OptionError("option '--' is incomplete");
          } else {
            // single option
            // e.g., ./exec -s
            (*pr_)[block.substr(1)] = nullptr;
          }
        }
        break;
      default: // >=3
        if (block[0] == '-') {
          if (block[1] == '-') {
            // a long format option
            // e.g., ./exec --option
            (*pr_)[block.substr(2)] = nullptr;
          } else {
            // a combination options
            // e.g., ./exec -ab[...]
            auto tbegin = block.begin() + 1; // ignore the first '-'
            auto tend = block.end();
            auto t = tbegin;

            for (; t != tend; ++t) {
              string key;
              key.push_back(*t);
              (*pr_)[key] = nullptr;
            }
          }
        }
        break;
    }// switch

    if (block[0] != '-' && previous != block //not the first option
            ) {

      if (previous[0] != '-') {
        // previous is not an option, error occur
        // e.g., ./exec abc def
        throw OptionError("'" + block + "' is not allowed here");
      }

      string key;

      if (previous[0] == '-' && previous[1] == '-') {
        // previous is a long format option.
        // e.g., ./exec --option value
        key = previous.substr(2);
      } else {
        // it's the value of previous option.
        // e.g., ./exec -o   [...]
        // e.g., ./exec -opq [...]
        key.push_back(*(previous.end() - 1));
      }

      if (pr_->find(key) != pr_->end()) {
        (*pr_)[key] = new CParseItem(block);
      }
    }

    previous = block;
  }// for

  if (chain_) {
    this->set_addition();
  }

  return pr_;
}

CParser::ParseResult* CParser::parse(const char* command_line) {
  int i = 0;
  string block;
  vector<string> blocks;
  char c;
  while ((c = command_line[i++]) != '\0') {
    if (c != ' ') {
      block.push_back(c);
    } else {
      if (!block.empty()) {
        blocks.push_back(block);
      }
      block.clear();
    }
  }
  if (!block.empty()) {
    blocks.push_back(block);
  }
  size_t size = blocks.size(); // argc
  char** argv = new char* [size];
  i = 0;
  std::for_each(blocks.begin(), blocks.end(), [&argv, &i](const string& b) {
    argv[i++] = const_cast<char*>(b.c_str());
  });
  auto pr = this->parse(static_cast<const int>(size),
                        const_cast<const char**>(argv));

  delete[] argv;
  argv = nullptr;

  return pr;
}

bool CParser::has(const char* key) {
  string skey(key);

  if (pr_ && !pr_->empty() && !skey.empty()) {
    if (skey[0] == '-') {
      //check combination options, e.g., CParser::has("-xyz")
      for (size_t i = 1; i < skey.size(); ++i) {
        string tkey;
        tkey.push_back(skey[i]);
        if (pr_->find(tkey) == pr_->end()) {
          return false;
        }
      }
      return true;
    } else {
      // check single option, e.g., CParser::has("x")
      return pr_->find(skey) != pr_->end();
    }
  }
  return false;
}

bool CParser::has_or(int n, ...) {
  va_list keys;
  va_start(keys, n);
  while (n--) {
    const char* key = va_arg(keys, const char *);
    if (this->has(key)) {
      return true;
    }
  }
  va_end(keys);
  return false;
}

bool CParser::has_and(int n, ...) {
  va_list keys;
  va_start(keys, n);
  while (n--) {
    const char* key = va_arg(keys, const char *);
    if (!this->has(key)) {
      return false;
    }
  }
  va_end(keys);
  return true;
}

void CParser::dump() {
  if (pr_) {
    auto ibegin = pr_->begin();
    auto iend = pr_->end();
    auto it = ibegin;
    for (; it != iend; ++it) {
      cout << it->first;
      if (it->second) {
        cout << " = " << it->second->val() << endl;
      } else {
        cout << " set" << endl;
      }
    }
  }
}

bool CParser::init(const int argc, const char** argv) {
  argc_ = argc;
  argv_ = argv;
  if (argc > 0) {
    this->cleanup();

    args_.reserve(static_cast<size_t>(argc_));

    for (int i = 0; i < argc_; ++i) {
      args_.push_back(argv_[i]);
    }

    pr_ = new CParser::ParseResult;
    return true;
  }
  return false;
}

void CParser::cleanup() {
  args_.clear();
  if (pr_) {
    auto ibegin = pr_->begin();
    auto iend = pr_->end();
    auto it = ibegin;
    for (; it != iend; ++it) {
      CParseItem* item = it->second;
      if (item)
        delete item;
    }
    delete pr_;
    pr_ = nullptr;
  }
}

void CParser::set_addition() {
  auto begin = chain_->begin();
  auto end = chain_->end();

  std::for_each(begin, end, [this](const Generator::Row& row) {
    // assume both -o and --option are allowed,
    // but only provide -o,
    // then set the another --option.
    // vice versa.
    const string& def = row.default_value;
    const string& ops = row.option_short;
    const string& opl = row.option_long;
    ParseResult& pr = *pr_;

    bool has_short = this->has(ops.c_str());
    bool has_long = this->has(opl.c_str());

    // assume -o [ --option ] arg = 1
    // but not provide option value,
    // then set to default 1.
    // otherwise, both set to user defined value

    if (!ops.empty()) {
      if (has_short) {
        if (pr[ops] != nullptr && !opl.empty()) {
          pr[opl] = new CParseItem(std::move(pr[ops]->val()));
        } else if (pr[ops] == nullptr && !def.empty()) {
          pr[ops] = new CParseItem(std::move(def));
          if (!opl.empty())
            pr[opl] = new CParseItem(std::move(def));
        } else {
          pr[opl] = nullptr;
        }
      }
    }

    if (!opl.empty()) {
      if (has_long) {
        if (pr[opl] != nullptr && !ops.empty()) {
          pr[ops] = new CParseItem(std::move(pr[opl]->val()));
        } else if (pr[opl] == nullptr && !def.empty()) {
          if (!ops.empty())
            pr[ops] = new CParseItem(std::move(def));
          pr[opl] = new CParseItem(std::move(def));
        } else {
          pr[ops] = nullptr;
        }
      }
    }

    if (!has_long && !has_short && !def.empty()) {
      if (!opl.empty())
        pr[opl] = new CParseItem(std::move(def));
      if (!ops.empty())
        pr[ops] = new CParseItem(std::move(def));
    }
  }

  );
}

}
<commit_msg>A shorter CParser::dump().<commit_after>#include "commandline_parser.h"

using namespace std;

namespace parser
{

// class OptionError

OptionError::OptionError(const string& msg)
        : _msg(msg) {

}

const char* OptionError::what() const throw() {
  string msg;
  msg.append("Command line parse error: ").append(_msg).push_back('.');
  return msg.c_str();
}

OptionError::~OptionError() throw() {

}

// class CCParseItem

CParseItem::CParseItem(const string& val)
        : _val(val) {

}

CParseItem* CParser::get(const string& key) {
  if (pr_->find(key) != pr_->end()) {
    return (*pr_)[key];
  }
  return nullptr;
}

string CParseItem::val() const {
  return _val;
}

// class CParser

CParser::CParser()
        : chain_(nullptr), pr_(nullptr) {

}

CParser::~CParser() {
  this->cleanup();
}

CParser::ParseResult* CParser::parse(const int argc, const char** argv) {
  if (!this->init(argc, argv)) {
    return nullptr;
  }
  auto ibegin = args_.begin() + 1; // ignore the first cmd name
  auto iend = args_.end();
  auto it = ibegin;

  string block;
  string previous(*ibegin);

  for (; it != iend; ++it) {
    block.assign(*it);

    switch (block.size()) {
      case 1:
        if (block == "-") {
          throw OptionError("single '-' is not allowed");
        }
        break;
      case 2:
        if (block[0] == '-') {
          if (block[1] == '-') {
            throw OptionError("option '--' is incomplete");
          } else {
            // single option
            // e.g., ./exec -s
            (*pr_)[block.substr(1)] = nullptr;
          }
        }
        break;
      default: // >=3
        if (block[0] == '-') {
          if (block[1] == '-') {
            // a long format option
            // e.g., ./exec --option
            (*pr_)[block.substr(2)] = nullptr;
          } else {
            // a combination options
            // e.g., ./exec -ab[...]
            auto tbegin = block.begin() + 1; // ignore the first '-'
            auto tend = block.end();
            auto t = tbegin;

            for (; t != tend; ++t) {
              string key;
              key.push_back(*t);
              (*pr_)[key] = nullptr;
            }
          }
        }
        break;
    }// switch

    if (block[0] != '-' && previous != block //not the first option
            ) {

      if (previous[0] != '-') {
        // previous is not an option, error occur
        // e.g., ./exec abc def
        throw OptionError("'" + block + "' is not allowed here");
      }

      string key;

      if (previous[0] == '-' && previous[1] == '-') {
        // previous is a long format option.
        // e.g., ./exec --option value
        key = previous.substr(2);
      } else {
        // it's the value of previous option.
        // e.g., ./exec -o   [...]
        // e.g., ./exec -opq [...]
        key.push_back(*(previous.end() - 1));
      }

      if (pr_->find(key) != pr_->end()) {
        (*pr_)[key] = new CParseItem(block);
      }
    }

    previous = block;
  }// for

  if (chain_) {
    this->set_addition();
  }

  return pr_;
}

CParser::ParseResult* CParser::parse(const char* command_line) {
  int i = 0;
  string block;
  vector<string> blocks;
  char c;
  while ((c = command_line[i++]) != '\0') {
    if (c != ' ') {
      block.push_back(c);
    } else {
      if (!block.empty()) {
        blocks.push_back(block);
      }
      block.clear();
    }
  }
  if (!block.empty()) {
    blocks.push_back(block);
  }
  size_t size = blocks.size(); // argc
  char** argv = new char* [size];
  i = 0;
  std::for_each(blocks.begin(), blocks.end(), [&argv, &i](const string& b) {
    argv[i++] = const_cast<char*>(b.c_str());
  });
  auto pr = this->parse(static_cast<const int>(size),
                        const_cast<const char**>(argv));

  delete[] argv;
  argv = nullptr;

  return pr;
}

bool CParser::has(const char* key) {
  string skey(key);

  if (pr_ && !pr_->empty() && !skey.empty()) {
    if (skey[0] == '-') {
      //check combination options, e.g., CParser::has("-xyz")
      for (size_t i = 1; i < skey.size(); ++i) {
        string tkey;
        tkey.push_back(skey[i]);
        if (pr_->find(tkey) == pr_->end()) {
          return false;
        }
      }
      return true;
    } else {
      // check single option, e.g., CParser::has("x")
      return pr_->find(skey) != pr_->end();
    }
  }
  return false;
}

bool CParser::has_or(int n, ...) {
  va_list keys;
  va_start(keys, n);
  while (n--) {
    const char* key = va_arg(keys, const char *);
    if (this->has(key)) {
      return true;
    }
  }
  va_end(keys);
  return false;
}

bool CParser::has_and(int n, ...) {
  va_list keys;
  va_start(keys, n);
  while (n--) {
    const char* key = va_arg(keys, const char *);
    if (!this->has(key)) {
      return false;
    }
  }
  va_end(keys);
  return true;
}

void CParser::dump() {
  if (pr_) {
    for (auto pair : *pr_) {
      cout << pair.first;
      if (pair.second) {
        cout << " = " << pair.second->val() << endl;
      } else {
        cout << " set" << endl;
      }
    }
  }
}

bool CParser::init(const int argc, const char** argv) {
  argc_ = argc;
  argv_ = argv;
  if (argc > 0) {
    this->cleanup();

    args_.reserve(static_cast<size_t>(argc_));

    for (int i = 0; i < argc_; ++i) {
      args_.push_back(argv_[i]);
    }

    pr_ = new CParser::ParseResult;
    return true;
  }
  return false;
}

void CParser::cleanup() {
  args_.clear();
  if (pr_) {
    auto ibegin = pr_->begin();
    auto iend = pr_->end();
    auto it = ibegin;
    for (; it != iend; ++it) {
      CParseItem* item = it->second;
      if (item)
        delete item;
    }
    delete pr_;
    pr_ = nullptr;
  }
}

void CParser::set_addition() {
  auto begin = chain_->begin();
  auto end = chain_->end();

  std::for_each(begin, end, [this](const Generator::Row& row) {
    // assume both -o and --option are allowed,
    // but only provide -o,
    // then set the another --option.
    // vice versa.
    const string& def = row.default_value;
    const string& ops = row.option_short;
    const string& opl = row.option_long;
    ParseResult& pr = *pr_;

    bool has_short = this->has(ops.c_str());
    bool has_long = this->has(opl.c_str());

    // assume -o [ --option ] arg = 1
    // but not provide option value,
    // then set to default 1.
    // otherwise, both set to user defined value

    if (!ops.empty()) {
      if (has_short) {
        if (pr[ops] != nullptr && !opl.empty()) {
          pr[opl] = new CParseItem(std::move(pr[ops]->val()));
        } else if (pr[ops] == nullptr && !def.empty()) {
          pr[ops] = new CParseItem(std::move(def));
          if (!opl.empty())
            pr[opl] = new CParseItem(std::move(def));
        } else {
          pr[opl] = nullptr;
        }
      }
    }

    if (!opl.empty()) {
      if (has_long) {
        if (pr[opl] != nullptr && !ops.empty()) {
          pr[ops] = new CParseItem(std::move(pr[opl]->val()));
        } else if (pr[opl] == nullptr && !def.empty()) {
          if (!ops.empty())
            pr[ops] = new CParseItem(std::move(def));
          pr[opl] = new CParseItem(std::move(def));
        } else {
          pr[ops] = nullptr;
        }
      }
    }

    if (!has_long && !has_short && !def.empty()) {
      if (!opl.empty())
        pr[opl] = new CParseItem(std::move(def));
      if (!ops.empty())
        pr[ops] = new CParseItem(std::move(def));
    }
  }

  );
}

}
<|endoftext|>


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

  Program:   Visualization Toolkit
  Module:    vtkPStreamTracer.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
#include "vtkPStreamTracer.h"

#include "vtkAppendPolyData.h"
#include "vtkInterpolatedVelocityField.h"
#include "vtkMultiProcessController.h"
#include "vtkFloatArray.h"
#include "vtkIdList.h"
#include "vtkIntArray.h"
#include "vtkObjectFactory.h"
#include "vtkPolyData.h"
#include "vtkRungeKutta2.h"

vtkCxxRevisionMacro(vtkPStreamTracer, "1.3");
vtkStandardNewMacro(vtkPStreamTracer);

vtkCxxSetObjectMacro(vtkPStreamTracer, Controller, vtkMultiProcessController);
vtkCxxSetObjectMacro(vtkPStreamTracer,
                     Interpolator,
                     vtkInterpolatedVelocityField);

vtkPStreamTracer::vtkPStreamTracer()
{
  this->Controller = vtkMultiProcessController::GetGlobalController();
  if (this->Controller)
    {
    this->Controller->Register(this);
    }
  this->Interpolator = 0;
  this->Seeds = 0;
  this->SeedIds = 0;
  this->IntegrationDirections = 0;
}

vtkPStreamTracer::~vtkPStreamTracer()
{
  if (this->Controller)
    {
    this->Controller->UnRegister(this);
    this->Controller = 0;
    }
  this->SetInterpolator(0);
  if (this->Seeds)
    {
    this->Seeds->Delete();
    }
  if (this->SeedIds)
    {
    this->SeedIds->Delete();
    }
  if (this->IntegrationDirections)
    {
    this->IntegrationDirections->Delete();
    }
}

void vtkPStreamTracer::ForwardTask(float seed[3],
                                   int direction,
                                   int isNewSeed,
                                   int lastid,
                                   int currentLine)
{
  int myid = this->Controller->GetLocalProcessId();
  int numProcs = this->Controller->GetNumberOfProcesses();
  int nextid;
  if (myid == numProcs-1)
    {
    nextid = 0;
    }
  else
    {
    nextid = myid+1;
    }

  this->Controller->Send(&isNewSeed, 1, nextid, 311);
  this->Controller->Send(&lastid, 1, nextid, 322);
  if (isNewSeed != 2)
    {
    this->Controller->Send(seed, 3, nextid, 333);
    this->Controller->Send(&direction, 1, nextid, 344);
    this->Controller->Send(&currentLine, 1, nextid, 355);
    }
}

int vtkPStreamTracer::ReceiveAndProcessTask()
{
  int isNewSeed;
  int lastid;
  int currentLine;
  int direction=FORWARD;
  float seed[3] = {0.0, 0.0, 0.0};
  int myid = this->Controller->GetLocalProcessId();
  int numProcs = this->Controller->GetNumberOfProcesses();

  this->Controller->Receive(&isNewSeed,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            311);
  this->Controller->Receive(&lastid,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            322);
  if ( isNewSeed == 2 )
    {
    if ( (( myid == numProcs-1 && lastid == 0 ) ||
          ( myid != numProcs-1 && lastid == myid + 1) ))
      {
      // All processes have been already told to stop. No need to tell
      // the next one.
      return 0;
      }
    this->ForwardTask(seed, direction, 2, lastid, 0);
    return 0;
    }
  this->Controller->Receive(seed,
                            3,
                            vtkMultiProcessController::ANY_SOURCE,
                            333);
  this->Controller->Receive(&direction,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            344);
  this->Controller->Receive(&currentLine,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            355);
  return this->ProcessTask(seed, direction, isNewSeed, lastid, currentLine);

}

int vtkPStreamTracer::ProcessTask(float seed[3],
                                  int direction,
                                  int isNewSeed,
                                  int lastid,
                                  int currentLine)
{
  int myid = this->Controller->GetLocalProcessId();

  // This seed was visited by everybody and nobody had it.
  // Must be out of domain.
  // TEMP: TELL ALL PROCESSES TO STOP
  if (isNewSeed == 0 && lastid == myid)
    {
    vtkIdType numLines = this->SeedIds->GetNumberOfIds();
    currentLine++;
    if ( currentLine < numLines )
      {
      this->ProcessTask(
        this->Seeds->GetTuple(this->SeedIds->GetId(currentLine)),
        this->IntegrationDirections->GetValue(currentLine),
        1,
        myid,
        currentLine);
      return 1;
      }
    else
      {
      this->ForwardTask(seed, direction, 2, myid, currentLine);
      return 0;
      }
    }

  float velocity[3];
  // We don't have it, let's forward it to the next guy
  if (!this->Interpolator->FunctionValues(seed, velocity))
    {
    this->ForwardTask(seed, direction, 0, lastid, currentLine);
    return 1;
    }

  float lastPoint[3];

  vtkFloatArray* seeds = vtkFloatArray::New();
  seeds->SetNumberOfComponents(3);
  seeds->InsertNextTuple(seed);

  vtkIdList* seedIds = vtkIdList::New();
  seedIds->InsertNextId(0);

  vtkIntArray* integrationDirections = vtkIntArray::New();
  integrationDirections->InsertNextValue(direction);

  vtkPolyData* tmpOutput = 0;
  vtkPolyData* output = this->GetOutput();
  if ( output->GetNumberOfCells() > 0 )
    {
    tmpOutput = vtkPolyData::New();
    this->Integrate(tmpOutput,
                    seeds,
                    seedIds,
                    integrationDirections,
                    lastPoint);
    if ( tmpOutput->GetNumberOfCells() > 0 )
      {
      vtkPolyData* outputcp = vtkPolyData::New();
      outputcp->ShallowCopy(output);
      vtkAppendPolyData* append = vtkAppendPolyData::New();
      append->AddInput(outputcp);
      append->AddInput(tmpOutput);
      append->Update();
      vtkPolyData* appoutput = append->GetOutput();
      output->CopyStructure(appoutput);
      output->GetPointData()->PassData(appoutput->GetPointData());
      output->GetCellData()->PassData(appoutput->GetCellData());
      append->Delete();
      outputcp->Delete();
      }
    tmpOutput->Register(this);
    tmpOutput->Delete();
    }
  else
    {
    this->Integrate(output,
                    seeds,
                    seedIds,
                    integrationDirections,
                    lastPoint);
    tmpOutput = output;
    tmpOutput->Register(this);
    }

  int numPoints = tmpOutput->GetNumberOfPoints();
  if (numPoints == 0)
    {
    this->ForwardTask(lastPoint, direction, 2, myid, currentLine);
    seeds->Delete();
    seedIds->Delete();
    integrationDirections->Delete();
    tmpOutput->UnRegister(this);
    return 0;
    }

  tmpOutput->GetPoint(numPoints-1, lastPoint);
  tmpOutput->UnRegister(this);

  vtkInitialValueProblemSolver* ivp = this->Integrator;
  ivp->Register(this);

  vtkRungeKutta2* tmpSolver = vtkRungeKutta2::New();
  this->SetIntegrator(tmpSolver);
  tmpSolver->Delete();
  seeds->SetTuple(0, lastPoint);
  seedIds->SetId(0,0);
  vtkPolyData* dummyOutput = vtkPolyData::New();
  this->Integrate(dummyOutput,
                  seeds,
                  seedIds,
                  integrationDirections,
                  lastPoint);
  dummyOutput->Delete();
  this->SetIntegrator(ivp);
  ivp->UnRegister(this);

  // New seed
  this->ForwardTask(lastPoint, direction, 1, myid, currentLine);

  seeds->Delete();
  seedIds->Delete();
  integrationDirections->Delete();

  return 1;
}

void vtkPStreamTracer::ComputeInputUpdateExtents( vtkDataObject *output )
{
  for (int idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx] != NULL)
      {
      if (idx != 1 )
        {
        this->Inputs[idx]->SetUpdateExtent(output->GetUpdatePiece(),
                                           output->GetUpdateNumberOfPieces(),
                                           output->GetUpdateGhostLevel());
        }
      else
        {
        this->Inputs[idx]->SetUpdateExtent(0, 1, 0);
        }
      }
    }
}

void vtkPStreamTracer::ExecuteInformation()
{
  vtkDataSet *output = this->GetOutput();
  output->SetMaximumNumberOfPieces(-1);
}

void vtkPStreamTracer::Execute()
{
  if (!this->Controller)
    {
    vtkErrorMacro("No controller assigned. Can not execute.");
    return;
    }

  if (this->Controller->GetNumberOfProcesses() == 1)
    {
    this->Superclass::Execute();
    return;
    }

  vtkInterpolatedVelocityField* func;
  int maxCellSize = 0;
  if (this->CheckInputs(func, &maxCellSize) != VTK_OK)
    {
    vtkErrorMacro("No appropriate inputs have been found. Can not execute.");
    func->Delete();
    // >>>>>>>>>> TODO: All should pass this test.
    return;
    }
  func->SetCaching(0);
  this->SetInterpolator(func);
  func->Delete();

  this->InitializeSeeds(this->Seeds,
                        this->SeedIds,
                        this->IntegrationDirections);

  int myid = this->Controller->GetLocalProcessId();
  if (this->Seeds)
    {
    if (myid == 0)
      {
      int currentLine = 0;
      this->ProcessTask(
        this->Seeds->GetTuple(this->SeedIds->GetId(currentLine)),
        this->IntegrationDirections->GetValue(currentLine),
        1,
        0,
        currentLine);
      }
    while(1)
      {
      if (!this->ReceiveAndProcessTask()) { break; }
      }
    }

  if (this->Seeds)
    {
    this->Seeds->Delete();
    this->Seeds = 0;
    }
  this->IntegrationDirections->Delete();
  this->IntegrationDirections = 0;
  this->SeedIds->Delete();
  this->SeedIds = 0;
}

void vtkPStreamTracer::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "Controller: " << this->Controller << endl;
}
<commit_msg>fix some compiler warnings hopefully<commit_after>/*=========================================================================

  Program:   Visualization Toolkit
  Module:    vtkPStreamTracer.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

  Copyright (c) 1993-2002 Ken Martin, Will Schroeder, Bill Lorensen
  All rights reserved.
  See Copyright.txt or http://www.kitware.com/Copyright.htm for details.

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

=========================================================================*/
#include "vtkPStreamTracer.h"

#include "vtkAppendPolyData.h"
#include "vtkInterpolatedVelocityField.h"
#include "vtkMultiProcessController.h"
#include "vtkFloatArray.h"
#include "vtkIdList.h"
#include "vtkIntArray.h"
#include "vtkObjectFactory.h"
#include "vtkPolyData.h"
#include "vtkRungeKutta2.h"

vtkCxxRevisionMacro(vtkPStreamTracer, "1.4");
vtkStandardNewMacro(vtkPStreamTracer);

vtkCxxSetObjectMacro(vtkPStreamTracer, Controller, vtkMultiProcessController);
vtkCxxSetObjectMacro(vtkPStreamTracer,
                     Interpolator,
                     vtkInterpolatedVelocityField);

vtkPStreamTracer::vtkPStreamTracer()
{
  this->Controller = vtkMultiProcessController::GetGlobalController();
  if (this->Controller)
    {
    this->Controller->Register(this);
    }
  this->Interpolator = 0;
  this->Seeds = 0;
  this->SeedIds = 0;
  this->IntegrationDirections = 0;
}

vtkPStreamTracer::~vtkPStreamTracer()
{
  if (this->Controller)
    {
    this->Controller->UnRegister(this);
    this->Controller = 0;
    }
  this->SetInterpolator(0);
  if (this->Seeds)
    {
    this->Seeds->Delete();
    }
  if (this->SeedIds)
    {
    this->SeedIds->Delete();
    }
  if (this->IntegrationDirections)
    {
    this->IntegrationDirections->Delete();
    }
}

void vtkPStreamTracer::ForwardTask(float seed[3],
                                   int direction,
                                   int isNewSeed,
                                   int lastid,
                                   int currentLine)
{
  int myid = this->Controller->GetLocalProcessId();
  int numProcs = this->Controller->GetNumberOfProcesses();
  int nextid;
  if (myid == numProcs-1)
    {
    nextid = 0;
    }
  else
    {
    nextid = myid+1;
    }

  this->Controller->Send(&isNewSeed, 1, nextid, 311);
  this->Controller->Send(&lastid, 1, nextid, 322);
  if (isNewSeed != 2)
    {
    this->Controller->Send(seed, 3, nextid, 333);
    this->Controller->Send(&direction, 1, nextid, 344);
    this->Controller->Send(&currentLine, 1, nextid, 355);
    }
}

int vtkPStreamTracer::ReceiveAndProcessTask()
{
  int isNewSeed = 0;
  int lastid = 0;
  int currentLine = 0;
  int direction=FORWARD;
  float seed[3] = {0.0, 0.0, 0.0};
  int myid = this->Controller->GetLocalProcessId();
  int numProcs = this->Controller->GetNumberOfProcesses();

  this->Controller->Receive(&isNewSeed,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            311);
  this->Controller->Receive(&lastid,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            322);
  if ( isNewSeed == 2 )
    {
    if ( (( myid == numProcs-1 && lastid == 0 ) ||
          ( myid != numProcs-1 && lastid == myid + 1) ))
      {
      // All processes have been already told to stop. No need to tell
      // the next one.
      return 0;
      }
    this->ForwardTask(seed, direction, 2, lastid, 0);
    return 0;
    }
  this->Controller->Receive(seed,
                            3,
                            vtkMultiProcessController::ANY_SOURCE,
                            333);
  this->Controller->Receive(&direction,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            344);
  this->Controller->Receive(&currentLine,
                            1,
                            vtkMultiProcessController::ANY_SOURCE,
                            355);
  return this->ProcessTask(seed, direction, isNewSeed, lastid, currentLine);

}

int vtkPStreamTracer::ProcessTask(float seed[3],
                                  int direction,
                                  int isNewSeed,
                                  int lastid,
                                  int currentLine)
{
  int myid = this->Controller->GetLocalProcessId();

  // This seed was visited by everybody and nobody had it.
  // Must be out of domain.
  // TEMP: TELL ALL PROCESSES TO STOP
  if (isNewSeed == 0 && lastid == myid)
    {
    vtkIdType numLines = this->SeedIds->GetNumberOfIds();
    currentLine++;
    if ( currentLine < numLines )
      {
      this->ProcessTask(
        this->Seeds->GetTuple(this->SeedIds->GetId(currentLine)),
        this->IntegrationDirections->GetValue(currentLine),
        1,
        myid,
        currentLine);
      return 1;
      }
    else
      {
      this->ForwardTask(seed, direction, 2, myid, currentLine);
      return 0;
      }
    }

  float velocity[3];
  // We don't have it, let's forward it to the next guy
  if (!this->Interpolator->FunctionValues(seed, velocity))
    {
    this->ForwardTask(seed, direction, 0, lastid, currentLine);
    return 1;
    }

  float lastPoint[3];

  vtkFloatArray* seeds = vtkFloatArray::New();
  seeds->SetNumberOfComponents(3);
  seeds->InsertNextTuple(seed);

  vtkIdList* seedIds = vtkIdList::New();
  seedIds->InsertNextId(0);

  vtkIntArray* integrationDirections = vtkIntArray::New();
  integrationDirections->InsertNextValue(direction);

  vtkPolyData* tmpOutput = 0;
  vtkPolyData* output = this->GetOutput();
  if ( output->GetNumberOfCells() > 0 )
    {
    tmpOutput = vtkPolyData::New();
    this->Integrate(tmpOutput,
                    seeds,
                    seedIds,
                    integrationDirections,
                    lastPoint);
    if ( tmpOutput->GetNumberOfCells() > 0 )
      {
      vtkPolyData* outputcp = vtkPolyData::New();
      outputcp->ShallowCopy(output);
      vtkAppendPolyData* append = vtkAppendPolyData::New();
      append->AddInput(outputcp);
      append->AddInput(tmpOutput);
      append->Update();
      vtkPolyData* appoutput = append->GetOutput();
      output->CopyStructure(appoutput);
      output->GetPointData()->PassData(appoutput->GetPointData());
      output->GetCellData()->PassData(appoutput->GetCellData());
      append->Delete();
      outputcp->Delete();
      }
    tmpOutput->Register(this);
    tmpOutput->Delete();
    }
  else
    {
    this->Integrate(output,
                    seeds,
                    seedIds,
                    integrationDirections,
                    lastPoint);
    tmpOutput = output;
    tmpOutput->Register(this);
    }

  int numPoints = tmpOutput->GetNumberOfPoints();
  if (numPoints == 0)
    {
    this->ForwardTask(lastPoint, direction, 2, myid, currentLine);
    seeds->Delete();
    seedIds->Delete();
    integrationDirections->Delete();
    tmpOutput->UnRegister(this);
    return 0;
    }

  tmpOutput->GetPoint(numPoints-1, lastPoint);
  tmpOutput->UnRegister(this);

  vtkInitialValueProblemSolver* ivp = this->Integrator;
  ivp->Register(this);

  vtkRungeKutta2* tmpSolver = vtkRungeKutta2::New();
  this->SetIntegrator(tmpSolver);
  tmpSolver->Delete();
  seeds->SetTuple(0, lastPoint);
  seedIds->SetId(0,0);
  vtkPolyData* dummyOutput = vtkPolyData::New();
  this->Integrate(dummyOutput,
                  seeds,
                  seedIds,
                  integrationDirections,
                  lastPoint);
  dummyOutput->Delete();
  this->SetIntegrator(ivp);
  ivp->UnRegister(this);

  // New seed
  this->ForwardTask(lastPoint, direction, 1, myid, currentLine);

  seeds->Delete();
  seedIds->Delete();
  integrationDirections->Delete();

  return 1;
}

void vtkPStreamTracer::ComputeInputUpdateExtents( vtkDataObject *output )
{
  for (int idx = 0; idx < this->NumberOfInputs; ++idx)
    {
    if (this->Inputs[idx] != NULL)
      {
      if (idx != 1 )
        {
        this->Inputs[idx]->SetUpdateExtent(output->GetUpdatePiece(),
                                           output->GetUpdateNumberOfPieces(),
                                           output->GetUpdateGhostLevel());
        }
      else
        {
        this->Inputs[idx]->SetUpdateExtent(0, 1, 0);
        }
      }
    }
}

void vtkPStreamTracer::ExecuteInformation()
{
  vtkDataSet *output = this->GetOutput();
  output->SetMaximumNumberOfPieces(-1);
}

void vtkPStreamTracer::Execute()
{
  if (!this->Controller)
    {
    vtkErrorMacro("No controller assigned. Can not execute.");
    return;
    }

  if (this->Controller->GetNumberOfProcesses() == 1)
    {
    this->Superclass::Execute();
    return;
    }

  vtkInterpolatedVelocityField* func;
  int maxCellSize = 0;
  if (this->CheckInputs(func, &maxCellSize) != VTK_OK)
    {
    vtkErrorMacro("No appropriate inputs have been found. Can not execute.");
    func->Delete();
    // >>>>>>>>>> TODO: All should pass this test.
    return;
    }
  func->SetCaching(0);
  this->SetInterpolator(func);
  func->Delete();

  this->InitializeSeeds(this->Seeds,
                        this->SeedIds,
                        this->IntegrationDirections);

  int myid = this->Controller->GetLocalProcessId();
  if (this->Seeds)
    {
    if (myid == 0)
      {
      int currentLine = 0;
      this->ProcessTask(
        this->Seeds->GetTuple(this->SeedIds->GetId(currentLine)),
        this->IntegrationDirections->GetValue(currentLine),
        1,
        0,
        currentLine);
      }
    while(1)
      {
      if (!this->ReceiveAndProcessTask()) { break; }
      }
    }

  if (this->Seeds)
    {
    this->Seeds->Delete();
    this->Seeds = 0;
    }
  this->IntegrationDirections->Delete();
  this->IntegrationDirections = 0;
  this->SeedIds->Delete();
  this->SeedIds = 0;
}

void vtkPStreamTracer::PrintSelf(ostream& os, vtkIndent indent)
{
  this->Superclass::PrintSelf(os,indent);
  os << indent << "Controller: " << this->Controller << endl;
}
<|endoftext|>


<commit_before>/* Worker.cpp
 *
 * Kubo Ryosuke
 */

#include "Worker.h"
#include "Tree.h"
#include "../Searcher.h"
#include <functional>

namespace sunfish {

	void Worker::init(int id, Searcher* ps) {
		psearcher = ps;
		workerId = id;
		treeId.store(Tree::InvalidId);
		memset(&info, 0, sizeof(info));
	}

	void Worker::startOnNewThread() {
		job.store(false);
		shutdown.store(false);
		thread = std::thread(std::bind(std::mem_fun(&Worker::waitForJob), this));
	}

	void Worker::startOnCurrentThread(int tid) {
		treeId.store(tid);
		job.store(true);
		shutdown.store(false);
	}

	void Worker::stop() {
		shutdown.store(true);
		thread.join();
	}

	void Worker::setJob(int tid) {
		treeId.store(tid);
		job.store(true);
	}

	void Worker::unsetJob() {
		job.store(false);
	}

	void Worker::swapTree(int tid) {
		treeId.store(tid);
	}

	void Worker::waitForJob(Tree* suspendedTree) {
		if (suspendedTree != nullptr) {
			std::lock_guard<std::mutex> lock(psearcher->getSplitMutex());
			unsetJob();
			psearcher->addIdleWorker();
		}

		while (true) {
			if (suspendedTree != nullptr && suspendedTree->getTlp().childCount.load() == 0) {
				std::lock_guard<std::mutex> lock(psearcher->getSplitMutex());
				if (!job.load()) {
					setJob(suspendedTree->getTlp().treeId);
					psearcher->reduceIdleWorker();
					return;
				}
			}

			if (shutdown.load()) {
				return;
			}

			if (job.load()) {
				psearcher->searchTlp(treeId.load());
				{
					std::lock_guard<std::mutex> lock(psearcher->getSplitMutex());

					psearcher->releaseTree(treeId.load());

					if (suspendedTree != nullptr && suspendedTree->getTlp().childCount.load() == 0) {
						setJob(suspendedTree->getTlp().treeId);
						return;
					}

					unsetJob();
					psearcher->addIdleWorker();
				}
			}

			std::this_thread::yield();
		}
	}

}
<commit_msg>Fix worker<commit_after>/* Worker.cpp
 *
 * Kubo Ryosuke
 */

#include "Worker.h"
#include "Tree.h"
#include "../Searcher.h"
#include <functional>

namespace sunfish {

	void Worker::init(int id, Searcher* ps) {
		psearcher = ps;
		workerId = id;
		treeId.store(Tree::InvalidId);
		memset(&info, 0, sizeof(info));
	}

	void Worker::startOnNewThread() {
		job.store(false);
		shutdown.store(false);
		thread = std::thread(std::bind(std::mem_fun(&Worker::waitForJob), this, nullptr));
	}

	void Worker::startOnCurrentThread(int tid) {
		treeId.store(tid);
		job.store(true);
		shutdown.store(false);
	}

	void Worker::stop() {
		shutdown.store(true);
		thread.join();
	}

	void Worker::setJob(int tid) {
		treeId.store(tid);
		job.store(true);
	}

	void Worker::unsetJob() {
		job.store(false);
	}

	void Worker::swapTree(int tid) {
		treeId.store(tid);
	}

	void Worker::waitForJob(Tree* suspendedTree) {
		if (suspendedTree != nullptr) {
			std::lock_guard<std::mutex> lock(psearcher->getSplitMutex());
			unsetJob();
			psearcher->addIdleWorker();
		}

		while (true) {
			if (suspendedTree != nullptr && suspendedTree->getTlp().childCount.load() == 0) {
				std::lock_guard<std::mutex> lock(psearcher->getSplitMutex());
				if (!job.load()) {
					setJob(suspendedTree->getTlp().treeId);
					psearcher->reduceIdleWorker();
					return;
				}
			}

			if (shutdown.load()) {
				return;
			}

			if (job.load()) {
				psearcher->searchTlp(treeId.load());
				{
					std::lock_guard<std::mutex> lock(psearcher->getSplitMutex());

					psearcher->releaseTree(treeId.load());

					if (suspendedTree != nullptr && suspendedTree->getTlp().childCount.load() == 0) {
						setJob(suspendedTree->getTlp().treeId);
						return;
					}

					unsetJob();
					psearcher->addIdleWorker();
				}
			}

			std::this_thread::yield();
		}
	}

}
<|endoftext|>


<commit_before>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// 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 "thread.h"
#include "sysinfo.h"
#include "string.h"

#include <iostream>
#include <xmmintrin.h>

#if defined(PTHREADS_WIN32)
#pragma comment (lib, "pthreadVC.lib")
#endif

////////////////////////////////////////////////////////////////////////////////
/// Windows Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__WIN32__)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

namespace embree
{
  /*! set the affinity of a given thread */
  void setAffinity(HANDLE thread, ssize_t affinity)
  {
    typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)();
    typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD);
    typedef BOOL (WINAPI *SetThreadGroupAffinityFunc)(HANDLE, const GROUP_AFFINITY *, PGROUP_AFFINITY);
    typedef BOOL (WINAPI *SetThreadIdealProcessorExFunc)(HANDLE, PPROCESSOR_NUMBER, PPROCESSOR_NUMBER);
    HMODULE hlib = LoadLibrary("Kernel32");
    GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount");
    GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc)GetProcAddress(hlib, "GetActiveProcessorCount");
    SetThreadGroupAffinityFunc pSetThreadGroupAffinity = (SetThreadGroupAffinityFunc)GetProcAddress(hlib, "SetThreadGroupAffinity");
    SetThreadIdealProcessorExFunc pSetThreadIdealProcessorEx = (SetThreadIdealProcessorExFunc)GetProcAddress(hlib, "SetThreadIdealProcessorEx");
    if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount && pSetThreadGroupAffinity && pSetThreadIdealProcessorEx)
    {
      int groups = pGetActiveProcessorGroupCount();
      int totalProcessors = 0, group = 0, number = 0;
      for (int i = 0; i<groups; i++) {
        int processors = pGetActiveProcessorCount(i);
        if (totalProcessors + processors > affinity) {
          group = i;
          number = (int)affinity - totalProcessors;
          break;
        }
        totalProcessors += processors;
      }

      GROUP_AFFINITY groupAffinity;
      groupAffinity.Group = (WORD)group;
      groupAffinity.Mask = (KAFFINITY)(uint64_t(1) << number);
      groupAffinity.Reserved[0] = 0;
      groupAffinity.Reserved[1] = 0;
      groupAffinity.Reserved[2] = 0;
      if (!pSetThreadGroupAffinity(thread, &groupAffinity, nullptr))
        WARNING("SetThreadGroupAffinity failed"); // on purpose only a warning

      PROCESSOR_NUMBER processorNumber;
      processorNumber.Group = group;
      processorNumber.Number = number;
      processorNumber.Reserved = 0;
      if (!pSetThreadIdealProcessorEx(thread, &processorNumber, nullptr))
        WARNING("SetThreadIdealProcessorEx failed"); // on purpose only a warning
    }
    else
    {
      if (!SetThreadAffinityMask(thread, DWORD_PTR(uint64_t(1) << affinity)))
        WARNING("SetThreadAffinityMask failed"); // on purpose only a warning
      if (SetThreadIdealProcessor(thread, (DWORD)affinity) == (DWORD)-1)
        WARNING("SetThreadIdealProcessor failed"); // on purpose only a warning
      }
  }

  /*! set affinity of the calling thread */
  void setAffinity(ssize_t affinity) {
    setAffinity(GetCurrentThread(), affinity);
  }

  struct ThreadStartupData
  {
  public:
    ThreadStartupData (thread_func f, void* arg)
      : f(f), arg(arg) {}
  public:
    thread_func f;
    void* arg;
  };

  static void* threadStartup(ThreadStartupData* parg)
  {
    _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6));
    parg->f(parg->arg);
    delete parg;
    return nullptr;
  }

#if !defined(PTHREADS_WIN32)

  /*! creates a hardware thread running on specific core */
  thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID)
  {
    HANDLE thread = CreateThread(nullptr, stack_size, (LPTHREAD_START_ROUTINE)threadStartup, new ThreadStartupData(f,arg), 0, nullptr);
    if (thread == nullptr) FATAL("CreateThread failed");
    if (threadID >= 0) setAffinity(thread, threadID);
    return thread_t(thread);
  }

  /*! the thread calling this function gets yielded */
  void yield() {
    SwitchToThread();
  }

  /*! waits until the given thread has terminated */
  void join(thread_t tid) {
    WaitForSingleObject(HANDLE(tid), INFINITE);
    CloseHandle(HANDLE(tid));
  }

  /*! destroy a hardware thread by its handle */
  void destroyThread(thread_t tid) {
    TerminateThread(HANDLE(tid),0);
    CloseHandle(HANDLE(tid));
  }

  /*! creates thread local storage */
  tls_t createTls() {
    return tls_t(size_t(TlsAlloc()));
  }

  /*! set the thread local storage pointer */
  void setTls(tls_t tls, void* const ptr) {
    TlsSetValue(DWORD(size_t(tls)), ptr);
  }

  /*! return the thread local storage pointer */
  void* getTls(tls_t tls) {
    return TlsGetValue(DWORD(size_t(tls)));
  }

  /*! destroys thread local storage identifier */
  void destroyTls(tls_t tls) {
    TlsFree(DWORD(size_t(tls)));
  }
#endif
}

#endif

////////////////////////////////////////////////////////////////////////////////
/// Linux Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__LINUX__)

#include <fstream>
#include <sstream>
#include <algorithm>

namespace embree
{
  /* changes thread ID mapping such that we first fill up all thread on one core */
  size_t mapThreadID(size_t threadID)
  {
    static MutexSys mutex;
    Lock<MutexSys> lock(mutex);
    static std::vector<size_t> threadIDs;

    if (threadIDs.size() == 0)
    {
      /* parse thread/CPU topology */
      for (size_t cpuID=0;;cpuID++)
      {
        std::fstream fs;
        std::string cpu = std::string("/sys/devices/system/cpu/cpu") + std::to_string((long long)cpuID) + std::string("/topology/thread_siblings_list");
        fs.open (cpu.c_str(), std::fstream::in);
        if (fs.fail()) break;

        int i;
        while (fs >> i)
        {
          if (std::none_of(threadIDs.begin(),threadIDs.end(),[&] (int id) { return id == i; }))
            threadIDs.push_back(i);
          if (fs.peek() == ',')
            fs.ignore();
        }
        fs.close();
      }

#if 0
      for (size_t i=0;i<threadIDs.size();i++)
        std::cout << i << " -> " << threadIDs[i] << std::endl;
#endif

      /* verify the mapping and do not use it if the mapping has errors */
      for (size_t i=0;i<threadIDs.size();i++) {
        for (size_t j=0;j<threadIDs.size();j++) {
          if (i != j && threadIDs[i] == threadIDs[j]) {
            threadIDs.clear();
          }
        }
      }
    }

    /* re-map threadIDs if mapping is available */
    size_t ID = threadID;
    if (threadID < threadIDs.size())
      ID = threadIDs[threadID];

    return ID;
  }

  /*! set affinity of the calling thread */
  void setAffinity(ssize_t affinity)
  {
    cpu_set_t cset;
    CPU_ZERO(&cset);
    CPU_SET(mapThreadID(affinity), &cset);

    if (pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset) != 0)
      WARNING("pthread_setaffinity_np failed"); // on purpose only a warning
  }
}
#endif

////////////////////////////////////////////////////////////////////////////////
/// FreeBSD Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__FreeBSD__)

#include <pthread_np.h>

namespace embree
{
  /*! set affinity of the calling thread */
  void setAffinity(ssize_t affinity)
  {
    cpuset_t cset;
    CPU_ZERO(&cset);
    CPU_SET(affinity, &cset);

    if (pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset) != 0)
      WARNING("pthread_setaffinity_np failed"); // on purpose only a warning
  }
}
#endif

////////////////////////////////////////////////////////////////////////////////
/// MacOSX Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__MACOSX__)

#include <mach/thread_act.h>
#include <mach/thread_policy.h>
#include <mach/mach_init.h>

namespace embree
{
  /*! set affinity of the calling thread */
  void setAffinity(ssize_t affinity)
  {
    thread_affinity_policy ap;
    ap.affinity_tag = affinity;
    if (thread_policy_set(mach_thread_self(),THREAD_AFFINITY_POLICY,(thread_policy_t)&ap,THREAD_AFFINITY_POLICY_COUNT) != KERN_SUCCESS)
      WARNING("setting thread affinity failed"); // on purpose only a warning
  }
}
#endif

////////////////////////////////////////////////////////////////////////////////
/// Unix Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__UNIX__) || defined(PTHREADS_WIN32)

#include <pthread.h>
#include <sched.h>

#if defined(__USE_NUMA__)
#include <numa.h>
#endif

namespace embree
{
  struct ThreadStartupData
  {
  public:
    ThreadStartupData (thread_func f, void* arg, int affinity)
      : f(f), arg(arg), affinity(affinity) {}
  public:
    thread_func f;
    void* arg;
    ssize_t affinity;
  };

  static void* threadStartup(ThreadStartupData* parg)
  {
    _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6));

    /*! Mac OS X does not support setting affinity at thread creation time */
#if defined(__MACOSX__)
    if (parg->affinity >= 0)
	setAffinity(parg->affinity);
#endif

    parg->f(parg->arg);
    delete parg;
    return nullptr;
  }

  /*! creates a hardware thread running on specific core */
  thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID)
  {
    /* set stack size */
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    if (stack_size > 0) pthread_attr_setstacksize (&attr, stack_size);

    /* create thread */
    pthread_t* tid = new pthread_t;
    if (pthread_create(tid,&attr,(void*(*)(void*))threadStartup,new ThreadStartupData(f,arg,threadID)) != 0) {
      pthread_attr_destroy(&attr);
      delete tid;
      FATAL("pthread_create failed");
    }
    pthread_attr_destroy(&attr);

    /* set affinity */
#if defined(__LINUX__)
    if (threadID >= 0) {
      cpu_set_t cset;
      CPU_ZERO(&cset);
      CPU_SET(mapThreadID(threadID), &cset);
      if (pthread_setaffinity_np(*tid, sizeof(cset), &cset))
        WARNING("pthread_setaffinity_np failed"); // on purpose only a warning
    }
#elif defined(__FreeBSD__)
    if (threadID >= 0) {
      cpuset_t cset;
      CPU_ZERO(&cset);
      CPU_SET(threadID, &cset);
      if (pthread_setaffinity_np(*tid, sizeof(cset), &cset))
        WARNING("pthread_setaffinity_np failed"); // on purpose only a warning
    }
#endif

    return thread_t(tid);
  }

  /*! the thread calling this function gets yielded */
  void yield() {
    sched_yield();
  }

  /*! waits until the given thread has terminated */
  void join(thread_t tid) {
    if (pthread_join(*(pthread_t*)tid, nullptr) != 0)
      FATAL("pthread_join failed");
    delete (pthread_t*)tid;
  }

  /*! destroy a hardware thread by its handle */
  void destroyThread(thread_t tid) {
    pthread_cancel(*(pthread_t*)tid);
    delete (pthread_t*)tid;
  }

  /*! creates thread local storage */
  tls_t createTls()
  {
    pthread_key_t* key = new pthread_key_t;
    if (pthread_key_create(key,nullptr) != 0)
      FATAL("pthread_key_create failed");

    return tls_t(key);
  }

  /*! return the thread local storage pointer */
  void* getTls(tls_t tls)
  {
    assert(tls);
    return pthread_getspecific(*(pthread_key_t*)tls);
  }

  /*! set the thread local storage pointer */
  void setTls(tls_t tls, void* const ptr)
  {
    assert(tls);
    if (pthread_setspecific(*(pthread_key_t*)tls, ptr) != 0)
      FATAL("pthread_setspecific failed");
  }

  /*! destroys thread local storage identifier */
  void destroyTls(tls_t tls)
  {
    assert(tls);
    if (pthread_key_delete(*(pthread_key_t*)tls) != 0)
      FATAL("pthread_key_delete failed");
    delete (pthread_key_t*)tls;
  }
}

#endif
<commit_msg>fixed memory leak in createTls<commit_after>// ======================================================================== //
// Copyright 2009-2016 Intel Corporation                                    //
//                                                                          //
// 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 "thread.h"
#include "sysinfo.h"
#include "string.h"

#include <iostream>
#include <xmmintrin.h>

#if defined(PTHREADS_WIN32)
#pragma comment (lib, "pthreadVC.lib")
#endif

////////////////////////////////////////////////////////////////////////////////
/// Windows Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__WIN32__)

#define WIN32_LEAN_AND_MEAN
#include <windows.h>

namespace embree
{
  /*! set the affinity of a given thread */
  void setAffinity(HANDLE thread, ssize_t affinity)
  {
    typedef WORD (WINAPI *GetActiveProcessorGroupCountFunc)();
    typedef DWORD (WINAPI *GetActiveProcessorCountFunc)(WORD);
    typedef BOOL (WINAPI *SetThreadGroupAffinityFunc)(HANDLE, const GROUP_AFFINITY *, PGROUP_AFFINITY);
    typedef BOOL (WINAPI *SetThreadIdealProcessorExFunc)(HANDLE, PPROCESSOR_NUMBER, PPROCESSOR_NUMBER);
    HMODULE hlib = LoadLibrary("Kernel32");
    GetActiveProcessorGroupCountFunc pGetActiveProcessorGroupCount = (GetActiveProcessorGroupCountFunc)GetProcAddress(hlib, "GetActiveProcessorGroupCount");
    GetActiveProcessorCountFunc pGetActiveProcessorCount = (GetActiveProcessorCountFunc)GetProcAddress(hlib, "GetActiveProcessorCount");
    SetThreadGroupAffinityFunc pSetThreadGroupAffinity = (SetThreadGroupAffinityFunc)GetProcAddress(hlib, "SetThreadGroupAffinity");
    SetThreadIdealProcessorExFunc pSetThreadIdealProcessorEx = (SetThreadIdealProcessorExFunc)GetProcAddress(hlib, "SetThreadIdealProcessorEx");
    if (pGetActiveProcessorGroupCount && pGetActiveProcessorCount && pSetThreadGroupAffinity && pSetThreadIdealProcessorEx)
    {
      int groups = pGetActiveProcessorGroupCount();
      int totalProcessors = 0, group = 0, number = 0;
      for (int i = 0; i<groups; i++) {
        int processors = pGetActiveProcessorCount(i);
        if (totalProcessors + processors > affinity) {
          group = i;
          number = (int)affinity - totalProcessors;
          break;
        }
        totalProcessors += processors;
      }

      GROUP_AFFINITY groupAffinity;
      groupAffinity.Group = (WORD)group;
      groupAffinity.Mask = (KAFFINITY)(uint64_t(1) << number);
      groupAffinity.Reserved[0] = 0;
      groupAffinity.Reserved[1] = 0;
      groupAffinity.Reserved[2] = 0;
      if (!pSetThreadGroupAffinity(thread, &groupAffinity, nullptr))
        WARNING("SetThreadGroupAffinity failed"); // on purpose only a warning

      PROCESSOR_NUMBER processorNumber;
      processorNumber.Group = group;
      processorNumber.Number = number;
      processorNumber.Reserved = 0;
      if (!pSetThreadIdealProcessorEx(thread, &processorNumber, nullptr))
        WARNING("SetThreadIdealProcessorEx failed"); // on purpose only a warning
    }
    else
    {
      if (!SetThreadAffinityMask(thread, DWORD_PTR(uint64_t(1) << affinity)))
        WARNING("SetThreadAffinityMask failed"); // on purpose only a warning
      if (SetThreadIdealProcessor(thread, (DWORD)affinity) == (DWORD)-1)
        WARNING("SetThreadIdealProcessor failed"); // on purpose only a warning
      }
  }

  /*! set affinity of the calling thread */
  void setAffinity(ssize_t affinity) {
    setAffinity(GetCurrentThread(), affinity);
  }

  struct ThreadStartupData
  {
  public:
    ThreadStartupData (thread_func f, void* arg)
      : f(f), arg(arg) {}
  public:
    thread_func f;
    void* arg;
  };

  static void* threadStartup(ThreadStartupData* parg)
  {
    _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6));
    parg->f(parg->arg);
    delete parg;
    return nullptr;
  }

#if !defined(PTHREADS_WIN32)

  /*! creates a hardware thread running on specific core */
  thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID)
  {
    HANDLE thread = CreateThread(nullptr, stack_size, (LPTHREAD_START_ROUTINE)threadStartup, new ThreadStartupData(f,arg), 0, nullptr);
    if (thread == nullptr) FATAL("CreateThread failed");
    if (threadID >= 0) setAffinity(thread, threadID);
    return thread_t(thread);
  }

  /*! the thread calling this function gets yielded */
  void yield() {
    SwitchToThread();
  }

  /*! waits until the given thread has terminated */
  void join(thread_t tid) {
    WaitForSingleObject(HANDLE(tid), INFINITE);
    CloseHandle(HANDLE(tid));
  }

  /*! destroy a hardware thread by its handle */
  void destroyThread(thread_t tid) {
    TerminateThread(HANDLE(tid),0);
    CloseHandle(HANDLE(tid));
  }

  /*! creates thread local storage */
  tls_t createTls() {
    return tls_t(size_t(TlsAlloc()));
  }

  /*! set the thread local storage pointer */
  void setTls(tls_t tls, void* const ptr) {
    TlsSetValue(DWORD(size_t(tls)), ptr);
  }

  /*! return the thread local storage pointer */
  void* getTls(tls_t tls) {
    return TlsGetValue(DWORD(size_t(tls)));
  }

  /*! destroys thread local storage identifier */
  void destroyTls(tls_t tls) {
    TlsFree(DWORD(size_t(tls)));
  }
#endif
}

#endif

////////////////////////////////////////////////////////////////////////////////
/// Linux Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__LINUX__)

#include <fstream>
#include <sstream>
#include <algorithm>

namespace embree
{
  /* changes thread ID mapping such that we first fill up all thread on one core */
  size_t mapThreadID(size_t threadID)
  {
    static MutexSys mutex;
    Lock<MutexSys> lock(mutex);
    static std::vector<size_t> threadIDs;

    if (threadIDs.size() == 0)
    {
      /* parse thread/CPU topology */
      for (size_t cpuID=0;;cpuID++)
      {
        std::fstream fs;
        std::string cpu = std::string("/sys/devices/system/cpu/cpu") + std::to_string((long long)cpuID) + std::string("/topology/thread_siblings_list");
        fs.open (cpu.c_str(), std::fstream::in);
        if (fs.fail()) break;

        int i;
        while (fs >> i)
        {
          if (std::none_of(threadIDs.begin(),threadIDs.end(),[&] (int id) { return id == i; }))
            threadIDs.push_back(i);
          if (fs.peek() == ',')
            fs.ignore();
        }
        fs.close();
      }

#if 0
      for (size_t i=0;i<threadIDs.size();i++)
        std::cout << i << " -> " << threadIDs[i] << std::endl;
#endif

      /* verify the mapping and do not use it if the mapping has errors */
      for (size_t i=0;i<threadIDs.size();i++) {
        for (size_t j=0;j<threadIDs.size();j++) {
          if (i != j && threadIDs[i] == threadIDs[j]) {
            threadIDs.clear();
          }
        }
      }
    }

    /* re-map threadIDs if mapping is available */
    size_t ID = threadID;
    if (threadID < threadIDs.size())
      ID = threadIDs[threadID];

    return ID;
  }

  /*! set affinity of the calling thread */
  void setAffinity(ssize_t affinity)
  {
    cpu_set_t cset;
    CPU_ZERO(&cset);
    CPU_SET(mapThreadID(affinity), &cset);

    if (pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset) != 0)
      WARNING("pthread_setaffinity_np failed"); // on purpose only a warning
  }
}
#endif

////////////////////////////////////////////////////////////////////////////////
/// FreeBSD Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__FreeBSD__)

#include <pthread_np.h>

namespace embree
{
  /*! set affinity of the calling thread */
  void setAffinity(ssize_t affinity)
  {
    cpuset_t cset;
    CPU_ZERO(&cset);
    CPU_SET(affinity, &cset);

    if (pthread_setaffinity_np(pthread_self(), sizeof(cset), &cset) != 0)
      WARNING("pthread_setaffinity_np failed"); // on purpose only a warning
  }
}
#endif

////////////////////////////////////////////////////////////////////////////////
/// MacOSX Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__MACOSX__)

#include <mach/thread_act.h>
#include <mach/thread_policy.h>
#include <mach/mach_init.h>

namespace embree
{
  /*! set affinity of the calling thread */
  void setAffinity(ssize_t affinity)
  {
    thread_affinity_policy ap;
    ap.affinity_tag = affinity;
    if (thread_policy_set(mach_thread_self(),THREAD_AFFINITY_POLICY,(thread_policy_t)&ap,THREAD_AFFINITY_POLICY_COUNT) != KERN_SUCCESS)
      WARNING("setting thread affinity failed"); // on purpose only a warning
  }
}
#endif

////////////////////////////////////////////////////////////////////////////////
/// Unix Platform
////////////////////////////////////////////////////////////////////////////////

#if defined(__UNIX__) || defined(PTHREADS_WIN32)

#include <pthread.h>
#include <sched.h>

#if defined(__USE_NUMA__)
#include <numa.h>
#endif

namespace embree
{
  struct ThreadStartupData
  {
  public:
    ThreadStartupData (thread_func f, void* arg, int affinity)
      : f(f), arg(arg), affinity(affinity) {}
  public:
    thread_func f;
    void* arg;
    ssize_t affinity;
  };

  static void* threadStartup(ThreadStartupData* parg)
  {
    _mm_setcsr(_mm_getcsr() | /*FTZ:*/ (1<<15) | /*DAZ:*/ (1<<6));

    /*! Mac OS X does not support setting affinity at thread creation time */
#if defined(__MACOSX__)
    if (parg->affinity >= 0)
	setAffinity(parg->affinity);
#endif

    parg->f(parg->arg);
    delete parg;
    return nullptr;
  }

  /*! creates a hardware thread running on specific core */
  thread_t createThread(thread_func f, void* arg, size_t stack_size, ssize_t threadID)
  {
    /* set stack size */
    pthread_attr_t attr;
    pthread_attr_init(&attr);
    if (stack_size > 0) pthread_attr_setstacksize (&attr, stack_size);

    /* create thread */
    pthread_t* tid = new pthread_t;
    if (pthread_create(tid,&attr,(void*(*)(void*))threadStartup,new ThreadStartupData(f,arg,threadID)) != 0) {
      pthread_attr_destroy(&attr);
      delete tid;
      FATAL("pthread_create failed");
    }
    pthread_attr_destroy(&attr);

    /* set affinity */
#if defined(__LINUX__)
    if (threadID >= 0) {
      cpu_set_t cset;
      CPU_ZERO(&cset);
      CPU_SET(mapThreadID(threadID), &cset);
      if (pthread_setaffinity_np(*tid, sizeof(cset), &cset))
        WARNING("pthread_setaffinity_np failed"); // on purpose only a warning
    }
#elif defined(__FreeBSD__)
    if (threadID >= 0) {
      cpuset_t cset;
      CPU_ZERO(&cset);
      CPU_SET(threadID, &cset);
      if (pthread_setaffinity_np(*tid, sizeof(cset), &cset))
        WARNING("pthread_setaffinity_np failed"); // on purpose only a warning
    }
#endif

    return thread_t(tid);
  }

  /*! the thread calling this function gets yielded */
  void yield() {
    sched_yield();
  }

  /*! waits until the given thread has terminated */
  void join(thread_t tid) {
    if (pthread_join(*(pthread_t*)tid, nullptr) != 0)
      FATAL("pthread_join failed");
    delete (pthread_t*)tid;
  }

  /*! destroy a hardware thread by its handle */
  void destroyThread(thread_t tid) {
    pthread_cancel(*(pthread_t*)tid);
    delete (pthread_t*)tid;
  }

  /*! creates thread local storage */
  tls_t createTls()
  {
    pthread_key_t* key = new pthread_key_t;
    if (pthread_key_create(key,nullptr) != 0) {
      delete key;
      FATAL("pthread_key_create failed");
    }

    return tls_t(key);
  }

  /*! return the thread local storage pointer */
  void* getTls(tls_t tls)
  {
    assert(tls);
    return pthread_getspecific(*(pthread_key_t*)tls);
  }

  /*! set the thread local storage pointer */
  void setTls(tls_t tls, void* const ptr)
  {
    assert(tls);
    if (pthread_setspecific(*(pthread_key_t*)tls, ptr) != 0)
      FATAL("pthread_setspecific failed");
  }

  /*! destroys thread local storage identifier */
  void destroyTls(tls_t tls)
  {
    assert(tls);
    if (pthread_key_delete(*(pthread_key_t*)tls) != 0)
      FATAL("pthread_key_delete failed");
    delete (pthread_key_t*)tls;
  }
}

#endif
<|endoftext|>