<commit_before>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#include "FunctionSubstring.hpp"

#include <PlatformSupport/DoubleSupport.hpp>

#include "XObjectFactory.hpp"

const XObjectPtr		FunctionSubstring::s_nullXObjectPtr;

FunctionSubstring::FunctionSubstring()
{
}

FunctionSubstring::~FunctionSubstring()
{
}

/*
 * Get the value for the start index (C-style, not XPath).
 */
inline XalanDOMString::size_type
getStartIndex(double	theSecondArgValue)
{
	// We always subtract 1 for C-style index, since XPath indexes from 1.

	// Anything less than, or equal to 1 is 0.
	if (theSecondArgValue <= 1)
	{
		return 0;
	}
	else
	{
		return XalanDOMString::size_type(DoubleSupport::round(theSecondArgValue)) - 1;
	}
}

/*
 * Get the length of the substring.
 */
inline XalanDOMString::size_type
getSubstringLength(
			XalanDOMString::size_type	theSourceStringLength,
			XalanDOMString::size_type	theStartIndex,
			double						theThirdArgValue)
{
	// The last index must be less than theThirdArgValue.  Since it has
	// already been rounded, subtracting 1 will do the job.
	const XalanDOMString::size_type		theLastIndex = XalanDOMString::size_type(theThirdArgValue - 1);

	if (theLastIndex >= theSourceStringLength)
	{
		return theSourceStringLength - theStartIndex;
	}
	else
	{
		return theLastIndex - theStartIndex;
	}
}

/*
 * Get the total of the second and third arguments.
 */
inline double
getTotal(
			XalanDOMString::size_type	theSourceStringLength,
			double						theSecondArgValue,
			const XObjectPtr&			arg3)
{
	// Total the second and third arguments.  Ithe third argument is
	// missing, make it the length of the string + 1 (for XPath
	// indexing style).
	if (arg3.null() == true)
	{
		return double(theSourceStringLength + 1);
	}
	else
	{
		const double	theRoundedValue =
			DoubleSupport::round(theSecondArgValue + arg3->num());

		// If there's overflow, then we should return the length of the string + 1.
		if (DoubleSupport::isPositiveInfinity(theRoundedValue) == true)
		{
			return double(theSourceStringLength + 1);
		}
		else
		{
			return theRoundedValue;
		}
	}
}

static const XalanDOMString		theEmptyString;

inline XObjectPtr
createEmptyString(XPathExecutionContext&	executionContext)
{
	return executionContext.getXObjectFactory().createString(theEmptyString);
}

XObjectPtr
FunctionSubstring::execute(
			XPathExecutionContext&	executionContext,
			XalanNode*				context,
			const XObjectPtr		arg1,
			const XObjectPtr		arg2,
			const Locator*			locator) const
{
	assert(arg1.null() == false && arg2.null() == false);

	return execute(executionContext, context, arg1, arg2, s_nullXObjectPtr, locator);
}

XObjectPtr
FunctionSubstring::execute(
			XPathExecutionContext&	executionContext,
			XalanNode*				/* context */,
			const XObjectPtr		arg1,
			const XObjectPtr		arg2,
			const XObjectPtr		arg3,
			const Locator*			/* locator */) const
{
	assert(arg1.null() == false && arg2.null() == false);

	const XalanDOMString&				theSourceString = arg1->str();
	const XalanDOMString::size_type		theSourceStringLength = length(theSourceString);

	if (theSourceStringLength == 0)
	{
		return createEmptyString(executionContext);
	}
	else
	{
		// Get the value of the second argument...
		const double	theSecondArgValue =
			DoubleSupport::round(arg2->num());

		// XPath indexes from 1, so this is the first XPath index....
		const XalanDOMString::size_type		theStartIndex = getStartIndex(theSecondArgValue);

		if (theStartIndex >= theSourceStringLength)
		{
			return createEmptyString(executionContext);
		}
		else
		{
			const double	theTotal =
				getTotal(theSourceStringLength, theSecondArgValue, arg3);

			if (DoubleSupport::isNaN(theSecondArgValue) == true ||
				DoubleSupport::isNaN(theTotal) == true ||
				DoubleSupport::isNegativeInfinity(theTotal) == true ||
				theTotal < double(theStartIndex))
			{
				return createEmptyString(executionContext);
			}
			else
			{
				const XalanDOMString::size_type		theSubstringLength =
					getSubstringLength(
						theSourceStringLength,
						theStartIndex,
						theTotal);

				XPathExecutionContext::GetAndReleaseCachedString	theResult(executionContext);

				XalanDOMString&		theString = theResult.get();

				assign(
						theString,
						toCharArray(theSourceString) + theStartIndex,
						theSubstringLength);

				return executionContext.getXObjectFactory().createString(theResult);
			}
		}
	}
}

#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
Function*
#else
FunctionSubstring*
#endif
FunctionSubstring::clone() const
{
	return new FunctionSubstring(*this);
}

const XalanDOMString
FunctionSubstring::getError() const
{
	return StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("The substring() function takes two or three arguments!"));
}
<commit_msg>Fixed 64-bit HP problem.<commit_after>/*
 * The Apache Software License, Version 1.1
 *
 *
 * Copyright (c) 2000 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. 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.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Xalan" and "Apache Software Foundation" must
 *    not be used to endorse or promote products derived from this
 *    software without prior written permission. For written
 *    permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    nor may "Apache" appear in their name, without prior written
 *    permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation and was
 * originally based on software copyright (c) 1999, International
 * Business Machines, Inc., http://www.ibm.com.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */
#include "FunctionSubstring.hpp"

#include <PlatformSupport/DoubleSupport.hpp>

#include "XObjectFactory.hpp"

const XObjectPtr		FunctionSubstring::s_nullXObjectPtr;

FunctionSubstring::FunctionSubstring()
{
}

FunctionSubstring::~FunctionSubstring()
{
}

/*
 * Get the value for the start index (C-style, not XPath).
 */
inline XalanDOMString::size_type
getStartIndex(
			double						theSecondArgValue,
			XalanDOMString::size_type	theStringLength)
{
	// We always subtract 1 for C-style index, since XPath indexes from 1.

	// Anything less than, or equal to 1 is 0.
	if (theSecondArgValue <= 1 ||
		DoubleSupport::isNaN(theSecondArgValue) == true)
	{
		return 0;
	}
	else if (DoubleSupport::isPositiveInfinity(theSecondArgValue) == true)
	{
		return theStringLength;
	}
	else
	{
		return XalanDOMString::size_type(DoubleSupport::round(theSecondArgValue)) - 1;
	}
}

/*
 * Get the length of the substring.
 */
inline XalanDOMString::size_type
getSubstringLength(
			XalanDOMString::size_type	theSourceStringLength,
			XalanDOMString::size_type	theStartIndex,
			double						theThirdArgValue)
{
	// The last index must be less than theThirdArgValue.  Since it has
	// already been rounded, subtracting 1 will do the job.
	const XalanDOMString::size_type		theLastIndex = XalanDOMString::size_type(theThirdArgValue - 1);

	if (theLastIndex >= theSourceStringLength)
	{
		return theSourceStringLength - theStartIndex;
	}
	else
	{
		return theLastIndex - theStartIndex;
	}
}

/*
 * Get the total of the second and third arguments.
 */
inline double
getTotal(
			XalanDOMString::size_type	theSourceStringLength,
			double						theSecondArgValue,
			const XObjectPtr&			arg3)
{
	// Total the second and third arguments.  Ithe third argument is
	// missing, make it the length of the string + 1 (for XPath
	// indexing style).
	if (arg3.null() == true)
	{
		return double(theSourceStringLength + 1);
	}
	else
	{
		const double	theRoundedValue =
			DoubleSupport::round(theSecondArgValue + arg3->num());

		// If there's overflow, then we should return the length of the string + 1.
		if (DoubleSupport::isPositiveInfinity(theRoundedValue) == true)
		{
			return double(theSourceStringLength + 1);
		}
		else
		{
			return theRoundedValue;
		}
	}
}

static const XalanDOMString		theEmptyString;

inline XObjectPtr
createEmptyString(XPathExecutionContext&	executionContext)
{
	return executionContext.getXObjectFactory().createString(theEmptyString);
}

XObjectPtr
FunctionSubstring::execute(
			XPathExecutionContext&	executionContext,
			XalanNode*				context,
			const XObjectPtr		arg1,
			const XObjectPtr		arg2,
			const Locator*			locator) const
{
	assert(arg1.null() == false && arg2.null() == false);

	return execute(executionContext, context, arg1, arg2, s_nullXObjectPtr, locator);
}

XObjectPtr
FunctionSubstring::execute(
			XPathExecutionContext&	executionContext,
			XalanNode*				/* context */,
			const XObjectPtr		arg1,
			const XObjectPtr		arg2,
			const XObjectPtr		arg3,
			const Locator*			/* locator */) const
{
	assert(arg1.null() == false && arg2.null() == false);

	const XalanDOMString&				theSourceString = arg1->str();
	const XalanDOMString::size_type		theSourceStringLength = length(theSourceString);

	if (theSourceStringLength == 0)
	{
		return createEmptyString(executionContext);
	}
	else
	{
		// Get the value of the second argument...
		const double	theSecondArgValue =
			DoubleSupport::round(arg2->num());

		// XPath indexes from 1, so this is the first XPath index....
		const XalanDOMString::size_type		theStartIndex = getStartIndex(theSecondArgValue, theSourceStringLength);

		if (theStartIndex >= theSourceStringLength)
		{
			return createEmptyString(executionContext);
		}
		else
		{
			const double	theTotal =
				getTotal(theSourceStringLength, theSecondArgValue, arg3);

			if (DoubleSupport::isNaN(theSecondArgValue) == true ||
				DoubleSupport::isNaN(theTotal) == true ||
				DoubleSupport::isNegativeInfinity(theTotal) == true ||
				theTotal < double(theStartIndex))
			{
				return createEmptyString(executionContext);
			}
			else
			{
				const XalanDOMString::size_type		theSubstringLength =
					getSubstringLength(
						theSourceStringLength,
						theStartIndex,
						theTotal);

				XPathExecutionContext::GetAndReleaseCachedString	theResult(executionContext);

				XalanDOMString&		theString = theResult.get();

				assign(
						theString,
						toCharArray(theSourceString) + theStartIndex,
						theSubstringLength);

				return executionContext.getXObjectFactory().createString(theResult);
			}
		}
	}
}

#if defined(XALAN_NO_COVARIANT_RETURN_TYPE)
Function*
#else
FunctionSubstring*
#endif
FunctionSubstring::clone() const
{
	return new FunctionSubstring(*this);
}

const XalanDOMString
FunctionSubstring::getError() const
{
	return StaticStringToDOMString(XALAN_STATIC_UCODE_STRING("The substring() function takes two or three arguments!"));
}
<|endoftext|>


<commit_before>/**
 * @file 	ex6.cpp
 * @author 	Fabian Wegscheider
 * @date 	Jun 20, 2017
 */

#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#include <boost/heap/fibonacci_heap.hpp>
#include <boost/timer/timer.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/qi.hpp>

using namespace std;
using namespace boost;
namespace po = boost::program_options;

typedef adjacency_list<vecS, vecS, undirectedS,
		no_property, property<edge_weight_t, double>> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef pair<int,int> Edge;
typedef pair<int, double> Pair;
typename graph_traits<Graph>::out_edge_iterator out_i, out_end;

/*
 * Data that is stored in one node of a heap. Contains an integer and a double.
 * Comparisons are made by the double, smaller has higher priority
 */
struct heap_data
{
    heap::fibonacci_heap<heap_data>::handle_type handle;
    Pair pair;

    heap_data(Pair p):
        pair(p)
    {}

    bool operator<(heap_data const & rhs) const {
        return pair.second > rhs.pair.second;
    }
};

using Heap = heap::fibonacci_heap<heap_data>;

/**
 * My own implementation of Dijkstra using a fibonacci heap from boost
 * @param g the graph which is an adjacency_list from boost
 * @param numVertices the number of vertices in g
 * @param source the source node for Dijkstra
 * @return vector of resulting distances to source
 */
vector<double> myDijkstra(Graph g, int numVertices, int source) {

	vector<double> distances(numVertices);
	distances[0] = 0;

	Heap heap;

	Heap::handle_type *handles = new Heap::handle_type[numVertices];
	handles[0] = heap.push(make_pair(0,0.));

	//initialization of the heap
	for (int i = 1; i < numVertices; ++i) {
		handles[i] = heap.push(make_pair(i, numeric_limits<double>::infinity()));
		distances[i] = numeric_limits<double>::infinity();
	}

	property_map<Graph, edge_weight_t>::type weights = get(edge_weight, g);
	property_map<Graph, vertex_index_t>::type index = get(vertex_index, g);

	//the actual algorithm
	while (!heap.empty()) {
		Pair min = heap.top().pair;
		heap.pop();
		for (tie(out_i, out_end) = out_edges(*(vertices(g).first+min.first), g);
				out_i != out_end; ++out_i) {
			double tmp = min.second + weights[*out_i];
			int targetIndex = index[target(*out_i, g)];
			if (tmp < distances[targetIndex]) {
				distances[targetIndex] = tmp;
				(*handles[targetIndex]).pair.second = tmp;
				heap.increase(handles[targetIndex]);
			}
		}
	}

	return distances;
}
//		split(parts, line, is_any_of(" "));
//		if (parts.size() != 3) {
//			cerr << "error in line " << (i+2) << ": line should consists of "
//					"two integers and a double!" << endl;
//			exit(EXIT_FAILURE);
//		}

/**
 * main function which reads a graph from a .gph file, then calculates shortest
 * paths from all vertices to the first vertex with the dijsktra algorithm
 * and prints the furthest vertex together with its distance
 * to the standard output
 * @param numargs number of inputs on command line
 * @param args array of * inputs on command line
 * @return whether the function operated successfully
 */
int main(int numargs, char *args[]) {

	timer::cpu_timer t;
	bool useOwnMethod;

	/*parsing command line options*/
	po::options_description desc("Allowed options");
	desc.add_options()
			("help,h", "produce help message")
			("m1", "use my own dijkstra method")
			("m2", "use dijkstra method from boost")
			("input-file", po::value< string >(), "input file");
	po::positional_options_description p;
	p.add("input-file", -1);
	po::variables_map vm;
	po::store(po::command_line_parser(numargs, args).
			options(desc).positional(p).run(), vm);
	po::notify(vm);

	if (vm.count("help")) {
	    cout << desc << "\n";
	   	exit(EXIT_SUCCESS);
	}

	if (vm.count("m1") && !vm.count("m2")) {
		useOwnMethod = true;
		cout << "using my own method for calculation..." << endl << endl;
	} else if (vm.count("m2") && !vm.count("m1")) {
		useOwnMethod = false;
		cout << "using boost method for calculation..." << endl << endl;
	} else {
		cerr << "please specify the method you want to use (type -h for help)" << endl;
		exit(EXIT_FAILURE);
	}

	string input;
	if (vm.count("input-file")) {
	    input = vm["input-file"].as< string >();
	} else {
		cerr << "please specify an input file in the .gph format" << endl;
		exit(EXIT_FAILURE);
	}
	/*end of parsing command line options*/

	ifstream inputFile;
	inputFile.open(input);							//trying to read file
	if (inputFile.fail()) {
		cerr << "file could not be read" << endl;
		exit(EXIT_FAILURE);
	}

	int numVertices;
	int numEdges;

	string line;
	getline(inputFile, line);					//first line is read
	vector<string> parts;
	split(parts, line, is_any_of(" "));

	if (parts.size() != 2) {
		cerr << "error in file: first line should consist of two integers!" << endl;
		exit(EXIT_FAILURE);
	}

	try {
		numVertices = stoi(parts[0]);		//information from the first line
		numEdges = stoi(parts[1]);			//are stored
	} catch (...) {
		cerr << "error in file: first line should consist of two integers!" << endl;
		exit(EXIT_FAILURE);
	}

	Edge *edges =  new Edge[numEdges];			//in these arrays all information about
	double *weights = new double[numEdges];		//the edges are stored

	int i = 0;

	using namespace boost::spirit;
	using qi::int_;
	using qi::double_;
	using qi::phrase_parse;
	using ascii::space;

	//read line by line using boost to parse each line to int,int,double
	while (getline(inputFile, line)) {
		try {
			auto it = line.begin();
			int start;
			int end;
			double weight;
			bool success = phrase_parse(it, line.end(),
					int_[([&start](int j){ start = j; })]
					>> int_[([&end](int j){ end = j; })]
					>> double_[([&weight](double j){ weight = j; })], space);
			if (success && it == line.end()) {
				edges[i] = Edge(start-1, end-1);
				weights[i] = weight;
			} else {
				cerr << "error in line " << (i+2) << ": line should consists of "
						"two integers and a double!" << endl;
				exit(EXIT_FAILURE);
			}
		} catch(...) {
			cerr << "error in line " << (i+2) << ": line should consists of "
					"two integers and a double!" << endl;
			exit(EXIT_FAILURE);
		}
		++i;
	}

	//undirected graph is constructed with all edges and their weights
	Graph g(edges, edges + numEdges , weights, numVertices);

	//in this vector the resulting distances from dijkstra are stored
	vector<double> distances;

	//call of dijsktra depending on chosen option
	if (!useOwnMethod) {
		distances.resize(numVertices);
		dijkstra_shortest_paths(g, *(vertices(g).first), distance_map(&distances[0]));
	} else {
		distances = myDijkstra(g, numVertices, 0);
	}

	double maxDist = 0;
	int maxIdx = 0;

	//search for furthest vertex
	for (int i = 1; i < numVertices; i++) {
		double tmp = distances[i];
			if (tmp > maxDist) {
				maxDist = tmp;
				maxIdx = i;
			}
	}

	//results are printed to command line
	cout << "RESULT VERTEX " << (maxIdx+1) << endl;
	cout << "RESULT DIST " << maxDist << endl;
	cout << endl << "running time: " << t.format() <<  endl;

	exit(EXIT_SUCCESS);
}

<commit_msg>fixed another bug<commit_after>/**
 * @file 	ex6.cpp
 * @author 	Fabian Wegscheider
 * @date 	Jun 20, 2017
 */

#include <iostream>
#include <fstream>
#include <boost/program_options.hpp>
#include <boost/heap/fibonacci_heap.hpp>
#include <boost/timer/timer.hpp>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/graph_traits.hpp>
#include <boost/graph/dijkstra_shortest_paths.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/spirit/include/qi.hpp>

using namespace std;
using namespace boost;
namespace po = boost::program_options;

typedef adjacency_list<vecS, vecS, undirectedS,
		no_property, property<edge_weight_t, double>> Graph;
typedef graph_traits<Graph>::vertex_descriptor Vertex;
typedef pair<int,int> Edge;
typedef pair<int, double> Pair;
typename graph_traits<Graph>::out_edge_iterator out_i, out_end;

/**
 * Data that is stored in one node of a heap. Contains an integer and a double.
 * Comparisons are made by the double, smaller has higher priority
 */
struct heap_data
{
    heap::fibonacci_heap<heap_data>::handle_type handle;
    Pair pair;

    heap_data(Pair p):
        pair(p)
    {}

    bool operator<(heap_data const & rhs) const {
        return pair.second > rhs.pair.second;
    }
};

using Heap = heap::fibonacci_heap<heap_data>;

/**
 * My own implementation of Dijkstra using a fibonacci heap from boost
 * @param g the graph which is an adjacency_list from boost
 * @param numVertices the number of vertices in g
 * @param source the source node for Dijkstra
 * @return vector of resulting distances to source
 */
vector<double> myDijkstra(Graph g, int numVertices, int source) {

	vector<double> distances(numVertices);
	distances[0] = 0;

	Heap heap;

	Heap::handle_type *handles = new Heap::handle_type[numVertices];
	handles[0] = heap.push(make_pair(0,0.));

	//initialization of the heap
	for (int i = 1; i < numVertices; ++i) {
		handles[i] = heap.push(make_pair(i, numeric_limits<double>::infinity()));
		distances[i] = numeric_limits<double>::infinity();
	}

	property_map<Graph, edge_weight_t>::type weights = get(edge_weight, g);
	property_map<Graph, vertex_index_t>::type index = get(vertex_index, g);

	//the actual algorithm
	while (!heap.empty()) {
		Pair min = heap.top().pair;
		heap.pop();
		for (tie(out_i, out_end) = out_edges(*(vertices(g).first+min.first), g);
				out_i != out_end; ++out_i) {
			double tmp = min.second + weights[*out_i];
			int targetIndex = index[target(*out_i, g)];
			if (tmp < distances[targetIndex]) {
				distances[targetIndex] = tmp;
				(*handles[targetIndex]).pair.second = tmp;
				heap.increase(handles[targetIndex]);
			}
		}
	}

	delete[] handles;
	return distances;
}

/**
 * main function which reads a graph from a .gph file, then calculates shortest
 * paths from all vertices to the first vertex with the dijsktra algorithm
 * and prints the furthest vertex together with its distance
 * to the standard output
 * @param numargs number of inputs on command line
 * @param args array of * inputs on command line
 * @return whether the function operated successfully
 */
int main(int numargs, char *args[]) {

	timer::cpu_timer t;
	bool useOwnMethod;

	/*parsing command line options*/
	po::options_description desc("Allowed options");
	desc.add_options()
			("help,h", "produce help message")
			("m1", "use my own dijkstra method")
			("m2", "use dijkstra method from boost")
			("input-file", po::value< string >(), "input file");
	po::positional_options_description p;
	p.add("input-file", -1);
	po::variables_map vm;
	po::store(po::command_line_parser(numargs, args).
			options(desc).positional(p).run(), vm);
	po::notify(vm);

	if (vm.count("help")) {
	    cout << desc << "\n";
	   	exit(EXIT_SUCCESS);
	}

	if (vm.count("m1") && !vm.count("m2")) {
		useOwnMethod = true;
		cout << "using my own method for calculation..." << endl << endl;
	} else if (vm.count("m2") && !vm.count("m1")) {
		useOwnMethod = false;
		cout << "using boost method for calculation..." << endl << endl;
	} else {
		cerr << "please specify the method you want to use (type -h for help)" << endl;
		exit(EXIT_FAILURE);
	}

	string input;
	if (vm.count("input-file")) {
	    input = vm["input-file"].as< string >();
	} else {
		cerr << "please specify an input file in the .gph format" << endl;
		exit(EXIT_FAILURE);
	}
	/*end of parsing command line options*/

	ifstream inputFile;
	inputFile.open(input);							//trying to read file
	if (inputFile.fail()) {
		cerr << "file could not be read" << endl;
		exit(EXIT_FAILURE);
	}

	int numVertices;
	int numEdges;

	string line;
	getline(inputFile, line);					//first line is read
	vector<string> parts;
	split(parts, line, is_any_of(" "));

	if (parts.size() != 2) {
		cerr << "error in file: first line should consist of two integers!" << endl;
		exit(EXIT_FAILURE);
	}

	try {
		numVertices = stoi(parts[0]);		//information from the first line
		numEdges = stoi(parts[1]);			//are stored
	} catch (...) {
		cerr << "error in file: first line should consist of two integers!" << endl;
		exit(EXIT_FAILURE);
	}

	Edge *edges =  new Edge[numEdges];			//in these arrays all information about
	double *weights = new double[numEdges];		//the edges are stored

	int i = 0;

	using namespace boost::spirit;
	using qi::int_;
	using qi::double_;
	using qi::phrase_parse;
	using ascii::space;

	//read line by line using boost to parse each line to int,int,double
	while (getline(inputFile, line)) {
		try {
			auto it = line.begin();
			int start;
			int end;
			double weight;
			bool success = phrase_parse(it, line.end(),
					int_[([&start](int j){ start = j; })]
					>> int_[([&end](int j){ end = j; })]
					>> double_[([&weight](double j){ weight = j; })], space);
			if (success && it == line.end()) {
				edges[i] = Edge(start-1, end-1);
				weights[i] = weight;
			} else {
				cerr << "error in line " << (i+2) << ": line should consists of "
						"two integers and a double!" << endl;
				exit(EXIT_FAILURE);
			}
		} catch(...) {
			cerr << "error in line " << (i+2) << ": line should consists of "
					"two integers and a double!" << endl;
			exit(EXIT_FAILURE);
		}
		++i;
	}

	//undirected graph is constructed with all edges and their weights
	Graph g(edges, edges + numEdges , weights, numVertices);

	//in this vector the resulting distances from dijkstra are stored
	vector<double> distances;

	//call of dijsktra depending on chosen option
	if (!useOwnMethod) {
		distances.resize(numVertices);
		dijkstra_shortest_paths(g, *(vertices(g).first), distance_map(&distances[0]));
	} else {
		distances = myDijkstra(g, numVertices, 0);
	}

	double maxDist = 0;
	int maxIdx = 0;

	//search for furthest vertex
	for (int i = 1; i < numVertices; i++) {
		double tmp = distances[i];
			if (tmp > maxDist) {
				maxDist = tmp;
				maxIdx = i;
			}
	}

	//results are printed to command line
	cout << "RESULT VERTEX " << (maxIdx+1) << endl;
	cout << "RESULT DIST " << maxDist << endl;
	cout << endl << "running time: " << t.format() <<  endl;

	delete[] edges;
	delete[] weights;

	exit(EXIT_SUCCESS);
}

<|endoftext|>


<commit_before>#include "application.h"
#include <inttypes.h>

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);
SerialLogHandler traceLog(LOG_LEVEL_TRACE);

static TCPServer tcpServer = TCPServer(6666);
static TCPClient tcpClient;

// Toggle LED pin to see that application loop is not blocked.
// You could use D7 when testing with a Photon.
// I'm using another pin here, because D7 is one of the SWD pins used by the debugger
const int LED_PIN = P1S0;

enum tcp_state_enum {
    RUNNING_FINE,
    OH_NO_ITS_BORKED_PARTICLE,
    STOPPED,
    ALLOWED_TO_RESTART,
};

volatile uint8_t tcp_state;

void stopTcp(){
    tcpServer.stop();
    tcpClient.stop();
    Serial.print("TCP server stopped\n");
}

void startTcp(){
    tcpServer.begin();
    Serial.print("TCP server started\n");
}

void handle_network_events(system_event_t event, int param){
    switch(param){
    case network_status_powering_on:
        break;
    case network_status_on:
        break;
    case network_status_powering_off:
        break;
    case network_status_off:
        break;
    case network_status_connecting:
        // set a flag to restart the TCP server, outside of the system thread
        // restarting it here doesn't work
        // leaving it running doesn't work
        SINGLE_THREADED_BLOCK(){
            tcp_state = tcp_state_enum::OH_NO_ITS_BORKED_PARTICLE;
        }
        break;
    case network_status_connected:
        SINGLE_THREADED_BLOCK(){
            tcp_state = tcp_state_enum::ALLOWED_TO_RESTART;
        }
        break;
    default:
        break;
    }
}

void handle_cloud_events(system_event_t event, int param){
    switch(param){
    case cloud_status_connecting:
        break;
    case cloud_status_connected:
        break;
    case cloud_status_disconnecting:
        break;
    case cloud_status_disconnected:
        break;
    default:
        break;
    }
}

void setup() {
    Serial.begin(115200);
    pinMode(LED_PIN, OUTPUT);

    WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);

    System.on(network_status, handle_network_events);
    System.on(cloud_status, handle_cloud_events);
    tcp_state = tcp_state_enum::ALLOWED_TO_RESTART;
}

void loop() {
    static uint32_t last_update = millis();
    static uint32_t lastLedToggle = millis();

    switch(tcp_state){
        case tcp_state_enum::RUNNING_FINE:
            break;
        case tcp_state_enum::OH_NO_ITS_BORKED_PARTICLE:
            Serial.print("Stopping TCP\n");
            SINGLE_THREADED_BLOCK(){
                tcp_state = tcp_state_enum::STOPPED;
            }
            stopTcp();
            break;
        case tcp_state_enum::ALLOWED_TO_RESTART:
            Serial.print("Restarting TCP\n");
            startTcp();
            SINGLE_THREADED_BLOCK(){
                tcp_state = tcp_state_enum::RUNNING_FINE; // assume it is running fine afterwards
            }
            break;

    }

    if(tcp_state == tcp_state_enum::RUNNING_FINE){
        if(tcpClient.status()){
            while (tcpClient.available() > 0) {
                char inByte = tcpClient.read();
                switch(inByte){
                case ' ':
                case '\n':
                case '\r':
                    break;
                case 't':
                    size_t result = tcpClient.write("toc"); // send toc back over tcp
                    Serial.printf("hw->py: toc (%d bytes sent) \n", result); // confirm toc sent over tcp
                }
                Serial.printf("py->hw: %c\n", inByte); // confirm character received from tcp
            }
        }
        else{
            tcpClient.stop();
            // listen for a new client
            TCPClient newClient = tcpServer.available();
            if(newClient) {
               Serial.print("New TCP client\n");
               tcpClient.stop();
               tcpClient = newClient;
            }
        }
    }

    // print status on serial every second
    if ( millis() - last_update > 1000UL ) {
        last_update = millis();
        bool wifiReady = WiFi.ready();
        IPAddress ip = WiFi.localIP();
        int signal = WiFi.RSSI();
        int clientConnected = tcpClient.connected();
        Serial.printf(
                "WiFi.ready(): %d\t\t"
                "IP: %d.%d.%d.%d\t\t"
                "RSSI: %d\t\t"
                "TCP client connected: %d\t\t"
                "millis(): %" PRIu32 "\n",
                wifiReady,
                ip[0],ip[1],ip[2],ip[3],
                signal,
                clientConnected,
                last_update);

        /* When the signal gets below -80, the P1 will stop responding to TCP.
         * - It still has an IP
         * - It still has WiFi.ready() returning 1.
         * - The LED is still breathing green.
         *
         * There is one symptom that something is wrong though:
         * When TCP stopped working, the P1 would return RSSI 2.
         *
         * This seems to be a failed to get RSSI timeout:
         *
            int8_t WiFiClass::RSSI() {
                if (!network_ready(*this, 0, NULL))
                    return 0;

                system_tick_t _functionStart = millis();
                while ((millis() - _functionStart) < 1000) {
                    int rv = wlan_connected_rssi();
                    if (rv != 0)
                        return (rv);
                }
                return (2);
            }
         *
         * In an attempt to fix this, I tried disconnecting and reconnecting WiFi.
         * But WiFi.disconnect() gives a stack overflow SOS (13 blinks).
         */

        if(signal == 2){
            Serial.print("WiFi is in ERROR state. Resetting WiFi");
            WiFi.disconnect();
            WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
        }
    }

    if ( millis() - lastLedToggle > 200UL ) {
        static bool ledOn = true;
        ledOn = !ledOn;
        digitalWrite(LED_PIN, ledOn);
        lastLedToggle = millis();
    }
}
<commit_msg>Only go to 'borked' state when not in stopped state in wifi test app<commit_after>#include "application.h"
#include <inttypes.h>

SYSTEM_MODE(MANUAL);
SYSTEM_THREAD(ENABLED);
SerialLogHandler traceLog(LOG_LEVEL_TRACE);

static TCPServer tcpServer = TCPServer(6666);
static TCPClient tcpClient;

// Toggle LED pin to see that application loop is not blocked.
// You could use D7 when testing with a Photon.
// I'm using another pin here, because D7 is one of the SWD pins used by the debugger
const int LED_PIN = P1S0;

enum tcp_state_enum {
    RUNNING_FINE,
    OH_NO_ITS_BORKED_PARTICLE,
    STOPPED,
    ALLOWED_TO_RESTART,
};

volatile uint8_t tcp_state;

void stopTcp(){
    tcpServer.stop();
    tcpClient.stop();
    Serial.print("TCP server stopped\n");
}

void startTcp(){
    tcpServer.begin();
    Serial.print("TCP server started\n");
}

void handle_network_events(system_event_t event, int param){
    switch(param){
    case network_status_powering_on:
        break;
    case network_status_on:
        break;
    case network_status_powering_off:
        break;
    case network_status_off:
        break;
    case network_status_connecting:
        // set a flag to restart the TCP server, outside of the system thread
        // restarting it here doesn't work
        // leaving it running doesn't work
        if(tcp_state != tcp_state_enum::STOPPED){
            tcp_state = tcp_state_enum::OH_NO_ITS_BORKED_PARTICLE;
        }
        break;
    case network_status_connected:
        tcp_state = tcp_state_enum::ALLOWED_TO_RESTART;
        break;
    default:
        break;
    }
}

void handle_cloud_events(system_event_t event, int param){
    switch(param){
    case cloud_status_connecting:
        break;
    case cloud_status_connected:
        break;
    case cloud_status_disconnecting:
        break;
    case cloud_status_disconnected:
        break;
    default:
        break;
    }
}

void setup() {
    Serial.begin(115200);
    pinMode(LED_PIN, OUTPUT);

    WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);

    System.on(network_status, handle_network_events);
    System.on(cloud_status, handle_cloud_events);
    tcp_state = tcp_state_enum::ALLOWED_TO_RESTART;
}

void loop() {
    static uint32_t last_update = millis();
    static uint32_t lastLedToggle = millis();

    switch(tcp_state){
        case tcp_state_enum::RUNNING_FINE:
            break;
        case tcp_state_enum::OH_NO_ITS_BORKED_PARTICLE:
            Serial.print("Stopping TCP\n");
            stopTcp();
            tcp_state = tcp_state_enum::STOPPED;
            break;
        case tcp_state_enum::STOPPED:
            break;
        case tcp_state_enum::ALLOWED_TO_RESTART:
            Serial.print("Restarting TCP\n");
            startTcp();
            tcp_state = tcp_state_enum::RUNNING_FINE; // assume it is running fine afterwards
            break;

    }

    if(tcp_state == tcp_state_enum::RUNNING_FINE){
        if(tcpClient.status()){
            while (tcpClient.available() > 0) {
                char inByte = tcpClient.read();
                switch(inByte){
                case ' ':
                case '\n':
                case '\r':
                    break;
                case 't':
                    size_t result = tcpClient.write("toc"); // send toc back over tcp
                    Serial.printf("hw->py: toc (%d bytes sent) \n", result); // confirm toc sent over tcp
                }
                Serial.printf("py->hw: %c\n", inByte); // confirm character received from tcp
            }
        }
        else{
            tcpClient.stop();
            // listen for a new client
            TCPClient newClient = tcpServer.available();
            if(newClient) {
               Serial.print("New TCP client\n");
               tcpClient.stop();
               tcpClient = newClient;
            }
        }
    }

    // print status on serial every second
    if ( millis() - last_update > 1000UL ) {
        last_update = millis();
        bool wifiReady = WiFi.ready();
        IPAddress ip = WiFi.localIP();
        int signal = WiFi.RSSI();
        int clientConnected = tcpClient.connected();
        Serial.printf(
                "WiFi.ready(): %d\t\t"
                "IP: %d.%d.%d.%d\t\t"
                "RSSI: %d\t\t"
                "TCP client connected: %d\t\t"
                "millis(): %" PRIu32 "\n",
                wifiReady,
                ip[0],ip[1],ip[2],ip[3],
                signal,
                clientConnected,
                last_update);

        /* When the signal gets below -80, the P1 will stop responding to TCP.
         * - It still has an IP
         * - It still has WiFi.ready() returning 1.
         * - The LED is still breathing green.
         *
         * There is one symptom that something is wrong though:
         * When TCP stopped working, the P1 would return RSSI 2.
         *
         * This seems to be a failed to get RSSI timeout:
         *
            int8_t WiFiClass::RSSI() {
                if (!network_ready(*this, 0, NULL))
                    return 0;

                system_tick_t _functionStart = millis();
                while ((millis() - _functionStart) < 1000) {
                    int rv = wlan_connected_rssi();
                    if (rv != 0)
                        return (rv);
                }
                return (2);
            }
         *
         * In an attempt to fix this, I tried disconnecting and reconnecting WiFi.
         * But WiFi.disconnect() gives a stack overflow SOS (13 blinks).
         */

        if(signal == 2){
            Serial.print("\n\n\nWiFi is in ERROR state. Resetting WiFi\n\n\n");
            WiFi.disconnect();
            WiFi.connect(WIFI_CONNECT_SKIP_LISTEN);
        }
    }

    if ( millis() - lastLedToggle > 200UL ) {
        static bool ledOn = true;
        ledOn = !ledOn;
        digitalWrite(LED_PIN, ledOn);
        lastLedToggle = millis();
    }
}
<|endoftext|>


<commit_before>#include <Graphics.h>
#include <Surface.h>
#include "Render.h"

namespace nme
{

static bool IsPOW2(int inX)
{
   return (inX & (inX-1)) == 0;
}

enum { EDGE_CLAMP, EDGE_REPEAT, EDGE_POW2 };

#define GET_PIXEL_POINTERS \
         int frac_x = (mPos.x & 0xff00) >> 8; \
         int frac_nx = 0x100 - frac_x; \
         int frac_y = (mPos.y & 0xffff); \
         int frac_ny = 0x10000 - frac_y; \
 \
            if (EDGE == EDGE_CLAMP) \
            { \
               int x_step = 4; \
               int y_step = mStride; \
 \
               if (x<0) {  x_step = x = 0; } \
               else if (x>=mW1) { x_step = 0; x = mW1; } \
 \
               if (y<0) {  y_step = y = 0; } \
               else if (y>=mH1) { y_step = 0; y = mH1; } \
 \
               const uint8 * ptr = mBase + y*mStride + x*4; \
               p00 = *(ARGB *)ptr; \
               p01 = *(ARGB *)(ptr + x_step); \
               p10 = *(ARGB *)(ptr + y_step); \
               p11 = *(ARGB *)(ptr + y_step + x_step); \
            } \
            else if (EDGE==EDGE_POW2) \
            { \
               const uint8 *p = mBase + (y&mH1)*mStride; \
 \
               p00 = *(ARGB *)(p+ (x & mW1)*4); \
               p01 = *(ARGB *)(p+ ((x+1) & mW1)*4); \
 \
               p = mBase + ( (y+1) &mH1)*mStride; \
               p10 = *(ARGB *)(p+ (x & mW1)*4); \
               p11 = *(ARGB *)(p+ ((x+1) & mW1)*4); \
            } \
            else \
            { \
               int x1 = ((x+1) % mWidth) * 4; \
               if (x1<0) x1+=mWidth; \
               x = (x % mWidth)*4; \
               if (x<0) x+=mWidth; \
 \
               int y0= (y%mHeight); if (y0<0) y0+=mHeight; \
               const uint8 *p = mBase + y0*mStride; \
 \
               p00 = *(ARGB *)(p+ x); \
               p01 = *(ARGB *)(p+ x1); \
\
               int y1= ((y+1)%mHeight); if (y1<0) y1+=mHeight; \
               p = mBase + y1*mStride; \
               p10 = *(ARGB *)(p+ x); \
               p11 = *(ARGB *)(p+ x1); \
            }

#define MODIFY_EDGE_XY \
         if (EDGE == EDGE_CLAMP) \
         { \
            if (x<0) x = 0; \
            else if (x>=mWidth) x = mW1; \
 \
            if (y<0) y = 0; \
            else if (y>=mHeight) y = mH1; \
         } \
         else if (EDGE == EDGE_POW2) \
         { \
            x &= mW1; \
            y &= mH1; \
         } \
         else if (EDGE == EDGE_REPEAT) \
         { \
            x = x % mWidth; if (x<0) x+=mWidth;\
            y = y % mHeight; if (y<0) y+=mHeight;\
         }

class BitmapFillerBase : public Filler
{
public:
   BitmapFillerBase(GraphicsBitmapFill *inFill) : mBitmap(inFill)
   {
      mWidth = mBitmap->bitmapData->Width();
      mHeight = mBitmap->bitmapData->Height();
      mW1 = mWidth-1;
      mH1 = mHeight-1;
      mBase = mBitmap->bitmapData->GetBase();
      mStride = mBitmap->bitmapData->GetStride();
      mMapped = false;
   }

   inline void SetPos(int inSX,int inSY)
   {
      mPos.x = (int)( (mMapper.m00*inSX + mMapper.m01*inSY + mMapper.mtx) * (1<<16) + 0.5);
      mPos.y = (int)( (mMapper.m10*inSX + mMapper.m11*inSY + mMapper.mty) * (1<<16) + 0.5);
   }

   void SetupMatrix(const Matrix &inMatrix)
   {
      if (mMapped) return;

      // Get combined mapping matrix...
      Matrix mapper = inMatrix;
      mapper = mapper.Mult(mBitmap->matrix);
      mMapper = mapper.Inverse();
      //mMapper.Scale(mWidth/1638.4,mHeight/1638.4);
      mMapper.Translate(0.5,0.5);

      mDPxDX = (int)(mMapper.m00 * (1<<16)+ 0.5);
      mDPyDX = (int)(mMapper.m10 * (1<<16)+ 0.5);
   }

   void SetMapping(const UserPoint *inVertex, const float *inUVT,int inComponents)
   {
      mMapped = true;
      double w = mBitmap->bitmapData->Width();
      double h = mBitmap->bitmapData->Height();
      // Solve tx = f(x,y),  ty = f(x,y)
      double dx1 = inVertex[1].x-inVertex[0].x;
      double dy1 = inVertex[1].y-inVertex[0].y;
      double dx2 = inVertex[2].x-inVertex[0].x;
      double dy2 = inVertex[2].y-inVertex[0].y;
      double du1 = (inUVT[inComponents  ] - inUVT[0])*w;
      double du2 = (inUVT[inComponents*2] - inUVT[0])*w;
      double dv1 = (inUVT[inComponents  +1] - inUVT[1])*h;
      double dv2 = (inUVT[inComponents*2+1] - inUVT[1])*h;
      double dw1 = inComponents==3 ? inUVT[inComponents+2]-inUVT[2] : 0;
      double dw2 = inComponents==3 ? inUVT[inComponents*2+2]-inUVT[2] : 0;
      // u = a*x + b*y + c
      //   u0 = a*v0.x + b*v0.y + c
      //   u1 = a*v1.x + b*v1.y + c
      //   u2 = a*v2.x + b*v2.y + c
      //
      //   (u1-u0) = a*(v1.x-v0.x) + b*(v1.y-v0.y) = du1 = a*dx1 + b*dy1
      //   (u2-u0) = a*(v2.x-v0.x) + b*(v2.y-v0.y) = du2 = a*dx2 + b*dy2
      //
      //   du1*dy2 - du2*dy1= a*(dx1*dy2 - dx2*dy1)
      double det = dx1*dy2 - dx2*dy1;
      if (det==0)
      {
         // TODO: x-only or y-only
         mMapper = Matrix(0,0,inUVT[0],inUVT[1]);
         mWX = mWY = 0;
         mWC = 1;
      }
      else
      {
         det = 1.0/det;

         double a = mMapper.m00 = (du1*dy2 - du2*dy1)*det;
         double b = mMapper.m01 = dy1!=0 ? (du1-a*dx1)/dy1 : dy2!=0 ? (du1-a*dx2)/dy2 : 0;
         mMapper.mtx = inUVT[0]*w - a*inVertex[0].x - b*inVertex[0].y;

         a = mMapper.m10 = (dv1*dy2 - dv2*dy1)*det;
         b = mMapper.m11 = dy1!=0 ? (dv1-a*dx1)/dy1 : dy2!=0 ? (dv1-a*dx2)/dy2 : 0;
         mMapper.mty = inUVT[1]*h - a*inVertex[0].x - b*inVertex[0].y;

         if (mPerspective)
         {
            mWX = (dv1*dy2 - dv2*dy1)*det;
         }
      }

      mMapper.Translate(0.5,0.5);

      mDPxDX = (int)(mMapper.m00 * (1<<16)+ 0.5);
      mDPyDX = (int)(mMapper.m10 * (1<<16)+ 0.5);

   }

   const uint8 *mBase;
   int  mStride;

   ImagePoint mPos;
   int mDPxDX;
   int mDPyDX;
   int mWidth;
   int mHeight;
   int mW1;
   int mH1;
   bool mMapped;
   double mWX, mWY, mWZ;
   double mTX, mTY, mTZ;
   Matrix mMapper;
   GraphicsBitmapFill *mBitmap;
};

template<int EDGE,bool SMOOTH,bool HAS_ALPHA,bool PERSP>
class BitmapFiller : public BitmapFillerBase
{
public:
   enum { HasAlpha = HAS_ALPHA };

   BitmapFiller(GraphicsBitmapFill *inFill) : BitmapFillerBase(inFill) { }

   ARGB GetInc( )
   {
      int x = mPos.x >> 16;
      int y = mPos.y >> 16;
      if (SMOOTH)
      {
         ARGB result;

         ARGB p00,p01,p10,p11;

         GET_PIXEL_POINTERS

         mPos.x += mDPxDX;
         mPos.y += mDPyDX;

         result.c0 = ( (p00.c0*frac_nx + p01.c0*frac_x)*frac_ny +
                    (  p10.c0*frac_nx + p11.c0*frac_x)*frac_y ) >> 24;
         result.c1 = ( (p00.c1*frac_nx + p01.c1*frac_x)*frac_ny +
                    (  p10.c1*frac_nx + p11.c1*frac_x)*frac_y ) >> 24;
         result.c2 = ( (p00.c2*frac_nx + p01.c2*frac_x)*frac_ny +
                    (  p10.c2*frac_nx + p11.c2*frac_x)*frac_y ) >> 24;

         if (HAS_ALPHA)
         {
            result.a = ( (p00.a*frac_nx + p01.a*frac_x)*frac_ny +
                         (p10.a*frac_nx + p11.a*frac_x)*frac_y ) >> 24;
         }
         else
            result.a = 255;
         return result;
      }
      else
      {
         mPos.x += mDPxDX;
         mPos.y += mDPyDX;
         MODIFY_EDGE_XY;
         return *(ARGB *)( mBase + y*mStride + x*4);
      }
   }

   void Fill(const AlphaMask &mAlphaMask,int inTX,int inTY,
       const RenderTarget &inTarget,const RenderState &inState)
   {
      SetupMatrix(*inState.mTransform.mMatrix);

      bool swap =  (inTarget.mPixelFormat & pfSwapRB) != (mBitmap->bitmapData->Format() & pfSwapRB);
      Render( mAlphaMask, *this, inTarget, swap, inState, inTX,inTY );
   }

};

// --- Pseudo constructor ---------------------------------------------------------------

template<int EDGE,bool SMOOTH,bool PERSP>
static Filler *CreateAlpha(GraphicsBitmapFill *inFill)
{
   if (inFill->bitmapData->Format() & pfHasAlpha)
      return new BitmapFiller<EDGE,SMOOTH,PERSP,true>(inFill);
   else
      return new BitmapFiller<EDGE,SMOOTH,PERSP,false>(inFill);
}

template<int EDGE,bool SMOOTH>
static Filler *CreatePerspective(GraphicsBitmapFill *inFill,bool inPerspective)
{
   if (inPerspective)
      return CreateAlpha<EDGE,SMOOTH,true>(inFill);
   else
      return CreateAlpha<EDGE,SMOOTH,false>(inFill);

}

template<int EDGE>
static Filler *CreateSmooth(GraphicsBitmapFill *inFill,bool inPerspective)
{
   if (inFill->smooth)
      return CreatePerspective<EDGE,true>(inFill,inPerspective);
   else
      return CreatePerspective<EDGE,false>(inFill,inPerspective);
}

Filler *Filler::Create(GraphicsBitmapFill *inFill,bool inPerspective)
{
   if (inFill->repeat)
   {
      if ( IsPOW2(inFill->bitmapData->Width()) && IsPOW2(inFill->bitmapData->Height()) )
         return CreateSmooth<EDGE_POW2>(inFill,inPerspective);
      else
         return CreateSmooth<EDGE_REPEAT>(inFill,inPerspective);
   }
   else
      return CreateSmooth<EDGE_CLAMP>(inFill,inPerspective);
}

} // end namespace nme

<commit_msg>Fix perspective mapping<commit_after>#include <Graphics.h>
#include <Surface.h>
#include "Render.h"

namespace nme
{

static bool IsPOW2(int inX)
{
   return (inX & (inX-1)) == 0;
}

enum { EDGE_CLAMP, EDGE_REPEAT, EDGE_POW2 };

#define GET_PIXEL_POINTERS \
         int frac_x = (mPos.x & 0xff00) >> 8; \
         int frac_nx = 0x100 - frac_x; \
         int frac_y = (mPos.y & 0xffff); \
         int frac_ny = 0x10000 - frac_y; \
 \
            if (EDGE == EDGE_CLAMP) \
            { \
               int x_step = 4; \
               int y_step = mStride; \
 \
               if (x<0) {  x_step = x = 0; } \
               else if (x>=mW1) { x_step = 0; x = mW1; } \
 \
               if (y<0) {  y_step = y = 0; } \
               else if (y>=mH1) { y_step = 0; y = mH1; } \
 \
               const uint8 * ptr = mBase + y*mStride + x*4; \
               p00 = *(ARGB *)ptr; \
               p01 = *(ARGB *)(ptr + x_step); \
               p10 = *(ARGB *)(ptr + y_step); \
               p11 = *(ARGB *)(ptr + y_step + x_step); \
            } \
            else if (EDGE==EDGE_POW2) \
            { \
               const uint8 *p = mBase + (y&mH1)*mStride; \
 \
               p00 = *(ARGB *)(p+ (x & mW1)*4); \
               p01 = *(ARGB *)(p+ ((x+1) & mW1)*4); \
 \
               p = mBase + ( (y+1) &mH1)*mStride; \
               p10 = *(ARGB *)(p+ (x & mW1)*4); \
               p11 = *(ARGB *)(p+ ((x+1) & mW1)*4); \
            } \
            else \
            { \
               int x1 = ((x+1) % mWidth) * 4; \
               if (x1<0) x1+=mWidth; \
               x = (x % mWidth)*4; \
               if (x<0) x+=mWidth; \
 \
               int y0= (y%mHeight); if (y0<0) y0+=mHeight; \
               const uint8 *p = mBase + y0*mStride; \
 \
               p00 = *(ARGB *)(p+ x); \
               p01 = *(ARGB *)(p+ x1); \
\
               int y1= ((y+1)%mHeight); if (y1<0) y1+=mHeight; \
               p = mBase + y1*mStride; \
               p10 = *(ARGB *)(p+ x); \
               p11 = *(ARGB *)(p+ x1); \
            }

#define MODIFY_EDGE_XY \
         if (EDGE == EDGE_CLAMP) \
         { \
            if (x<0) x = 0; \
            else if (x>=mWidth) x = mW1; \
 \
            if (y<0) y = 0; \
            else if (y>=mHeight) y = mH1; \
         } \
         else if (EDGE == EDGE_POW2) \
         { \
            x &= mW1; \
            y &= mH1; \
         } \
         else if (EDGE == EDGE_REPEAT) \
         { \
            x = x % mWidth; if (x<0) x+=mWidth;\
            y = y % mHeight; if (y<0) y+=mHeight;\
         }

class BitmapFillerBase : public Filler
{
public:
   BitmapFillerBase(GraphicsBitmapFill *inFill) : mBitmap(inFill)
   {
      mWidth = mBitmap->bitmapData->Width();
      mHeight = mBitmap->bitmapData->Height();
      mW1 = mWidth-1;
      mH1 = mHeight-1;
      mBase = mBitmap->bitmapData->GetBase();
      mStride = mBitmap->bitmapData->GetStride();
      mMapped = false;
		mPerspective = false;
   }

   void SetupMatrix(const Matrix &inMatrix)
   {
      if (mMapped) return;

      // Get combined mapping matrix...
      Matrix mapper = inMatrix;
      mapper = mapper.Mult(mBitmap->matrix);
      mMapper = mapper.Inverse();
      //mMapper.Scale(mWidth/1638.4,mHeight/1638.4);
      mMapper.Translate(0.5,0.5);

      mDPxDX = (int)(mMapper.m00 * (1<<16)+ 0.5);
      mDPyDX = (int)(mMapper.m10 * (1<<16)+ 0.5);
   }

   void SetMapping(const UserPoint *inVertex, const float *inUVT,int inComponents)
   {
      mMapped = true;
      double w = mBitmap->bitmapData->Width();
      double h = mBitmap->bitmapData->Height();
      // Solve tx = f(x,y),  ty = f(x,y)
      double dx1;
      double dy1;
      double dx2;
      double dy2;
      double du1;
      double du2;
      double dv1;
      double dv2;
      double dw1=0;
      double dw2=0;
		double w0=1,w1=1,w2=1;
		if (inComponents==3)
		{
			w0 = inUVT[2];
			w1 = inUVT[3+2];
			w2 = inUVT[6+2];
			//w0 = w1 = w2 = 1.0;
			dx1 = inVertex[1].x-inVertex[0].x;
         dy1 = inVertex[1].y-inVertex[0].y;
         dx2 = inVertex[2].x-inVertex[0].x;
         dy2 = inVertex[2].y-inVertex[0].y;
         du1 = (inUVT[inComponents  ]*w1 - inUVT[0]*w0)*w;
         du2 = (inUVT[inComponents*2]*w2 - inUVT[0]*w0)*w;
         dv1 = (inUVT[inComponents  +1]*w1 - inUVT[1]*w0)*h;
         dv2 = (inUVT[inComponents*2+1]*w2 - inUVT[1]*w0)*h;

         dw1 = w1 - w0;
         dw2 = w2 - w0;
		}
		else
		{
		   dx1 = inVertex[1].x-inVertex[0].x;
         dy1 = inVertex[1].y-inVertex[0].y;
         dx2 = inVertex[2].x-inVertex[0].x;
         dy2 = inVertex[2].y-inVertex[0].y;
         du1 = (inUVT[inComponents  ] - inUVT[0])*w;
         du2 = (inUVT[inComponents*2] - inUVT[0])*w;
         dv1 = (inUVT[inComponents  +1] - inUVT[1])*h;
         dv2 = (inUVT[inComponents*2+1] - inUVT[1])*h;
		}

      // u = a*x + b*y + c
      //   u0 = a*v0.x + b*v0.y + c
      //   u1 = a*v1.x + b*v1.y + c
      //   u2 = a*v2.x + b*v2.y + c
      //
      //   (u1-u0) = a*(v1.x-v0.x) + b*(v1.y-v0.y) = du1 = a*dx1 + b*dy1
      //   (u2-u0) = a*(v2.x-v0.x) + b*(v2.y-v0.y) = du2 = a*dx2 + b*dy2
      //
      //   du1*dy2 - du2*dy1= a*(dx1*dy2 - dx2*dy1)
      double det = dx1*dy2 - dx2*dy1;
      if (det==0)
      {
         // TODO: x-only or y-only
         mMapper = Matrix(0,0,inUVT[0],inUVT[1]);
         mWX = mWY = 0;
         mW0 = 1;
      }
      else
      {
         det = 1.0/det;

         double a = mMapper.m00 = (du1*dy2 - du2*dy1)*det;
         double b = mMapper.m01 = (du2*dx1 - du1*dx2)*det;
         mMapper.mtx = (inUVT[0]*w*w0 - a*inVertex[0].x - b*inVertex[0].y);

         a = mMapper.m10 = (dv1*dy2 - dv2*dy1)*det;
			b = (dv2*dx1 - dv1*dx2)*det;
         mMapper.mty = (inUVT[1]*h*w0 - a*inVertex[0].x - b*inVertex[0].y);

         if (mPerspective && inComponents>2)
         {
            a = mWX = (dw1*dy2 - dw2*dy1)*det;
            b = mWY = (dw2*dx1 - dw1*dx2)*det;
            mW0= w0 - a*inVertex[0].x - b*inVertex[0].y;
         }
      }

      mMapper.Translate(0.5,0.5);

		if (!mPerspective || inComponents<3)
		{
         mDPxDX = (int)(mMapper.m00 * (1<<16)+ 0.5);
         mDPyDX = (int)(mMapper.m10 * (1<<16)+ 0.5);
		}
   }

   const uint8 *mBase;
   int  mStride;

   ImagePoint mPos;
   int mDPxDX;
   int mDPyDX;
   int mWidth;
   int mHeight;
   int mW1;
   int mH1;
   bool mMapped;
   bool mPerspective;
   double mWX, mWY, mW0;
   double mTX, mTY, mTW;
   Matrix mMapper;
   GraphicsBitmapFill *mBitmap;
};

template<int EDGE,bool SMOOTH,bool PERSP,bool HAS_ALPHA>
class BitmapFiller : public BitmapFillerBase
{
public:
   enum { HasAlpha = HAS_ALPHA };

   BitmapFiller(GraphicsBitmapFill *inFill) : BitmapFillerBase(inFill)
	{
		mPerspective = PERSP;
	}

   ARGB GetInc( )
   {
		if (PERSP)
		{
         double w = 65536.0/mTW;
         mPos.x = (int)(mTX*w);
         mPos.y = (int)(mTY*w);
			mTX += mMapper.m00;
			mTY += mMapper.m10;
			mTW += mWX;
		}
      int x = mPos.x >> 16;
      int y = mPos.y >> 16;
      if (SMOOTH)
      {
         ARGB result;

         ARGB p00,p01,p10,p11;

         GET_PIXEL_POINTERS

			if (!PERSP)
			{
            mPos.x += mDPxDX;
            mPos.y += mDPyDX;
			}

         result.c0 = ( (p00.c0*frac_nx + p01.c0*frac_x)*frac_ny +
                    (  p10.c0*frac_nx + p11.c0*frac_x)*frac_y ) >> 24;
         result.c1 = ( (p00.c1*frac_nx + p01.c1*frac_x)*frac_ny +
                    (  p10.c1*frac_nx + p11.c1*frac_x)*frac_y ) >> 24;
         result.c2 = ( (p00.c2*frac_nx + p01.c2*frac_x)*frac_ny +
                    (  p10.c2*frac_nx + p11.c2*frac_x)*frac_y ) >> 24;

         if (HAS_ALPHA)
         {
            result.a = ( (p00.a*frac_nx + p01.a*frac_x)*frac_ny +
                         (p10.a*frac_nx + p11.a*frac_x)*frac_y ) >> 24;
         }
         else
            result.a = 255;
         return result;
      }
      else
      {
			if (!PERSP)
			{
            mPos.x += mDPxDX;
            mPos.y += mDPyDX;
			}
         MODIFY_EDGE_XY;
         return *(ARGB *)( mBase + y*mStride + x*4);
      }
   }

   inline void SetPos(int inSX,int inSY)
   {
		if (PERSP)
		{
		   double x = inSX;
         double y = inSY;
         mTX = mMapper.m00*x + mMapper.m01*y + mMapper.mtx;
         mTY = mMapper.m10*x + mMapper.m11*y + mMapper.mty;
         mTW =         mWX*x +         mWY*y +         mW0;
		}
		else
		{
         mPos.x = (int)( (mMapper.m00*inSX + mMapper.m01*inSY + mMapper.mtx) * (1<<16) + 0.5);
         mPos.y = (int)( (mMapper.m10*inSX + mMapper.m11*inSY + mMapper.mty) * (1<<16) + 0.5);
		}
   }

   void Fill(const AlphaMask &mAlphaMask,int inTX,int inTY,
       const RenderTarget &inTarget,const RenderState &inState)
   {
      SetupMatrix(*inState.mTransform.mMatrix);

      bool swap =  (inTarget.mPixelFormat & pfSwapRB) != (mBitmap->bitmapData->Format() & pfSwapRB);
      Render( mAlphaMask, *this, inTarget, swap, inState, inTX,inTY );
   }

};

// --- Pseudo constructor ---------------------------------------------------------------

template<int EDGE,bool SMOOTH,bool PERSP>
static Filler *CreateAlpha(GraphicsBitmapFill *inFill)
{
   if (inFill->bitmapData->Format() & pfHasAlpha)
      return new BitmapFiller<EDGE,SMOOTH,PERSP,true>(inFill);
   else
      return new BitmapFiller<EDGE,SMOOTH,PERSP,false>(inFill);
}

template<int EDGE,bool SMOOTH>
static Filler *CreatePerspective(GraphicsBitmapFill *inFill,bool inPerspective)
{
   if (inPerspective)
      return CreateAlpha<EDGE,SMOOTH,true>(inFill);
   else
      return CreateAlpha<EDGE,SMOOTH,false>(inFill);

}

template<int EDGE>
static Filler *CreateSmooth(GraphicsBitmapFill *inFill,bool inPerspective)
{
   if (inFill->smooth)
      return CreatePerspective<EDGE,true>(inFill,inPerspective);
   else
      return CreatePerspective<EDGE,false>(inFill,inPerspective);
}

Filler *Filler::Create(GraphicsBitmapFill *inFill,bool inPerspective)
{
   if (inFill->repeat)
   {
      if ( IsPOW2(inFill->bitmapData->Width()) && IsPOW2(inFill->bitmapData->Height()) )
         return CreateSmooth<EDGE_POW2>(inFill,inPerspective);
      else
         return CreateSmooth<EDGE_REPEAT>(inFill,inPerspective);
   }
   else
      return CreateSmooth<EDGE_CLAMP>(inFill,inPerspective);
}

} // end namespace nme

<|endoftext|>


<commit_before>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#define FML_USED_ON_EMBEDDER

#include <cstdlib>

#include "flutter/assets/asset_manager.h"
#include "flutter/assets/directory_asset_bundle.h"
#include "flutter/fml/file.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/message_loop.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/task_runner.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/switches.h"
#include "flutter/shell/common/thread_host.h"
#include "third_party/dart/runtime/include/bin/dart_io_api.h"

namespace shell {

// Checks whether the engine's main Dart isolate has no pending work.  If so,
// then exit the given message loop.
class ScriptCompletionTaskObserver {
 public:
  ScriptCompletionTaskObserver(Shell& shell,
                               fml::RefPtr<fml::TaskRunner> main_task_runner,
                               bool run_forever)
      : engine_(shell.GetEngine()),
        main_task_runner_(std::move(main_task_runner)),
        run_forever_(run_forever) {}

  int GetExitCodeForLastError() const {
    // Exit codes used by the Dart command line tool.
    const int kApiErrorExitCode = 253;
    const int kCompilationErrorExitCode = 254;
    const int kErrorExitCode = 255;
    switch (last_error_) {
      case tonic::kCompilationErrorType:
        return kCompilationErrorExitCode;
      case tonic::kApiErrorType:
        return kApiErrorExitCode;
      case tonic::kUnknownErrorType:
        return kErrorExitCode;
      default:
        return 0;
    }
  }

  void DidProcessTask() {
    if (engine_) {
      last_error_ = engine_->GetUIIsolateLastError();
      if (engine_->UIIsolateHasLivePorts()) {
        // The UI isolate still has live ports and is running. Nothing to do
        // just yet.
        return;
      }
    }

    if (run_forever_) {
      // We need this script to run forever. We have already recorded the last
      // error. Keep going.
      return;
    }

    if (!has_terminated) {
      // Only try to terminate the loop once.
      has_terminated = true;
      main_task_runner_->PostTask(
          []() { fml::MessageLoop::GetCurrent().Terminate(); });
    }
  }

 private:
  fml::WeakPtr<Engine> engine_;
  fml::RefPtr<fml::TaskRunner> main_task_runner_;
  bool run_forever_ = false;
  tonic::DartErrorHandleType last_error_ = tonic::kUnknownErrorType;
  bool has_terminated = false;

  FML_DISALLOW_COPY_AND_ASSIGN(ScriptCompletionTaskObserver);
};

int RunTester(const blink::Settings& settings, bool run_forever) {
  const auto thread_label = "io.flutter.test";

  fml::MessageLoop::EnsureInitializedForCurrentThread();

  auto current_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();

  // Setup a single threaded test runner configuration.
  const blink::TaskRunners task_runners(thread_label,  // dart thread label
                                        current_task_runner,  // platform
                                        current_task_runner,  // gpu
                                        current_task_runner,  // ui
                                        current_task_runner   // io
  );

  Shell::CreateCallback<PlatformView> on_create_platform_view =
      [](Shell& shell) {
        return std::make_unique<PlatformView>(shell, shell.GetTaskRunners());
      };

  Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
    return std::make_unique<Rasterizer>(shell.GetTaskRunners());
  };

  auto shell = Shell::Create(task_runners,             //
                             settings,                 //
                             on_create_platform_view,  //
                             on_create_rasterizer      //
  );

  if (!shell || !shell->IsSetup()) {
    FML_LOG(ERROR) << "Could not setup the shell.";
    return EXIT_FAILURE;
  }

  if (settings.application_kernel_asset.empty()) {
    FML_LOG(ERROR) << "Dart kernel file not specified.";
    return EXIT_FAILURE;
  }

  // Initialize default testing locales. There is no platform to
  // pass locales on the tester, so to retain expected locale behavior,
  // we emulate it in here by passing in 'en_US' and 'zh_CN' as test locales.
  const char* locale_json =
      "{\"method\":\"setLocale\",\"args\":[\"en\",\"US\",\"\",\"\",\"zh\","
      "\"CN\",\"\",\"\"]}";
  std::vector<uint8_t> locale_bytes(locale_json,
                                    locale_json + std::strlen(locale_json));
  fml::RefPtr<blink::PlatformMessageResponse> response;
  shell->GetPlatformView()->DispatchPlatformMessage(
      fml::MakeRefCounted<blink::PlatformMessage>("flutter/localization",
                                                  locale_bytes, response));

  std::initializer_list<fml::FileMapping::Protection> protection = {
      fml::FileMapping::Protection::kRead};
  auto main_dart_file_mapping = std::make_unique<fml::FileMapping>(
      fml::OpenFile(
          fml::paths::AbsolutePath(settings.application_kernel_asset).c_str(),
          false, fml::FilePermission::kRead),
      protection);

  auto isolate_configuration =
      IsolateConfiguration::CreateForKernel(std::move(main_dart_file_mapping));

  if (!isolate_configuration) {
    FML_LOG(ERROR) << "Could create isolate configuration.";
    return EXIT_FAILURE;
  }

  auto asset_manager = std::make_shared<blink::AssetManager>();
  asset_manager->PushBack(std::make_unique<blink::DirectoryAssetBundle>(
      fml::Duplicate(settings.assets_dir)));
  asset_manager->PushBack(
      std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
          settings.assets_path.c_str(), false, fml::FilePermission::kRead)));

  RunConfiguration run_configuration(std::move(isolate_configuration),
                                     std::move(asset_manager));

  // The script completion task observer that will be installed on the UI thread
  // that watched if the engine has any live ports.
  ScriptCompletionTaskObserver completion_observer(
      *shell,  // a valid shell
      fml::MessageLoop::GetCurrent()
          .GetTaskRunner(),  // the message loop to terminate
      run_forever            // should the exit be ignored
  );

  bool engine_did_run = false;

  fml::AutoResetWaitableEvent sync_run_latch;
  fml::TaskRunner::RunNowOrPostTask(
      shell->GetTaskRunners().GetUITaskRunner(),
      fml::MakeCopyable([&sync_run_latch, &completion_observer,
                         engine = shell->GetEngine(),
                         config = std::move(run_configuration),
                         &engine_did_run]() mutable {
        fml::MessageLoop::GetCurrent().AddTaskObserver(
            reinterpret_cast<intptr_t>(&completion_observer),
            [&completion_observer]() { completion_observer.DidProcessTask(); });
        if (engine->Run(std::move(config)) !=
            shell::Engine::RunStatus::Failure) {
          engine_did_run = true;

          blink::ViewportMetrics metrics;
          metrics.device_pixel_ratio = 3.0;
          metrics.physical_width = 2400;   // 800 at 3x resolution
          metrics.physical_height = 1800;  // 600 at 3x resolution
          engine->SetViewportMetrics(metrics);

        } else {
          FML_DLOG(ERROR) << "Could not launch the engine with configuration.";
        }
        sync_run_latch.Signal();
      }));
  sync_run_latch.Wait();

  // Run the message loop and wait for the script to do its thing.
  fml::MessageLoop::GetCurrent().Run();

  // Cleanup the completion observer synchronously as it is living on the
  // stack.
  fml::AutoResetWaitableEvent latch;
  fml::TaskRunner::RunNowOrPostTask(
      shell->GetTaskRunners().GetUITaskRunner(),
      [&latch, &completion_observer] {
        fml::MessageLoop::GetCurrent().RemoveTaskObserver(
            reinterpret_cast<intptr_t>(&completion_observer));
        latch.Signal();
      });
  latch.Wait();

  if (!engine_did_run) {
    // If the engine itself didn't have a chance to run, there is no point in
    // asking it if there was an error. Signal a failure unconditionally.
    return EXIT_FAILURE;
  }

  return completion_observer.GetExitCodeForLastError();
}

}  // namespace shell

int main(int argc, char* argv[]) {
  dart::bin::SetExecutableName(argv[0]);
  dart::bin::SetExecutableArguments(argc - 1, argv);

  auto command_line = fml::CommandLineFromArgcArgv(argc, argv);

  if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) {
    shell::PrintUsage("flutter_tester");
    return EXIT_SUCCESS;
  }

  auto settings = shell::SettingsFromCommandLine(command_line);
  if (command_line.positional_args().size() > 0) {
    // The tester may not use the switch for the main dart file path. Specifying
    // it as a positional argument instead.
    settings.application_kernel_asset = command_line.positional_args()[0];
  }

  if (settings.application_kernel_asset.size() == 0) {
    FML_LOG(ERROR) << "Dart kernel file not specified.";
    return EXIT_FAILURE;
  }

  settings.icu_data_path = "icudtl.dat";

  // The tools that read logs get confused if there is a log tag specified.
  settings.log_tag = "";

  settings.task_observer_add = [](intptr_t key, fml::closure callback) {
    fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
  };

  settings.task_observer_remove = [](intptr_t key) {
    fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
  };

  return shell::RunTester(
      settings,
      command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever)));
}
<commit_msg>[flutter_tester] Accept --icu-data-file-path (#8374)<commit_after>// Copyright 2013 The Flutter Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#define FML_USED_ON_EMBEDDER

#include <cstdlib>

#include "flutter/assets/asset_manager.h"
#include "flutter/assets/directory_asset_bundle.h"
#include "flutter/fml/file.h"
#include "flutter/fml/make_copyable.h"
#include "flutter/fml/message_loop.h"
#include "flutter/fml/paths.h"
#include "flutter/fml/synchronization/waitable_event.h"
#include "flutter/fml/task_runner.h"
#include "flutter/shell/common/platform_view.h"
#include "flutter/shell/common/rasterizer.h"
#include "flutter/shell/common/shell.h"
#include "flutter/shell/common/switches.h"
#include "flutter/shell/common/thread_host.h"
#include "third_party/dart/runtime/include/bin/dart_io_api.h"

namespace shell {

// Checks whether the engine's main Dart isolate has no pending work.  If so,
// then exit the given message loop.
class ScriptCompletionTaskObserver {
 public:
  ScriptCompletionTaskObserver(Shell& shell,
                               fml::RefPtr<fml::TaskRunner> main_task_runner,
                               bool run_forever)
      : engine_(shell.GetEngine()),
        main_task_runner_(std::move(main_task_runner)),
        run_forever_(run_forever) {}

  int GetExitCodeForLastError() const {
    // Exit codes used by the Dart command line tool.
    const int kApiErrorExitCode = 253;
    const int kCompilationErrorExitCode = 254;
    const int kErrorExitCode = 255;
    switch (last_error_) {
      case tonic::kCompilationErrorType:
        return kCompilationErrorExitCode;
      case tonic::kApiErrorType:
        return kApiErrorExitCode;
      case tonic::kUnknownErrorType:
        return kErrorExitCode;
      default:
        return 0;
    }
  }

  void DidProcessTask() {
    if (engine_) {
      last_error_ = engine_->GetUIIsolateLastError();
      if (engine_->UIIsolateHasLivePorts()) {
        // The UI isolate still has live ports and is running. Nothing to do
        // just yet.
        return;
      }
    }

    if (run_forever_) {
      // We need this script to run forever. We have already recorded the last
      // error. Keep going.
      return;
    }

    if (!has_terminated) {
      // Only try to terminate the loop once.
      has_terminated = true;
      main_task_runner_->PostTask(
          []() { fml::MessageLoop::GetCurrent().Terminate(); });
    }
  }

 private:
  fml::WeakPtr<Engine> engine_;
  fml::RefPtr<fml::TaskRunner> main_task_runner_;
  bool run_forever_ = false;
  tonic::DartErrorHandleType last_error_ = tonic::kUnknownErrorType;
  bool has_terminated = false;

  FML_DISALLOW_COPY_AND_ASSIGN(ScriptCompletionTaskObserver);
};

int RunTester(const blink::Settings& settings, bool run_forever) {
  const auto thread_label = "io.flutter.test";

  fml::MessageLoop::EnsureInitializedForCurrentThread();

  auto current_task_runner = fml::MessageLoop::GetCurrent().GetTaskRunner();

  // Setup a single threaded test runner configuration.
  const blink::TaskRunners task_runners(thread_label,  // dart thread label
                                        current_task_runner,  // platform
                                        current_task_runner,  // gpu
                                        current_task_runner,  // ui
                                        current_task_runner   // io
  );

  Shell::CreateCallback<PlatformView> on_create_platform_view =
      [](Shell& shell) {
        return std::make_unique<PlatformView>(shell, shell.GetTaskRunners());
      };

  Shell::CreateCallback<Rasterizer> on_create_rasterizer = [](Shell& shell) {
    return std::make_unique<Rasterizer>(shell.GetTaskRunners());
  };

  auto shell = Shell::Create(task_runners,             //
                             settings,                 //
                             on_create_platform_view,  //
                             on_create_rasterizer      //
  );

  if (!shell || !shell->IsSetup()) {
    FML_LOG(ERROR) << "Could not setup the shell.";
    return EXIT_FAILURE;
  }

  if (settings.application_kernel_asset.empty()) {
    FML_LOG(ERROR) << "Dart kernel file not specified.";
    return EXIT_FAILURE;
  }

  // Initialize default testing locales. There is no platform to
  // pass locales on the tester, so to retain expected locale behavior,
  // we emulate it in here by passing in 'en_US' and 'zh_CN' as test locales.
  const char* locale_json =
      "{\"method\":\"setLocale\",\"args\":[\"en\",\"US\",\"\",\"\",\"zh\","
      "\"CN\",\"\",\"\"]}";
  std::vector<uint8_t> locale_bytes(locale_json,
                                    locale_json + std::strlen(locale_json));
  fml::RefPtr<blink::PlatformMessageResponse> response;
  shell->GetPlatformView()->DispatchPlatformMessage(
      fml::MakeRefCounted<blink::PlatformMessage>("flutter/localization",
                                                  locale_bytes, response));

  std::initializer_list<fml::FileMapping::Protection> protection = {
      fml::FileMapping::Protection::kRead};
  auto main_dart_file_mapping = std::make_unique<fml::FileMapping>(
      fml::OpenFile(
          fml::paths::AbsolutePath(settings.application_kernel_asset).c_str(),
          false, fml::FilePermission::kRead),
      protection);

  auto isolate_configuration =
      IsolateConfiguration::CreateForKernel(std::move(main_dart_file_mapping));

  if (!isolate_configuration) {
    FML_LOG(ERROR) << "Could create isolate configuration.";
    return EXIT_FAILURE;
  }

  auto asset_manager = std::make_shared<blink::AssetManager>();
  asset_manager->PushBack(std::make_unique<blink::DirectoryAssetBundle>(
      fml::Duplicate(settings.assets_dir)));
  asset_manager->PushBack(
      std::make_unique<blink::DirectoryAssetBundle>(fml::OpenDirectory(
          settings.assets_path.c_str(), false, fml::FilePermission::kRead)));

  RunConfiguration run_configuration(std::move(isolate_configuration),
                                     std::move(asset_manager));

  // The script completion task observer that will be installed on the UI thread
  // that watched if the engine has any live ports.
  ScriptCompletionTaskObserver completion_observer(
      *shell,  // a valid shell
      fml::MessageLoop::GetCurrent()
          .GetTaskRunner(),  // the message loop to terminate
      run_forever            // should the exit be ignored
  );

  bool engine_did_run = false;

  fml::AutoResetWaitableEvent sync_run_latch;
  fml::TaskRunner::RunNowOrPostTask(
      shell->GetTaskRunners().GetUITaskRunner(),
      fml::MakeCopyable([&sync_run_latch, &completion_observer,
                         engine = shell->GetEngine(),
                         config = std::move(run_configuration),
                         &engine_did_run]() mutable {
        fml::MessageLoop::GetCurrent().AddTaskObserver(
            reinterpret_cast<intptr_t>(&completion_observer),
            [&completion_observer]() { completion_observer.DidProcessTask(); });
        if (engine->Run(std::move(config)) !=
            shell::Engine::RunStatus::Failure) {
          engine_did_run = true;

          blink::ViewportMetrics metrics;
          metrics.device_pixel_ratio = 3.0;
          metrics.physical_width = 2400;   // 800 at 3x resolution
          metrics.physical_height = 1800;  // 600 at 3x resolution
          engine->SetViewportMetrics(metrics);

        } else {
          FML_DLOG(ERROR) << "Could not launch the engine with configuration.";
        }
        sync_run_latch.Signal();
      }));
  sync_run_latch.Wait();

  // Run the message loop and wait for the script to do its thing.
  fml::MessageLoop::GetCurrent().Run();

  // Cleanup the completion observer synchronously as it is living on the
  // stack.
  fml::AutoResetWaitableEvent latch;
  fml::TaskRunner::RunNowOrPostTask(
      shell->GetTaskRunners().GetUITaskRunner(),
      [&latch, &completion_observer] {
        fml::MessageLoop::GetCurrent().RemoveTaskObserver(
            reinterpret_cast<intptr_t>(&completion_observer));
        latch.Signal();
      });
  latch.Wait();

  if (!engine_did_run) {
    // If the engine itself didn't have a chance to run, there is no point in
    // asking it if there was an error. Signal a failure unconditionally.
    return EXIT_FAILURE;
  }

  return completion_observer.GetExitCodeForLastError();
}

}  // namespace shell

int main(int argc, char* argv[]) {
  dart::bin::SetExecutableName(argv[0]);
  dart::bin::SetExecutableArguments(argc - 1, argv);

  auto command_line = fml::CommandLineFromArgcArgv(argc, argv);

  if (command_line.HasOption(shell::FlagForSwitch(shell::Switch::Help))) {
    shell::PrintUsage("flutter_tester");
    return EXIT_SUCCESS;
  }

  auto settings = shell::SettingsFromCommandLine(command_line);
  if (command_line.positional_args().size() > 0) {
    // The tester may not use the switch for the main dart file path. Specifying
    // it as a positional argument instead.
    settings.application_kernel_asset = command_line.positional_args()[0];
  }

  if (settings.application_kernel_asset.size() == 0) {
    FML_LOG(ERROR) << "Dart kernel file not specified.";
    return EXIT_FAILURE;
  }

  if (settings.icu_data_path.size() == 0) {
    settings.icu_data_path = "icudtl.dat";
  }

  // The tools that read logs get confused if there is a log tag specified.
  settings.log_tag = "";

  settings.task_observer_add = [](intptr_t key, fml::closure callback) {
    fml::MessageLoop::GetCurrent().AddTaskObserver(key, std::move(callback));
  };

  settings.task_observer_remove = [](intptr_t key) {
    fml::MessageLoop::GetCurrent().RemoveTaskObserver(key);
  };

  return shell::RunTester(
      settings,
      command_line.HasOption(shell::FlagForSwitch(shell::Switch::RunForever)));
}
<|endoftext|>