<commit_before>/*
 *  Created on: 16 Aug 2011
 *      Author: @benjamg
 */

#include <array>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include <zmqpp/zmqpp.hpp>

#ifndef BUILD_CLIENT_NAME
#define BUILD_CLIENT_NAME "zmqpp"
#endif

boost::program_options::options_description connection_options()
{
	boost::program_options::options_description options("Connection Options");
	options.add_options()
		("annotate,a", "annotate output with direction")
		("bind,b", boost::program_options::value<std::vector<std::string>>(), "bind to specified endpoint")
		("connect,c", boost::program_options::value<std::vector<std::string>>(), "connect to specified endpoint")
		("multipart,m", "enable multipart message sending")
		;

	return options;
}

boost::program_options::options_description miscellaneous_options()
{
	boost::program_options::options_description options("Miscellaneous Options");
	options.add_options()
		("version", "display version")
		("help", "show this help page")
		;

	return options;
}

void usage(std::string const& executable_name)
{
	std::cerr << "Usage: " << executable_name << " [options] SOCKETTYPE [--bind|--connect] ENDPOINT" << std::endl;
	std::cerr << "0mq command line client tool." << std::endl;
	std::cerr << "SOCKETTYPE is one of the supported 0mq socket types." << std::endl;
	std::cerr << "ENDPOINT is any valid 0mq endpoint." << std::endl;
}

typedef std::tuple<zmqpp::socket_type, bool, bool, bool> socket_type_data;

int main(int argc, char const* argv[])
{
	boost::program_options::positional_options_description arguments;
	arguments.add("type", 1);
	arguments.add("connect", 1);

	boost::program_options::options_description all;
	all.add_options()
		("type", "0mq socket type")
		;
	all.add(miscellaneous_options());
	all.add(connection_options());

	boost::program_options::variables_map vm;
	bool usage = false;

	std::map<std::string, socket_type_data> socket_types;
	socket_types["push"] = socket_type_data(zmqpp::socket_type::push, true, false, false);
	socket_types["pull"] = socket_type_data(zmqpp::socket_type::pull, false, true, false);

	socket_types["pub"] = socket_type_data(zmqpp::socket_type::publish, true, false, false);
	socket_types["sub"] = socket_type_data(zmqpp::socket_type::subscribe, false, true, false);

	socket_types["req"] = socket_type_data(zmqpp::socket_type::request, true, false, true);
	socket_types["rep"] = socket_type_data(zmqpp::socket_type::reply, false, true, true);

	try {
		boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(all).positional(arguments).run(), vm);
	}
	catch(boost::program_options::too_many_positional_options_error& e)
	{
		std::cerr << "Too many arguments provided." << std::endl;
		usage = true;
	}
	catch(boost::program_options::unknown_option& e)
	{
		std::cerr << "Unknown option '" << e.get_option_name() << "'." << std::endl;
		usage = true;
	}

	if (vm.count("type") && (socket_types.end() == socket_types.find(vm["type"].as<std::string>())))
	{
		std::cerr << "Unknown value '" << vm["type"].as<std::string>() << "' provided for 0mq socket type." << std::endl;
		usage = true;
	}

	if (vm.count("version"))
	{
		uint8_t major, minor, patch;
		zmqpp::zmq_version(major, minor, patch);

		std::cerr << BUILD_CLIENT_NAME << " version " << BUILD_VERSION << std::endl;
		std::cerr << "  built against 0mq version " << static_cast<int>(major) << "." << static_cast<int>(minor) << "." << static_cast<int>(patch) << std::endl;

		return EXIT_SUCCESS;
	}

	if (usage || (0 == vm.count("type")) || vm.count("help") ||
			((0 == vm.count("connect")) && (0 == vm.count("bind"))))
	{
		std::cerr << "Usage: " BUILD_CLIENT_NAME " [options] SOCKETTYPE ENDPOINT" << std::endl;
		std::cerr << "0mq command line client tool." << std::endl;
		std::cerr << "SOCKETTYPE is one of the supported 0mq socket types." << std::endl;

		auto it = socket_types.begin();
		std::cerr << "  " << (*it).first;
		for(++it; it != socket_types.end(); ++it)
		{
			std::cerr << ", " << (*it).first;
		}
		std::cerr << std::endl;

		std::cerr << "ENDPOINT is any valid 0mq endpoint." << std::endl;
		std::cerr << std::endl;

		if (!vm.count("help"))
		{
			return EXIT_FAILURE;
		}

		std::cerr << connection_options() << std::endl;
		std::cerr << miscellaneous_options() << std::endl;
		return EXIT_SUCCESS;
	}

	int standardin = fileno(stdin);
	if (standardin < 0) // really?
	{
		std::cerr << "Unable to get standard input, this might be an OS thing, sorry." << std::endl;
		return EXIT_FAILURE;
	}

	socket_type_data data = socket_types[vm["type"].as<std::string>()];
	zmqpp::socket_type type = std::get<0>(data);
	bool can_send = std::get<1>(data);
	bool can_recv = std::get<2>(data);
	bool toggles = std::get<3>(data);

	zmqpp::context context;
	zmqpp::socket socket(context, type);

	if ("sub" == vm["type"].as<std::string>())
	{
		socket.subscribe("");
	}

	if (vm.count("bind"))
	{
		std::vector<std::string> endpoints = vm["bind"].as<std::vector<std::string>>();
		for(size_t i = 0; i < endpoints.size(); ++i)
		{
			std::cerr << "binding to " << endpoints[i] << std::endl;
			try
			{
				socket.bind(endpoints[i]);
			}
			catch(zmqpp::zmq_internal_exception& e)
			{
				std::cerr << "failed to bind to endpoint: " << e.what() << std::endl;
				return EXIT_FAILURE;
			}
		}
	}

	if (vm.count("connect"))
	{
		std::vector<std::string> endpoints = vm["connect"].as<std::vector<std::string>>();
		for(size_t i = 0; i < endpoints.size(); ++i)
		{
			std::cerr << "connecting to " << endpoints[i] << std::endl;
			try
			{
				socket.connect(endpoints[i]);
			}
			catch(zmqpp::zmq_internal_exception& e)
			{
				std::cerr << "failed to bind to endpoint: " << e.what() << std::endl;
				return EXIT_FAILURE;
			}
		}
	}

	bool multipart = (vm.count("multipart") > 0);

	zmqpp::poller poller;
	poller.add(socket);
	poller.add(standardin);

	if (can_send || toggles)
	{
		std::cerr << "While sending packets is allowed data entered on standard in will be sent to the 0mq socket." << std::endl;
		std::cerr << "messages will be considered terminated by newline." << std::endl;
		std::cerr << std::endl;

		if (toggles && !can_send)
		{
			std::cerr << "Sending starts as disabled for this socket type." << std::endl;
			std::cerr << std::endl;
		}
	}

	if (multipart)
	{
		std::cerr << "Multipart messages enabled, newline on an empty line will be considered packet end." << std::endl;
		std::cerr << "The empty part will not be included." << std::endl;
		std::cerr << std::endl;
	}

	bool annotate = (vm.count("annotate") > 0);

	zmqpp::message message;
	while(true)
	{
		poller.check_for(socket, (can_recv) ? zmqpp::poller::POLL_IN : zmqpp::poller::POLL_NONE);
		poller.check_for(standardin, (can_send) ? zmqpp::poller::POLL_IN : zmqpp::poller::POLL_NONE);

		if(poller.poll())
		{
			if (poller.has_input(socket))
			{
				assert(can_recv);

				do
				{
					std::string message;
					socket.receive(message);

					if (annotate)
					{
						std::cout << "<<: ";
					}

					std::cout << message << std::endl;

				} while(socket.has_more_parts());

				if (toggles)
				{
					can_recv = false;
					can_send = true;
					std::cerr << "**: Sending now enabled" << std::endl;
				}
			}

			if (poller.has_input(standardin))
			{
				assert(can_send);

				std::array<char, 512> buffer;
				char* result = fgets(buffer.data(), buffer.size(), stdin);
				if (nullptr == result)
				{
					if (annotate)
					{
						std::cerr << "!!: ";
					}

					std::cerr << "Error in standard input" << std::endl;
					return EXIT_FAILURE;
				}

				buffer[strlen(buffer.data()) - 1] = 0;
				if (!multipart || (strlen(buffer.data()) > 0))
				{
					message.add(buffer.data(), strlen(buffer.data()));
				}

				if (!multipart || (strlen(buffer.data()) == 0))
				{
					for(size_t i = 0; i < message.parts(); ++i)
					{
						if (annotate)
						{
							std::cout << ">>: ";
						}

						std::cout << message.get<std::string>(i) << std::endl;
					}

					if (!socket.send(message, true))
					{
						if (annotate)
						{
							std::cerr << "!!: ";
						}

						std::cerr << "Send failed, socket would have blocked" << std::endl;
					}

					if (toggles)
					{
						can_recv = true;
						can_send = false;

						if (annotate)
						{
							std::cerr << "**: ";
						}

						std::cerr << "Sending now disabled" << std::endl;
					}
				}
			}
		}
	}

	return EXIT_SUCCESS;
}
<commit_msg>additional minor output options<commit_after>/*
 *  Created on: 16 Aug 2011
 *      Author: @benjamg
 */

#include <array>
#include <iostream>
#include <string>
#include <tuple>
#include <vector>

#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>

#include <zmqpp/zmqpp.hpp>

#ifndef BUILD_CLIENT_NAME
#define BUILD_CLIENT_NAME "zmqpp"
#endif

boost::program_options::options_description connection_options()
{
	boost::program_options::options_description options("Connection Options");
	options.add_options()
		("annotate,a", "annotate output with direction")
		("bind,b", boost::program_options::value<std::vector<std::string>>(), "bind to specified endpoint")
		("connect,c", boost::program_options::value<std::vector<std::string>>(), "connect to specified endpoint")
		("flush,f", "flush output frequently")
		("multipart,m", "enable multipart message sending")
		("newline,n", "extra newlines")
		;

	return options;
}

boost::program_options::options_description miscellaneous_options()
{
	boost::program_options::options_description options("Miscellaneous Options");
	options.add_options()
		("version", "display version")
		("help", "show this help page")
		;

	return options;
}

void usage(std::string const& executable_name)
{
	std::cerr << "Usage: " << executable_name << " [options] SOCKETTYPE [--bind|--connect] ENDPOINT" << std::endl;
	std::cerr << "0mq command line client tool." << std::endl;
	std::cerr << "SOCKETTYPE is one of the supported 0mq socket types." << std::endl;
	std::cerr << "ENDPOINT is any valid 0mq endpoint." << std::endl;
}

typedef std::tuple<zmqpp::socket_type, bool, bool, bool> socket_type_data;

int main(int argc, char const* argv[])
{
	boost::program_options::positional_options_description arguments;
	arguments.add("type", 1);
	arguments.add("connect", 1);

	boost::program_options::options_description all;
	all.add_options()
		("type", "0mq socket type")
		;
	all.add(miscellaneous_options());
	all.add(connection_options());

	boost::program_options::variables_map vm;
	bool usage = false;

	std::map<std::string, socket_type_data> socket_types;
	socket_types["push"] = socket_type_data(zmqpp::socket_type::push, true, false, false);
	socket_types["pull"] = socket_type_data(zmqpp::socket_type::pull, false, true, false);

	socket_types["pub"] = socket_type_data(zmqpp::socket_type::publish, true, false, false);
	socket_types["sub"] = socket_type_data(zmqpp::socket_type::subscribe, false, true, false);

	socket_types["req"] = socket_type_data(zmqpp::socket_type::request, true, false, true);
	socket_types["rep"] = socket_type_data(zmqpp::socket_type::reply, false, true, true);

	try {
		boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(all).positional(arguments).run(), vm);
	}
	catch(boost::program_options::too_many_positional_options_error& e)
	{
		std::cerr << "Too many arguments provided." << std::endl;
		usage = true;
	}
	catch(boost::program_options::unknown_option& e)
	{
		std::cerr << "Unknown option '" << e.get_option_name() << "'." << std::endl;
		usage = true;
	}

	if (vm.count("type") && (socket_types.end() == socket_types.find(vm["type"].as<std::string>())))
	{
		std::cerr << "Unknown value '" << vm["type"].as<std::string>() << "' provided for 0mq socket type." << std::endl;
		usage = true;
	}

	if (vm.count("version"))
	{
		uint8_t major, minor, patch;
		zmqpp::zmq_version(major, minor, patch);

		std::cerr << BUILD_CLIENT_NAME << " version " << BUILD_VERSION << std::endl;
		std::cerr << "  built against 0mq version " << static_cast<int>(major) << "." << static_cast<int>(minor) << "." << static_cast<int>(patch) << std::endl;

		return EXIT_SUCCESS;
	}

	if (usage || (0 == vm.count("type")) || vm.count("help") ||
			((0 == vm.count("connect")) && (0 == vm.count("bind"))))
	{
		std::cerr << "Usage: " BUILD_CLIENT_NAME " [options] SOCKETTYPE ENDPOINT" << std::endl;
		std::cerr << "0mq command line client tool." << std::endl;
		std::cerr << "SOCKETTYPE is one of the supported 0mq socket types." << std::endl;

		auto it = socket_types.begin();
		std::cerr << "  " << (*it).first;
		for(++it; it != socket_types.end(); ++it)
		{
			std::cerr << ", " << (*it).first;
		}
		std::cerr << std::endl;

		std::cerr << "ENDPOINT is any valid 0mq endpoint." << std::endl;
		std::cerr << std::endl;

		if (!vm.count("help"))
		{
			return EXIT_FAILURE;
		}

		std::cerr << connection_options() << std::endl;
		std::cerr << miscellaneous_options() << std::endl;
		return EXIT_SUCCESS;
	}

	int standardin = fileno(stdin);
	if (standardin < 0) // really?
	{
		std::cerr << "Unable to get standard input, this might be an OS thing, sorry." << std::endl;
		return EXIT_FAILURE;
	}

	socket_type_data data = socket_types[vm["type"].as<std::string>()];
	zmqpp::socket_type type = std::get<0>(data);
	bool can_send = std::get<1>(data);
	bool can_recv = std::get<2>(data);
	bool toggles = std::get<3>(data);

	zmqpp::context context;
	zmqpp::socket socket(context, type);

	if ("sub" == vm["type"].as<std::string>())
	{
		socket.subscribe("");
	}

	if (vm.count("bind"))
	{
		std::vector<std::string> endpoints = vm["bind"].as<std::vector<std::string>>();
		for(size_t i = 0; i < endpoints.size(); ++i)
		{
			std::cerr << "binding to " << endpoints[i] << std::endl;
			try
			{
				socket.bind(endpoints[i]);
			}
			catch(zmqpp::zmq_internal_exception& e)
			{
				std::cerr << "failed to bind to endpoint: " << e.what() << std::endl;
				return EXIT_FAILURE;
			}
		}
	}

	if (vm.count("connect"))
	{
		std::vector<std::string> endpoints = vm["connect"].as<std::vector<std::string>>();
		for(size_t i = 0; i < endpoints.size(); ++i)
		{
			std::cerr << "connecting to " << endpoints[i] << std::endl;
			try
			{
				socket.connect(endpoints[i]);
			}
			catch(zmqpp::zmq_internal_exception& e)
			{
				std::cerr << "failed to bind to endpoint: " << e.what() << std::endl;
				return EXIT_FAILURE;
			}
		}
	}

	bool multipart = (vm.count("multipart") > 0);

	zmqpp::poller poller;
	poller.add(socket);
	poller.add(standardin);

	if (can_send || toggles)
	{
		std::cerr << "While sending packets is allowed data entered on standard in will be sent to the 0mq socket." << std::endl;
		std::cerr << "messages will be considered terminated by newline." << std::endl;
		std::cerr << std::endl;

		if (toggles && !can_send)
		{
			std::cerr << "Sending starts as disabled for this socket type." << std::endl;
			std::cerr << std::endl;
		}
	}

	if (multipart)
	{
		std::cerr << "Multipart messages enabled, newline on an empty line will be considered packet end." << std::endl;
		std::cerr << "The empty part will not be included." << std::endl;
		std::cerr << std::endl;
	}

	bool annotate = (vm.count("annotate") > 0);
	bool flush = (vm.count("flush") > 0);
	bool newline = (vm.count("newline") > 0);

	zmqpp::message message;
	while(true)
	{
		poller.check_for(socket, (can_recv) ? zmqpp::poller::POLL_IN : zmqpp::poller::POLL_NONE);
		poller.check_for(standardin, (can_send) ? zmqpp::poller::POLL_IN : zmqpp::poller::POLL_NONE);

		if(poller.poll())
		{
			if (poller.has_input(socket))
			{
				assert(can_recv);

				do
				{
					std::string message;
					socket.receive(message);

					if (annotate)
					{
						std::cout << "<<: ";
					}

					std::cout << message << std::endl;

					if (newline)
					{
						std::cout << std::endl;
					}
					if (flush)
					{
						std::cout.flush();
					}

				} while(socket.has_more_parts());

				if (toggles)
				{
					can_recv = false;
					can_send = true;
					std::cerr << "**: Sending now enabled" << std::endl;
				}
			}

			if (poller.has_input(standardin))
			{
				assert(can_send);

				std::array<char, 512> buffer;
				char* result = fgets(buffer.data(), buffer.size(), stdin);
				if (nullptr == result)
				{
					if (annotate)
					{
						std::cerr << "!!: ";
					}

					std::cerr << "Error in standard input" << std::endl;
					return EXIT_FAILURE;
				}

				buffer[strlen(buffer.data()) - 1] = 0;
				if (!multipart || (strlen(buffer.data()) > 0))
				{
					message.add(buffer.data(), strlen(buffer.data()));
				}

				if (!multipart || (strlen(buffer.data()) == 0))
				{
					for(size_t i = 0; i < message.parts(); ++i)
					{
						if (annotate)
						{
							std::cout << ">>: ";
						}

						std::cout << message.get<std::string>(i) << std::endl;
					}

					if (newline)
					{
						std::cout << std::endl;
					}
					if (flush)
					{
						std::cout.flush();
					}

					if (!socket.send(message, true))
					{
						if (annotate)
						{
							std::cerr << "!!: ";
						}

						std::cerr << "Send failed, socket would have blocked" << std::endl;
					}

					if (toggles)
					{
						can_recv = true;
						can_send = false;

						if (annotate)
						{
							std::cerr << "**: ";
						}

						std::cerr << "Sending now disabled" << std::endl;
					}
				}
			}
		}
	}

	return EXIT_SUCCESS;
}
<|endoftext|>


<commit_before>
/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity expression compiler, testing the behaviour of the code.
 */

#include <string>
#include <boost/test/unit_test.hpp>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <libsolidity/CompilerStack.h>

using namespace std;

namespace dev
{
namespace solidity
{
namespace test
{

class ExecutionFramework
{
public:
	ExecutionFramework() { g_logVerbosity = 0; }

	bytes compileAndRun(std::string const& _sourceCode)
	{
		bytes code = dev::solidity::CompilerStack::compile(_sourceCode);
		sendMessage(code, true);
		return m_output;
	}

	bytes callFunction(byte _index, bytes const& _data)
	{
		sendMessage(bytes(1, _index) + _data, false);
		return m_output;
	}

	bytes callFunction(byte _index, u256 const& _argument1)
	{
		callFunction(_index, toBigEndian(_argument1));
		return m_output;
	}

private:
	void sendMessage(bytes const& _data, bool _isCreation)
	{
		eth::Executive executive(m_state);
		eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data)
										 : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data);
		bytes transactionRLP = t.rlp();
		try
		{
			// this will throw since the transaction is invalid, but it should nevertheless store the transaction
			executive.setup(&transactionRLP);
		}
		catch (...) {}
		if (_isCreation)
		{
			BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address()));
			m_contractAddress = executive.newAddress();
			BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
		}
		else
			BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address()));
		BOOST_REQUIRE(executive.go());
		executive.finalize();
		m_output = executive.out().toBytes();
	}

	Address m_contractAddress;
	eth::State m_state;
	u256 const m_gasPrice = 100 * eth::szabo;
	u256 const m_gas = 1000000;
	bytes m_output;
};

BOOST_AUTO_TEST_SUITE(SolidityCompilerEndToEndTest)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint a) returns(uint d) { return a * 7; }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	u256 a = 0x200030004;
	bytes result = framework.callFunction(0, a);
	BOOST_CHECK(result == toBigEndian(a * 7));
}

BOOST_AUTO_TEST_CASE(empty_contract)
{
	char const* sourceCode = "contract test {\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes()).empty());
}

BOOST_AUTO_TEST_CASE(recursive_calls)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint n) returns(uint nfac) {\n"
							 "    if (n <= 1) return 1;\n"
							 "    else return n * f(n - 1);\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
	BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
	BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
}

BOOST_AUTO_TEST_CASE(while_loop)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint n) returns(uint nfac) {\n"
							 "    nfac = 1;\n"
							 "    var i = 2;\n"
							 "    while (i <= n) nfac *= i++;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(0, u256(2)) == toBigEndian(u256(2)));
	BOOST_CHECK(framework.callFunction(0, u256(3)) == toBigEndian(u256(6)));
	BOOST_CHECK(framework.callFunction(0, u256(4)) == toBigEndian(u256(24)));
}

BOOST_AUTO_TEST_CASE(calling_other_functions)
{
	// note that the index of a function is its index in the sorted sequence of functions
	char const* sourceCode = "contract collatz {\n"
							 "  function run(uint x) returns(uint y) {\n"
							 "    while ((y = x) > 1) {\n"
							 "      if (x % 2 == 0) x = evenStep(x);\n"
							 "      else x = oddStep(x);\n"
							 "    }\n"
							 "  }\n"
							 "  function evenStep(uint x) returns(uint y) {\n"
							 "    return x / 2;\n"
							 "  }\n"
							 "  function oddStep(uint x) returns(uint y) {\n"
							 "    return 3 * x + 1;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(2, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(framework.callFunction(2, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(2)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(8)) == toBigEndian(u256(1)));
	BOOST_CHECK(framework.callFunction(2, u256(127)) == toBigEndian(u256(1)));
}

BOOST_AUTO_TEST_CASE(many_local_variables)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(uint x1, uint x2, uint x3) returns(uint y) {\n"
							 "    var a = 0x1; var b = 0x10; var c = 0x100;\n"
							 "    y = a + b + c + x1 + x2 + x3;\n"
							 "    y += b + x2;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000)))
				== toBigEndian(u256(0x121121)));
}

BOOST_AUTO_TEST_CASE(packing_unpacking_types)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n"
							 "    if (a) y = 1;\n"
							 "    y = y * 0x100000000 | ~b;\n"
							 "    y = y * 0x10000000000000000 | ~c;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0"))
				== fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f"));
}

BOOST_AUTO_TEST_CASE(multiple_return_values)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(bool x1, uint x2) returns(uint y1, bool y2, uint y3) {\n"
							 "    y1 = x2; y2 = x1;\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
				== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0)));
}

BOOST_AUTO_TEST_CASE(short_circuiting)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(uint x) returns(uint y) {\n"
							 "    x == 0 || ((x = 8) > 0);\n"
							 "    return x;"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(framework.callFunction(0, u256(1)) == toBigEndian(u256(8)));
}

BOOST_AUTO_TEST_CASE(high_bits_cleaning)
{
	char const* sourceCode = "contract test {\n"
							 "  function run() returns(uint256 y) {\n"
							 "    uint32 x = uint32(0xffffffff) + 10;\n"
							 "    if (x >= 0xffffffff) return 0;\n"
							 "    return x;"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(9)));
}

BOOST_AUTO_TEST_CASE(sign_extension)
{
	char const* sourceCode = "contract test {\n"
							 "  function run() returns(uint256 y) {\n"
							 "    int64 x = -int32(0xff);\n"
							 "    if (x >= 0xff) return 0;\n"
							 "    return -uint256(x);"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(0xff)));
}

BOOST_AUTO_TEST_CASE(small_unsigned_types)
{
	char const* sourceCode = "contract test {\n"
							 "  function run() returns(uint256 y) {\n"
							 "    uint32 x = uint32(0xffffff) * 0xffffff;\n"
							 "    return x / 0x100;"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(0xfffe0000)));
}

BOOST_AUTO_TEST_CASE(small_signed_types)
{
	char const* sourceCode = "contract test {\n"
							 "  function run() returns(int256 y) {\n"
							 "    return -int32(10) * -int64(20);\n"
							 "  }\n"
							 "}\n";
	ExecutionFramework framework;
	framework.compileAndRun(sourceCode);
	BOOST_CHECK(framework.callFunction(0, bytes()) == toBigEndian(u256(200)));
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<commit_msg>Fixes for test framework (sign the transaction).<commit_after>
/*
	This file is part of cpp-ethereum.

	cpp-ethereum is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

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

	You should have received a copy of the GNU General Public License
	along with cpp-ethereum.  If not, see <http://www.gnu.org/licenses/>.
*/
/**
 * @author Christian <c@ethdev.com>
 * @date 2014
 * Unit tests for the solidity expression compiler, testing the behaviour of the code.
 */

#include <string>
#include <boost/test/unit_test.hpp>
#include <libethereum/State.h>
#include <libethereum/Executive.h>
#include <libsolidity/CompilerStack.h>

using namespace std;

namespace dev
{
namespace solidity
{
namespace test
{

class ExecutionFramework
{
public:
	ExecutionFramework() { g_logVerbosity = 0; }

	bytes const& compileAndRun(std::string const& _sourceCode)
	{
		bytes code = dev::solidity::CompilerStack::compile(_sourceCode);
		sendMessage(code, true);
		BOOST_REQUIRE(!m_output.empty());
		return m_output;
	}

	bytes const& callFunction(byte _index, bytes const& _data)
	{
		sendMessage(bytes(1, _index) + _data, false);
		return m_output;
	}

	bytes const& callFunction(byte _index, u256 const& _argument1)
	{
		return callFunction(_index, toBigEndian(_argument1));
	}

private:
	void sendMessage(bytes const& _data, bool _isCreation)
	{
		eth::Executive executive(m_state);
		eth::Transaction t = _isCreation ? eth::Transaction(0, m_gasPrice, m_gas, _data, 0, KeyPair::create().sec())
										 : eth::Transaction(0, m_gasPrice, m_gas, m_contractAddress, _data, 0, KeyPair::create().sec());
		bytes transactionRLP = t.rlp();
		try
		{
			// this will throw since the transaction is invalid, but it should nevertheless store the transaction
			executive.setup(&transactionRLP);
		}
		catch (...) {}
		if (_isCreation)
		{
			BOOST_REQUIRE(!executive.create(Address(), 0, m_gasPrice, m_gas, &_data, Address()));
			m_contractAddress = executive.newAddress();
			BOOST_REQUIRE(m_contractAddress);
			BOOST_REQUIRE(m_state.addressHasCode(m_contractAddress));
		}
		else
			BOOST_REQUIRE(!executive.call(m_contractAddress, Address(), 0, m_gasPrice, &_data, m_gas, Address()));
		BOOST_REQUIRE(executive.go());
		executive.finalize();
		m_output = executive.out().toVector();
	}

	Address m_contractAddress;
	eth::State m_state;
	u256 const m_gasPrice = 100 * eth::szabo;
	u256 const m_gas = 1000000;
	bytes m_output;
};

BOOST_FIXTURE_TEST_SUITE(SolidityCompilerEndToEndTest, ExecutionFramework)

BOOST_AUTO_TEST_CASE(smoke_test)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint a) returns(uint d) { return a * 7; }\n"
							 "}\n";
	compileAndRun(sourceCode);
	u256 a = 0x200030004;
	BOOST_CHECK(callFunction(0, a) == toBigEndian(a * 7));
}

BOOST_AUTO_TEST_CASE(empty_contract)
{
	char const* sourceCode = "contract test {\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, bytes()).empty());
}

BOOST_AUTO_TEST_CASE(recursive_calls)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint n) returns(uint nfac) {\n"
							 "    if (n <= 1) return 1;\n"
							 "    else return n * f(n - 1);\n"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1)));
	BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2)));
	BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6)));
	BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24)));
}

BOOST_AUTO_TEST_CASE(while_loop)
{
	char const* sourceCode = "contract test {\n"
							 "  function f(uint n) returns(uint nfac) {\n"
							 "    nfac = 1;\n"
							 "    var i = 2;\n"
							 "    while (i <= n) nfac *= i++;\n"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(1)));
	BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(callFunction(0, u256(2)) == toBigEndian(u256(2)));
	BOOST_CHECK(callFunction(0, u256(3)) == toBigEndian(u256(6)));
	BOOST_CHECK(callFunction(0, u256(4)) == toBigEndian(u256(24)));
}

BOOST_AUTO_TEST_CASE(calling_other_functions)
{
	// note that the index of a function is its index in the sorted sequence of functions
	char const* sourceCode = "contract collatz {\n"
							 "  function run(uint x) returns(uint y) {\n"
							 "    while ((y = x) > 1) {\n"
							 "      if (x % 2 == 0) x = evenStep(x);\n"
							 "      else x = oddStep(x);\n"
							 "    }\n"
							 "  }\n"
							 "  function evenStep(uint x) returns(uint y) {\n"
							 "    return x / 2;\n"
							 "  }\n"
							 "  function oddStep(uint x) returns(uint y) {\n"
							 "    return 3 * x + 1;\n"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(2, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(callFunction(2, u256(1)) == toBigEndian(u256(1)));
	BOOST_CHECK(callFunction(2, u256(2)) == toBigEndian(u256(1)));
	BOOST_CHECK(callFunction(2, u256(8)) == toBigEndian(u256(1)));
	BOOST_CHECK(callFunction(2, u256(127)) == toBigEndian(u256(1)));
}

BOOST_AUTO_TEST_CASE(many_local_variables)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(uint x1, uint x2, uint x3) returns(uint y) {\n"
							 "    var a = 0x1; var b = 0x10; var c = 0x100;\n"
							 "    y = a + b + c + x1 + x2 + x3;\n"
							 "    y += b + x2;\n"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, toBigEndian(u256(0x1000)) + toBigEndian(u256(0x10000)) + toBigEndian(u256(0x100000)))
				== toBigEndian(u256(0x121121)));
}

BOOST_AUTO_TEST_CASE(packing_unpacking_types)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(bool a, uint32 b, uint64 c) returns(uint256 y) {\n"
							 "    if (a) y = 1;\n"
							 "    y = y * 0x100000000 | ~b;\n"
							 "    y = y * 0x10000000000000000 | ~c;\n"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, fromHex("01""0f0f0f0f""f0f0f0f0f0f0f0f0"))
				== fromHex("00000000000000000000000000000000000000""01""f0f0f0f0""0f0f0f0f0f0f0f0f"));
}

BOOST_AUTO_TEST_CASE(multiple_return_values)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(bool x1, uint x2) returns(uint y1, bool y2, uint y3) {\n"
							 "    y1 = x2; y2 = x1;\n"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, bytes(1, 1) + toBigEndian(u256(0xcd)))
				== toBigEndian(u256(0xcd)) + bytes(1, 1) + toBigEndian(u256(0)));
}

BOOST_AUTO_TEST_CASE(short_circuiting)
{
	char const* sourceCode = "contract test {\n"
							 "  function run(uint x) returns(uint y) {\n"
							 "    x == 0 || ((x = 8) > 0);\n"
							 "    return x;"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, u256(0)) == toBigEndian(u256(0)));
	BOOST_CHECK(callFunction(0, u256(1)) == toBigEndian(u256(8)));
}

BOOST_AUTO_TEST_CASE(high_bits_cleaning)
{
	char const* sourceCode = "contract test {\n"
							 "  function run() returns(uint256 y) {\n"
							 "    uint32 x = uint32(0xffffffff) + 10;\n"
							 "    if (x >= 0xffffffff) return 0;\n"
							 "    return x;"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(9)));
}

BOOST_AUTO_TEST_CASE(sign_extension)
{
	char const* sourceCode = "contract test {\n"
							 "  function run() returns(uint256 y) {\n"
							 "    int64 x = -int32(0xff);\n"
							 "    if (x >= 0xff) return 0;\n"
							 "    return -uint256(x);"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xff)));
}

BOOST_AUTO_TEST_CASE(small_unsigned_types)
{
	char const* sourceCode = "contract test {\n"
							 "  function run() returns(uint256 y) {\n"
							 "    uint32 x = uint32(0xffffff) * 0xffffff;\n"
							 "    return x / 0x100;"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(0xfe0000)));
}

BOOST_AUTO_TEST_CASE(small_signed_types)
{
	char const* sourceCode = "contract test {\n"
							 "  function run() returns(int256 y) {\n"
							 "    return -int32(10) * -int64(20);\n"
							 "  }\n"
							 "}\n";
	compileAndRun(sourceCode);
	BOOST_CHECK(callFunction(0, bytes()) == toBigEndian(u256(200)));
}

BOOST_AUTO_TEST_SUITE_END()

}
}
} // end namespaces

<|endoftext|>


<commit_before>// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
#include "meshoptimizer.h"

#include <assert.h>
#include <math.h>
#include <string.h>

size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles)
{
	assert(index_count % 3 == 0);
	assert(max_vertices >= 3);
	assert(max_triangles >= 1);

	// meshlet construction is limited by max vertices and max triangles per meshlet
	// the worst case is that the input is an unindexed stream since this equally stresses both limits
	// note that we assume that in the worst case, we leave 2 vertices unpacked in each meshlet - if we have space for 3 we can pack any triangle
	size_t max_vertices_conservative = max_vertices - 2;
	size_t meshlet_limit_vertices = (index_count + max_vertices_conservative - 1) / max_vertices_conservative;
	size_t meshlet_limit_triangles = (index_count / 3 + max_triangles - 1) / max_triangles;

	return meshlet_limit_vertices > meshlet_limit_triangles ? meshlet_limit_vertices : meshlet_limit_triangles;
}

size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
{
	assert(index_count % 3 == 0);
	assert(max_vertices >= 3);
	assert(max_triangles >= 1);

	meshopt_Meshlet meshlet;
	memset(&meshlet, 0, sizeof(meshlet));

	assert(max_vertices <= sizeof(meshlet.vertices) / sizeof(meshlet.vertices[0]));
	assert(max_triangles <= sizeof(meshlet.indices) / 3);

	// index of the vertex in the meshlet, 0xff if the vertex isn't used
	meshopt_Buffer<unsigned char> used(vertex_count);
	memset(used.data, -1, vertex_count);

	size_t offset = 0;

	for (size_t i = 0; i < index_count; i += 3)
	{
		unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
		assert(a < vertex_count && b < vertex_count && c < vertex_count);

		unsigned char& av = used[a];
		unsigned char& bv = used[b];
		unsigned char& cv = used[c];

		unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);

		if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
		{
			destination[offset++] = meshlet;

			for (size_t j = 0; j < meshlet.vertex_count; ++j)
				used[meshlet.vertices[j]] = 0xff;

			memset(&meshlet, 0, sizeof(meshlet));
		}

		if (av == 0xff)
		{
			av = meshlet.vertex_count;
			meshlet.vertices[meshlet.vertex_count++] = a;
		}

		if (bv == 0xff)
		{
			bv = meshlet.vertex_count;
			meshlet.vertices[meshlet.vertex_count++] = b;
		}

		if (cv == 0xff)
		{
			cv = meshlet.vertex_count;
			meshlet.vertices[meshlet.vertex_count++] = c;
		}

		meshlet.indices[meshlet.triangle_count][0] = av;
		meshlet.indices[meshlet.triangle_count][1] = bv;
		meshlet.indices[meshlet.triangle_count][2] = cv;
		meshlet.triangle_count++;
	}

	if (meshlet.triangle_count)
		destination[offset++] = meshlet;

	assert(offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));

	return offset;
}

meshopt_Cone meshopt_computeClusterCone(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{
	assert(index_count % 3 == 0);
	assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
	assert(vertex_positions_stride % sizeof(float) == 0);

	assert(index_count / 3 <= 256);

	size_t vertex_stride_float = vertex_positions_stride / sizeof(float);

	float normals[256][3];
	float corners[256][3];
	unsigned int triangles = 0;

	float cluster_area = 0;
	float cluster_centroid[3] = {};

	for (unsigned int i = 0; i < index_count; i += 3)
	{
		unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
		assert(a < vertex_count && b < vertex_count && c < vertex_count);

		const float* p0 = vertex_positions + vertex_stride_float * a;
		const float* p1 = vertex_positions + vertex_stride_float * b;
		const float* p2 = vertex_positions + vertex_stride_float * c;

		float p10[3] = { p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] };
		float p20[3] = { p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2] };

		float normalx = p10[1] * p20[2] - p10[2] * p20[1];
		float normaly = p10[2] * p20[0] - p10[0] * p20[2];
		float normalz = p10[0] * p20[1] - p10[1] * p20[0];

		float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz);

		// no need to include degenerate triangles - they will be invisible anyway
		if (area == 0.f)
			continue;

		// record triangle normals & corners for future use (this is a plane eqn)
		normals[triangles][0] = normalx / area;
		normals[triangles][1] = normaly / area;
		normals[triangles][2] = normalz / area;
		corners[triangles][0] = p0[0];
		corners[triangles][1] = p0[1];
		corners[triangles][2] = p0[2];
		triangles++;

		// area-weighted centroid
		cluster_centroid[0] += (p0[0] + p1[0] + p2[0]) * (area / 3);
		cluster_centroid[1] += (p0[1] + p1[1] + p2[1]) * (area / 3);
		cluster_centroid[2] += (p0[2] + p1[2] + p2[2]) * (area / 3);
		cluster_area += area;
	}

	float inv_cluster_area = cluster_area == 0 ? 0 : 1 / cluster_area;

	cluster_centroid[0] *= inv_cluster_area;
	cluster_centroid[1] *= inv_cluster_area;
	cluster_centroid[2] *= inv_cluster_area;

	// build a cone around triangle normals
	float axis[3] = {};

	for (unsigned int i = 0; i < triangles; ++i)
	{
		axis[0] += normals[i][0];
		axis[1] += normals[i][1];
		axis[2] += normals[i][2];
	}

	float avglength = sqrtf(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
	float invavglength = avglength == 0.f ? 0.f : 1.f / avglength;

	axis[0] *= invavglength;
	axis[1] *= invavglength;
	axis[2] *= invavglength;

	float mindp = 1.f;

	for (unsigned int i = 0; i < triangles; ++i)
	{
		float dp = normals[i][0] * axis[0] + normals[i][1] * axis[1] + normals[i][2] * axis[2];

		mindp = (dp < mindp) ? dp : mindp;
	}

	// degenerate cluster, no valid triangles or normal cone is larger than a hemisphere
	if (triangles == 0 || mindp <= 0.f)
	{
		meshopt_Cone cone = {};
		cone.cutoff = 1;
		return cone;
	}

	float maxt = 0;

	// we need to find the point on centroid-t*axis ray that lies in negative half-space of all triangles
	for (unsigned int i = 0; i < triangles; ++i)
	{
		// dot(centroid-t*axis-corner, trinormal) = 0
		// dot(centroid-corner, trinormal) - t * dot(axis, trinormal) = 0
		float cx = cluster_centroid[0] - corners[i][0];
		float cy = cluster_centroid[1] - corners[i][1];
		float cz = cluster_centroid[2] - corners[i][2];

		float dc = cx * normals[i][0] + cy * normals[i][1] + cz * normals[i][2];
		float dn = axis[0] * normals[i][0] + axis[1] * normals[i][1] + axis[2] * normals[i][2];

		// dn should be more than mindp cutoff above
		assert(dn > 0.f);
		float t = dc / dn;

		maxt = (t > maxt) ? t : maxt;
	}

	meshopt_Cone cone;

	// cone apex should be in the negative half-space of all cluster triangles by construction
	cone.apex[0] = cluster_centroid[0] - axis[0] * maxt;
	cone.apex[1] = cluster_centroid[1] - axis[1] * maxt;
	cone.apex[2] = cluster_centroid[2] - axis[2] * maxt;

	// note: this axis is the axis of the normal cone, but our test for perspective camera effectively negates the axis
	cone.axis[0] = axis[0];
	cone.axis[1] = axis[1];
	cone.axis[2] = axis[2];

	// cos(a) for normal cone is mindp; we need to add 90 degrees on both sides and invert the cone
	// which gives us -cos(a+90) = -(-sin(a)) = sin(a) = sqrt(1 - cos^2(a))
	cone.cutoff = sqrtf(1 - mindp * mindp);

	return cone;
}

meshopt_Cone meshopt_computeMeshletCone(const meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{
	assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
	assert(vertex_positions_stride % sizeof(float) == 0);

	unsigned int indices[sizeof(meshlet->indices) / sizeof(meshlet->indices[0][0])];

	for (unsigned int i = 0; i < meshlet->triangle_count; ++i)
	{
		unsigned int a = meshlet->vertices[meshlet->indices[i][0]];
		unsigned int b = meshlet->vertices[meshlet->indices[i][1]];
		unsigned int c = meshlet->vertices[meshlet->indices[i][2]];

		assert(a < vertex_count && b < vertex_count && c < vertex_count);

		indices[i * 3 + 0] = a;
		indices[i * 3 + 1] = b;
		indices[i * 3 + 2] = c;
	}

	return meshopt_computeClusterCone(indices, meshlet->triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride);
}
<commit_msg>clusterizer: Fix robustness issues by discarding wide cones<commit_after>// This file is part of meshoptimizer library; see meshoptimizer.h for version/license details
#include "meshoptimizer.h"

#include <assert.h>
#include <math.h>
#include <string.h>

size_t meshopt_buildMeshletsBound(size_t index_count, size_t max_vertices, size_t max_triangles)
{
	assert(index_count % 3 == 0);
	assert(max_vertices >= 3);
	assert(max_triangles >= 1);

	// meshlet construction is limited by max vertices and max triangles per meshlet
	// the worst case is that the input is an unindexed stream since this equally stresses both limits
	// note that we assume that in the worst case, we leave 2 vertices unpacked in each meshlet - if we have space for 3 we can pack any triangle
	size_t max_vertices_conservative = max_vertices - 2;
	size_t meshlet_limit_vertices = (index_count + max_vertices_conservative - 1) / max_vertices_conservative;
	size_t meshlet_limit_triangles = (index_count / 3 + max_triangles - 1) / max_triangles;

	return meshlet_limit_vertices > meshlet_limit_triangles ? meshlet_limit_vertices : meshlet_limit_triangles;
}

size_t meshopt_buildMeshlets(meshopt_Meshlet* destination, const unsigned int* indices, size_t index_count, size_t vertex_count, size_t max_vertices, size_t max_triangles)
{
	assert(index_count % 3 == 0);
	assert(max_vertices >= 3);
	assert(max_triangles >= 1);

	meshopt_Meshlet meshlet;
	memset(&meshlet, 0, sizeof(meshlet));

	assert(max_vertices <= sizeof(meshlet.vertices) / sizeof(meshlet.vertices[0]));
	assert(max_triangles <= sizeof(meshlet.indices) / 3);

	// index of the vertex in the meshlet, 0xff if the vertex isn't used
	meshopt_Buffer<unsigned char> used(vertex_count);
	memset(used.data, -1, vertex_count);

	size_t offset = 0;

	for (size_t i = 0; i < index_count; i += 3)
	{
		unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
		assert(a < vertex_count && b < vertex_count && c < vertex_count);

		unsigned char& av = used[a];
		unsigned char& bv = used[b];
		unsigned char& cv = used[c];

		unsigned int used_extra = (av == 0xff) + (bv == 0xff) + (cv == 0xff);

		if (meshlet.vertex_count + used_extra > max_vertices || meshlet.triangle_count >= max_triangles)
		{
			destination[offset++] = meshlet;

			for (size_t j = 0; j < meshlet.vertex_count; ++j)
				used[meshlet.vertices[j]] = 0xff;

			memset(&meshlet, 0, sizeof(meshlet));
		}

		if (av == 0xff)
		{
			av = meshlet.vertex_count;
			meshlet.vertices[meshlet.vertex_count++] = a;
		}

		if (bv == 0xff)
		{
			bv = meshlet.vertex_count;
			meshlet.vertices[meshlet.vertex_count++] = b;
		}

		if (cv == 0xff)
		{
			cv = meshlet.vertex_count;
			meshlet.vertices[meshlet.vertex_count++] = c;
		}

		meshlet.indices[meshlet.triangle_count][0] = av;
		meshlet.indices[meshlet.triangle_count][1] = bv;
		meshlet.indices[meshlet.triangle_count][2] = cv;
		meshlet.triangle_count++;
	}

	if (meshlet.triangle_count)
		destination[offset++] = meshlet;

	assert(offset <= meshopt_buildMeshletsBound(index_count, max_vertices, max_triangles));

	return offset;
}

meshopt_Cone meshopt_computeClusterCone(const unsigned int* indices, size_t index_count, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{
	assert(index_count % 3 == 0);
	assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
	assert(vertex_positions_stride % sizeof(float) == 0);

	assert(index_count / 3 <= 256);

	size_t vertex_stride_float = vertex_positions_stride / sizeof(float);

	float normals[256][3];
	float corners[256][3];
	unsigned int triangles = 0;

	float cluster_area = 0;
	float cluster_centroid[3] = {};

	for (unsigned int i = 0; i < index_count; i += 3)
	{
		unsigned int a = indices[i + 0], b = indices[i + 1], c = indices[i + 2];
		assert(a < vertex_count && b < vertex_count && c < vertex_count);

		const float* p0 = vertex_positions + vertex_stride_float * a;
		const float* p1 = vertex_positions + vertex_stride_float * b;
		const float* p2 = vertex_positions + vertex_stride_float * c;

		float p10[3] = { p1[0] - p0[0], p1[1] - p0[1], p1[2] - p0[2] };
		float p20[3] = { p2[0] - p0[0], p2[1] - p0[1], p2[2] - p0[2] };

		float normalx = p10[1] * p20[2] - p10[2] * p20[1];
		float normaly = p10[2] * p20[0] - p10[0] * p20[2];
		float normalz = p10[0] * p20[1] - p10[1] * p20[0];

		float area = sqrtf(normalx * normalx + normaly * normaly + normalz * normalz);

		// no need to include degenerate triangles - they will be invisible anyway
		if (area == 0.f)
			continue;

		// record triangle normals & corners for future use (this is a plane eqn)
		normals[triangles][0] = normalx / area;
		normals[triangles][1] = normaly / area;
		normals[triangles][2] = normalz / area;
		corners[triangles][0] = p0[0];
		corners[triangles][1] = p0[1];
		corners[triangles][2] = p0[2];
		triangles++;

		// area-weighted centroid
		cluster_centroid[0] += (p0[0] + p1[0] + p2[0]) * (area / 3);
		cluster_centroid[1] += (p0[1] + p1[1] + p2[1]) * (area / 3);
		cluster_centroid[2] += (p0[2] + p1[2] + p2[2]) * (area / 3);
		cluster_area += area;
	}

	float inv_cluster_area = cluster_area == 0 ? 0 : 1 / cluster_area;

	cluster_centroid[0] *= inv_cluster_area;
	cluster_centroid[1] *= inv_cluster_area;
	cluster_centroid[2] *= inv_cluster_area;

	// build a cone around triangle normals
	float axis[3] = {};

	for (unsigned int i = 0; i < triangles; ++i)
	{
		axis[0] += normals[i][0];
		axis[1] += normals[i][1];
		axis[2] += normals[i][2];
	}

	float avglength = sqrtf(axis[0] * axis[0] + axis[1] * axis[1] + axis[2] * axis[2]);
	float invavglength = avglength == 0.f ? 0.f : 1.f / avglength;

	axis[0] *= invavglength;
	axis[1] *= invavglength;
	axis[2] *= invavglength;

	float mindp = 1.f;

	for (unsigned int i = 0; i < triangles; ++i)
	{
		float dp = normals[i][0] * axis[0] + normals[i][1] * axis[1] + normals[i][2] * axis[2];

		mindp = (dp < mindp) ? dp : mindp;
	}

	// degenerate cluster, no valid triangles or normal cone is larger than a hemisphere
	// note that if mindp is positive but close to 0, the triangle intersection code below gets less stable
	// we arbitrarily decide that if a normal cone is ~168 degrees wide or more, the cone isn't useful
	if (triangles == 0 || mindp <= 0.1f)
	{
		meshopt_Cone cone = {};
		cone.cutoff = 1;
		return cone;
	}

	float maxt = 0;

	// we need to find the point on centroid-t*axis ray that lies in negative half-space of all triangles
	for (unsigned int i = 0; i < triangles; ++i)
	{
		// dot(centroid-t*axis-corner, trinormal) = 0
		// dot(centroid-corner, trinormal) - t * dot(axis, trinormal) = 0
		float cx = cluster_centroid[0] - corners[i][0];
		float cy = cluster_centroid[1] - corners[i][1];
		float cz = cluster_centroid[2] - corners[i][2];

		float dc = cx * normals[i][0] + cy * normals[i][1] + cz * normals[i][2];
		float dn = axis[0] * normals[i][0] + axis[1] * normals[i][1] + axis[2] * normals[i][2];

		// dn should be more than mindp cutoff above
		assert(dn > 0.f);
		float t = dc / dn;

		maxt = (t > maxt) ? t : maxt;
	}

	meshopt_Cone cone;

	// cone apex should be in the negative half-space of all cluster triangles by construction
	cone.apex[0] = cluster_centroid[0] - axis[0] * maxt;
	cone.apex[1] = cluster_centroid[1] - axis[1] * maxt;
	cone.apex[2] = cluster_centroid[2] - axis[2] * maxt;

	// note: this axis is the axis of the normal cone, but our test for perspective camera effectively negates the axis
	cone.axis[0] = axis[0];
	cone.axis[1] = axis[1];
	cone.axis[2] = axis[2];

	// cos(a) for normal cone is mindp; we need to add 90 degrees on both sides and invert the cone
	// which gives us -cos(a+90) = -(-sin(a)) = sin(a) = sqrt(1 - cos^2(a))
	cone.cutoff = sqrtf(1 - mindp * mindp);

	return cone;
}

meshopt_Cone meshopt_computeMeshletCone(const meshopt_Meshlet* meshlet, const float* vertex_positions, size_t vertex_count, size_t vertex_positions_stride)
{
	assert(vertex_positions_stride > 0 && vertex_positions_stride <= 256);
	assert(vertex_positions_stride % sizeof(float) == 0);

	unsigned int indices[sizeof(meshlet->indices) / sizeof(meshlet->indices[0][0])];

	for (unsigned int i = 0; i < meshlet->triangle_count; ++i)
	{
		unsigned int a = meshlet->vertices[meshlet->indices[i][0]];
		unsigned int b = meshlet->vertices[meshlet->indices[i][1]];
		unsigned int c = meshlet->vertices[meshlet->indices[i][2]];

		assert(a < vertex_count && b < vertex_count && c < vertex_count);

		indices[i * 3 + 0] = a;
		indices[i * 3 + 1] = b;
		indices[i * 3 + 2] = c;
	}

	return meshopt_computeClusterCone(indices, meshlet->triangle_count * 3, vertex_positions, vertex_count, vertex_positions_stride);
}
<|endoftext|>


<commit_before>/* LXSACN.cpp
   Copyright 2015 by Claude Heintz Design
   This code is in the public domain

   LXSACN partially implements E1.31,
   Lightweight streaming protocol for transport of DMX512 using ACN

   sACN E 1.31 is a public standard published by the PLASA technical standards program
   http://tsp.plasa.org/tsp/documents/published_docs.php
*/

#include "LXSACN.h"

LXSACN::LXSACN ( void )
{
	initialize(0);
}

LXSACN::LXSACN ( uint8_t* buffer )
{
	initialize(buffer);
}

LXSACN::~LXSACN ( void )
{
	if ( _owns_buffer ) {		// if we created this buffer, then free the memory
		free(_packet_buffer);
	}
}

void  LXSACN::initialize  ( uint8_t* b ) {
	if ( b == 0 ) {
		// create buffer
		_packet_buffer = (uint8_t*) malloc(SACN_BUFFER_MAX);
		_owns_buffer = 1;
	} else {
		// external buffer
		_packet_buffer = b;
		_owns_buffer = 0;
	}

	//zero buffer including _dmx_data[0] which is start code
    for (int n=0; n<SACN_BUFFER_MAX; n++) {
    	_packet_buffer[n] = 0;
    	if ( n < SACN_CID_LENGTH ) {
    		 _dmx_sender_id[n] = 0;
    	}
    }

    _dmx_slots = 0;
    _universe = 1;                    // NOTE: unlike Art-Net, sACN universes begin at 1
    _sequence = 1;
}

uint8_t  LXSACN::universe ( void ) {
	return _universe;
}

void LXSACN::setUniverse ( uint8_t u ) {
	_universe = u;
}

int  LXSACN::numberOfSlots ( void ) {
	return _dmx_slots;
}

void LXSACN::setNumberOfSlots ( int n ) {
	_dmx_slots = n;
}

uint8_t LXSACN::getSlot ( int slot ) {
	return _packet_buffer[SACN_ADDRESS_OFFSET+slot];
}

void LXSACN::setSlot ( int slot, uint8_t value ) {
	_packet_buffer[SACN_ADDRESS_OFFSET+slot] = value;
}

uint8_t LXSACN::startCode ( void ) {
	return _packet_buffer[SACN_ADDRESS_OFFSET];
}

void LXSACN::setStartCode ( uint8_t value ) {
	_packet_buffer[SACN_ADDRESS_OFFSET] = value;
}

uint8_t* LXSACN::dmxData( void ) {
	return &_packet_buffer[SACN_ADDRESS_OFFSET];
}

uint8_t LXSACN::readDMXPacket ( EthernetUDP eUDP ) {
   if ( readSACNPacket(eUDP) > 0 ) {
   	return ( startCode() == 0 );
   }
   return 0;
}

uint8_t LXSACN::readDMXPacketContents ( EthernetUDP eUDP, uint16_t packetSize ) {
	if ( parse_root_layer(packetSize) > 0 ) {
   	if ( startCode() == 0 ) {
   		return RESULT_DMX_RECEIVED;
   	}
   }
   return RESULT_NONE;
}

uint16_t LXSACN::readSACNPacket ( EthernetUDP eUDP ) {
   _dmx_slots = 0;
   uint16_t packetSize = eUDP.parsePacket();
   if ( packetSize ) {
      packetSize = eUDP.read(_packet_buffer, SACN_BUFFER_MAX);
      _dmx_slots = parse_root_layer(packetSize);
   }
   return _dmx_slots;
}

void LXSACN::sendDMX ( EthernetUDP eUDP, IPAddress to_ip ) {
   for (int n=0; n<126; n++) {
    	_packet_buffer[n] = 0;		// zero outside layers & start code
    }
   _packet_buffer[0] = 0;
   _packet_buffer[1] = 0x10;
   _packet_buffer[4] = 'A';
   _packet_buffer[5] = 'S';
   _packet_buffer[6] = 'C';
   _packet_buffer[7] = '-';
   _packet_buffer[8] = 'E';
   _packet_buffer[9] = '1';
   _packet_buffer[10] = '.';
   _packet_buffer[11] = '1';
   _packet_buffer[12] = '7';
   uint16_t fplusl = _dmx_slots + 110 + 0x7000;
   _packet_buffer[16] = fplusl >> 8;
   _packet_buffer[17] = fplusl & 0xff;
   _packet_buffer[21] = 0x04;
   fplusl = _dmx_slots + 88 + 0x7000;
   _packet_buffer[38] = fplusl >> 8;
   _packet_buffer[39] = fplusl & 0xff;
   _packet_buffer[43] = 0x02;
   _packet_buffer[44] = 'A';
   _packet_buffer[45] = 'r';
   _packet_buffer[46] = 'd';
   _packet_buffer[47] = 'u';
   _packet_buffer[48] = 'i';
   _packet_buffer[49] = 'n';
   _packet_buffer[50] = 'o';
   _packet_buffer[108] = 100;	//priority
   if ( _sequence == 0 ) {
     _sequence = 1;
   } else {
     _sequence++;
   }
   _packet_buffer[111] = _sequence;
   _packet_buffer[113] = _universe >> 8;
   _packet_buffer[114] = _universe & 0xff;
   fplusl = _dmx_slots + 11 + 0x7000;
   _packet_buffer[115] = fplusl >> 8;
   _packet_buffer[116] = fplusl & 0xff;
   _packet_buffer[117] = 0x02;
   _packet_buffer[118] = 0xa1;
   _packet_buffer[122] = 0x01;
   fplusl = _dmx_slots + 1;
   _packet_buffer[123] = fplusl >> 8;
   _packet_buffer[124] = fplusl & 0xFF;
   //assume dmx data has been set
   eUDP.beginPacket(to_ip, SACN_PORT);
   eUDP.write(_packet_buffer, _dmx_slots + 126);
   eUDP.endPacket();
}

uint16_t LXSACN::parse_root_layer( uint16_t size ) {
  if  ( _packet_buffer[1] == 0x10 ) {									//preamble size
    if ( strcmp((const char*)&_packet_buffer[4], "ASC-E1.17") == 0 ) {
      uint16_t tsize = size - 16;
      if ( checkFlagsAndLength(&_packet_buffer[16], tsize) ) { // root pdu length
        if ( _packet_buffer[21] == 0x04 ) {							// vector RLP is 1.31 data
          return parse_framing_layer( tsize );
        }
      }
    }       // ACN packet identifier
  }			// preamble size
  return 0;
}

uint16_t LXSACN::parse_framing_layer( uint16_t size ) {
   uint16_t tsize = size - 22;
   if ( checkFlagsAndLength(&_packet_buffer[38], tsize) ) {     // framing pdu length
     if ( _packet_buffer[43] == 0x02 ) {                        // vector dmp is 1.31
        if ( _packet_buffer[114] == _universe ) {// implementation has 255 universe limit
          return parse_dmp_layer( tsize );
        }
     }
   }
   return 0;
}

uint16_t LXSACN::parse_dmp_layer( uint16_t size ) {
  uint16_t tsize = size - 77;
  if ( checkFlagsAndLength(&_packet_buffer[115], tsize) ) {  // dmp pdu length
    if ( _packet_buffer[117] == 0x02 ) {                     // Set Property
      if ( _packet_buffer[118] == 0xa1 ) {                   // address and data format
        if ( _dmx_sender_id[0] == 0  ) {
          for(int k=0; k<SACN_CID_LENGTH; k++) {		 // if _dmx_sender_id is not set
            _dmx_sender_id[k] = _packet_buffer[k+22];  // set it to id of this packet
          }
        }
        for(int k=0; k<SACN_CID_LENGTH; k++) {
          if ( _dmx_sender_id[k] != _packet_buffer[k+22] ) {
            return 0;
          }
        }
        uint16_t slots = _packet_buffer[124];      // if same sender, good dmx!
        slots += _packet_buffer[123] << 8;
        return slots;
      }
    }
  }
  return 0;
}

//  utility for checking 2 byte:  flags (high nibble == 0x7) && 12 bit length

uint8_t LXSACN::checkFlagsAndLength( uint8_t* flb, uint16_t size ) {
	if ( ( flb[0] & 0xF0 ) == 0x70 ) {
	   uint16_t pdu_length = flb[1];
		pdu_length += ((flb[0] & 0x0f) << 8);
		if ( ( pdu_length != 0 ) && ( size >= pdu_length ) ) {
		   return 1;
		}
	}
	return 0;
}
<commit_msg>Update LXSACN.cpp<commit_after>/* LXSACN.cpp
   Copyright 2015-2015 by Claude Heintz Design
   see LXDMXEthernet.h for license

   LXSACN partially implements E1.31,
   Lightweight streaming protocol for transport of DMX512 using ACN

   sACN E 1.31 is a public standard published by the PLASA technical standards program
   http://tsp.plasa.org/tsp/documents/published_docs.php
*/

#include "LXSACN.h"

LXSACN::LXSACN ( void )
{
	initialize(0);
}

LXSACN::LXSACN ( uint8_t* buffer )
{
	initialize(buffer);
}

LXSACN::~LXSACN ( void )
{
	if ( _owns_buffer ) {		// if we created this buffer, then free the memory
		free(_packet_buffer);
	}
}

void  LXSACN::initialize  ( uint8_t* b ) {
	if ( b == 0 ) {
		// create buffer
		_packet_buffer = (uint8_t*) malloc(SACN_BUFFER_MAX);
		_owns_buffer = 1;
	} else {
		// external buffer
		_packet_buffer = b;
		_owns_buffer = 0;
	}

	//zero buffer including _dmx_data[0] which is start code
    for (int n=0; n<SACN_BUFFER_MAX; n++) {
    	_packet_buffer[n] = 0;
    	if ( n < SACN_CID_LENGTH ) {
    		 _dmx_sender_id[n] = 0;
    	}
    }

    _dmx_slots = 0;
    _universe = 1;                    // NOTE: unlike Art-Net, sACN universes begin at 1
    _sequence = 1;
}

uint8_t  LXSACN::universe ( void ) {
	return _universe;
}

void LXSACN::setUniverse ( uint8_t u ) {
	_universe = u;
}

int  LXSACN::numberOfSlots ( void ) {
	return _dmx_slots;
}

void LXSACN::setNumberOfSlots ( int n ) {
	_dmx_slots = n;
}

uint8_t LXSACN::getSlot ( int slot ) {
	return _packet_buffer[SACN_ADDRESS_OFFSET+slot];
}

void LXSACN::setSlot ( int slot, uint8_t value ) {
	_packet_buffer[SACN_ADDRESS_OFFSET+slot] = value;
}

uint8_t LXSACN::startCode ( void ) {
	return _packet_buffer[SACN_ADDRESS_OFFSET];
}

void LXSACN::setStartCode ( uint8_t value ) {
	_packet_buffer[SACN_ADDRESS_OFFSET] = value;
}

uint8_t* LXSACN::dmxData( void ) {
	return &_packet_buffer[SACN_ADDRESS_OFFSET];
}

uint8_t LXSACN::readDMXPacket ( EthernetUDP eUDP ) {
   if ( readSACNPacket(eUDP) > 0 ) {
   	return ( startCode() == 0 );
   }
   return 0;
}

uint8_t LXSACN::readDMXPacketContents ( EthernetUDP eUDP, uint16_t packetSize ) {
	if ( parse_root_layer(packetSize) > 0 ) {
   	if ( startCode() == 0 ) {
   		return RESULT_DMX_RECEIVED;
   	}
   }
   return RESULT_NONE;
}

uint16_t LXSACN::readSACNPacket ( EthernetUDP eUDP ) {
   _dmx_slots = 0;
   uint16_t packetSize = eUDP.parsePacket();
   if ( packetSize ) {
      packetSize = eUDP.read(_packet_buffer, SACN_BUFFER_MAX);
      _dmx_slots = parse_root_layer(packetSize);
   }
   return _dmx_slots;
}

void LXSACN::sendDMX ( EthernetUDP eUDP, IPAddress to_ip ) {
   for (int n=0; n<126; n++) {
    	_packet_buffer[n] = 0;		// zero outside layers & start code
    }
   _packet_buffer[0] = 0;
   _packet_buffer[1] = 0x10;
   _packet_buffer[4] = 'A';
   _packet_buffer[5] = 'S';
   _packet_buffer[6] = 'C';
   _packet_buffer[7] = '-';
   _packet_buffer[8] = 'E';
   _packet_buffer[9] = '1';
   _packet_buffer[10] = '.';
   _packet_buffer[11] = '1';
   _packet_buffer[12] = '7';
   uint16_t fplusl = _dmx_slots + 110 + 0x7000;
   _packet_buffer[16] = fplusl >> 8;
   _packet_buffer[17] = fplusl & 0xff;
   _packet_buffer[21] = 0x04;
   fplusl = _dmx_slots + 88 + 0x7000;
   _packet_buffer[38] = fplusl >> 8;
   _packet_buffer[39] = fplusl & 0xff;
   _packet_buffer[43] = 0x02;
   _packet_buffer[44] = 'A';
   _packet_buffer[45] = 'r';
   _packet_buffer[46] = 'd';
   _packet_buffer[47] = 'u';
   _packet_buffer[48] = 'i';
   _packet_buffer[49] = 'n';
   _packet_buffer[50] = 'o';
   _packet_buffer[108] = 100;	//priority
   if ( _sequence == 0 ) {
     _sequence = 1;
   } else {
     _sequence++;
   }
   _packet_buffer[111] = _sequence;
   _packet_buffer[113] = _universe >> 8;
   _packet_buffer[114] = _universe & 0xff;
   fplusl = _dmx_slots + 11 + 0x7000;
   _packet_buffer[115] = fplusl >> 8;
   _packet_buffer[116] = fplusl & 0xff;
   _packet_buffer[117] = 0x02;
   _packet_buffer[118] = 0xa1;
   _packet_buffer[122] = 0x01;
   fplusl = _dmx_slots + 1;
   _packet_buffer[123] = fplusl >> 8;
   _packet_buffer[124] = fplusl & 0xFF;
   //assume dmx data has been set
   eUDP.beginPacket(to_ip, SACN_PORT);
   eUDP.write(_packet_buffer, _dmx_slots + 126);
   eUDP.endPacket();
}

uint16_t LXSACN::parse_root_layer( uint16_t size ) {
  if  ( _packet_buffer[1] == 0x10 ) {									//preamble size
    if ( strcmp((const char*)&_packet_buffer[4], "ASC-E1.17") == 0 ) {
      uint16_t tsize = size - 16;
      if ( checkFlagsAndLength(&_packet_buffer[16], tsize) ) { // root pdu length
        if ( _packet_buffer[21] == 0x04 ) {							// vector RLP is 1.31 data
          return parse_framing_layer( tsize );
        }
      }
    }       // ACN packet identifier
  }			// preamble size
  return 0;
}

uint16_t LXSACN::parse_framing_layer( uint16_t size ) {
   uint16_t tsize = size - 22;
   if ( checkFlagsAndLength(&_packet_buffer[38], tsize) ) {     // framing pdu length
     if ( _packet_buffer[43] == 0x02 ) {                        // vector dmp is 1.31
        if ( _packet_buffer[114] == _universe ) {// implementation has 255 universe limit
          return parse_dmp_layer( tsize );
        }
     }
   }
   return 0;
}

uint16_t LXSACN::parse_dmp_layer( uint16_t size ) {
  uint16_t tsize = size - 77;
  if ( checkFlagsAndLength(&_packet_buffer[115], tsize) ) {  // dmp pdu length
    if ( _packet_buffer[117] == 0x02 ) {                     // Set Property
      if ( _packet_buffer[118] == 0xa1 ) {                   // address and data format
        if ( _dmx_sender_id[0] == 0  ) {
          for(int k=0; k<SACN_CID_LENGTH; k++) {		 // if _dmx_sender_id is not set
            _dmx_sender_id[k] = _packet_buffer[k+22];  // set it to id of this packet
          }
        }
        for(int k=0; k<SACN_CID_LENGTH; k++) {
          if ( _dmx_sender_id[k] != _packet_buffer[k+22] ) {
            return 0;
          }
        }
        uint16_t slots = _packet_buffer[124];      // if same sender, good dmx!
        slots += _packet_buffer[123] << 8;
        return slots;
      }
    }
  }
  return 0;
}

//  utility for checking 2 byte:  flags (high nibble == 0x7) && 12 bit length

uint8_t LXSACN::checkFlagsAndLength( uint8_t* flb, uint16_t size ) {
	if ( ( flb[0] & 0xF0 ) == 0x70 ) {
	   uint16_t pdu_length = flb[1];
		pdu_length += ((flb[0] & 0x0f) << 8);
		if ( ( pdu_length != 0 ) && ( size >= pdu_length ) ) {
		   return 1;
		}
	}
	return 0;
}
<|endoftext|>


<commit_before>#include <iostream>

#include "Message.h"
#include "Ladder.h"
#include "Point.h"

using namespace std;

#define ALIVE true
#define DEAD  false

// IsLadderCaptured֐p
game_info_t search_game[100];

void
LadderExtension( const game_info_t *game, int color, bool *ladder_pos )
{
  const string_t *string = game->string;
  int i, ladder = PASS;
  game_info_t *shicho_game = AllocateGame();
  bool checked[BOARD_MAX] = { false };
  int neighbor;
  bool flag;

  for (i = 0; i < MAX_STRING; i++) {
    if (!string[i].flag ||
	string[i].color != color) {
      continue;
    }
    // A^瓦钅ӏ
    ladder = string[i].lib[0];

    flag = false;

    // A^𓦂ŖT̂̂mF
    if (!checked[ladder] && string[i].libs == 1) {
      // אڂGAď邩mF
      neighbor = string[i].neighbor[0];
      while (neighbor != NEIGHBOR_END) {
	if (string[neighbor].libs == 1) {
	  CopyGame(shicho_game, game);
	  PutStone(shicho_game, string[neighbor].lib[0], color);
	  if (IsLadderCaptured(0, shicho_game, string[i].origin, FLIP_COLOR(color)) == DEAD) {
	    if (string[i].size >= 2) {
	      ladder_pos[string[neighbor].lib[0]] = true;
	    }
	  } else {
	    flag = true;
	    break;
	  }
	}
	neighbor = string[i].neighbor[neighbor];
      }

      // ďȂ͓Ă݂
      if (!flag) {
	if (IsLegal(game, ladder, color)) {
	  CopyGame(shicho_game, game);
	  PutStone(shicho_game, ladder, color);
	  if (string[i].size >= 2 &&
	      IsLadderCaptured(0, shicho_game, ladder, FLIP_COLOR(color)) == DEAD){
	      ladder_pos[ladder] = true;
	  }
	}
      }
      checked[ladder] = true;
    }
  }

  FreeGame(shicho_game);
}

bool
IsLadderCaptured( int depth, const game_info_t *game, int ren_xy, int turn_color )
{
  const string_t *string = game->string;
  int str = game->string_id[ren_xy];
  int escape_color, capture_color;
  int escape_xy, capture_xy;
  const char *board = game->board;
  int neighbor;

  if (depth >= 100) {
    return ALIVE;
  }

  if (board[ren_xy] == S_EMPTY) {
    return DEAD;
  } else if (string[str].libs >= 3) {
    return ALIVE;
  }

  escape_color = board[ren_xy];
  capture_color = FLIP_COLOR(escape_color);

  if (turn_color == escape_color) {
    // ͂̓GA邩mF,
    // ȂĒT𑱂
    neighbor = string[str].neighbor[0];
    while (neighbor != NEIGHBOR_END) {
      if (string[neighbor].libs == 1) {
	if (IsLegal(game, string[neighbor].lib[0], escape_color)) {
	  CopyGame(&search_game[depth], game);
	  PutStone(&search_game[depth], string[neighbor].lib[0], escape_color);
	  if (IsLadderCaptured(depth + 1, &search_game[depth], ren_xy, FLIP_COLOR(turn_color)) == ALIVE) {
	    return ALIVE;
	  }
	}
      }
      neighbor = string[str].neighbor[neighbor];
    }

    // łĂ݂ĒT𑱂
    escape_xy = string[str].lib[0];
    while (escape_xy != LIBERTY_END) {
      if (IsLegal(game, escape_xy, escape_color)) {
	CopyGame(&search_game[depth], game);
	PutStone(&search_game[depth], escape_xy, escape_color);
	if (IsLadderCaptured(depth + 1, &search_game[depth], ren_xy, FLIP_COLOR(turn_color)) == ALIVE) {
	  return ALIVE;
	}
      }
      escape_xy = string[str].lib[escape_xy];
    }
    return DEAD;
  } else {
    if (string[str].libs == 1) return DEAD;
    // ǂ鑤Ȃ̂ŃA^ɂłĂ݂
    capture_xy = string[str].lib[0];
    while (capture_xy != LIBERTY_END) {
      if (IsLegal(game, capture_xy, capture_color)) {
	CopyGame(&search_game[depth], game);
	PutStone(&search_game[depth], capture_xy, capture_color);
	if (IsLadderCaptured(depth + 1, &search_game[depth], ren_xy, FLIP_COLOR(turn_color)) == DEAD) {
	  return DEAD;
	}
      }
      capture_xy = string[str].lib[capture_xy];
    }
  }

  return ALIVE;
}

//////////////////////////////////////////
//  ȂV`E𓦂肩  //
//////////////////////////////////////////
bool
CheckLadderExtension( const game_info_t *game, int color, int pos )
{
  const char *board = game->board;
  const string_t *string = game->string;
  const int *string_id = game->string_id;
  int ladder = PASS;
  game_info_t *shicho_game = AllocateGame();
  bool flag = false;
  int id;

  if (board[pos] != color){
    FreeGame(shicho_game);
    return false;
  }

  id = string_id[pos];

  ladder = string[id].lib[0];

  if (string[id].libs == 1 && IsLegal(game, ladder, color)){
    CopyGame(shicho_game, game);
    PutStone(shicho_game, ladder, color);
    if (IsLadderCaptured(0, shicho_game, ladder, FLIP_COLOR(color)) == DEAD) {
      flag = true;
    } else {
      flag = false;
    }
  }

  FreeGame(shicho_game);

  return flag;
}
<commit_msg>Lock in Ladder<commit_after>#include <iostream>
#include <mutex>

#include "Message.h"
#include "Ladder.h"
#include "Point.h"

using namespace std;

#define ALIVE true
#define DEAD  false

// IsLadderCaptured֐p
static game_info_t search_game[100];

static mutex mutex_ladder;

void
LadderExtension( const game_info_t *game, int color, bool *ladder_pos )
{
  lock_guard<mutex> lock(mutex_ladder);
  const string_t *string = game->string;
  int i, ladder = PASS;
  static game_info_t *shicho_game = AllocateGame();
  bool checked[BOARD_MAX] = { false };
  int neighbor;
  bool flag;

  for (i = 0; i < MAX_STRING; i++) {
    if (!string[i].flag ||
	string[i].color != color) {
      continue;
    }
    // A^瓦钅ӏ
    ladder = string[i].lib[0];

    flag = false;

    // A^𓦂ŖT̂̂mF
    if (!checked[ladder] && string[i].libs == 1) {
      // אڂGAď邩mF
      neighbor = string[i].neighbor[0];
      while (neighbor != NEIGHBOR_END) {
	if (string[neighbor].libs == 1) {
	  CopyGame(shicho_game, game);
	  PutStone(shicho_game, string[neighbor].lib[0], color);
	  if (IsLadderCaptured(0, shicho_game, string[i].origin, FLIP_COLOR(color)) == DEAD) {
	    if (string[i].size >= 2) {
	      ladder_pos[string[neighbor].lib[0]] = true;
	    }
	  } else {
	    flag = true;
	    break;
	  }
	}
	neighbor = string[i].neighbor[neighbor];
      }

      // ďȂ͓Ă݂
      if (!flag) {
	if (IsLegal(game, ladder, color)) {
	  CopyGame(shicho_game, game);
	  PutStone(shicho_game, ladder, color);
	  if (string[i].size >= 2 &&
	      IsLadderCaptured(0, shicho_game, ladder, FLIP_COLOR(color)) == DEAD){
	      ladder_pos[ladder] = true;
	  }
	}
      }
      checked[ladder] = true;
    }
  }

  //FreeGame(shicho_game);
}

bool
IsLadderCaptured( int depth, const game_info_t *game, int ren_xy, int turn_color )
{
  const string_t *string = game->string;
  int str = game->string_id[ren_xy];
  int escape_color, capture_color;
  int escape_xy, capture_xy;
  const char *board = game->board;
  int neighbor;

  if (depth >= 100) {
    return ALIVE;
  }

  if (board[ren_xy] == S_EMPTY) {
    return DEAD;
  } else if (string[str].libs >= 3) {
    return ALIVE;
  }

  escape_color = board[ren_xy];
  capture_color = FLIP_COLOR(escape_color);

  if (turn_color == escape_color) {
    // ͂̓GA邩mF,
    // ȂĒT𑱂
    neighbor = string[str].neighbor[0];
    while (neighbor != NEIGHBOR_END) {
      if (string[neighbor].libs == 1) {
	if (IsLegal(game, string[neighbor].lib[0], escape_color)) {
	  CopyGame(&search_game[depth], game);
	  PutStone(&search_game[depth], string[neighbor].lib[0], escape_color);
	  if (IsLadderCaptured(depth + 1, &search_game[depth], ren_xy, FLIP_COLOR(turn_color)) == ALIVE) {
	    return ALIVE;
	  }
	}
      }
      neighbor = string[str].neighbor[neighbor];
    }

    // łĂ݂ĒT𑱂
    escape_xy = string[str].lib[0];
    while (escape_xy != LIBERTY_END) {
      if (IsLegal(game, escape_xy, escape_color)) {
	CopyGame(&search_game[depth], game);
	PutStone(&search_game[depth], escape_xy, escape_color);
	if (IsLadderCaptured(depth + 1, &search_game[depth], ren_xy, FLIP_COLOR(turn_color)) == ALIVE) {
	  return ALIVE;
	}
      }
      escape_xy = string[str].lib[escape_xy];
    }
    return DEAD;
  } else {
    if (string[str].libs == 1) return DEAD;
    // ǂ鑤Ȃ̂ŃA^ɂłĂ݂
    capture_xy = string[str].lib[0];
    while (capture_xy != LIBERTY_END) {
      if (IsLegal(game, capture_xy, capture_color)) {
	CopyGame(&search_game[depth], game);
	PutStone(&search_game[depth], capture_xy, capture_color);
	if (IsLadderCaptured(depth + 1, &search_game[depth], ren_xy, FLIP_COLOR(turn_color)) == DEAD) {
	  return DEAD;
	}
      }
      capture_xy = string[str].lib[capture_xy];
    }
  }

  return ALIVE;
}

//////////////////////////////////////////
//  ȂV`E𓦂肩  //
//////////////////////////////////////////
bool
CheckLadderExtension( const game_info_t *game, int color, int pos )
{
  lock_guard<mutex> lock(mutex_ladder);
  const char *board = game->board;
  const string_t *string = game->string;
  const int *string_id = game->string_id;
  int ladder = PASS;
  game_info_t *shicho_game = AllocateGame();
  bool flag = false;
  int id;

  if (board[pos] != color){
    FreeGame(shicho_game);
    return false;
  }

  id = string_id[pos];

  ladder = string[id].lib[0];

  if (string[id].libs == 1 && IsLegal(game, ladder, color)){
    CopyGame(shicho_game, game);
    PutStone(shicho_game, ladder, color);
    if (IsLadderCaptured(0, shicho_game, ladder, FLIP_COLOR(color)) == DEAD) {
      flag = true;
    } else {
      flag = false;
    }
  }

  FreeGame(shicho_game);

  return flag;
}
<|endoftext|>


<commit_before>// SciTE - Scintilla based Text Editor
// LexCPP.cxx - lexer for C++, C, Java, and Javascript
// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool classifyWordCpp(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
	char s[100];
	bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
	bool wordIsUUID = false;
	for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) {
		s[i] = styler[start + i];
		s[i + 1] = '\0';
	}
	char chAttr = SCE_C_IDENTIFIER;
	if (wordIsNumber)
		chAttr = SCE_C_NUMBER;
	else {
		if (keywords.InList(s)) {
			chAttr = SCE_C_WORD;
			wordIsUUID = strcmp(s, "uuid") == 0;
		}
	}
	styler.ColourTo(end, chAttr);
	return wordIsUUID;
}

static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
	Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	styler.StartAt(startPos);

	bool fold = styler.GetPropertyInt("fold");
	bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor");
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;

	int state = initStyle;
	if (state == SCE_C_STRINGEOL)	// Does not leak onto next line
		state = SCE_C_DEFAULT;
	char chPrev = ' ';
	char chNext = styler[startPos];
	unsigned int lengthDoc = startPos + length;
	int visChars = 0;
	styler.StartSegment(startPos);
	bool lastWordWasUUID = false;
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
			// End of line
			if (state == SCE_C_STRINGEOL) {
				styler.ColourTo(i, state);
				state = SCE_C_DEFAULT;
			}
			if (fold) {
				int lev = levelPrev;
				if (visChars == 0)
					lev |= SC_FOLDLEVELWHITEFLAG;
				if ((levelCurrent > levelPrev) && (visChars > 0))
					lev |= SC_FOLDLEVELHEADERFLAG;
				styler.SetLevel(lineCurrent, lev);
				lineCurrent++;
				visChars = 0;
				levelPrev = levelCurrent;
			}
		}
		if (!isspace(ch))
			visChars++;

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			chPrev = ' ';
			i += 1;
			continue;
		}

		if (state == SCE_C_DEFAULT) {
			if (iswordstart(ch)) {
				styler.ColourTo(i-1, state);
				if (lastWordWasUUID) {
					state = SCE_C_UUID;
					lastWordWasUUID = false;
				} else {
					state = SCE_C_WORD;
				}
			} else if (ch == '/' && chNext == '*') {
				styler.ColourTo(i-1, state);
				if (styler.SafeGetCharAt(i + 2) == '*')
					state = SCE_C_COMMENTDOC;
				else
					state = SCE_C_COMMENT;
			} else if (ch == '/' && chNext == '/') {
				styler.ColourTo(i-1, state);
				state = SCE_C_COMMENTLINE;
			} else if (ch == '\"') {
				styler.ColourTo(i-1, state);
				state = SCE_C_STRING;
			} else if (ch == '\'') {
				styler.ColourTo(i-1, state);
				state = SCE_C_CHARACTER;
			} else if (ch == '#') {
				styler.ColourTo(i-1, state);
				state = SCE_C_PREPROCESSOR;
				// Skip whitespace between # and preprocessor word
				do {
					i++;
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				} while (isspace(ch));
			} else if (isoperator(ch)) {
				styler.ColourTo(i-1, state);
				styler.ColourTo(i, SCE_C_OPERATOR);
				if ((ch == '{') || (ch == '}')) {
					levelCurrent += (ch == '{') ? 1 : -1;
				}
			}
		} else if (state == SCE_C_WORD) {
			if (!iswordchar(ch)) {
				lastWordWasUUID = classifyWordCpp(styler.GetStartSegment(), i - 1, keywords, styler);
				state = SCE_C_DEFAULT;
				if (ch == '/' && chNext == '*') {
					if (styler.SafeGetCharAt(i + 2) == '*')
						state = SCE_C_COMMENTDOC;
					else
						state = SCE_C_COMMENT;
				} else if (ch == '/' && chNext == '/') {
					state = SCE_C_COMMENTLINE;
				} else if (ch == '\"') {
					state = SCE_C_STRING;
				} else if (ch == '\'') {
					state = SCE_C_CHARACTER;
				} else if (isoperator(ch)) {
					styler.ColourTo(i, SCE_C_OPERATOR);
					if ((ch == '{') || (ch == '}')) {
						levelCurrent += (ch == '{') ? 1 : -1;
					}
				}
			}
		} else {
			if (state == SCE_C_PREPROCESSOR) {
				if (stylingWithinPreprocessor) {
					if (isspace(ch)) {
						styler.ColourTo(i-1, state);
						state = SCE_C_DEFAULT;
					}
				} else {
					if ((ch == '\r' || ch == '\n') && !(chPrev == '\\' || chPrev == '\r')) {
						styler.ColourTo(i-1, state);
						state = SCE_C_DEFAULT;
					}
				}
			} else if (state == SCE_C_COMMENT) {
				if (ch == '/' && chPrev == '*') {
					if (((i > styler.GetStartSegment() + 2) || (
						(initStyle == SCE_C_COMMENT) &&
						(styler.GetStartSegment() == static_cast<unsigned int>(startPos))))) {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
					}
				}
			} else if (state == SCE_C_COMMENTDOC) {
				if (ch == '/' && chPrev == '*') {
					if (((i > styler.GetStartSegment() + 2) || (
						(initStyle == SCE_C_COMMENTDOC) &&
						(styler.GetStartSegment() == static_cast<unsigned int>(startPos))))) {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
					}
				}
			} else if (state == SCE_C_COMMENTLINE) {
				if (ch == '\r' || ch == '\n') {
					styler.ColourTo(i-1, state);
					state = SCE_C_DEFAULT;
				}
			} else if (state == SCE_C_STRING) {
				if (ch == '\\') {
					if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
						i++;
						ch = chNext;
						chNext = styler.SafeGetCharAt(i + 1);
					}
				} else if (ch == '\"') {
					styler.ColourTo(i, state);
					state = SCE_C_DEFAULT;
				} else if (chNext == '\r' || chNext == '\n') {
					styler.ColourTo(i-1, SCE_C_STRINGEOL);
					state = SCE_C_STRINGEOL;
				}
			} else if (state == SCE_C_CHARACTER) {
				if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) {
					styler.ColourTo(i-1, SCE_C_STRINGEOL);
					state = SCE_C_STRINGEOL;
				} else if (ch == '\\') {
					if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
						i++;
						ch = chNext;
						chNext = styler.SafeGetCharAt(i + 1);
					}
				} else if (ch == '\'') {
					styler.ColourTo(i, state);
					state = SCE_C_DEFAULT;
				}
			} else if (state == SCE_C_UUID) {
				if (ch == '\r' || ch == '\n' || ch == ')') {
					styler.ColourTo(i-1, state);
					if (ch == ')')
						styler.ColourTo(i, SCE_C_OPERATOR);
					state = SCE_C_DEFAULT;
				}
			}
		}
		chPrev = ch;
	}
	styler.ColourTo(lengthDoc - 1, state);

	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	if (fold) {
		int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
		//styler.SetLevel(lineCurrent, levelCurrent | flagsNext);
		styler.SetLevel(lineCurrent, levelPrev | flagsNext);

	}
}

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc);
<commit_msg>Fixed hang where only visible char in file is '#'.<commit_after>// SciTE - Scintilla based Text Editor
// LexCPP.cxx - lexer for C++, C, Java, and Javascript
// Copyright 1998-2000 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static bool classifyWordCpp(unsigned int start, unsigned int end, WordList &keywords, Accessor &styler) {
	char s[100];
	bool wordIsNumber = isdigit(styler[start]) || (styler[start] == '.');
	bool wordIsUUID = false;
	for (unsigned int i = 0; i < end - start + 1 && i < 30; i++) {
		s[i] = styler[start + i];
		s[i + 1] = '\0';
	}
	char chAttr = SCE_C_IDENTIFIER;
	if (wordIsNumber)
		chAttr = SCE_C_NUMBER;
	else {
		if (keywords.InList(s)) {
			chAttr = SCE_C_WORD;
			wordIsUUID = strcmp(s, "uuid") == 0;
		}
	}
	styler.ColourTo(end, chAttr);
	return wordIsUUID;
}

static void ColouriseCppDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[],
	Accessor &styler) {

	WordList &keywords = *keywordlists[0];

	styler.StartAt(startPos);

	bool fold = styler.GetPropertyInt("fold");
	bool stylingWithinPreprocessor = styler.GetPropertyInt("styling.within.preprocessor");
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;

	int state = initStyle;
	if (state == SCE_C_STRINGEOL)	// Does not leak onto next line
		state = SCE_C_DEFAULT;
	char chPrev = ' ';
	char chNext = styler[startPos];
	unsigned int lengthDoc = startPos + length;
	int visChars = 0;
	styler.StartSegment(startPos);
	bool lastWordWasUUID = false;
	for (unsigned int i = startPos; i < lengthDoc; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);

		if ((ch == '\r' && chNext != '\n') || (ch == '\n')) {
			// End of line
			if (state == SCE_C_STRINGEOL) {
				styler.ColourTo(i, state);
				state = SCE_C_DEFAULT;
			}
			if (fold) {
				int lev = levelPrev;
				if (visChars == 0)
					lev |= SC_FOLDLEVELWHITEFLAG;
				if ((levelCurrent > levelPrev) && (visChars > 0))
					lev |= SC_FOLDLEVELHEADERFLAG;
				styler.SetLevel(lineCurrent, lev);
				lineCurrent++;
				visChars = 0;
				levelPrev = levelCurrent;
			}
		}
		if (!isspace(ch))
			visChars++;

		if (styler.IsLeadByte(ch)) {
			chNext = styler.SafeGetCharAt(i + 2);
			chPrev = ' ';
			i += 1;
			continue;
		}

		if (state == SCE_C_DEFAULT) {
			if (iswordstart(ch)) {
				styler.ColourTo(i-1, state);
				if (lastWordWasUUID) {
					state = SCE_C_UUID;
					lastWordWasUUID = false;
				} else {
					state = SCE_C_WORD;
				}
			} else if (ch == '/' && chNext == '*') {
				styler.ColourTo(i-1, state);
				if (styler.SafeGetCharAt(i + 2) == '*')
					state = SCE_C_COMMENTDOC;
				else
					state = SCE_C_COMMENT;
			} else if (ch == '/' && chNext == '/') {
				styler.ColourTo(i-1, state);
				state = SCE_C_COMMENTLINE;
			} else if (ch == '\"') {
				styler.ColourTo(i-1, state);
				state = SCE_C_STRING;
			} else if (ch == '\'') {
				styler.ColourTo(i-1, state);
				state = SCE_C_CHARACTER;
			} else if (ch == '#') {
				styler.ColourTo(i-1, state);
				state = SCE_C_PREPROCESSOR;
				// Skip whitespace between # and preprocessor word
				do {
					i++;
					ch = chNext;
					chNext = styler.SafeGetCharAt(i + 1);
				} while (isspace(ch) && (i < lengthDoc));
			} else if (isoperator(ch)) {
				styler.ColourTo(i-1, state);
				styler.ColourTo(i, SCE_C_OPERATOR);
				if ((ch == '{') || (ch == '}')) {
					levelCurrent += (ch == '{') ? 1 : -1;
				}
			}
		} else if (state == SCE_C_WORD) {
			if (!iswordchar(ch)) {
				lastWordWasUUID = classifyWordCpp(styler.GetStartSegment(), i - 1, keywords, styler);
				state = SCE_C_DEFAULT;
				if (ch == '/' && chNext == '*') {
					if (styler.SafeGetCharAt(i + 2) == '*')
						state = SCE_C_COMMENTDOC;
					else
						state = SCE_C_COMMENT;
				} else if (ch == '/' && chNext == '/') {
					state = SCE_C_COMMENTLINE;
				} else if (ch == '\"') {
					state = SCE_C_STRING;
				} else if (ch == '\'') {
					state = SCE_C_CHARACTER;
				} else if (isoperator(ch)) {
					styler.ColourTo(i, SCE_C_OPERATOR);
					if ((ch == '{') || (ch == '}')) {
						levelCurrent += (ch == '{') ? 1 : -1;
					}
				}
			}
		} else {
			if (state == SCE_C_PREPROCESSOR) {
				if (stylingWithinPreprocessor) {
					if (isspace(ch)) {
						styler.ColourTo(i-1, state);
						state = SCE_C_DEFAULT;
					}
				} else {
					if ((ch == '\r' || ch == '\n') && !(chPrev == '\\' || chPrev == '\r')) {
						styler.ColourTo(i-1, state);
						state = SCE_C_DEFAULT;
					}
				}
			} else if (state == SCE_C_COMMENT) {
				if (ch == '/' && chPrev == '*') {
					if (((i > styler.GetStartSegment() + 2) || (
						(initStyle == SCE_C_COMMENT) &&
						(styler.GetStartSegment() == static_cast<unsigned int>(startPos))))) {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
					}
				}
			} else if (state == SCE_C_COMMENTDOC) {
				if (ch == '/' && chPrev == '*') {
					if (((i > styler.GetStartSegment() + 2) || (
						(initStyle == SCE_C_COMMENTDOC) &&
						(styler.GetStartSegment() == static_cast<unsigned int>(startPos))))) {
						styler.ColourTo(i, state);
						state = SCE_C_DEFAULT;
					}
				}
			} else if (state == SCE_C_COMMENTLINE) {
				if (ch == '\r' || ch == '\n') {
					styler.ColourTo(i-1, state);
					state = SCE_C_DEFAULT;
				}
			} else if (state == SCE_C_STRING) {
				if (ch == '\\') {
					if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
						i++;
						ch = chNext;
						chNext = styler.SafeGetCharAt(i + 1);
					}
				} else if (ch == '\"') {
					styler.ColourTo(i, state);
					state = SCE_C_DEFAULT;
				} else if (chNext == '\r' || chNext == '\n') {
					styler.ColourTo(i-1, SCE_C_STRINGEOL);
					state = SCE_C_STRINGEOL;
				}
			} else if (state == SCE_C_CHARACTER) {
				if ((ch == '\r' || ch == '\n') && (chPrev != '\\')) {
					styler.ColourTo(i-1, SCE_C_STRINGEOL);
					state = SCE_C_STRINGEOL;
				} else if (ch == '\\') {
					if (chNext == '\"' || chNext == '\'' || chNext == '\\') {
						i++;
						ch = chNext;
						chNext = styler.SafeGetCharAt(i + 1);
					}
				} else if (ch == '\'') {
					styler.ColourTo(i, state);
					state = SCE_C_DEFAULT;
				}
			} else if (state == SCE_C_UUID) {
				if (ch == '\r' || ch == '\n' || ch == ')') {
					styler.ColourTo(i-1, state);
					if (ch == ')')
						styler.ColourTo(i, SCE_C_OPERATOR);
					state = SCE_C_DEFAULT;
				}
			}
		}
		chPrev = ch;
	}
	styler.ColourTo(lengthDoc - 1, state);

	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	if (fold) {
		int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
		//styler.SetLevel(lineCurrent, levelCurrent | flagsNext);
		styler.SetLevel(lineCurrent, levelPrev | flagsNext);

	}
}

LexerModule lmCPP(SCLEX_CPP, ColouriseCppDoc);
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <iostream>
#include <crtdbg.h>
#include <windows.h>
#include "UnitTestHarness/MemoryLeakWarning.h"

#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#endif

static int expectCount = 0;

void MemoryLeakWarning::Enable()
{
  _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE );
  _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
  _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE );
  _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
  _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE );
  _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
  SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

const char* MemoryLeakWarning::FinalReport()
{
  //windows reports leaks automatically when set up as above
  return "";
}

static _CrtMemState s1, s2, s3;

void MemoryLeakWarning::CheckPointUsage()
{
  expectCount = 0;
  _CrtMemCheckpoint( &s1 );
}

static char message[50] = "";
bool MemoryLeakWarning::UsageIsNotBalanced()
{
  _CrtMemCheckpoint( &s2 );
  if (_CrtMemDifference( &s3, &s1, &s2) )
  {
      if (s3.lCounts[1] == expectCount)
        return false;
      else
      {
        sprintf(message, "this test leaks %d blocks", s3.lCounts[1]);
        return true;
      }
  }
  else
  {
    return false;
  }
}

const char* MemoryLeakWarning::Message()
{
  return message;
}

void MemoryLeakWarning::IgnoreLeaks(int n)
{
    expectCount = n;
}
<commit_msg>Added stuff about leaks to be expected. Not nice, but needed.<commit_after>/*
 * Copyright (c) 2007, Michael Feathers, James Grenning and Bas Vodde
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *     * Redistributions of source code must retain the above copyright
 *       notice, this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright
 *       notice, this list of conditions and the following disclaimer in the
 *       documentation and/or other materials provided with the distribution.
 *     * Neither the name of the <organization> nor the
 *       names of its contributors may be used to endorse or promote products
 *       derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE EARLIER MENTIONED AUTHORS ``AS IS'' AND ANY
 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL <copyright holder> BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#define CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <iostream>
#include <crtdbg.h>
#include <windows.h>
#include "UnitTestHarness/MemoryLeakWarning.h"

#ifdef   _DEBUG
#define  SET_CRT_DEBUG_FIELD(a) \
            _CrtSetDbgFlag((a) | _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG))
#else
#define  SET_CRT_DEBUG_FIELD(a)   ((void) 0)
#endif

static int expectCount = 0;

void MemoryLeakWarning::Enable()
{
  _CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE );
  _CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDERR );
  _CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE );
  _CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDERR );
  _CrtSetReportMode( _CRT_ASSERT, _CRTDBG_MODE_DEBUG|_CRTDBG_MODE_FILE );
  _CrtSetReportFile( _CRT_ASSERT, _CRTDBG_FILE_STDERR );
  SET_CRT_DEBUG_FIELD( _CRTDBG_LEAK_CHECK_DF );
}

const char* MemoryLeakWarning::FinalReport(int toBeDeletedLeaks)
{
  //windows reports leaks automatically when set up as above
  return "";
}

static _CrtMemState s1, s2, s3;

void MemoryLeakWarning::CheckPointUsage()
{
  expectCount = 0;
  _CrtMemCheckpoint( &s1 );
}

static char message[50] = "";
bool MemoryLeakWarning::UsageIsNotBalanced()
{
  _CrtMemCheckpoint( &s2 );
  if (_CrtMemDifference( &s3, &s1, &s2) )
  {
      if (s3.lCounts[1] == expectCount)
        return false;
      else
      {
        sprintf(message, "this test leaks %d blocks", s3.lCounts[1]);
        return true;
      }
  }
  else
  {
    return false;
  }
}

const char* MemoryLeakWarning::Message()
{
  return message;
}

void MemoryLeakWarning::IgnoreLeaks(int n)
{
    expectCount = n;
}
<|endoftext|>