<commit_before>#include "stdafx.h"
#include "titlescene.h"
#include <dukat/dukat.h>

namespace dukat
{
	TitleScene::TitleScene(Game3* game3) : game(game3)
	{
		overlay_meshes.stage = RenderStage::OVERLAY;
		overlay_meshes.visible = true;

		auto title_text = game->create_text_mesh();
		title_text->set_size(1.0f / 10.0f);
		title_text->transform.position = { 0.0f, 0.25f, 0.0f };
		title_text->set_text("<#red>Framebuffer Effects</>");
		title_text->align = TextMeshInstance::Align::Center;
		overlay_meshes.add_instance(std::move(title_text));

		auto fractals_text = game->create_text_mesh();
		fractals_text->set_size(1.0f / 20.0f);
		fractals_text->transform.position = { -1.0f, 0.0f, 0.0f };
		fractals_button = std::make_unique<TextButton>(fractals_text.get());
		fractals_button->set_text("Fractals");
		fractals_button->set_index(0);
		fractals_button->set_trigger([&](void) {
			game->push_scene("fractals");
		});
		overlay_meshes.add_instance(std::move(fractals_text));

		auto ripples_text = game->create_text_mesh();
		ripples_text->set_size(1.0f / 20.0f);
		ripples_text->transform.position = { -1.0f, -0.1f, 0.0f };
		ripples_button = std::make_unique<TextButton>(ripples_text.get());
		ripples_button->set_text("Ripple Pond");
		ripples_button->set_index(1);
		ripples_button->set_trigger([&](void) {
			game->push_scene("ripplepond");
		});
		overlay_meshes.add_instance(std::move(ripples_text));

		auto quit_text = game->create_text_mesh();
		quit_text->set_size(1.0f / 20.0f);
		quit_text->transform.position = { -1.0f, -0.2f, 0.0f };
		quit_button = std::make_unique<TextButton>(quit_text.get());
		quit_button->set_text("Quit");
		quit_button->set_index(2);
		quit_button->set_trigger([&](void) {
			game->set_done(true);
		});
		overlay_meshes.add_instance(std::move(quit_text));
	}

	void TitleScene::activate(void)
	{
		auto settings = game->get_settings();
		auto camera = std::make_unique<FixedCamera3>(game, Vector3{ 0.0f, 0.0f, 2.5f }, Vector3{ 0.0f, 0.0f, 0.0f }, Vector3::unit_y);
		camera->set_vertical_fov(settings.get_float("camera.fov"));
		camera->set_clip(settings.get_float("camera.nearclip"), settings.get_float("camera.farclip"));
		camera->refresh();
		game->get_renderer()->set_camera(std::move(camera));

		game->set_controller(this);

		game->get<UIManager>()->add_control(fractals_button.get());
		game->get<UIManager>()->add_control(ripples_button.get());
		game->get<UIManager>()->add_control(quit_button.get());
		game->get<UIManager>()->first_control();
	}

	void TitleScene::deactivate(void)
	{
		game->get<UIManager>()->remove_control(fractals_button.get());
		game->get<UIManager>()->remove_control(ripples_button.get());
		game->get<UIManager>()->remove_control(quit_button.get());
	}

	void TitleScene::update(float delta)
	{
		overlay_meshes.update(delta);
	}

	void TitleScene::handle_keyboard(const SDL_Event& e)
	{
		switch (e.key.keysym.sym)
		{
		case SDLK_SPACE:
		case SDLK_RETURN:
			game->get<UIManager>()->trigger_focus();
			break;
		case SDLK_UP:
			game->get<UIManager>()->prev_control();
			break;
		case SDLK_DOWN:
			game->get<UIManager>()->next_control();
			break;
		}
	}

	void TitleScene::render(void)
	{
		auto renderer = game->get_renderer();
		std::vector<Mesh*> meshes;
		meshes.push_back(game->get_debug_meshes());
		meshes.push_back(&overlay_meshes);
		renderer->render(meshes);
	}
}<commit_msg>Fixed framebuffer example<commit_after>#include "stdafx.h"
#include "titlescene.h"
#include <dukat/dukat.h>

namespace dukat
{
	TitleScene::TitleScene(Game3* game3) : game(game3)
	{
		overlay_meshes.stage = RenderStage::OVERLAY;
		overlay_meshes.visible = true;

		auto title_text = game->create_text_mesh();
		title_text->set_size(1.0f / 10.0f);
		title_text->transform.position = { 0.0f, 0.25f, 0.0f };
		title_text->set_text("<#red>Framebuffer Effects</>");
		title_text->halign = TextMeshInstance::Align::Center;
		overlay_meshes.add_instance(std::move(title_text));

		auto fractals_text = game->create_text_mesh();
		fractals_text->set_size(1.0f / 20.0f);
		fractals_text->transform.position = { -1.0f, 0.0f, 0.0f };
		fractals_button = std::make_unique<TextButton>(fractals_text.get());
		fractals_button->set_text("Fractals");
		fractals_button->set_index(0);
		fractals_button->set_trigger([&](void) {
			game->push_scene("fractals");
		});
		overlay_meshes.add_instance(std::move(fractals_text));

		auto ripples_text = game->create_text_mesh();
		ripples_text->set_size(1.0f / 20.0f);
		ripples_text->transform.position = { -1.0f, -0.1f, 0.0f };
		ripples_button = std::make_unique<TextButton>(ripples_text.get());
		ripples_button->set_text("Ripple Pond");
		ripples_button->set_index(1);
		ripples_button->set_trigger([&](void) {
			game->push_scene("ripplepond");
		});
		overlay_meshes.add_instance(std::move(ripples_text));

		auto quit_text = game->create_text_mesh();
		quit_text->set_size(1.0f / 20.0f);
		quit_text->transform.position = { -1.0f, -0.2f, 0.0f };
		quit_button = std::make_unique<TextButton>(quit_text.get());
		quit_button->set_text("Quit");
		quit_button->set_index(2);
		quit_button->set_trigger([&](void) {
			game->set_done(true);
		});
		overlay_meshes.add_instance(std::move(quit_text));
	}

	void TitleScene::activate(void)
	{
		auto settings = game->get_settings();
		auto camera = std::make_unique<FixedCamera3>(game, Vector3{ 0.0f, 0.0f, 2.5f }, Vector3{ 0.0f, 0.0f, 0.0f }, Vector3::unit_y);
		camera->set_vertical_fov(settings.get_float("camera.fov"));
		camera->set_clip(settings.get_float("camera.nearclip"), settings.get_float("camera.farclip"));
		camera->refresh();
		game->get_renderer()->set_camera(std::move(camera));

		game->set_controller(this);

		game->get<UIManager>()->add_control(fractals_button.get());
		game->get<UIManager>()->add_control(ripples_button.get());
		game->get<UIManager>()->add_control(quit_button.get());
		game->get<UIManager>()->first_control();
	}

	void TitleScene::deactivate(void)
	{
		game->get<UIManager>()->remove_control(fractals_button.get());
		game->get<UIManager>()->remove_control(ripples_button.get());
		game->get<UIManager>()->remove_control(quit_button.get());
	}

	void TitleScene::update(float delta)
	{
		overlay_meshes.update(delta);
	}

	void TitleScene::handle_keyboard(const SDL_Event& e)
	{
		switch (e.key.keysym.sym)
		{
		case SDLK_SPACE:
		case SDLK_RETURN:
			game->get<UIManager>()->trigger_focus();
			break;
		case SDLK_UP:
			game->get<UIManager>()->prev_control();
			break;
		case SDLK_DOWN:
			game->get<UIManager>()->next_control();
			break;
		}
	}

	void TitleScene::render(void)
	{
		auto renderer = game->get_renderer();
		std::vector<Mesh*> meshes;
		meshes.push_back(game->get_debug_meshes());
		meshes.push_back(&overlay_meshes);
		renderer->render(meshes);
	}
}<|endoftext|>


<commit_before>/*************************************************************
 * Author: Mgumbo
 *
 * Date Completed: 24 February 2016
 *
 * Description: File containing the implementation for
 *				the Calculator class.
 ***************************************************************/

#include <iostream>
#include <cstdlib>
#include "Calculator.h"

/**
 * A default constructor. Initializes the bool controlling looping
 * to true.
 **/
Calculator::Calculator() : _running(true)
{
}

/**
 * A wrapper function that begins to display the menu.
 **/
void Calculator::start()
{
	//continue to loop through the menu
	do
	{
		displayMenu();
	} while (_running);
} //end start

/**
 * Loops through a text-based menu in order to get user input. Prompts
 * the user to enter an expression and, if it is valid, evaluates the
 * expression and prints the result. This menu will continue to loop
 * until the user provides input to exit.
 **/
void Calculator::displayMenu()
{
	//prompt user and get input
	std::cout << "Enter an expression: ";
	std::string expression;
	std::getline(std::cin, expression);

	//check if the user's group operator input is valid
	if (matchingGroupOperators(expression))
	{
		expression = convertToPostfix(expression);
		std::cout << "Postfix: " << expression << "\n";
		std::cout << "Result is: " << evaluatePostfix(expression) << "\n";

		//check if the user wants to keep using the calculator
		char userInput = ' ';
		do
		{
			std::cout << "Would you like to continue (y/n)? ";
			std::cin >> userInput;

			if (userInput == 'n') //if the user wants to exit
			{
				_running = false; //the user wants to quit
				break; //exit current while
			} //end if
			else if (userInput != 'y') //if user does not input 'y' or 'n'
				std::cout << "Please enter a valid response.\n";
		} while (userInput != 'y'); //end do-while

		std::cout << "\n"; //print a blank line for clarity
		std::cin.ignore(); //clear newline char from stream to continue
	} //end if
	else
		std::cout << "Invalid group operators. "
				  << "Please verify your parenthesis.\n\n";
} //end displayMenu

/**
 * Takes a string representing an expression in infix notation as a parameter
 * and iterates through it in order to verify that each opening group operator
 * has an accompanying closing group operator.
 **/
bool Calculator::matchingGroupOperators(std::string infixExpression) const
{
	//this stack will hold open parenthesis to verify the expression is valid
	Mystack<char> verifyStack;

	//loop through the expression
	for (int i = 0; i < infixExpression.length(); i++)
	{
		if (infixExpression[i] == '(')
			verifyStack.push('(');
		else if (infixExpression[i] == ')')
		{
			if (verifyStack.isEmpty()) //if there's a close without an open
				return false;
			else
				verifyStack.pop();
		} //end else if
	} //end for

	return verifyStack.isEmpty();
} //end matchingGroupOperators

/**
 * Returns an int representing the precedence level of a given operator
 * character. '+' and '-' have the same precedence, but have a lower
 * precedence than '*', '/', and '%'.
 **/
int Calculator::checkPrecedence(char op) const
{
	return (op == '+' || op == '-') ? 1 : 2;
} //end checkPrecedence

/**
 * Takes a string representing an expression in infix notation as a parameter
 * and then attempts to convert the expression into postfix notation. This
 * will account for numbers with multiple digits, and adds a space in between
 * each operator and operand before returning a string representing the
 * expression in proper postfix notation.
 **/
std::string Calculator::convertToPostfix(std::string infixExpression)
{
	std::string postfixExpression = ""; //chars will be appended in postfix form
	Mystack<char> operators; //stack that will hold operators

	//loop through the characters of the infix expression
	for (int i = 0; i < infixExpression.length(); i++)
	{
		char ch = infixExpression[i];

		switch (ch) //check the character
		{
		case ' ': //simply ignore spaces if the user types any
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			while (isdigit(infixExpression[i])) //account for multiple digits
				postfixExpression += infixExpression[i++]; //append digits

			i--; //decrement to prevent from skipping over operators
			postfixExpression += ' '; //add a space after the complete number
			break;
		case '(': //opening group operator
			operators.push(ch);
			break;
		case ')': //closing group operator
			while (operators.top() != '(')
			{
				postfixExpression += operators.top(); //append top of stack
				operators.pop();
				postfixExpression += ' ';
			} //end while
			operators.pop();
			break;
		case '-':
		case '+':
		case '*':
		case '/':
		case '%':
			/* pop the stack until it's either empty, the next operator is
			   higher precedence, or the top is the closing group operator */
			while (!operators.isEmpty() &&
				checkPrecedence(ch) <= checkPrecedence(operators.top()) &&
				operators.top() != '(')
			{
				postfixExpression += operators.top(); //append top of stack
				operators.pop();
				postfixExpression += ' ';
			} //end while
			operators.push(ch); //add the new operator to the stack
			break;
		default: //if the user inputs an invalid character, return empty string
			std::cout << "Invalid character: " << ch << "\n";
			return "";
		} //end switch
	} //end for

	//append the remainder of the operators until there are no more
	while (!operators.isEmpty())
	{
		postfixExpression += operators.top();
		postfixExpression += ' '; //append a space in between operators
		operators.pop();
	} //end while

	return postfixExpression;
} //end convertToPostfix

/**
 * Takes a string representing an expression in postfix notation as a parameter
 * and evaluates the expression to return the result. While iterating through
 * the string, adds operands to a stack and performs operations on them until
 * the expression has been fully evaluated. The result is then returned as an
 * int.
 **/
int Calculator::evaluatePostfix(std::string postfixExpression)
{
	Mystack<int> operands; //will hold all of the operands for evaluation

	//iterate through the postfix expression
	for (int i = 0; i < postfixExpression.length(); i++)
	{
		if (isdigit(postfixExpression[i]))
		{
			std::string temp; //will hold the digits for a multi-digit number
			while (postfixExpression[i] != ' ')
				temp += postfixExpression[i++]; //append digit and increment

			//convert the string to an int, and then push it onto the stack
			operands.push(std::atoi(temp.c_str()));
		} //end if
		else if (postfixExpression[i] != ' ') //do not treat spaces as operators
		{
			//prepare operands and operators
			char operatorChar = postfixExpression[i];
			int operand1, operand2;

			if (!operands.isEmpty()) //the stack should have operands in it
			{
				//since the second operand went in last, get it out first
				operand2 = operands.top();
				operands.pop();
			} //end if
			else
			{
				std::cout << "Error, only one operand. "
						  << "Unable to calculate proper result.\n";
				return 0;
			} //end else

			if (!operands.isEmpty()) //the stack should still have stuff in it
			{
				//now the first operand is retrieved
				operand1 = operands.top();
				operands.pop();
			} //end if
			else
			{
				std::cout << "Error, only one operand. "
						  << "Unable to calculate proper result.\n";
				return 0;
			} //end else

			//perform the appropriate operation
			switch (operatorChar)
			{
			case '+': //addition
				operands.push(operand1 + operand2);
				break;
			case '-': //subtraction
				operands.push(operand1 - operand2);
				break;
			case '*': //multiplication
				operands.push(operand1 * operand2);
				break;
			case '/': //division
				operands.push(operand1 / operand2);
				break;
			case '%': //modulus
				operands.push(operand1 % operand2);
				break;
			} //end switch
		} //end else if
	} //end for

	int result = 0; //initialize to 0 in case the user didn't actually enter anything
	if (!operands.isEmpty())
	{
		//the top is equal to the result, so store it and pop to clear the stack
		result = operands.top();
		operands.pop();
	} //end if

	if (!operands.isEmpty()) //if the stack has contents, something went wrong
	{
		std::cout << "Error, incorrect result\n";
		return 0;
	} //end if

	return result;
} //end evaluatePostfix<commit_msg>Updated file<commit_after>/*************************************************************
 * Author: Mgumbo
 *
 * Date Completed: 24 February 2016
 *
 * Description: File containing the implementation for
 *		the Calculator class.
 ***************************************************************/

#include <iostream>
#include <cstdlib>
#include "Calculator.h"

/**
 * A default constructor. Initializes the bool controlling looping
 * to true.
 **/
Calculator::Calculator() : _running(true)
{
}

/**
 * A wrapper function that begins to display the menu.
 **/
void Calculator::start()
{
	//continue to loop through the menu
	do
	{
		displayMenu();
	} while (_running);
} //end start

/**
 * Loops through a text-based menu in order to get user input. Prompts
 * the user to enter an expression and, if it is valid, evaluates the
 * expression and prints the result. This menu will continue to loop
 * until the user provides input to exit.
 **/
void Calculator::displayMenu()
{
	//prompt user and get input
	std::cout << "Enter an expression: ";
	std::string expression;
	std::getline(std::cin, expression);

	//check if the user's group operator input is valid
	if (matchingGroupOperators(expression))
	{
		expression = convertToPostfix(expression);
		std::cout << "Postfix: " << expression << "\n";
		std::cout << "Result is: " << evaluatePostfix(expression) << "\n";

		//check if the user wants to keep using the calculator
		char userInput = ' ';
		do
		{
			std::cout << "Would you like to continue (y/n)? ";
			std::cin >> userInput;

			if (userInput == 'n') //if the user wants to exit
			{
				_running = false; //the user wants to quit
				break; //exit current while
			} //end if
			else if (userInput != 'y') //if user does not input 'y' or 'n'
				std::cout << "Please enter a valid response.\n";
		} while (userInput != 'y'); //end do-while

		std::cout << "\n"; //print a blank line for clarity
		std::cin.ignore(); //clear newline char from stream to continue
	} //end if
	else
		std::cout << "Invalid group operators. "
				  << "Please verify your parenthesis.\n\n";
} //end displayMenu

/**
 * Takes a string representing an expression in infix notation as a parameter
 * and iterates through it in order to verify that each opening group operator
 * has an accompanying closing group operator.
 **/
bool Calculator::matchingGroupOperators(std::string infixExpression) const
{
	//this stack will hold open parenthesis to verify the expression is valid
	Mystack<char> verifyStack;

	//loop through the expression
	for (int i = 0; i < infixExpression.length(); i++)
	{
		if (infixExpression[i] == '(')
			verifyStack.push('(');
		else if (infixExpression[i] == ')')
		{
			if (verifyStack.isEmpty()) //if there's a close without an open
				return false;
			else
				verifyStack.pop();
		} //end else if
	} //end for

	return verifyStack.isEmpty();
} //end matchingGroupOperators

/**
 * Returns an int representing the precedence level of a given operator
 * character. '+' and '-' have the same precedence, but have a lower
 * precedence than '*', '/', and '%'.
 **/
int Calculator::checkPrecedence(char op) const
{
	return (op == '+' || op == '-') ? 1 : 2;
} //end checkPrecedence

/**
 * Takes a string representing an expression in infix notation as a parameter
 * and then attempts to convert the expression into postfix notation. This
 * will account for numbers with multiple digits, and adds a space in between
 * each operator and operand before returning a string representing the
 * expression in proper postfix notation.
 **/
std::string Calculator::convertToPostfix(std::string infixExpression)
{
	std::string postfixExpression = ""; //chars will be appended in postfix form
	Mystack<char> operators; //stack that will hold operators

	//loop through the characters of the infix expression
	for (int i = 0; i < infixExpression.length(); i++)
	{
		char ch = infixExpression[i];

		switch (ch) //check the character
		{
		case ' ': //simply ignore spaces if the user types any
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
			while (isdigit(infixExpression[i])) //account for multiple digits
				postfixExpression += infixExpression[i++]; //append digits

			i--; //decrement to prevent from skipping over operators
			postfixExpression += ' '; //add a space after the complete number
			break;
		case '(': //opening group operator
			operators.push(ch);
			break;
		case ')': //closing group operator
			while (operators.top() != '(')
			{
				postfixExpression += operators.top(); //append top of stack
				operators.pop();
				postfixExpression += ' ';
			} //end while
			operators.pop();
			break;
		case '-':
		case '+':
		case '*':
		case '/':
		case '%':
			/* pop the stack until it's either empty, the next operator is
			   higher precedence, or the top is the closing group operator */
			while (!operators.isEmpty() &&
				checkPrecedence(ch) <= checkPrecedence(operators.top()) &&
				operators.top() != '(')
			{
				postfixExpression += operators.top(); //append top of stack
				operators.pop();
				postfixExpression += ' ';
			} //end while
			operators.push(ch); //add the new operator to the stack
			break;
		default: //if the user inputs an invalid character, return empty string
			std::cout << "Invalid character: " << ch << "\n";
			return "";
		} //end switch
	} //end for

	//append the remainder of the operators until there are no more
	while (!operators.isEmpty())
	{
		postfixExpression += operators.top();
		postfixExpression += ' '; //append a space in between operators
		operators.pop();
	} //end while

	return postfixExpression;
} //end convertToPostfix

/**
 * Takes a string representing an expression in postfix notation as a parameter
 * and evaluates the expression to return the result. While iterating through
 * the string, adds operands to a stack and performs operations on them until
 * the expression has been fully evaluated. The result is then returned as an
 * int.
 **/
int Calculator::evaluatePostfix(std::string postfixExpression)
{
	Mystack<int> operands; //will hold all of the operands for evaluation

	//iterate through the postfix expression
	for (int i = 0; i < postfixExpression.length(); i++)
	{
		if (isdigit(postfixExpression[i]))
		{
			std::string temp; //will hold the digits for a multi-digit number
			while (postfixExpression[i] != ' ')
				temp += postfixExpression[i++]; //append digit and increment

			//convert the string to an int, and then push it onto the stack
			operands.push(std::atoi(temp.c_str()));
		} //end if
		else if (postfixExpression[i] != ' ') //do not treat spaces as operators
		{
			//prepare operands and operators
			char operatorChar = postfixExpression[i];
			int operand1, operand2;

			if (!operands.isEmpty()) //the stack should have operands in it
			{
				//since the second operand went in last, get it out first
				operand2 = operands.top();
				operands.pop();
			} //end if
			else
			{
				std::cout << "Error, only one operand. "
						  << "Unable to calculate proper result.\n";
				return 0;
			} //end else

			if (!operands.isEmpty()) //the stack should still have stuff in it
			{
				//now the first operand is retrieved
				operand1 = operands.top();
				operands.pop();
			} //end if
			else
			{
				std::cout << "Error, only one operand. "
						  << "Unable to calculate proper result.\n";
				return 0;
			} //end else

			//perform the appropriate operation
			switch (operatorChar)
			{
			case '+': //addition
				operands.push(operand1 + operand2);
				break;
			case '-': //subtraction
				operands.push(operand1 - operand2);
				break;
			case '*': //multiplication
				operands.push(operand1 * operand2);
				break;
			case '/': //division
				operands.push(operand1 / operand2);
				break;
			case '%': //modulus
				operands.push(operand1 % operand2);
				break;
			} //end switch
		} //end else if
	} //end for

	int result = 0; //initialize to 0 in case the user didn't actually enter anything
	if (!operands.isEmpty())
	{
		//the top is equal to the result, so store it and pop to clear the stack
		result = operands.top();
		operands.pop();
	} //end if

	if (!operands.isEmpty()) //if the stack has contents, something went wrong
	{
		std::cout << "Error, incorrect result\n";
		return 0;
	} //end if

	return result;
} //end evaluatePostfix
<|endoftext|>


<commit_before>/*
 * Clever programming language
 * Copyright (c) 2011 Clever Team
 *
 * 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.
 *
 * $Id$
 */

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include "testrunner.h"

TestRunner::~TestRunner() {
	std::vector<std::string>::iterator it;

	for (it = tmp_files.begin(); it != tmp_files.end(); ++it) {
		unlink(it->c_str());
	}
}

void TestRunner::show_result(void) const {
	timeval end_time;
	double duration;

	gettimeofday(&end_time, NULL);

	duration = (end_time.tv_sec  - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec)/1000000.0;

	std::cout << "-----------------------------------" << std::endl;
	std::cout << "Tests: " << files.size() << std::endl;
	std::cout << "-----------------------------------" << std::endl;
	std::cout << "Passed tests: " << pass << std::endl;
	std::cout << "Failed tests: " << fail << std::endl;

#ifndef _WIN32
	if (valgrind) {
		std::cout << "Leaked tests: " << leak << std::endl;
	}
#endif

	std::cout << "-----------------------------------" << std::endl;
	std::cout << "Time taken: " << duration << " seconds" << std::endl;
	std::cout << "-----------------------------------" << std::endl;
}

void TestRunner::find(char* dir) {
	DIR *dp;
	std::fstream filep;
	std::string path;

	// Ignore .log files
	path = std::string(dir);
	if ((path.size()-4 == path.rfind(".log")) || (path.size()-4 == path.rfind(".mem"))) {
		return;
	}

	// If it's not a file, then it must be a directory
	filep.open(dir);
	if (filep.is_open()) {
		filep.close();
		files.push_back(std::string(dir));
	} else if ((dp = opendir(dir)) != NULL) {
		closedir(dp);
		path = std::string(dir);
		if (path[path.size()-1] != '/') {
			path = path + "/";
		}
		load_folder(path.c_str());
	} else {
		std::cout << "Couldn't open the file or directory specified: " << std::string(dir) << std::endl;
		//exit(1);
		return;
	}
}

void TestRunner::run(void) {
	FILE *fp;
	std::vector<std::string>::iterator it;
	std::string file_name, tmp_file;
	pcrecpp::RE regex("((?s:.(?!==CODE==))+)\\s*==CODE==\\s*((?s:.(?!==RESULT==))+)\\s*==RESULT==\\s*((?s:.+))\\s+");

	if (!files.size()) {
		std::cout << "No files found.";
		exit(1);
	}

	for (it = files.begin(); it != files.end(); ++it) {
		char result[300] = {0};
		std::string title, source, expect, log_line, command;
		unsigned int filesize;

		file_name = *it;

		tmp_file = file_name + ".tmp";

		regex.FullMatch(read_file(file_name.c_str()), &title, &source, &expect);

		write_file(tmp_file, source);

#ifndef _WIN32
		if (valgrind) {
			command = std::string("valgrind -q --tool=memcheck --leak-check=yes --num-callers=30 --log-file=") + file_name + std::string(".mem");
			command = command + std::string(" ./clever -f ") + tmp_file + " 2>&1";
			fp = popen(command.c_str(), "r");
		} else {
			command = std::string("./clever -f ") + tmp_file + " 2>&1";
			fp = popen(command.c_str(), "r");
		}
#else
		command = std::string("clever.exe -f ") + tmp_file + " 2>&1";
		fp = popen(command.c_str(), "r");
#endif

		fread(result, 1, sizeof(result)-1, fp);

		// Tricky uh?
		pclose(fp);

		// Valgrind log is empty?
#ifndef _WIN32
		if (valgrind) {
			filesize = file_size(file_name + std::string(".mem"));
			if (filesize == 0) {
				remove(std::string(file_name + std::string(".mem")).c_str());
			} else {
				std::cout << "[LEAK] ";
				leak++;
			}
		}
#endif

		if (pcrecpp::RE(expect).FullMatch(result)) {
			if ((valgrind && filesize == 0) || !valgrind) {
				std::cout << "[OKAY] ";
			}
			pass++;

			// If the log file exists, then remove it.
			if (file_exists(file_name + ".log")) {
				unlink(std::string(file_name + ".log").c_str());
			}
		} else {
			if ((valgrind && filesize == 0) || !valgrind) {
				std::cout << "[FAIL] ";
			}
			log_line = std::string("== Expected ==\n") + expect + std::string("\n");
			log_line.append(std::string("== Got ==\n") + std::string(result));
			write_log(file_name,log_line);
			fail++;
		}

		std::cout << title << " (" << file_name << ")" << std::endl;
	}
}

void TestRunner::write_file(std::string& name, std::string& source) {
	std::ofstream file(name.c_str());

	file << source;
	file.close();

	tmp_files.push_back(name);
}

std::string TestRunner::read_file(const char* name) const {
	std::string source, line;
	std::ifstream file;

	file.open(name);

	if (!file) {
		std::cout << "Couldn't open file " << name << std::endl;
		exit(1);
	}

	while (!file.eof()) {
		getline(file, line);
		source += line + '\n';
	}
	file.close();

	return source;
}

void TestRunner::load_folder(const char* dir) {
	DIR *dp, *dpr;
	struct dirent *dirp;
	std::string path,file;

	if ((dp = opendir(dir)) != NULL) {
		while ((dirp = readdir(dp)) != NULL) {
			if (strcmp(dirp->d_name, ".") == 0 ||
				strcmp(dirp->d_name, "..") == 0 ||
				strstr(dirp->d_name, ".tmp") ||
				strstr(dirp->d_name, ".svn")) {
				continue;
			}
			// Ignore .log files
			file = std::string(dirp->d_name);
			if ((file.size()-4 == file.rfind(".log")) || (file.size()-4 == file.rfind(".mem"))) {
				continue;
			}
			// Is this a folder or a file?
			path = std::string(dir) + std::string(dirp->d_name) + "/";
			if ((dpr = opendir(path.c_str())) != NULL) {
				closedir(dpr);
				load_folder(path.c_str());
			} else {
				path = std::string(dir) + std::string(dirp->d_name);
				files.push_back(path.c_str());
			}
		}
		closedir(dp);
	}
}

std::string TestRunner::extract_folder(const char* file) const {
	std::string path;
	size_t found;

	path = std::string(file);
	found = path.rfind("/");
	if (found != path.npos) {
		path = path.substr(0,found+1);
	}

	return path;
}

void TestRunner::write_log(std::string testname, std::string message) {
	FILE *log;

	testname = testname + ".log";
	log = fopen(testname.c_str(),"w");
	if (log) {
		fputs(message.c_str(),log);
		fclose(log);
	}
}

unsigned int TestRunner::file_size(std::string file) {
	std::ifstream stream;
	unsigned int length;

	stream.open(file.c_str());
	if (stream.is_open()) {
		stream.seekg(0,std::ios::end);
		length = stream.tellg();
		stream.close();

		return length;
	}

	return 0;
}

bool TestRunner::file_exists(std::string file) {
	std::ifstream stream;

	stream.open(file.c_str());
	if (stream.is_open()) {
		stream.close();
		return true;
	} else {
		return false;
	}
}

// ---------------------

void usage(void)
{
	std::cout << "Clever Language - Testrunner" << std::endl;
	std::cout << "Usage: testrunner [options] path-of-test-file/dir" << std::endl;
#ifndef _WIN32
	std::cout << "\t-m: run valgrind on each test" << std::endl;
#endif
}

int main(int argc, char *argv[])
{
	TestRunner testrunner;
	int start_paths = 1;

	if (argc == 1) {
		usage();
		return 1;
	} else {
#ifndef _WIN32
		if (std::string(argv[1]) == std::string("-m")) {
			if (argc == 2) {
				// ./testrunner -m?
				usage();
				return 1;
			}
			// ./testrunner -m <something here>?
			testrunner.valgrind = true;
			start_paths = 2;
#else
			if (argc == 1) {
				// ./testrunner -m?
				usage();
				return 1;
#endif
		} else {
			// ./testrunner <something here>
			testrunner.valgrind = false;
			start_paths = 1;
		}
	}

	for (; start_paths < argc; start_paths++) {
		testrunner.find(argv[start_paths]);
	}
	testrunner.run();
	testrunner.show_result();

	return 0;
}<commit_msg>- Fixed Issue #23<commit_after>/*
 * Clever programming language
 * Copyright (c) 2011 Clever Team
 *
 * 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.
 *
 * $Id$
 */

#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include "testrunner.h"

TestRunner::~TestRunner() {
	std::vector<std::string>::iterator it;

	for (it = tmp_files.begin(); it != tmp_files.end(); ++it) {
		unlink(it->c_str());
	}
}

void TestRunner::show_result(void) const {
	timeval end_time;
	double duration;

	gettimeofday(&end_time, NULL);

	duration = (end_time.tv_sec  - start_time.tv_sec) + (end_time.tv_usec - start_time.tv_usec)/1000000.0;

	std::cout << "-----------------------------------" << std::endl;
	std::cout << "Tests: " << files.size() << std::endl;
	std::cout << "-----------------------------------" << std::endl;
	std::cout << "Passed tests: " << pass << std::endl;
	std::cout << "Failed tests: " << fail << std::endl;

#ifndef _WIN32
	if (valgrind) {
		std::cout << "Leaked tests: " << leak << std::endl;
	}
#endif

	std::cout << "-----------------------------------" << std::endl;
	std::cout << "Time taken: " << duration << " seconds" << std::endl;
	std::cout << "-----------------------------------" << std::endl;
}

void TestRunner::find(char* dir) {
	DIR *dp;
	std::fstream filep;
	std::string path;

	// Ignore .log files
	path = std::string(dir);
	if ((path.size()-4 == path.rfind(".log")) || (path.size()-4 == path.rfind(".mem"))) {
		return;
	}

	// If it's not a file, then it must be a directory
	filep.open(dir);
	if (filep.is_open()) {
		filep.close();
		files.push_back(std::string(dir));
	} else if ((dp = opendir(dir)) != NULL) {
		closedir(dp);
		path = std::string(dir);
		if (path[path.size()-1] != '/') {
			path = path + "/";
		}
		load_folder(path.c_str());
	} else {
		std::cout << "Couldn't open the file or directory specified: " << std::string(dir) << std::endl;
		//exit(1);
		return;
	}
}

void TestRunner::run(void) {
	FILE *fp;
	std::vector<std::string>::iterator it;
	std::string file_name, tmp_file;
	pcrecpp::RE regex("((?s:.(?!==CODE==))+)\\s*==CODE==\\s*((?s:.(?!==RESULT==))+)\\s*==RESULT==\\s*((?s:.+))\\s+");

	if (!files.size()) {
		std::cout << "No files found.";
		exit(1);
	}

	for (it = files.begin(); it != files.end(); ++it) {
		char result[300] = {0};
		std::string title, source, expect, log_line, command;
		unsigned int filesize;

		file_name = *it;

		tmp_file = file_name + ".tmp";

		regex.FullMatch(read_file(file_name.c_str()), &title, &source, &expect);

		write_file(tmp_file, source);

#ifndef _WIN32
		if (valgrind) {
			command = std::string("valgrind -q --tool=memcheck --leak-check=yes --num-callers=30 --log-file=") + file_name + std::string(".mem");
			command = command + std::string(" ./clever -f ") + tmp_file + " 2>&1";
			fp = popen(command.c_str(), "r");
		} else {
			command = std::string("./clever -f ") + tmp_file + " 2>&1";
			fp = popen(command.c_str(), "r");
		}
#else
		command = std::string("clever.exe -f ") + tmp_file + " 2>&1";
		fp = popen(command.c_str(), "r");
#endif

		fread(result, 1, sizeof(result)-1, fp);

		// Tricky uh?
		pclose(fp);

		// Valgrind log is empty?
#ifndef _WIN32
		if (valgrind) {
			filesize = file_size(file_name + std::string(".mem"));
			if (filesize == 0) {
				remove(std::string(file_name + std::string(".mem")).c_str());
			} else {
				std::cout << "[LEAK] ";
				leak++;
			}
		}
#endif

		if (pcrecpp::RE(expect).FullMatch(result)) {
			if ((valgrind && filesize == 0) || !valgrind) {
				std::cout << "[OKAY] ";
			}
			pass++;

			// If the log file exists, then remove it.
			if (file_exists(file_name + ".log")) {
				unlink(std::string(file_name + ".log").c_str());
			}
		} else {
			if ((valgrind && filesize == 0) || !valgrind) {
				std::cout << "[FAIL] ";
			}
			log_line = std::string("== Expected ==\n") + expect + std::string("\n");
			log_line.append(std::string("== Got ==\n") + std::string(result));
			write_log(file_name,log_line);
			fail++;
		}

		std::cout << title << " (" << file_name << ")" << std::endl;
	}
}

void TestRunner::write_file(std::string& name, std::string& source) {
	std::ofstream file(name.c_str());

	file << source;
	file.close();

	tmp_files.push_back(name);
}

std::string TestRunner::read_file(const char* name) const {
	std::string source, line;
	std::ifstream file;

	file.open(name);

	if (!file) {
		std::cout << "Couldn't open file " << name << std::endl;
		exit(1);
	}

	while (!file.eof()) {
		getline(file, line);
		source += line + '\n';
	}
	file.close();

	return source;
}

void TestRunner::load_folder(const char* dir) {
	DIR *dp, *dpr;
	struct dirent *dirp;
	std::string path,file;

	if ((dp = opendir(dir)) != NULL) {
		while ((dirp = readdir(dp)) != NULL) {
			if (strcmp(dirp->d_name, ".") == 0 ||
				strcmp(dirp->d_name, "..") == 0 ||
				strstr(dirp->d_name, ".tmp") ||
				strstr(dirp->d_name, ".svn") ||
                strstr(dirp->d_name, ".gitignore")) {
				continue;
			}
			// Ignore .log files
			file = std::string(dirp->d_name);
			if ((file.size()-4 == file.rfind(".log")) || (file.size()-4 == file.rfind(".mem"))) {
				continue;
			}
			// Is this a folder or a file?
			path = std::string(dir) + std::string(dirp->d_name) + "/";
			if ((dpr = opendir(path.c_str())) != NULL) {
				closedir(dpr);
				load_folder(path.c_str());
			} else {
				path = std::string(dir) + std::string(dirp->d_name);
				files.push_back(path.c_str());
			}
		}
		closedir(dp);
	}
}

std::string TestRunner::extract_folder(const char* file) const {
	std::string path;
	size_t found;

	path = std::string(file);
	found = path.rfind("/");
	if (found != path.npos) {
		path = path.substr(0,found+1);
	}

	return path;
}

void TestRunner::write_log(std::string testname, std::string message) {
	FILE *log;

	testname = testname + ".log";
	log = fopen(testname.c_str(),"w");
	if (log) {
		fputs(message.c_str(),log);
		fclose(log);
	}
}

unsigned int TestRunner::file_size(std::string file) {
	std::ifstream stream;
	unsigned int length;

	stream.open(file.c_str());
	if (stream.is_open()) {
		stream.seekg(0,std::ios::end);
		length = stream.tellg();
		stream.close();

		return length;
	}

	return 0;
}

bool TestRunner::file_exists(std::string file) {
	std::ifstream stream;

	stream.open(file.c_str());
	if (stream.is_open()) {
		stream.close();
		return true;
	} else {
		return false;
	}
}

// ---------------------

void usage(void)
{
	std::cout << "Clever Language - Testrunner" << std::endl;
	std::cout << "Usage: testrunner [options] path-of-test-file/dir" << std::endl;
#ifndef _WIN32
	std::cout << "\t-m: run valgrind on each test" << std::endl;
#endif
}

int main(int argc, char *argv[])
{
	TestRunner testrunner;
	int start_paths = 1;

	if (argc == 1) {
		usage();
		return 1;
	} else {
#ifndef _WIN32
		if (std::string(argv[1]) == std::string("-m")) {
			if (argc == 2) {
				// ./testrunner -m?
				usage();
				return 1;
			}
			// ./testrunner -m <something here>?
			testrunner.valgrind = true;
			start_paths = 2;
#else
			if (argc == 1) {
				// ./testrunner -m?
				usage();
				return 1;
#endif
		} else {
			// ./testrunner <something here>
			testrunner.valgrind = false;
			start_paths = 1;
		}
	}

	for (; start_paths < argc; start_paths++) {
		testrunner.find(argv[start_paths]);
	}
	testrunner.run();
	testrunner.show_result();

	return 0;
}
<|endoftext|>


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

  Library:   CTK

  Copyright (c) Isomics Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

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

// Qt includes
#include <QDebug>
#include <QDate>
#include <QDateTime>
#include <QDateTimeEdit>

// CTK includes
#include "ctkDateRangeWidget.h"
#include "ui_ctkDateRangeWidget.h"
#include "ctkLogger.h"

static ctkLogger logger("org.commontk.libs.widgets.ctkDateRangeWidget");

//-----------------------------------------------------------------------------
class ctkDateRangeWidgetPrivate: public Ui_ctkDateRangeWidget
{
  Q_DECLARE_PUBLIC(ctkDateRangeWidget);
protected:
  ctkDateRangeWidget* const q_ptr;
public:
  ctkDateRangeWidgetPrivate(ctkDateRangeWidget& object);
  /// Automatically select the right radio button based on the date range
  void autoselectRadioButton();

  /// ForceSelectRange is set to true when the user expressively requested
  /// to have "Select Range" option active. This property is set only if
  /// the user clicks on the option or if setSelectRange() is programatically
  /// called
  bool          ForceSelectRange;
  /// DisplayTime is true if the time is displayed in the range widget
  bool          DisplayTime;
};

// --------------------------------------------------------------------------
ctkDateRangeWidgetPrivate::ctkDateRangeWidgetPrivate(ctkDateRangeWidget& object)
  :q_ptr(&object)
{
  this->ForceSelectRange = false;
  this->DisplayTime = true;
}
// -------------------------------------------------------------------------
void ctkDateRangeWidgetPrivate::autoselectRadioButton()
{
  Q_Q(ctkDateRangeWidget);
  QDate startDate = q->startDateTime().date();
  QDate endDate = q->endDateTime().date();
  if (this->ForceSelectRange)
    {
    this->SelectRangeRadioButton->setChecked(true);
    }
  else if (q->isAnyDate())
    {
    this->AnyDateRadioButton->setChecked(true);
    }
  else if (q->startDateTime() != QDateTime(q->startDateTime().date()) ||
           q->endDateTime() != QDateTime(q->endDateTime().date()))
    {
    this->SelectRangeRadioButton->setChecked(true);
    }
  else if (startDate.addDays(1) == endDate &&
           startDate == QDate::currentDate())
    {
    this->TodayRadioButton->setChecked(true);
    }
  else if (startDate.addDays(1) == endDate &&
           endDate == QDate::currentDate())
    {
    this->YesterdayRadioButton->setChecked(true);
    }
  else if (startDate.addDays(7) == endDate &&
           endDate == QDate::currentDate())
    {
    this->LastWeekRadioButton->setChecked(true);
    }
  else if (startDate.addDays(31) == endDate &&
           endDate == QDate::currentDate())
    {
    this->LastMonthRadioButton->setChecked(true);
    }
  else
    {
    this->SelectRangeRadioButton->setChecked(true);
    }
}

// --------------------------------------------------------------------------
ctkDateRangeWidget::ctkDateRangeWidget(QWidget* _parent) : Superclass(_parent)
  , d_ptr(new ctkDateRangeWidgetPrivate(*this))
{
  Q_D(ctkDateRangeWidget);

  d->setupUi(this);

  d->DateRangeWidget->setVisible(d->SelectRangeRadioButton->isChecked());

  this->setDisplayTime(false);
  this->setDateTimeRange(QDateTime(), QDateTime());

  // Note that we connect on the clicked() signal and not the toggled.
  // The clicked() signal is fired only when the USER clicks the radio button
  // and not when the button is checked programatically (except using click()).
  QObject::connect(d->AnyDateRadioButton, SIGNAL(clicked()),
                   this, SLOT(setAnyDate()));
  QObject::connect(d->TodayRadioButton, SIGNAL(clicked()),
                   this, SLOT(setToday()));
  QObject::connect(d->YesterdayRadioButton, SIGNAL(clicked()),
                   this, SLOT(setYesterday()));
  QObject::connect(d->LastWeekRadioButton, SIGNAL(clicked()),
                   this, SLOT(setLastWeek()));
  QObject::connect(d->LastMonthRadioButton, SIGNAL(clicked()),
                   this, SLOT(setLastMonth()));
  QObject::connect(d->SelectRangeRadioButton, SIGNAL(clicked()),
                   this, SLOT(setSelectRange()));

  QObject::connect(d->StartDate, SIGNAL(dateTimeChanged(QDateTime)),
                   this, SIGNAL(startDateTimeChanged(QDateTime)));
  QObject::connect(d->EndDate, SIGNAL(dateTimeChanged(QDateTime)),
                   this, SIGNAL(endDateTimeChanged(QDateTime)));
  QObject::connect(d->StartDate, SIGNAL(dateTimeChanged(QDateTime)),
                   this, SLOT(onDateTimeChanged()));
  QObject::connect(d->EndDate, SIGNAL(dateTimeChanged(QDateTime)),
                   this, SLOT(onDateTimeChanged()));
}

// --------------------------------------------------------------------------
ctkDateRangeWidget::~ctkDateRangeWidget()
{
}

// --------------------------------------------------------------------------
QDateTime ctkDateRangeWidget::startDateTime()const
{
  Q_D(const ctkDateRangeWidget);
  return d->StartDate->dateTime();
}

// --------------------------------------------------------------------------
QDateTime ctkDateRangeWidget::endDateTime()const
{
  Q_D(const ctkDateRangeWidget);
  return d->EndDate->dateTime();
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setStartDateTime(QDateTime dateTime)
{
  Q_D(ctkDateRangeWidget);
  d->StartDate->setDateTime(dateTime);
  d->autoselectRadioButton();
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setEndDateTime(QDateTime dateTime)
{
  Q_D(ctkDateRangeWidget);
  d->EndDate->setDateTime(dateTime);
  d->autoselectRadioButton();
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setDateTimeRange(QDateTime startDateTime, QDateTime endDateTime)
{
  Q_D(ctkDateRangeWidget);
  d->StartDate->setDateTime(startDateTime.isValid() ?
    startDateTime : d->StartDate->minimumDateTime());
  d->EndDate->setDateTime(endDateTime.isValid() ?
    endDateTime : d->EndDate->maximumDateTime());
  d->autoselectRadioButton();
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setDateRange(QDate startDate, QDate endDate)
{
  this->setDateTimeRange(QDateTime(startDate), QDateTime(endDate));
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setAnyDate()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  this->setDateTimeRange(QDateTime(), QDateTime());
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setToday()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  QDate today = QDate::currentDate();
  this->setDateRange(today, today.addDays(1));
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setYesterday()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  QDate today = QDate::currentDate();
  this->setDateRange(today.addDays(-1), today);
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setLastWeek()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  QDate today = QDate::currentDate();
  this->setDateRange(today.addDays(-7), today);
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setLastMonth()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  QDate today = QDate::currentDate();
  this->setDateRange(today.addMonths(-1), today);
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setSelectRange()
{
  Q_D(ctkDateRangeWidget);
  d->SelectRangeRadioButton->setChecked(true);
  d->ForceSelectRange = true;
}

// -------------------------------------------------------------------------
bool ctkDateRangeWidget::isAnyDate()const
{
  Q_D(const ctkDateRangeWidget);
  return this->startDateTime() == d->StartDate->minimumDateTime() &&
         this->endDateTime() == d->EndDate->maximumDateTime();
}

// -------------------------------------------------------------------------
void ctkDateRangeWidget::setDisplayTime(bool displayTime)
{
  Q_D(ctkDateRangeWidget);
  d->DisplayTime = displayTime;
  if ( displayTime )
    {
    d->StartDate->setDisplayFormat( QString( "MMM dd, yyyy HH:mm:ss") );
    d->EndDate->setDisplayFormat( QString( "MMM dd, yyyy HH:mm:ss") );
    }
  else
    {
    d->StartDate->setDisplayFormat( QString( "MMM dd, yyyy") );
    d->EndDate->setDisplayFormat( QString( "MMM dd, yyyy") );
    }
}

// -------------------------------------------------------------------------
bool ctkDateRangeWidget::displayTime()const
{
  logger.error("including time in the date range is not supported now");
  Q_D(const ctkDateRangeWidget);
  return d->DisplayTime;
}

// -------------------------------------------------------------------------
void ctkDateRangeWidget::onDateTimeChanged()
{
  Q_D(ctkDateRangeWidget);
  d->autoselectRadioButton();
}
<commit_msg>COMP: Fix QDateTime Start and End time deprecation warning<commit_after>/*=========================================================================

  Library:   CTK

  Copyright (c) Isomics Inc.

  Licensed under the Apache License, Version 2.0 (the "License");
  you may not use this file except in compliance with the License.
  You may obtain a copy of the License at

      http://www.apache.org/licenses/LICENSE-2.0.txt

  Unless required by applicable law or agreed to in writing, software
  distributed under the License is distributed on an "AS IS" BASIS,
  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  See the License for the specific language governing permissions and
  limitations under the License.

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

// Qt includes
#include <QDebug>
#include <QDate>
#include <QDateTime>
#include <QDateTimeEdit>

// CTK includes
#include "ctkDateRangeWidget.h"
#include "ui_ctkDateRangeWidget.h"
#include "ctkLogger.h"

static ctkLogger logger("org.commontk.libs.widgets.ctkDateRangeWidget");

//-----------------------------------------------------------------------------
class ctkDateRangeWidgetPrivate: public Ui_ctkDateRangeWidget
{
  Q_DECLARE_PUBLIC(ctkDateRangeWidget);
protected:
  ctkDateRangeWidget* const q_ptr;
public:
  ctkDateRangeWidgetPrivate(ctkDateRangeWidget& object);
  /// Automatically select the right radio button based on the date range
  void autoselectRadioButton();

  /// ForceSelectRange is set to true when the user expressively requested
  /// to have "Select Range" option active. This property is set only if
  /// the user clicks on the option or if setSelectRange() is programatically
  /// called
  bool          ForceSelectRange;
  /// DisplayTime is true if the time is displayed in the range widget
  bool          DisplayTime;
};

// --------------------------------------------------------------------------
ctkDateRangeWidgetPrivate::ctkDateRangeWidgetPrivate(ctkDateRangeWidget& object)
  :q_ptr(&object)
{
  this->ForceSelectRange = false;
  this->DisplayTime = true;
}
// -------------------------------------------------------------------------
void ctkDateRangeWidgetPrivate::autoselectRadioButton()
{
  Q_Q(ctkDateRangeWidget);
  QDate startDate = q->startDateTime().date();
  QDate endDate = q->endDateTime().date();
  #if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
  QDateTime startOfDay = q->startDateTime().date().startOfDay();
  QDateTime endOfDay = q->startDateTime().date().endOfDay();
  #else
  QDateTime startOfDay = QDateTime(q->startDateTime().date());
  QDateTime endOfDay = QDateTime(q->endDateTime().date());
  #endif
  if (this->ForceSelectRange)
    {
    this->SelectRangeRadioButton->setChecked(true);
    }
  else if (q->isAnyDate())
    {
    this->AnyDateRadioButton->setChecked(true);
    }
  else if (q->startDateTime() != startOfDay ||
           q->endDateTime() != endOfDay)
    {
    this->SelectRangeRadioButton->setChecked(true);
    }
  else if (startDate.addDays(1) == endDate &&
           startDate == QDate::currentDate())
    {
    this->TodayRadioButton->setChecked(true);
    }
  else if (startDate.addDays(1) == endDate &&
           endDate == QDate::currentDate())
    {
    this->YesterdayRadioButton->setChecked(true);
    }
  else if (startDate.addDays(7) == endDate &&
           endDate == QDate::currentDate())
    {
    this->LastWeekRadioButton->setChecked(true);
    }
  else if (startDate.addDays(31) == endDate &&
           endDate == QDate::currentDate())
    {
    this->LastMonthRadioButton->setChecked(true);
    }
  else
    {
    this->SelectRangeRadioButton->setChecked(true);
    }
}

// --------------------------------------------------------------------------
ctkDateRangeWidget::ctkDateRangeWidget(QWidget* _parent) : Superclass(_parent)
  , d_ptr(new ctkDateRangeWidgetPrivate(*this))
{
  Q_D(ctkDateRangeWidget);

  d->setupUi(this);

  d->DateRangeWidget->setVisible(d->SelectRangeRadioButton->isChecked());

  this->setDisplayTime(false);
  this->setDateTimeRange(QDateTime(), QDateTime());

  // Note that we connect on the clicked() signal and not the toggled.
  // The clicked() signal is fired only when the USER clicks the radio button
  // and not when the button is checked programatically (except using click()).
  QObject::connect(d->AnyDateRadioButton, SIGNAL(clicked()),
                   this, SLOT(setAnyDate()));
  QObject::connect(d->TodayRadioButton, SIGNAL(clicked()),
                   this, SLOT(setToday()));
  QObject::connect(d->YesterdayRadioButton, SIGNAL(clicked()),
                   this, SLOT(setYesterday()));
  QObject::connect(d->LastWeekRadioButton, SIGNAL(clicked()),
                   this, SLOT(setLastWeek()));
  QObject::connect(d->LastMonthRadioButton, SIGNAL(clicked()),
                   this, SLOT(setLastMonth()));
  QObject::connect(d->SelectRangeRadioButton, SIGNAL(clicked()),
                   this, SLOT(setSelectRange()));

  QObject::connect(d->StartDate, SIGNAL(dateTimeChanged(QDateTime)),
                   this, SIGNAL(startDateTimeChanged(QDateTime)));
  QObject::connect(d->EndDate, SIGNAL(dateTimeChanged(QDateTime)),
                   this, SIGNAL(endDateTimeChanged(QDateTime)));
  QObject::connect(d->StartDate, SIGNAL(dateTimeChanged(QDateTime)),
                   this, SLOT(onDateTimeChanged()));
  QObject::connect(d->EndDate, SIGNAL(dateTimeChanged(QDateTime)),
                   this, SLOT(onDateTimeChanged()));
}

// --------------------------------------------------------------------------
ctkDateRangeWidget::~ctkDateRangeWidget()
{
}

// --------------------------------------------------------------------------
QDateTime ctkDateRangeWidget::startDateTime()const
{
  Q_D(const ctkDateRangeWidget);
  return d->StartDate->dateTime();
}

// --------------------------------------------------------------------------
QDateTime ctkDateRangeWidget::endDateTime()const
{
  Q_D(const ctkDateRangeWidget);
  return d->EndDate->dateTime();
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setStartDateTime(QDateTime dateTime)
{
  Q_D(ctkDateRangeWidget);
  d->StartDate->setDateTime(dateTime);
  d->autoselectRadioButton();
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setEndDateTime(QDateTime dateTime)
{
  Q_D(ctkDateRangeWidget);
  d->EndDate->setDateTime(dateTime);
  d->autoselectRadioButton();
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setDateTimeRange(QDateTime startDateTime, QDateTime endDateTime)
{
  Q_D(ctkDateRangeWidget);
  d->StartDate->setDateTime(startDateTime.isValid() ?
    startDateTime : d->StartDate->minimumDateTime());
  d->EndDate->setDateTime(endDateTime.isValid() ?
    endDateTime : d->EndDate->maximumDateTime());
  d->autoselectRadioButton();
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setDateRange(QDate startDate, QDate endDate)
{
  #if (QT_VERSION >= QT_VERSION_CHECK(5,14,0))
  this->setDateTimeRange(startDate.startOfDay(), endDate.endOfDay());
  #else
  this->setDateTimeRange(QDateTime(startDate), QDateTime(endDate));
  #endif
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setAnyDate()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  this->setDateTimeRange(QDateTime(), QDateTime());
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setToday()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  QDate today = QDate::currentDate();
  this->setDateRange(today, today.addDays(1));
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setYesterday()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  QDate today = QDate::currentDate();
  this->setDateRange(today.addDays(-1), today);
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setLastWeek()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  QDate today = QDate::currentDate();
  this->setDateRange(today.addDays(-7), today);
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setLastMonth()
{
  Q_D(ctkDateRangeWidget);
  d->ForceSelectRange = false;
  QDate today = QDate::currentDate();
  this->setDateRange(today.addMonths(-1), today);
}

// --------------------------------------------------------------------------
void ctkDateRangeWidget::setSelectRange()
{
  Q_D(ctkDateRangeWidget);
  d->SelectRangeRadioButton->setChecked(true);
  d->ForceSelectRange = true;
}

// -------------------------------------------------------------------------
bool ctkDateRangeWidget::isAnyDate()const
{
  Q_D(const ctkDateRangeWidget);
  return this->startDateTime() == d->StartDate->minimumDateTime() &&
         this->endDateTime() == d->EndDate->maximumDateTime();
}

// -------------------------------------------------------------------------
void ctkDateRangeWidget::setDisplayTime(bool displayTime)
{
  Q_D(ctkDateRangeWidget);
  d->DisplayTime = displayTime;
  if ( displayTime )
    {
    d->StartDate->setDisplayFormat( QString( "MMM dd, yyyy HH:mm:ss") );
    d->EndDate->setDisplayFormat( QString( "MMM dd, yyyy HH:mm:ss") );
    }
  else
    {
    d->StartDate->setDisplayFormat( QString( "MMM dd, yyyy") );
    d->EndDate->setDisplayFormat( QString( "MMM dd, yyyy") );
    }
}

// -------------------------------------------------------------------------
bool ctkDateRangeWidget::displayTime()const
{
  logger.error("including time in the date range is not supported now");
  Q_D(const ctkDateRangeWidget);
  return d->DisplayTime;
}

// -------------------------------------------------------------------------
void ctkDateRangeWidget::onDateTimeChanged()
{
  Q_D(ctkDateRangeWidget);
  d->autoselectRadioButton();
}
<|endoftext|>


<commit_before>#include "aina.hpp"

#include <stdlib.h>
#include <stdint.h>

#include <string>
#include <functional>
#include <unordered_map>

namespace aina {

enum cell_type : uint8_t {
    T_FREE,
    T_NIL,
    T_PAIR,
    T_SYMBOL,
};

struct cell {
    cell_type type;

    union {

        struct {
            const char *name;
            size_t len;
        } uniq;

        struct {
            value_t car, cdr;
        } pair;

        struct {
            const char *name;
            size_t len, hash;
        } symbol;

    } object;
};

static auto & c_type(struct cell *c)
{ return c->type; }

static auto & c_uniq(struct cell *c)
{ return c->object.uniq; }

static auto & c_pair(struct cell *c)
{ return c->object.pair; }

static auto & c_symbol(struct cell *c)
{ return c->object.symbol; }

static value_t make_unique_object(const char *name, cell_type type)
{
    auto v = static_cast<value_t>(calloc(1, sizeof(struct cell)));
    c_type(v) = type;
    c_uniq(v).name = strdup(name);
    c_uniq(v).len = strlen(name);
    return v;
}

static value_t new_cell()
{
    return static_cast<value_t>(calloc(1, sizeof(struct cell)));
}

static value_t g_nil = make_unique_object("()", T_NIL);
static std::unordered_map<size_t, value_t> g_symbols;

bool is_null(value_t v)
{
    return v == g_nil;
}

value_t nil()
{
    return g_nil;
}

bool is_pair(value_t v)
{
    return T_PAIR == c_type(v);
}

value_t cons(value_t a, value_t b)
{
    auto v = new_cell();
    c_type(v) = T_PAIR;
    c_pair(v).car = a;
    c_pair(v).cdr = b;
    return v;
}

bool is_symbol(value_t v)
{
    return T_SYMBOL == c_type(v);
}

value_t symbol(const char *name)
{
    const std::string str(name);
    const size_t hashval = std::hash<std::string>{}(str);

    auto it = g_symbols.find(hashval);
    if (it != g_symbols.end())
        return it->second;

    auto v = new_cell();
    c_type(v) = T_SYMBOL;
    c_symbol(v).name = strdup(name);
    c_symbol(v).len = str.length();
    c_symbol(v).hash = hashval;

    g_symbols[hashval] = v;
    return v;
}

} // namespace aina

<commit_msg>add missing include<commit_after>#include "aina.hpp"

#include <stdlib.h>
#include <stdint.h>
#include <string.h>

#include <string>
#include <functional>
#include <unordered_map>

namespace aina {

enum cell_type : uint8_t {
    T_FREE,
    T_NIL,
    T_PAIR,
    T_SYMBOL,
};

struct cell {
    cell_type type;

    union {

        struct {
            const char *name;
            size_t len;
        } uniq;

        struct {
            value_t car, cdr;
        } pair;

        struct {
            const char *name;
            size_t len, hash;
        } symbol;

    } object;
};

static auto & c_type(struct cell *c)
{ return c->type; }

static auto & c_uniq(struct cell *c)
{ return c->object.uniq; }

static auto & c_pair(struct cell *c)
{ return c->object.pair; }

static auto & c_symbol(struct cell *c)
{ return c->object.symbol; }

static value_t make_unique_object(const char *name, cell_type type)
{
    auto v = static_cast<value_t>(calloc(1, sizeof(struct cell)));
    c_type(v) = type;
    c_uniq(v).name = strdup(name);
    c_uniq(v).len = strlen(name);
    return v;
}

static value_t new_cell()
{
    return static_cast<value_t>(calloc(1, sizeof(struct cell)));
}

static value_t g_nil = make_unique_object("()", T_NIL);
static std::unordered_map<size_t, value_t> g_symbols;

bool is_null(value_t v)
{
    return v == g_nil;
}

value_t nil()
{
    return g_nil;
}

bool is_pair(value_t v)
{
    return T_PAIR == c_type(v);
}

value_t cons(value_t a, value_t b)
{
    auto v = new_cell();
    c_type(v) = T_PAIR;
    c_pair(v).car = a;
    c_pair(v).cdr = b;
    return v;
}

bool is_symbol(value_t v)
{
    return T_SYMBOL == c_type(v);
}

value_t symbol(const char *name)
{
    const std::string str(name);
    const size_t hashval = std::hash<std::string>{}(str);

    auto it = g_symbols.find(hashval);
    if (it != g_symbols.end())
        return it->second;

    auto v = new_cell();
    c_type(v) = T_SYMBOL;
    c_symbol(v).name = strdup(name);
    c_symbol(v).len = str.length();
    c_symbol(v).hash = hashval;

    g_symbols[hashval] = v;
    return v;
}

} // namespace aina

<|endoftext|>


<commit_before><commit_msg>Switch between full and windowed screen in the game project.<commit_after><|endoftext|>


<commit_before>#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <Engine/MainWindow.hpp>
#include <Engine/Manager/Managers.hpp>
#include <Engine/Hymn.hpp>
#include <Engine/Util/Log.hpp>

int main() {
    if (!glfwInit())
        return 1;

    Log() << "Game started - " << time(nullptr) << "\n";

    MainWindow* window = new MainWindow(640, 480, false, false, "Hymn to Beauty", false);
    glewInit();
    window->Init(false);

    Managers().StartUp();

    Hymn().Load(".");

    while (!window->ShouldClose()) {
        window->Update();
        Hymn().Render();
        window->SwapBuffers();
        glfwPollEvents();
    }

    Managers().ShutDown();

    delete window;

    glfwTerminate();

    Log() << "Game ended - " << time(nullptr) << "\n";

    return 0;
}
<commit_msg>Main game loop with target FPS.<commit_after>#include <GL/glew.h>
#include <GLFW/glfw3.h>
#include <Engine/MainWindow.hpp>
#include <Engine/Manager/Managers.hpp>
#include <Engine/Hymn.hpp>
#include <Engine/Util/Log.hpp>
#include <thread>

int main() {
    if (!glfwInit())
        return 1;

    Log() << "Game started - " << time(nullptr) << "\n";

    MainWindow* window = new MainWindow(640, 480, false, false, "Hymn to Beauty", false);
    glewInit();
    window->Init(false);

    Managers().StartUp();

    Hymn().Load(".");

    // Main loop.
    double targetFPS = 60.0;
    double lastTime = glfwGetTime();
    double lastTimeRender = glfwGetTime();
    while (!window->ShouldClose()) {
        double deltaTime = glfwGetTime() - lastTime;
        lastTime = glfwGetTime();

        window->Update();
        Hymn().Update(static_cast<float>(deltaTime));
        Hymn().Render();

        // Swap buffers and wait until next frame.
        window->SwapBuffers();

        long wait = static_cast<long>((1.0 / targetFPS + lastTimeRender - glfwGetTime()) * 1000000.0);
        if (wait > 0)
            std::this_thread::sleep_for(std::chrono::microseconds(wait));
        lastTimeRender = glfwGetTime();

        // Get input.
        glfwPollEvents();
    }

    Managers().ShutDown();

    delete window;

    glfwTerminate();

    Log() << "Game ended - " << time(nullptr) << "\n";

    return 0;
}
<|endoftext|>


<commit_before>/*
*	Odometer.cpp - Handles the gyroscope (L3G4200D) sensor of the Smartcar.
*	Version: 0.3
*	Author: Dimitris Platis (based on the bildr.org example: http://bildr.org/2011/06/l3g4200d-arduino/)
* 	License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html
*/

#include "Smartcar.h"

/* ---- GYROSCOPE (L3G4200D) ---- */
const unsigned short Gyroscope::DEFAULT_GYRO_SAMPLING = 100; //how often (in ms) will the gyroscope be updated
const int Gyroscope::DEFAULT_GYRO_OFFSET = 8; //value that's usually given by the gyroscope when not moving. Use calibrate method to get an approximation
const float GYRO_SENSITIVITY = 0.07; //L3G4200D specific.
const int GYRO_THRESHOLD = 12; //Tolerance threshold. Determined experimentally, adapt accordingly.
const int CTRL_REG1 = 0x20;
const int CTRL_REG2 = 0x21;
const int CTRL_REG3 = 0x22;
const int CTRL_REG4 = 0x23;
const int CTRL_REG5 = 0x24;
const int L3G4200D_Address = 105; //gyroscope I2C address

Gyroscope::Gyroscope(int offset){
	_gyroOffset = offset;
}

void Gyroscope::attach(){
	initializeGyro();
}

void Gyroscope::begin(unsigned short samplingPeriod){
	_prevSample = millis();
	_samplingRate = samplingPeriod;
}

/* based on http://www.pieter-jan.com/node/7 integration algorithm */
void Gyroscope::update(){
	if (millis()- _prevSample > _samplingRate){
		float gyroRate = 0;
		int gyroValue = getGyroValues();
		short drift = _gyroOffset - gyroValue;
 		if (abs(drift) > GYRO_THRESHOLD){ //if there has been a big enough drift (trying to contemplate for the noise)
			gyroRate = drift * GYRO_SENSITIVITY;
		}
		unsigned long now = millis();
		_angularDisplacement += gyroRate / (1000.0 / (now - _prevSample));
		_prevSample = now;
	}
}

void Gyroscope::initializeGyro(){
	if (!TWCR) Wire.begin(); //if it hasn't been started (TWCR==0), start it
	setupL3G4200D(2000); // Configure L3G4200 at 2000 deg/sec. Other options: 250, 500 (NOT suggested, will have to redetermine offset)
}

/* based on the bildr.org example: http://bildr.org/2011/06/l3g4200d-arduino/ */
int Gyroscope::getGyroValues(){
	byte zMSB = readRegister(L3G4200D_Address, 0x2D);
	byte zLSB = readRegister(L3G4200D_Address, 0x2C);
	return ((zMSB << 8) | zLSB);
}

int Gyroscope::setupL3G4200D(int scale){
	//From  Jim Lindblom of Sparkfun's code

	// Enable x, y, z and turn off power down:
	writeRegister(L3G4200D_Address, CTRL_REG1, 0b00001111);

	// If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
	writeRegister(L3G4200D_Address, CTRL_REG2, 0b00000000);

	// Configure CTRL_REG3 to generate data ready interrupt on INT2
	// No interrupts used on INT1, if you'd like to configure INT1
	// or INT2 otherwise, consult the datasheet:
	writeRegister(L3G4200D_Address, CTRL_REG3, 0b00001000);

	// CTRL_REG4 controls the full-scale range, among other things:

	if(scale == 250){
		writeRegister(L3G4200D_Address, CTRL_REG4, 0b00000000);
	}else if(scale == 500){
		writeRegister(L3G4200D_Address, CTRL_REG4, 0b00010000);
	}else{
		writeRegister(L3G4200D_Address, CTRL_REG4, 0b00110000);
	}

	// CTRL_REG5 controls high-pass filtering of outputs, use it
	// if you'd like:
	writeRegister(L3G4200D_Address, CTRL_REG5, 0b00000000);
}

void Gyroscope::writeRegister(int deviceAddress, byte address, byte val) {
	Wire.beginTransmission(deviceAddress); // start transmission to device
	Wire.write(address);       // send register address
	Wire.write(val);         // send value to write
	Wire.endTransmission();     // end transmission
}

int Gyroscope::readRegister(int deviceAddress, byte address){
	int v;
	Wire.beginTransmission(deviceAddress);
	Wire.write(address); // register to read
	Wire.endTransmission();
	Wire.requestFrom(deviceAddress, 1); // read a byte

	while(!Wire.available()) {
		//waiting
 	}

	v = Wire.read();

	return v;
}

int Gyroscope::calibrate(int measurements){ //use this function in order to determine the offset and change GYRO_OFFSET accordingly
	if (!measurements) return -1; //if a 0 was an argument, return a very high value, to avoid a division with 0 and indicate error
	long sum = 0;
	for (int i = 0; i < measurements; i++){
		sum += getGyroValues();
		delay(10);
	}
	return sum/measurements; //return the average
}
<commit_msg>function is void as it does not return something<commit_after>/*
*	Odometer.cpp - Handles the gyroscope (L3G4200D) sensor of the Smartcar.
*	Version: 0.3
*	Author: Dimitris Platis (based on the bildr.org example: http://bildr.org/2011/06/l3g4200d-arduino/)
* 	License: GNU GPL v3 http://www.gnu.org/licenses/gpl-3.0.html
*/

#include "Smartcar.h"

/* ---- GYROSCOPE (L3G4200D) ---- */
const unsigned short Gyroscope::DEFAULT_GYRO_SAMPLING = 100; //how often (in ms) will the gyroscope be updated
const int Gyroscope::DEFAULT_GYRO_OFFSET = 8; //value that's usually given by the gyroscope when not moving. Use calibrate method to get an approximation
const float GYRO_SENSITIVITY = 0.07; //L3G4200D specific.
const int GYRO_THRESHOLD = 12; //Tolerance threshold. Determined experimentally, adapt accordingly.
const int CTRL_REG1 = 0x20;
const int CTRL_REG2 = 0x21;
const int CTRL_REG3 = 0x22;
const int CTRL_REG4 = 0x23;
const int CTRL_REG5 = 0x24;
const int L3G4200D_Address = 105; //gyroscope I2C address

Gyroscope::Gyroscope(int offset){
	_gyroOffset = offset;
}

void Gyroscope::attach(){
	initializeGyro();
}

void Gyroscope::begin(unsigned short samplingPeriod){
	_prevSample = millis();
	_samplingRate = samplingPeriod;
}

/* based on http://www.pieter-jan.com/node/7 integration algorithm */
void Gyroscope::update(){
	if (millis()- _prevSample > _samplingRate){
		float gyroRate = 0;
		int gyroValue = getGyroValues();
		short drift = _gyroOffset - gyroValue;
 		if (abs(drift) > GYRO_THRESHOLD){ //if there has been a big enough drift (trying to contemplate for the noise)
			gyroRate = drift * GYRO_SENSITIVITY;
		}
		unsigned long now = millis();
		_angularDisplacement += gyroRate / (1000.0 / (now - _prevSample));
		_prevSample = now;
	}
}

void Gyroscope::initializeGyro(){
	Wire.begin(); //initialize the i2c connection
	setupL3G4200D(2000); // Configure L3G4200 at 2000 deg/sec. Other options: 250, 500 (NOT suggested, will have to redetermine offset)
}

/* based on the bildr.org example: http://bildr.org/2011/06/l3g4200d-arduino/ */
int Gyroscope::getGyroValues(){
	byte zMSB = readRegister(L3G4200D_Address, 0x2D);
	byte zLSB = readRegister(L3G4200D_Address, 0x2C);
	return ((zMSB << 8) | zLSB);
}

void Gyroscope::setupL3G4200D(int scale){
	//From  Jim Lindblom of Sparkfun's code

	// Enable x, y, z and turn off power down:
	writeRegister(L3G4200D_Address, CTRL_REG1, 0b00001111);

	// If you'd like to adjust/use the HPF, you can edit the line below to configure CTRL_REG2:
	writeRegister(L3G4200D_Address, CTRL_REG2, 0b00000000);

	// Configure CTRL_REG3 to generate data ready interrupt on INT2
	// No interrupts used on INT1, if you'd like to configure INT1
	// or INT2 otherwise, consult the datasheet:
	writeRegister(L3G4200D_Address, CTRL_REG3, 0b00001000);

	// CTRL_REG4 controls the full-scale range, among other things:

	if(scale == 250){
		writeRegister(L3G4200D_Address, CTRL_REG4, 0b00000000);
	}else if(scale == 500){
		writeRegister(L3G4200D_Address, CTRL_REG4, 0b00010000);
	}else{
		writeRegister(L3G4200D_Address, CTRL_REG4, 0b00110000);
	}

	// CTRL_REG5 controls high-pass filtering of outputs, use it
	// if you'd like:
	writeRegister(L3G4200D_Address, CTRL_REG5, 0b00000000);
}

void Gyroscope::writeRegister(int deviceAddress, byte address, byte val) {
	Wire.beginTransmission(deviceAddress); // start transmission to device
	Wire.write(address);       // send register address
	Wire.write(val);         // send value to write
	Wire.endTransmission();     // end transmission
}

int Gyroscope::readRegister(int deviceAddress, byte address){
	int v;
	Wire.beginTransmission(deviceAddress);
	Wire.write(address); // register to read
	Wire.endTransmission();
	Wire.requestFrom(deviceAddress, 1); // read a byte

	while(!Wire.available()) {
		//waiting
 	}

	v = Wire.read();

	return v;
}

int Gyroscope::calibrate(int measurements){ //use this function in order to determine the offset and change GYRO_OFFSET accordingly
	if (!measurements) return -1; //if a 0 was an argument, return a very high value, to avoid a division with 0 and indicate error
	long sum = 0;
	for (int i = 0; i < measurements; i++){
		sum += getGyroValues();
		delay(10);
	}
	return sum/measurements; //return the average
}
<|endoftext|>


<commit_before>#include <stdexcept>
#include "gtest/gtest.h"
#include "lexer.hpp"
#include "parser.hpp"
#include "optimizer.hpp"
#include "ast.hpp"

TEST(OptimizerTest, CombineIncVisitor)
{
  bfc::parser<bfc::stream_source> parser{
    bfc::lexer<bfc::stream_source>{bfc::stream_source{new std::stringstream{"+++"}}}};
  bfc::optimizer optimizer{false, true};
  bfc::ast_node node = optimizer.optimize(parser.parse());
  EXPECT_FALSE(((bfc::ast_program *) node.get())->empty()) << "Should not produce and empty program node";
  auto it = ((bfc::ast_program *) node.get())->begin();
  EXPECT_NE(dynamic_cast<bfc::ast_add*>(it->get()), nullptr) << "INCs should be parsed into ast_add";
  EXPECT_EQ(((bfc::ast_add*)it->get())->value(), (bf_value) 3) << "3 INCs should be optimized into one ast_add";

}

TEST(OptimizerTest, CombinePtrVisitor)
{
  bfc::parser<bfc::stream_source> parser{
    bfc::lexer<bfc::stream_source>{bfc::stream_source{new std::stringstream{">>>"}}}};
  bfc::optimizer optimizer{false, true};
  bfc::ast_node node = optimizer.optimize(parser.parse());
  EXPECT_FALSE(((bfc::ast_program *) node.get())->empty()) << "Should not produce and empty program node";
  auto it = ((bfc::ast_program *) node.get())->begin();
  EXPECT_NE(dynamic_cast<bfc::ast_mov*>(it->get()), nullptr) << "INCs should be parsed into ast_add";
  EXPECT_EQ(((bfc::ast_mov*)it->get())->offset(), (ptrdiff_t) 3) << "3 INCs should be optimized into one ast_add";

}

TEST(OptimizerTest, ClearLoopsVisitor)
{
  bfc::parser<bfc::stream_source> parser{
    bfc::lexer<bfc::stream_source>{bfc::stream_source{new std::stringstream{"[-]"}}}};
  bfc::optimizer optimizer{false, true};
  bfc::ast_node node = optimizer.optimize(parser.parse());
  EXPECT_FALSE(((bfc::ast_program *) node.get())->empty()) << "Should not produce and empty program node";
  auto it = ((bfc::ast_program *) node.get())->begin();
  EXPECT_NE(dynamic_cast<bfc::ast_set*>(it->get()), nullptr) << "INCs should be parsed into ast_add";
  EXPECT_EQ(((bfc::ast_set*)it->get())->value(), (bf_value) 0) << "3 INCs should be optimized into one ast_add";
}

int main(int argc, char** argv)
{
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<commit_msg>Added test for combine set visitor<commit_after>#include <stdexcept>
#include "gtest/gtest.h"
#include "lexer.hpp"
#include "parser.hpp"
#include "optimizer.hpp"
#include "ast.hpp"

TEST(OptimizerTest, CombineIncVisitor)
{
  bfc::parser<bfc::stream_source> parser{
    bfc::lexer<bfc::stream_source>{bfc::stream_source{new std::stringstream{"+++"}}}};
  bfc::optimizer optimizer{false, true};
  bfc::ast_node node = optimizer.optimize(parser.parse());
  EXPECT_FALSE(((bfc::ast_program *) node.get())->empty()) << "Should not produce an empty program node";
  auto it = ((bfc::ast_program *) node.get())->begin();
  EXPECT_NE(dynamic_cast<bfc::ast_add*>(it->get()), nullptr) << "INCs should be parsed into ast_add";
  EXPECT_EQ(((bfc::ast_add*)it->get())->value(), (bf_value) 3) << "3 INCs should be optimized into one ast_add";

}

TEST(OptimizerTest, CombinePtrVisitor)
{
  bfc::parser<bfc::stream_source> parser{
    bfc::lexer<bfc::stream_source>{bfc::stream_source{new std::stringstream{">>>"}}}};
  bfc::optimizer optimizer{false, true};
  bfc::ast_node node = optimizer.optimize(parser.parse());
  EXPECT_FALSE(((bfc::ast_program *) node.get())->empty()) << "Should not produce an empty program node";
  auto it = ((bfc::ast_program *) node.get())->begin();
  EXPECT_NE(dynamic_cast<bfc::ast_mov*>(it->get()), nullptr) << "MOVs should be parsed into ast_mov";
  EXPECT_EQ(((bfc::ast_mov*)it->get())->offset(), (ptrdiff_t) 3) << "3 MOVs should be optimized into one ast_mov";

}

TEST(OptimizerTest, ClearLoopsVisitor)
{
  bfc::parser<bfc::stream_source> parser{
    bfc::lexer<bfc::stream_source>{bfc::stream_source{new std::stringstream{"[-]"}}}};
  bfc::optimizer optimizer{false, true};
  bfc::ast_node node = optimizer.optimize(parser.parse());
  EXPECT_FALSE(((bfc::ast_program *) node.get())->empty()) << "Should not produce an empty program node";
  auto it = ((bfc::ast_program *) node.get())->begin();
  EXPECT_NE(dynamic_cast<bfc::ast_set*>(it->get()), nullptr) << "Code should be parsed into ast_set";
  EXPECT_EQ(((bfc::ast_set*)it->get())->value(), (bf_value) 0) << "Clearing loop [-] should be optimized into one ast_set(0)";
}

TEST(OptimizerTest, CombineSetVisitor)
{
  bfc::parser<bfc::stream_source> parser{
    bfc::lexer<bfc::stream_source>{bfc::stream_source{new std::stringstream{"[-]++"}}}};
  bfc::optimizer optimizer{false, true};
  bfc::ast_node node = optimizer.optimize(parser.parse());
  EXPECT_FALSE(((bfc::ast_program *) node.get())->empty()) << "Should not produce an empty program node";
  auto it = ((bfc::ast_program *) node.get())->begin();
  EXPECT_NE(dynamic_cast<bfc::ast_set*>(it->get()), nullptr) << "Code should be parsed into ast_set";
  EXPECT_EQ(((bfc::ast_set*)it->get())->value(), (bf_value) 2) << "ast_set(0) and 2 INCs should be parsed into ast_set(2)";
}

int main(int argc, char** argv)
{
  testing::InitGoogleTest(&argc, argv);
  return RUN_ALL_TESTS();
}
<|endoftext|>


<commit_before>/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project.                                                               */
/*----------------------------------------------------------------------------*/

#include "Dispatcher.h"

#include "tcpsockets/TCPAcceptor.h"
#include "tcpsockets/TCPConnector.h"

using namespace nt;

#define DEBUG(str) puts(str)

std::unique_ptr<Dispatcher> Dispatcher::m_instance;

Dispatcher::Dispatcher()
    : m_server(false),
      m_active(false),
      m_update_rate(100),
      m_do_flush(false),
      m_do_reconnect(false) {}

Dispatcher::~Dispatcher() { Stop(); }

void Dispatcher::StartServer(const char* listen_address, unsigned int port) {
  {
    std::lock_guard<std::mutex> lock(m_user_mutex);
    if (m_active) return;
    m_active = true;
  }
  m_server = true;
  m_dispatch_thread = std::thread(&Dispatcher::DispatchThreadMain, this);
  m_clientserver_thread =
      std::thread(&Dispatcher::ServerThreadMain, this, listen_address, port);
}

void Dispatcher::StartClient(const char* server_name, unsigned int port) {
  {
    std::lock_guard<std::mutex> lock(m_user_mutex);
    if (m_active) return;
    m_active = true;
  }
  m_server = false;
  m_dispatch_thread = std::thread(&Dispatcher::DispatchThreadMain, this);
  m_clientserver_thread =
      std::thread(&Dispatcher::ClientThreadMain, this, server_name, port);
}

void Dispatcher::Stop() {
  {
    std::lock_guard<std::mutex> lock(m_user_mutex);
    m_active = false;

    // close all connections
    for (auto& conn : m_connections) conn.net->Stop();
  }

  // wake up dispatch thread with a flush
  m_flush_cv.notify_one();

  // wake up client thread with a reconnect
  ClientReconnect();

  // wake up server thread by shutting down the socket
  if (m_server_acceptor) m_server_acceptor->shutdown();

  // join threads
  if (m_dispatch_thread.joinable()) m_dispatch_thread.join();
  if (m_clientserver_thread.joinable()) m_clientserver_thread.join();
}

void Dispatcher::SetUpdateRate(double interval) {
  // don't allow update rates faster than 100 ms
  if (interval < 0.1)
    interval = 0.1;
  m_update_rate = static_cast<unsigned int>(interval * 1000);
}

void Dispatcher::SetIdentity(llvm::StringRef name) {
  std::lock_guard<std::mutex> lock(m_user_mutex);
  m_identity = name;
}

void Dispatcher::Flush() {
  auto now = std::chrono::steady_clock::now();
  {
    std::lock_guard<std::mutex> lock(m_flush_mutex);
    // don't allow flushes more often than every 100 ms
    if ((now - m_last_flush) < std::chrono::milliseconds(100))
      return;
    m_last_flush = now;
    m_do_flush = true;
  }
  m_flush_cv.notify_one();
}

void Dispatcher::DispatchThreadMain() {
  auto timeout_time = std::chrono::steady_clock::now();
  int count = 0;
  while (m_active) {
    // handle loop taking too long
    auto start = std::chrono::steady_clock::now();
    if (start > timeout_time)
      timeout_time = start;

    // wait for periodic or when flushed
    timeout_time += std::chrono::milliseconds(m_update_rate);
    std::unique_lock<std::mutex> lock(m_flush_mutex);
    m_reconnect_cv.wait_until(lock, timeout_time,
                              [&] { return !m_active || m_do_flush; });
    m_do_flush = false;
    lock.unlock();
    if (!m_active) break;  // in case we were woken up to terminate

    if (++count > 10) {
      DEBUG("dispatch running");
      count = 0;
    }
  }
}

void Dispatcher::ServerThreadMain(const char* listen_address,
                                  unsigned int port) {
  m_server_acceptor.reset(
      new TCPAcceptor(static_cast<int>(port), listen_address));
  if (m_server_acceptor->start() != 0) {
    m_active = false;
    return;
  }
  while (m_active) {
    auto stream = m_server_acceptor->accept();
    if (!stream) {
      m_active = false;
      break;
    }
    DEBUG("server got a connection");

    // add to connections list
    Connection conn;
    conn.net.reset(new NetworkConnection(
        std::move(stream),
        [this](unsigned int id) { return GetEntryType(id); }));
    conn.net->Start();
    AddConnection(std::move(conn));
  }
}

void Dispatcher::ClientThreadMain(const char* server_name, unsigned int port) {
  unsigned int proto_rev = 0x0300;
  while (m_active) {
    // get identity
    std::string self_id;
    {
      std::lock_guard<std::mutex> lock(m_user_mutex);
      self_id = m_identity;
    }

    // sleep between retries
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    // try to connect (with timeout)
    DEBUG("client trying to connect");
    auto stream = TCPConnector::connect(server_name, static_cast<int>(port), 1);
    if (!stream) continue;  // keep retrying
    DEBUG("client connected");

    Connection conn;
    conn.net.reset(new NetworkConnection(
        std::move(stream),
        [this](unsigned int id) { return GetEntryType(id); }));
    conn.net->set_proto_rev(proto_rev);
    conn.net->Start();

    // send client hello
    DEBUG("client sending hello");
    conn.net->outgoing().push(
        NetworkConnection::Outgoing{Message::ClientHello(self_id)});

    // wait for response
    auto msg = conn.net->incoming().pop();
    if (!msg) {
      // disconnected, retry
      DEBUG("client disconnected waiting for first response");
      proto_rev = 0x0300;
      continue;
    }

    if (msg->Is(Message::kProtoUnsup)) {
      // reconnect with lower protocol (if possible)
      if (proto_rev <= 0x0200) {
        // no more options, abort (but keep trying to connect)
        proto_rev = 0x0300;
        continue;
      }
      proto_rev = 0x0200;
      continue;
    }

    if (proto_rev >= 0x0300) {
      // should be server hello; if not, disconnect, but keep trying to connect
      if (!msg->Is(Message::kServerHello)) continue;
      conn.remote_id = msg->str();
      // get the next message (blocks)
      msg = conn.net->incoming().pop();
    }

    // receive initial assignments
    std::vector<std::shared_ptr<Message>> incoming;
    while (true) {
      if (!msg) {
        // disconnected, retry
        DEBUG("client disconnected waiting for initial entries");
        proto_rev = 0x0300;
        continue;
      }
      if (msg->Is(Message::kServerHelloDone)) break;
      if (!msg->Is(Message::kEntryAssign)) {
        // unexpected message
        DEBUG("received message other than entry assignment during initial handshake");
        proto_rev = 0x0300;
        continue;
      }
      incoming.push_back(msg);
      // get the next message (blocks)
      msg = conn.net->incoming().pop();
    }

    // generate outgoing assignments
    NetworkConnection::Outgoing outgoing;

    if (proto_rev >= 0x0300)
      outgoing.push_back(Message::ClientHelloDone());

    if (!outgoing.empty())
      conn.net->outgoing().push(std::move(outgoing));

    // add to connections list (the dispatcher thread will handle from here)
    AddConnection(std::move(conn));

    // block until told to reconnect
    std::unique_lock<std::mutex> lock(m_reconnect_mutex);
    m_reconnect_cv.wait(lock, [&] { return m_do_reconnect; });
    m_do_reconnect = false;
    lock.unlock();
  }
}

void Dispatcher::ClientReconnect() {
  if (m_server) return;
  {
    std::lock_guard<std::mutex> lock(m_reconnect_mutex);
    m_do_reconnect = true;
  }
  m_reconnect_cv.notify_one();
}

void Dispatcher::AddConnection(Connection&& conn) {
  std::lock_guard<std::mutex> lock(m_user_mutex);
  m_connections.push_back(std::move(conn));
}

NT_Type Dispatcher::GetEntryType(unsigned int id) const {
  std::lock_guard<std::mutex> lock(m_idmap_mutex);
  if (id >= m_idmap.size()) return NT_UNASSIGNED;
  auto value = m_idmap[id]->value();
  if (!value) return NT_UNASSIGNED;
  return value->type();
}
<commit_msg>Dispatcher: Avoid warning by using for(;;) instead of while(true).<commit_after>/*----------------------------------------------------------------------------*/
/* Copyright (c) FIRST 2015. All Rights Reserved.                             */
/* Open Source Software - may be modified and shared by FRC teams. The code   */
/* must be accompanied by the FIRST BSD license file in the root directory of */
/* the project.                                                               */
/*----------------------------------------------------------------------------*/

#include "Dispatcher.h"

#include "tcpsockets/TCPAcceptor.h"
#include "tcpsockets/TCPConnector.h"

using namespace nt;

#define DEBUG(str) puts(str)

std::unique_ptr<Dispatcher> Dispatcher::m_instance;

Dispatcher::Dispatcher()
    : m_server(false),
      m_active(false),
      m_update_rate(100),
      m_do_flush(false),
      m_do_reconnect(false) {}

Dispatcher::~Dispatcher() { Stop(); }

void Dispatcher::StartServer(const char* listen_address, unsigned int port) {
  {
    std::lock_guard<std::mutex> lock(m_user_mutex);
    if (m_active) return;
    m_active = true;
  }
  m_server = true;
  m_dispatch_thread = std::thread(&Dispatcher::DispatchThreadMain, this);
  m_clientserver_thread =
      std::thread(&Dispatcher::ServerThreadMain, this, listen_address, port);
}

void Dispatcher::StartClient(const char* server_name, unsigned int port) {
  {
    std::lock_guard<std::mutex> lock(m_user_mutex);
    if (m_active) return;
    m_active = true;
  }
  m_server = false;
  m_dispatch_thread = std::thread(&Dispatcher::DispatchThreadMain, this);
  m_clientserver_thread =
      std::thread(&Dispatcher::ClientThreadMain, this, server_name, port);
}

void Dispatcher::Stop() {
  {
    std::lock_guard<std::mutex> lock(m_user_mutex);
    m_active = false;

    // close all connections
    for (auto& conn : m_connections) conn.net->Stop();
  }

  // wake up dispatch thread with a flush
  m_flush_cv.notify_one();

  // wake up client thread with a reconnect
  ClientReconnect();

  // wake up server thread by shutting down the socket
  if (m_server_acceptor) m_server_acceptor->shutdown();

  // join threads
  if (m_dispatch_thread.joinable()) m_dispatch_thread.join();
  if (m_clientserver_thread.joinable()) m_clientserver_thread.join();
}

void Dispatcher::SetUpdateRate(double interval) {
  // don't allow update rates faster than 100 ms
  if (interval < 0.1)
    interval = 0.1;
  m_update_rate = static_cast<unsigned int>(interval * 1000);
}

void Dispatcher::SetIdentity(llvm::StringRef name) {
  std::lock_guard<std::mutex> lock(m_user_mutex);
  m_identity = name;
}

void Dispatcher::Flush() {
  auto now = std::chrono::steady_clock::now();
  {
    std::lock_guard<std::mutex> lock(m_flush_mutex);
    // don't allow flushes more often than every 100 ms
    if ((now - m_last_flush) < std::chrono::milliseconds(100))
      return;
    m_last_flush = now;
    m_do_flush = true;
  }
  m_flush_cv.notify_one();
}

void Dispatcher::DispatchThreadMain() {
  auto timeout_time = std::chrono::steady_clock::now();
  int count = 0;
  while (m_active) {
    // handle loop taking too long
    auto start = std::chrono::steady_clock::now();
    if (start > timeout_time)
      timeout_time = start;

    // wait for periodic or when flushed
    timeout_time += std::chrono::milliseconds(m_update_rate);
    std::unique_lock<std::mutex> lock(m_flush_mutex);
    m_reconnect_cv.wait_until(lock, timeout_time,
                              [&] { return !m_active || m_do_flush; });
    m_do_flush = false;
    lock.unlock();
    if (!m_active) break;  // in case we were woken up to terminate

    if (++count > 10) {
      DEBUG("dispatch running");
      count = 0;
    }
  }
}

void Dispatcher::ServerThreadMain(const char* listen_address,
                                  unsigned int port) {
  m_server_acceptor.reset(
      new TCPAcceptor(static_cast<int>(port), listen_address));
  if (m_server_acceptor->start() != 0) {
    m_active = false;
    return;
  }
  while (m_active) {
    auto stream = m_server_acceptor->accept();
    if (!stream) {
      m_active = false;
      break;
    }
    DEBUG("server got a connection");

    // add to connections list
    Connection conn;
    conn.net.reset(new NetworkConnection(
        std::move(stream),
        [this](unsigned int id) { return GetEntryType(id); }));
    conn.net->Start();
    AddConnection(std::move(conn));
  }
}

void Dispatcher::ClientThreadMain(const char* server_name, unsigned int port) {
  unsigned int proto_rev = 0x0300;
  while (m_active) {
    // get identity
    std::string self_id;
    {
      std::lock_guard<std::mutex> lock(m_user_mutex);
      self_id = m_identity;
    }

    // sleep between retries
    std::this_thread::sleep_for(std::chrono::milliseconds(500));

    // try to connect (with timeout)
    DEBUG("client trying to connect");
    auto stream = TCPConnector::connect(server_name, static_cast<int>(port), 1);
    if (!stream) continue;  // keep retrying
    DEBUG("client connected");

    Connection conn;
    conn.net.reset(new NetworkConnection(
        std::move(stream),
        [this](unsigned int id) { return GetEntryType(id); }));
    conn.net->set_proto_rev(proto_rev);
    conn.net->Start();

    // send client hello
    DEBUG("client sending hello");
    conn.net->outgoing().push(
        NetworkConnection::Outgoing{Message::ClientHello(self_id)});

    // wait for response
    auto msg = conn.net->incoming().pop();
    if (!msg) {
      // disconnected, retry
      DEBUG("client disconnected waiting for first response");
      proto_rev = 0x0300;
      continue;
    }

    if (msg->Is(Message::kProtoUnsup)) {
      // reconnect with lower protocol (if possible)
      if (proto_rev <= 0x0200) {
        // no more options, abort (but keep trying to connect)
        proto_rev = 0x0300;
        continue;
      }
      proto_rev = 0x0200;
      continue;
    }

    if (proto_rev >= 0x0300) {
      // should be server hello; if not, disconnect, but keep trying to connect
      if (!msg->Is(Message::kServerHello)) continue;
      conn.remote_id = msg->str();
      // get the next message (blocks)
      msg = conn.net->incoming().pop();
    }

    // receive initial assignments
    std::vector<std::shared_ptr<Message>> incoming;
    for (;;) {
      if (!msg) {
        // disconnected, retry
        DEBUG("client disconnected waiting for initial entries");
        proto_rev = 0x0300;
        continue;
      }
      if (msg->Is(Message::kServerHelloDone)) break;
      if (!msg->Is(Message::kEntryAssign)) {
        // unexpected message
        DEBUG("received message other than entry assignment during initial handshake");
        proto_rev = 0x0300;
        continue;
      }
      incoming.push_back(msg);
      // get the next message (blocks)
      msg = conn.net->incoming().pop();
    }

    // generate outgoing assignments
    NetworkConnection::Outgoing outgoing;

    if (proto_rev >= 0x0300)
      outgoing.push_back(Message::ClientHelloDone());

    if (!outgoing.empty())
      conn.net->outgoing().push(std::move(outgoing));

    // add to connections list (the dispatcher thread will handle from here)
    AddConnection(std::move(conn));

    // block until told to reconnect
    std::unique_lock<std::mutex> lock(m_reconnect_mutex);
    m_reconnect_cv.wait(lock, [&] { return m_do_reconnect; });
    m_do_reconnect = false;
    lock.unlock();
  }
}

void Dispatcher::ClientReconnect() {
  if (m_server) return;
  {
    std::lock_guard<std::mutex> lock(m_reconnect_mutex);
    m_do_reconnect = true;
  }
  m_reconnect_cv.notify_one();
}

void Dispatcher::AddConnection(Connection&& conn) {
  std::lock_guard<std::mutex> lock(m_user_mutex);
  m_connections.push_back(std::move(conn));
}

NT_Type Dispatcher::GetEntryType(unsigned int id) const {
  std::lock_guard<std::mutex> lock(m_idmap_mutex);
  if (id >= m_idmap.size()) return NT_UNASSIGNED;
  auto value = m_idmap[id]->value();
  if (!value) return NT_UNASSIGNED;
  return value->type();
}
<|endoftext|>