<commit_before>/**
* @file Shader.cpp
*/
#include "Shader.h"
#include <vector>
#include <iostream>
#include <cstdint>
#include <stdio.h>
#include <sys/stat.h>

namespace Shader {

/**
* VF[_R[hRpC.
*
* @param type VF[_̎.
* @param string VF[_R[hւ̃|C^.
*
* @return 쐬VF[_IuWFNg.
*/
GLuint CompileShader(GLenum type, const GLchar* string)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &string, nullptr);
	glCompileShader(shader);
	GLint compiled = 0;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
	if (!compiled) {
		GLint infoLen = 0;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
		if (infoLen) {
			std::vector<char> buf;
			buf.resize(infoLen);
			if (static_cast<int>(buf.size()) >= infoLen) {
				glGetShaderInfoLog(shader, infoLen, NULL, buf.data());
				std::cerr << "ERROR: VF[_̃RpCɎs" << buf.data() << std::endl;
			}
			glDeleteShader(shader);
		}
		return 0;
	}
	return shader;
}

/**
* VF[_vO쐬.
*
* @param vsCode _VF[_R[hւ̃|C^.
* @param fsCode tOgVF[_R[hւ̃|C^.
*
* @return 쐬vOIuWFNg.
*/
GLuint CreateProgram(const GLchar* vsCode, const GLchar* fsCode)
{
	GLuint vs = CompileShader(GL_VERTEX_SHADER, vsCode);
	GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsCode);
	if (!vs || !fs) {
		return 0;
	}
	GLuint program = glCreateProgram();
	glAttachShader(program, fs);
	glDeleteShader(fs);
	glAttachShader(program, vs);
	glDeleteShader(vs);
	glLinkProgram(program);
	GLint linkStatus = GL_FALSE;
	glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
	if (linkStatus != GL_TRUE) {
		GLint infoLen = 0;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
		if (infoLen) {
			std::vector<char> buf;
			buf.resize(infoLen);
			if (static_cast<int>(buf.size()) >= infoLen) {
				glGetProgramInfoLog(program, infoLen, NULL, buf.data());
				std::cerr << "ERROR: VF[_̃NɎs" << buf.data() << std::endl;
			}
		}
		glDeleteProgram(program);
		return 0;
	}
	return program;
}

/**
* t@Cǂݍ.
*
* @param filename ǂݍރt@C.
* @param buf      ǂݍݐobt@.
*
* @retval true ǂݍݐ.
* @retval false ǂݍݎs.
*/
bool ReadFile(const char* filename, std::vector<char>& buf)
{
	struct stat st;
	if (stat(filename, &st)) {
		return false;
	}
	FILE* fp = fopen(filename, "rb");
	if (!fp) {
		return false;
	}
	buf.resize(st.st_size);
	const size_t readSize = fread(buf.data(), 1, st.st_size, fp);
	fclose(fp);
	if (readSize != st.st_size) {
		return false;
	}
	return true;
}

/**
* t@CVF[_vO쐬.
*
* @param vsCode _VF[_t@C.
* @param fsCode tOgVF[_t@C.
*
* @return 쐬vOIuWFNg.
*/
GLuint CreateProgramFromFile(const char* vsFilename, const char* fsFilename)
{
	std::vector<char> vsBuf;
	if (!ReadFile(vsFilename, vsBuf)) {
		std::cerr << "ERROR in Shader::CreateProgramFromFile:\n" << vsFilename << "ǂݍ߂܂." << std::endl;
		return 0;
	}
	std::vector<char> fsBuf;
	if (!ReadFile(fsFilename, fsBuf)) {
		std::cerr << "ERROR in Shader::CreateProgramFromFile:\n" << fsFilename << "ǂݍ߂܂." << std::endl;
		return 0;
	}
	return CreateProgram(vsBuf.data(), fsBuf.data());
}

} // namespace Shader<commit_msg>読み込んだデータに0終端を追加.<commit_after>/**
* @file Shader.cpp
*/
#include "Shader.h"
#include <vector>
#include <iostream>
#include <cstdint>
#include <stdio.h>
#include <sys/stat.h>

namespace Shader {

/**
* VF[_R[hRpC.
*
* @param type VF[_̎.
* @param string VF[_R[hւ̃|C^.
*
* @return 쐬VF[_IuWFNg.
*/
GLuint CompileShader(GLenum type, const GLchar* string)
{
	GLuint shader = glCreateShader(type);
	glShaderSource(shader, 1, &string, nullptr);
	glCompileShader(shader);
	GLint compiled = 0;
	glGetShaderiv(shader, GL_COMPILE_STATUS, &compiled);
	if (!compiled) {
		GLint infoLen = 0;
		glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLen);
		if (infoLen) {
			std::vector<char> buf;
			buf.resize(infoLen);
			if (static_cast<int>(buf.size()) >= infoLen) {
				glGetShaderInfoLog(shader, infoLen, NULL, buf.data());
				std::cerr << "ERROR: VF[_̃RpCɎs" << buf.data() << std::endl;
			}
			glDeleteShader(shader);
		}
		return 0;
	}
	return shader;
}

/**
* VF[_vO쐬.
*
* @param vsCode _VF[_R[hւ̃|C^.
* @param fsCode tOgVF[_R[hւ̃|C^.
*
* @return 쐬vOIuWFNg.
*/
GLuint CreateProgram(const GLchar* vsCode, const GLchar* fsCode)
{
	GLuint vs = CompileShader(GL_VERTEX_SHADER, vsCode);
	GLuint fs = CompileShader(GL_FRAGMENT_SHADER, fsCode);
	if (!vs || !fs) {
		return 0;
	}
	GLuint program = glCreateProgram();
	glAttachShader(program, fs);
	glDeleteShader(fs);
	glAttachShader(program, vs);
	glDeleteShader(vs);
	glLinkProgram(program);
	GLint linkStatus = GL_FALSE;
	glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
	if (linkStatus != GL_TRUE) {
		GLint infoLen = 0;
		glGetProgramiv(program, GL_INFO_LOG_LENGTH, &infoLen);
		if (infoLen) {
			std::vector<char> buf;
			buf.resize(infoLen);
			if (static_cast<int>(buf.size()) >= infoLen) {
				glGetProgramInfoLog(program, infoLen, NULL, buf.data());
				std::cerr << "ERROR: VF[_̃NɎs" << buf.data() << std::endl;
			}
		}
		glDeleteProgram(program);
		return 0;
	}
	return program;
}

/**
* t@Cǂݍ.
*
* @param filename ǂݍރt@C.
* @param buf      ǂݍݐobt@.
*
* @retval true ǂݍݐ.
* @retval false ǂݍݎs.
*/
bool ReadFile(const char* filename, std::vector<char>& buf)
{
	struct stat st;
	if (stat(filename, &st)) {
		return false;
	}
	FILE* fp = fopen(filename, "rb");
	if (!fp) {
		return false;
	}
	buf.resize(st.st_size + 1);
	const size_t readSize = fread(buf.data(), 1, st.st_size, fp);
	fclose(fp);
	if (readSize != st.st_size) {
		return false;
	}
	buf.back() = '\0';
	return true;
}

/**
* t@CVF[_vO쐬.
*
* @param vsCode _VF[_t@C.
* @param fsCode tOgVF[_t@C.
*
* @return 쐬vOIuWFNg.
*/
GLuint CreateProgramFromFile(const char* vsFilename, const char* fsFilename)
{
	std::vector<char> vsBuf;
	if (!ReadFile(vsFilename, vsBuf)) {
		std::cerr << "ERROR in Shader::CreateProgramFromFile:\n" << vsFilename << "ǂݍ߂܂." << std::endl;
		return 0;
	}
	std::vector<char> fsBuf;
	if (!ReadFile(fsFilename, fsBuf)) {
		std::cerr << "ERROR in Shader::CreateProgramFromFile:\n" << fsFilename << "ǂݍ߂܂." << std::endl;
		return 0;
	}
	return CreateProgram(vsBuf.data(), fsBuf.data());
}

} // namespace Shader<|endoftext|>


<commit_before>#include "calc.h"
#include <stdexcept>
#include <string>

// Calculates the result of two numbers a and b and basic math operator.
int calc(int a, int b, char operator_symbol) {
	switch (operator_symbol) {
		case '*': return a*b;
		case '/':
			if (b == 0) throw std::domain_error{"division by zero"};
			return a/b;
		case '+': return a+b;
		case '-': return a-b;
		case '%':
			if (b == 0) throw std::domain_error{"division by zero"};
			return a%b;
	}

	auto reason = std::string("invalid operator: ");
	reason.push_back(operator_symbol);
	throw std::invalid_argument{reason};
}

int calc(std::istream &input) {
	int a {0}, b {0};
	char operator_symbol { };
	input >> a >> operator_symbol >> b;
	return calc(a, b, operator_symbol);
}
<commit_msg>calc(std::istream): raise when input term is malformed<commit_after>#include "calc.h"
#include <stdexcept>
#include <string>

// Calculates the result of two numbers a and b and basic math operator.
int calc(int a, int b, char operator_symbol) {
	switch (operator_symbol) {
		case '*': return a*b;
		case '/':
			if (b == 0) throw std::domain_error{"division by zero"};
			return a/b;
		case '+': return a+b;
		case '-': return a-b;
		case '%':
			if (b == 0) throw std::domain_error{"division by zero"};
			return a%b;
	}

	auto reason = std::string("invalid operator: ");
	reason.push_back(operator_symbol);
	throw std::invalid_argument{reason};
}

int calc(std::istream &input) {
	int a {0}, b {0};
	char operator_symbol { };
	input >> a >> operator_symbol >> b;
	if (input.fail() || !input.eof())
			throw std::invalid_argument{ "malformed input term"};
	return calc(a, b, operator_symbol);
}
<|endoftext|>


<commit_before>/// HEADER
#include "evaluate_binary_classifier.h"

/// PROJECT
#include <csapex/msg/io.h>
#include <csapex/utility/register_apex_plugin.h>
#include <utils_param/parameter_factory.h>
#include <csapex/model/node_modifier.h>

/// SYSTEM
//#include <boost/assign.hpp>

CSAPEX_REGISTER_CLASS(csapex::EvaluateBinaryClassifier, csapex::Node)

using namespace csapex;
using namespace csapex::connection_types;

EvaluateBinaryClassifier::EvaluateBinaryClassifier()
{
}

void EvaluateBinaryClassifier::setupParameters(Parameterizable& parameters)
{
}

void EvaluateBinaryClassifier::setup(NodeModifier& node_modifier)
{
    in_ = node_modifier.addInput<ConfusionMatrixMessage>("Confusion Matrix");
}

void EvaluateBinaryClassifier::process()
{
    connection_types::ConfusionMatrixMessage::ConstPtr msg = msg::getMessage<connection_types::ConfusionMatrixMessage>(in_);

    const ConfusionMatrix& cm = msg->confusion;

    if(cm.classes.size() != 2) {
        throw std::logic_error("needs a confusion matrix with exactly 2 classes");
    }

    metrics_.clear();

    int tp = cm.histogram.at(std::make_pair(1, 1));
    int tn = cm.histogram.at(std::make_pair(0, 0));
    int fp = cm.histogram.at(std::make_pair(0, 1));
    int fn = cm.histogram.at(std::make_pair(1, 0));
    int p = tp + fn;
    int n = tn + fp;

    metrics_.push_back(Metric("Sensitivity", "True positive rate, hit rate, recall", 0.0, 1.0,
                              tp / double(p)));
    metrics_.push_back(Metric("specificity", "(SPC) or True Negative Rate", 0.0, 1.0,
                              tn / double(n)));
    metrics_.push_back(Metric("precision", "positive predictive value (PPV)", 0.0, 1.0,
                              tp / double(tp + fp)));
    metrics_.push_back(Metric("negative predictive value", "NPV", 0.0, 1.0,
                              tn / double(tn + fn)));
    metrics_.push_back(Metric("fall-out", "false positive rate (FPR)", 1.0, 0.0,
                              fp / double(n)));
    metrics_.push_back(Metric("false discovery rate", "FDR", 1.0, 0.0,
                              fp / double(fp + tp)));
    metrics_.push_back(Metric("Miss Rate", "False Negative Rate (FNR)", 1.0, 0.0,
                              fn / double(p)));

    metrics_.push_back(Metric("accuracy", "ACC", 0.0, 1.0,
                              (tp + tn) / double(p + n)));
    metrics_.push_back(Metric("F1 score", "the harmonic mean of precision and sensitivity", 0.0, 1.0,
                              (2 * tp) / double(2 * tp + fp + fn)));
    metrics_.push_back(Metric("Matthews correlation coefficient", "MCC", -1.0, 1.0,
                              (tp * tn - fp * fn)
                              /
                              std::sqrt(double(tp + fp) * double(tp + fn) * double(tn + fp) * double(tn + fn))));

    display_request();
}

const EvaluateBinaryClassifier::Metrics& EvaluateBinaryClassifier::getMetrics() const
{
    return metrics_;
}
<commit_msg>better error handling<commit_after>/// HEADER
#include "evaluate_binary_classifier.h"

/// PROJECT
#include <csapex/msg/io.h>
#include <csapex/utility/register_apex_plugin.h>
#include <utils_param/parameter_factory.h>
#include <csapex/model/node_modifier.h>

/// SYSTEM
//#include <boost/assign.hpp>

CSAPEX_REGISTER_CLASS(csapex::EvaluateBinaryClassifier, csapex::Node)

using namespace csapex;
using namespace csapex::connection_types;

EvaluateBinaryClassifier::EvaluateBinaryClassifier()
{
}

void EvaluateBinaryClassifier::setupParameters(Parameterizable& parameters)
{
}

void EvaluateBinaryClassifier::setup(NodeModifier& node_modifier)
{
    in_ = node_modifier.addInput<ConfusionMatrixMessage>("Confusion Matrix");
}

void EvaluateBinaryClassifier::process()
{
    connection_types::ConfusionMatrixMessage::ConstPtr msg = msg::getMessage<connection_types::ConfusionMatrixMessage>(in_);

    const ConfusionMatrix& cm = msg->confusion;

    if(cm.classes.size() != 2) {
        modifier_->setWarning("needs a confusion matrix with exactly 2 classes");
        return;
    }

    modifier_->setNoError();

    metrics_.clear();

    int tp = cm.histogram.at(std::make_pair(1, 1));
    int tn = cm.histogram.at(std::make_pair(0, 0));
    int fp = cm.histogram.at(std::make_pair(0, 1));
    int fn = cm.histogram.at(std::make_pair(1, 0));
    int p = tp + fn;
    int n = tn + fp;

    metrics_.push_back(Metric("Sensitivity", "True positive rate, hit rate, recall", 0.0, 1.0,
                              tp / double(p)));
    metrics_.push_back(Metric("specificity", "(SPC) or True Negative Rate", 0.0, 1.0,
                              tn / double(n)));
    metrics_.push_back(Metric("precision", "positive predictive value (PPV)", 0.0, 1.0,
                              tp / double(tp + fp)));
    metrics_.push_back(Metric("negative predictive value", "NPV", 0.0, 1.0,
                              tn / double(tn + fn)));
    metrics_.push_back(Metric("fall-out", "false positive rate (FPR)", 1.0, 0.0,
                              fp / double(n)));
    metrics_.push_back(Metric("false discovery rate", "FDR", 1.0, 0.0,
                              fp / double(fp + tp)));
    metrics_.push_back(Metric("Miss Rate", "False Negative Rate (FNR)", 1.0, 0.0,
                              fn / double(p)));

    metrics_.push_back(Metric("accuracy", "ACC", 0.0, 1.0,
                              (tp + tn) / double(p + n)));
    metrics_.push_back(Metric("F1 score", "the harmonic mean of precision and sensitivity", 0.0, 1.0,
                              (2 * tp) / double(2 * tp + fp + fn)));
    metrics_.push_back(Metric("Matthews correlation coefficient", "MCC", -1.0, 1.0,
                              (tp * tn - fp * fn)
                              /
                              std::sqrt(double(tp + fp) * double(tp + fn) * double(tn + fp) * double(tn + fn))));

    display_request();
}

const EvaluateBinaryClassifier::Metrics& EvaluateBinaryClassifier::getMetrics() const
{
    return metrics_;
}
<|endoftext|>


<commit_before>/*

Copyright (c) 2008, Arvid Norberg
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 name of the author 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.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>
#include <stdlib.h>

#include "libtorrent/config.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/assert.hpp"

using namespace libtorrent;

namespace
{
	char to_lower(char c) { return std::tolower(c); }
}

namespace libtorrent
{
	http_parser::http_parser()
		: m_recv_pos(0)
		, m_status_code(-1)
		, m_content_length(-1)
		, m_state(read_status)
		, m_recv_buffer(0, 0)
		, m_body_start_pos(0)
		, m_finished(false)
	{}

	boost::tuple<int, int> http_parser::incoming(
		buffer::const_interval recv_buffer, bool& error)
	{
		TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
		boost::tuple<int, int> ret(0, 0);
		int start_pos = m_recv_buffer.left();

		// early exit if there's nothing new in the receive buffer
		if (start_pos == recv_buffer.left()) return ret;
		m_recv_buffer = recv_buffer;

		if (m_state == error_state)
		{
			error = true;
			return ret;
		}

		char const* pos = recv_buffer.begin + m_recv_pos;
		if (m_state == read_status)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			// if we don't have a full line yet, wait.
			if (newline == recv_buffer.end)
			{
				boost::get<1>(ret) += m_recv_buffer.left() - start_pos;
				return ret;
			}

			if (newline == pos)
			{
				m_state = error_state;
				error = true;
				return ret;
			}

			char const* line_end = newline;
			if (pos != line_end && *(line_end - 1) == '\r') --line_end;

			std::istringstream line(std::string(pos, line_end));
			++newline;
			int incoming = (int)std::distance(pos, newline);
			m_recv_pos += incoming;
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
			pos = newline;

			line >> m_protocol;
			if (m_protocol.substr(0, 5) == "HTTP/")
			{
				line >> m_status_code;
				std::getline(line, m_server_message);
			}
			else
			{
				m_method = m_protocol;
				std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower);
				m_protocol.clear();
				line >> m_path >> m_protocol;
				m_status_code = 0;
			}
			m_state = read_header;
			start_pos = pos - recv_buffer.begin;
		}

		if (m_state == read_header)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			std::string line;

			while (newline != recv_buffer.end && m_state == read_header)
			{
				// if the LF character is preceeded by a CR
				// charachter, don't copy it into the line string.
				char const* line_end = newline;
				if (pos != line_end && *(line_end - 1) == '\r') --line_end;
				line.assign(pos, line_end);
				++newline;
				m_recv_pos += newline - pos;
				pos = newline;

				std::string::size_type separator = line.find(':');
				if (separator == std::string::npos)
				{
					// this means we got a blank line,
					// the header is finished and the body
					// starts.
					m_state = read_body;
					m_body_start_pos = m_recv_pos;
					break;
				}

				std::string name = line.substr(0, separator);
				std::transform(name.begin(), name.end(), name.begin(), &to_lower);
				++separator;
				// skip whitespace
				while (separator < line.size()
					&& (line[separator] == ' ' || line[separator] == '\t'))
					++separator;
				std::string value = line.substr(separator, std::string::npos);
				m_header.insert(std::make_pair(name, value));

				if (name == "content-length")
				{
#ifdef TORRENT_WINDOWS
					m_content_length = _atoi64(value.c_str());
#else
					m_content_length = atoll(value.c_str());
#endif
				}
				else if (name == "content-range")
				{
					std::stringstream range_str(value);
					char dummy;
					std::string bytes;
					size_type range_start, range_end;
					// apparently some web servers do not send the "bytes"
					// in their content-range
					if (value.find(' ') != std::string::npos)
						range_str >> bytes;
					range_str >> range_start >> dummy >> range_end;
					if (!range_str || range_end < range_start)
					{
						m_state = error_state;
						error = true;
						return ret;
					}
					// the http range is inclusive
					m_content_length = range_end - range_start + 1;
				}

				TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
				newline = std::find(pos, recv_buffer.end, '\n');
			}
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
		}

		if (m_state == read_body)
		{
			int incoming = recv_buffer.end - pos;
			if (m_recv_pos - m_body_start_pos + incoming > m_content_length
				&& m_content_length >= 0)
				incoming = m_content_length - m_recv_pos + m_body_start_pos;

			TORRENT_ASSERT(incoming >= 0);
			m_recv_pos += incoming;
			boost::get<0>(ret) += incoming;

			if (m_content_length >= 0
				&& m_recv_pos - m_body_start_pos >= m_content_length)
			{
				m_finished = true;
			}
		}
		return ret;
	}

	buffer::const_interval http_parser::get_body() const
	{
		TORRENT_ASSERT(m_state == read_body);
		if (m_content_length >= 0)
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + (std::min)(size_type(m_recv_pos)
				, m_body_start_pos + m_content_length));
		else
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + m_recv_pos);
	}

	void http_parser::reset()
	{
		m_recv_pos = 0;
		m_body_start_pos = 0;
		m_status_code = -1;
		m_content_length = -1;
		m_finished = false;
		m_state = read_status;
		m_recv_buffer.begin = 0;
		m_recv_buffer.end = 0;
		m_header.clear();
	}

}

<commit_msg>fix to http_parser when used to parse requests instead of responses<commit_after>/*

Copyright (c) 2008, Arvid Norberg
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 name of the author 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.

*/

#include "libtorrent/pch.hpp"

#include <cctype>
#include <algorithm>
#include <stdlib.h>

#include "libtorrent/config.hpp"
#include "libtorrent/http_parser.hpp"
#include "libtorrent/assert.hpp"

using namespace libtorrent;

namespace
{
	char to_lower(char c) { return std::tolower(c); }
}

namespace libtorrent
{
	http_parser::http_parser()
		: m_recv_pos(0)
		, m_status_code(-1)
		, m_content_length(-1)
		, m_state(read_status)
		, m_recv_buffer(0, 0)
		, m_body_start_pos(0)
		, m_finished(false)
	{}

	boost::tuple<int, int> http_parser::incoming(
		buffer::const_interval recv_buffer, bool& error)
	{
		TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left());
		boost::tuple<int, int> ret(0, 0);
		int start_pos = m_recv_buffer.left();

		// early exit if there's nothing new in the receive buffer
		if (start_pos == recv_buffer.left()) return ret;
		m_recv_buffer = recv_buffer;

		if (m_state == error_state)
		{
			error = true;
			return ret;
		}

		char const* pos = recv_buffer.begin + m_recv_pos;
		if (m_state == read_status)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			// if we don't have a full line yet, wait.
			if (newline == recv_buffer.end)
			{
				boost::get<1>(ret) += m_recv_buffer.left() - start_pos;
				return ret;
			}

			if (newline == pos)
			{
				m_state = error_state;
				error = true;
				return ret;
			}

			char const* line_end = newline;
			if (pos != line_end && *(line_end - 1) == '\r') --line_end;

			std::istringstream line(std::string(pos, line_end));
			++newline;
			int incoming = (int)std::distance(pos, newline);
			m_recv_pos += incoming;
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
			pos = newline;

			line >> m_protocol;
			if (m_protocol.substr(0, 5) == "HTTP/")
			{
				line >> m_status_code;
				std::getline(line, m_server_message);
			}
			else
			{
				m_method = m_protocol;
				std::transform(m_method.begin(), m_method.end(), m_method.begin(), &to_lower);
				m_protocol.clear();
				line >> m_path >> m_protocol;
				m_status_code = 0;
			}
			m_state = read_header;
			start_pos = pos - recv_buffer.begin;
		}

		if (m_state == read_header)
		{
			TORRENT_ASSERT(!m_finished);
			char const* newline = std::find(pos, recv_buffer.end, '\n');
			std::string line;

			while (newline != recv_buffer.end && m_state == read_header)
			{
				// if the LF character is preceeded by a CR
				// charachter, don't copy it into the line string.
				char const* line_end = newline;
				if (pos != line_end && *(line_end - 1) == '\r') --line_end;
				line.assign(pos, line_end);
				++newline;
				m_recv_pos += newline - pos;
				pos = newline;

				std::string::size_type separator = line.find(':');
				if (separator == std::string::npos)
				{
					// this means we got a blank line,
					// the header is finished and the body
					// starts.
					m_state = read_body;
					// if this is a request (not a response)
					// we're done once we reach the end of the headers
					if (!m_method.empty()) m_finished = true;
					m_body_start_pos = m_recv_pos;
					break;
				}

				std::string name = line.substr(0, separator);
				std::transform(name.begin(), name.end(), name.begin(), &to_lower);
				++separator;
				// skip whitespace
				while (separator < line.size()
					&& (line[separator] == ' ' || line[separator] == '\t'))
					++separator;
				std::string value = line.substr(separator, std::string::npos);
				m_header.insert(std::make_pair(name, value));

				if (name == "content-length")
				{
#ifdef TORRENT_WINDOWS
					m_content_length = _atoi64(value.c_str());
#else
					m_content_length = atoll(value.c_str());
#endif
				}
				else if (name == "content-range")
				{
					std::stringstream range_str(value);
					char dummy;
					std::string bytes;
					size_type range_start, range_end;
					// apparently some web servers do not send the "bytes"
					// in their content-range
					if (value.find(' ') != std::string::npos)
						range_str >> bytes;
					range_str >> range_start >> dummy >> range_end;
					if (!range_str || range_end < range_start)
					{
						m_state = error_state;
						error = true;
						return ret;
					}
					// the http range is inclusive
					m_content_length = range_end - range_start + 1;
				}

				TORRENT_ASSERT(m_recv_pos <= (int)recv_buffer.left());
				newline = std::find(pos, recv_buffer.end, '\n');
			}
			boost::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos);
		}

		if (m_state == read_body)
		{
			int incoming = recv_buffer.end - pos;
			if (m_recv_pos - m_body_start_pos + incoming > m_content_length
				&& m_content_length >= 0)
				incoming = m_content_length - m_recv_pos + m_body_start_pos;

			TORRENT_ASSERT(incoming >= 0);
			m_recv_pos += incoming;
			boost::get<0>(ret) += incoming;

			if (m_content_length >= 0
				&& m_recv_pos - m_body_start_pos >= m_content_length)
			{
				m_finished = true;
			}
		}
		return ret;
	}

	buffer::const_interval http_parser::get_body() const
	{
		TORRENT_ASSERT(m_state == read_body);
		if (m_content_length >= 0)
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + (std::min)(size_type(m_recv_pos)
				, m_body_start_pos + m_content_length));
		else
			return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos
				, m_recv_buffer.begin + m_recv_pos);
	}

	void http_parser::reset()
	{
		m_recv_pos = 0;
		m_body_start_pos = 0;
		m_status_code = -1;
		m_content_length = -1;
		m_finished = false;
		m_state = read_status;
		m_recv_buffer.begin = 0;
		m_recv_buffer.end = 0;
		m_header.clear();
	}

}

<|endoftext|>


<commit_before>// Line- and column-sensitive test; run lines follow.

class string {
 public:
  string();
  string(const char *);
  string(const char *, int n);
};

template<typename T>
class vector {
public:
  vector(const T &, unsigned n);
  template<typename InputIterator>
  vector(InputIterator first, InputIterator last);
  void push_back(const T&);
};
template<typename T> void vector<T>::push_back(const T&) { }
void f() {

}

int foo();

void g() {
  vector<int>(foo(), foo());
}

// RUN: c-index-test -code-completion-at=%s:20:2 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:20:2 -std=c++0x %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText alignof}{LeftParen (}{Placeholder type}{RightParen )} (40)
// CHECK-CC1: NotImplemented:{ResultType bool}{TypedText noexcept}{LeftParen (}{Placeholder expression}{RightParen )} (40)
// CHECK-CC1: NotImplemented:{ResultType std::nullptr_t}{TypedText nullptr} (40)
// CHECK-CC1: NotImplemented:{TypedText operator} (40)
// CHECK-CC1-NOT: push_back
// CHECK-CC1: ClassDecl:{TypedText string} (50)
// CHECK-CC1: CXXConstructor:{TypedText string}{LeftParen (}{RightParen )} (50)
// CHECK-CC1: CXXConstructor:{TypedText string}{LeftParen (}{Placeholder const char *}{RightParen )} (50)
// CHECK-CC1: CXXConstructor:{TypedText string}{LeftParen (}{Placeholder const char *}{Comma , }{Placeholder int n}{RightParen )} (50)
// CHECK-CC1: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)
// CHECK-CC1: CXXConstructor:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder const T &}{Comma , }{Placeholder unsigned int n}{RightParen )} (50)
// CHECK-CC1: FunctionTemplate:{ResultType void}{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder InputIterator first}{Comma , }{Placeholder InputIterator last}{RightParen )} (50)

// RUN: c-index-test -code-completion-at=%s:19:1 %s | FileCheck -check-prefix=CHECK-CC2 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:19:1 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ClassDecl:{TypedText string} (50)
// CHECK-CC2-NOT: CXXConstructor
// CHECK-CC2: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)

// RUN: c-index-test -code-completion-at=%s:26:15 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: NotImplemented:{TypedText float} (50)
// CHECK-CC3: FunctionDecl:{ResultType int}{TypedText foo}{LeftParen (}{RightParen )} (50)
// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText g}{LeftParen (}{RightParen )} (50)
// CHECK-CC3: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)
// CHECK-CC3: CXXConstructor:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder const T &}{Comma , }{Placeholder unsigned int n}{RightParen )} (50)
// CHECK-CC3: FunctionTemplate:{ResultType void}{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder InputIterator first}{Comma , }{Placeholder InputIterator last}{RightParen )} (50)

// RUN: c-index-test -code-completion-at=%s:18:59 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: NotImplemented:{ResultType vector<T> *}{TypedText this} (40)
<commit_msg>Tweak this test to test more directly what we want, and hopefully work around the brokenness of code completion under -fdelayed-template-parsing<commit_after>// Line- and column-sensitive test; run lines follow.

class string {
 public:
  string();
  string(const char *);
  string(const char *, int n);
};

template<typename T>
class vector {
public:
  vector(const T &, unsigned n);
  template<typename InputIterator>
  vector(InputIterator first, InputIterator last);
  void push_back(const T&);
};
template<typename T> void vector<T>::push_back(const T&) { }
void f() {

}

int foo();

void g() {
  vector<int>(foo(), foo());
}

struct X {
  void f() const;
};

void X::f() const {

}

// RUN: c-index-test -code-completion-at=%s:20:2 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC1 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:20:2 -std=c++0x %s | FileCheck -check-prefix=CHECK-CC1 %s
// CHECK-CC1: NotImplemented:{ResultType size_t}{TypedText alignof}{LeftParen (}{Placeholder type}{RightParen )} (40)
// CHECK-CC1: NotImplemented:{ResultType bool}{TypedText noexcept}{LeftParen (}{Placeholder expression}{RightParen )} (40)
// CHECK-CC1: NotImplemented:{ResultType std::nullptr_t}{TypedText nullptr} (40)
// CHECK-CC1: NotImplemented:{TypedText operator} (40)
// CHECK-CC1-NOT: push_back
// CHECK-CC1: ClassDecl:{TypedText string} (50)
// CHECK-CC1: CXXConstructor:{TypedText string}{LeftParen (}{RightParen )} (50)
// CHECK-CC1: CXXConstructor:{TypedText string}{LeftParen (}{Placeholder const char *}{RightParen )} (50)
// CHECK-CC1: CXXConstructor:{TypedText string}{LeftParen (}{Placeholder const char *}{Comma , }{Placeholder int n}{RightParen )} (50)
// CHECK-CC1: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)
// CHECK-CC1: CXXConstructor:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder const T &}{Comma , }{Placeholder unsigned int n}{RightParen )} (50)
// CHECK-CC1: FunctionTemplate:{ResultType void}{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder InputIterator first}{Comma , }{Placeholder InputIterator last}{RightParen )} (50)

// RUN: c-index-test -code-completion-at=%s:19:1 %s | FileCheck -check-prefix=CHECK-CC2 %s
// RUN: env CINDEXTEST_EDITING=1 CINDEXTEST_COMPLETION_CACHING=1 c-index-test -code-completion-at=%s:19:1 %s | FileCheck -check-prefix=CHECK-CC2 %s
// CHECK-CC2: ClassDecl:{TypedText string} (50)
// CHECK-CC2-NOT: CXXConstructor
// CHECK-CC2: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)

// RUN: c-index-test -code-completion-at=%s:26:15 %s | FileCheck -check-prefix=CHECK-CC3 %s
// CHECK-CC3: NotImplemented:{TypedText float} (50)
// CHECK-CC3: FunctionDecl:{ResultType int}{TypedText foo}{LeftParen (}{RightParen )} (50)
// CHECK-CC3: FunctionDecl:{ResultType void}{TypedText g}{LeftParen (}{RightParen )} (50)
// CHECK-CC3: ClassTemplate:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >} (50)
// CHECK-CC3: CXXConstructor:{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder const T &}{Comma , }{Placeholder unsigned int n}{RightParen )} (50)
// CHECK-CC3: FunctionTemplate:{ResultType void}{TypedText vector}{LeftAngle <}{Placeholder typename T}{RightAngle >}{LeftParen (}{Placeholder InputIterator first}{Comma , }{Placeholder InputIterator last}{RightParen )} (50)

// RUN: c-index-test -code-completion-at=%s:34:1 %s -std=c++0x | FileCheck -check-prefix=CHECK-CC4 %s
// CHECK-CC4: NotImplemented:{ResultType const X *}{TypedText this} (40)
<|endoftext|>


<commit_before>//
//  StaticAnalyser.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 23/08/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#include "StaticAnalyser.hpp"

#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iterator>

// Analysers
#include "Acorn/StaticAnalyser.hpp"
#include "AmstradCPC/StaticAnalyser.hpp"
#include "AppleII/StaticAnalyser.hpp"
#include "Atari2600/StaticAnalyser.hpp"
#include "AtariST/StaticAnalyser.hpp"
#include "Coleco/StaticAnalyser.hpp"
#include "Commodore/StaticAnalyser.hpp"
#include "DiskII/StaticAnalyser.hpp"
#include "Macintosh/StaticAnalyser.hpp"
#include "MSX/StaticAnalyser.hpp"
#include "Oric/StaticAnalyser.hpp"
#include "Sega/StaticAnalyser.hpp"
#include "ZX8081/StaticAnalyser.hpp"

// Cartridges
#include "../../Storage/Cartridge/Formats/BinaryDump.hpp"
#include "../../Storage/Cartridge/Formats/PRG.hpp"

// Disks
#include "../../Storage/Disk/DiskImage/Formats/AcornADF.hpp"
#include "../../Storage/Disk/DiskImage/Formats/AppleDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/CPCDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/D64.hpp"
#include "../../Storage/Disk/DiskImage/Formats/MacintoshIMG.hpp"
#include "../../Storage/Disk/DiskImage/Formats/G64.hpp"
#include "../../Storage/Disk/DiskImage/Formats/DMK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/HFE.hpp"
#include "../../Storage/Disk/DiskImage/Formats/MSA.hpp"
#include "../../Storage/Disk/DiskImage/Formats/MSXDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/NIB.hpp"
#include "../../Storage/Disk/DiskImage/Formats/OricMFMDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/SSD.hpp"
#include "../../Storage/Disk/DiskImage/Formats/ST.hpp"
#include "../../Storage/Disk/DiskImage/Formats/STX.hpp"
#include "../../Storage/Disk/DiskImage/Formats/WOZ.hpp"

// Mass Storage Devices (i.e. usually, hard disks)
#include "../../Storage/MassStorage/Formats/HFV.hpp"

// Tapes
#include "../../Storage/Tape/Formats/CAS.hpp"
#include "../../Storage/Tape/Formats/CommodoreTAP.hpp"
#include "../../Storage/Tape/Formats/CSW.hpp"
#include "../../Storage/Tape/Formats/OricTAP.hpp"
#include "../../Storage/Tape/Formats/TapePRG.hpp"
#include "../../Storage/Tape/Formats/TapeUEF.hpp"
#include "../../Storage/Tape/Formats/TZX.hpp"
#include "../../Storage/Tape/Formats/ZX80O81P.hpp"

// Target Platform Types
#include "../../Storage/TargetPlatforms.hpp"

using namespace Analyser::Static;

static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::IntType &potential_platforms) {
	Media result;

	// Get the extension, if any; it will be assumed that extensions are reliable, so an extension is a broad-phase
	// test as to file format.
	std::string::size_type final_dot = file_name.find_last_of(".");
	if(final_dot == std::string::npos) return result;
	std::string extension = file_name.substr(final_dot + 1);
	std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);

#define Insert(list, class, platforms) \
	list.emplace_back(new Storage::class(file_name));\
	potential_platforms |= platforms;\
	TargetPlatform::TypeDistinguisher *distinguisher = dynamic_cast<TargetPlatform::TypeDistinguisher *>(list.back().get());\
	if(distinguisher) potential_platforms &= distinguisher->target_platform_type();

#define TryInsert(list, class, platforms) \
	try {\
		Insert(list, class, platforms) \
	} catch(...) {}

#define Format(ext, list, class, platforms) \
	if(extension == ext)	{		\
		TryInsert(list, class, platforms)	\
	}

	Format("80", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// 80
	Format("81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// 81
	Format("a26", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600)							// A26
	Format("adf", result.disks, Disk::DiskImageHolder<Storage::Disk::AcornADF>, TargetPlatform::Acorn)			// ADF
	Format("bin", result.cartridges, Cartridge::BinaryDump, TargetPlatform::AllCartridge)						// BIN (cartridge dump)
	Format("cas", result.tapes, Tape::CAS, TargetPlatform::MSX)													// CAS
	Format("cdt", result.tapes, Tape::TZX, TargetPlatform::AmstradCPC)											// CDT
	Format("col", result.cartridges, Cartridge::BinaryDump, TargetPlatform::ColecoVision)						// COL
	Format("csw", result.tapes, Tape::CSW, TargetPlatform::AllTape)												// CSW
	Format("d64", result.disks, Disk::DiskImageHolder<Storage::Disk::D64>, TargetPlatform::Commodore)			// D64
	Format("dmk", result.disks, Disk::DiskImageHolder<Storage::Disk::DMK>, TargetPlatform::MSX)					// DMK
	Format("do", result.disks, Disk::DiskImageHolder<Storage::Disk::AppleDSK>, TargetPlatform::DiskII)			// DO
	Format("dsd", result.disks, Disk::DiskImageHolder<Storage::Disk::SSD>, TargetPlatform::Acorn)				// DSD
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::CPCDSK>, TargetPlatform::AmstradCPC)		// DSK (Amstrad CPC)
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::AppleDSK>, TargetPlatform::DiskII)			// DSK (Apple II)
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh)	// DSK (Macintosh, floppy disk)
	Format("dsk", result.mass_storage_devices, MassStorage::HFV, TargetPlatform::Macintosh)						// DSK (Macintosh, hard disk)
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::MSXDSK>, TargetPlatform::MSX)				// DSK (MSX)
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::OricMFMDSK>, TargetPlatform::Oric)			// DSK (Oric)
	Format("g64", result.disks, Disk::DiskImageHolder<Storage::Disk::G64>, TargetPlatform::Commodore)			// G64
	Format(	"hfe",
			result.disks,
			Disk::DiskImageHolder<Storage::Disk::HFE>,
			TargetPlatform::Acorn | TargetPlatform::AmstradCPC | TargetPlatform::Commodore | TargetPlatform::Oric)
			// HFE (TODO: switch to AllDisk once the MSX stops being so greedy)
	Format("img", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh)		// IMG (DiskCopy 4.2)
	Format("image", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh)	// IMG (DiskCopy 4.2)
	Format("msa", result.disks, Disk::DiskImageHolder<Storage::Disk::MSA>, TargetPlatform::AtariST)				// MSA
	Format("nib", result.disks, Disk::DiskImageHolder<Storage::Disk::NIB>, TargetPlatform::DiskII)				// NIB
	Format("o", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// O
	Format("p", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// P
	Format("po", result.disks, Disk::DiskImageHolder<Storage::Disk::AppleDSK>, TargetPlatform::DiskII)			// PO
	Format("p81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// P81

	// PRG
	if(extension == "prg") {
		// try instantiating as a ROM; failing that accept as a tape
		try {
			Insert(result.cartridges, Cartridge::PRG, TargetPlatform::Commodore)
		} catch(...) {
			try {
				Insert(result.tapes, Tape::PRG, TargetPlatform::Commodore)
			} catch(...) {}
		}
	}

	Format(	"rom",
			result.cartridges,
			Cartridge::BinaryDump,
			TargetPlatform::AcornElectron | TargetPlatform::ColecoVision | TargetPlatform::MSX)					// ROM
	Format("sg", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Sega)								// SG
	Format("sms", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Sega)								// SMS
	Format("ssd", result.disks, Disk::DiskImageHolder<Storage::Disk::SSD>, TargetPlatform::Acorn)				// SSD
	Format("st", result.disks, Disk::DiskImageHolder<Storage::Disk::ST>, TargetPlatform::AtariST)				// ST
	Format("stx", result.disks, Disk::DiskImageHolder<Storage::Disk::STX>, TargetPlatform::AtariST)				// STX
	Format("tap", result.tapes, Tape::CommodoreTAP, TargetPlatform::Commodore)									// TAP (Commodore)
	Format("tap", result.tapes, Tape::OricTAP, TargetPlatform::Oric)											// TAP (Oric)
	Format("tsx", result.tapes, Tape::TZX, TargetPlatform::MSX)													// TSX
	Format("tzx", result.tapes, Tape::TZX, TargetPlatform::ZX8081)												// TZX
	Format("uef", result.tapes, Tape::UEF, TargetPlatform::Acorn)												// UEF (tape)
	Format("woz", result.disks, Disk::DiskImageHolder<Storage::Disk::WOZ>, TargetPlatform::DiskII)				// WOZ

#undef Format
#undef Insert
#undef TryInsert

	return result;
}

Media Analyser::Static::GetMedia(const std::string &file_name) {
	TargetPlatform::IntType throwaway;
	return GetMediaAndPlatforms(file_name, throwaway);
}

TargetList Analyser::Static::GetTargets(const std::string &file_name) {
	TargetList targets;

	// Collect all disks, tapes ROMs, etc as can be extrapolated from this file, forming the
	// union of all platforms this file might be a target for.
	TargetPlatform::IntType potential_platforms = 0;
	Media media = GetMediaAndPlatforms(file_name, potential_platforms);

	// Hand off to platform-specific determination of whether these things are actually compatible and,
	// if so, how to load them.
	#define Append(x) {\
		auto new_targets = x::GetTargets(media, file_name, potential_platforms);\
		std::move(new_targets.begin(), new_targets.end(), std::back_inserter(targets));\
	}
	if(potential_platforms & TargetPlatform::Acorn)			Append(Acorn);
	if(potential_platforms & TargetPlatform::AmstradCPC)	Append(AmstradCPC);
	if(potential_platforms & TargetPlatform::AppleII)		Append(AppleII);
	if(potential_platforms & TargetPlatform::Atari2600)		Append(Atari2600);
	if(potential_platforms & TargetPlatform::AtariST)		Append(AtariST);
	if(potential_platforms & TargetPlatform::ColecoVision)	Append(Coleco);
	if(potential_platforms & TargetPlatform::Commodore)		Append(Commodore);
	if(potential_platforms & TargetPlatform::DiskII)		Append(DiskII);
	if(potential_platforms & TargetPlatform::Macintosh)		Append(Macintosh);
	if(potential_platforms & TargetPlatform::MSX)			Append(MSX);
	if(potential_platforms & TargetPlatform::Oric)			Append(Oric);
	if(potential_platforms & TargetPlatform::Sega)			Append(Sega);
	if(potential_platforms & TargetPlatform::ZX8081)		Append(ZX8081);
	#undef Append

	// Reset any tapes to their initial position
	for(const auto &target : targets) {
		for(auto &tape : target->media.tapes) {
			tape->reset();
		}
	}

	// Sort by initial confidence. Use a stable sort in case any of the machine-specific analysers
	// picked their insertion order carefully.
	std::stable_sort(targets.begin(), targets.end(),
		[] (const std::unique_ptr<Target> &a, const std::unique_ptr<Target> &b) {
			return a->confidence > b->confidence;
		});

	return targets;
}
<commit_msg>Permits the Oric analyser to check CPC-style DSKs.<commit_after>//
//  StaticAnalyser.cpp
//  Clock Signal
//
//  Created by Thomas Harte on 23/08/2016.
//  Copyright 2016 Thomas Harte. All rights reserved.
//

#include "StaticAnalyser.hpp"

#include <algorithm>
#include <cstdlib>
#include <cstring>
#include <iterator>

// Analysers
#include "Acorn/StaticAnalyser.hpp"
#include "AmstradCPC/StaticAnalyser.hpp"
#include "AppleII/StaticAnalyser.hpp"
#include "Atari2600/StaticAnalyser.hpp"
#include "AtariST/StaticAnalyser.hpp"
#include "Coleco/StaticAnalyser.hpp"
#include "Commodore/StaticAnalyser.hpp"
#include "DiskII/StaticAnalyser.hpp"
#include "Macintosh/StaticAnalyser.hpp"
#include "MSX/StaticAnalyser.hpp"
#include "Oric/StaticAnalyser.hpp"
#include "Sega/StaticAnalyser.hpp"
#include "ZX8081/StaticAnalyser.hpp"

// Cartridges
#include "../../Storage/Cartridge/Formats/BinaryDump.hpp"
#include "../../Storage/Cartridge/Formats/PRG.hpp"

// Disks
#include "../../Storage/Disk/DiskImage/Formats/AcornADF.hpp"
#include "../../Storage/Disk/DiskImage/Formats/AppleDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/CPCDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/D64.hpp"
#include "../../Storage/Disk/DiskImage/Formats/MacintoshIMG.hpp"
#include "../../Storage/Disk/DiskImage/Formats/G64.hpp"
#include "../../Storage/Disk/DiskImage/Formats/DMK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/HFE.hpp"
#include "../../Storage/Disk/DiskImage/Formats/MSA.hpp"
#include "../../Storage/Disk/DiskImage/Formats/MSXDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/NIB.hpp"
#include "../../Storage/Disk/DiskImage/Formats/OricMFMDSK.hpp"
#include "../../Storage/Disk/DiskImage/Formats/SSD.hpp"
#include "../../Storage/Disk/DiskImage/Formats/ST.hpp"
#include "../../Storage/Disk/DiskImage/Formats/STX.hpp"
#include "../../Storage/Disk/DiskImage/Formats/WOZ.hpp"

// Mass Storage Devices (i.e. usually, hard disks)
#include "../../Storage/MassStorage/Formats/HFV.hpp"

// Tapes
#include "../../Storage/Tape/Formats/CAS.hpp"
#include "../../Storage/Tape/Formats/CommodoreTAP.hpp"
#include "../../Storage/Tape/Formats/CSW.hpp"
#include "../../Storage/Tape/Formats/OricTAP.hpp"
#include "../../Storage/Tape/Formats/TapePRG.hpp"
#include "../../Storage/Tape/Formats/TapeUEF.hpp"
#include "../../Storage/Tape/Formats/TZX.hpp"
#include "../../Storage/Tape/Formats/ZX80O81P.hpp"

// Target Platform Types
#include "../../Storage/TargetPlatforms.hpp"

using namespace Analyser::Static;

static Media GetMediaAndPlatforms(const std::string &file_name, TargetPlatform::IntType &potential_platforms) {
	Media result;

	// Get the extension, if any; it will be assumed that extensions are reliable, so an extension is a broad-phase
	// test as to file format.
	std::string::size_type final_dot = file_name.find_last_of(".");
	if(final_dot == std::string::npos) return result;
	std::string extension = file_name.substr(final_dot + 1);
	std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);

#define Insert(list, class, platforms) \
	list.emplace_back(new Storage::class(file_name));\
	potential_platforms |= platforms;\
	TargetPlatform::TypeDistinguisher *distinguisher = dynamic_cast<TargetPlatform::TypeDistinguisher *>(list.back().get());\
	if(distinguisher) potential_platforms &= distinguisher->target_platform_type();

#define TryInsert(list, class, platforms) \
	try {\
		Insert(list, class, platforms) \
	} catch(...) {}

#define Format(ext, list, class, platforms) \
	if(extension == ext)	{		\
		TryInsert(list, class, platforms)	\
	}

	Format("80", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// 80
	Format("81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// 81
	Format("a26", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Atari2600)							// A26
	Format("adf", result.disks, Disk::DiskImageHolder<Storage::Disk::AcornADF>, TargetPlatform::Acorn)			// ADF
	Format("bin", result.cartridges, Cartridge::BinaryDump, TargetPlatform::AllCartridge)						// BIN (cartridge dump)
	Format("cas", result.tapes, Tape::CAS, TargetPlatform::MSX)													// CAS
	Format("cdt", result.tapes, Tape::TZX, TargetPlatform::AmstradCPC)											// CDT
	Format("col", result.cartridges, Cartridge::BinaryDump, TargetPlatform::ColecoVision)						// COL
	Format("csw", result.tapes, Tape::CSW, TargetPlatform::AllTape)												// CSW
	Format("d64", result.disks, Disk::DiskImageHolder<Storage::Disk::D64>, TargetPlatform::Commodore)			// D64
	Format("dmk", result.disks, Disk::DiskImageHolder<Storage::Disk::DMK>, TargetPlatform::MSX)					// DMK
	Format("do", result.disks, Disk::DiskImageHolder<Storage::Disk::AppleDSK>, TargetPlatform::DiskII)			// DO
	Format("dsd", result.disks, Disk::DiskImageHolder<Storage::Disk::SSD>, TargetPlatform::Acorn)				// DSD
	Format(	"dsk",
			result.disks,
			Disk::DiskImageHolder<Storage::Disk::CPCDSK>,
			TargetPlatform::AmstradCPC | TargetPlatform::Oric)													// DSK (Amstrad CPC)
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::AppleDSK>, TargetPlatform::DiskII)			// DSK (Apple II)
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh)	// DSK (Macintosh, floppy disk)
	Format("dsk", result.mass_storage_devices, MassStorage::HFV, TargetPlatform::Macintosh)						// DSK (Macintosh, hard disk)
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::MSXDSK>, TargetPlatform::MSX)				// DSK (MSX)
	Format("dsk", result.disks, Disk::DiskImageHolder<Storage::Disk::OricMFMDSK>, TargetPlatform::Oric)			// DSK (Oric)
	Format("g64", result.disks, Disk::DiskImageHolder<Storage::Disk::G64>, TargetPlatform::Commodore)			// G64
	Format(	"hfe",
			result.disks,
			Disk::DiskImageHolder<Storage::Disk::HFE>,
			TargetPlatform::Acorn | TargetPlatform::AmstradCPC | TargetPlatform::Commodore | TargetPlatform::Oric)
			// HFE (TODO: switch to AllDisk once the MSX stops being so greedy)
	Format("img", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh)		// IMG (DiskCopy 4.2)
	Format("image", result.disks, Disk::DiskImageHolder<Storage::Disk::MacintoshIMG>, TargetPlatform::Macintosh)	// IMG (DiskCopy 4.2)
	Format("msa", result.disks, Disk::DiskImageHolder<Storage::Disk::MSA>, TargetPlatform::AtariST)				// MSA
	Format("nib", result.disks, Disk::DiskImageHolder<Storage::Disk::NIB>, TargetPlatform::DiskII)				// NIB
	Format("o", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// O
	Format("p", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// P
	Format("po", result.disks, Disk::DiskImageHolder<Storage::Disk::AppleDSK>, TargetPlatform::DiskII)			// PO
	Format("p81", result.tapes, Tape::ZX80O81P, TargetPlatform::ZX8081)											// P81

	// PRG
	if(extension == "prg") {
		// try instantiating as a ROM; failing that accept as a tape
		try {
			Insert(result.cartridges, Cartridge::PRG, TargetPlatform::Commodore)
		} catch(...) {
			try {
				Insert(result.tapes, Tape::PRG, TargetPlatform::Commodore)
			} catch(...) {}
		}
	}

	Format(	"rom",
			result.cartridges,
			Cartridge::BinaryDump,
			TargetPlatform::AcornElectron | TargetPlatform::ColecoVision | TargetPlatform::MSX)					// ROM
	Format("sg", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Sega)								// SG
	Format("sms", result.cartridges, Cartridge::BinaryDump, TargetPlatform::Sega)								// SMS
	Format("ssd", result.disks, Disk::DiskImageHolder<Storage::Disk::SSD>, TargetPlatform::Acorn)				// SSD
	Format("st", result.disks, Disk::DiskImageHolder<Storage::Disk::ST>, TargetPlatform::AtariST)				// ST
	Format("stx", result.disks, Disk::DiskImageHolder<Storage::Disk::STX>, TargetPlatform::AtariST)				// STX
	Format("tap", result.tapes, Tape::CommodoreTAP, TargetPlatform::Commodore)									// TAP (Commodore)
	Format("tap", result.tapes, Tape::OricTAP, TargetPlatform::Oric)											// TAP (Oric)
	Format("tsx", result.tapes, Tape::TZX, TargetPlatform::MSX)													// TSX
	Format("tzx", result.tapes, Tape::TZX, TargetPlatform::ZX8081)												// TZX
	Format("uef", result.tapes, Tape::UEF, TargetPlatform::Acorn)												// UEF (tape)
	Format("woz", result.disks, Disk::DiskImageHolder<Storage::Disk::WOZ>, TargetPlatform::DiskII)				// WOZ

#undef Format
#undef Insert
#undef TryInsert

	return result;
}

Media Analyser::Static::GetMedia(const std::string &file_name) {
	TargetPlatform::IntType throwaway;
	return GetMediaAndPlatforms(file_name, throwaway);
}

TargetList Analyser::Static::GetTargets(const std::string &file_name) {
	TargetList targets;

	// Collect all disks, tapes ROMs, etc as can be extrapolated from this file, forming the
	// union of all platforms this file might be a target for.
	TargetPlatform::IntType potential_platforms = 0;
	Media media = GetMediaAndPlatforms(file_name, potential_platforms);

	// Hand off to platform-specific determination of whether these things are actually compatible and,
	// if so, how to load them.
	#define Append(x) {\
		auto new_targets = x::GetTargets(media, file_name, potential_platforms);\
		std::move(new_targets.begin(), new_targets.end(), std::back_inserter(targets));\
	}
	if(potential_platforms & TargetPlatform::Acorn)			Append(Acorn);
	if(potential_platforms & TargetPlatform::AmstradCPC)	Append(AmstradCPC);
	if(potential_platforms & TargetPlatform::AppleII)		Append(AppleII);
	if(potential_platforms & TargetPlatform::Atari2600)		Append(Atari2600);
	if(potential_platforms & TargetPlatform::AtariST)		Append(AtariST);
	if(potential_platforms & TargetPlatform::ColecoVision)	Append(Coleco);
	if(potential_platforms & TargetPlatform::Commodore)		Append(Commodore);
	if(potential_platforms & TargetPlatform::DiskII)		Append(DiskII);
	if(potential_platforms & TargetPlatform::Macintosh)		Append(Macintosh);
	if(potential_platforms & TargetPlatform::MSX)			Append(MSX);
	if(potential_platforms & TargetPlatform::Oric)			Append(Oric);
	if(potential_platforms & TargetPlatform::Sega)			Append(Sega);
	if(potential_platforms & TargetPlatform::ZX8081)		Append(ZX8081);
	#undef Append

	// Reset any tapes to their initial position
	for(const auto &target : targets) {
		for(auto &tape : target->media.tapes) {
			tape->reset();
		}
	}

	// Sort by initial confidence. Use a stable sort in case any of the machine-specific analysers
	// picked their insertion order carefully.
	std::stable_sort(targets.begin(), targets.end(),
		[] (const std::unique_ptr<Target> &a, const std::unique_ptr<Target> &b) {
			return a->confidence > b->confidence;
		});

	return targets;
}
<|endoftext|>


<commit_before><commit_msg>Tiled rendering: Use VirtualDevice, and set the MapMode correctly.<commit_after><|endoftext|>


<commit_before>/***************************************************************************\
**
**  tRunTimer.cpp: functions for tRunTimer objects.
**
**  tRunTimer objects are used to keep track of time in a time-evolving
**  simulation model. Their services include keeping track of when it's
**  time to write output, printing the current time to standard output if
**  desired, and writing the current time to a file every so often.
**
**  Version 1.0, Greg Tucker, November 1997
**
**  Potential additions/improvements:
**  - add functions to set output interval and time status notification
**    interval
**
**  $Id: tRunTimer.cpp,v 1.8 1999-02-01 21:01:28 gtucker Exp $
\***************************************************************************/

#include <iostream.h>
#include <fstream.h>
#include <assert.h>

#include "../tInputFile/tInputFile.h"

#include "tRunTimer.h"
//****************************************************
// Constructors
//
// - A default constructor
// - A constructor that sets the run duration and
//   output interval (and if desired sets the option
//   to print time steps to stdout; default is 1,
//   see header file)
// - A constructor that reads run duration and
//   output interval from a tInputFile object (and
//   if desired sets the option
//   to print time steps to stdout; default is 1,
//   see header file)
//   NG changed this constructor so that if layering
//   info is read in, the start time is set to the
//   time which layers are read in.  Must have this
//   for the layering to make sense, but might also
//   want this if reading in any type of input other
//   than the standard parameters.  (OPTREADINPUT>0)
//   Wasn't changed because I don't know how other
//   people want this handled.  Bad practice to have
//   something about layering in here though.
//
// Note that the notifyInterval is always initialized
// at 1000, but of course this could be changed.
//****************************************************

tRunTimer::tRunTimer()
{
	currentTime = 0;
	endTime = 1;
	outputInterval = 1;
	nextOutputTime = 0;
	optPrintEachTime = 1;
	notifyInterval = 1000;
	nextNotify = 0;
}

tRunTimer::tRunTimer( double duration, double opint, int optprint )
{
	currentTime = 0;
	endTime = duration;
	outputInterval = opint;
	nextOutputTime = 0;
	optPrintEachTime = optprint;
	notifyInterval = 1000;
	nextNotify = 0;
}

tRunTimer::tRunTimer( tInputFile &infile, int optprint )
{
	endTime = infile.ReadItem( endTime, "RUNTIME" );
	outputInterval = infile.ReadItem( outputInterval, "OPINTRVL" );
	optPrintEachTime = optprint;
	notifyInterval = 1000;
  double help;
  //If you are reading in layering information, the timer should
  //be set to the time in which the layers were output, since
  //time is tracked in the layers and restarting at time zero
  //would make the layer times non-sensical.
  help = infile.ReadItem( help, "OPTREADINPUT" );
  if(help>0){
     help = infile.ReadItem( help, "INPUTTIME" );
     currentTime = help;
     endTime += help;
     nextOutputTime = help;
     nextNotify = help;
  }
  else{
     nextOutputTime = 0;
     nextNotify = 0;
     currentTime = 0;
  }

}

//****************************************************
// Start
//
// Sets the current time and run duration.
//****************************************************
void tRunTimer::Start( double start, double end )
{
   currentTime = start;
   if( end>0.0 ) endTime = end;
}

//****************************************************
// getCurrentTime
//
// Returns the current time.
//****************************************************
double tRunTimer::getCurrentTime()
{
	return currentTime;
}

//****************************************************
// RemainingTime
//
// Returns the remaining time.
//****************************************************
double tRunTimer::RemainingTime()
{
	return endTime - currentTime;
}

//****************************************************
// Advance
//
// Increments the current time by dt.
// Returns 1 if there is still time
// remaining, 0 if the time is up.
//****************************************************
int tRunTimer::Advance( double dt )
{
	currentTime += dt;
	return( currentTime < endTime );
}

//****************************************************
// ReportTimeStatus
//
// Reports the current time to a file and to
// standard output if desired. Output to file is
// only done at selected intervals.
// Compares currentTime with nextNotify to see
// whether it's time to update the time status file,
// and if so opens the file and writes the current
// time (overwriting any previous contents).
// Regardless of the status of nextNotify, if
// optPrintEachTime is selected, the current time is
// reported to cout.
//****************************************************
void tRunTimer::ReportTimeStatus()
{
	if( optPrintEachTime ) cout << currentTime << endl;
	if( currentTime >= nextNotify )
	{
		timeStatusFile.open( "run.time" );
		assert( timeStatusFile.good() );
		timeStatusFile << currentTime << endl;
		timeStatusFile.close();
		nextNotify += notifyInterval;
	}
}

//*************************************************
// CheckOutputTime
//
// Checks to see whether it's time to write output
// yet.
//*************************************************
int tRunTimer::CheckOutputTime()
{
	if( currentTime>=nextOutputTime )
	{
		nextOutputTime += outputInterval;
		return 1;
	}
	else return 0;
}

//*************************************************
// IsFinished
//
// Checks to see whether the run is finished.
//*************************************************
int tRunTimer::IsFinished()
{
	return( currentTime >= endTime );
}

<commit_msg>a little doc<commit_after>/***************************************************************************\
**
**  tRunTimer.cpp: functions for tRunTimer objects.
**
**  tRunTimer objects are used to keep track of time in a time-evolving
**  simulation model. Their services include keeping track of when it's
**  time to write output, printing the current time to standard output if
**  desired, and writing the current time to a file every so often.
**
**  Version 1.0, Greg Tucker, November 1997
**
**  Potential additions/improvements:
**  - add functions to set output interval and time status notification
**    interval
**
**  $Id: tRunTimer.cpp,v 1.9 1999-04-01 17:20:22 gtucker Exp $
\***************************************************************************/

#include <iostream.h>
#include <fstream.h>
#include <assert.h>

#include "../tInputFile/tInputFile.h"
#include "tRunTimer.h"

//****************************************************
// Constructors
//
// - A default constructor
// - A constructor that sets the run duration and
//   output interval (and if desired sets the option
//   to print time steps to stdout; default is 1,
//   see header file)
// - A constructor that reads run duration and
//   output interval from a tInputFile object (and
//   if desired sets the option
//   to print time steps to stdout; default is 1,
//   see header file)
//   NG changed this constructor so that if layering
//   info is read in, the start time is set to the
//   time which layers are read in.  Must have this
//   for the layering to make sense, but might also
//   want this if reading in any type of input other
//   than the standard parameters.  (OPTREADINPUT>0)
//   Wasn't changed because I don't know how other
//   people want this handled.  Bad practice to have
//   something about layering in here though.
//
// Note that the notifyInterval is always initialized
// at 1000, but of course this could be changed.
//****************************************************

tRunTimer::tRunTimer()
{
	currentTime = 0;
	endTime = 1;
	outputInterval = 1;
	nextOutputTime = 0;
	optPrintEachTime = 1;
	notifyInterval = 1000;
	nextNotify = 0;
}

tRunTimer::tRunTimer( double duration, double opint, int optprint )
{
	currentTime = 0;
	endTime = duration;
	outputInterval = opint;
	nextOutputTime = 0;
	optPrintEachTime = optprint;
	notifyInterval = 1000;
	nextNotify = 0;
}

tRunTimer::tRunTimer( tInputFile &infile, int optprint )
{
	endTime = infile.ReadItem( endTime, "RUNTIME" );
	outputInterval = infile.ReadItem( outputInterval, "OPINTRVL" );
	optPrintEachTime = optprint;
	notifyInterval = 1000;
  double help;

  //If you are reading in layering information, the timer should
  //be set to the time in which the layers were output, since
  //time is tracked in the layers and restarting at time zero
  //would make the layer times non-sensical.
  help = infile.ReadItem( help, "OPTREADINPUT" );
  if(help>0){
     help = infile.ReadItem( help, "INPUTTIME" );
     currentTime = help;
     endTime += help;
     nextOutputTime = help;
     nextNotify = help;
  }
  else{
     nextOutputTime = 0;
     nextNotify = 0;
     currentTime = 0;
  }

}

//****************************************************
// Start
//
// Sets the current time and run duration.
//****************************************************
void tRunTimer::Start( double start, double end )
{
   currentTime = start;
   if( end>0.0 ) endTime = end;
}

//****************************************************
// getCurrentTime
//
// Returns the current time.
//****************************************************
double tRunTimer::getCurrentTime()
{
	return currentTime;
}

//****************************************************
// RemainingTime
//
// Returns the remaining time.
//****************************************************
double tRunTimer::RemainingTime()
{
	return endTime - currentTime;
}

//****************************************************
// Advance
//
// Increments the current time by dt.
// Returns 1 if there is still time
// remaining, 0 if the time is up.
//****************************************************
int tRunTimer::Advance( double dt )
{
	currentTime += dt;
	return( currentTime < endTime );
}

//****************************************************
// ReportTimeStatus
//
// Reports the current time to a file and to
// standard output if desired. Output to file is
// only done at selected intervals.
// Compares currentTime with nextNotify to see
// whether it's time to update the time status file,
// and if so opens the file and writes the current
// time (overwriting any previous contents).
// Regardless of the status of nextNotify, if
// optPrintEachTime is selected, the current time is
// reported to cout.
//****************************************************
void tRunTimer::ReportTimeStatus()
{
	if( optPrintEachTime ) cout << currentTime << endl;
	if( currentTime >= nextNotify )
	{
		timeStatusFile.open( "run.time" );
		assert( timeStatusFile.good() );
		timeStatusFile << currentTime << endl;
		timeStatusFile.close();
		nextNotify += notifyInterval;
	}
}

//*************************************************
// CheckOutputTime
//
// Checks to see whether it's time to write output
// yet.
//*************************************************
int tRunTimer::CheckOutputTime()
{
	if( currentTime>=nextOutputTime )
	{
		nextOutputTime += outputInterval;
		return 1;
	}
	else return 0;
}

//*************************************************
// IsFinished
//
// Checks to see whether the run is finished.
//*************************************************
int tRunTimer::IsFinished()
{
	return( currentTime >= endTime );
}

<|endoftext|>


<commit_before>/// HEADER
#include "vector_plot.h"

/// PROJECT
#include <csapex/msg/io.h>
#include <csapex_opencv/cv_mat_message.h>
#include <csapex/param/parameter_factory.h>
#include <csapex/model/node_modifier.h>
#include <csapex/utility/register_apex_plugin.h>
#include <csapex/msg/generic_value_message.hpp>
#include <csapex/view/utility/QtCvImageConverter.h>
#include <csapex/msg/generic_vector_message.hpp>

/// SYSTEM
#include <qwt_scale_engine.h>

using namespace csapex;
using namespace csapex::connection_types;

CSAPEX_REGISTER_CLASS(csapex::VectorPlot, csapex::Node)

VectorPlot::VectorPlot():
    initialize_(true),
    basic_line_color_changed_(true),
    has_time_in_(false),
    num_plots_(1)
{

}

void VectorPlot::setup(NodeModifier &node_modifier)
{
    setupVariadic(node_modifier);
    in_time_  = node_modifier.addOptionalInput<GenericVectorMessage, double>("time");

    out_ = node_modifier.addOutput<CvMatMessage>("Plot");

    color_line_.resize(num_plots_);
}

void VectorPlot::setupParameters(Parameterizable &parameters)
{

    setupVariadicParameters(parameters);

    parameters.addParameter(param::ParameterFactory::declareRange
                            ("~plot/width",
                             128, 4096, 640, 1),
                            [this](param::Parameter* p) {
        width_ = p->as<int>();
        update();
    });
    parameters.addParameter(param::ParameterFactory::declareRange
                            ("~plot/height",
                             128, 4096, 320, 1),
                            [this](param::Parameter* p) {
        height_ = p->as<int>();
        update();
    });

    std::function<void(param::Parameter* p)> setLineColors= [this](param::Parameter* p){
        std::vector<int> c = p->as<std::vector<int>>();
        basic_line_color_.setRed(c[0]);
        basic_line_color_.setGreen(c[1]);
        basic_line_color_.setBlue(c[2]);
        calculateLineColors();
        basic_line_color_changed_ = true;
        update();
    };

    Plot::setupParameters(parameters);

    parameters.addParameter(param::ParameterFactory::declareColorParameter(
                                "~plot/color/line", 100, 100, 255),
                            setLineColors);
    parameters.addParameter(param::ParameterFactory::declareRange(
                                "~plot/line/width", 0.0, 10.0, 0.0, 0.01),
                            line_width_);

    parameters.addParameter(param::ParameterFactory::declareBool
                            ("~output/time/relative",
                             param::ParameterDescription("Use time relative to the first entry"),
                             true),
                            time_relative_);
    parameters.addParameter(param::ParameterFactory::declareBool
                            ("~output/time/seconds",
                             param::ParameterDescription("Convert the time to seconds"),
                             true),
                            time_seconds_);

    parameters.addParameter(param::ParameterFactory::declareTrigger("reset"),
                            [this](param::Parameter*) {
        reset();
    });

    color_fill_.setAlpha(100);
}

void VectorPlot::process()
{
    std::size_t num_inputs = VariadicInputs::getVariadicInputCount();
    num_plots_ = num_inputs;;

    for(std::size_t i_inputs = 0; i_inputs < num_plots_; ++ i_inputs){
        InputPtr in = VariadicInputs::getVariadicInput(i_inputs);
        if(!msg::isConnected(in.get())){
            --num_plots_;
        }

    }

    data_v_.resize(num_plots_);
    calculateLineColors();

    std::size_t data_counter = 0;

    for(std::size_t i_inputs = 0; i_inputs < num_inputs; ++i_inputs){

        InputPtr in = VariadicInputs::getVariadicInput(i_inputs);
        if(msg::isConnected(in.get())){
            GenericVectorMessage::ConstPtr message = msg::getMessage<GenericVectorMessage>(in.get());

            apex_assert(std::dynamic_pointer_cast<GenericValueMessage<double>>(message->nestedType()));

            data_v_[data_counter].resize(message->nestedValueCount());

            for(std::size_t n_point = 0; n_point <message->nestedValueCount(); ++n_point){
                auto pval = std::dynamic_pointer_cast<GenericValueMessage<double> const>(message->nestedValue(n_point));
                data_v_[data_counter][n_point] = pval->value;
            }
//            if(data_counter > 0){
//                apex_assert(data_v_[data_counter].size() == data_v_[data_counter -1].size());
//            }
            ++data_counter;
        }
    }

    data_t_raw_.clear();
    if(msg::hasMessage(in_time_)){
        has_time_in_ = true;
        std::shared_ptr<std::vector<double> const> time = msg::getMessage<GenericVectorMessage, double>(in_time_);
        data_t_raw_.resize(time->size());
        for(std::size_t n = 0; n < time->size(); ++n){
            data_t_raw_[n] = time->at(n);
        }

        apex_assert(data_t_raw_.size() == data_v_.front().size());
    }
    else{
        has_time_in_ = false;
        data_t_.resize(data_v_.front().size());
        for(std::size_t i = 0; i < data_t_.size();++i){
            data_t_[i] = i;
        }
    }

    preparePlot();

    if(msg::isConnected(out_)) {
        renderAndSend();
    }

    display_request();
}

void VectorPlot::reset()
{
    data_v_.clear();
    data_t_.clear();
    data_t_raw_.clear();
    initialize_ = true;
    num_plots_ = 1;
    init();
}

void VectorPlot::init()
{
    has_time_in_ = false;
    auto now = std::chrono::system_clock::now();
    start_t_ = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
}

void VectorPlot::preparePlot()
{
    color_fill_.setAlpha(100);

    if(has_time_in_){
        std::size_t n = data_t_raw_.size();
        data_t_.resize(n, 0.0);

        double time_offset = time_relative_ ? data_t_raw_.front() : 0.0;
        double time_scale = time_seconds_ ? 1e-6 : 1.0;

        for(std::size_t i = 0; i < n; ++i) {
            data_t_[i] = (data_t_raw_[i] - time_offset) * time_scale;
        }
    }

    std::vector<double> min_list;
    std::vector<double> max_list;
    for(auto data: data_v_) {
        if(data.size() != 0) {
            min_list.push_back(std::min(0.0, *std::min_element(data.begin(), data.end())));
            max_list.push_back(std::max(0.0, *std::max_element(data.begin(), data.end())));
        }
    }

    double min = std::min(0.0, *std::min_element(min_list.begin(), min_list.end()));
    double max = std::max(0.0, *std::max_element(max_list.begin(), max_list.end()));

    x_map.setScaleInterval(data_t_.front(), data_t_.back());
    y_map.setScaleInterval(min - 1, max + 1);
}

void VectorPlot::renderAndSend()
{
    QImage image(width_, height_, QImage::Format_RGB32);
    QPainter painter;
    painter.begin(&image);
    painter.fillRect(image.rect(), color_bg_);

    QRect r(0, 0, image.width(), image.height());

    x_map.setPaintInterval( r.left(), r.right() );
    y_map.setPaintInterval( r.bottom(), r.top() );

    if(basic_line_color_changed_) {
        calculateLineColors();
    }

    std::vector<double> x_data;

    QwtPlotCurve curve[data_v_.size()];
    for(std::size_t  num_plot= 0; num_plot < data_v_.size(); ++num_plot) {

        painter.setRenderHint( QPainter::Antialiasing,
                               curve[num_plot].testRenderHint( QwtPlotItem::RenderAntialiased ) );
        painter.setRenderHint( QPainter::HighQualityAntialiasing,
                               curve[num_plot].testRenderHint( QwtPlotItem::RenderAntialiased ) );
        curve[num_plot].setBaseline(0.0);

        curve[num_plot].setPen(color_line_.at(num_plot), line_width_);

        curve[num_plot].setStyle(QwtPlotCurve::Lines);

        curve[num_plot].setBrush(QBrush(color_fill_, Qt::SolidPattern));

        curve[num_plot].setRawSamples(data_t_.data(), data_v_.at(num_plot).data(), data_t_.size());

        curve[num_plot].draw(&painter, x_map, y_map, r);
    }

    QwtLinearScaleEngine e;
    QwtPlotScaleItem scale_time(QwtScaleDraw::TopScale, y_map.s1());
    scale_time.setScaleDiv(e.divideScale(x_map.s1(), x_map.s2(), 10, 10));

    QwtPlotScaleItem scale_value(QwtScaleDraw::RightScale, x_map.s1());
    scale_value.setScaleDiv(e.divideScale(y_map.s1(), y_map.s2(), 10, 10));

    scale_time.draw(&painter, x_map, y_map, r);
    scale_value.draw(&painter, x_map, y_map, r);

    CvMatMessage::Ptr out_msg = std::make_shared<CvMatMessage>(enc::bgr, 0);
    out_msg->value = QtCvImageConverter::Converter<QImage>::QImage2Mat(image);

    msg::publish(out_, out_msg);
}
double VectorPlot::getLineWidth() const
{
    return line_width_;
}

QColor VectorPlot::getLineColor(std::size_t idx) const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    return color_line_[idx];
}

const double* VectorPlot::getTData() const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    return data_t_.data();
}
const double* VectorPlot::getVData(std::size_t idx) const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    return data_v_.at(idx).data();
}
std::size_t VectorPlot::getVDataCountNumCurves() const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    return data_v_.size();
}
std::size_t VectorPlot::getCount() const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    std::vector<std::size_t> min_sz(1+data_v_.size());
    min_sz[0] = data_t_.size();
    for(std::size_t i = 0; i < data_v_.size(); ++i){
        min_sz[i+1] = data_v_[i].size();
    }
    std::size_t res  = std::min(data_t_.size(), *std::min_element(min_sz.begin(), min_sz.end()));
    return res;
}

Input* VectorPlot::createVariadicInput(TokenDataConstPtr type, const std::string& label, bool /*optional*/)
{
    return VariadicInputs::createVariadicInput(connection_types::makeEmpty<connection_types::GenericVectorMessage>(), label.empty() ? "Value" : label, getVariadicInputCount() == 0 ? false : true);
}

void VectorPlot::calculateLineColors()
{
    int r,g,b,a;
    basic_line_color_.getRgb(&r,&g,&b,&a);
    QColor color;
    color.setRed(r);
    color.setGreen(g);
    color.setBlue(b);
    int h,s,v;
    color.getHsv(&h,&s,&v);

    for(std::size_t i = 0; i < num_plots_; ++i) {

        double hnew =  h + i * 360/num_plots_;
        while (hnew > 359 || hnew < 0) {
            if(hnew > 359) {
                hnew -= 360;
            }
            else if(hnew < 0) {
                hnew += 360;
            }

        }
        color.setHsv(hnew,s,v);
        color_line_[i] = color;
    }

    basic_line_color_changed_ = false;
    update();
}
<commit_msg>fixed vector plot zero elements bug<commit_after>/// HEADER
#include "vector_plot.h"

/// PROJECT
#include <csapex/msg/io.h>
#include <csapex_opencv/cv_mat_message.h>
#include <csapex/param/parameter_factory.h>
#include <csapex/model/node_modifier.h>
#include <csapex/utility/register_apex_plugin.h>
#include <csapex/msg/generic_value_message.hpp>
#include <csapex/view/utility/QtCvImageConverter.h>
#include <csapex/msg/generic_vector_message.hpp>

/// SYSTEM
#include <qwt_scale_engine.h>

using namespace csapex;
using namespace csapex::connection_types;

CSAPEX_REGISTER_CLASS(csapex::VectorPlot, csapex::Node)

VectorPlot::VectorPlot():
    initialize_(true),
    basic_line_color_changed_(true),
    has_time_in_(false),
    num_plots_(1)
{

}

void VectorPlot::setup(NodeModifier &node_modifier)
{
    setupVariadic(node_modifier);
    in_time_  = node_modifier.addOptionalInput<GenericVectorMessage, double>("time");

    out_ = node_modifier.addOutput<CvMatMessage>("Plot");

    color_line_.resize(num_plots_);
}

void VectorPlot::setupParameters(Parameterizable &parameters)
{

    setupVariadicParameters(parameters);

    parameters.addParameter(param::ParameterFactory::declareRange
                            ("~plot/width",
                             128, 4096, 640, 1),
                            [this](param::Parameter* p) {
        width_ = p->as<int>();
        update();
    });
    parameters.addParameter(param::ParameterFactory::declareRange
                            ("~plot/height",
                             128, 4096, 320, 1),
                            [this](param::Parameter* p) {
        height_ = p->as<int>();
        update();
    });

    std::function<void(param::Parameter* p)> setLineColors= [this](param::Parameter* p){
        std::vector<int> c = p->as<std::vector<int>>();
        basic_line_color_.setRed(c[0]);
        basic_line_color_.setGreen(c[1]);
        basic_line_color_.setBlue(c[2]);
        calculateLineColors();
        basic_line_color_changed_ = true;
        update();
    };

    Plot::setupParameters(parameters);

    parameters.addParameter(param::ParameterFactory::declareColorParameter(
                                "~plot/color/line", 100, 100, 255),
                            setLineColors);
    parameters.addParameter(param::ParameterFactory::declareRange(
                                "~plot/line/width", 0.0, 10.0, 0.0, 0.01),
                            line_width_);

    parameters.addParameter(param::ParameterFactory::declareBool
                            ("~output/time/relative",
                             param::ParameterDescription("Use time relative to the first entry"),
                             true),
                            time_relative_);
    parameters.addParameter(param::ParameterFactory::declareBool
                            ("~output/time/seconds",
                             param::ParameterDescription("Convert the time to seconds"),
                             true),
                            time_seconds_);

    parameters.addParameter(param::ParameterFactory::declareTrigger("reset"),
                            [this](param::Parameter*) {
        reset();
    });

    color_fill_.setAlpha(100);
}

void VectorPlot::process()
{
    std::size_t num_inputs = VariadicInputs::getVariadicInputCount();
    num_plots_ = num_inputs;;

    for(std::size_t i_inputs = 0; i_inputs < num_plots_; ++ i_inputs){
        InputPtr in = VariadicInputs::getVariadicInput(i_inputs);
        if(!msg::isConnected(in.get())){
            --num_plots_;
        }

    }

    data_v_.resize(num_plots_);
    calculateLineColors();

    std::size_t data_counter = 0;

    for(std::size_t i_inputs = 0; i_inputs < num_inputs; ++i_inputs){

        InputPtr in = VariadicInputs::getVariadicInput(i_inputs);
        if(msg::isConnected(in.get())){
            GenericVectorMessage::ConstPtr message = msg::getMessage<GenericVectorMessage>(in.get());

            apex_assert(std::dynamic_pointer_cast<GenericValueMessage<double>>(message->nestedType()));

            data_v_[data_counter].resize(message->nestedValueCount());

            for(std::size_t n_point = 0; n_point <message->nestedValueCount(); ++n_point){
                auto pval = std::dynamic_pointer_cast<GenericValueMessage<double> const>(message->nestedValue(n_point));
                data_v_[data_counter][n_point] = pval->value;
            }
//            if(data_counter > 0){
//                apex_assert(data_v_[data_counter].size() == data_v_[data_counter -1].size());
//            }
            ++data_counter;
        }
    }

    data_t_raw_.clear();
    if(msg::hasMessage(in_time_)){
        has_time_in_ = true;
        std::shared_ptr<std::vector<double> const> time = msg::getMessage<GenericVectorMessage, double>(in_time_);
        data_t_raw_.resize(time->size());
        for(std::size_t n = 0; n < time->size(); ++n){
            data_t_raw_[n] = time->at(n);
        }

        apex_assert(data_t_raw_.size() == data_v_.front().size());
    }
    else{
        has_time_in_ = false;
        data_t_.resize(data_v_.front().size());
        for(std::size_t i = 0; i < data_t_.size();++i){
            data_t_[i] = i;
        }
    }

    preparePlot();

    if(msg::isConnected(out_)) {
        renderAndSend();
    }

    display_request();
}

void VectorPlot::reset()
{
    data_v_.clear();
    data_t_.clear();
    data_t_raw_.clear();
    initialize_ = true;
    num_plots_ = 1;
    init();
}

void VectorPlot::init()
{
    has_time_in_ = false;
    auto now = std::chrono::system_clock::now();
    start_t_ = std::chrono::duration_cast<std::chrono::microseconds>(now.time_since_epoch()).count();
}

void VectorPlot::preparePlot()
{
    color_fill_.setAlpha(100);

    if(has_time_in_){
        std::size_t n = data_t_raw_.size();
        data_t_.resize(n, 0.0);

        double time_offset = time_relative_ ? data_t_raw_.front() : 0.0;
        double time_scale = time_seconds_ ? 1e-6 : 1.0;

        for(std::size_t i = 0; i < n; ++i) {
            data_t_[i] = (data_t_raw_[i] - time_offset) * time_scale;
        }
    }

    std::vector<double> min_list;
    std::vector<double> max_list;
    for(auto data: data_v_) {
        if(data.size() != 0) {
            min_list.push_back(std::min(0.0, *std::min_element(data.begin(), data.end())));
            max_list.push_back(std::max(0.0, *std::max_element(data.begin(), data.end())));
        }
    }
    double min = 0;
    double max = 0;
    if(min_list.size() > 0){
        min = std::min(0.0, *std::min_element(min_list.begin(), min_list.end()));
    }
    if(max_list.size() > 0){
        max = std::max(0.0, *std::max_element(max_list.begin(), max_list.end()));
    }
    if(data_t_.size() == 0){
        x_map.setScaleInterval(-1,1);
    }
    else{
        x_map.setScaleInterval(data_t_.front(), data_t_.back());
    }
    y_map.setScaleInterval(min - 1, max + 1);
}

void VectorPlot::renderAndSend()
{
    QImage image(width_, height_, QImage::Format_RGB32);
    QPainter painter;
    painter.begin(&image);
    painter.fillRect(image.rect(), color_bg_);

    QRect r(0, 0, image.width(), image.height());

    x_map.setPaintInterval( r.left(), r.right() );
    y_map.setPaintInterval( r.bottom(), r.top() );

    if(basic_line_color_changed_) {
        calculateLineColors();
    }

    std::vector<double> x_data;

    QwtPlotCurve curve[data_v_.size()];
    for(std::size_t  num_plot= 0; num_plot < data_v_.size(); ++num_plot) {

        painter.setRenderHint( QPainter::Antialiasing,
                               curve[num_plot].testRenderHint( QwtPlotItem::RenderAntialiased ) );
        painter.setRenderHint( QPainter::HighQualityAntialiasing,
                               curve[num_plot].testRenderHint( QwtPlotItem::RenderAntialiased ) );
        curve[num_plot].setBaseline(0.0);

        curve[num_plot].setPen(color_line_.at(num_plot), line_width_);

        curve[num_plot].setStyle(QwtPlotCurve::Lines);

        curve[num_plot].setBrush(QBrush(color_fill_, Qt::SolidPattern));

        curve[num_plot].setRawSamples(data_t_.data(), data_v_.at(num_plot).data(), data_t_.size());

        curve[num_plot].draw(&painter, x_map, y_map, r);
    }

    QwtLinearScaleEngine e;
    QwtPlotScaleItem scale_time(QwtScaleDraw::TopScale, y_map.s1());
    scale_time.setScaleDiv(e.divideScale(x_map.s1(), x_map.s2(), 10, 10));

    QwtPlotScaleItem scale_value(QwtScaleDraw::RightScale, x_map.s1());
    scale_value.setScaleDiv(e.divideScale(y_map.s1(), y_map.s2(), 10, 10));

    scale_time.draw(&painter, x_map, y_map, r);
    scale_value.draw(&painter, x_map, y_map, r);

    CvMatMessage::Ptr out_msg = std::make_shared<CvMatMessage>(enc::bgr, 0);
    out_msg->value = QtCvImageConverter::Converter<QImage>::QImage2Mat(image);

    msg::publish(out_, out_msg);
}
double VectorPlot::getLineWidth() const
{
    return line_width_;
}

QColor VectorPlot::getLineColor(std::size_t idx) const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    return color_line_[idx];
}

const double* VectorPlot::getTData() const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    return data_t_.data();
}
const double* VectorPlot::getVData(std::size_t idx) const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    return data_v_.at(idx).data();
}
std::size_t VectorPlot::getVDataCountNumCurves() const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    return data_v_.size();
}
std::size_t VectorPlot::getCount() const
{
    std::unique_lock<std::recursive_mutex> lock(mutex_);
    std::vector<std::size_t> min_sz(1+data_v_.size());
    min_sz[0] = data_t_.size();
    for(std::size_t i = 0; i < data_v_.size(); ++i){
        min_sz[i+1] = data_v_[i].size();
    }
    std::size_t res  = std::min(data_t_.size(), *std::min_element(min_sz.begin(), min_sz.end()));
    return res;
}

Input* VectorPlot::createVariadicInput(TokenDataConstPtr type, const std::string& label, bool /*optional*/)
{
    return VariadicInputs::createVariadicInput(connection_types::makeEmpty<connection_types::GenericVectorMessage>(), label.empty() ? "Value" : label, getVariadicInputCount() == 0 ? false : true);
}

void VectorPlot::calculateLineColors()
{
    int r,g,b,a;
    basic_line_color_.getRgb(&r,&g,&b,&a);
    QColor color;
    color.setRed(r);
    color.setGreen(g);
    color.setBlue(b);
    int h,s,v;
    color.getHsv(&h,&s,&v);

    for(std::size_t i = 0; i < num_plots_; ++i) {

        double hnew =  h + i * 360/num_plots_;
        while (hnew > 359 || hnew < 0) {
            if(hnew > 359) {
                hnew -= 360;
            }
            else if(hnew < 0) {
                hnew += 360;
            }

        }
        color.setHsv(hnew,s,v);
        color_line_[i] = color;
    }

    basic_line_color_changed_ = false;
    update();
}
<|endoftext|>