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

#ifndef ZIPPYLOG_DEVICE_STRING_LOADER_HPP_
#define ZIPPYLOG_DEVICE_STRING_LOADER_HPP_

#include <zippylog/zippylog.hpp>
#include <zippylog/lua.hpp>
#include <zippylog/store.hpp>

#include <gtest/gtest_prod.h>

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

namespace zippylog {
namespace device {

/// Used to instantiate instances of the StringLoader
class ZIPPYLOG_EXPORT StringLoaderStartParams {
public:
    StringLoaderStartParams() :
      input_stream(NULL),
      lua_max_size(1024),
      output_stream(NULL),
      active(NULL)
    { }

    /// Input parameters

    /// Stream to read string data from
    ::std::istream * input_stream;

    /// Processing parameters

    /// Filename containing Lua code that we should load
    ::std::string lua_file;

    /// Lua code to load
    ::std::string lua_code;

    /// Max size (in kilobytes) that Lua interpreter is allowed to grow to
    uint32 lua_max_size;

    /// Output parameters

    /// If defined, a stream to write processed string data to
    ///
    /// This is typically only used for debugging purposes
    ::std::ostream * output_stream;

    /// If defined, will write to a store constructed from this store path
    ::std::string store_path;

    /// Default bucket to route envelopes to
    ///
    /// Must be defined if writing to a server or store
    ::std::string default_bucket;

    /// Default stream set to route envelopes to
    ///
    /// Must be defined if writing to a server or store
    ::std::string default_set;

    /// Misc parameters

    /// Semaphore for the device to remain active
    bool * active;
};

/// Represents the result of string processing in the string loader
class ZIPPYLOG_EXPORT StringLoaderProcessingResult {
public:
    StringLoaderProcessingResult() :
      success(false),
      has_bucket(false),
      has_set(false)
    { }

    ~StringLoaderProcessingResult() {
        for (size_t i = this->envelopes.size(); i; i--) {
            delete this->envelopes[i-1];
        }
    }

    bool success;

    /// Error describing what went wrong
    ///
    /// Only defined if success is false
    ::std::string error;

    /// Envelopes produced as part of processing
    ///
    /// The envelopes are owned by this object. They will be destroyed when
    /// the instance holding them is destroyed.
    ::std::vector<Envelope *> envelopes;

    bool has_bucket;
    bool has_set;

    ::std::string bucket;
    ::std::string set;
};

/// Device that loads strings into envelopes and optionally sends them
/// somewhere
///
/// The device can be configured with an input stream and an output mode or
/// modes. When configured this way, you simply configure the device, start
/// it, and it is self-sustaining.
///
/// Alternatively, you can create the device without any input or output and
/// call the functions that do processing. In those mode, you are free to
/// generate input or route output to your desire.
class ZIPPYLOG_EXPORT StringLoader {
public:
    /// Construct a string loader from parameters
    StringLoader(StringLoaderStartParams &params);

    ~StringLoader();

    /// Read a line from the configured input stream and process it
    ///
    /// Throws an exception if no input stream is configured
    void ReadLineAndProcess(StringLoaderProcessingResult &result);

    /// Process a string for loading
    ///
    /// This is what's internally called by ReceiveLine(). It handles all the
    /// logic for invoking Lua (if configured) and marshaling the string to an
    /// envelope.
    void ProcessString(::std::string const& s, StringLoaderProcessingResult &result);

    /// Sends a result to the configured outputs
    ///
    /// This is called internally when the device is executing on its own.
    /// The API is public just in case.
    void SendResult(StringLoaderProcessingResult const& result);

    /// Whether a Lua string loader is configured
    bool HaveLuaStringLoader() const { return this->have_lua_string_loader; }

    /// Runs the device
    ///
    /// Will read data from the input stream and route to the configured
    /// outputs until the semaphore passed in the constructor says to stop.
    ///
    /// In other words, this doesn't return until the semaphore goes to false.
    void Run();

protected:
    /// Stream we are reading from
    ::std::istream * const instream;

    /// Stream we are writing to
    ::std::ostream * const outstream;

    /// Lua interpreter for processing
    ::zippylog::lua::LuaState L;

    /// Whether the Lua state has string loader processing
    bool have_lua_string_loader;

    /// The default bucket for envelopes
    ::std::string default_bucket;

    /// The default stream set for envelopes
    ::std::string default_set;

    /// The store we are writing to
    ::zippylog::Store * store;

    /// Whether the device should remain active
    bool * const active;

private:
    StringLoader(StringLoader const &orig);
    StringLoader & operator=(StringLoader const &orig);

    FRIEND_TEST(StringLoaderTest, ConstructorTest);
};

}} // namespaces

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

#ifndef ZIPPYLOG_DEVICE_STRING_LOADER_HPP_
#define ZIPPYLOG_DEVICE_STRING_LOADER_HPP_

#include <zippylog/zippylog.hpp>
#include <zippylog/lua.hpp>
#include <zippylog/store.hpp>

#include <gtest/gtest_prod.h>

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

namespace zippylog {
namespace device {

/// Used to instantiate instances of the StringLoader
class ZIPPYLOG_EXPORT StringLoaderStartParams {
public:
    StringLoaderStartParams() :
      input_stream(NULL),
      lua_max_size(1024),
      output_stream(NULL),
      active(NULL)
    { }

    /// Input parameters

    /// Stream to read string data from
    ::std::istream * input_stream;

    /// Processing parameters

    /// Filename containing Lua code that we should load
    ::std::string lua_file;

    /// Lua code to load
    ::std::string lua_code;

    /// Max size (in kilobytes) that Lua interpreter is allowed to grow to
    uint32 lua_max_size;

    /// Output parameters

    /// If defined, a stream to write processed string data to
    ///
    /// This is typically only used for debugging purposes
    ::std::ostream * output_stream;

    /// If defined, will write to a store constructed from this store path
    ::std::string store_path;

    /// Default bucket to route envelopes to
    ///
    /// Must be defined if writing to a server or store
    ::std::string default_bucket;

    /// Default stream set to route envelopes to
    ///
    /// Must be defined if writing to a server or store
    ::std::string default_set;

    /// Misc parameters

    /// Semaphore for the device to remain active
    bool * active;
};

/// Represents the result of string processing in the string loader
class ZIPPYLOG_EXPORT StringLoaderProcessingResult {
public:
    /// Construct an empty result
    StringLoaderProcessingResult() :
      success(false),
      has_bucket(false),
      has_set(false)
    { }

    ~StringLoaderProcessingResult() {
        for (size_t i = this->envelopes.size(); i; i--) {
            delete this->envelopes[i-1];
        }
    }

    /// Whether the result was successful
    bool success;

    /// Error describing what went wrong
    ///
    /// Only defined if success is false
    ::std::string error;

    /// Envelopes produced as part of processing
    ///
    /// The envelopes are owned by this object. They will be destroyed when
    /// the instance holding them is destroyed.
    ::std::vector<Envelope *> envelopes;

    /// Whether a bucket was set
    ///
    /// If true, bucket should have a value
    bool has_bucket;

    /// Whether a stream set was set
    ///
    /// If true, set should have a value
    bool has_set;

    /// The bucket to load the envelope into
    ::std::string bucket;

    /// The stream set to load the envelope into
    ::std::string set;
};

/// Device that loads strings into envelopes and optionally sends them
/// somewhere
///
/// The device can be configured with an input stream and an output mode or
/// modes. When configured this way, you simply configure the device, start
/// it, and it is self-sustaining.
///
/// Alternatively, you can create the device without any input or output and
/// call the functions that do processing. In those mode, you are free to
/// generate input or route output to your desire.
class ZIPPYLOG_EXPORT StringLoader {
public:
    /// Construct a string loader from parameters
    ///
    /// @param params Parameters to control behavior
    StringLoader(StringLoaderStartParams &params);

    ~StringLoader();

    /// Read a line from the configured input stream and process it
    ///
    /// Throws an exception if no input stream is configured
    void ReadLineAndProcess(StringLoaderProcessingResult &result);

    /// Process a string for loading
    ///
    /// This is what's internally called by ReceiveLine(). It handles all the
    /// logic for invoking Lua (if configured) and marshaling the string to an
    /// envelope.
    void ProcessString(::std::string const& s, StringLoaderProcessingResult &result);

    /// Sends a result to the configured outputs
    ///
    /// This is called internally when the device is executing on its own.
    /// The API is public just in case.
    void SendResult(StringLoaderProcessingResult const& result);

    /// Whether a Lua string loader is configured
    bool HaveLuaStringLoader() const { return this->have_lua_string_loader; }

    /// Runs the device
    ///
    /// Will read data from the input stream and route to the configured
    /// outputs until the semaphore passed in the constructor says to stop.
    ///
    /// In other words, this doesn't return until the semaphore goes to false.
    void Run();

protected:
    /// Stream we are reading from
    ::std::istream * const instream;

    /// Stream we are writing to
    ::std::ostream * const outstream;

    /// Lua interpreter for processing
    ::zippylog::lua::LuaState L;

    /// Whether the Lua state has string loader processing
    bool have_lua_string_loader;

    /// The default bucket for envelopes
    ::std::string default_bucket;

    /// The default stream set for envelopes
    ::std::string default_set;

    /// The store we are writing to
    ::zippylog::Store * store;

    /// Whether the device should remain active
    bool * const active;

private:
    StringLoader(StringLoader const &orig);
    StringLoader & operator=(StringLoader const &orig);

    FRIEND_TEST(StringLoaderTest, ConstructorTest);
};

}} // namespaces

#endif<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_FUN_QUAD_FORM_DIAG_HPP
#define STAN_MATH_PRIM_FUN_QUAD_FORM_DIAG_HPP

#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>

namespace stan {
namespace math {

template <typename T1, typename T2, int R, int C>
inline Eigen::Matrix<return_type_t<T1, T2>, Eigen::Dynamic, Eigen::Dynamic>
quad_form_diag(const Eigen::Matrix<T1, Eigen::Dynamic, Eigen::Dynamic>& mat,
               const Eigen::Matrix<T2, R, C>& vec) {
  check_vector("quad_form_diag", "vec", vec);
  check_square("quad_form_diag", "mat", mat);
  check_multiplicable("quad_form_diag", mat, vec);
  return vec.asDiagonal() * mat * vec.asDiagonal();
}

}  // namespace math
}  // namespace stan

#endif
<commit_msg>Fix call to check_multiplicable<commit_after>#ifndef STAN_MATH_PRIM_FUN_QUAD_FORM_DIAG_HPP
#define STAN_MATH_PRIM_FUN_QUAD_FORM_DIAG_HPP

#include <stan/math/prim/err.hpp>
#include <stan/math/prim/fun/Eigen.hpp>

namespace stan {
namespace math {

template <typename T1, typename T2, int R, int C>
inline Eigen::Matrix<return_type_t<T1, T2>, Eigen::Dynamic, Eigen::Dynamic>
quad_form_diag(const Eigen::Matrix<T1, Eigen::Dynamic, Eigen::Dynamic>& mat,
               const Eigen::Matrix<T2, R, C>& vec) {
  check_vector("quad_form_diag", "vec", vec);
  check_square("quad_form_diag", "mat", mat);
  check_multiplicable("quad_form_diag", "mat", mat, "vec", vec);
  return vec.asDiagonal() * mat * vec.asDiagonal();
}

}  // namespace math
}  // namespace stan

#endif
<|endoftext|>


<commit_before>#include <algorithm>

#include <unistd.h>

#include "../core/converter.h"
#include "xsocket.h"

using namespace std;
using namespace MM_NAMESPACE()::NET;

SocketStream::SocketStream(int fd) : fd(fd) {}

SocketStream::SocketStream(const SocketStream& obj) : fd(obj.fd) {}

SocketStream::~SocketStream() { close(fd); }

void SocketStream::operator<<(const std::string& data) { send(data); }

void SocketStream::send(const std::string& data) { send(data, data.length()); }

void SocketStream::send(const std::string& data, int len) {
  int n = write(fd, data.c_str(), len);
  if (n < 0)
    throw SocketException("write() failed: " + str(n));
}

const std::string SocketStream::get(int len) {
  char buf[MAX_BUF];
  bzero(&buf, MAX_BUF);

  int n = read(fd, &buf, len);
  if (n < 0)
    throw SocketException("read() failed" + str(n));
  return buf;
}

const std::string SocketStream::operator>>(int len) { return get(len); }

Socket::Socket(SOCKET_TYPE type, int port)
    : fd(0), port(port), type(type), stream(0) {
  bzero((char*)&addr, sizeof(addr));

  if (type == TCP)
    fd = socket(AF_INET, SOCK_STREAM, 0);
  else if (type == UDP)
    fd = socket(AF_INET, SOCK_DGRAM, 0);
  else if (type == UNIX)
    fd = socket(AF_UNIX, SOCK_DGRAM, 0);

  if (fd < 0)
    throw SocketException("Could not create socket");
}

Socket::~Socket() {
  // hmmm no fd because SocketStream does the job
}

ServerSocket::ServerSocket(SOCKET_TYPE type, int port) : Socket(type, port) {
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(port);

  if (bind(fd, (struct sockaddr*)&addr, sizeof(addr)) == -1)
    throw SocketException("Could not bind to address/port");

  stream = new SocketStream(fd);
}

ServerSocket::~ServerSocket() {
  if (stream != NULL)
    delete stream;
}

SocketStream* ServerSocket::listen() {
  struct sockaddr_in client_addr;
  int client_addr_len = sizeof(client_addr);

  bzero((char*)&client_addr, client_addr_len);
  ::listen(fd, MAX_LISTEN_QUEUE);

  int client_fd =
      accept(fd, (struct sockaddr*)&client_addr, (socklen_t*)&client_addr_len);
  if (client_fd < 0)
    throw SocketException("Error during accaptance of remote client");
  return new SocketStream(client_fd);
}

ClientSocket::ClientSocket(SOCKET_TYPE type, int port,
                           const std::string& target)
    : Socket(type, port) {
  addr.sin_port = htons((unsigned short int)port);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = inet_addr(target.c_str());

  // socklen_t addr_len = sizeof(addr);
  if (connect(fd, (struct sockaddr*)&addr, sizeof(addr))) {
    perror("connect:");
    throw SocketException("Could not connect to given target");
  }

  stream = new SocketStream(fd);
}

ClientSocket::~ClientSocket() {}

void StreamSelecter::add_stream(SocketStream* stream) {
  streams.push_back(stream);
}

void StreamSelecter::remove_stream(SocketStream* stream) {
  std::remove(streams.begin(), streams.end(), stream);
}

SocketStream* StreamSelecter::select() { return this->select(250000); }

SocketStream* StreamSelecter::select(unsigned int usecs) {
  FD_ZERO(&socks);
  // for(vector<SocketStream*>::iterator i=streams.begin(); i!=streams.end();
  // ++i)
  for (SocketStream* stream : streams)
    FD_SET(stream->fd, &socks);

  struct timeval timeout;
  timeout.tv_sec = 0;
  timeout.tv_usec = usecs;

  int readsocks =
      ::select(sizeof(socks) * 8, &socks, (fd_set*)0, (fd_set*)0, &timeout);

  if (readsocks == 0)
    return NULL;

  // for(vector<SocketStream*>::iterator i=streams.begin(); i!=streams.end();
  // ++i)
  for (SocketStream* stream : streams)
    if (FD_ISSET(stream->fd, &socks))
      return stream;

  return NULL;
}
<commit_msg>xsocket compatibility fix, next try<commit_after>#include <algorithm>

#include <unistd.h>

#include "../core/converter.h"
#include "xsocket.h"

using namespace std;
using namespace MM_NAMESPACE()::NET;

SocketStream::SocketStream(int fd) : fd(fd) {}

SocketStream::SocketStream(const SocketStream& obj) : fd(obj.fd) {}

SocketStream::~SocketStream() { close(fd); }

void SocketStream::operator<<(const std::string& data) { send(data); }

void SocketStream::send(const std::string& data) { send(data, data.length()); }

void SocketStream::send(const std::string& data, int len) {
  int n = write(fd, data.c_str(), len);
  if (n < 0)
    throw SocketException("write() failed: " + str(n));
}

const std::string SocketStream::get(int len) {
  char buf[MAX_BUF];
  bzero(&buf, MAX_BUF);

  int n = read(fd, &buf, len);
  if (n < 0)
    throw SocketException("read() failed" + str(n));
  return buf;
}

const std::string SocketStream::operator>>(int len) { return get(len); }

Socket::Socket(SOCKET_TYPE type, int port)
    : fd(0), port(port), type(type), stream(0) {
  bzero((char*)&addr, sizeof(addr));

  if (type == TCP)
    fd = socket(AF_INET, SOCK_STREAM, 0);
  else if (type == UDP)
    fd = socket(AF_INET, SOCK_DGRAM, 0);
  else if (type == UNIX)
    fd = socket(AF_UNIX, SOCK_DGRAM, 0);

  if (fd < 0)
    throw SocketException("Could not create socket");
}

Socket::~Socket() {
  // hmmm no fd because SocketStream does the job
}

ServerSocket::ServerSocket(SOCKET_TYPE type, int port) : Socket(type, port) {
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = INADDR_ANY;
  addr.sin_port = htons(port);

  int ret = bind(fd, (struct sockaddr*)&addr, sizeof(addr));
  if (ret == -1)
    throw SocketException("Could not bind to address/port");

  stream = new SocketStream(fd);
}

ServerSocket::~ServerSocket() {
  if (stream != NULL)
    delete stream;
}

SocketStream* ServerSocket::listen() {
  struct sockaddr_in client_addr;
  int client_addr_len = sizeof(client_addr);

  bzero((char*)&client_addr, client_addr_len);
  ::listen(fd, MAX_LISTEN_QUEUE);

  int client_fd =
      accept(fd, (struct sockaddr*)&client_addr, (socklen_t*)&client_addr_len);
  if (client_fd < 0)
    throw SocketException("Error during accaptance of remote client");
  return new SocketStream(client_fd);
}

ClientSocket::ClientSocket(SOCKET_TYPE type, int port,
                           const std::string& target)
    : Socket(type, port) {
  addr.sin_port = htons((unsigned short int)port);
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = inet_addr(target.c_str());

  // socklen_t addr_len = sizeof(addr);
  if (connect(fd, (struct sockaddr*)&addr, sizeof(addr))) {
    perror("connect:");
    throw SocketException("Could not connect to given target");
  }

  stream = new SocketStream(fd);
}

ClientSocket::~ClientSocket() {}

void StreamSelecter::add_stream(SocketStream* stream) {
  streams.push_back(stream);
}

void StreamSelecter::remove_stream(SocketStream* stream) {
  std::remove(streams.begin(), streams.end(), stream);
}

SocketStream* StreamSelecter::select() { return this->select(250000); }

SocketStream* StreamSelecter::select(unsigned int usecs) {
  FD_ZERO(&socks);
  // for(vector<SocketStream*>::iterator i=streams.begin(); i!=streams.end();
  // ++i)
  for (SocketStream* stream : streams)
    FD_SET(stream->fd, &socks);

  struct timeval timeout;
  timeout.tv_sec = 0;
  timeout.tv_usec = usecs;

  int readsocks =
      ::select(sizeof(socks) * 8, &socks, (fd_set*)0, (fd_set*)0, &timeout);

  if (readsocks == 0)
    return NULL;

  // for(vector<SocketStream*>::iterator i=streams.begin(); i!=streams.end();
  // ++i)
  for (SocketStream* stream : streams)
    if (FD_ISSET(stream->fd, &socks))
      return stream;

  return NULL;
}
<|endoftext|>


<commit_before>/*
* Copyright (c)2015 - 2016 Oasis LMF Limited
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   * Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in
*     the documentation and/or other materials provided with the
*     distribution.
*
*   * Neither the original author of this software nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/*
Author: Ben Matharu  email: ben.matharu@oasislmf.org
*/

#include "../include/oasis.h"
#include <iostream>
#include <vector>
#include <map>
#include <math.h>
#include <chrono>
#include <thread>

#if defined(_MSC_VER)
#include "../wingetopt/wingetopt.h"
#else
#include <unistd.h>
#endif

using namespace std;
struct period_occ {
	int period_no;
	int occ_date_id;
};

namespace pltcalc {
	bool firstOutput = true;
	std::map<int, std::vector<period_occ> > m_occ;
	int date_algorithm_ = 0;
	int samplesize_ = 0;

	void d(long long g, int& y, int& mm, int& dd)
	{
		y = (10000 * g + 14780) / 3652425;
		int ddd = (int) g - (365 * y + y / 4 - y / 100 + y / 400);
		if (ddd < 0) {
			y = y - 1;
			ddd = (int) g - (365 * y + y / 4 - y / 100 + y / 400);
		}
		int mi = (100 * ddd + 52) / 3060;
		mm = (mi + 2) % 12 + 1;
		y = y + (mi + 2) / 12;
		dd = ddd - (mi * 306 + 5) / 10 + 1;
		return;
	}

	void loadoccurrence()
	{
		FILE* fin = fopen(OCCURRENCE_FILE, "rb");
		if (fin == NULL) {
			fprintf(stderr, "%s: Error opening file %s\n", __func__, OCCURRENCE_FILE);
			exit(-1);
		}

		int no_of_periods = 0;
		occurrence occ;
		int i = fread(&date_algorithm_, sizeof(date_algorithm_), 1, fin);
		i = fread(&no_of_periods, sizeof(no_of_periods), 1, fin);
		i = fread(&occ, sizeof(occ), 1, fin);
		while (i != 0) {
			period_occ p;
			p.occ_date_id = occ.occ_date_id;
			p.period_no = occ.period_no;
			m_occ[occ.event_id].push_back(p);
			//event_to_periods[occ.event_id].push_back(occ.period_no);
			i = fread(&occ, sizeof(occ), 1, fin);
		}

		fclose(fin);

	}

	struct outrec {
		int type;
		int summary_id;
		int period_no;
		int event_id;
		OASIS_FLOAT mean;
		OASIS_FLOAT standard_deviation;
		OASIS_FLOAT exp_value;
		int occ_date_id;
	};
	void domeanout(const summarySampleslevelHeader& sh , OASIS_FLOAT mean_val)
	{
		std::vector<period_occ>& vp = m_occ[sh.event_id];
		outrec o;
		o.event_id = sh.event_id;
		o.summary_id = sh.summary_id;
		o.exp_value = sh.expval;
		o.mean = mean_val;
		o.standard_deviation = 0;
		for (auto p : vp) {
			o.period_no = p.period_no;
			o.occ_date_id = p.occ_date_id;
			if (date_algorithm_) {
				int occ_year, occ_month, occ_day;
				d(o.occ_date_id, occ_year, occ_month, occ_day);
				printf("%d,%d,%d,%d,%0.2f,%0.2f,%0.2f,%d,%d,%d\n",1, o.summary_id, o.period_no, o.event_id, o.mean, o.standard_deviation, o.exp_value, occ_year, occ_month, occ_day);
			}
			else {
				printf("%d,%d,%d,%d,%0.2f,%0.2f,%0.2f,%d\n", 1,o.summary_id, o.period_no, o.event_id, o.mean, o.standard_deviation, o.exp_value, o.occ_date_id);
			}
		}
	}
	void dopltcalc(const summarySampleslevelHeader& sh, const std::vector<sampleslevelRec>& vrec)
	{
		std::vector<period_occ>& vp = m_occ[sh.event_id];
		bool hasrec = false;
		bool firsttime = true;
		outrec o;
		o.event_id = sh.event_id;
		o.summary_id = sh.summary_id;
		o.exp_value = sh.expval;
		o.mean = 0;
		o.standard_deviation = 0;

		OASIS_FLOAT squared_loss_sum = 0;
		OASIS_FLOAT loss_sum = 0;
		for (auto p : vp) {
			o.period_no = p.period_no;
			o.occ_date_id = p.occ_date_id;
			if (firsttime == true) { // only do this once
				for (auto v : vrec) {
					if (v.sidx > 0) {
						hasrec = true;
						loss_sum += v.loss;
						squared_loss_sum += (v.loss * v.loss);
					}
				}
				firsttime = false;
			}
			if (hasrec) {
				o.mean = loss_sum / samplesize_;
				//o.standard_deviation = ((squared_loss_sum - loss_sum)/ samplesize_)/(samplesize_ -1);
				OASIS_FLOAT sd = (squared_loss_sum - ((loss_sum * loss_sum) / samplesize_)) / (samplesize_ - 1);
				OASIS_FLOAT x = sd / squared_loss_sum;
				if (x < 0.0000001) sd = 0;   // fix OASIS_FLOATing point precision problems caused by using large numbers
				o.standard_deviation = sqrt(sd);
				if (o.mean > 0 || o.standard_deviation > 0) {
					if (date_algorithm_) {
						int occ_year, occ_month, occ_day;
						d(o.occ_date_id, occ_year, occ_month, occ_day);
						printf("%d,%d,%d,%d,%0.2f,%0.2f,%0.2f,%d,%d,%d\n",2, o.summary_id, o.period_no, o.event_id, o.mean, o.standard_deviation, o.exp_value, occ_year, occ_month, occ_day);
					}
					else {
						printf("%d,%d,%d,%d,%0.2f,%0.2f,%0.2f,%d\n", 2, o.summary_id, o.period_no, o.event_id, o.mean, o.standard_deviation, o.exp_value, o.occ_date_id);
					}
				}
			}
		}

	}

	void doit(bool skipHeader)
	{
		loadoccurrence();
		int summarycalcstream_type = 0;
		int i = fread(&summarycalcstream_type, sizeof(summarycalcstream_type), 1, stdin);
		int stream_type = summarycalcstream_type & summarycalc_id;

		if (stream_type != summarycalc_id) {
			std::cerr << "Not a summarycalc stream type\n";
			exit(-1);
		}
		stream_type = streamno_mask & summarycalcstream_type;
		if (date_algorithm_) {
			if (skipHeader == false) printf("type, summary_id,period_no,event_id,mean,standard_deviation,exposure_value,occ_year,occ_month,occ_day\n");
		}
		else {
			if (skipHeader == false) printf("type, summary_id,period_no,event_id,mean,standard_deviation,exposure_value,occ_date_id\n");
		}

		if (firstOutput == true) {
			std::this_thread::sleep_for(std::chrono::milliseconds(PIPE_DELAY)); // used to stop possible race condition with kat
			firstOutput = false;
		}
		if (stream_type == 1) {
			int summary_set = 0;
			int j = 0;
			i = fread(&samplesize_, sizeof(samplesize_), 1, stdin);
			if (i != 0) i = fread(&summary_set, sizeof(summary_set), 1, stdin);
			std::vector<sampleslevelRec> vrec;
			summarySampleslevelHeader sh;
			while (i != 0) {
				i = fread(&sh, sizeof(sh), 1, stdin);
				while (i != 0) {
					sampleslevelRec sr;
					i = fread(&sr, sizeof(sr), 1, stdin);
					if (i == 0 || sr.sidx == 0) {
						dopltcalc(sh, vrec);
						vrec.clear();
						break;
					}
					if (sr.sidx == -1) {
						domeanout(sh, sr.loss);
					}else {
						vrec.push_back(sr);
					}
				}

				j++;
			}

		}
	}

}
<commit_msg>white space removed in pltcalc output<commit_after>/*
* Copyright (c)2015 - 2016 Oasis LMF Limited
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
*   * Redistributions of source code must retain the above copyright
*     notice, this list of conditions and the following disclaimer.
*
*   * Redistributions in binary form must reproduce the above copyright
*     notice, this list of conditions and the following disclaimer in
*     the documentation and/or other materials provided with the
*     distribution.
*
*   * Neither the original author of this software nor the names of its
*     contributors may be used to endorse or promote products derived
*     from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
* THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
* DAMAGE.
*/
/*
Author: Ben Matharu  email: ben.matharu@oasislmf.org
*/

#include "../include/oasis.h"
#include <iostream>
#include <vector>
#include <map>
#include <math.h>
#include <chrono>
#include <thread>

#if defined(_MSC_VER)
#include "../wingetopt/wingetopt.h"
#else
#include <unistd.h>
#endif

using namespace std;
struct period_occ {
	int period_no;
	int occ_date_id;
};

namespace pltcalc {
	bool firstOutput = true;
	std::map<int, std::vector<period_occ> > m_occ;
	int date_algorithm_ = 0;
	int samplesize_ = 0;

	void d(long long g, int& y, int& mm, int& dd)
	{
		y = (10000 * g + 14780) / 3652425;
		int ddd = (int) g - (365 * y + y / 4 - y / 100 + y / 400);
		if (ddd < 0) {
			y = y - 1;
			ddd = (int) g - (365 * y + y / 4 - y / 100 + y / 400);
		}
		int mi = (100 * ddd + 52) / 3060;
		mm = (mi + 2) % 12 + 1;
		y = y + (mi + 2) / 12;
		dd = ddd - (mi * 306 + 5) / 10 + 1;
		return;
	}

	void loadoccurrence()
	{
		FILE* fin = fopen(OCCURRENCE_FILE, "rb");
		if (fin == NULL) {
			fprintf(stderr, "%s: Error opening file %s\n", __func__, OCCURRENCE_FILE);
			exit(-1);
		}

		int no_of_periods = 0;
		occurrence occ;
		int i = fread(&date_algorithm_, sizeof(date_algorithm_), 1, fin);
		i = fread(&no_of_periods, sizeof(no_of_periods), 1, fin);
		i = fread(&occ, sizeof(occ), 1, fin);
		while (i != 0) {
			period_occ p;
			p.occ_date_id = occ.occ_date_id;
			p.period_no = occ.period_no;
			m_occ[occ.event_id].push_back(p);
			//event_to_periods[occ.event_id].push_back(occ.period_no);
			i = fread(&occ, sizeof(occ), 1, fin);
		}

		fclose(fin);

	}

	struct outrec {
		int type;
		int summary_id;
		int period_no;
		int event_id;
		OASIS_FLOAT mean;
		OASIS_FLOAT standard_deviation;
		OASIS_FLOAT exp_value;
		int occ_date_id;
	};
	void domeanout(const summarySampleslevelHeader& sh , OASIS_FLOAT mean_val)
	{
		std::vector<period_occ>& vp = m_occ[sh.event_id];
		outrec o;
		o.event_id = sh.event_id;
		o.summary_id = sh.summary_id;
		o.exp_value = sh.expval;
		o.mean = mean_val;
		o.standard_deviation = 0;
		for (auto p : vp) {
			o.period_no = p.period_no;
			o.occ_date_id = p.occ_date_id;
			if (date_algorithm_) {
				int occ_year, occ_month, occ_day;
				d(o.occ_date_id, occ_year, occ_month, occ_day);
				printf("%d,%d,%d,%d,%0.2f,%0.2f,%0.2f,%d,%d,%d\n",1, o.summary_id, o.period_no, o.event_id, o.mean, o.standard_deviation, o.exp_value, occ_year, occ_month, occ_day);
			}
			else {
				printf("%d,%d,%d,%d,%0.2f,%0.2f,%0.2f,%d\n", 1,o.summary_id, o.period_no, o.event_id, o.mean, o.standard_deviation, o.exp_value, o.occ_date_id);
			}
		}
	}
	void dopltcalc(const summarySampleslevelHeader& sh, const std::vector<sampleslevelRec>& vrec)
	{
		std::vector<period_occ>& vp = m_occ[sh.event_id];
		bool hasrec = false;
		bool firsttime = true;
		outrec o;
		o.event_id = sh.event_id;
		o.summary_id = sh.summary_id;
		o.exp_value = sh.expval;
		o.mean = 0;
		o.standard_deviation = 0;

		OASIS_FLOAT squared_loss_sum = 0;
		OASIS_FLOAT loss_sum = 0;
		for (auto p : vp) {
			o.period_no = p.period_no;
			o.occ_date_id = p.occ_date_id;
			if (firsttime == true) { // only do this once
				for (auto v : vrec) {
					if (v.sidx > 0) {
						hasrec = true;
						loss_sum += v.loss;
						squared_loss_sum += (v.loss * v.loss);
					}
				}
				firsttime = false;
			}
			if (hasrec) {
				o.mean = loss_sum / samplesize_;
				//o.standard_deviation = ((squared_loss_sum - loss_sum)/ samplesize_)/(samplesize_ -1);
				OASIS_FLOAT sd = (squared_loss_sum - ((loss_sum * loss_sum) / samplesize_)) / (samplesize_ - 1);
				OASIS_FLOAT x = sd / squared_loss_sum;
				if (x < 0.0000001) sd = 0;   // fix OASIS_FLOATing point precision problems caused by using large numbers
				o.standard_deviation = sqrt(sd);
				if (o.mean > 0 || o.standard_deviation > 0) {
					if (date_algorithm_) {
						int occ_year, occ_month, occ_day;
						d(o.occ_date_id, occ_year, occ_month, occ_day);
						printf("%d,%d,%d,%d,%0.2f,%0.2f,%0.2f,%d,%d,%d\n",2, o.summary_id, o.period_no, o.event_id, o.mean, o.standard_deviation, o.exp_value, occ_year, occ_month, occ_day);
					}
					else {
						printf("%d,%d,%d,%d,%0.2f,%0.2f,%0.2f,%d\n", 2, o.summary_id, o.period_no, o.event_id, o.mean, o.standard_deviation, o.exp_value, o.occ_date_id);
					}
				}
			}
		}

	}

	void doit(bool skipHeader)
	{
		loadoccurrence();
		int summarycalcstream_type = 0;
		int i = fread(&summarycalcstream_type, sizeof(summarycalcstream_type), 1, stdin);
		int stream_type = summarycalcstream_type & summarycalc_id;

		if (stream_type != summarycalc_id) {
			std::cerr << "Not a summarycalc stream type\n";
			exit(-1);
		}
		stream_type = streamno_mask & summarycalcstream_type;
		if (date_algorithm_) {
			if (skipHeader == false) printf("type,summary_id,period_no,event_id,mean,standard_deviation,exposure_value,occ_year,occ_month,occ_day\n");
		}
		else {
			if (skipHeader == false) printf("type,summary_id,period_no,event_id,mean,standard_deviation,exposure_value,occ_date_id\n");
		}

		if (firstOutput == true) {
			std::this_thread::sleep_for(std::chrono::milliseconds(PIPE_DELAY)); // used to stop possible race condition with kat
			firstOutput = false;
		}
		if (stream_type == 1) {
			int summary_set = 0;
			int j = 0;
			i = fread(&samplesize_, sizeof(samplesize_), 1, stdin);
			if (i != 0) i = fread(&summary_set, sizeof(summary_set), 1, stdin);
			std::vector<sampleslevelRec> vrec;
			summarySampleslevelHeader sh;
			while (i != 0) {
				i = fread(&sh, sizeof(sh), 1, stdin);
				while (i != 0) {
					sampleslevelRec sr;
					i = fread(&sr, sizeof(sr), 1, stdin);
					if (i == 0 || sr.sidx == 0) {
						dopltcalc(sh, vrec);
						vrec.clear();
						break;
					}
					if (sr.sidx == -1) {
						domeanout(sh, sr.loss);
					}else {
						vrec.push_back(sr);
					}
				}

				j++;
			}

		}
	}

}
<|endoftext|>


<commit_before>//
//  poScene.cpp
//  BasicTest
//
//  Created by Stephen Varga on 3/17/14.
//
//
#include "cinder/app/App.h"

#include "poScene.h"
#include "poNodeContainer.h"

namespace po {
    SceneRef Scene::create()
    {
        return create(po::NodeContainer::create());
    }

    SceneRef Scene::create(NodeContainerRef rootNode)
    {
        SceneRef scene(new Scene(rootNode));
        scene->getRootNode()->setScene(scene);
        return scene;
    }

    Scene::Scene(NodeContainerRef rootNode)
    : mRootNode(rootNode)
    , mAutoCam(true)
    , eventCenter(EventCenter::create())
    {
    }

    Scene::~Scene()
    {
    }

    void Scene::setDrawOffset(ci::Vec2f offset) {
        eventCenter->setInteractionOffset(offset);
    }

    #pragma mark -

    void Scene::update()
    {
        //Send a copy of all over our children to be processed
        processTrackingQueue();
        eventCenter->processEvents(allChildren);

        mRootNode->updateTree();

        if(mAutoCam)
            mCamera.setOrtho( 0, ci::app::getWindowWidth(), ci::app::getWindowHeight(), 0, -1, 1 );
    }

    void Scene::draw()
    {
        drawOrderCounter = 0;

        if (mAutoCam) {
			ci::gl::setMatricesWindow(ci::app::getWindowSize());
        }

        mRootNode->drawTree();

    }

    #pragma mark -

    uint32_t Scene::getNextDrawOrder()
    {
        return drawOrderCounter++;
    }

    void Scene::setRootNode(NodeContainerRef node)
    {
        if(node) {
            mRootNode->removeScene();
            mRootNode = node;
            mRootNode->setScene(shared_from_this());
        }
    }

    #pragma mark -
    void Scene::trackChildNode(NodeRef node) {
        mTrackingQueue[node] = true;
    }

    void Scene::untrackChildNode(NodeRef node) {
        mTrackingQueue[node] = false;
    }

    void Scene::processTrackingQueue()
    {
        for (auto &kv : mTrackingQueue) {
            if(kv.second) {
                allChildren.push_back(kv.first);
            }

            else {
                std::vector<NodeRef>::iterator iter = std::find(allChildren.begin(), allChildren.end(), kv.first);
                if(iter != allChildren.end())
                    allChildren.erase(iter);
            }
        }

        mTrackingQueue.clear();
    }
}
<commit_msg>Avoiding double addition of tracked objects<commit_after>//
//  poScene.cpp
//  BasicTest
//
//  Created by Stephen Varga on 3/17/14.
//
//
#include "cinder/app/App.h"

#include "poScene.h"
#include "poNodeContainer.h"

namespace po {
    SceneRef Scene::create()
    {
        return create(po::NodeContainer::create());
    }

    SceneRef Scene::create(NodeContainerRef rootNode)
    {
        SceneRef scene(new Scene(rootNode));
        scene->getRootNode()->setScene(scene);
        return scene;
    }

    Scene::Scene(NodeContainerRef rootNode)
    : mRootNode(rootNode)
    , mAutoCam(true)
    , eventCenter(EventCenter::create())
    {
    }

    Scene::~Scene()
    {
    }

    void Scene::setDrawOffset(ci::Vec2f offset) {
        eventCenter->setInteractionOffset(offset);
    }

    #pragma mark -

    void Scene::update()
    {
        //Send a copy of all over our children to be processed
        processTrackingQueue();
        eventCenter->processEvents(allChildren);

        mRootNode->updateTree();

        if(mAutoCam)
            mCamera.setOrtho( 0, ci::app::getWindowWidth(), ci::app::getWindowHeight(), 0, -1, 1 );
    }

    void Scene::draw()
    {
        drawOrderCounter = 0;

        if (mAutoCam) {
			ci::gl::setMatricesWindow(ci::app::getWindowSize());
        }

        mRootNode->drawTree();

    }

    #pragma mark -

    uint32_t Scene::getNextDrawOrder()
    {
        return drawOrderCounter++;
    }

    void Scene::setRootNode(NodeContainerRef node)
    {
        if(node) {
            mRootNode->removeScene();
            mRootNode = node;
            mRootNode->setScene(shared_from_this());
        }
    }

    #pragma mark -
    void Scene::trackChildNode(NodeRef node) {
        mTrackingQueue[node] = true;
    }

    void Scene::untrackChildNode(NodeRef node) {
        mTrackingQueue[node] = false;
    }

    void Scene::processTrackingQueue()
    {
        for (auto &kv : mTrackingQueue) {
            std::vector<NodeRef>::iterator iter = std::find(allChildren.begin(), allChildren.end(), kv.first);
            if(kv.second && iter == allChildren.end()) {
                allChildren.push_back(kv.first);
            }

            else {
                if(iter != allChildren.end())
                    allChildren.erase(iter);
            }
        }

        mTrackingQueue.clear();
    }
}
<|endoftext|>


<commit_before>/*
   position_record.cpp: ボードの状態を記録するクラスの実装。

   The MIT License (MIT)

   Copyright (c) 2014 Hironori Ishibashi

   Permission is hereby granted, free of charge, to any person obtaining a copy
   of this software and associated documentation files (the "Software"), to
   deal in the Software without restriction, including without limitation the
   rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
   sell copies of the Software, and to permit persons to whom the Software is
   furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included in
   all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
   IN THE SOFTWARE.
*/

#include "position_record.h"

#include <iostream>
#include "common.h"
#include "chess_engine.h"

namespace Sayuri {
  /**************************/
  /* コンストラクタと代入。 */
  /**************************/
  PositionRecord::PositionRecord(const ChessEngine& engine) {
    // 駒の配置をコピー。ついでにhas_castled_もコピー。
    for (Side side = 0; side < NUM_SIDES; side++) {
      has_castled_[side] = engine.has_castled()[side];
      for (Piece piece_type = 0; piece_type < NUM_PIECE_TYPES; piece_type++) {
        position_[side][piece_type] = engine.position()[side][piece_type];
      }
    }

    // それ以外をコピー。
    to_move_ = engine.to_move();
    castling_rights_ = engine.castling_rights();
    en_passant_square_ = engine.en_passant_square();
    ply_100_ = engine.ply_100();
    ply_ = engine.ply();
    pos_hash_ = engine.GetCurrentHash();
  }

  // デフォルトコンストラクタ。
  PositionRecord::PositionRecord() :
  to_move_(NO_SIDE),
  castling_rights_(0),
  en_passant_square_(0),
  ply_100_(0),
  ply_(0),
  pos_hash_(0) {
    for (Side side = 0; side < NUM_SIDES; side++) {
      has_castled_[side] = false;
      for (Piece piece_type = 0; piece_type < NUM_PIECE_TYPES; piece_type++) {
        position_[side][piece_type] = 0;
      }
    }
  }

  // コピーコンストラクタ。
  PositionRecord::PositionRecord(const PositionRecord& record) {
    ScanMember(record);
  }

  // ムーブコンストラクタ。
  PositionRecord::PositionRecord(PositionRecord&& record) {
    ScanMember(record);
  }

  // コピー代入演算子。
  PositionRecord& PositionRecord::operator=(const PositionRecord& record) {
    ScanMember(record);
    return *this;
  }

  // ムーブ代入演算子。
  PositionRecord& PositionRecord::operator=(PositionRecord&& record) {
    ScanMember(record);
    return *this;
  }

  /****************/
  /* 比較演算子。 */
  /****************/
  bool PositionRecord::operator==(const ChessEngine& engine) const {
    if (pos_hash_ != engine.GetCurrentHash()) return false;
    if (to_move_ != engine.to_move()) return false;
    if (castling_rights_ != engine.castling_rights()) return false;
    if (en_passant_square_ != engine.en_passant_square()) return false;
    for (Side side = WHITE; side <= BLACK; side++) {
      for (Piece piece_type = PAWN; piece_type <= KING; piece_type++) {
        if (position_[side][piece_type]
        != engine.position()[side][piece_type]) {
          return false;
        }
      }
    }

    return true;
  }

  bool PositionRecord::operator!=(const ChessEngine& engine) const {
    if (pos_hash_ != engine.GetCurrentHash()) return true;
    if (to_move_ != engine.to_move()) return true;
    if (castling_rights_ != engine.castling_rights()) return true;
    if (en_passant_square_ != engine.en_passant_square()) return true;
    for (Side side = WHITE; side <= BLACK; side++) {
      for (Piece piece_type = PAWN; piece_type <= KING; piece_type++) {
        if (position_[side][piece_type]
        != engine.position()[side][piece_type]) {
          return true;
        }
      }
    }

    return false;
  }

  bool PositionRecord::operator==(const PositionRecord& record) const {
    if (pos_hash_ != record.pos_hash_) return false;
    if (to_move_ != record.to_move_) return false;
    if (castling_rights_ != record.castling_rights_) return false;
    if (en_passant_square_ != record.en_passant_square_) return false;
    for (Side side = WHITE; side <= BLACK; side++) {
      for (Piece piece_type = PAWN; piece_type <= KING; piece_type++) {
        if (position_[side][piece_type]
        != record.position_[side][piece_type]) {
          return false;
        }
      }
    }

    return true;
  }

  bool PositionRecord::operator!=(const PositionRecord& record) const {
    if (pos_hash_ != record.pos_hash_) return true;
    if (to_move_ != record.to_move_) return true;
    if (castling_rights_ != record.castling_rights_) return true;
    if (en_passant_square_ != record.en_passant_square_) return true;
    for (Side side = WHITE; side <= BLACK; side++) {
      for (Piece piece_type = PAWN; piece_type <= KING; piece_type++) {
        if (position_[side][piece_type]
        != record.position_[side][piece_type]) {
          return true;
        }
      }
    }

    return true;
  }

  /**********************/
  /* プライベート関数。 */
  /**********************/
  // メンバをコピーする。
  void PositionRecord::ScanMember(const PositionRecord& record) {
    // 駒の配置をコピー。
    for (Side side = 0; side < NUM_SIDES; side++) {
      has_castled_[side] = record.has_castled_[side];
      for (Piece piece_type = 0; piece_type < NUM_PIECE_TYPES; piece_type++) {
        position_[side][piece_type] = record.position_[side][piece_type];
      }
    }

    // その他をコピー。
    to_move_ = record.to_move_;
    castling_rights_ = record.castling_rights_;
    en_passant_square_ = record.en_passant_square_;
    ply_100_ = record.ply_100_;
    ply_ = record.ply_;
    pos_hash_ = record.pos_hash_;
  }
}  // namespace Sayuri
<commit_msg>position_record.cppのDoxygen化<commit_after>/* The MIT License (MIT)
 *
 * Copyright (c) 2014 Hironori Ishibashi
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to
 * deal in the Software without restriction, including without limitation the
 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
 * sell copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 * IN THE SOFTWARE.
 */

/**
 * @file position_record.cpp
 * @author Hironori Ishibashi
 * @brief エンジンのボードの状態を記録するクラスの実装。
 */

#include "position_record.h"

#include <iostream>
#include "common.h"
#include "chess_engine.h"

/** Sayuri 名前空間。 */
namespace Sayuri {
  // ==================== //
  // コンストラクタと代入 //
  // ==================== //
  // コンストラクタ。
  PositionRecord::PositionRecord(const ChessEngine& engine) {
    // 駒の配置をコピー。ついでにhas_castled_もコピー。
    for (Side side = 0; side < NUM_SIDES; side++) {
      has_castled_[side] = engine.has_castled()[side];
      for (Piece piece_type = 0; piece_type < NUM_PIECE_TYPES; piece_type++) {
        position_[side][piece_type] = engine.position()[side][piece_type];
      }
    }

    // それ以外をコピー。
    to_move_ = engine.to_move();
    castling_rights_ = engine.castling_rights();
    en_passant_square_ = engine.en_passant_square();
    ply_100_ = engine.ply_100();
    ply_ = engine.ply();
    pos_hash_ = engine.GetCurrentHash();
  }

  // コンストラクタ。
  PositionRecord::PositionRecord() :
  to_move_(NO_SIDE),
  castling_rights_(0),
  en_passant_square_(0),
  ply_100_(0),
  ply_(0),
  pos_hash_(0) {
    for (Side side = 0; side < NUM_SIDES; side++) {
      has_castled_[side] = false;
      for (Piece piece_type = 0; piece_type < NUM_PIECE_TYPES; piece_type++) {
        position_[side][piece_type] = 0;
      }
    }
  }

  // コピーコンストラクタ。
  PositionRecord::PositionRecord(const PositionRecord& record) {
    ScanMember(record);
  }

  // ムーブコンストラクタ。
  PositionRecord::PositionRecord(PositionRecord&& record) {
    ScanMember(record);
  }

  // コピー代入演算子。
  PositionRecord& PositionRecord::operator=(const PositionRecord& record) {
    ScanMember(record);
    return *this;
  }

  // ムーブ代入演算子。
  PositionRecord& PositionRecord::operator=(PositionRecord&& record) {
    ScanMember(record);
    return *this;
  }

  // ========== //
  // 比較演算子 //
  // ========== //
  bool PositionRecord::operator==(const ChessEngine& engine) const {
    if (pos_hash_ != engine.GetCurrentHash()) return false;
    if (to_move_ != engine.to_move()) return false;
    if (castling_rights_ != engine.castling_rights()) return false;
    if (en_passant_square_ != engine.en_passant_square()) return false;
    for (Side side = WHITE; side <= BLACK; side++) {
      for (Piece piece_type = PAWN; piece_type <= KING; piece_type++) {
        if (position_[side][piece_type]
        != engine.position()[side][piece_type]) {
          return false;
        }
      }
    }

    return true;
  }

  bool PositionRecord::operator!=(const ChessEngine& engine) const {
    if (pos_hash_ != engine.GetCurrentHash()) return true;
    if (to_move_ != engine.to_move()) return true;
    if (castling_rights_ != engine.castling_rights()) return true;
    if (en_passant_square_ != engine.en_passant_square()) return true;
    for (Side side = WHITE; side <= BLACK; side++) {
      for (Piece piece_type = PAWN; piece_type <= KING; piece_type++) {
        if (position_[side][piece_type]
        != engine.position()[side][piece_type]) {
          return true;
        }
      }
    }

    return false;
  }

  bool PositionRecord::operator==(const PositionRecord& record) const {
    if (pos_hash_ != record.pos_hash_) return false;
    if (to_move_ != record.to_move_) return false;
    if (castling_rights_ != record.castling_rights_) return false;
    if (en_passant_square_ != record.en_passant_square_) return false;
    for (Side side = WHITE; side <= BLACK; side++) {
      for (Piece piece_type = PAWN; piece_type <= KING; piece_type++) {
        if (position_[side][piece_type]
        != record.position_[side][piece_type]) {
          return false;
        }
      }
    }

    return true;
  }

  bool PositionRecord::operator!=(const PositionRecord& record) const {
    if (pos_hash_ != record.pos_hash_) return true;
    if (to_move_ != record.to_move_) return true;
    if (castling_rights_ != record.castling_rights_) return true;
    if (en_passant_square_ != record.en_passant_square_) return true;
    for (Side side = WHITE; side <= BLACK; side++) {
      for (Piece piece_type = PAWN; piece_type <= KING; piece_type++) {
        if (position_[side][piece_type]
        != record.position_[side][piece_type]) {
          return true;
        }
      }
    }

    return true;
  }

  // ================ //
  // プライベート関数 //
  // ================ //
  // メンバをコピーする。
  void PositionRecord::ScanMember(const PositionRecord& record) {
    // 駒の配置をコピー。
    for (Side side = 0; side < NUM_SIDES; side++) {
      has_castled_[side] = record.has_castled_[side];
      for (Piece piece_type = 0; piece_type < NUM_PIECE_TYPES; piece_type++) {
        position_[side][piece_type] = record.position_[side][piece_type];
      }
    }

    // その他をコピー。
    to_move_ = record.to_move_;
    castling_rights_ = record.castling_rights_;
    en_passant_square_ = record.en_passant_square_;
    ply_100_ = record.ply_100_;
    ply_ = record.ply_;
    pos_hash_ = record.pos_hash_;
  }
}  // namespace Sayuri
<|endoftext|>


<commit_before>
#include <libclientserver.h>

/**
 * Init
 *
 * This should be called to intialize any base class member variables and state.
 *
 */
void ClientBase::Init()
{
	memset(&m_SoftTimeout, 0, sizeof(m_SoftTimeout));
	memset(&m_HardTimeout, 0, sizeof(m_HardTimeout));
	memset(&m_ReConnectDelay, 0, sizeof(m_ReConnectDelay));

	m_SoftTimeout.tv_sec = 5;
	m_HardTimeout.tv_sec = 30;
	m_ReConnectDelay.tv_sec = 1;

	m_LastID = 1;

	m_Handler = NULL;
}

/**
 * WaitForConnect
 *
 * This function provides a method that will sleep until the client reaches a connected state to the server.
 * Please be aware that this function will not return until a connection has been made.
 * However when it returns it is possible the that client could have also been disconnected from the server again.
 */
void ClientBase::WaitForConnect()
{
	struct timespec ts;
	ts.tv_sec = 30;
	ts.tv_nsec = 0;
	while(WaitForConnect(&ts) == false) { }
}

/**
 * WaitForConnect
 * @param[in] Timeout The specified time to wait before returning
 * @return If a connection was made.
 *
 * This function provides a method that will sleep until the client reaches a connected state to the server. Or until the value in timeout has elasped
 * However when it returns it is possible the that client could have also been disconnected from the server again. Event when the function returns true.
 */
bool ClientBase::WaitForConnect(const struct timespec *Timeout)
{
	ScopedLock lock(&m_ConnectedMutex);

	while(IsConnected() == false)
	{
		if (m_ConnectedMutex.Wait(Timeout) == 0)
		{
			if (IsConnected())
				return true;
		}
	}

	return IsConnected();
}

/**
 * SetReConnectDelay
 * @param[in] Timeout The time to wait before retrying a connection
 *
 * This function sets the retry time between connections to the server.
 *
 */
void ClientBase::SetReConnectDelay(const struct timespec *Timeout)
{
	memcpy(&m_ReConnectDelay, Timeout, sizeof(m_ReConnectDelay));
}

/**
 * SetSoftTimeout
 * @params[in] Timeout value
 *
 * This function will set the default soft timeout value when sending requests
 * The function will take a copy of the struture that SoftTimeout points to.
 *
 * The soft timeout values can be overridded by the server. If the server sends keepalive messages
 */
void ClientBase::SetSoftTimeout(const struct timespec *SoftTimeout)
{
	memcpy(&m_SoftTimeout, SoftTimeout, sizeof(m_SoftTimeout));
}

/**
 * SetHardTimeout
 * @params[in] Timeout value
 *
 * This function will set the default hard timeout value when sending requests
 * The function will take a copy of the struture that HardTimeout points to.
 *
 * The hard timeout value will never be ignored when sending requests.
 * If it is ignored then it should be considered a bug.
 */
void ClientBase::SetHardTimeout(const struct timespec *HardTimeout)
{
	memcpy(&m_HardTimeout, HardTimeout, sizeof(m_HardTimeout));
}

/**
 * SetHandler
 * @params[in] Handler
 *
 * Register a Handler class which is used by the client so that the client implmenetation can take certain actions when various events occur.
 * These event happen during Disconnect / Connect / Errors
 *
 */
void ClientBase::SetHandler(IClientHandler *Handler)
{
	m_Handler = Handler;
}

/**
 * SendRequest
 * @param[in] request The Client Request
 * @param[out] response The Server Response
 * @param[in] SoftTimeout The soft timeout value
 * @param[in] HardTimeout The hard timeout value
 * @return True when a response is recived from the server
 *
 * This function is the full version of SendRequest with arugments for setting both the Soft/Hard timeout functions.
 * the Soft/Hard timeout values that are specified to this function will override any default that have been set.
 *
 * If the function returns false. The contents of the response will be undefined.
 */
int ClientBase::SendRequest(Request *request, Request *response, const struct timespec *SoftTimeout, const struct timespec *HardTimeout)
{
	struct RequestMapEntry Entry;

	memset(&Entry, 0, sizeof(Entry));
	Entry.id = m_LastID++;
	Entry.Response = response;
	Entry.ValidResponse = false;
	Entry.KeepAlive = false;

	request->SetID(Entry.id);

	request->SetArg("_TIMEOUT_SOFT", Encoder::ToStr(SoftTimeout));
	request->SetArg("_TIMEOUT_HARD", Encoder::ToStr(HardTimeout));

	m_rmap.Add(&Entry);
	if (DoSendRequest(request, SoftTimeout) == false)	//Get Out quickly option - happens when we are disconnected
	{
		m_rmap.Remove(&Entry);
		return -ETIMEDOUT;
	}
	m_rmap.Wait(&Entry, SoftTimeout, HardTimeout);
	m_rmap.Remove(&Entry);

	if (Entry.ValidResponse == false)
		return -ETIMEDOUT;

	if (response->HasArg("_ERRNO"))
	{
		int myerr = 0;
		if (Decoder::ToInt(response->GetArg("_ERRNO"), &myerr) == false)
			return -EINVAL;
		return -myerr;
	}
	else
	{
		abort(); //This is a bug - Ntoe the fact that this calls abort. The fact that you should never reach here!
	}

	return Entry.ValidResponse;
}

/**
 * SendRequest
 * @param[in] request The Client Request
 * @param[out] response The Server Response
 * @param[in] SoftTimeout The soft timeout value
 *
 * This function is the partial version of SendRequest with arugments for setting both the Soft timeout functions.
 * the Soft timeout values that are specified to this function will override any default that have been set.
 *
 * the hard timeout value that will be used is the default configured value on the instance of the class.
 *
 * For more details please read the documentation on the full function.
 */
int ClientBase::SendRequest(Request *request, Request *response, const struct timespec *SoftTimeout)
{
	return SendRequest(request, response, SoftTimeout, &m_HardTimeout);
}

/**
 * SendRequest
 * @param[in] request The Client Request
 * @param[out] response The Server Response
 *
 * This is the basic function for sending a request where the default values of Soft/Hard timeout will be used.
 * For more details please read the documentation on the full function.
 */
int ClientBase::SendRequest(Request *request, Request *response)
{
	return SendRequest(request, response, &m_SoftTimeout, &m_HardTimeout);
}

/**
 * SendCommand
 * @param[in] command
 * @param[in] Timeout
 * @return True when successful
 *
 * Note this function can return True even when sending the command is not successful. It Only states that the command was queued to be send to the server.
 * If the Client is not Connected to the server then this function will immeditatly return false.
 */
int ClientBase::SendCommand(Request *command, const struct timespec *Timeout)
{
	return DoSendCommand(command, Timeout);
}

/**
 * SendCommand
 * @param[in] command
 * @param[in] Timeout
 * @return True when successful
 *
 * Note this function can return True even when sending the command is not successful. It Only states that the command was queued to be send to the server.
 * If the Client is not Connected to the server then this function will immeditatly return false.
 */
int ClientBase::SendCommand(Request *command)
{
	return SendCommand(command, &m_SoftTimeout);
}

/**
 * DoSendRequest
 * @param[in] request
 * @param[in] Timeout
 *
 * This function is used to sending the request for the client.
 * Note that the soft timeout value should be passed to the timeout argument to this function.
 * The hard timeout value is no longer required as the server does not have the request until we complete.
 */
bool ClientBase::DoSendRequest(Request *request, const struct timespec *Timeout)
{
	std::string str = "REQUEST " + request->Encode() + "\n";
	return SendLine(&str, Timeout);
}

/**
 * DoSendCommand
 * @param[in] request
 * @param[in] Timeout
 *
 * This function is used to sending the request for the client.
 * Note that the soft timeout value should be passed to the timeout argument to this function.
 * the hard timeout value is not used for commands
 */
bool ClientBase::DoSendCommand(Request *request, const struct timespec *Timeout)
{
	std::string str = "COMMAND " + request->Encode() + "\n";
	return SendLine(&str, Timeout);
}

/**
 * GetNextID
 * @return The next avilable ID
 *
 * This function is used to generate a unique index for every request that is sent by the client
 */
uint64_t ClientBase::GetNextID()
{
	ScopedLock lock(&m_LastIDMutex);
	m_LastID++;
	return m_LastID;
}

/**
 * RaiseOnConnect
 *
 * This function is called when a client makes a connection to the server
 */
void ClientBase::RaiseOnConnect()
{
	ScopedLock lock(&m_ConnectedMutex);
	m_connected = true;
	m_ConnectedMutex.WakeUpAll();

	if (m_Handler != NULL)
		m_Handler->OnConnect();
}

/**
 * RaiseOnConnectError
 * @param[in] err the contents of errno when the error occured
 * @param[in] str a text version of the error
 *
 * The function is called every time a connection fails to the server
 */
void ClientBase::RaiseOnConnectError(int err, const std::string &str)
{
	if (m_Handler != NULL)
		m_Handler->OnConnectError(err, str);
}

/**
 * RaiseOnSendError
 * @param[in] err the contents of errno when the error occured
 * @param[in] str a text version of the error
 *
 * The function is called when there is an error sending data to the server
 */
void ClientBase::RaiseOnSendError(int err, const std::string &str)
{
	if (m_Handler != NULL)
		m_Handler->OnSendError(err, str);
}

/**
 * RaiseOnDisconnect
 * @param[in] err the contents of errno when the error occured
 * @param[in] str a text version of the error
 *
 * The function is called when the client disconnects from the server for any reason.
 * Note that the err value may indicate success which is valid and only suggests that the connection
 * was shutdown cleanly as requested
 */
void ClientBase::RaiseOnDisconnect(int err, const std::string &str)
{
	ScopedLock lock(&m_ConnectedMutex);
	m_connected = false;

	if (m_Handler != NULL)
		m_Handler->OnDisconnect(err, str);
}

/**
 * RaiseOnResponse
 * @param[in] response
 *
 * This function is called when a response is recived by the client
 */
void ClientBase::RaiseOnResponse(Request *response)
{
	if (m_Handler != NULL)
	{
		if (m_Handler->OnResponse(response) == false)
		{
			return;
		}
	}
	m_rmap.WakeUp(response);
}

/**
 * RaiseOnKeepAlive
 * @param[in] response
 *
 * This function is called when a keepalive is recived by the client
 */
void ClientBase::RaiseOnKeepAlive(Request *response)
{
	if (m_Handler != NULL)
	{
		if (m_Handler->OnKeepAlive(response) == false)
		{
			return;
		}
	}
	m_rmap.KeepAlive(response);
}

/**
 * RaiseOnEvent
 * @param[in] event
 *
 * This function is called when an event is recived by the client
 */
void ClientBase::RaiseOnEvent(Request *event)
{
	if (m_Handler != NULL)
	{
		if (m_Handler->OnEvent(event) == false)
		{
			return;
		}
	}
}

/**
 * RaiseOnData
 * @param[in] str
 *
 * This function is called when a line of data is recived by the client
 */
void ClientBase::RaiseOnData(const std::string *str)
{
	std::string command = "";
	std::string args = "";

	if (String::SplitOne(str, &command, &args, " ") == false)
	{
		RaiseOnBadLine(str);
		return;
	}

	if (command == "RESPONSE")
	{
		Request response;
		if (response.Decode(&args) == false)
		{
			RaiseOnBadLine(str);
			return;
		}
		RaiseOnResponse(&response);
		return;
	}

	if (command == "KEEPALIVE")
	{
		Request keepalive;
		if (keepalive.Decode(&args) == false)
		{
			RaiseOnBadLine(str);
			return;
		}
		RaiseOnKeepAlive(&keepalive);
		return;
	}

	if (command == "EVENT")
	{
		Request event;
		if (event.Decode(&args) == false)
		{
			RaiseOnBadLine(str);
			return;
		}
		RaiseOnEvent(&event);
		return;
	}

	RaiseOnBadLine(str);
	return;
}

/**
 * RaiseOnBadLine
 * @param[in] str
 *
 * This function is called when a line of bad data / non-parseable data is recived by the client
 */
void ClientBase::RaiseOnBadLine(const std::string *str)
{
	if (m_Handler != NULL)
		m_Handler->OnBadLine(str);

	abort();
}

<commit_msg>Make sure if errno is set it returns the correct value, also fixed a typo in a comment<commit_after>
#include <libclientserver.h>

/**
 * Init
 *
 * This should be called to intialize any base class member variables and state.
 *
 */
void ClientBase::Init()
{
	memset(&m_SoftTimeout, 0, sizeof(m_SoftTimeout));
	memset(&m_HardTimeout, 0, sizeof(m_HardTimeout));
	memset(&m_ReConnectDelay, 0, sizeof(m_ReConnectDelay));

	m_SoftTimeout.tv_sec = 5;
	m_HardTimeout.tv_sec = 30;
	m_ReConnectDelay.tv_sec = 1;

	m_LastID = 1;

	m_Handler = NULL;
}

/**
 * WaitForConnect
 *
 * This function provides a method that will sleep until the client reaches a connected state to the server.
 * Please be aware that this function will not return until a connection has been made.
 * However when it returns it is possible the that client could have also been disconnected from the server again.
 */
void ClientBase::WaitForConnect()
{
	struct timespec ts;
	ts.tv_sec = 30;
	ts.tv_nsec = 0;
	while(WaitForConnect(&ts) == false) { }
}

/**
 * WaitForConnect
 * @param[in] Timeout The specified time to wait before returning
 * @return If a connection was made.
 *
 * This function provides a method that will sleep until the client reaches a connected state to the server. Or until the value in timeout has elasped
 * However when it returns it is possible the that client could have also been disconnected from the server again. Event when the function returns true.
 */
bool ClientBase::WaitForConnect(const struct timespec *Timeout)
{
	ScopedLock lock(&m_ConnectedMutex);

	while(IsConnected() == false)
	{
		if (m_ConnectedMutex.Wait(Timeout) == 0)
		{
			if (IsConnected())
				return true;
		}
	}

	return IsConnected();
}

/**
 * SetReConnectDelay
 * @param[in] Timeout The time to wait before retrying a connection
 *
 * This function sets the retry time between connections to the server.
 *
 */
void ClientBase::SetReConnectDelay(const struct timespec *Timeout)
{
	memcpy(&m_ReConnectDelay, Timeout, sizeof(m_ReConnectDelay));
}

/**
 * SetSoftTimeout
 * @params[in] Timeout value
 *
 * This function will set the default soft timeout value when sending requests
 * The function will take a copy of the struture that SoftTimeout points to.
 *
 * The soft timeout values can be overridded by the server. If the server sends keepalive messages
 */
void ClientBase::SetSoftTimeout(const struct timespec *SoftTimeout)
{
	memcpy(&m_SoftTimeout, SoftTimeout, sizeof(m_SoftTimeout));
}

/**
 * SetHardTimeout
 * @params[in] Timeout value
 *
 * This function will set the default hard timeout value when sending requests
 * The function will take a copy of the struture that HardTimeout points to.
 *
 * The hard timeout value will never be ignored when sending requests.
 * If it is ignored then it should be considered a bug.
 */
void ClientBase::SetHardTimeout(const struct timespec *HardTimeout)
{
	memcpy(&m_HardTimeout, HardTimeout, sizeof(m_HardTimeout));
}

/**
 * SetHandler
 * @params[in] Handler
 *
 * Register a Handler class which is used by the client so that the client implmenetation can take certain actions when various events occur.
 * These event happen during Disconnect / Connect / Errors
 *
 */
void ClientBase::SetHandler(IClientHandler *Handler)
{
	m_Handler = Handler;
}

/**
 * SendRequest
 * @param[in] request The Client Request
 * @param[out] response The Server Response
 * @param[in] SoftTimeout The soft timeout value
 * @param[in] HardTimeout The hard timeout value
 * @return True when a response is recived from the server
 *
 * This function is the full version of SendRequest with arugments for setting both the Soft/Hard timeout functions.
 * the Soft/Hard timeout values that are specified to this function will override any default that have been set.
 *
 * If the function returns false. The contents of the response will be undefined.
 */
int ClientBase::SendRequest(Request *request, Request *response, const struct timespec *SoftTimeout, const struct timespec *HardTimeout)
{
	struct RequestMapEntry Entry;

	memset(&Entry, 0, sizeof(Entry));
	Entry.id = m_LastID++;
	Entry.Response = response;
	Entry.ValidResponse = false;
	Entry.KeepAlive = false;

	request->SetID(Entry.id);

	request->SetArg("_TIMEOUT_SOFT", Encoder::ToStr(SoftTimeout));
	request->SetArg("_TIMEOUT_HARD", Encoder::ToStr(HardTimeout));

	m_rmap.Add(&Entry);
	if (DoSendRequest(request, SoftTimeout) == false)	//Get Out quickly option - happens when we are disconnected
	{
		m_rmap.Remove(&Entry);
		return -ETIMEDOUT;
	}
	m_rmap.Wait(&Entry, SoftTimeout, HardTimeout);
	m_rmap.Remove(&Entry);

	if (Entry.ValidResponse == false)
		return -ETIMEDOUT;

	if (response->HasArg("_ERRNO"))
	{
		int myerr = 0;
		if (Decoder::ToInt(response->GetArg("_ERRNO"), &myerr) == false)
			return -EINVAL;
		return myerr;
	}
	else
	{
		abort(); //This is a bug - Note the fact that this calls abort. The fact that you should never reach here!
	}

	return Entry.ValidResponse;
}

/**
 * SendRequest
 * @param[in] request The Client Request
 * @param[out] response The Server Response
 * @param[in] SoftTimeout The soft timeout value
 *
 * This function is the partial version of SendRequest with arugments for setting both the Soft timeout functions.
 * the Soft timeout values that are specified to this function will override any default that have been set.
 *
 * the hard timeout value that will be used is the default configured value on the instance of the class.
 *
 * For more details please read the documentation on the full function.
 */
int ClientBase::SendRequest(Request *request, Request *response, const struct timespec *SoftTimeout)
{
	return SendRequest(request, response, SoftTimeout, &m_HardTimeout);
}

/**
 * SendRequest
 * @param[in] request The Client Request
 * @param[out] response The Server Response
 *
 * This is the basic function for sending a request where the default values of Soft/Hard timeout will be used.
 * For more details please read the documentation on the full function.
 */
int ClientBase::SendRequest(Request *request, Request *response)
{
	return SendRequest(request, response, &m_SoftTimeout, &m_HardTimeout);
}

/**
 * SendCommand
 * @param[in] command
 * @param[in] Timeout
 * @return True when successful
 *
 * Note this function can return True even when sending the command is not successful. It Only states that the command was queued to be send to the server.
 * If the Client is not Connected to the server then this function will immeditatly return false.
 */
int ClientBase::SendCommand(Request *command, const struct timespec *Timeout)
{
	return DoSendCommand(command, Timeout);
}

/**
 * SendCommand
 * @param[in] command
 * @param[in] Timeout
 * @return True when successful
 *
 * Note this function can return True even when sending the command is not successful. It Only states that the command was queued to be send to the server.
 * If the Client is not Connected to the server then this function will immeditatly return false.
 */
int ClientBase::SendCommand(Request *command)
{
	return SendCommand(command, &m_SoftTimeout);
}

/**
 * DoSendRequest
 * @param[in] request
 * @param[in] Timeout
 *
 * This function is used to sending the request for the client.
 * Note that the soft timeout value should be passed to the timeout argument to this function.
 * The hard timeout value is no longer required as the server does not have the request until we complete.
 */
bool ClientBase::DoSendRequest(Request *request, const struct timespec *Timeout)
{
	std::string str = "REQUEST " + request->Encode() + "\n";
	return SendLine(&str, Timeout);
}

/**
 * DoSendCommand
 * @param[in] request
 * @param[in] Timeout
 *
 * This function is used to sending the request for the client.
 * Note that the soft timeout value should be passed to the timeout argument to this function.
 * the hard timeout value is not used for commands
 */
bool ClientBase::DoSendCommand(Request *request, const struct timespec *Timeout)
{
	std::string str = "COMMAND " + request->Encode() + "\n";
	return SendLine(&str, Timeout);
}

/**
 * GetNextID
 * @return The next avilable ID
 *
 * This function is used to generate a unique index for every request that is sent by the client
 */
uint64_t ClientBase::GetNextID()
{
	ScopedLock lock(&m_LastIDMutex);
	m_LastID++;
	return m_LastID;
}

/**
 * RaiseOnConnect
 *
 * This function is called when a client makes a connection to the server
 */
void ClientBase::RaiseOnConnect()
{
	ScopedLock lock(&m_ConnectedMutex);
	m_connected = true;
	m_ConnectedMutex.WakeUpAll();

	if (m_Handler != NULL)
		m_Handler->OnConnect();
}

/**
 * RaiseOnConnectError
 * @param[in] err the contents of errno when the error occured
 * @param[in] str a text version of the error
 *
 * The function is called every time a connection fails to the server
 */
void ClientBase::RaiseOnConnectError(int err, const std::string &str)
{
	if (m_Handler != NULL)
		m_Handler->OnConnectError(err, str);
}

/**
 * RaiseOnSendError
 * @param[in] err the contents of errno when the error occured
 * @param[in] str a text version of the error
 *
 * The function is called when there is an error sending data to the server
 */
void ClientBase::RaiseOnSendError(int err, const std::string &str)
{
	if (m_Handler != NULL)
		m_Handler->OnSendError(err, str);
}

/**
 * RaiseOnDisconnect
 * @param[in] err the contents of errno when the error occured
 * @param[in] str a text version of the error
 *
 * The function is called when the client disconnects from the server for any reason.
 * Note that the err value may indicate success which is valid and only suggests that the connection
 * was shutdown cleanly as requested
 */
void ClientBase::RaiseOnDisconnect(int err, const std::string &str)
{
	ScopedLock lock(&m_ConnectedMutex);
	m_connected = false;

	if (m_Handler != NULL)
		m_Handler->OnDisconnect(err, str);
}

/**
 * RaiseOnResponse
 * @param[in] response
 *
 * This function is called when a response is recived by the client
 */
void ClientBase::RaiseOnResponse(Request *response)
{
	if (m_Handler != NULL)
	{
		if (m_Handler->OnResponse(response) == false)
		{
			return;
		}
	}
	m_rmap.WakeUp(response);
}

/**
 * RaiseOnKeepAlive
 * @param[in] response
 *
 * This function is called when a keepalive is recived by the client
 */
void ClientBase::RaiseOnKeepAlive(Request *response)
{
	if (m_Handler != NULL)
	{
		if (m_Handler->OnKeepAlive(response) == false)
		{
			return;
		}
	}
	m_rmap.KeepAlive(response);
}

/**
 * RaiseOnEvent
 * @param[in] event
 *
 * This function is called when an event is recived by the client
 */
void ClientBase::RaiseOnEvent(Request *event)
{
	if (m_Handler != NULL)
	{
		if (m_Handler->OnEvent(event) == false)
		{
			return;
		}
	}
}

/**
 * RaiseOnData
 * @param[in] str
 *
 * This function is called when a line of data is recived by the client
 */
void ClientBase::RaiseOnData(const std::string *str)
{
	std::string command = "";
	std::string args = "";

	if (String::SplitOne(str, &command, &args, " ") == false)
	{
		RaiseOnBadLine(str);
		return;
	}

	if (command == "RESPONSE")
	{
		Request response;
		if (response.Decode(&args) == false)
		{
			RaiseOnBadLine(str);
			return;
		}
		RaiseOnResponse(&response);
		return;
	}

	if (command == "KEEPALIVE")
	{
		Request keepalive;
		if (keepalive.Decode(&args) == false)
		{
			RaiseOnBadLine(str);
			return;
		}
		RaiseOnKeepAlive(&keepalive);
		return;
	}

	if (command == "EVENT")
	{
		Request event;
		if (event.Decode(&args) == false)
		{
			RaiseOnBadLine(str);
			return;
		}
		RaiseOnEvent(&event);
		return;
	}

	RaiseOnBadLine(str);
	return;
}

/**
 * RaiseOnBadLine
 * @param[in] str
 *
 * This function is called when a line of bad data / non-parseable data is recived by the client
 */
void ClientBase::RaiseOnBadLine(const std::string *str)
{
	if (m_Handler != NULL)
		m_Handler->OnBadLine(str);

	abort();
}

<|endoftext|>


<commit_before>/*
 * Connection.cpp
 *
 *  Created on: Apr 11, 2015
 *      Author: jonno
 */

#include "Connection.h"
#include "Constants.h"

#include <iostream>

using namespace std;

Connection::Connection(ConnectionData* connection) {
	mConnectionData = connection;
}

void Connection::handleConnection() {
	int sock = mConnectionData->socket;
	//sockaddr_in client = mConnectionData->client;

	mSock = std::make_unique<Socket>(sock);

	if (!this->receiveGreeting()) {
		return;
	}

	RequestDetails request;
	if (!this->handleRequest(request)) {
		return;
	}

	// Try to connect.
	auto outSock = setupForwardConnection(request);
	if (outSock == nullptr) {
		return;
	}

	this->relayTraffic(outSock);

}

bool Connection::verifyVersion(bytes greeting) {
	if (greeting.size() >= 1) {
		return verifySOCKSVersion(greeting[0]);
	}
	return false;
}

bool Connection::verifySOCKSVersion(char version) {
	if (version != Constants::SOCKS::Version::V5) {
		cerr << "Invalid SOCKS Version." << endl;
		return false;
	}
	return true;
}

bool Connection::checkAuthentication(char methodCount) {

	bytes methods;
	if (!mSock->receive(methods, methodCount))
	{
		return false;
	}

	bool allowsNoAuth = false;

	for (unsigned int i = 0; i < methods.size(); ++i)
	{
		if (methods[i] == Constants::SOCKS::Authentication::NoAuth)
			allowsNoAuth = true;
	}

	if (!allowsNoAuth)
	{
		cerr << "Client doesn't support unauthenticated sessions." << endl;
		// socks V5, no auth methods
		mSock->send(hexBytes("05FF"));
		return false;
	}

	//	cerr << "Using NoAuth" << endl;
	mSock->send(hexBytes("0500"));

	return true;
}

bool Connection::receiveGreeting() {

	bytes version;
	if ((!mSock->receive(version, 2)) || (version.size() != 2) ) {
		cerr << "Could not read the SOCKS version" << endl;
		return false;
	}

	if (!this->verifySOCKSVersion(version[0])) {
		cout << hex << version[0] << version[1]<< endl;
		return false;
	}

	if (!this->checkAuthentication(version[1])) {
		return false;
	}

	return true;
}

bool Connection::handleRequest(RequestDetails& request) {
	bytes header;

	if (!mSock->receive(header, 4))
	{
		return false;
	}

	if (header.size() != 4)
	{
		return false;
	}

	if (!this->verifySOCKSVersion(header[0])) {
		return false;
	}

	// We only support TCP CONNECT, so fail other commands.
	if (header[1] != Constants::SOCKS::Command::TCPConnection)
	{
		// Unsupported command.
		cerr << "Unsupported command." << endl;
		// TODO: fix this trash
		mSock->send(hexBytes("050200010000000000"));
		return false;
	}
	// header[2] is 0x00 - reserved

	bytes address;
	AddressType addressType;

	// Get the type of address they want to connect to.
	switch (header[3])
	{
		case Constants::IP::Type::IPV4: {
			addressType = IPV4_ADDRESS;
			mSock->receive(address, Constants::IP::Length::IPV4);
		}
			break;

		case Constants::IP::Type::Domain: {
			addressType = DOMAIN_ADDRESS;
			bytes len;
			// get length of domain name
			mSock->receive(len, 1);
			// get domain name
			mSock->receive(address, len[0]);
		}
			break;

		case Constants::IP::Type::IPV6: {
			addressType = IPV6_ADDRESS;
			mSock->receive(address, Constants::IP::Length::IPV6);
		}
			break;

		default:
			cerr << "Invalid address type." << endl;
			// TODO: Fix this trash
			mSock->send(hexBytes("050200010000000000"));
			return false;
	}

	// Get the port.
	bytes rawPort;
	if (!mSock->receive(rawPort, 2)) {
		cerr << "Could not read the port" << endl;
		return false;
	}

	unsigned char h = rawPort[0];
	unsigned char l = rawPort[1];
	int port = (h << 8) + l;

	request.port = port;
	request.address = address;
	request.addressType = addressType;

	return true;
}

std::shared_ptr<Socket> Connection::setupForwardConnection(const RequestDetails& request) {
	bool connected = false;

	auto outSock = std::make_shared<Socket>();

	switch (request.addressType) {
		case IPV4_ADDRESS:
			connected = outSock->connect4(request.address, request.port);
			break;
		case IPV6_ADDRESS:
			connected = outSock->connect6(request.address, request.port);
			break;
		case DOMAIN_ADDRESS:
			connected = outSock->connect(request.address, request.port);
			break;
		default:
			cerr << "No connection type specified." << endl;
			break;
	}

	// Send reply.

	// This is wrong - the address & port should be the local address of outSock on the server.
	// Not sure why the client would need this, so I'm just going for 0s.
	if (connected)
	{
		cerr << "Connected!" << endl;
		mSock->send(hexBytes("050000") + hexBytes("01cb007101abab"));
	}
	else
	{
		cerr << "Connection failed." << endl;
		mSock->send(hexBytes("050400") + hexBytes("01cb007101abab")); // Host unreachable.
		return nullptr;
	}
	return outSock;
}

void Connection::relayTraffic(std::shared_ptr<Socket> outSock) {
	pollfd polls[2];
	polls[0].fd = mSock->descriptor();
	polls[0].events = POLLIN; // Listen for data availability.
	polls[0].revents = 0;
	polls[1].fd = outSock->descriptor(); // Will be the output socket.
	polls[1].events = POLLIN;
	polls[1].revents = 0;

	while (true)
	{
		int ret = poll(polls, 2, 60000);
		if (ret == -1)
		{
			cerr << strerror(errno) << endl;
			break;
		}
		if (ret == 0)
		{
//			cerr << "No data (timeout)" << endl;
			break;
		}

		if (polls[0].revents & POLLIN)
		{
			bytes data;
			if (!mSock->receive(data))
			{
//				cerr << "Read error: " << strerror(errno) << endl;
				break;
			}
			if (data.empty())
			{
//				cerr << "Read EOF." << endl;
				break;
			}

			if (!outSock->send(data))
			{
//				cerr << "Write error: " << strerror(errno) << endl;
			}
		}

		if (polls[1].revents & POLLIN)
		{
			bytes data;
			if (!outSock->receive(data))
			{
//				cerr << "Read error: " << strerror(errno) << endl;
				break;
			}
			if (data.empty())
			{
//				cerr << "Read EOF." << endl;
				break;
			}

			if (!mSock->send(data))
			{
//				cerr << "Write error: " << strerror(errno) << endl;
			}
		}

		if ((polls[0].revents & (POLLHUP | POLLNVAL | POLLERR)) || (polls[1].revents & (POLLHUP | POLLNVAL | POLLERR)) )
		{
//			cerr << "Connection finished." << endl; // Could be an error...
			break;
		}
	}
}

Connection::~Connection() {
	//delete mConnectionData;
}
<commit_msg>Added new method for encoding to connection.<commit_after>/*
 * Connection.cpp
 *
 *  Created on: Apr 11, 2015
 *      Author: jonno
 */

#include "Connection.h"
#include "Constants.h"
#include "Util.h"

#include <iostream>

using namespace std;

Connection::Connection(ConnectionData* connection) {
	mConnectionData = connection;
}

void Connection::handleConnection() {
	int sock = mConnectionData->socket;
	//sockaddr_in client = mConnectionData->client;

	mSock = std::make_unique<Socket>(sock);

	if (!this->receiveGreeting()) {
		return;
	}

	RequestDetails request;
	if (!this->handleRequest(request)) {
		return;
	}

	// Try to connect.
	auto outSock = setupForwardConnection(request);
	if (outSock == nullptr) {
		return;
	}

	this->relayTraffic(outSock);

}

bool Connection::verifyVersion(bytes greeting) {
	if (greeting.size() >= 1) {
		return verifySOCKSVersion(greeting[0]);
	}
	return false;
}

bool Connection::verifySOCKSVersion(char version) {
	if (version != Constants::SOCKS::Version::V5) {
		cerr << "Invalid SOCKS Version." << endl;
		return false;
	}
	return true;
}

bool Connection::checkAuthentication(char methodCount) {

	bytes methods;
	if (!mSock->receive(methods, methodCount))
	{
		return false;
	}

	bool allowsNoAuth = false;

	for (unsigned int i = 0; i < methods.size(); ++i)
	{
		if (methods[i] == Constants::SOCKS::Authentication::NoAuth)
			allowsNoAuth = true;
	}

	if (!allowsNoAuth)
	{
		cerr << "Client doesn't support unauthenticated sessions." << endl;
		// socks V5, no auth methods
		mSock->send(Constants::Messages::Auth::InvalidAuth);
		return false;
	}

	//	cerr << "Using NoAuth" << endl;
	mSock->send(Constants::Messages::Auth::UseNoAuth);

	return true;
}

bool Connection::receiveGreeting() {

	bytes version;
	if ((!mSock->receive(version, 2)) || (version.size() != 2) ) {
		cerr << "Could not read the SOCKS version" << endl;
		return false;
	}

	if (!this->verifySOCKSVersion(version[0])) {
		cout << hex << version[0] << version[1]<< endl;
		return false;
	}

	if (!this->checkAuthentication(version[1])) {
		return false;
	}

	return true;
}

bool Connection::handleRequest(RequestDetails& request) {
	bytes header;

	if (!mSock->receive(header, 4))
	{
		return false;
	}

	if (header.size() != 4)
	{
		return false;
	}

	if (!this->verifySOCKSVersion(header[0])) {
		return false;
	}

	// We only support TCP CONNECT, so fail other commands.
	if (header[1] != Constants::SOCKS::Command::TCPConnection)
	{
		// Unsupported command.
		cerr << "Unsupported command." << endl;
		// TODO: fix this trash
		mSock->send(Util::hexToString("050200010000000000"));
		return false;
	}
	// header[2] is 0x00 - reserved

	bytes address;
	AddressType addressType;

	// Get the type of address they want to connect to.
	switch (header[3])
	{
		case Constants::IP::Type::IPV4: {
			addressType = IPV4_ADDRESS;
			mSock->receive(address, Constants::IP::Length::IPV4);
		}
			break;

		case Constants::IP::Type::Domain: {
			addressType = DOMAIN_ADDRESS;
			bytes len;
			// get length of domain name
			mSock->receive(len, 1);
			// get domain name
			mSock->receive(address, len[0]);
		}
			break;

		case Constants::IP::Type::IPV6: {
			addressType = IPV6_ADDRESS;
			mSock->receive(address, Constants::IP::Length::IPV6);
		}
			break;

		default:
			cerr << "Invalid address type." << endl;
			// TODO: Fix this trash
			mSock->send(Util::hexToString("050200010000000000"));
			return false;
	}

	// Get the port.
	bytes rawPort;
	if (!mSock->receive(rawPort, 2)) {
		cerr << "Could not read the port" << endl;
		return false;
	}

	unsigned char h = rawPort[0];
	unsigned char l = rawPort[1];
	int port = (h << 8) + l;

	request.port = port;
	request.address = address;
	request.addressType = addressType;

	return true;
}

std::shared_ptr<Socket> Connection::setupForwardConnection(const RequestDetails& request) {
	bool connected = false;

	auto outSock = std::make_shared<Socket>();

	switch (request.addressType) {
		case IPV4_ADDRESS:
			connected = outSock->connect4(request.address, request.port);
			break;
		case IPV6_ADDRESS:
			connected = outSock->connect6(request.address, request.port);
			break;
		case DOMAIN_ADDRESS:
			connected = outSock->connect(request.address, request.port);
			break;
		default:
			cerr << "No connection type specified." << endl;
			break;
	}

	// Send reply.

	// This is wrong - the address & port should be the local address of outSock on the server.
	// Not sure why the client would need this, so I'm just going for 0s.
	if (connected)
	{
		cerr << "Connected!" << endl;
		mSock->send(Util::hexToString("050000") + Util::hexToString("01cb007101abab"));
	}
	else
	{
		cerr << "Connection failed." << endl;
		mSock->send(Util::hexToString("050400") + Util::hexToString("01cb007101abab")); // Host unreachable.
		return nullptr;
	}
	return outSock;
}

void Connection::relayTraffic(std::shared_ptr<Socket> outSock) {
	pollfd polls[2];
	polls[0].fd = mSock->descriptor();
	polls[0].events = POLLIN; // Listen for data availability.
	polls[0].revents = 0;
	polls[1].fd = outSock->descriptor(); // Will be the output socket.
	polls[1].events = POLLIN;
	polls[1].revents = 0;

	while (true)
	{
		int ret = poll(polls, 2, 60000);
		if (ret == -1)
		{
			cerr << strerror(errno) << endl;
			break;
		}
		if (ret == 0)
		{
//			cerr << "No data (timeout)" << endl;
			break;
		}

		if (polls[0].revents & POLLIN)
		{
			bytes data;
			if (!mSock->receive(data))
			{
//				cerr << "Read error: " << strerror(errno) << endl;
				break;
			}
			if (data.empty())
			{
//				cerr << "Read EOF." << endl;
				break;
			}

			if (!outSock->send(data))
			{
//				cerr << "Write error: " << strerror(errno) << endl;
			}
		}

		if (polls[1].revents & POLLIN)
		{
			bytes data;
			if (!outSock->receive(data))
			{
//				cerr << "Read error: " << strerror(errno) << endl;
				break;
			}
			if (data.empty())
			{
//				cerr << "Read EOF." << endl;
				break;
			}

			if (!mSock->send(data))
			{
//				cerr << "Write error: " << strerror(errno) << endl;
			}
		}

		if ((polls[0].revents & (POLLHUP | POLLNVAL | POLLERR)) || (polls[1].revents & (POLLHUP | POLLNVAL | POLLERR)) )
		{
//			cerr << "Connection finished." << endl; // Could be an error...
			break;
		}
	}
}

Connection::~Connection() {
	//delete mConnectionData;
}
<|endoftext|>