<commit_before>
//--------------------------------------------------
//  file: RPN+UnitTests.cpp
//-------------------------------------------------

#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "RPNCalc.h"
#include "RPNTestHelper.h"

using namespace P4_RPNCALC;

TEST_CASE("Operation Methods")
{
	RPNTestHelper test;

	SECTION("Sanity Tests") {
		for (int n = 0; n < 100; n++) {
			REQUIRE(test.expectedStackOutput(to_string(n), to_string(n)));
		}
	}

	SECTION("Method: clearAll()")
	{
		REQUIRE(test.expectedStackOutput("50", "50"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("50 100 +", "150"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("50 100 + 200", "200"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("50", "50"));
		REQUIRE(test.expectedOutput("C", ""));
		REQUIRE(test.expectedStackOutput("50 100 +", "150"));
		REQUIRE(test.expectedOutput("C", ""));
		REQUIRE(test.expectedStackOutput("50 100 + 200", "200"));
		REQUIRE(test.expectedOutput("C", ""));
	}

	SECTION("Method: clearEntry()")
	{
		REQUIRE(test.expectedStackOutput("50", "50"));
		REQUIRE(test.expectedOutput("ce", ""));
		REQUIRE(test.expectedStackOutput("50 100 +", "150"));
		REQUIRE(test.expectedOutput("ce", ""));
		REQUIRE(test.expectedStackOutput("50 100 + 200", "200"));
		REQUIRE(test.expectedStackOutput("ce", "150"));
		REQUIRE(test.expectedOutput("ce", ""));

		REQUIRE(test.expectedStackOutput("50", "50"));
		REQUIRE(test.expectedOutput("CE", ""));
		REQUIRE(test.expectedStackOutput("50 100 +", "150"));
		REQUIRE(test.expectedOutput("CE", ""));
		REQUIRE(test.expectedStackOutput("50 100 + 200", "200"));
		REQUIRE(test.expectedStackOutput("CE", "150"));
		REQUIRE(test.expectedOutput("CE", ""));
	}

	SECTION("Method: add()")
	{
		REQUIRE(test.expectedStackOutput("3 5+", "8"));
		REQUIRE(test.expectedStackOutput("2 4 3 +", "7"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("3 4 + 6", "6"));
		REQUIRE(test.expectedStackOutput("4 +", "10"));
		REQUIRE(test.expectedStackOutput("-12 +", "-2"));
		REQUIRE(test.expectedStackOutput("5 +", "3"));
		REQUIRE(test.expectedStackOutput("3 +", "6"));
		REQUIRE(test.getStackOutput("10 100 +") == "110");
		REQUIRE(test.getStackOutput("10 100+") == "110");
	}

	SECTION("Method: combinations of add() & subtract()")
	{
		REQUIRE(test.getStackOutput("4.4 5.5 + 60 -") == "-50.1");
		REQUIRE(test.expectedStackOutput("4.4 5.5 - 60 +", "58.9"));
		REQUIRE(test.expectedStackOutput("40 50 + 60 -", "30"));
		REQUIRE(test.expectedStackOutput("40 50 - 60 +", "50"));
		REQUIRE(test.expectedStackOutput("40 50 60 + -", "-70"));
		REQUIRE(test.expectedStackOutput("40 50 60 - +", "30"));
		REQUIRE(test.expectedStackOutput("-40 -50 + 60 -", "-150"));
		REQUIRE(test.expectedStackOutput("-40 -50 + -60 -", "-30"));
		REQUIRE(test.expectedStackOutput("-40 -50 - 60 +", "70"));
		REQUIRE(test.expectedStackOutput("-40 -50 - -60 +", "-50"));
	}

	SECTION("Method: subtract()")
	{
		REQUIRE(test.expectedStackOutput("5 6 -", "-1"));
		REQUIRE(test.expectedStackOutput("3 9 4 -", "5"));
		REQUIRE(test.expectedStackOutput("-", "-2"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("-1 5 -", "-6"));
		REQUIRE(test.expectedStackOutput("10 100 -", "-90"));
		REQUIRE(test.expectedStackOutput("10 100-", "-90"));
		REQUIRE(test.expectedStackOutput("-", "0"));
	}

	SECTION("Method: multiply()")
	{
		REQUIRE(test.expectedStackOutput("3 9 7 2 4 *", "8"));
		REQUIRE(test.expectedStackOutput("*", "56"));
		REQUIRE(test.expectedStackOutput("*", "504"));
		REQUIRE(test.expectedStackOutput("*", "1512"));
		REQUIRE(test.expectError("*"));
		REQUIRE(test.getOutput("c") == "");
		REQUIRE(test.expectedStackOutput("-4 -6 *", "24"));
		REQUIRE(test.expectedStackOutput("-2 *", "-48"));
		REQUIRE(test.expectedStackOutput("10 100 *", "1000"));
		REQUIRE(test.expectedStackOutput("10 100*", "1000"));
		REQUIRE(test.expectedStackOutput("5.5 2.2*", "12.1"));
	}

	SECTION("Method: divide()")
	{
		REQUIRE(test.expectedStackOutput("16 4 2 /", "2"));
		REQUIRE(test.expectedStackOutput("/", "8"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("2 5 /", "0.4"));
		REQUIRE(test.expectedStackOutput("9 3 7 /", "0.428571"));
		REQUIRE(test.expectedStackOutput("-1 /", "-0.428571"));
		REQUIRE(test.expectedStackOutput("-1 / ", "0.428571"));
		REQUIRE(test.expectedStackOutput("100 10 /", "10"));
		REQUIRE(test.expectedStackOutput("100 10/", "10"));
		REQUIRE(test.expectedStackOutput("/", "1"));
		REQUIRE(test.expectedStackOutput("/", "0.428571"));
		REQUIRE(test.expectedStackOutput("/", "21"));
		REQUIRE(test.expectedStackOutput("/", "0.0190476"));
		REQUIRE(test.expectedStackOutput("/", "0.0190476"));
		REQUIRE(test.expectError("/"));
	}

	SECTION("Method: mod()")
	{
		REQUIRE(test.expectedStackOutput("16 8 6 %", "2"));
		REQUIRE(test.expectedStackOutput("%", "0"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectError("%"));
		REQUIRE(test.expectedStackOutput("10 1 %", "0"));
		REQUIRE(test.expectedStackOutput("10 2 %", "0"));
		REQUIRE(test.expectedStackOutput("10 3 %", "1"));
		REQUIRE(test.expectedStackOutput("10 4 %", "2"));
		REQUIRE(test.expectedStackOutput("10 5 %", "0"));
		REQUIRE(test.expectedStackOutput("10 6 %", "4"));
		REQUIRE(test.expectedStackOutput("10 7 %", "3"));
		REQUIRE(test.expectedStackOutput("10 8 %", "2"));
		REQUIRE(test.expectedStackOutput("10 9 %", "1"));
		REQUIRE(test.expectedStackOutput("10 10 %", "0"));
		REQUIRE(test.expectedStackOutput("100 70 %", "30"));
		REQUIRE(test.expectedStackOutput("100 70%", "30"));
	}

	SECTION("Method: exp()")
	{
		REQUIRE(test.expectedStackOutput("10 2 ^", "100"));
		REQUIRE(test.expectedStackOutput("10 2 2 ^", "4"));
		REQUIRE(test.expectedStackOutput("^", "10000"));
		REQUIRE(test.expectedStackOutput("-10 2 ^", "100"));
		REQUIRE(test.expectedStackOutput("-10 3 ^", "-1000"));
		REQUIRE(test.expectedStackOutput("-10 3^", "-1000"));
		REQUIRE(test.expectedStackOutput("0^", "1"));
		REQUIRE(test.expectedStackOutput("^", "-1000"));
		REQUIRE(test.expectedStackOutput("^", "0"));
		REQUIRE(test.expectedStackOutput("^", "1"));
		REQUIRE(test.expectedStackOutput("^", "100"));
		REQUIRE(test.expectError("^"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectError("^"));
		REQUIRE(test.expectedStackOutput("100 100^", "1e+200"));
	}

	SECTION("Method: neg()")
	{
		REQUIRE(test.expectedStackOutput("-1000", "-1000"));
		REQUIRE(test.expectedStackOutput("M", "1000"));
		REQUIRE(test.getStackOutput("-1000 -1*") == "1000");
		REQUIRE(test.expectedStackOutput("M", "-1000"));
		REQUIRE(test.expectedStackOutput("-4/", "250"));
		REQUIRE(test.expectedStackOutput("m", "-250"));
		REQUIRE(test.expectedStackOutput("-2*", "500"));
		REQUIRE(test.expectedStackOutput("m", "-500"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectError("m"));
		REQUIRE(test.expectError("M"));
	}

	/*
	SECTION("Method: rotateDown()")
	{
		REQUIRE(test.expectedInputOutput("100 200", "200"));
		REQUIRE(test.expectedInputOutput("D", "100"));
		REQUIRE(test.expectedInputOutput("D", "200"));
		REQUIRE(test.expectedInputOutput("d", "100"));
		REQUIRE(test.expectedInputOutput("d", "200"));
		REQUIRE(test.expectedInputOutput("c", ""));
		REQUIRE(test.expectedInputOutput("D", "<<error>>"));
		REQUIRE(test.expectedInputOutput("c", ""));
		REQUIRE(test.expectedInputOutput("d", "<<error>>"));
	}

	SECTION("Method: rotateUp()")
	{
		REQUIRE(test.expectedInputOutput("300 500", "500"));
		REQUIRE(test.expectedInputOutput("U", "300"));
		REQUIRE(test.expectedInputOutput("U", "500"));
		REQUIRE(test.expectedInputOutput("u", "300"));
		REQUIRE(test.expectedInputOutput("u", "500"));
		REQUIRE(test.expectedInputOutput("c", ""));
		REQUIRE(test.expectedInputOutput("U", "<<error>>"));
		REQUIRE(test.expectedInputOutput("c", ""));
		REQUIRE(test.expectedInputOutput("u", "<<error>>"));
	}

	SECTION("Methods: saveToFile(), loadProgram(), recordProgram(), runProgram()")
	{
		REQUIRE(test.expectedInputOutput("R", "<<error>>"));
		REQUIRE(test.expectedInputOutput("F", "<<error>>"));
		REQUIRE(test.expectedInputOutput("p", "0>"));
		REQUIRE(test.expectedInputOutput("5 10 +", "1>"));
		REQUIRE(test.expectedInputOutput("20 30 -", "2>"));
		//REQUIRE(test.expectedInputOutput("P", ""));
		//REQUIRE(test.expectedInputOutput("f", "Enter a filename:"));
		REQUIRE(test.expectedInputOutput("test1", ""));
		//REQUIRE(test.expectedInputOutput("l", "Enter a filename:"));
		REQUIRE(test.expectedInputOutput("test", "error"));
		//REQUIRE(test.expectedInputOutput("L", "Enter a filename:"));
		REQUIRE(test.expectedInputOutput("test1", ""));
		REQUIRE(test.expectedInputOutput("r", "-10"));
		REQUIRE(test.expectedInputOutput("c", ""));
	}

	SECTION("Methods: getReg(), setReg()")
	{
		REQUIRE(test.expectedInputOutput("s0", "<<error>>"));
		REQUIRE(test.expectedInputOutput("S1", "<<error>>"));
		REQUIRE(test.expectedInputOutput("s5", "<<error>>"));
		REQUIRE(test.expectedInputOutput("G0", "0"));
		REQUIRE(test.expectedInputOutput("g1", "0"));
		REQUIRE(test.expectedInputOutput("G5", "0"));
		REQUIRE(test.expectedInputOutput("1000", "1000"));
		REQUIRE(test.expectedInputOutput("s5", "1000"));
		REQUIRE(test.expectedInputOutput("2.5", "2.5"));
		REQUIRE(test.expectedInputOutput("S0", "2.5"));
		REQUIRE(test.expectedInputOutput("G5", "1000"));
		REQUIRE(test.expectedInputOutput("g0", "2.5"));
	}
	// */
}
//*/<commit_msg>uncomment rotate down tests<commit_after>
//--------------------------------------------------
//  file: RPN+UnitTests.cpp
//-------------------------------------------------

#define CATCH_CONFIG_MAIN
#include "catch.hpp"
#include "RPNCalc.h"
#include "RPNTestHelper.h"

using namespace P4_RPNCALC;

TEST_CASE("Operation Methods")
{
	RPNTestHelper test;

	SECTION("Sanity Tests") {
		for (int n = 0; n < 100; n++) {
			REQUIRE(test.expectedStackOutput(to_string(n), to_string(n)));
		}
	}

	SECTION("Method: clearAll()")
	{
		REQUIRE(test.expectedStackOutput("50", "50"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("50 100 +", "150"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("50 100 + 200", "200"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("50", "50"));
		REQUIRE(test.expectedOutput("C", ""));
		REQUIRE(test.expectedStackOutput("50 100 +", "150"));
		REQUIRE(test.expectedOutput("C", ""));
		REQUIRE(test.expectedStackOutput("50 100 + 200", "200"));
		REQUIRE(test.expectedOutput("C", ""));
	}

	SECTION("Method: clearEntry()")
	{
		REQUIRE(test.expectedStackOutput("50", "50"));
		REQUIRE(test.expectedOutput("ce", ""));
		REQUIRE(test.expectedStackOutput("50 100 +", "150"));
		REQUIRE(test.expectedOutput("ce", ""));
		REQUIRE(test.expectedStackOutput("50 100 + 200", "200"));
		REQUIRE(test.expectedStackOutput("ce", "150"));
		REQUIRE(test.expectedOutput("ce", ""));

		REQUIRE(test.expectedStackOutput("50", "50"));
		REQUIRE(test.expectedOutput("CE", ""));
		REQUIRE(test.expectedStackOutput("50 100 +", "150"));
		REQUIRE(test.expectedOutput("CE", ""));
		REQUIRE(test.expectedStackOutput("50 100 + 200", "200"));
		REQUIRE(test.expectedStackOutput("CE", "150"));
		REQUIRE(test.expectedOutput("CE", ""));
	}

	SECTION("Method: add()")
	{
		REQUIRE(test.expectedStackOutput("3 5+", "8"));
		REQUIRE(test.expectedStackOutput("2 4 3 +", "7"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("3 4 + 6", "6"));
		REQUIRE(test.expectedStackOutput("4 +", "10"));
		REQUIRE(test.expectedStackOutput("-12 +", "-2"));
		REQUIRE(test.expectedStackOutput("5 +", "3"));
		REQUIRE(test.expectedStackOutput("3 +", "6"));
		REQUIRE(test.getStackOutput("10 100 +") == "110");
		REQUIRE(test.getStackOutput("10 100+") == "110");
	}

	SECTION("Method: combinations of add() & subtract()")
	{
		REQUIRE(test.getStackOutput("4.4 5.5 + 60 -") == "-50.1");
		REQUIRE(test.expectedStackOutput("4.4 5.5 - 60 +", "58.9"));
		REQUIRE(test.expectedStackOutput("40 50 + 60 -", "30"));
		REQUIRE(test.expectedStackOutput("40 50 - 60 +", "50"));
		REQUIRE(test.expectedStackOutput("40 50 60 + -", "-70"));
		REQUIRE(test.expectedStackOutput("40 50 60 - +", "30"));
		REQUIRE(test.expectedStackOutput("-40 -50 + 60 -", "-150"));
		REQUIRE(test.expectedStackOutput("-40 -50 + -60 -", "-30"));
		REQUIRE(test.expectedStackOutput("-40 -50 - 60 +", "70"));
		REQUIRE(test.expectedStackOutput("-40 -50 - -60 +", "-50"));
	}

	SECTION("Method: subtract()")
	{
		REQUIRE(test.expectedStackOutput("5 6 -", "-1"));
		REQUIRE(test.expectedStackOutput("3 9 4 -", "5"));
		REQUIRE(test.expectedStackOutput("-", "-2"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("-1 5 -", "-6"));
		REQUIRE(test.expectedStackOutput("10 100 -", "-90"));
		REQUIRE(test.expectedStackOutput("10 100-", "-90"));
		REQUIRE(test.expectedStackOutput("-", "0"));
	}

	SECTION("Method: multiply()")
	{
		REQUIRE(test.expectedStackOutput("3 9 7 2 4 *", "8"));
		REQUIRE(test.expectedStackOutput("*", "56"));
		REQUIRE(test.expectedStackOutput("*", "504"));
		REQUIRE(test.expectedStackOutput("*", "1512"));
		REQUIRE(test.expectError("*"));
		REQUIRE(test.getOutput("c") == "");
		REQUIRE(test.expectedStackOutput("-4 -6 *", "24"));
		REQUIRE(test.expectedStackOutput("-2 *", "-48"));
		REQUIRE(test.expectedStackOutput("10 100 *", "1000"));
		REQUIRE(test.expectedStackOutput("10 100*", "1000"));
		REQUIRE(test.expectedStackOutput("5.5 2.2*", "12.1"));
	}

	SECTION("Method: divide()")
	{
		REQUIRE(test.expectedStackOutput("16 4 2 /", "2"));
		REQUIRE(test.expectedStackOutput("/", "8"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectedStackOutput("2 5 /", "0.4"));
		REQUIRE(test.expectedStackOutput("9 3 7 /", "0.428571"));
		REQUIRE(test.expectedStackOutput("-1 /", "-0.428571"));
		REQUIRE(test.expectedStackOutput("-1 / ", "0.428571"));
		REQUIRE(test.expectedStackOutput("100 10 /", "10"));
		REQUIRE(test.expectedStackOutput("100 10/", "10"));
		REQUIRE(test.expectedStackOutput("/", "1"));
		REQUIRE(test.expectedStackOutput("/", "0.428571"));
		REQUIRE(test.expectedStackOutput("/", "21"));
		REQUIRE(test.expectedStackOutput("/", "0.0190476"));
		REQUIRE(test.expectedStackOutput("/", "0.0190476"));
		REQUIRE(test.expectError("/"));
	}

	SECTION("Method: mod()")
	{
		REQUIRE(test.expectedStackOutput("16 8 6 %", "2"));
		REQUIRE(test.expectedStackOutput("%", "0"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectError("%"));
		REQUIRE(test.expectedStackOutput("10 1 %", "0"));
		REQUIRE(test.expectedStackOutput("10 2 %", "0"));
		REQUIRE(test.expectedStackOutput("10 3 %", "1"));
		REQUIRE(test.expectedStackOutput("10 4 %", "2"));
		REQUIRE(test.expectedStackOutput("10 5 %", "0"));
		REQUIRE(test.expectedStackOutput("10 6 %", "4"));
		REQUIRE(test.expectedStackOutput("10 7 %", "3"));
		REQUIRE(test.expectedStackOutput("10 8 %", "2"));
		REQUIRE(test.expectedStackOutput("10 9 %", "1"));
		REQUIRE(test.expectedStackOutput("10 10 %", "0"));
		REQUIRE(test.expectedStackOutput("100 70 %", "30"));
		REQUIRE(test.expectedStackOutput("100 70%", "30"));
	}

	SECTION("Method: exp()")
	{
		REQUIRE(test.expectedStackOutput("10 2 ^", "100"));
		REQUIRE(test.expectedStackOutput("10 2 2 ^", "4"));
		REQUIRE(test.expectedStackOutput("^", "10000"));
		REQUIRE(test.expectedStackOutput("-10 2 ^", "100"));
		REQUIRE(test.expectedStackOutput("-10 3 ^", "-1000"));
		REQUIRE(test.expectedStackOutput("-10 3^", "-1000"));
		REQUIRE(test.expectedStackOutput("0^", "1"));
		REQUIRE(test.expectedStackOutput("^", "-1000"));
		REQUIRE(test.expectedStackOutput("^", "0"));
		REQUIRE(test.expectedStackOutput("^", "1"));
		REQUIRE(test.expectedStackOutput("^", "100"));
		REQUIRE(test.expectError("^"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectError("^"));
		REQUIRE(test.expectedStackOutput("100 100^", "1e+200"));
	}

	SECTION("Method: neg()")
	{
		REQUIRE(test.expectedStackOutput("-1000", "-1000"));
		REQUIRE(test.expectedStackOutput("M", "1000"));
		REQUIRE(test.getStackOutput("-1000 -1*") == "1000");
		REQUIRE(test.expectedStackOutput("M", "-1000"));
		REQUIRE(test.expectedStackOutput("-4/", "250"));
		REQUIRE(test.expectedStackOutput("m", "-250"));
		REQUIRE(test.expectedStackOutput("-2*", "500"));
		REQUIRE(test.expectedStackOutput("m", "-500"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectError("m"));
		REQUIRE(test.expectError("M"));
	}

	SECTION("Method: rotateDown()")
	{
		REQUIRE(test.expectedStackOutput("100 200", "200"));
		REQUIRE(test.expectedStackOutput("D", "100"));
		REQUIRE(test.expectedStackOutput("D", "200"));
		REQUIRE(test.expectedStackOutput("d", "100"));
		REQUIRE(test.expectedStackOutput("d", "200"));
		REQUIRE(test.expectedOutput("c", ""));
		REQUIRE(test.expectError("D"));
		REQUIRE(test.expectError("d"));
	}

	/*
	SECTION("Method: rotateUp()")
	{
		REQUIRE(test.expectedInputOutput("300 500", "500"));
		REQUIRE(test.expectedInputOutput("U", "300"));
		REQUIRE(test.expectedInputOutput("U", "500"));
		REQUIRE(test.expectedInputOutput("u", "300"));
		REQUIRE(test.expectedInputOutput("u", "500"));
		REQUIRE(test.expectedInputOutput("c", ""));
		REQUIRE(test.expectedInputOutput("U", "<<error>>"));
		REQUIRE(test.expectedInputOutput("c", ""));
		REQUIRE(test.expectedInputOutput("u", "<<error>>"));
	}

	SECTION("Methods: saveToFile(), loadProgram(), recordProgram(), runProgram()")
	{
		REQUIRE(test.expectedInputOutput("R", "<<error>>"));
		REQUIRE(test.expectedInputOutput("F", "<<error>>"));
		REQUIRE(test.expectedInputOutput("p", "0>"));
		REQUIRE(test.expectedInputOutput("5 10 +", "1>"));
		REQUIRE(test.expectedInputOutput("20 30 -", "2>"));
		//REQUIRE(test.expectedInputOutput("P", ""));
		//REQUIRE(test.expectedInputOutput("f", "Enter a filename:"));
		REQUIRE(test.expectedInputOutput("test1", ""));
		//REQUIRE(test.expectedInputOutput("l", "Enter a filename:"));
		REQUIRE(test.expectedInputOutput("test", "error"));
		//REQUIRE(test.expectedInputOutput("L", "Enter a filename:"));
		REQUIRE(test.expectedInputOutput("test1", ""));
		REQUIRE(test.expectedInputOutput("r", "-10"));
		REQUIRE(test.expectedInputOutput("c", ""));
	}

	SECTION("Methods: getReg(), setReg()")
	{
		REQUIRE(test.expectedInputOutput("s0", "<<error>>"));
		REQUIRE(test.expectedInputOutput("S1", "<<error>>"));
		REQUIRE(test.expectedInputOutput("s5", "<<error>>"));
		REQUIRE(test.expectedInputOutput("G0", "0"));
		REQUIRE(test.expectedInputOutput("g1", "0"));
		REQUIRE(test.expectedInputOutput("G5", "0"));
		REQUIRE(test.expectedInputOutput("1000", "1000"));
		REQUIRE(test.expectedInputOutput("s5", "1000"));
		REQUIRE(test.expectedInputOutput("2.5", "2.5"));
		REQUIRE(test.expectedInputOutput("S0", "2.5"));
		REQUIRE(test.expectedInputOutput("G5", "1000"));
		REQUIRE(test.expectedInputOutput("g0", "2.5"));
	}
	// */
}
//*/<|endoftext|>


<commit_before>////////////////////////////////////////////////////////////
//
//  General package
//
// ---------------------------------------------------------
//
//  AUTHOR: Miguel Ramos Pernas
//  e-mail: miguel.ramos.pernas@cern.ch
//
//  Last update: 19/10/2017
//
// ---------------------------------------------------------
//
//  Description:
//
//  Definition of the main class to print information into
//  a terminal/file. It can be formatted so one can put
//  colors and change the style of the words being
//  displayed.
//
// ---------------------------------------------------------
////////////////////////////////////////////////////////////

#ifndef EXCEPTIONS_HPP
#define EXCEPTIONS_HPP

#include "Messenger.hpp"

#include <exception>
#include <string>
#include <sstream>

//_______________________________________________________________________________

namespace isis {

  //_______________________________________________________________________________
  // Base class to represent an exception
  class BaseException : public std::exception {

  public:

    // Constructor given the string to be printed and the message code
    BaseException( const std::string &info, const MsgCode &st = MsgCode::Error ) {

      std::stringstream ss;
      Messenger msg(st, &ss);
      msg << info << IEndMsg;

      fWhat = ss.str();
    }

    // Destructor. The output is not printed if the "fIgnore" flag is true.
    virtual ~BaseException() { if ( !fIgnore ) std::cout << this->what(); }

    // Ignore the output of this exception
    void ignore() { fIgnore = true; }

    const char* msg() {

      this->ignore();
      return this->what();
    }

  protected:

    // Redefinition of the method from "std::exception"
    const char* what() const throw() { return fWhat.c_str(); }

    // Store what is going to be printed
    std::string fWhat;

    // Flag to ignore the output of this exception
    bool fIgnore = false;

  };

  //_______________________________________________________________________________
  // Represent an exception to be thrown when an input argument is invalid
  class InvalidArgument : public BaseException {

  public:

    // Constructor given the invalid argument and the message code
    InvalidArgument( const std::string &arg, const MsgCode &st = MsgCode::Error ) :
      BaseException(std::string{"Invalid argument \""} + arg + std::string{"\""}, st) { }
  };

    //_______________________________________________________________________________
  // Represent an exception to be thrown when an object could not be found
  class NotFound : public BaseException {

  public:

    // Constructor given the object name, the argument and the message code
    NotFound( const std::string &objname, const std::string &arg, const MsgCode &st = MsgCode::Error ) :
      BaseException(std::string{"Unable to find "} + objname +
		    std::string{"\""} + arg + std::string{"\""}, st) { }

  };

}

#endif
<commit_msg>Fix issue with one print from the exceptions<commit_after>////////////////////////////////////////////////////////////
//
//  General package
//
// ---------------------------------------------------------
//
//  AUTHOR: Miguel Ramos Pernas
//  e-mail: miguel.ramos.pernas@cern.ch
//
//  Last update: 19/10/2017
//
// ---------------------------------------------------------
//
//  Description:
//
//  Definition of the main class to print information into
//  a terminal/file. It can be formatted so one can put
//  colors and change the style of the words being
//  displayed.
//
// ---------------------------------------------------------
////////////////////////////////////////////////////////////

#ifndef EXCEPTIONS_HPP
#define EXCEPTIONS_HPP

#include "Messenger.hpp"

#include <exception>
#include <string>
#include <sstream>

//_______________________________________________________________________________

namespace isis {

  //_______________________________________________________________________________
  // Base class to represent an exception
  class BaseException : public std::exception {

  public:

    // Constructor given the string to be printed and the message code
    BaseException( const std::string &info, const MsgCode &st = MsgCode::Error ) {

      std::stringstream ss;
      Messenger msg(st, &ss);
      msg << info << IEndMsg;

      fWhat = ss.str();
    }

    // Destructor. The output is not printed if the "fIgnore" flag is true.
    virtual ~BaseException() { if ( !fIgnore ) std::cout << this->what(); }

    // Ignore the output of this exception
    void ignore() { fIgnore = true; }

    const char* msg() {

      this->ignore();
      return this->what();
    }

  protected:

    // Redefinition of the method from "std::exception"
    const char* what() const throw() { return fWhat.c_str(); }

    // Store what is going to be printed
    std::string fWhat;

    // Flag to ignore the output of this exception
    bool fIgnore = false;

  };

  //_______________________________________________________________________________
  // Represent an exception to be thrown when an input argument is invalid
  class InvalidArgument : public BaseException {

  public:

    // Constructor given the invalid argument and the message code
    InvalidArgument( const std::string &arg, const MsgCode &st = MsgCode::Error ) :
      BaseException(std::string{"Invalid argument \""} + arg + std::string{"\""}, st) { }
  };

    //_______________________________________________________________________________
  // Represent an exception to be thrown when an object could not be found
  class NotFound : public BaseException {

  public:

    // Constructor given the object name, the argument and the message code
    NotFound( const std::string &objname, const std::string &arg, const MsgCode &st = MsgCode::Error ) :
      BaseException(std::string{"Unable to find "} + objname +
		    std::string{" \""} + arg + std::string{"\""}, st) { }

  };

}

#endif
<|endoftext|>


<commit_before>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <functional>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <thread>
#include <unistd.h>
#include "fnord-base/exception.h"
#include "fnord-base/inspect.h"
#include "fnord-base/thread/eventloop.h"

namespace fnord {
namespace thread {

EventLoop::EventLoop() :
    max_fd_(1),
    running_(true),
    threadid_(std::this_thread::get_id()),
    callbacks_(FD_SETSIZE + 1, nullptr) {
  FD_ZERO(&op_read_);
  FD_ZERO(&op_write_);
  FD_ZERO(&op_error_);
  setupRunQWakeupPipe();
}

EventLoop::~EventLoop() {
  close(runq_wakeup_pipe_[0]);
  close(runq_wakeup_pipe_[1]);
}

void EventLoop::setupRunQWakeupPipe() {
  if (pipe(runq_wakeup_pipe_) < 0) {
    RAISE_ERRNO(kIOError, "pipe() failed");
  }

  int flags = fcntl(runq_wakeup_pipe_[0], F_GETFL, 0);
  flags |= O_NONBLOCK;

  if (fcntl(runq_wakeup_pipe_[0], F_SETFL, flags) != 0) {
    RAISE_ERRNO(kIOError, "fnctl(%i) failed", runq_wakeup_pipe_[0]);
  }

  FD_SET(runq_wakeup_pipe_[0], &op_read_);
  if (runq_wakeup_pipe_[0] > max_fd_) {
    max_fd_ = runq_wakeup_pipe_[0];
  }

  callbacks_[runq_wakeup_pipe_[0]] = std::bind(&EventLoop::onRunQWakeup, this);
}

void EventLoop::run(std::function<void()> task) {
  if (std::this_thread::get_id() == threadid_) {
    task();
  } else {
    appendToRunQ(task);
  }
}

void EventLoop::appendToRunQ(std::function<void()> task) {
  std::unique_lock<std::mutex> lk(runq_mutex_);
  runq_.emplace_back(task);
  lk.unlock();
  wakeup();
}

void EventLoop::runOnReadable(std::function<void()> task, int fd) {
  if (std::this_thread::get_id() != threadid_) {
    appendToRunQ([this, task, fd] {
      runOnReadable(task, fd);
    });

    return;
  }

  if (fd > FD_SETSIZE) {
    RAISEF(kIOError, "fd is too large: $0, max is $1", fd, FD_SETSIZE);
  }

  if (fd > max_fd_) {
    max_fd_ = fd;
  }

  FD_SET(fd, &op_read_);
  FD_SET(fd, &op_error_);

  callbacks_[fd] = task;
}

void EventLoop::runOnWritable(std::function<void()> task, int fd) {
  if (std::this_thread::get_id() != threadid_) {
    appendToRunQ([this, task, fd] {
      runOnWritable(task, fd);
    });

    return;
  }

  if (fd > FD_SETSIZE) {
    RAISEF(kIOError, "fd is too large: $0, max is $1", fd, FD_SETSIZE);
  }

  if (fd > max_fd_) {
    max_fd_ = fd;
  }

  FD_SET(fd, &op_write_);
  FD_SET(fd, &op_error_);

  callbacks_[fd] = task;
}

void EventLoop::poll() {
  fd_set op_read, op_write, op_error;

  memcpy(&op_read, &op_read_, sizeof(fd_set));
  memcpy(&op_write, &op_write_, sizeof(fd_set));
  memcpy(&op_error, &op_error_, sizeof(fd_set));

  int res = select(max_fd_ + 1, &op_read, &op_write, &op_error, NULL);

  if (res == 0) {
    return;
  }

  if (res == -1) {
    if (errno == EINTR) {
      return;
    }

    RAISE_ERRNO(kIOError, "select() failed");
  }

  for (int fd = 0; fd <= max_fd_; fd++) {
    if (FD_ISSET(fd, &op_read)) {
      FD_CLR(fd, &op_read_);
      FD_CLR(fd, &op_error_);
      callbacks_[fd]();
    }

    else if (FD_ISSET(fd, &op_write)) {
      FD_CLR(fd, &op_write_);
      FD_CLR(fd, &op_error_);
      callbacks_[fd]();
    }
  }
}

void EventLoop::wakeup() {
  write(runq_wakeup_pipe_[1], "\x0", 1);
}

void EventLoop::runOnWakeup(
    std::function<void()> task,
    Wakeup* wakeup,
    long wakeup_generation) {
  wakeup->onWakeup(wakeup_generation, [this, task] {
    this->run(task);
  });
}

void EventLoop::onRunQWakeup() {
  FD_SET(runq_wakeup_pipe_[0], &op_read_);

  static char devnull[512];
  while (read(runq_wakeup_pipe_[0], devnull, sizeof(devnull)) > 0);

  std::list<std::function<void()>> tasks;

  std::unique_lock<std::mutex> lk(runq_mutex_);
  tasks.splice(tasks.begin(), runq_);
  lk.unlock();

  for (const auto& task : tasks) {
    task();
  }
}

void EventLoop::run() {
  threadid_ = std::this_thread::get_id();

  while (running_.load()) {
    poll();
  }
}

void EventLoop::shutdown() {
  running_ = false;
  wakeup();
}

}
}
<commit_msg>ugly ugly hack<commit_after>/**
 * This file is part of the "FnordMetric" project
 *   Copyright (c) 2014 Paul Asmuth, Google Inc.
 *
 * FnordMetric is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License v3.0. You should have received a
 * copy of the GNU General Public License along with this program. If not, see
 * <http://www.gnu.org/licenses/>.
 */
#include <functional>
#include <stdlib.h>
#include <stdio.h>
#include <assert.h>
#include <string.h>
#include <thread>
#include <unistd.h>
#include "fnord-base/exception.h"
#include "fnord-base/inspect.h"
#include "fnord-base/thread/eventloop.h"

namespace fnord {
namespace thread {

EventLoop::EventLoop() :
    max_fd_(1),
    running_(true),
    threadid_(std::this_thread::get_id()),
    callbacks_(FD_SETSIZE + 1, nullptr) {
  FD_ZERO(&op_read_);
  FD_ZERO(&op_write_);
  FD_ZERO(&op_error_);
  setupRunQWakeupPipe();
}

EventLoop::~EventLoop() {
  close(runq_wakeup_pipe_[0]);
  close(runq_wakeup_pipe_[1]);
}

void EventLoop::setupRunQWakeupPipe() {
  if (pipe(runq_wakeup_pipe_) < 0) {
    RAISE_ERRNO(kIOError, "pipe() failed");
  }

  int flags = fcntl(runq_wakeup_pipe_[0], F_GETFL, 0);
  flags |= O_NONBLOCK;

  if (fcntl(runq_wakeup_pipe_[0], F_SETFL, flags) != 0) {
    RAISE_ERRNO(kIOError, "fnctl(%i) failed", runq_wakeup_pipe_[0]);
  }

  FD_SET(runq_wakeup_pipe_[0], &op_read_);
  if (runq_wakeup_pipe_[0] > max_fd_) {
    max_fd_ = runq_wakeup_pipe_[0];
  }

  callbacks_[runq_wakeup_pipe_[0]] = std::bind(&EventLoop::onRunQWakeup, this);
}

void EventLoop::run(std::function<void()> task) {
  if (std::this_thread::get_id() == threadid_) {
    task();
  } else {
    appendToRunQ(task);
  }
}

void EventLoop::appendToRunQ(std::function<void()> task) {
  std::unique_lock<std::mutex> lk(runq_mutex_);
  runq_.emplace_back(task);
  lk.unlock();
  wakeup();
}

void EventLoop::runOnReadable(std::function<void()> task, int fd) {
  if (std::this_thread::get_id() != threadid_) {
    appendToRunQ([this, task, fd] {
      runOnReadable(task, fd);
    });

    return;
  }

  if (fd > FD_SETSIZE) {
    RAISEF(kIOError, "fd is too large: $0, max is $1", fd, FD_SETSIZE);
  }

  if (fd > max_fd_) {
    max_fd_ = fd;
  }

  FD_SET(fd, &op_read_);
  FD_SET(fd, &op_error_);

  callbacks_[fd] = task;
}

void EventLoop::runOnWritable(std::function<void()> task, int fd) {
  if (std::this_thread::get_id() != threadid_) {
    appendToRunQ([this, task, fd] {
      runOnWritable(task, fd);
    });

    return;
  }

  if (fd > FD_SETSIZE) {
    RAISEF(kIOError, "fd is too large: $0, max is $1", fd, FD_SETSIZE);
  }

  if (fd > max_fd_) {
    max_fd_ = fd;
  }

  FD_SET(fd, &op_write_);
  FD_SET(fd, &op_error_);

  callbacks_[fd] = task;
}

void EventLoop::poll() {
  fd_set op_read, op_write, op_error;

  memcpy(&op_read, &op_read_, sizeof(fd_set));
  memcpy(&op_write, &op_write_, sizeof(fd_set));
  memcpy(&op_error, &op_error_, sizeof(fd_set));

  int res = select(max_fd_ + 1, &op_read, &op_write, &op_error, NULL);

  if (res == 0) {
    return;
  }

  if (res == -1) {
    if (errno == EINTR) {
      return;
    }

    RAISE_ERRNO(kIOError, "select() failed");
  }

  for (int fd = 0; fd <= max_fd_; fd++) {
    if (FD_ISSET(fd, &op_read)) {
      FD_CLR(fd, &op_read_);
      FD_CLR(fd, &op_error_);
      callbacks_[fd]();
    }

    else if (FD_ISSET(fd, &op_write)) {
      FD_CLR(fd, &op_write_);
      FD_CLR(fd, &op_error_);
      callbacks_[fd]();
    }
  }
}

void EventLoop::wakeup() {
  write(runq_wakeup_pipe_[1], "\x0", 1);
}

void EventLoop::runOnWakeup(
    std::function<void()> task,
    Wakeup* wakeup,
    long wakeup_generation) {
  wakeup->onWakeup(wakeup_generation, [this, task] {
    this->run(task);
  });
}

void EventLoop::onRunQWakeup() {
  FD_SET(runq_wakeup_pipe_[0], &op_read_);

  static char devnull[512];
  while (read(runq_wakeup_pipe_[0], devnull, sizeof(devnull)) > 0);

  std::list<std::function<void()>> tasks;

  std::unique_lock<std::mutex> lk(runq_mutex_);
  tasks.splice(tasks.begin(), runq_);
  lk.unlock();

  for (const auto& task : tasks) {
    task();
  }
}

void EventLoop::run() {
  threadid_ = std::this_thread::get_id();

  while (running_.load()) {
    poll();
  }
}

void EventLoop::shutdown() {
  usleep(10000); // FIXPAUL hack!!!!
  running_ = false;
  wakeup();
}

}
}
<|endoftext|>


<commit_before>/*
 * EMULAB-COPYRIGHT
 * Copyright (c) 2006 University of Utah and the Flux Group.
 * All rights reserved.
 */

#include "UdpMaxDelaySensor.h"
#include "CommandOutput.h"

using namespace std;

UdpMaxDelaySensor::UdpMaxDelaySensor(UdpPacketSensor const *udpPacketSensorVal, UdpMinDelaySensor const *minDelaySensorVal, UdpLossSensor const *lossSensorVal)
	: maxDelay(0),sentDelay(0),
	packetHistory(udpPacketSensorVal),
	minDelaySensor(minDelaySensorVal),
	lossSensor(lossSensorVal)
{

}

UdpMaxDelaySensor::~UdpMaxDelaySensor()
{

}

void UdpMaxDelaySensor::localSend(PacketInfo *packet)
{

}

void UdpMaxDelaySensor::localAck(PacketInfo *packet)
{
	 // This is a re-ordered ACK or a corrupted packet - don't do anything
	// with it - just return.
	// If this packet is ACKing a packet that we lost due to libpcap send loss,
	// dont use this packet timestamp for RTT calculations.
	if( packetHistory->isAckValid() == false || packetHistory->isAckFake() == true)
		return;

        unsigned short int seqNum = *(unsigned short int *)(packet->payload + 1);
        unsigned long long oneWayQueueDelay;

	vector<UdpPacketInfo>::iterator vecIterator;
	vector<UdpPacketInfo> ackedPackets = packetHistory->getAckedPackets();
        vecIterator = find_if(ackedPackets.begin(), ackedPackets.end(), bind2nd(equalSeqNum(), seqNum));

	if(vecIterator == ackedPackets.end())
	{
		logWrite(ERROR,"UdpMaxDelay: Cannot find seqNum=%d in AckedPacketList", seqNum);
		return;
	}

	unsigned long long timeStamp = packet->packetTime.toMicroseconds();

	// Find the one way RTT for this packet.
	oneWayQueueDelay = (timeStamp - (*vecIterator).timeStamp)/2;

	// Scale the value of one way RTT, so that it is correct for a transmission
	// size of 1518 bytes.

	// We lost this packet size details due to loss in libpcap, use the
	// size echoed in the ACK packet - this does not included the header
	// overhead for the packet - we assume that the packet on the reverse path
	// has the same overhead length as the original packet.
	oneWayQueueDelay = ( oneWayQueueDelay )*1518 / ((*vecIterator).packetSize);

	if(oneWayQueueDelay < minDelaySensor->getMinDelay())
	{
		logWrite(ERROR,"Incorrect oneWayQueueDelay value = %llu, minDelay = %llu, seqNum=%d, SENDTS=%llu,RECVTS=%llu", oneWayQueueDelay, minDelaySensor->getMinDelay(),seqNum, (*vecIterator).timeStamp, timeStamp);
		return;

	}
	// Find the queuing delay for this packet, by subtracting the
	// one way minimum delay from the above value.
	oneWayQueueDelay = oneWayQueueDelay - minDelaySensor->getMinDelay();

	if(oneWayQueueDelay > 90000000)
	{
		logWrite(ERROR,"Incorrect oneWayQueueDelay value = %llu, minDelay = %llu, seqNum=%d, SENDTS=%llu,RECVTS=%llu", oneWayQueueDelay, minDelaySensor->getMinDelay(),seqNum, (*vecIterator).timeStamp, timeStamp);
		return;
	}

        // Set this as the new maximum one way queuing delay.
        if(oneWayQueueDelay > maxDelay)
                maxDelay = oneWayQueueDelay;

        // Send an event message to the monitor to change the value of maximum one way delay.
	if(lossSensor->getPacketLoss() > 0)
        {
		// Report the maximum delay
		ostringstream messageBuffer;
		if(maxDelay > sentDelay)
		{
			messageBuffer<<"MAXINQ="<<(maxDelay+minDelaySensor->getMinDelay())/1000;
			global::output->eventMessage(messageBuffer.str(), packet->elab);
			sentDelay = maxDelay;
		}

		logWrite(SENSOR,"VALUE::New Max Delay = %llu",maxDelay);
        }
	logWrite(SENSOR,"MAXD:TIME=%llu,MAXD=%llu",timeStamp,maxDelay);
	logWrite(SENSOR,"ACTUAL_MAXD:TIME=%llu,ACTUAL_MAXD=%llu",timeStamp,oneWayQueueDelay);

}
<commit_msg>A little tweak for the better - removed scaling of max delay values (which used to depend on packet size).<commit_after>/*
 * EMULAB-COPYRIGHT
 * Copyright (c) 2006 University of Utah and the Flux Group.
 * All rights reserved.
 */

#include "UdpMaxDelaySensor.h"
#include "CommandOutput.h"

using namespace std;

UdpMaxDelaySensor::UdpMaxDelaySensor(UdpPacketSensor const *udpPacketSensorVal, UdpMinDelaySensor const *minDelaySensorVal, UdpLossSensor const *lossSensorVal)
: maxDelay(0),sentDelay(0),
    packetHistory(udpPacketSensorVal),
    minDelaySensor(minDelaySensorVal),
    lossSensor(lossSensorVal)
{

}

UdpMaxDelaySensor::~UdpMaxDelaySensor()
{

}

void UdpMaxDelaySensor::localSend(PacketInfo *packet)
{

}

void UdpMaxDelaySensor::localAck(PacketInfo *packet)
{
    // This is a re-ordered ACK or a corrupted packet - don't do anything
    // with it - just return.
    // If this packet is ACKing a packet that we lost due to libpcap send loss,
    // dont use this packet timestamp for RTT calculations.
    if( packetHistory->isAckValid() == false || packetHistory->isAckFake() == true)
        return;

    unsigned short int seqNum = *(unsigned short int *)(packet->payload + 1);
    unsigned long long oneWayQueueDelay;

    vector<UdpPacketInfo>::iterator vecIterator;
    vector<UdpPacketInfo> ackedPackets = packetHistory->getAckedPackets();
    vecIterator = find_if(ackedPackets.begin(), ackedPackets.end(), bind2nd(equalSeqNum(), seqNum));

    if(vecIterator == ackedPackets.end())
    {
        logWrite(ERROR,"UdpMaxDelay: Cannot find seqNum=%d in AckedPacketList", seqNum);
        return;
    }

    unsigned long long timeStamp = packet->packetTime.toMicroseconds();

    // Find the one way RTT for this packet.
    oneWayQueueDelay = (timeStamp - (*vecIterator).timeStamp)/2;

    // Scale the value of one way RTT, so that it is correct for a transmission
    // size of 1518 bytes.

    // We lost this packet size details due to loss in libpcap, use the
    // size echoed in the ACK packet - this does not included the header
    // overhead for the packet - we assume that the packet on the reverse path
    // has the same overhead length as the original packet.
    //oneWayQueueDelay = ( oneWayQueueDelay )*1518 / ((*vecIterator).packetSize);
    // NOTE: Do not scale the queuing delay - the results are bad for small
    // packet transmissions.

    //if(oneWayQueueDelay < minDelaySensor->getMinDelay())
    //{
    //	logWrite(ERROR,"Incorrect oneWayQueueDelay value = %llu, minDelay = %llu, seqNum=%d, SENDTS=%llu,RECVTS=%llu", oneWayQueueDelay, minDelaySensor->getMinDelay(),seqNum, (*vecIterator).timeStamp, timeStamp);
    //	return;

    //}
    // Find the queuing delay for this packet, by subtracting the
    // one way minimum delay from the above value.
    if(oneWayQueueDelay > minDelaySensor->getMinDelay())
        oneWayQueueDelay = oneWayQueueDelay - minDelaySensor->getMinDelay();
    else
        oneWayQueueDelay = 0;

    if(oneWayQueueDelay > 90000000)
    {
        logWrite(ERROR,"Incorrect oneWayQueueDelay value = %llu, minDelay = %llu, seqNum=%d, SENDTS=%llu,RECVTS=%llu", oneWayQueueDelay, minDelaySensor->getMinDelay(),seqNum, (*vecIterator).timeStamp, timeStamp);
        return;
    }

    // Set this as the new maximum one way queuing delay.
    if(oneWayQueueDelay > maxDelay)
        maxDelay = oneWayQueueDelay;

    // Send an event message to the monitor to change the value of maximum one way delay.
    if(lossSensor->getPacketLoss() > 0)
    {
        // Report the maximum delay
        ostringstream messageBuffer;
        if(maxDelay > sentDelay)
        {
            messageBuffer<<"MAXINQ="<<(maxDelay+minDelaySensor->getMinDelay())/1000;
            global::output->eventMessage(messageBuffer.str(), packet->elab);
            sentDelay = maxDelay;
        }

        logWrite(SENSOR,"VALUE::New Max Delay = %llu",maxDelay);
    }
    logWrite(SENSOR,"MAXD:TIME=%llu,MAXD=%llu",timeStamp,maxDelay);
    logWrite(SENSOR,"ACTUAL_MAXD:TIME=%llu,ACTUAL_MAXD=%llu",timeStamp,oneWayQueueDelay);

}
<|endoftext|>


<commit_before>/** Copyright (C) 2016, 2017 European Spallation Source ERIC */

#include <cassert>
#include <common/Detector.h>
#include <common/EFUArgs.h>
#include <common/Trace.h>
#include <efu/Launcher.h>
#include <iostream>
#include <thread>
#include <map>

void Launcher::launchThreads(std::shared_ptr<Detector> &detector) {
  auto startThreadsWithoutAffinity = [&detector]() {
    XTRACE(MAIN, ALW, "Launching threads without core affinity.\n");
    for (auto &ThreadInfo : detector->GetThreadInfo()) {
      XTRACE(MAIN, ALW, "Creating new thread (id: %s)\n", ThreadInfo.name.c_str());
      ThreadInfo.thread = std::thread(ThreadInfo.func);
    }
  };

  auto setThreadCoreAffinity = [](std::thread &thread, std::uint16_t core) {
#ifdef __linux__
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core, &cpuset);
    XTRACE(MAIN, ALW, "Setting thread affinity to core %d\n", core);
    GLOG_INF("Setting thread affinity to core " + std::to_string(core));

      int __attribute__((unused))s = pthread_setaffinity_np(thread.native_handle(), sizeof(cpu_set_t), &cpuset);
      assert(s == 0);
    }
#else
#pragma message("setaffinity only implemented for Linux")
    GLOG_WAR("setaffinity only implemented for Linux");
#endif
  };

  std::map<std::string,std::uint16_t> AffinityMap;
  for (auto &Affinity : ThreadCoreAffinity) {
    AffinityMap[Affinity.Name] = Affinity.Core;
  }
  if (0 == ThreadCoreAffinity.size()) {
    startThreadsWithoutAffinity();
  } else if (1 == ThreadCoreAffinity.size() and ThreadCoreAffinity[0].Name == "implicit_affinity") {
    XTRACE(MAIN, ALW, "Launching threads with implicit core affinity.\n");
    int CoreCounter = ThreadCoreAffinity[0].Core;
    for (auto &ThreadInfo : detector->GetThreadInfo()) {
      XTRACE(MAIN, ALW, "Creating new thread (id: %s)\n", ThreadInfo.name.c_str());
      ThreadInfo.thread = std::thread(ThreadInfo.func);
      setThreadCoreAffinity(ThreadInfo.thread, CoreCounter++);
    }
  } else {
    XTRACE(MAIN, ALW, "Launching threads with explicit core affinity.\n");
    for (auto &ThreadInfo : detector->GetThreadInfo()) {
      XTRACE(MAIN, ALW, "Creating new thread (id: %s)\n", ThreadInfo.name.c_str());
      ThreadInfo.thread = std::thread(ThreadInfo.func);
      if (1 == AffinityMap.count(ThreadInfo.name)) {
        setThreadCoreAffinity(ThreadInfo.thread, AffinityMap[ThreadInfo.name]);
      }
    }
  }
}
<commit_msg>Improved the error messages.<commit_after>/** Copyright (C) 2016, 2017 European Spallation Source ERIC */

#include <cassert>
#include <common/Detector.h>
#include <common/EFUArgs.h>
#include <common/Trace.h>
#include <efu/Launcher.h>
#include <iostream>
#include <thread>
#include <map>

void Launcher::launchThreads(std::shared_ptr<Detector> &detector) {
  auto startThreadsWithoutAffinity = [&detector]() {
    XTRACE(MAIN, ALW, "Launching threads without core affinity.\n");
    for (auto &ThreadInfo : detector->GetThreadInfo()) {
      XTRACE(MAIN, ALW, "Creating new thread (id: %s)\n", ThreadInfo.name.c_str());
      ThreadInfo.thread = std::thread(ThreadInfo.func);
    }
  };

  auto setThreadCoreAffinity = [](std::thread &thread, std::uint16_t core) {
#ifdef __linux__
    cpu_set_t cpuset;
    CPU_ZERO(&cpuset);
    CPU_SET(core, &cpuset);
    XTRACE(MAIN, ALW, "Setting thread affinity to core %d\n", core);
    GLOG_INF("Setting thread affinity to core " + std::to_string(core));

      int __attribute__((unused))s = pthread_setaffinity_np(thread.native_handle(), sizeof(cpu_set_t), &cpuset);
      assert(s == 0);
    }
#else
#pragma message("setaffinity only implemented for Linux")
    GLOG_WAR("setaffinity only implemented for Linux");
#endif
  };

  std::map<std::string,std::uint16_t> AffinityMap;
  for (auto &Affinity : ThreadCoreAffinity) {
    AffinityMap[Affinity.Name] = Affinity.Core;
  }
  if (0 == ThreadCoreAffinity.size()) {
    startThreadsWithoutAffinity();
  } else if (1 == ThreadCoreAffinity.size() and ThreadCoreAffinity[0].Name == "implicit_affinity") {
    XTRACE(MAIN, ALW, "Launching threads with implicit core affinity.\n");
    int CoreCounter = ThreadCoreAffinity[0].Core;
    for (auto &ThreadInfo : detector->GetThreadInfo()) {
      XTRACE(MAIN, ALW, "Creating new thread (id: %s)\n", ThreadInfo.name.c_str());
      ThreadInfo.thread = std::thread(ThreadInfo.func);
      setThreadCoreAffinity(ThreadInfo.thread, CoreCounter++);
    }
  } else {
    XTRACE(MAIN, ALW, "Launching threads with explicit core affinity.\n");
    for (auto &ThreadInfo : detector->GetThreadInfo()) {
      XTRACE(MAIN, ALW, "Creating new thread (id: %s)\n", ThreadInfo.name.c_str());
      ThreadInfo.thread = std::thread(ThreadInfo.func);
      if (1 == AffinityMap.count(ThreadInfo.name)) {
        setThreadCoreAffinity(ThreadInfo.thread, AffinityMap[ThreadInfo.name]);
      } else {
        XTRACE(MAIN, ALW, "No thread core affinity information available for thread with id: %s\n", ThreadInfo.name.c_str());
      }
    }
  }
}
<|endoftext|>


<commit_before><commit_msg>Localization: Unsigned value cannot be negative.<commit_after><|endoftext|>


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

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkTestingMacros.h"
#include <mitkTestingConfig.h>
#include <mitkTestFixture.h>

#include <mitkIOUtil.h>
#include <mitkInteractionTestHelper.h>
#include <mitkPointSet.h>
#include <mitkPointSetDataInteractor.h>

class mitkPointSetDataInteractorTestSuite : public mitk::TestFixture
{

  CPPUNIT_TEST_SUITE(mitkPointSetDataInteractorTestSuite);
  MITK_TEST(AddPointInteraction);
  MITK_TEST(DeletePointInteraction);
  CPPUNIT_TEST_SUITE_END();

private:
  mitk::DataNode::Pointer m_TestPointSetNode;
  mitk::PointSetDataInteractor::Pointer m_DataInteractor;
  mitk::PointSet::Pointer m_TestPointSet;

public:

  void setUp()
  {
    //Create DataNode as a container for our PointSet to be tested
    m_TestPointSetNode = mitk::DataNode::New();

    // Create PointSetData Interactor
    m_DataInteractor = mitk::PointSetDataInteractor::New();
    // Load the according state machine for regular point set interaction
    m_DataInteractor->LoadStateMachine("PointSet.xml");
    // Set the configuration file that defines the triggers for the transitions
    m_DataInteractor->SetEventConfig("PointSetConfig.xml");

    //Create new PointSet which will receive the interaction input
    m_TestPointSet = mitk::PointSet::New();
    m_TestPointSetNode->SetData(m_TestPointSet);
    // set the DataNode (which already is added to the DataStorage)
    m_DataInteractor->SetDataNode(m_TestPointSetNode);
  }

  void tearDown()
  {
    //destroy all objects
    m_TestPointSetNode = NULL;
    m_TestPointSet = NULL;
    m_DataInteractor = NULL;
  }

  void AddPointInteraction()
  {
    //Path to the reference PointSet
    std::string referencePointSetPath = GetTestDataFilePath("InteractionTestData/ReferenceData/PointSetDataInteractor_add_points_in_2D_ref.mps");

    //Path to the interaction xml file
    std::string interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/PointSetDataInteractor_add_points_in_2D.xml");

    //Create test helper to initialize all necessary objects for interaction
    mitk::InteractionTestHelper interactionTestHelper(interactionXmlPath);

    //Add our test node to the DataStorage of our test helper
    interactionTestHelper.AddNodeToStorage(m_TestPointSetNode);

    //Start Interaction
    interactionTestHelper.PlaybackInteraction();

    //Load the reference PointSet
    mitk::PointSet::Pointer referencePointSet = mitk::IOUtil::LoadPointSet(referencePointSetPath);

    //Compare reference with the result of the interaction
    MITK_ASSERT_EQUAL(m_TestPointSet, referencePointSet, "");
  }

  void PlayInteraction( std::string &xmlFile, mitk::DataNode* node )
  {
    mitk::InteractionTestHelper interactionTestHelper( xmlFile );
    interactionTestHelper.AddNodeToStorage( node );
    interactionTestHelper.PlaybackInteraction();
  }

  void EvaluateState( std::string &refPsFile, mitk::PointSet::Pointer ps, int selected )
  {
    mitk::PointSet::Pointer refPs = mitk::IOUtil::LoadPointSet( refPsFile );

    MITK_ASSERT_EQUAL(ps, refPs, "");

    MITK_TEST_CONDITION_REQUIRED(ps->GetNumberOfSelected() == 1, "One selected point." );
    MITK_TEST_CONDITION_REQUIRED(ps->GetSelectInfo( selected ) , "Testing if point is selected." );
  }

  void SetupInteractor( mitk::PointSetDataInteractor* dataInteractor, mitk::DataNode* node )
  {
    dataInteractor->LoadStateMachine("PointSet.xml");
    dataInteractor->SetEventConfig("PointSetConfig.xml");
    dataInteractor->SetDataNode( node );
  }

  void DeletePointInteraction()
  {
    mitk::PointSetDataInteractor::Pointer dataInteractor = mitk::PointSetDataInteractor::New();
    mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New();

    //Path to the reference PointSet
    std::string referencePointSetPath = GetTestDataFilePath("InteractionTestData/InitPointSet.mps");
    mitk::PointSet::Pointer ps = mitk::IOUtil::LoadPointSet( referencePointSetPath );
    pointSetNode->SetData( ps );

    this->SetupInteractor( dataInteractor, pointSetNode );

    std::string interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-0_1.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet-0.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-1_3.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet-1.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-2_4.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet-2.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-3_8.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet-3.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-4_2.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet-4.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-5_6.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet-5.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-6_7.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet-6.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-7_5.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet1.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );

    MITK_TEST_CONDITION_REQUIRED(ps->GetPointSet()->GetNumberOfPoints() == 0, "Empty point set check.");
    MITK_TEST_CONDITION_REQUIRED(ps->GetNumberOfSelected() == 0, "No selected points." );
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkPointSetDataInteractor)
<commit_msg>Geometries for TestPointSet and ReferencePointSet have to be updated before comparison.<commit_after>/*===================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center,
Division of Medical and Biological Informatics.
All rights reserved.

This software is distributed WITHOUT ANY WARRANTY; without
even the implied warranty of MERCHANTABILITY or FITNESS FOR
A PARTICULAR PURPOSE.

See LICENSE.txt or http://www.mitk.org for details.

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

#include "mitkTestingMacros.h"
#include <mitkTestingConfig.h>
#include <mitkTestFixture.h>

#include <mitkIOUtil.h>
#include <mitkInteractionTestHelper.h>
#include <mitkPointSet.h>
#include <mitkPointSetDataInteractor.h>

class mitkPointSetDataInteractorTestSuite : public mitk::TestFixture
{

  CPPUNIT_TEST_SUITE(mitkPointSetDataInteractorTestSuite);
  MITK_TEST(AddPointInteraction);
  MITK_TEST(DeletePointInteraction);
  CPPUNIT_TEST_SUITE_END();

private:
  mitk::DataNode::Pointer m_TestPointSetNode;
  mitk::PointSetDataInteractor::Pointer m_DataInteractor;
  mitk::PointSet::Pointer m_TestPointSet;

public:

  void setUp()
  {
    //Create DataNode as a container for our PointSet to be tested
    m_TestPointSetNode = mitk::DataNode::New();

    // Create PointSetData Interactor
    m_DataInteractor = mitk::PointSetDataInteractor::New();
    // Load the according state machine for regular point set interaction
    m_DataInteractor->LoadStateMachine("PointSet.xml");
    // Set the configuration file that defines the triggers for the transitions
    m_DataInteractor->SetEventConfig("PointSetConfig.xml");

    //Create new PointSet which will receive the interaction input
    m_TestPointSet = mitk::PointSet::New();
    m_TestPointSetNode->SetData(m_TestPointSet);
    // set the DataNode (which already is added to the DataStorage)
    m_DataInteractor->SetDataNode(m_TestPointSetNode);
  }

  void tearDown()
  {
    //destroy all objects
    m_TestPointSetNode = NULL;
    m_TestPointSet = NULL;
    m_DataInteractor = NULL;
  }

  void AddPointInteraction()
  {
    //Path to the reference PointSet
    std::string referencePointSetPath = GetTestDataFilePath("InteractionTestData/ReferenceData/PointSetDataInteractor_add_points_in_2D_ref.mps");

    //Path to the interaction xml file
    std::string interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/PointSetDataInteractor_add_points_in_2D.xml");

    //Create test helper to initialize all necessary objects for interaction
    mitk::InteractionTestHelper interactionTestHelper(interactionXmlPath);

    //Add our test node to the DataStorage of our test helper
    interactionTestHelper.AddNodeToStorage(m_TestPointSetNode);

    //Start Interaction
    interactionTestHelper.PlaybackInteraction();

    //Load the reference PointSet
    mitk::PointSet::Pointer referencePointSet = mitk::IOUtil::LoadPointSet(referencePointSetPath);

    //Compare reference with the result of the interaction
    MITK_ASSERT_EQUAL(m_TestPointSet, referencePointSet, "");
  }

  void PlayInteraction( std::string &xmlFile, mitk::DataNode* node )
  {
    mitk::InteractionTestHelper interactionTestHelper( xmlFile );
    interactionTestHelper.AddNodeToStorage( node );
    interactionTestHelper.PlaybackInteraction();
  }

  void EvaluateState( std::string &refPsFile, mitk::PointSet::Pointer ps, int selected )
  {
    mitk::PointSet::Pointer refPs = mitk::IOUtil::LoadPointSet( refPsFile );
    refPs->UpdateOutputInformation();
    ps->UpdateOutputInformation();

    MITK_ASSERT_EQUAL(ps, refPs, "");

    MITK_TEST_CONDITION_REQUIRED(true, "Test against reference point set." );
    MITK_TEST_CONDITION_REQUIRED(ps->GetNumberOfSelected() == 1, "One selected point." );
    MITK_TEST_CONDITION_REQUIRED(ps->GetSelectInfo( selected ) , "Testing if proper point is selected." );
  }

  void SetupInteractor( mitk::PointSetDataInteractor* dataInteractor, mitk::DataNode* node )
  {
    dataInteractor->LoadStateMachine("PointSet.xml");
    dataInteractor->SetEventConfig("PointSetConfig.xml");
    dataInteractor->SetDataNode( node );
  }

  void DeletePointInteraction()
  {
    mitk::PointSetDataInteractor::Pointer dataInteractor = mitk::PointSetDataInteractor::New();
    mitk::DataNode::Pointer pointSetNode = mitk::DataNode::New();

    //Path to the reference PointSet
    std::string referencePointSetPath = GetTestDataFilePath("InteractionTestData/InitPointSet.mps");
    mitk::PointSet::Pointer ps = mitk::IOUtil::LoadPointSet( referencePointSetPath );
    pointSetNode->SetData( ps );

    this->SetupInteractor( dataInteractor, pointSetNode );

    std::string interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-0_1.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/refPointSet-0.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-1_3.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/refPointSet-1.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-2_4.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/refPointSet-2.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-3_8.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/refPointSet-3.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 1 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-4_2.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/refPointSet-4.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-5_6.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/refPointSet-5.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-6_7.xml");
    referencePointSetPath = GetTestDataFilePath("InteractionTestData/refPointSet-6.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );
    EvaluateState( referencePointSetPath, ps, 4 );

    interactionXmlPath = GetTestDataFilePath("InteractionTestData/Interactions/testInteractionDel-7_5.xml");
    //referencePointSetPath = GetTestDataFilePath("InteractionTestData/PointSet1.mps");
    PlayInteraction( interactionXmlPath, pointSetNode );

    MITK_TEST_CONDITION_REQUIRED(ps->GetPointSet()->GetNumberOfPoints() == 0, "Empty point set check.");
    MITK_TEST_CONDITION_REQUIRED(ps->GetNumberOfSelected() == 0, "No selected points." );
  }

};

MITK_TEST_SUITE_REGISTRATION(mitkPointSetDataInteractor)
<|endoftext|>


<commit_before>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

//  Software Guide : BeginLatex
//
//  This example introduces the use of the
//  \doxygen{CannyEdgeDetectionImageFilter}. This filter is widely used for
//  edge detection since it is the optimal solution satisfying the constraints
//  of good sensitivity, localization and noise robustness.
//
//  \index{itk::CannyEdgeDetectionImageFilter|textbf}
//
//  Software Guide : EndLatex

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkCastImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"

//  Software Guide : BeginLatex
//
//  The first step required for using this filter is to include its header file.
//
//  \index{itk::CannyEdgeDetectionImageFilter!header}
//
//  Software Guide : EndLatex

// Software Guide : BeginCodeSnippet
#include "itkCannyEdgeDetectionImageFilter.h"
// Software Guide : EndCodeSnippet

int main(int argc, char* argv[])
{
  if( argc < 3 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0] << " inputImage outputImage [variance upperThreshold lowerThreshold]" << std::endl;
    return EXIT_FAILURE;
    }

  const char * inputFilename  = argv[1];
  const char * outputFilename = argv[2];
  float variance = 2.0;
  float upperThreshold = 0.0;
  float lowerThreshold = 0.0;

  if( argc > 3 )
    {
    variance = atof( argv[3] );
    }

  if( argc > 4 )
    {
    upperThreshold = atof( argv[4] );
    }

  if( argc > 5 )
    {
    lowerThreshold = atof( argv[5] );
    }

  std::cout << "Variance = " << variance << std::endl;
  std::cout << "UpperThreshold = " << upperThreshold << std::endl;
  std::cout << "LowerThreshold = " << lowerThreshold << std::endl;

  typedef unsigned char    CharPixelType;  //  IO
  typedef double           RealPixelType;  //  Operations
  const   unsigned int     Dimension = 2;

  typedef itk::Image<CharPixelType, Dimension>    CharImageType;
  typedef itk::Image<RealPixelType, Dimension>    RealImageType;

  typedef itk::ImageFileReader< CharImageType >  ReaderType;
  typedef itk::ImageFileWriter< CharImageType >  WriterType;

  //  Software Guide : BeginLatex
  //
  //  This filter operates on images of pixel type \code{float}. It is then
  //  necessary to cast the type of the input images which are usually of
  //  integer type. The \doxygen{CastImageFilter} is used here for this purpose.
  //  Its image template parameters are defined for casting from the input type
  //  to the \code{float} type used for processing.
  //
  //  Software Guide : EndLatex

  // Software Guide : BeginCodeSnippet
  typedef itk::CastImageFilter< CharImageType, RealImageType>
                                                         CastToRealFilterType;
  // Software Guide : EndCodeSnippet

  typedef itk::RescaleIntensityImageFilter<RealImageType, CharImageType > RescaleFilter;

  //  Software Guide : BeginLatex
  //
  //  The \doxygen{CannyEdgeDetectionImageFilter} is instantiated using the
  //  \code{float} image type.
  //
  //  \index{itk::CannyEdgeDetectionImageFilter|textbf}
  //
  //  Software Guide : EndLatex

  typedef itk::CannyEdgeDetectionImageFilter<RealImageType, RealImageType> CannyFilter;

  //Setting the IO

  ReaderType::Pointer reader = ReaderType::New();
  WriterType::Pointer writer = WriterType::New();

  CastToRealFilterType::Pointer toReal = CastToRealFilterType::New();
  RescaleFilter::Pointer rescale = RescaleFilter::New();

  //Setting the ITK pipeline filter

  CannyFilter::Pointer cannyFilter = CannyFilter::New();

  reader->SetFileName( inputFilename  );
  writer->SetFileName( outputFilename );

  //The output of an edge filter is 0 or 1
  rescale->SetOutputMinimum(   0 );
  rescale->SetOutputMaximum( 255 );

  toReal->SetInput( reader->GetOutput() );

  cannyFilter->SetInput( toReal->GetOutput() );
  cannyFilter->SetVariance( variance );
  cannyFilter->SetUpperThreshold( upperThreshold );
  cannyFilter->SetLowerThreshold( lowerThreshold );

  rescale->SetInput( cannyFilter->GetOutput() );
  writer->SetInput( rescale->GetOutput() );

  try
    {
    writer->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
    return EXIT_FAILURE;
    }

  return EXIT_SUCCESS;

}
<commit_msg>DOC: Expanded Canny Edge Detection Example<commit_after>/*=========================================================================
 *
 *  Copyright Insight Software Consortium
 *
 *  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.txt
 *
 *  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.
 *
 *=========================================================================*/

//  Software Guide : BeginLatex
//
//  This example introduces the use of the
//  \doxygen{CannyEdgeDetectionImageFilter}. Canny edge detection is widely used for
//  edge detection since it is the optimal solution satisfying the constraints
//  of good sensitivity, localization and noise robustness.  To achieve this
//  end, Canny edge detection is implemented internally as a multi-stage
//  algorithm, which involves Gaussian smoothing to remove noise, calculation
//  of gradient magnitudes to localize edge features, non-maximum suppression
//  to remove suprious features, and finally thresholding to yield a binary image.
//  Though the specifics of this internal pipeline are largely abstracted from
//  the user of the class, it is nonetheless beneficial to have a general
//  understanding of these components so that parameters can be appropriately
//  adjusted.
//
//  \index{itk::CannyEdgeDetectionImageFilter|textbf}
//
//  The first step required for using this filter is to include its header file.
//
//  \index{itk::CannyEdgeDetectionImageFilter!header}
//
//  Software Guide : EndLatex

#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkCastImageFilter.h"
#include "itkRescaleIntensityImageFilter.h"

// Software Guide : BeginCodeSnippet
#include "itkCannyEdgeDetectionImageFilter.h"
// Software Guide : EndCodeSnippet

int main(int argc, char* argv[])
{

  if( argc < 3 )
    {
    std::cerr << "Usage: " << std::endl;
    std::cerr << argv[0]
              << " inputImage outputImage"
              << " [variance upperThreshold lowerThreshold]" << std::endl;
    return EXIT_FAILURE;
    }

  const char * inputFilename  = argv[1];
  const char * outputFilename = argv[2];

  float variance = 2.0;
  float upperThreshold = 0.0;
  float lowerThreshold = 0.0;

  if( argc > 3 )
    {
    variance = atof( argv[3] );
    }

  if( argc > 4 )
    {
    upperThreshold = atof( argv[4] );
    }

  if( argc > 5 )
    {
    lowerThreshold = atof( argv[5] );
    }

  std::cout << "Variance = " << variance << std::endl;
  std::cout << "UpperThreshold = " << upperThreshold << std::endl;
  std::cout << "LowerThreshold = " << lowerThreshold << std::endl;

  //  Software Guide : BeginLatex
  //
  //  In this example, images are read and written with \code{unsigned char}
  //  pixel type.  However, Canny edge detection requires floating point
  //  pixel types in order to avoid numerical errors.  For this reason,
  //  a separate internal image type with pixel type \code{double} is defined
  //  for edge detection.
  //
  //  Software Guide : EndLatex

  //  Software Guide : BeginCodeSnippet
  const   unsigned int  Dimension = 2;
  typedef unsigned char CharPixelType;  //  IO
  typedef double        RealPixelType;  //  Operations

  typedef itk::Image<CharPixelType, Dimension> CharImageType;
  typedef itk::Image<RealPixelType, Dimension> RealImageType;

  //  Software Guide : EndCodeSnippet

  typedef itk::ImageFileReader<CharImageType> ReaderType;
  typedef itk::ImageFileWriter<CharImageType> WriterType;

  //  Software Guide : BeginLatex
  //
  //  The \code{CharImageType} image is cast to and from \code{RealImageType}
  //  using \doxygen{CastImageFilter} and \code{RescaleIntensityImageFilter},
  //  respectively; both the input and output of \code{CannyEdgeDetectionImageFilter}
  //  are \code{RealImageType}.
  //
  //  Software Guide : EndLatex

  //  Software Guide : BeginCodeSnippet
  typedef itk::CastImageFilter<CharImageType, RealImageType>
                                                         CastToRealFilterType;

  typedef itk::CannyEdgeDetectionImageFilter<RealImageType, RealImageType> CannyFilter;

  typedef itk::RescaleIntensityImageFilter<RealImageType, CharImageType> RescaleFilter;

  //  Software Guide : EndCodeSnippet

  //Setting the IO

  ReaderType::Pointer           reader      = ReaderType::New();
  CastToRealFilterType::Pointer toReal      = CastToRealFilterType::New();
  CannyFilter::Pointer          cannyFilter = CannyFilter::New();
  RescaleFilter::Pointer        rescale     = RescaleFilter::New();
  WriterType::Pointer           writer      = WriterType::New();

  reader->SetFileName( inputFilename  );
  writer->SetFileName( outputFilename );

  toReal->SetInput( reader->GetOutput() );
  cannyFilter->SetInput( toReal->GetOutput() );
  rescale->SetInput( cannyFilter->GetOutput() );
  writer->SetInput( rescale->GetOutput() );

  //  Software Guide : BeginLatex
  //
  //  In this example, three parameters of the Canny edge detection
  //  filter may be set via the \code{SetVariance()}, \code{SetUpperThreshold()},
  //  and \code{SetLowerThreshold()} methods.  Based on the previous discussion
  //  of the steps in the internal pipeline, we understand that
  //  \code{variance} adjusts the amount of Gaussian smoothing and
  //  \code{upperThreshold} and \code{lowerThreshold} control which edges are
  //  selected in the final step.
  //
  //  Software Guide : EndLatex

  //  Software Guide : BeginCodeSnippet
  cannyFilter->SetVariance( variance );
  cannyFilter->SetUpperThreshold( upperThreshold );
  cannyFilter->SetLowerThreshold( lowerThreshold );

  //  Software Guide : EndCodeSnippet

  //  Software Guide : BeginLatex
  //
  //  Finally, \code{Update()} is called on \code{writer} to trigger excecution
  //  of the pipeline.  As usual, the call is wrapped in a \code{try/catch}
  //  block.
  //
  //  Software Guide : EndLatex

  //  Software Guide : BeginCodeSnippet
  try
    {
    writer->Update();
    }
  catch( itk::ExceptionObject & err )
    {
    std::cout << "ExceptionObject caught !" << std::endl;
    std::cout << err << std::endl;
    return EXIT_FAILURE;
    }

  // Software Guide : EndCodeSnippet

  return EXIT_SUCCESS;

}
<|endoftext|>


<commit_before>#include "kernel.h"
#include "ilwis.h"
#include "geometries.h"
#include "ilwisdata.h"
#include "coordinatesystem.h"
#include "georeference.h"
#include "georefimplementation.h"
#include "factory.h"
#include "abstractfactory.h"
#include "coordinatesystem.h"
#include "georeference.h"
#include "simpelgeoreference.h"
#include "cornersgeoreference.h"
#include "georefimplementationfactory.h"

using namespace Ilwis;

GeoRefImplementationFactory::GeoRefImplementationFactory() : AbstractFactory("georefimplementationfactory","ilwis","")
{
}

void GeoRefImplementationFactory::addCreator(const QString &name, CreateGeoRefImplementation func)
{
    auto iter = _implCreators.find(name);
    if ( iter == _implCreators.end()) {
        _implCreators[name] = func;
    }
}

GeoRefImplementation *GeoRefImplementationFactory::create(const QString& name)  {
    auto iter = _implCreators.find(name);
    if ( iter != _implCreators.end()) {
        return _implCreators[name]();
    }
    return 0;
}

bool GeoRefImplementationFactory::prepare()
{
    AbstractFactory::prepare();

    addCreator("simpel",SimpelGeoReference::create);
    addCreator("corners",CornersGeoReference::create);

    return true;
}

<commit_msg>georefctp added to the factory<commit_after>#include "kernel.h"
#include "ilwis.h"
#include "geometries.h"
#include "ilwisdata.h"
#include "coordinatesystem.h"
#include "georeference.h"
#include "georefimplementation.h"
#include "factory.h"
#include "abstractfactory.h"
#include "coordinatesystem.h"
#include "georeference.h"
#include "simpelgeoreference.h"
#include "cornersgeoreference.h"
#include "controlpoint.h"
#include "ctpgeoreference.h"
#include "Eigen/LU"
#include "mathhelper.h"
#include "planarctpgeoreference.h"
#include "georefimplementationfactory.h"

using namespace Ilwis;

GeoRefImplementationFactory::GeoRefImplementationFactory() : AbstractFactory("georefimplementationfactory","ilwis","")
{
}

void GeoRefImplementationFactory::addCreator(const QString &name, CreateGeoRefImplementation func)
{
    auto iter = _implCreators.find(name);
    if ( iter == _implCreators.end()) {
        _implCreators[name] = func;
    }
}

GeoRefImplementation *GeoRefImplementationFactory::create(const QString& name)  {
    auto iter = _implCreators.find(name);
    if ( iter != _implCreators.end()) {
        return _implCreators[name]();
    }
    return 0;
}

bool GeoRefImplementationFactory::prepare()
{
    AbstractFactory::prepare();

    addCreator("simpel",SimpelGeoReference::create);
    addCreator("corners",CornersGeoReference::create);
    addCreator("tiepoints",PlanarCTPGeoReference::create);

    return true;
}

<|endoftext|>


<commit_before>#include "Halide.h"
#include <stdio.h>

#include "test/common/halide_test_dirs.h"

using namespace Halide;

int main(int argc, char **argv) {
    // Make sure it's possible to generate object files for lots of
    // targets. This provides early warning that you may have broken
    // Halide on some other platform.

    Func f("f");
    Var x;
    f(x) = x;

    std::string targets[] = {
        "x86-64-linux",
        "x86-32-linux",
        "x86-64-osx",
        "x86-32-osx",
        "x86-64-windows",
        "x86-32-windows",
        "arm-64-ios",
        "arm-32-ios",
        "arm-64-android",
        "arm-32-android",
        "mips-32-android"
    };

    for (const std::string &t : targets) {
        Target target(t);
        if (!target.supported()) continue;

        std::string object_name = Internal::get_test_tmp_dir() + "test_object_" + t;
        std::string lib_name = Internal::get_test_tmp_dir() + "test_lib_" + t;
        if (target.os == Target::Windows && !target.has_feature(Target::MinGW)) {
            object_name += ".obj";
            lib_name += ".lib";
        } else {
            object_name += ".o";
            lib_name += ".a";
        }

        Internal::ensure_no_file_exists(object_name);
        Internal::ensure_no_file_exists(lib_name);

        f.compile_to_file("test_object_" + t, std::vector<Argument>(), "", target);
        f.compile_to_static_library("test_lib_" + t, std::vector<Argument>(), "", target);

        Internal::assert_file_exists(object_name);
        Internal::assert_file_exists(lib_name);
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Fix cross_compilation<commit_after>#include "Halide.h"
#include <stdio.h>

#include "test/common/halide_test_dirs.h"

using namespace Halide;

int main(int argc, char **argv) {
    // Make sure it's possible to generate object files for lots of
    // targets. This provides early warning that you may have broken
    // Halide on some other platform.

    Func f("f");
    Var x;
    f(x) = x;

    std::string targets[] = {
        "x86-64-linux",
        "x86-32-linux",
        "x86-64-osx",
        "x86-32-osx",
        "x86-64-windows",
        "x86-32-windows",
        "arm-64-ios",
        "arm-32-ios",
        "arm-64-android",
        "arm-32-android",
        "mips-32-android"
    };

    for (const std::string &t : targets) {
        Target target(t);
        if (!target.supported()) continue;

        std::string object_name = Internal::get_test_tmp_dir() + "test_object_" + t;
        std::string lib_name = Internal::get_test_tmp_dir() + "test_lib_" + t;
        if (target.os == Target::Windows && !target.has_feature(Target::MinGW)) {
            object_name += ".obj";
            lib_name += ".lib";
        } else {
            object_name += ".o";
            lib_name += ".a";
        }

        Internal::ensure_no_file_exists(object_name);
        Internal::ensure_no_file_exists(lib_name);

        f.compile_to_file(Internal::get_test_tmp_dir() + "test_object_" + t, std::vector<Argument>(), "", target);
        f.compile_to_static_library(Internal::get_test_tmp_dir() + "test_lib_" + t, std::vector<Argument>(), "", target);

        Internal::assert_file_exists(object_name);
        Internal::assert_file_exists(lib_name);
    }

    printf("Success!\n");
    return 0;
}
<|endoftext|>


<commit_before><commit_msg>Remove the temporary instrumentation to getaddrinfo(). This is a revert of r31267.<commit_after><|endoftext|>


<commit_before>// Copyright 2019 DeepMind Technologies Ltd. All rights reserved.
//
// 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 "open_spiel/games/chess/pgn.h"

#include <iostream>
#include <string>
#include <utility>
#include <vector>

#include "open_spiel/abseil-cpp/absl/strings/match.h"
#include "open_spiel/abseil-cpp/absl/strings/str_cat.h"
#include "open_spiel/abseil-cpp/absl/strings/str_join.h"
#include "open_spiel/spiel_utils.h"

namespace open_spiel {
namespace pgn {
namespace {

template <typename T>
void WriteTag(
    std::ostream& os, const std::string& key, const T& value) {
  os << "[" << key << " \"" << value << "\']" << std::endl;
}

void WriteComment(std::ostream& os, const std::string& comment) {
  os << "{" << comment << "}";
}

std::string GetResultString(const State &state) {
  std::string result_str;
  if (state.IsTerminal()) {
    std::vector<std::string> results;
    for (double ret : state.Returns()) {
      if (ret == chess::WinUtility()) {
        results.emplace_back("1");
      } else if (ret == chess::DrawUtility()) {
        results.emplace_back("1/2");
      } else if (ret == chess::LossUtility()) {
        results.emplace_back("0");
      } else {
        SpielFatalError("Invalid chess utility");
      }
    }
    result_str = results[chess::ColorToPlayer(chess::Color::kWhite)] + "-" +
                 results[chess::ColorToPlayer(chess::Color::kBlack)];
  } else {
    result_str = "*";
  }
  return result_str;
}

void WriteHeader(std::ostream& os, const std::string& event, int round,
                 const std::string& white, const std::string& black,
                 const State& state,
                 const std::vector<std::pair<std::string, std::string>> &tags = {}) {

  WriteTag(os, "Event", event);
  WriteTag(os, "Site", "OpenSpiel");
  WriteTag(os, "Round", round);

  std::string date_str;
  if (state.IsTerminal()) {
    time_t ttime = time(nullptr);
    char buffer[11];
    strftime(buffer,sizeof(buffer),"%Y.%m.%d", localtime(&ttime));
    date_str = buffer;
  } else {
    date_str = "????.??.??";
  }

  WriteTag(os, "Date", date_str);
  WriteTag(os, "White", white);
  WriteTag(os, "Black", black);
  WriteTag(os, "Result", GetResultString(state));
  for (const auto &[key, value] : tags) {
    WriteTag(os, key, value);
  }
}

std::string CheckTypeToPGNString(kriegspiel::KriegspielCheckType check_type) {

  switch (check_type) {
    case kriegspiel::KriegspielCheckType::kNoCheck:
      return "";
    case kriegspiel::KriegspielCheckType::kFile:
      return "F";
    case kriegspiel::KriegspielCheckType::kRank:
      return "R";
    case kriegspiel::KriegspielCheckType::kLongDiagonal:
      return "L";
    case kriegspiel::KriegspielCheckType::kShortDiagonal:
      return "S";
    case kriegspiel::KriegspielCheckType::kKnight:
      return "N";
    default:
      SpielFatalError("Unknown check type");
  }
}

std::string CheckTypesToPGNString(
    const std::pair<kriegspiel::KriegspielCheckType,
    kriegspiel::KriegspielCheckType>& check_type) {

  std::string str;
  str += CheckTypeToPGNString(check_type.first);
  if (check_type.second != kriegspiel::KriegspielCheckType::kNoCheck) {
    std::string second_check_str = CheckTypeToPGNString(check_type.second);
    if (second_check_str < str) {
      str = second_check_str + str;
    }
    else {
      str += second_check_str;
    }
  }
  return str;
}

} // namespace

ChessPGN::ChessPGN(const chess::ChessState &state, const std::string& event,
                        int round, const std::string& white,
                        const std::string& black) :
    state_(state),
    event_(event),
    round_(round),
    white_(white),
    black_(black) {}

void ChessPGN::WriteHeader(std::ostream& os) const {
  pgn::WriteHeader(os, event_, round_, white_, black_, state_);
}

void ChessPGN::WriteMoves(std::ostream& os) const {
  chess::ChessBoard board = state_.StartBoard();

  for (const chess::Move& move : state_.MovesHistory()) {
    if (board.ToPlay() == chess::Color::kWhite) {
      os << board.Movenumber() << ". ";
    }
    else {
      os << "   ";
      if (board.Movenumber() > 9) os << " ";
      if (board.Movenumber() > 99) os << " ";
    }
    os << move.ToSAN(board) << std::endl;
    board.ApplyMove(move);
  }
}

void ChessPGN::WriteResult(std::ostream& os) const {
  os << GetResultString(state_) << std::endl;
}

KriegspielPGN::KriegspielPGN(const kriegspiel::KriegspielState &state,
                             const std::string& event,
                             int round,
                             const std::string& white,
                             const std::string& black,
                             chess::Color filtered) :
    state_(state),
    event_(event),
    round_(round),
    white_(white),
    black_(black),
    filtered_(filtered) {}

void KriegspielPGN::WriteHeader(std::ostream &os) const {
  std::vector<std::pair<std::string, std::string>> tags
      {std::make_pair("Variant", "ICC"),
       std::make_pair("Filtered", GetFilteredString())};

  pgn::WriteHeader(os, event_, round_, white_, black_, state_, tags);
}

void KriegspielPGN::WriteMoves(std::ostream &os) const {
  chess::ChessBoard board = state_.StartBoard();

  std::vector<std::string> illegal_moves;
  for (auto &[move, msg] : state_.MoveMsgHistory()) {
    std::string move_str = move.ToSAN(board, true);
    if (msg.illegal) {
      illegal_moves.emplace_back(move_str);
      continue;
    }
    if (board.ToPlay() == chess::Color::kWhite) {
      os << board.Movenumber() << ". ";
    }
    else {
      os << "   ";
      if (board.Movenumber() > 9) os << " ";
      if (board.Movenumber() > 99) os << " ";
    }
    if (filtered_ == chess::Color::kEmpty || filtered_ == board.ToPlay()) {
      os << move_str << " ";
    }
    else {
      os << "??" << " ";
    }

    WriteUmpireComment(os, illegal_moves, msg);
    os << std::endl;

    board.ApplyMove(move);
    illegal_moves.clear();
  }
}

void KriegspielPGN::WriteResult(std::ostream &os) const {
  os << GetResultString(state_) << std::endl;
}

std::string KriegspielPGN::GetFilteredString() const {
  if (filtered_ == chess::Color::kEmpty) {
    return "no";
  }
  return chess::ColorToString(filtered_);
}

void KriegspielPGN::WriteUmpireComment(
    std::ostream &os, const std::vector<std::string> &illegal_moves,
    const kriegspiel::KriegspielUmpireMessage& msg) const {

  std::string str;
  if (msg.capture_type != kriegspiel::KriegspielCaptureType::kNoCapture) {
    str += chess::SquareToString(msg.square);
  }
  std::string check_types_str = CheckTypesToPGNString(msg.check_types);
  if (!check_types_str.empty()) {
    if (!str.empty()) {
      str += ",";
    }
    str += check_types_str;
  }
  str += ":";
  if (filtered_ == chess::Color::kEmpty ||
      filtered_ == chess::OppColor(msg.to_move)) {
    str += absl::StrJoin(illegal_moves.rbegin(), illegal_moves.rend(), ",");
  } else {
    str += std::to_string(illegal_moves.size());
  }

  WriteComment(os, str);
}

std::ostream& operator<<(std::ostream& os, const PGN& pgn) {

  pgn.WriteHeader(os);
  os << std::endl;
  pgn.WriteMoves(os);
  pgn.WriteResult(os);

  // There is a possibility to write multiple games in one file. Those games
  // should be separated by multiple empty lines.
  os << std::endl << std::endl;
  return os;
}
}  // namespace pgn
}  // namespace open_spiel
<commit_msg>PGN tag fixed<commit_after>// Copyright 2019 DeepMind Technologies Ltd. All rights reserved.
//
// 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 "open_spiel/games/chess/pgn.h"

#include <iostream>
#include <string>
#include <utility>
#include <vector>

#include "open_spiel/abseil-cpp/absl/strings/match.h"
#include "open_spiel/abseil-cpp/absl/strings/str_cat.h"
#include "open_spiel/abseil-cpp/absl/strings/str_join.h"
#include "open_spiel/spiel_utils.h"

namespace open_spiel {
namespace pgn {
namespace {

template <typename T>
void WriteTag(
    std::ostream& os, const std::string& key, const T& value) {
  os << "[" << key << " \"" << value << "\"]" << std::endl;
}

void WriteComment(std::ostream& os, const std::string& comment) {
  os << "{" << comment << "}";
}

std::string GetResultString(const State &state) {
  std::string result_str;
  if (state.IsTerminal()) {
    std::vector<std::string> results;
    for (double ret : state.Returns()) {
      if (ret == chess::WinUtility()) {
        results.emplace_back("1");
      } else if (ret == chess::DrawUtility()) {
        results.emplace_back("1/2");
      } else if (ret == chess::LossUtility()) {
        results.emplace_back("0");
      } else {
        SpielFatalError("Invalid chess utility");
      }
    }
    result_str = results[chess::ColorToPlayer(chess::Color::kWhite)] + "-" +
                 results[chess::ColorToPlayer(chess::Color::kBlack)];
  } else {
    result_str = "*";
  }
  return result_str;
}

void WriteHeader(std::ostream& os, const std::string& event, int round,
                 const std::string& white, const std::string& black,
                 const State& state,
                 const std::vector<std::pair<std::string, std::string>> &tags = {}) {

  WriteTag(os, "Event", event);
  WriteTag(os, "Site", "OpenSpiel");
  WriteTag(os, "Round", round);

  std::string date_str;
  if (state.IsTerminal()) {
    time_t ttime = time(nullptr);
    char buffer[11];
    strftime(buffer,sizeof(buffer),"%Y.%m.%d", localtime(&ttime));
    date_str = buffer;
  } else {
    date_str = "????.??.??";
  }

  WriteTag(os, "Date", date_str);
  WriteTag(os, "White", white);
  WriteTag(os, "Black", black);
  WriteTag(os, "Result", GetResultString(state));
  for (const auto &[key, value] : tags) {
    WriteTag(os, key, value);
  }
}

std::string CheckTypeToPGNString(kriegspiel::KriegspielCheckType check_type) {

  switch (check_type) {
    case kriegspiel::KriegspielCheckType::kNoCheck:
      return "";
    case kriegspiel::KriegspielCheckType::kFile:
      return "F";
    case kriegspiel::KriegspielCheckType::kRank:
      return "R";
    case kriegspiel::KriegspielCheckType::kLongDiagonal:
      return "L";
    case kriegspiel::KriegspielCheckType::kShortDiagonal:
      return "S";
    case kriegspiel::KriegspielCheckType::kKnight:
      return "N";
    default:
      SpielFatalError("Unknown check type");
  }
}

std::string CheckTypesToPGNString(
    const std::pair<kriegspiel::KriegspielCheckType,
    kriegspiel::KriegspielCheckType>& check_type) {

  std::string str;
  str += CheckTypeToPGNString(check_type.first);
  if (check_type.second != kriegspiel::KriegspielCheckType::kNoCheck) {
    std::string second_check_str = CheckTypeToPGNString(check_type.second);
    if (second_check_str < str) {
      str = second_check_str + str;
    }
    else {
      str += second_check_str;
    }
  }
  return str;
}

} // namespace

ChessPGN::ChessPGN(const chess::ChessState &state, const std::string& event,
                        int round, const std::string& white,
                        const std::string& black) :
    state_(state),
    event_(event),
    round_(round),
    white_(white),
    black_(black) {}

void ChessPGN::WriteHeader(std::ostream& os) const {
  pgn::WriteHeader(os, event_, round_, white_, black_, state_);
}

void ChessPGN::WriteMoves(std::ostream& os) const {
  chess::ChessBoard board = state_.StartBoard();

  for (const chess::Move& move : state_.MovesHistory()) {
    if (board.ToPlay() == chess::Color::kWhite) {
      os << board.Movenumber() << ". ";
    }
    else {
      os << "   ";
      if (board.Movenumber() > 9) os << " ";
      if (board.Movenumber() > 99) os << " ";
    }
    os << move.ToSAN(board) << std::endl;
    board.ApplyMove(move);
  }
}

void ChessPGN::WriteResult(std::ostream& os) const {
  os << GetResultString(state_) << std::endl;
}

KriegspielPGN::KriegspielPGN(const kriegspiel::KriegspielState &state,
                             const std::string& event,
                             int round,
                             const std::string& white,
                             const std::string& black,
                             chess::Color filtered) :
    state_(state),
    event_(event),
    round_(round),
    white_(white),
    black_(black),
    filtered_(filtered) {}

void KriegspielPGN::WriteHeader(std::ostream &os) const {
  std::vector<std::pair<std::string, std::string>> tags
      {std::make_pair("Variant", "ICC"),
       std::make_pair("Filtered", GetFilteredString())};

  pgn::WriteHeader(os, event_, round_, white_, black_, state_, tags);
}

void KriegspielPGN::WriteMoves(std::ostream &os) const {
  chess::ChessBoard board = state_.StartBoard();

  std::vector<std::string> illegal_moves;
  for (auto &[move, msg] : state_.MoveMsgHistory()) {
    std::string move_str = move.ToSAN(board, true);
    if (msg.illegal) {
      illegal_moves.emplace_back(move_str);
      continue;
    }
    if (board.ToPlay() == chess::Color::kWhite) {
      os << board.Movenumber() << ". ";
    }
    else {
      os << "   ";
      if (board.Movenumber() > 9) os << " ";
      if (board.Movenumber() > 99) os << " ";
    }
    if (filtered_ == chess::Color::kEmpty || filtered_ == board.ToPlay()) {
      os << move_str << " ";
    }
    else {
      os << "??" << " ";
    }

    WriteUmpireComment(os, illegal_moves, msg);
    os << std::endl;

    board.ApplyMove(move);
    illegal_moves.clear();
  }
}

void KriegspielPGN::WriteResult(std::ostream &os) const {
  os << GetResultString(state_) << std::endl;
}

std::string KriegspielPGN::GetFilteredString() const {
  if (filtered_ == chess::Color::kEmpty) {
    return "no";
  }
  return chess::ColorToString(filtered_);
}

void KriegspielPGN::WriteUmpireComment(
    std::ostream &os, const std::vector<std::string> &illegal_moves,
    const kriegspiel::KriegspielUmpireMessage& msg) const {

  std::string str;
  if (msg.capture_type != kriegspiel::KriegspielCaptureType::kNoCapture) {
    str += chess::SquareToString(msg.square);
  }
  std::string check_types_str = CheckTypesToPGNString(msg.check_types);
  if (!check_types_str.empty()) {
    if (!str.empty()) {
      str += ",";
    }
    str += check_types_str;
  }
  str += ":";
  if (filtered_ == chess::Color::kEmpty ||
      filtered_ == chess::OppColor(msg.to_move)) {
    str += absl::StrJoin(illegal_moves.rbegin(), illegal_moves.rend(), ",");
  } else {
    str += std::to_string(illegal_moves.size());
  }

  WriteComment(os, str);
}

std::ostream& operator<<(std::ostream& os, const PGN& pgn) {

  pgn.WriteHeader(os);
  os << std::endl;
  pgn.WriteMoves(os);
  pgn.WriteResult(os);

  // There is a possibility to write multiple games in one file. Those games
  // should be separated by multiple empty lines.
  os << std::endl << std::endl;
  return os;
}
}  // namespace pgn
}  // namespace open_spiel
<|endoftext|>