<commit_before>    /*
        open source routing machine
    Copyright (C) Dennis Luxen, others 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.

This program 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 Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#ifndef MAP_MATCHING_PLUGIN_H
#define MAP_MATCHING_PLUGIN_H

#include "plugin_base.hpp"

#include "../algorithms/bayes_classifier.hpp"
#include "../algorithms/object_encoder.hpp"
#include "../util/integer_range.hpp"
#include "../data_structures/search_engine.hpp"
#include "../routing_algorithms/map_matching.hpp"
#include "../util/compute_angle.hpp"
#include "../util/simple_logger.hpp"
#include "../util/string_util.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/gpx_descriptor.hpp"
#include "../descriptors/json_descriptor.hpp"

#include <cstdlib>

#include <algorithm>
#include <memory>
#include <string>
#include <vector>

template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
{
  private:
    std::unordered_map<std::string, unsigned> descriptor_table;
    std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;

    using ClassifierT = BayesClassifier<LaplaceDistribution, LaplaceDistribution, double>;
    using TraceClassification = ClassifierT::ClassificationT;

  public:
    MapMatchingPlugin(DataFacadeT *facade)
    : descriptor_string("match")
    , facade(facade)
    // the values where derived from fitting a laplace distribution
    // to the values of manually classified traces
    , classifier(LaplaceDistribution(0.0057154021891018675, 0.020294704891166186),
                 LaplaceDistribution(0.11467696742821254, 0.49918444000368756),
                 0.7977883096366508) // valid apriori probability
    {
        descriptor_table.emplace("json", 0);
        search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
    }

    virtual ~MapMatchingPlugin() { search_engine_ptr.reset(); }

    const std::string GetDescriptor() const final { return descriptor_string; }

    TraceClassification classify(float trace_length, float matched_length, int removed_points) const
    {
        double distance_feature = -std::log(trace_length) + std::log(matched_length);

        // matched to the same point
        if (!std::isfinite(distance_feature))
        {
            return std::make_pair(ClassifierT::ClassLabel::NEGATIVE, 1.0);
        }

        auto label_with_confidence =  classifier.classify(distance_feature);

        // "second stage classifier": if we need to remove points there is something fishy
        if (removed_points > 0)
        {
            return std::make_pair(ClassifierT::ClassLabel::NEGATIVE, 1.0);
        }

        return label_with_confidence;
    }

    bool get_candiates(const std::vector<FixedPointCoordinate>& input_coords, std::vector<double>& sub_trace_lengths, Matching::CandidateLists& candidates_lists)
    {
        double last_distance = coordinate_calculation::great_circle_distance(
            input_coords[0],
            input_coords[1]);
        sub_trace_lengths.resize(input_coords.size());
        sub_trace_lengths[0] = 0;
        for (const auto current_coordinate : osrm::irange<std::size_t>(0, input_coords.size()))
        {
            bool allow_uturn = false;
            if (0 < current_coordinate)
            {
                last_distance = coordinate_calculation::great_circle_distance(
                    input_coords[current_coordinate - 1],
                    input_coords[current_coordinate]);
                sub_trace_lengths[current_coordinate] += sub_trace_lengths[current_coordinate-1] + last_distance;
            }

            if (input_coords.size()-1 > current_coordinate && 0 < current_coordinate)
            {
                double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
                                                    input_coords[current_coordinate-1],
                                                    input_coords[current_coordinate],
                                                    input_coords[current_coordinate+1]);

                // sharp turns indicate a possible uturn
                if (turn_angle < 100.0 || turn_angle > 260.0)
                {
                    allow_uturn = true;
                }
            }

            std::vector<std::pair<PhantomNode, double>> candidates;
            if (!facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
                    input_coords[current_coordinate],
                    candidates,
                    last_distance/2.0,
                    5,
                    Matching::max_number_of_candidates))
            {
                return false;
            }

            if (allow_uturn)
            {
                candidates_lists.push_back(candidates);
            }
            else
            {
                unsigned compact_size = candidates.size();
                for (const auto i : osrm::irange(0u, compact_size))
                {
                    // Split edge if it is bidirectional and append reverse direction to end of list
                    if (candidates[i].first.forward_node_id != SPECIAL_NODEID
                     && candidates[i].first.reverse_node_id != SPECIAL_NODEID)
                    {
                        PhantomNode reverse_node(candidates[i].first);
                        reverse_node.forward_node_id = SPECIAL_NODEID;
                        candidates.push_back(std::make_pair(reverse_node, candidates[i].second));

                        candidates[i].first.reverse_node_id = SPECIAL_NODEID;
                    }
                }
                candidates_lists.push_back(candidates);
            }

        }

        return true;
    }

    int HandleRequest(const RouteParameters &route_parameters, osrm::json::Object &json_result) final
    {
        // check number of parameters
        if (!check_all_coordinates(route_parameters.coordinates))
        {
            return 400;
        }

        std::vector<double> sub_trace_lengths;
        Matching::CandidateLists candidates_lists;
        const auto& input_coords = route_parameters.coordinates;
        const auto& input_timestamps = route_parameters.timestamps;
        if (input_timestamps.size() > 0 && input_coords.size() != input_timestamps.size())
        {
            return 400;
        }
        bool found_candidates = get_candiates(input_coords, sub_trace_lengths, candidates_lists);
        if (!found_candidates)
        {
            return 400;
        }

        // call the actual map matching
        osrm::json::Object debug_info;
        Matching::SubMatchingList sub_matchings;
        search_engine_ptr->map_matching(candidates_lists, input_coords, input_timestamps, sub_matchings, debug_info);

        if (1 > sub_matchings.size())
        {
            return 400;
        }

        osrm::json::Array traces;
        for (auto& sub : sub_matchings)
        {
            // classify result
            double trace_length = sub_trace_lengths[sub.indices.back()] - sub_trace_lengths[sub.indices.front()];
            TraceClassification classification = classify(trace_length,
                                                          sub.length,
                                                          (sub.indices.back() - sub.indices.front() + 1) - sub.nodes.size());
            if (classification.first == ClassifierT::ClassLabel::POSITIVE)
            {
                sub.confidence = classification.second;
            }
            else
            {
                sub.confidence = 1-classification.second;
            }

            BOOST_ASSERT(sub.nodes.size() > 1);

            // FIXME this is a pretty bad hack. Geometries should obtained directly
            // from map_matching.
            // run shortest path routing to obtain geometry
            InternalRouteResult raw_route;
            PhantomNodes current_phantom_node_pair;
            for (unsigned i = 0; i < sub.nodes.size() - 1; ++i)
            {
                current_phantom_node_pair.source_phantom = sub.nodes[i];
                current_phantom_node_pair.target_phantom = sub.nodes[i + 1];
                raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
            }
            search_engine_ptr->shortest_path(
                raw_route.segment_end_coordinates,
                std::vector<bool>(raw_route.segment_end_coordinates.size(), true),
                raw_route);

            DescriptorConfig descriptor_config;

            auto iter = descriptor_table.find(route_parameters.output_format);
            unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0);

            descriptor_config.zoom_level = route_parameters.zoom_level;
            descriptor_config.instructions = false;
            descriptor_config.geometry = route_parameters.geometry;
            descriptor_config.encode_geometry = route_parameters.compression;

            std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
            switch (descriptor_type)
            {
            // case 0:
            //     descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
            //     break;
            case 1:
                descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(facade);
                break;
            // case 2:
            //      descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
            //      break;
            default:
                descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(facade);
                break;
            }

            osrm::json::Object temp_result;
            descriptor->SetConfig(descriptor_config);
            descriptor->Run(raw_route, temp_result);

            osrm::json::Array indices;
            for (const auto& i : sub.indices)
            {
                indices.values.emplace_back(i);
            }

            osrm::json::Object subtrace;
            subtrace.values["geometry"] = temp_result.values["route_geometry"];
            subtrace.values["confidence"] = sub.confidence;
            subtrace.values["indices"] = indices;
            subtrace.values["matched_points"] = temp_result.values["via_points"];

            traces.values.push_back(subtrace);
        }

        json_result.values["debug"] = debug_info;
        json_result.values["traces"] = traces;

        return 200;
    }

  private:
    std::string descriptor_string;
    DataFacadeT *facade;
    ClassifierT classifier;
};

#endif /* MAP_MATCHING_PLUGIN_H */
<commit_msg>Rename traces to matchings in response<commit_after>    /*
        open source routing machine
    Copyright (C) Dennis Luxen, others 2010

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU AFFERO General Public License as published by
the Free Software Foundation; either version 3 of the License, or
any later version.

This program 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 Affero General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
or see http://www.gnu.org/licenses/agpl.txt.
 */

#ifndef MAP_MATCHING_PLUGIN_H
#define MAP_MATCHING_PLUGIN_H

#include "plugin_base.hpp"

#include "../algorithms/bayes_classifier.hpp"
#include "../algorithms/object_encoder.hpp"
#include "../util/integer_range.hpp"
#include "../data_structures/search_engine.hpp"
#include "../routing_algorithms/map_matching.hpp"
#include "../util/compute_angle.hpp"
#include "../util/simple_logger.hpp"
#include "../util/string_util.hpp"
#include "../descriptors/descriptor_base.hpp"
#include "../descriptors/gpx_descriptor.hpp"
#include "../descriptors/json_descriptor.hpp"

#include <cstdlib>

#include <algorithm>
#include <memory>
#include <string>
#include <vector>

template <class DataFacadeT> class MapMatchingPlugin : public BasePlugin
{
  private:
    std::unordered_map<std::string, unsigned> descriptor_table;
    std::shared_ptr<SearchEngine<DataFacadeT>> search_engine_ptr;

    using ClassifierT = BayesClassifier<LaplaceDistribution, LaplaceDistribution, double>;
    using TraceClassification = ClassifierT::ClassificationT;

  public:
    MapMatchingPlugin(DataFacadeT *facade)
    : descriptor_string("match")
    , facade(facade)
    // the values where derived from fitting a laplace distribution
    // to the values of manually classified traces
    , classifier(LaplaceDistribution(0.0057154021891018675, 0.020294704891166186),
                 LaplaceDistribution(0.11467696742821254, 0.49918444000368756),
                 0.7977883096366508) // valid apriori probability
    {
        descriptor_table.emplace("json", 0);
        search_engine_ptr = std::make_shared<SearchEngine<DataFacadeT>>(facade);
    }

    virtual ~MapMatchingPlugin() { search_engine_ptr.reset(); }

    const std::string GetDescriptor() const final { return descriptor_string; }

    TraceClassification classify(float trace_length, float matched_length, int removed_points) const
    {
        double distance_feature = -std::log(trace_length) + std::log(matched_length);

        // matched to the same point
        if (!std::isfinite(distance_feature))
        {
            return std::make_pair(ClassifierT::ClassLabel::NEGATIVE, 1.0);
        }

        auto label_with_confidence =  classifier.classify(distance_feature);

        // "second stage classifier": if we need to remove points there is something fishy
        if (removed_points > 0)
        {
            return std::make_pair(ClassifierT::ClassLabel::NEGATIVE, 1.0);
        }

        return label_with_confidence;
    }

    bool get_candiates(const std::vector<FixedPointCoordinate>& input_coords, std::vector<double>& sub_trace_lengths, Matching::CandidateLists& candidates_lists)
    {
        double last_distance = coordinate_calculation::great_circle_distance(
            input_coords[0],
            input_coords[1]);
        sub_trace_lengths.resize(input_coords.size());
        sub_trace_lengths[0] = 0;
        for (const auto current_coordinate : osrm::irange<std::size_t>(0, input_coords.size()))
        {
            bool allow_uturn = false;
            if (0 < current_coordinate)
            {
                last_distance = coordinate_calculation::great_circle_distance(
                    input_coords[current_coordinate - 1],
                    input_coords[current_coordinate]);
                sub_trace_lengths[current_coordinate] += sub_trace_lengths[current_coordinate-1] + last_distance;
            }

            if (input_coords.size()-1 > current_coordinate && 0 < current_coordinate)
            {
                double turn_angle = ComputeAngle::OfThreeFixedPointCoordinates(
                                                    input_coords[current_coordinate-1],
                                                    input_coords[current_coordinate],
                                                    input_coords[current_coordinate+1]);

                // sharp turns indicate a possible uturn
                if (turn_angle < 100.0 || turn_angle > 260.0)
                {
                    allow_uturn = true;
                }
            }

            std::vector<std::pair<PhantomNode, double>> candidates;
            if (!facade->IncrementalFindPhantomNodeForCoordinateWithMaxDistance(
                    input_coords[current_coordinate],
                    candidates,
                    last_distance/2.0,
                    5,
                    Matching::max_number_of_candidates))
            {
                return false;
            }

            if (allow_uturn)
            {
                candidates_lists.push_back(candidates);
            }
            else
            {
                unsigned compact_size = candidates.size();
                for (const auto i : osrm::irange(0u, compact_size))
                {
                    // Split edge if it is bidirectional and append reverse direction to end of list
                    if (candidates[i].first.forward_node_id != SPECIAL_NODEID
                     && candidates[i].first.reverse_node_id != SPECIAL_NODEID)
                    {
                        PhantomNode reverse_node(candidates[i].first);
                        reverse_node.forward_node_id = SPECIAL_NODEID;
                        candidates.push_back(std::make_pair(reverse_node, candidates[i].second));

                        candidates[i].first.reverse_node_id = SPECIAL_NODEID;
                    }
                }
                candidates_lists.push_back(candidates);
            }

        }

        return true;
    }

    int HandleRequest(const RouteParameters &route_parameters, osrm::json::Object &json_result) final
    {
        // check number of parameters
        if (!check_all_coordinates(route_parameters.coordinates))
        {
            return 400;
        }

        std::vector<double> sub_trace_lengths;
        Matching::CandidateLists candidates_lists;
        const auto& input_coords = route_parameters.coordinates;
        const auto& input_timestamps = route_parameters.timestamps;
        if (input_timestamps.size() > 0 && input_coords.size() != input_timestamps.size())
        {
            return 400;
        }
        bool found_candidates = get_candiates(input_coords, sub_trace_lengths, candidates_lists);
        if (!found_candidates)
        {
            return 400;
        }

        // call the actual map matching
        osrm::json::Object debug_info;
        Matching::SubMatchingList sub_matchings;
        search_engine_ptr->map_matching(candidates_lists, input_coords, input_timestamps, sub_matchings, debug_info);

        if (1 > sub_matchings.size())
        {
            return 400;
        }

        osrm::json::Array matchings;
        for (auto& sub : sub_matchings)
        {
            // classify result
            double trace_length = sub_trace_lengths[sub.indices.back()] - sub_trace_lengths[sub.indices.front()];
            TraceClassification classification = classify(trace_length,
                                                          sub.length,
                                                          (sub.indices.back() - sub.indices.front() + 1) - sub.nodes.size());
            if (classification.first == ClassifierT::ClassLabel::POSITIVE)
            {
                sub.confidence = classification.second;
            }
            else
            {
                sub.confidence = 1-classification.second;
            }

            BOOST_ASSERT(sub.nodes.size() > 1);

            // FIXME this is a pretty bad hack. Geometries should obtained directly
            // from map_matching.
            // run shortest path routing to obtain geometry
            InternalRouteResult raw_route;
            PhantomNodes current_phantom_node_pair;
            for (unsigned i = 0; i < sub.nodes.size() - 1; ++i)
            {
                current_phantom_node_pair.source_phantom = sub.nodes[i];
                current_phantom_node_pair.target_phantom = sub.nodes[i + 1];
                raw_route.segment_end_coordinates.emplace_back(current_phantom_node_pair);
            }
            search_engine_ptr->shortest_path(
                raw_route.segment_end_coordinates,
                std::vector<bool>(raw_route.segment_end_coordinates.size(), true),
                raw_route);

            DescriptorConfig descriptor_config;

            auto iter = descriptor_table.find(route_parameters.output_format);
            unsigned descriptor_type = (iter != descriptor_table.end() ? iter->second : 0);

            descriptor_config.zoom_level = route_parameters.zoom_level;
            descriptor_config.instructions = false;
            descriptor_config.geometry = route_parameters.geometry;
            descriptor_config.encode_geometry = route_parameters.compression;

            std::shared_ptr<BaseDescriptor<DataFacadeT>> descriptor;
            switch (descriptor_type)
            {
            // case 0:
            //     descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>();
            //     break;
            case 1:
                descriptor = std::make_shared<GPXDescriptor<DataFacadeT>>(facade);
                break;
            // case 2:
            //      descriptor = std::make_shared<GEOJSONDescriptor<DataFacadeT>>();
            //      break;
            default:
                descriptor = std::make_shared<JSONDescriptor<DataFacadeT>>(facade);
                break;
            }

            osrm::json::Object temp_result;
            descriptor->SetConfig(descriptor_config);
            descriptor->Run(raw_route, temp_result);

            osrm::json::Array indices;
            for (const auto& i : sub.indices)
            {
                indices.values.emplace_back(i);
            }

            osrm::json::Object subtrace;
            subtrace.values["geometry"] = temp_result.values["route_geometry"];
            subtrace.values["confidence"] = sub.confidence;
            subtrace.values["indices"] = indices;
            subtrace.values["matched_points"] = temp_result.values["via_points"];

            matchings.values.push_back(subtrace);
        }

        json_result.values["debug"] = debug_info;
        json_result.values["matchings"] = matchings;

        return 200;
    }

  private:
    std::string descriptor_string;
    DataFacadeT *facade;
    ClassifierT classifier;
};

#endif /* MAP_MATCHING_PLUGIN_H */
<|endoftext|>


<commit_before>#include "cmd_base.h"

static bool graph(const std::vector<std::string> &args)
{
	std::vector<Argument> A;
	std::string f;
	for (auto &s : args)
	{
		if (s.empty()) continue;
		if (!f.empty()) f += ' ';
		size_t i0 = 0, n = s.length();
		while (i0 < n)
		{
			size_t i1 = s.find(';', i0);
			if (i1 == std::string::npos)
			{
				f += s.substr(i0);
				break;
			}
			else
			{
				f += s.substr(i0, i1-i0);
				A.emplace_back(std::move(f));
				f = "";
				i0 = i1+1;
			}
		}
	}
	if (!f.empty()) A.emplace_back(std::move(f));
	if (A.size() > 3) return false;
	for (auto &a : A)
	{
		size_t n = a.s.length(), k = 0;
		while (k < n && isspace(a.s[n-1-k])) ++k;
		if (k) a.s.erase(n -= k);
		k = 0;
		while (k < n && isspace(a.s[k])) ++k;
		if (k) a.s.erase(0, k);
		if (a.s.empty()) a.s = "-";//return false;
	}

	cmd.send(CID::GRAPH, std::move(A));
	return true;
}

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

CommandInfo ci_graph("graph", "g", CID::GRAPH, graph, "graph [f1|- [; f2|- [; f3|-]]]",
"Changes or prints the plotted expressions for the selected graph.");

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

extern void cmd_ls(const Graph &g, int i, bool selected);

void cmd_graph(PlotWindow &w, Command &cmd)
{
	Graph *cg = w.plot.current_graph();
	if (!cg) throw std::runtime_error("No graph selected");

	Graph &g = *cg;
	if (cmd.args.empty())
	{
		cmd_ls(g, w.plot.current_graph_index(), false /*just don't print that*/);
		return;
	}
	int nc = g.n_components(), na = (int)cmd.args.size();
	if (nc < 0 || na > nc) throw std::runtime_error(format("Graph only has %d components (%d given)", nc, na));
	std::string f1 = cmd.get_str(0), f2, f3;
	if (na > 1) f2 = cmd.get_str(1);
	if (na > 2) f3 = cmd.get_str(2, true);

	if (f1.empty() || f1 == "-") f1 = g.f1();
	if (f2.empty() || f2 == "-") f2 = g.f2();
	if (f3.empty() || f3 == "-") f3 = g.f3();

	g.set(f1, f2, f3);
	if (!g.isValid())
	{
		printf("Graph updated, but there were parsing errors:\n");
		Expression *x = g.expression();
		if (!x) throw std::logic_error("NULL expression (this should not happen)");
		const ParsingResult &r = x->result();
		printf("%s. At this point:\n", r.info.c_str());
		std::string &fe = (r.index==0 ? f1 : r.index==1 ? f2 : f3);
		printf("%s\n%*s", fe.c_str(), (int)r.pos, "");
		if (r.len == 0)
		{
			printf("^--\n");
		}
		else
		{
			for (size_t i = 0; i < r.len; ++i) putchar('~');
			putchar('\n');
		}
	}

	w.plot.update_axis();
	w.redraw();

	if (w.plot.number_of_visible_graphs() > 0 && !w.plot.axis.valid())
	{
		printf("Error: Axis type mismatch.\n");
	}
}

<commit_msg>Graph modes<commit_after>#include "cmd_base.h"

static bool parse_type(const std::string &s0, int &type)
{
	const char *s = s0.c_str();
	char X, Y, n, m; // X^n --> Y^m

	// Syntax:
	// (R|C|S)[[^]\d] [->] (R|C|S)[[^]\d]
	// or R[^k]|C for R^k->R | C->C
	while (isspace(*s)) ++s;
	if (*s!='R' && *s!='C' && *s!='S') return false;
	X = *s++;
	while (isspace(*s)) ++s;
	if (*s=='^')
	{
		++s;
		while (isspace(*s)) ++s;
		if (!isdigit(*s)) return false;
		n = *s++ - '0';
	}
	else if (isdigit(*s))
	{
		n = *s++ - '0';
	}
	else
	{
		n = 1;
	}
	while (isspace(*s)) ++s;
	bool arrow = false;
	if (*s == '-'){ ++s; arrow=true; while (*s == '-') ++s; if (*s != '>') return false; ++s; }
	while (isspace(*s)) ++s;

	if (*s!='R' && *s!='C' && *s!='S')
	{
		if (arrow) return false;
		Y = X; m = 1;
	}
	else
	{
		Y = *s++;
		while (isspace(*s)) ++s;
		if (*s=='^')
		{
			++s;
			while (isspace(*s)) ++s;
			if (!isdigit(*s)) return false;
			m = *s++ - '0';
		}
		else if (isdigit(*s))
		{
			m = *s++ - '0';
		}
		else
		{
			m = 1;
		}
	}
	while (isspace(*s)) ++s;
	if (*s) return false;

	const char *D[] = {"R1R1","R2R1","C1C1", "R1R2","R1R3","S1R2","S1R3", "R2R3","S2R3", "R3R1","R2R2","R3R3", NULL};
	int         T[] = { R_R  , R2_R , C_C  ,  R_R2 , R_R3 , S1_R2, S1_R3,  R2_R3, S2_R3,  R3_R , R2_R2, R3_R3,  -1 };

	for (int i = 0; D[i]; ++i)
	{
		const char *d = D[i];
		if (X==d[0] && Y==d[2] && n+'0' == d[1] && m+'0' == d[3])
		{
			type = T[i];
			return true;
		}
	}

	throw error("Graph type not supported", s0);
}

static bool parse_coord(const std::string &s, int &coord)
{
	if (s == "cart" || s == "cartesian") coord = GC_Cartesian;
	else if (s == "polar") coord = GC_Polar;
	else if (s == "sph" || s == "spherical") coord = GC_Spherical;
	else if (s == "cyl" || s == "cylindrical") coord = GC_Cylindrical;
	else return false;
	return true;
}

static bool parse_mode(const std::string &s, int &mode)
{
	if (s == "graph") mode = GM_Graph;
	else if (s == "image") mode = GM_Image;
	else if (s == "riemann") mode = GM_Riemann;
	else if (s == "vf") mode = GM_VF;
	else if (s == "re") mode = GM_Re;
	else if (s == "im") mode = GM_Im;
	else if (s == "abs") mode = GM_Abs;
	else if (s == "phase") mode = GM_Phase;
	else if (s == "zero" || s == "implicit") mode = GM_Implicit;
	else if (s == "color") mode = GM_Color;
	else if (s == "rcolor") mode = GM_RiemannColor;
	else if (s == "histogram" || s=="hist" || s=="histo") mode = GM_Histogram;
	else return false;
	return true;
}

static bool graph(const std::vector<std::string> &args)
{
	auto i = args.begin();

	bool add = false;
	int type = -1, mode = -1, coord = -1;
	while (i != args.end())
	{
		if (*i == "--")
		{
			++i;
			break;
		}
		else if (!add && (*i == "add" || *i == "new"))
		{
			++i;
			add = true;
		}
		else if (type  < 0 && parse_type (*i, type) ||
		         coord < 0 && parse_coord(*i, coord) ||
		         mode  < 0 && parse_mode (*i, mode))
		{
			++i;
		}
		else break;
	}

	std::vector<Argument> A;
	A.emplace_back((int)add);
	A.emplace_back(type);
	A.emplace_back(coord);
	A.emplace_back(mode);

	// remaining args are the plot expressions
	// they can contain unquoted whitespace, so just concat everything (separator is ';')
	std::string f;
	int nf = 0;
	for (; i != args.end(); ++i)
	{
		const std::string &s = *i;
		if (s.empty()) continue;
		if (!f.empty()) f += ' ';
		size_t i0 = 0, n = s.length();
		while (i0 < n)
		{
			size_t i1 = s.find(';', i0);
			if (i1 == std::string::npos)
			{
				f += s.substr(i0);
				break;
			}
			else
			{
				f += s.substr(i0, i1-i0);
				A.emplace_back(std::move(f)); ++nf;
				f = "";
				i0 = i1+1;
			}
		}
	}
	if (!f.empty())
	{
		A.emplace_back(std::move(f)); ++nf;
	}
	if (nf > 3) return false;

	// remove outer whitespace from the functions
	for (int i = 0; i < nf; ++i)
	{
		auto &s = A[A.size()-nf+i].s;
		size_t n = s.length(), k = 0;
		while (k < n && isspace(s[n-1-k])) ++k;
		if (k) s.erase(n -= k);
		k = 0;
		while (k < n && isspace(s[k])) ++k;
		if (k) s.erase(0, k);
	}

	cmd.send(CID::GRAPH, std::move(A));
	return true;
}

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

CommandInfo ci_graph("graph", "g", CID::GRAPH, graph, "graph [new|add] [domain->range] [re|im|abs|asre|asim] [cart|polar|sph|cyl] [--] [f1|- [; f2|- [; f3|-]]]",
"Changes or prints the modes and expressions for the selected graph.");

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

extern void cmd_ls(const Graph &g, int i, bool selected);

void cmd_graph(PlotWindow &w, Command &cmd)
{
	Graph *cg = w.plot.current_graph();
	if (!cg) throw std::runtime_error("No graph selected");
	Graph &g = *cg;

	int i = 0, na = (int)cmd.args.size();
	bool add = (bool)cmd.get_int(i++);
	int gt = cmd.get_int(i++);
	int gc = cmd.get_int(i++);
	int gm = cmd.get_int(i++);

	if (!add && gt < 0 && gc < 0 && gm < 0 && i == na)
	{
		cmd_ls(g, w.plot.current_graph_index(), false /*it is current, but don't print it here*/);
		return;
	}

	if (add)
	{
		printf("todo...\n");
		return;
	}
	if (gt >= 0) g.type((GraphType)gt);
	if (gc >= 0) g.coords((GraphCoords)gc);
	if (gm >= 0) g.mode((GraphMode)gm);

	//int nc = g.n_components(), nf = na-i;
	//if (nc < 0 || na > nc) throw std::runtime_error(format("Graph only has %d components (%d given)", nc, na));
	std::string f1, f2, f3;
	if (i < na) f1 = cmd.get_str(i++);
	if (i < na) f2 = cmd.get_str(i++);
	if (i < na) f3 = cmd.get_str(i++);

	if (f1.empty() || f1 == "-") f1 = g.f1();
	if (f2.empty() || f2 == "-") f2 = g.f2();
	if (f3.empty() || f3 == "-") f3 = g.f3();

	g.set(f1, f2, f3);
	if (!g.isValid())
	{
		printf("Graph updated, but there were parsing errors:\n");
		Expression *x = g.expression();
		if (!x) throw std::logic_error("NULL expression (this should not happen)");
		const ParsingResult &r = x->result();
		printf("%s. At this point:\n", r.info.c_str());
		std::string &fe = (r.index==0 ? f1 : r.index==1 ? f2 : f3);
		printf("%s\n%*s", fe.c_str(), (int)r.pos, "");
		if (r.len == 0)
		{
			printf("^--\n");
		}
		else
		{
			for (size_t i = 0; i < r.len; ++i) putchar('~');
			putchar('\n');
		}
	}

	w.plot.update_axis();
	w.redraw();

	if (w.plot.number_of_visible_graphs() > 0 && !w.plot.axis.valid())
	{
		printf("Error: Axis type mismatch.\n");
	}
}

<|endoftext|>


<commit_before>#include "Controller.h"
#include "ConfigMessage.h"
#include "System/Config.h"
#include "Framework/Replication/ReplicationConfig.h"
#include "Framework/Replication/PaxosLease/PaxosLease.h"
#include "Application/Common/ContextTransport.h"
#include "Application/Common/ClientSession.h"
#include "Application/Common/ClusterMessage.h"

void Controller::Init()
{
    unsigned        numControllers;
    int64_t         nodeID;
    uint64_t        runID;
    const char*     str;
    Endpoint        endpoint;

    primaryLeaseTimeout.SetCallable(MFUNC(Controller, OnPrimaryLeaseTimeout));

    systemDatabase.Open(configFile.GetValue("database.dir", "db"), "system");
    REPLICATION_CONFIG->Init(systemDatabase.GetTable("system"));

    runID = REPLICATION_CONFIG->GetRunID();
    runID += 1;
    REPLICATION_CONFIG->SetRunID(runID);
    REPLICATION_CONFIG->Commit();

    nodeID = configFile.GetIntValue("nodeID", -1);
    if (nodeID < 0)
        ASSERT_FAIL();

    CONTEXT_TRANSPORT->SetSelfNodeID(nodeID);
    REPLICATION_CONFIG->SetNodeID(nodeID);

    CONTEXT_TRANSPORT->SetClusterContext(this);

    // connect to the controller nodes
    numControllers = (unsigned) configFile.GetListNum("controllers");
    for (nodeID = 0; nodeID < numControllers; nodeID++)
    {
        str = configFile.GetListValue("controllers", nodeID, "");
        endpoint.Set(str);
        CONTEXT_TRANSPORT->AddNode(nodeID, endpoint);
    }

    configState.Init();
    configContext.Init(this, numControllers, systemDatabase.GetTable("paxos"));
    CONTEXT_TRANSPORT->AddQuorumContext(&configContext);

    ReadConfigState();
}

void Controller::Shutdown()
{
    CONTEXT_TRANSPORT->Shutdown();
    REPLICATION_CONFIG->Shutdown();
    systemDatabase.Close();
}

int64_t Controller::GetMaster()
{
    return (int64_t) configContext.GetLeader();
}

uint64_t Controller::GetNodeID()
{
    return REPLICATION_CONFIG->GetNodeID();
}

ConfigState* Controller::GetConfigState()
{
    return &configState;
}

void Controller::OnLearnLease()
{
    configState.hasMaster = true;
    configState.masterID = GetMaster();
    if ((uint64_t) GetMaster() == GetNodeID())
        UpdateListeners();
}

void Controller::OnLeaseTimeout()
{
    ConfigMessage*  itMessage;
    ClientRequest*  itRequest;

    configState.hasMaster = false;
    configState.masterID = 0;

    for (itRequest = requests.First(); itRequest != NULL; itRequest = requests.First())
    {
        requests.Remove(itRequest);
        itRequest->response.NoService();
        itRequest->OnComplete();
    }
    assert(requests.GetLength() == 0);

    for (itRequest = listenRequests.First(); itRequest != NULL; itRequest = listenRequests.First())
    {
        listenRequests.Remove(itRequest);
        itRequest->response.NoService();
        itRequest->OnComplete();
    }
    assert(listenRequests.GetLength() == 0);

    for (itMessage = configMessages.First(); itMessage != NULL; itMessage = configMessages.Delete(itMessage));
    assert(configMessages.GetLength() == 0);
}

void Controller::OnAppend(ConfigMessage& message, bool ownAppend)
{
    ClusterMessage  clusterMessage;

    if (message.type == CONFIGMESSAGE_REGISTER_SHARDSERVER)
    {
        // tell ContextTransport that this connection has a new nodeID
        CONTEXT_TRANSPORT->SetConnectionNodeID(message.endpoint, message.nodeID);
        // tell the shard server
        clusterMessage.SetNodeID(message.nodeID);
        CONTEXT_TRANSPORT->SendClusterMessage(message.nodeID, clusterMessage);
    }

    configState.OnMessage(message);
    WriteConfigState();

    if (ownAppend)
    {
        assert(configMessages.GetLength() > 0);
        assert(configMessages.First()->type == message.type);
        if (configMessages.First()->fromClient)
            SendClientResponse(message);
        configMessages.Delete(configMessages.First());
    }

    if (configContext.IsLeader())
        UpdateListeners();
}

bool Controller::IsValidClientRequest(ClientRequest* request)
{
     return request->IsControllerRequest();
}

void Controller::OnClientRequest(ClientRequest* request)
{
    ConfigMessage*  message;

    if (request->type == CLIENTREQUEST_GET_MASTER)
    {
        if (configContext.IsLeaderKnown())
            request->response.Number(configContext.GetLeader());
        else
            request->response.NoService();

        request->OnComplete();
        return;
    }
    else if (request->type == CLIENTREQUEST_GET_CONFIG_STATE)
    {
        listenRequests.Append(request);
        request->response.GetConfigStateResponse(&configState);
        request->OnComplete(false);
        return;
    }

    message = new ConfigMessage;
    FromClientRequest(request, message);

    if (!configState.CompleteMessage(*message))
    {
        delete message;
        request->response.Failed();
        request->OnComplete();
        return;
    }

    requests.Append(request);
    configMessages.Append(message);
    TryAppend();
}

void Controller::OnClientClose(ClientSession* session)
{
    ClientRequest*  it;
    ClientRequest*  next;

    for (it = listenRequests.First(); it != NULL; it = next)
    {
        next = listenRequests.Next(it);
        if (it->session == session)
        {
            listenRequests.Remove(it);
            it->OnComplete();
        }
    }
}

void Controller::OnClusterMessage(uint64_t /*nodeID*/, ClusterMessage& message)
{
    if (!configContext.IsLeader())
        return;

    switch (message.type)
    {
        case CLUSTERMESSAGE_SET_NODEID:
            ASSERT_FAIL();
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            ASSERT_FAIL();
        case CLUSTERMESSAGE_REQUEST_LEASE:
            OnRequestLease(message);
            break;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            ASSERT_FAIL();
    }
}

void Controller::OnIncomingConnectionReady(uint64_t nodeID, Endpoint endpoint)
{
    ClusterMessage      clusterMessage;
    ConfigShardServer*  shardServer;

    // if it's a shard server, send the configState
    if (nodeID >= CONFIG_MIN_SHARD_NODE_ID)
    {
        // TODO: send shutdown message in case of bad configuration
        shardServer = configState.GetShardServer(nodeID);
        if (shardServer == NULL)
            return;

        if (shardServer->endpoint != endpoint)
        {
            Log_Message("Badly configured shard server trying to connect"
             ", nodeID: %" PRIu64
             ", endpoint: %s",
             nodeID, endpoint.ToString());

            return;
        }

        clusterMessage.SetConfigState(&configState);
        CONTEXT_TRANSPORT->SendClusterMessage(nodeID, clusterMessage);
    }
}

bool Controller::OnAwaitingNodeID(Endpoint endpoint)
{
    ConfigShardServer*              shardServer;
    ConfigState::ShardServerList*   shardServers;
    ClusterMessage                  clusterMessage;

    if (!configContext.IsLeader())
        return true; // drop connection

    // look for existing endpoint
    shardServers = &configState.shardServers;
    for (shardServer = shardServers->First(); shardServer != NULL; shardServer = shardServers->Next(shardServer))
    {
        if (shardServer->endpoint == endpoint)
        {
            // tell ContextTransport that this connection has a new nodeID
            CONTEXT_TRANSPORT->SetConnectionNodeID(endpoint, shardServer->nodeID);

            // tell the shard server
            clusterMessage.SetNodeID(shardServer->nodeID);
            CONTEXT_TRANSPORT->SendClusterMessage(shardServer->nodeID, clusterMessage);

            // send config state
            clusterMessage.SetConfigState(&configState);
            CONTEXT_TRANSPORT->SendClusterMessage(shardServer->nodeID, clusterMessage);
            return false;
        }
    }

    TryRegisterShardServer(endpoint);
    return false;
}

void Controller::TryAppend()
{
    if (!configContext.IsAppending())
        configContext.Append(configMessages.First());
}

void Controller::FromClientRequest(ClientRequest* request, ConfigMessage* message)
{
    message->fromClient = true;

    switch (request->type)
    {
        case CLIENTREQUEST_CREATE_QUORUM:
            message->type = CONFIGMESSAGE_CREATE_QUORUM;
            message->productionType = request->productionType;
            message->nodes = request->nodes;
            return;
        case CLIENTREQUEST_CREATE_DATABASE:
            message->type = CONFIGMESSAGE_CREATE_DATABASE;
            message->name.Wrap(request->name);
            message->productionType = request->productionType;
            return;
        case CLIENTREQUEST_RENAME_DATABASE:
            message->type = CONFIGMESSAGE_RENAME_DATABASE;
            message->databaseID = request->databaseID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_DELETE_DATABASE:
            message->type = CONFIGMESSAGE_DELETE_DATABASE;
            message->databaseID = request->databaseID;
            return;
        case CLIENTREQUEST_CREATE_TABLE:
            message->type = CONFIGMESSAGE_CREATE_TABLE;
            message->databaseID = request->databaseID;
            message->quorumID = request->quorumID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_RENAME_TABLE:
            message->type = CONFIGMESSAGE_RENAME_TABLE;
            message->databaseID = request->databaseID;
            message->tableID = request->tableID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_DELETE_TABLE:
            message->type = CONFIGMESSAGE_DELETE_TABLE;
            message->databaseID = request->databaseID;
            message->tableID = request->tableID;
            return;
        default:
            ASSERT_FAIL();
    }
}

void Controller::ToClientResponse(ConfigMessage* message, ClientResponse* response)
{
    switch (response->request->type)
    {
        case CLIENTREQUEST_CREATE_QUORUM:
            response->Number(message->quorumID);
            return;
        case CLIENTREQUEST_CREATE_DATABASE:
            response->Number(message->databaseID);
            return;
        case CLIENTREQUEST_RENAME_DATABASE:
            response->OK();
            return;
        case CLIENTREQUEST_DELETE_DATABASE:
            response->OK();
            return;
        case CLIENTREQUEST_CREATE_TABLE:
            response->Number(message->tableID);
            return;
        case CLIENTREQUEST_RENAME_TABLE:
            response->OK();
            return;
        case CLIENTREQUEST_DELETE_TABLE:
            response->OK();
            return;
        default:
            ASSERT_FAIL();
    }
}

void Controller::OnPrimaryLeaseTimeout()
{
    uint64_t        now;
    ConfigQuorum*   quorum;
    PrimaryLease*   itLease;

    now = EventLoop::Now();

    for (itLease = primaryLeases.First(); itLease != NULL; /* advanced in body */)
    {
        if (itLease->expireTime < now)
        {
            quorum = configState.GetQuorum(itLease->quorumID);
            quorum->hasPrimary = false;
            quorum->primaryID = 0;
            itLease = primaryLeases.Delete(itLease);
        }
        else
            break;
    }

    UpdatePrimaryLeaseTimer();
    UpdateListeners();
}

void Controller::TryRegisterShardServer(Endpoint& endpoint)
{
    ConfigMessage*      message;

    message = new ConfigMessage;
    message->fromClient = false;
    message->RegisterShardServer(0, endpoint);
    if (!configState.CompleteMessage(*message))
        ASSERT_FAIL();

    configMessages.Append(message);
    TryAppend();
}

void Controller::ReadConfigState()
{
    bool        ret;
    ReadBuffer  value;

    ret =  true;
    ret &= systemDatabase.GetTable("config")->Get(ReadBuffer("state"), value);
    ret &= configState.Read(value);
    if (!ret)
        Log_Message("Starting with empty database...");

    Log_Trace("%.*s", P(&value));
}

void Controller::WriteConfigState()
{
    configState.Write(configStateBuffer);
    systemDatabase.GetTable("config")->Set(ReadBuffer("state"), ReadBuffer(configStateBuffer));
    systemDatabase.Commit();
}

void Controller::SendClientResponse(ConfigMessage& message)
{
    ClientRequest* request;

    assert(requests.GetLength() > 0);

    request = requests.First();
    requests.Remove(request);

    ToClientResponse(&message, &request->response);
    request->OnComplete();

}

void Controller::OnRequestLease(ClusterMessage& message)
{
    uint64_t*       it;
    ConfigQuorum*   quorum;

    quorum = configState.GetQuorum(message.quorumID);

    if (quorum == NULL)
    {
        Log_Trace("nodeID " PRIu64 " requesting lease for non-existing quorum %" PRIu64 "",
         message.nodeID, message.quorumID);
        return;
    }

    if (quorum->hasPrimary)
    {
        if (quorum->primaryID != message.nodeID)
            return;
        else
            return ExtendPrimaryLease(*quorum, message);
    }

    for (it = quorum->activeNodes.First(); it != NULL; it = quorum->activeNodes.Next(it))
    {
        if (*it == message.nodeID)
            break;
    }

    if (it == NULL)
    {
        Log_Trace("nodeID " PRIu64 " requesting lease but not active member or quorum %" PRIu64 "",
         message.nodeID, message.quorumID);
        return;
    }

    AssignPrimaryLease(*quorum, message);
}

void Controller::AssignPrimaryLease(ConfigQuorum& quorum, ClusterMessage& message)
{
    unsigned        duration;
    PrimaryLease*   primaryLease;
    ClusterMessage  response;

    quorum.hasPrimary = true;
    quorum.primaryID = message.nodeID;

    primaryLease = new PrimaryLease;
    primaryLease->quorumID = quorum.quorumID;
    primaryLease->nodeID = quorum.primaryID;
    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);
    primaryLease->expireTime = EventLoop::Now() + duration;
    primaryLeases.Add(primaryLease);

    UpdatePrimaryLeaseTimer();

    response.ReceiveLease(message.nodeID, message.quorumID, message.proposalID, duration);
    CONTEXT_TRANSPORT->SendClusterMessage(response.nodeID, response);
}

void Controller::ExtendPrimaryLease(ConfigQuorum& quorum, ClusterMessage& message)
{
    unsigned        duration;
    PrimaryLease*   it;
    ClusterMessage  response;

    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);

    for (it = primaryLeases.First(); it != NULL; it = primaryLeases.Next(it))
    {
        if (it->quorumID == quorum.quorumID)
            break;
    }

    assert(it != NULL);

    primaryLeases.Remove(it);
    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);
    it->expireTime = EventLoop::Now() + duration;
    primaryLeases.Add(it);
    UpdatePrimaryLeaseTimer();

    response.ReceiveLease(message.nodeID, message.quorumID, message.proposalID, duration);
    CONTEXT_TRANSPORT->SendClusterMessage(response.nodeID, response);
}

void Controller::UpdatePrimaryLeaseTimer()
{
    PrimaryLease* primaryLease;

    primaryLease = primaryLeases.First();
    if (!primaryLease)
        return;

    if (!primaryLeaseTimeout.IsActive() ||
     primaryLease->expireTime < primaryLeaseTimeout.GetExpireTime())
    {
        EventLoop::Remove(&primaryLeaseTimeout);
        primaryLeaseTimeout.SetExpireTime(primaryLease->expireTime);
        EventLoop::Add(&primaryLeaseTimeout);
    }
}

void Controller::UpdateListeners()
{
    ClientRequest*                  itRequest;
    ConfigShardServer*              itShardServer;
    ConfigState::ShardServerList*   shardServers;
    ClusterMessage                  message;

    // update clients
    for (itRequest = listenRequests.First(); itRequest != NULL; itRequest = listenRequests.Next(itRequest))
    {
        itRequest->response.GetConfigStateResponse(&configState);
        itRequest->OnComplete(false);
    }

    // update shard servers
    message.SetConfigState(&configState);
    shardServers = &configState.shardServers;
    for (itShardServer = shardServers->First();
     itShardServer != NULL;
     itShardServer = shardServers->Next(itShardServer))
    {
        CONTEXT_TRANSPORT->SendClusterMessage(itShardServer->nodeID, message);
    }
}
<commit_msg>Fixed bugs.<commit_after>#include "Controller.h"
#include "ConfigMessage.h"
#include "System/Config.h"
#include "Framework/Replication/ReplicationConfig.h"
#include "Framework/Replication/PaxosLease/PaxosLease.h"
#include "Application/Common/ContextTransport.h"
#include "Application/Common/ClientSession.h"
#include "Application/Common/ClusterMessage.h"

void Controller::Init()
{
    unsigned        numControllers;
    int64_t         nodeID;
    uint64_t        runID;
    const char*     str;
    Endpoint        endpoint;

    primaryLeaseTimeout.SetCallable(MFUNC(Controller, OnPrimaryLeaseTimeout));

    systemDatabase.Open(configFile.GetValue("database.dir", "db"), "system");
    REPLICATION_CONFIG->Init(systemDatabase.GetTable("system"));

    runID = REPLICATION_CONFIG->GetRunID();
    runID += 1;
    REPLICATION_CONFIG->SetRunID(runID);
    REPLICATION_CONFIG->Commit();

    nodeID = configFile.GetIntValue("nodeID", -1);
    if (nodeID < 0)
        ASSERT_FAIL();

    CONTEXT_TRANSPORT->SetSelfNodeID(nodeID);
    REPLICATION_CONFIG->SetNodeID(nodeID);

    CONTEXT_TRANSPORT->SetClusterContext(this);

    // connect to the controller nodes
    numControllers = (unsigned) configFile.GetListNum("controllers");
    for (nodeID = 0; nodeID < numControllers; nodeID++)
    {
        str = configFile.GetListValue("controllers", nodeID, "");
        endpoint.Set(str);
        CONTEXT_TRANSPORT->AddNode(nodeID, endpoint);
    }

    configState.Init();
    configContext.Init(this, numControllers, systemDatabase.GetTable("paxos"));
    CONTEXT_TRANSPORT->AddQuorumContext(&configContext);

    ReadConfigState();
}

void Controller::Shutdown()
{
    CONTEXT_TRANSPORT->Shutdown();
    REPLICATION_CONFIG->Shutdown();
    systemDatabase.Close();
}

int64_t Controller::GetMaster()
{
    return (int64_t) configContext.GetLeader();
}

uint64_t Controller::GetNodeID()
{
    return REPLICATION_CONFIG->GetNodeID();
}

ConfigState* Controller::GetConfigState()
{
    return &configState;
}

void Controller::OnLearnLease()
{
    configState.hasMaster = true;
    configState.masterID = GetMaster();
    if ((uint64_t) GetMaster() == GetNodeID())
        UpdateListeners();
}

void Controller::OnLeaseTimeout()
{
    ConfigMessage*  itMessage;
    ClientRequest*  itRequest;

    configState.hasMaster = false;
    configState.masterID = 0;

    for (itRequest = requests.First(); itRequest != NULL; itRequest = requests.First())
    {
        requests.Remove(itRequest);
        itRequest->response.NoService();
        itRequest->OnComplete();
    }
    assert(requests.GetLength() == 0);

    for (itRequest = listenRequests.First(); itRequest != NULL; itRequest = listenRequests.First())
    {
        listenRequests.Remove(itRequest);
        itRequest->response.NoService();
        itRequest->OnComplete();
    }
    assert(listenRequests.GetLength() == 0);

    for (itMessage = configMessages.First(); itMessage != NULL; itMessage = configMessages.Delete(itMessage));
    assert(configMessages.GetLength() == 0);
}

void Controller::OnAppend(ConfigMessage& message, bool ownAppend)
{
    ClusterMessage  clusterMessage;

    if (message.type == CONFIGMESSAGE_REGISTER_SHARDSERVER)
    {
        // tell ContextTransport that this connection has a new nodeID
        CONTEXT_TRANSPORT->SetConnectionNodeID(message.endpoint, message.nodeID);
        // tell the shard server
        clusterMessage.SetNodeID(message.nodeID);
        CONTEXT_TRANSPORT->SendClusterMessage(message.nodeID, clusterMessage);
    }

    configState.OnMessage(message);
    WriteConfigState();

    if (ownAppend)
    {
        assert(configMessages.GetLength() > 0);
        assert(configMessages.First()->type == message.type);
        if (configMessages.First()->fromClient)
            SendClientResponse(message);
        configMessages.Delete(configMessages.First());
    }

    if (configContext.IsLeader())
        UpdateListeners();
}

bool Controller::IsValidClientRequest(ClientRequest* request)
{
     return request->IsControllerRequest();
}

void Controller::OnClientRequest(ClientRequest* request)
{
    ConfigMessage*  message;

    if (request->type == CLIENTREQUEST_GET_MASTER)
    {
        if (configContext.IsLeaderKnown())
            request->response.Number(configContext.GetLeader());
        else
            request->response.NoService();

        request->OnComplete();
        return;
    }
    else if (request->type == CLIENTREQUEST_GET_CONFIG_STATE)
    {
        listenRequests.Append(request);
        request->response.GetConfigStateResponse(&configState);
        request->OnComplete(false);
        return;
    }

    message = new ConfigMessage;
    FromClientRequest(request, message);

    if (!configState.CompleteMessage(*message))
    {
        delete message;
        request->response.Failed();
        request->OnComplete();
        return;
    }

    requests.Append(request);
    configMessages.Append(message);
    TryAppend();
}

void Controller::OnClientClose(ClientSession* session)
{
    ClientRequest*  it;
    ClientRequest*  next;

    for (it = listenRequests.First(); it != NULL; it = next)
    {
        next = listenRequests.Next(it);
        if (it->session == session)
        {
            listenRequests.Remove(it);
            it->OnComplete();
        }
    }
}

void Controller::OnClusterMessage(uint64_t /*nodeID*/, ClusterMessage& message)
{
    if (!configContext.IsLeader())
        return;

    switch (message.type)
    {
        case CLUSTERMESSAGE_SET_NODEID:
            ASSERT_FAIL();
        case CLUSTERMESSAGE_SET_CONFIG_STATE:
            ASSERT_FAIL();
        case CLUSTERMESSAGE_REQUEST_LEASE:
            OnRequestLease(message);
            break;
        case CLUSTERMESSAGE_RECEIVE_LEASE:
            ASSERT_FAIL();
    }
}

void Controller::OnIncomingConnectionReady(uint64_t nodeID, Endpoint endpoint)
{
    ClusterMessage      clusterMessage;
    ConfigShardServer*  shardServer;

    // if it's a shard server, send the configState
    if (nodeID >= CONFIG_MIN_SHARD_NODE_ID)
    {
        // TODO: send shutdown message in case of bad configuration
        shardServer = configState.GetShardServer(nodeID);
        if (shardServer == NULL)
            return;

        if (shardServer->endpoint != endpoint)
        {
            Log_Message("Badly configured shard server trying to connect"
             ", nodeID: %" PRIu64
             ", endpoint: %s",
             nodeID, endpoint.ToString());

            return;
        }

        clusterMessage.SetConfigState(&configState);
        CONTEXT_TRANSPORT->SendClusterMessage(nodeID, clusterMessage);
    }
}

bool Controller::OnAwaitingNodeID(Endpoint endpoint)
{
    ConfigShardServer*              shardServer;
    ConfigState::ShardServerList*   shardServers;
    ClusterMessage                  clusterMessage;

    if (!configContext.IsLeader())
        return true; // drop connection

    // look for existing endpoint
    shardServers = &configState.shardServers;
    for (shardServer = shardServers->First(); shardServer != NULL; shardServer = shardServers->Next(shardServer))
    {
        if (shardServer->endpoint == endpoint)
        {
            // tell ContextTransport that this connection has a new nodeID
            CONTEXT_TRANSPORT->SetConnectionNodeID(endpoint, shardServer->nodeID);

            // tell the shard server
            clusterMessage.SetNodeID(shardServer->nodeID);
            CONTEXT_TRANSPORT->SendClusterMessage(shardServer->nodeID, clusterMessage);

            // send config state
            clusterMessage.SetConfigState(&configState);
            CONTEXT_TRANSPORT->SendClusterMessage(shardServer->nodeID, clusterMessage);
            return false;
        }
    }

    TryRegisterShardServer(endpoint);
    return false;
}

void Controller::TryAppend()
{
    if (!configContext.IsAppending())
        configContext.Append(configMessages.First());
}

void Controller::FromClientRequest(ClientRequest* request, ConfigMessage* message)
{
    message->fromClient = true;

    switch (request->type)
    {
        case CLIENTREQUEST_CREATE_QUORUM:
            message->type = CONFIGMESSAGE_CREATE_QUORUM;
            message->productionType = request->productionType;
            message->nodes = request->nodes;
            return;
        case CLIENTREQUEST_CREATE_DATABASE:
            message->type = CONFIGMESSAGE_CREATE_DATABASE;
            message->name.Wrap(request->name);
            message->productionType = request->productionType;
            return;
        case CLIENTREQUEST_RENAME_DATABASE:
            message->type = CONFIGMESSAGE_RENAME_DATABASE;
            message->databaseID = request->databaseID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_DELETE_DATABASE:
            message->type = CONFIGMESSAGE_DELETE_DATABASE;
            message->databaseID = request->databaseID;
            return;
        case CLIENTREQUEST_CREATE_TABLE:
            message->type = CONFIGMESSAGE_CREATE_TABLE;
            message->databaseID = request->databaseID;
            message->quorumID = request->quorumID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_RENAME_TABLE:
            message->type = CONFIGMESSAGE_RENAME_TABLE;
            message->databaseID = request->databaseID;
            message->tableID = request->tableID;
            message->name.Wrap(request->name);
            return;
        case CLIENTREQUEST_DELETE_TABLE:
            message->type = CONFIGMESSAGE_DELETE_TABLE;
            message->databaseID = request->databaseID;
            message->tableID = request->tableID;
            return;
        default:
            ASSERT_FAIL();
    }
}

void Controller::ToClientResponse(ConfigMessage* message, ClientResponse* response)
{
    switch (response->request->type)
    {
        case CLIENTREQUEST_CREATE_QUORUM:
            response->Number(message->quorumID);
            return;
        case CLIENTREQUEST_CREATE_DATABASE:
            response->Number(message->databaseID);
            return;
        case CLIENTREQUEST_RENAME_DATABASE:
            response->OK();
            return;
        case CLIENTREQUEST_DELETE_DATABASE:
            response->OK();
            return;
        case CLIENTREQUEST_CREATE_TABLE:
            response->Number(message->tableID);
            return;
        case CLIENTREQUEST_RENAME_TABLE:
            response->OK();
            return;
        case CLIENTREQUEST_DELETE_TABLE:
            response->OK();
            return;
        default:
            ASSERT_FAIL();
    }
}

void Controller::OnPrimaryLeaseTimeout()
{
    uint64_t        now;
    ConfigQuorum*   quorum;
    PrimaryLease*   itLease;

    now = EventLoop::Now();

    for (itLease = primaryLeases.First(); itLease != NULL; /* advanced in body */)
    {
        if (itLease->expireTime < now)
        {
            quorum = configState.GetQuorum(itLease->quorumID);
            quorum->hasPrimary = false;
            quorum->primaryID = 0;
            itLease = primaryLeases.Delete(itLease);
        }
        else
            break;
    }

    UpdatePrimaryLeaseTimer();
    UpdateListeners();
}

void Controller::TryRegisterShardServer(Endpoint& endpoint)
{
    ConfigMessage*      message;

    message = new ConfigMessage;
    message->fromClient = false;
    message->RegisterShardServer(0, endpoint);
    if (!configState.CompleteMessage(*message))
        ASSERT_FAIL();

    configMessages.Append(message);
    TryAppend();
}

void Controller::ReadConfigState()
{
    bool        ret;
    ReadBuffer  value;

    ret =  true;
    ret &= systemDatabase.GetTable("config")->Get(ReadBuffer("state"), value);
    ret &= configState.Read(value);
    if (!ret)
        Log_Message("Starting with empty database...");

    Log_Trace("%.*s", P(&value));
}

void Controller::WriteConfigState()
{
    configState.Write(configStateBuffer);
    systemDatabase.GetTable("config")->Set(ReadBuffer("state"), ReadBuffer(configStateBuffer));
    systemDatabase.Commit();
}

void Controller::SendClientResponse(ConfigMessage& message)
{
    ClientRequest* request;

    assert(requests.GetLength() > 0);

    request = requests.First();
    requests.Remove(request);

    ToClientResponse(&message, &request->response);
    request->OnComplete();

}

void Controller::OnRequestLease(ClusterMessage& message)
{
    uint64_t*       it;
    ConfigQuorum*   quorum;

    quorum = configState.GetQuorum(message.quorumID);

    if (quorum == NULL)
    {
        Log_Trace("nodeID " PRIu64 " requesting lease for non-existing quorum %" PRIu64 "",
         message.nodeID, message.quorumID);
        return;
    }

    if (quorum->hasPrimary)
    {
        if (quorum->primaryID == message.nodeID)
            ExtendPrimaryLease(*quorum, message);
        return;
    }

    for (it = quorum->activeNodes.First(); it != NULL; it = quorum->activeNodes.Next(it))
    {
        if (*it == message.nodeID)
            break;
    }

    if (it == NULL)
    {
        Log_Trace("nodeID " PRIu64 " requesting lease but not active member or quorum %" PRIu64 "",
         message.nodeID, message.quorumID);
        return;
    }

    AssignPrimaryLease(*quorum, message);
}

void Controller::AssignPrimaryLease(ConfigQuorum& quorum, ClusterMessage& message)
{
    unsigned        duration;
    PrimaryLease*   primaryLease;
    ClusterMessage  response;

    quorum.hasPrimary = true;
    quorum.primaryID = message.nodeID;

    primaryLease = new PrimaryLease;
    primaryLease->quorumID = quorum.quorumID;
    primaryLease->nodeID = quorum.primaryID;
    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);
    primaryLease->expireTime = EventLoop::Now() + duration;
    primaryLeases.Add(primaryLease);

    UpdatePrimaryLeaseTimer();

    response.ReceiveLease(message.nodeID, message.quorumID, message.proposalID, duration);
    CONTEXT_TRANSPORT->SendClusterMessage(response.nodeID, response);
}

void Controller::ExtendPrimaryLease(ConfigQuorum& quorum, ClusterMessage& message)
{
    unsigned        duration;
    PrimaryLease*   it;
    ClusterMessage  response;

    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);

    for (it = primaryLeases.First(); it != NULL; it = primaryLeases.Next(it))
    {
        if (it->quorumID == quorum.quorumID)
            break;
    }

    assert(it != NULL);

    primaryLeases.Remove(it);
    duration = MIN(message.duration, PAXOSLEASE_MAX_LEASE_TIME);
    it->expireTime = EventLoop::Now() + duration;
    primaryLeases.Add(it);
    UpdatePrimaryLeaseTimer();

    response.ReceiveLease(message.nodeID, message.quorumID, message.proposalID, duration);
    CONTEXT_TRANSPORT->SendClusterMessage(response.nodeID, response);
}

void Controller::UpdatePrimaryLeaseTimer()
{
    PrimaryLease* primaryLease;

    primaryLease = primaryLeases.First();
    if (!primaryLease)
        return;

    if (!primaryLeaseTimeout.IsActive() ||
     primaryLease->expireTime < primaryLeaseTimeout.GetExpireTime())
    {
        EventLoop::Remove(&primaryLeaseTimeout);
        primaryLeaseTimeout.SetExpireTime(primaryLease->expireTime);
        EventLoop::Add(&primaryLeaseTimeout);
    }
}

void Controller::UpdateListeners()
{
    ClientRequest*                  itRequest;
    ConfigShardServer*              itShardServer;
    ConfigState::ShardServerList*   shardServers;
    ClusterMessage                  message;

    // update clients
    for (itRequest = listenRequests.First(); itRequest != NULL; itRequest = listenRequests.Next(itRequest))
    {
        itRequest->response.GetConfigStateResponse(&configState);
        itRequest->OnComplete(false);
    }

    // update shard servers
    message.SetConfigState(&configState);
    shardServers = &configState.shardServers;
    for (itShardServer = shardServers->First();
     itShardServer != NULL;
     itShardServer = shardServers->Next(itShardServer))
    {
        CONTEXT_TRANSPORT->SendClusterMessage(itShardServer->nodeID, message);
    }
}
<|endoftext|>


<commit_before>#include "Board.h"
#include "Pawn.h"
#include "Rook.h"
#include "Knight.h"
#include "Bishop.h"
#include "Queen.h"
#include "King.h"

namespace Chess {
	Board::Board() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				pieces[x][y] = nullptr;
			}
		}

		// Black pawns
		for (int x = 0; x < 8; x++) {
			pieces[x][6] = new Pawn(Position(x, 6), false);
		}

		// White pawns
		for (int x = 0; x < 8; x++) {
			pieces[x][1] = new Pawn(Position(x, 1), true);
		}

		// Rooks
		pieces[0][7] = new Rook(Position(0, 7), false);
		pieces[7][7] = new Rook(Position(7, 7), false);
		pieces[0][0] = new Rook(Position(0, 0), true);
		pieces[7][0] = new Rook(Position(7, 0), true);

		// Knights
		pieces[1][7] = new Knight(Position(1, 7), false);
		pieces[6][7] = new Knight(Position(6, 7), false);
		pieces[1][0] = new Knight(Position(1, 0), true);
		pieces[6][0] = new Knight(Position(6, 0), true);

		// Bishops
		pieces[2][7] = new Bishop(Position(2, 7), false);
		pieces[5][7] = new Bishop(Position(5, 7), false);
		pieces[2][0] = new Bishop(Position(2, 0), true);
		pieces[5][0] = new Bishop(Position(5, 0), true);

		// Queens
		pieces[3][7] = new Queen(Position(3, 7), false);
		pieces[3][0] = new Queen(Position(3, 0), true);

		// Kings
		blackKing = new King(Position(4, 7), false);
		pieces[4][7] = blackKing;
		whiteKing = new King(Position(4, 0), true);
		pieces[4][0] = whiteKing;
	}

	Board::~Board() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				if (pieces[x][y] != nullptr)
					delete pieces[x][y];
			}
		}
	}

	Piece* Board::getPiece(const Position& position) const {
		return pieces[position.x][position.y];
	}

	bool Board::move(const Position& oldPosition, const Position& newPosition) {
		Piece* piece = getPiece(oldPosition);

		if (piece != nullptr) {
			// Check if the piece is of the right color.
			if (piece->isWhite() == (turn % 2 == 0)) {
				// Check if the move is legal.
				if (piece->isLegal(*this, newPosition)) {
					pieces[oldPosition.x][oldPosition.y] = nullptr;

					// Delete captured piece.
					if (pieces[newPosition.x][newPosition.y] != nullptr)
						delete pieces[newPosition.x][newPosition.y];

					// TODO: En passant.

					pieces[newPosition.x][newPosition.y] = piece;
					piece->move(newPosition);

					// TODO: Castling, promotion, pawn double move.

					turn++;
					return true;
				}
			}
		}

		return false;
	}
}<commit_msg>Reintroduced state transition.<commit_after>#include "Board.h"
#include "Pawn.h"
#include "Rook.h"
#include "Knight.h"
#include "Bishop.h"
#include "Queen.h"
#include "King.h"

namespace Chess {
	Board::Board() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				pieces[x][y] = nullptr;
			}
		}

		// Black pawns
		for (int x = 0; x < 8; x++) {
			pieces[x][6] = new Pawn(Position(x, 6), false);
		}

		// White pawns
		for (int x = 0; x < 8; x++) {
			pieces[x][1] = new Pawn(Position(x, 1), true);
		}

		// Rooks
		pieces[0][7] = new Rook(Position(0, 7), false);
		pieces[7][7] = new Rook(Position(7, 7), false);
		pieces[0][0] = new Rook(Position(0, 0), true);
		pieces[7][0] = new Rook(Position(7, 0), true);

		// Knights
		pieces[1][7] = new Knight(Position(1, 7), false);
		pieces[6][7] = new Knight(Position(6, 7), false);
		pieces[1][0] = new Knight(Position(1, 0), true);
		pieces[6][0] = new Knight(Position(6, 0), true);

		// Bishops
		pieces[2][7] = new Bishop(Position(2, 7), false);
		pieces[5][7] = new Bishop(Position(5, 7), false);
		pieces[2][0] = new Bishop(Position(2, 0), true);
		pieces[5][0] = new Bishop(Position(5, 0), true);

		// Queens
		pieces[3][7] = new Queen(Position(3, 7), false);
		pieces[3][0] = new Queen(Position(3, 0), true);

		// Kings
		blackKing = new King(Position(4, 7), false);
		pieces[4][7] = blackKing;
		whiteKing = new King(Position(4, 0), true);
		pieces[4][0] = whiteKing;
	}

	Board::~Board() {
		for (int x = 0; x < 8; x++) {
			for (int y = 0; y < 8; y++) {
				if (pieces[x][y] != nullptr)
					delete pieces[x][y];
			}
		}
	}

	Piece* Board::getPiece(const Position& position) const {
		return pieces[position.x][position.y];
	}

	bool Board::move(const Position& oldPosition, const Position& newPosition) {
		Piece* piece = getPiece(oldPosition);

		if (piece != nullptr) {
			// Check if the piece is of the right color.
			if (piece->isWhite() == (turn % 2 == 0)) {
				// Check if the move is legal.
				if (piece->isLegal(*this, newPosition)) {
					pieces[oldPosition.x][oldPosition.y] = nullptr;

					// Delete captured piece.
					if (pieces[newPosition.x][newPosition.y] != nullptr)
						delete pieces[newPosition.x][newPosition.y];

					// TODO: En passant.

					pieces[newPosition.x][newPosition.y] = piece;
					piece->move(newPosition);

					// TODO: Castling, promotion, pawn double move.

					turn++;
					if (state == GameState::BLACKPLAYS)
						state = GameState::WHITEPLAYS;
					else
						state = GameState::BLACKPLAYS;
					return true;
				}
			}
		}

		return false;
	}
}<|endoftext|>


<commit_before>/*
*	ExtraWork Client - Loads an ExtraWork DLL for information
*	Copyright (C) 2014  xboi209 (xboi209@gmail.com)
*
*	This program 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.
*
*	This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <Windows.h>
#include <iostream>
#include <cstdlib>

using namespace std;

struct EXTRAWORK
{
	WORD GameType;
	WORD Length;
	char OutBuffer[1024];
};

typedef BOOL(__fastcall *ExtraWorkProc)(void *);

enum GameType
{
	Diablo2 = 0x1,
	Warcraft3 = 0x2,
	Starcraft = 0x3,
	WorldOfWarcraft = 0x4
};

//Example:	Client IX86ExtraWork.dll 0x3 4
//			Program DLL Gametype Length
int main(int argc, char ** argv)
{
	HINSTANCE		hLib;
	ExtraWorkProc	lpfnExtraWork;
	BOOL			bReturn;
	EXTRAWORK		ew;

	if (argc == 1)
	{
		argv[1] = "IX86ExtraWork.dll";
		argv[2] = "0x3";
		argv[3] = "4";
	}
	else if (argc != 1 && argc != 4)
	{
		cout << "Invalid number of arguments" << endl;
		return 0;
	}

	hLib = LoadLibrary(argv[1]);

	bool success = false;
	if (hLib)
	{
		lpfnExtraWork = (ExtraWorkProc)GetProcAddress(hLib, "ExtraWork");
		ew.GameType = (WORD)strtoul(argv[2], NULL, 16);
		ew.Length = atoi(argv[3]);
		*ew.OutBuffer = 0;

		if (lpfnExtraWork)
		{
			bReturn = (*lpfnExtraWork)(&ew);

			cout << "ExtraWork returned " << (bReturn ? "TRUE" : "FALSE") << endl;
			cout << "GameType: " << ew.GameType << "\t\t" << "Length: " << ew.Length << endl << endl;
			cout << "Message: " << ew.OutBuffer << endl;

			success = true;
		}
		FreeLibrary(hLib);
	}

	if (!success)
		cout << "Could not load " << argv[1] << endl;

	return 0;
}<commit_msg>Comment<commit_after>/*
*	ExtraWork Client - Loads an ExtraWork DLL for information
*	Copyright (C) 2014  xboi209 (xboi209@gmail.com)
*
*	This program 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.
*
*	This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <Windows.h>
#include <iostream>
#include <cstdlib>

using namespace std;

struct EXTRAWORK
{
	WORD GameType;
	WORD Length;
	char OutBuffer[1024];
};

typedef BOOL(__fastcall *ExtraWorkProc)(void *);

enum GameType
{
	Diablo2 = 0x1,
	Warcraft3 = 0x2,
	Starcraft = 0x3,
	WorldOfWarcraft = 0x4
};

//Example:	Client IX86ExtraWork.dll 0x3 4
//		Program DLL Gametype Length
int main(int argc, char ** argv)
{
	HINSTANCE		hLib;
	ExtraWorkProc	lpfnExtraWork;
	BOOL			bReturn;
	EXTRAWORK		ew;

	if (argc == 1)
	{
		//Default values if no arguments are passed
		argv[1] = "IX86ExtraWork.dll";
		argv[2] = "0x3";
		argv[3] = "4";
	}
	else if (argc != 1 && argc != 4)
	{
		cout << "Invalid number of arguments" << endl;
		return 0;
	}

	hLib = LoadLibrary(argv[1]);

	bool success = false;
	if (hLib)
	{
		lpfnExtraWork = (ExtraWorkProc)GetProcAddress(hLib, "ExtraWork");
		ew.GameType = (WORD)strtoul(argv[2], NULL, 16);
		ew.Length = atoi(argv[3]);
		*ew.OutBuffer = 0;

		if (lpfnExtraWork)
		{
			bReturn = (*lpfnExtraWork)(&ew);

			cout << "ExtraWork returned " << (bReturn ? "TRUE" : "FALSE") << endl;
			cout << "GameType: " << ew.GameType << "\t\t" << "Length: " << ew.Length << endl << endl;
			cout << "Message: " << ew.OutBuffer << endl;

			success = true;
		}
		FreeLibrary(hLib);
	}

	if (!success)
		cout << "Could not load " << argv[1] << endl;

	return 0;
}
<|endoftext|>


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

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.0.0, packaged on August, 2008.

 http://glc-lib.sourceforge.net

 GLC-lib 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 2 of the License, or
 (at your option) any later version.

 GLC-lib 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 GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/

//! \file glc_part.cpp implementation of the GLC_Part class.

#include "glc_part.h"
#include "glc_world.h"
#include "glc_mesh2.h"

GLC_Part::GLC_Part(GLC_Collection *pCollection, GLC_Instance& instance, GLuint shaderId)
: GLC_Node(pCollection)
, m_RepID(instance.id())
{
	m_pCollection->add(instance, shaderId);
}

GLC_Part::~GLC_Part()
{
	if (not m_pCollection->isEmpty())
	{
		m_pCollection->remove(m_RepID);
	}
}
//////////////////////////////////////////////////////////////////////
// Get Functions
//////////////////////////////////////////////////////////////////////

// Clone the part
GLC_Part* GLC_Part::clone(GLC_Collection * pCollection) const
{
	GLC_Instance instance(m_pCollection->getInstanceHandle(m_RepID)->instanciate());
	GLC_Part* pReturnPart;
	// Test if the instance is in a shading group
	if(m_pCollection->isInAShadingGroup(m_RepID))
	{
		GLuint shaderId= m_pCollection->shadingGroup(m_RepID);
		pCollection->bindShader(shaderId);
		pReturnPart= new GLC_Part(pCollection, instance, shaderId);
	}
	else
	{
		pReturnPart= new GLC_Part(pCollection, instance);
	}

	return pReturnPart;
}

//! Get number of Faces
int GLC_Part::numberOfFaces() const
{
	int number= 0;
	const GLC_Mesh2* pMesh= dynamic_cast<GLC_Mesh2*>(m_pCollection->getInstanceHandle(m_RepID)->getGeometry());
	if (NULL != pMesh)
	{
		number= pMesh->numberOfFaces();
	}
	return number;
}
//! Get number of vertex
int GLC_Part::numberOfVertex() const
{
	int number= 0;
	const GLC_Mesh2* pMesh= dynamic_cast<GLC_Mesh2*>(m_pCollection->getInstanceHandle(m_RepID)->getGeometry());
	if (NULL != pMesh)
	{
		number= pMesh->numberOfVertex();
	}
	return number;
}

//////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////

// Move the Part with specified matrix
GLC_Part* GLC_Part::move(const GLC_Matrix4x4 &matrix)
{
	m_RelativeMatrix= matrix * m_RelativeMatrix;
	m_AbsoluteMatrix= matrix * m_AbsoluteMatrix;
	m_pCollection->getInstanceHandle(m_RepID)->setMatrix(m_AbsoluteMatrix);
	return this;
}
// Update Part absolute matrix
void GLC_Part::updateAbsoluteMatrix()
{
	if (NULL != m_pParent)
	{
		m_AbsoluteMatrix= m_pParent->absoluteMatrix() * m_RelativeMatrix;
		m_pCollection->getInstanceHandle(m_RepID)->setMatrix(m_AbsoluteMatrix);
	}
}
//! Reverse representation normal
void GLC_Part::reverseMeshNormal()
{
	GLC_Mesh2* pMesh= dynamic_cast<GLC_Mesh2*>(m_pCollection->getInstanceHandle(m_RepID)->getGeometry());
	if (NULL != pMesh)
	{
		pMesh->reverseNormal();
	}
}

<commit_msg>Bug Fix : When creating a part the instance matrix is used.<commit_after>/****************************************************************************

 This file is part of the GLC-lib library.
 Copyright (C) 2005-2008 Laurent Ribon (laumaya@users.sourceforge.net)
 Version 1.0.0, packaged on August, 2008.

 http://glc-lib.sourceforge.net

 GLC-lib 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 2 of the License, or
 (at your option) any later version.

 GLC-lib 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 GLC-lib; if not, write to the Free Software
 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA

*****************************************************************************/

//! \file glc_part.cpp implementation of the GLC_Part class.

#include "glc_part.h"
#include "glc_world.h"
#include "glc_mesh2.h"

GLC_Part::GLC_Part(GLC_Collection *pCollection, GLC_Instance& instance, GLuint shaderId)
: GLC_Node(pCollection)
, m_RepID(instance.id())
{
	m_pCollection->add(instance, shaderId);
	move(instance.getMatrix());
}

GLC_Part::~GLC_Part()
{
	if (not m_pCollection->isEmpty())
	{
		m_pCollection->remove(m_RepID);
	}
}
//////////////////////////////////////////////////////////////////////
// Get Functions
//////////////////////////////////////////////////////////////////////

// Clone the part
GLC_Part* GLC_Part::clone(GLC_Collection * pCollection) const
{
	GLC_Instance instance(m_pCollection->getInstanceHandle(m_RepID)->instanciate());
	GLC_Part* pReturnPart;
	// Test if the instance is in a shading group
	if(m_pCollection->isInAShadingGroup(m_RepID))
	{
		GLuint shaderId= m_pCollection->shadingGroup(m_RepID);
		pCollection->bindShader(shaderId);
		pReturnPart= new GLC_Part(pCollection, instance, shaderId);
	}
	else
	{
		pReturnPart= new GLC_Part(pCollection, instance);
	}

	return pReturnPart;
}

//! Get number of Faces
int GLC_Part::numberOfFaces() const
{
	int number= 0;
	const GLC_Mesh2* pMesh= dynamic_cast<GLC_Mesh2*>(m_pCollection->getInstanceHandle(m_RepID)->getGeometry());
	if (NULL != pMesh)
	{
		number= pMesh->numberOfFaces();
	}
	return number;
}
//! Get number of vertex
int GLC_Part::numberOfVertex() const
{
	int number= 0;
	const GLC_Mesh2* pMesh= dynamic_cast<GLC_Mesh2*>(m_pCollection->getInstanceHandle(m_RepID)->getGeometry());
	if (NULL != pMesh)
	{
		number= pMesh->numberOfVertex();
	}
	return number;
}

//////////////////////////////////////////////////////////////////////
// Set Functions
//////////////////////////////////////////////////////////////////////

// Move the Part with specified matrix
GLC_Part* GLC_Part::move(const GLC_Matrix4x4 &matrix)
{
	m_RelativeMatrix= matrix * m_RelativeMatrix;
	m_AbsoluteMatrix= matrix * m_AbsoluteMatrix;
	m_pCollection->getInstanceHandle(m_RepID)->setMatrix(m_AbsoluteMatrix);
	return this;
}
// Update Part absolute matrix
void GLC_Part::updateAbsoluteMatrix()
{
	if (NULL != m_pParent)
	{
		m_AbsoluteMatrix= m_pParent->absoluteMatrix() * m_RelativeMatrix;
		m_pCollection->getInstanceHandle(m_RepID)->setMatrix(m_AbsoluteMatrix);
	}
}
//! Reverse representation normal
void GLC_Part::reverseMeshNormal()
{
	GLC_Mesh2* pMesh= dynamic_cast<GLC_Mesh2*>(m_pCollection->getInstanceHandle(m_RepID)->getGeometry());
	if (NULL != pMesh)
	{
		pMesh->reverseNormal();
	}
}

<|endoftext|>


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

#include "diagnostics/xquery_diagnostics.h"
#include "diagnostics/assert.h"

#include "system/globalenv.h"

#include "context/namespace_context.h"
#include "context/static_context.h"

#include "runtime/accessors/accessors.h"

#include "runtime/visitors/planiter_visitor.h"

#include "store/api/item.h"
#include "store/api/iterator.h"
#include "store/api/item_factory.h"

#include "api/dynamiccontextimpl.h"
#include "api/unmarshaller.h"
#include "api/xqueryimpl.h"

namespace zorba {

/*******************************************************************************
  2.1 fn:node-name
********************************************************************************/
bool NodeNameIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t inNode;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if ((theChildren.size() == 0) || consumeNext(inNode, theChildren[0].getp(), planState))
  {
    if(theChildren.size() == 0)
    {
      //get the context item
    /*  DynamicContext  *external_dctx = planState.theQuery->getDynamicContext();//(planState.theQuery, planState.theGlobalDynCtx, getStaticContext());
      zorba::Item external_ctx_item;
      external_dctx->getContextItem(external_ctx_item);
      inNode = Unmarshaller::getInternalItem(external_ctx_item);
    */
    }
    if(inNode == NULL || !inNode->isNode())
    {
    }
    else if( inNode->getNodeKind() == store::StoreConsts::elementNode ||
        inNode->getNodeKind() == store::StoreConsts::attributeNode)
    {
      result = inNode->getNodeName();
      STACK_PUSH(true, state);
    }
    else if(inNode->getNodeKind() == store::StoreConsts::piNode)
    {
      GENV_ITEMFACTORY->createQName(result, zstring(), zstring(), inNode->getTarget());
      STACK_PUSH(true, state);
    }
  }
  STACK_END (state);
}

/*******************************************************************************
  2.2 fn:nilled
********************************************************************************/
bool NilledIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t inNode;

  PlanIteratorState *state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (consumeNext(inNode, theChildren[0].getp(), planState))
  {
    if (inNode->isNode()) {
      result = inNode->getNilled();
      STACK_PUSH(result != NULL, state);
    } else
			throw XQUERY_EXCEPTION(
				err::XPTY0004,
				ERROR_PARAMS( ZED( FnNilledArgNotNode ) ),
				ERROR_LOC( loc )
			);
  }

  STACK_END (state);
}

/*******************************************************************************
  2.3 fn:string
********************************************************************************/
bool FnStringIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t inVal;
  zstring strval;

  FnStringIteratorState* state;
  DEFAULT_STACK_INIT(FnStringIteratorState, state, planState);

  while(consumeNext(inVal, theChildren[0], planState))
  {
    if (inVal->isFunction())
    {
			throw XQUERY_EXCEPTION( err::FOTY0014, ERROR_LOC( loc ) );
    }
    state->hasOutput = true;
    inVal->getStringValue2(strval);
    GENV_ITEMFACTORY->createString(result, strval);
    STACK_PUSH(true, state);
  }

  if (!state->hasOutput && theEmptyStringOnNULL)
  {
    state->hasOutput = true;
    GENV_ITEMFACTORY->createString(result, strval);
    STACK_PUSH(true, state);
  }

  STACK_END (state);
}

/*******************************************************************************
  2.3 fn:data
********************************************************************************/
bool FnDataIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  PlanIter_t iter;
  store::Item_t itemNode;

  FnDataIteratorState* state;
  DEFAULT_STACK_INIT(FnDataIteratorState, state, planState);

  while (true)
  {
    if (!consumeNext(result, theChildren[0], planState))
      break;

    if (result->isFunction())
    {
			throw XQUERY_EXCEPTION( err::FOTY0013, ERROR_LOC( loc ) );
    }
    if (result->isAtomic())
    {
      STACK_PUSH(true, state);
    }
    else
    {
      assert(result->isNode());

      itemNode.transfer(result);
      try {
        itemNode->getTypedValue(result, state->theTypedValueIter);
      } catch (XQueryException& e) {
				set_source( e, loc );
				throw;
      }

      if (state->theTypedValueIter == NULL)
      {
        if (result == NULL)
          continue;

        STACK_PUSH(true, state );
      }
      else
      {
        state->theTypedValueIter->open();

        while (true)
        {
          if (!state->theTypedValueIter->next(result))
            break;

          assert(!result->isNode());
          STACK_PUSH(true, state );
        }
      }
    }
  }

  state->theTypedValueIter = 0; // TODO remove???
  STACK_END (state);
}

/*******************************************************************************
2.5 fn:base-uri
********************************************************************************/
bool BaseUriIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t inNode;
  zstring baseuri;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (consumeNext(inNode, theChildren[0].getp(), planState))
  {
    inNode->getBaseURI(baseuri);
    if (!baseuri.empty())
    {
      GENV_ITEMFACTORY->createAnyURI(result, baseuri);
      STACK_PUSH(true, state);
    }
  }

  STACK_END (state);
}

/*******************************************************************************
  2.6 fn:document-uri
********************************************************************************/
bool DocumentUriIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  zstring docuri;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (consumeNext(result, theChildren[0].getp(), planState))
  {
    result->getDocumentURI(docuri);
    if (!docuri.empty())
    {
      STACK_PUSH(GENV_ITEMFACTORY->createAnyURI(result, docuri), state);
    }
  }

  STACK_END (state);
}

/*******************************************************************************
  14.9 fn:root
********************************************************************************/
bool RootIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t contextNode;
  store::Item_t parentNode;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (!consumeNext(result, theChildren[0].getp(), planState))
    return false;

  parentNode = result->getParent();

  while (parentNode != NULL)
  {
    result = parentNode;
    parentNode = parentNode->getParent();
  }

  STACK_PUSH(true, state);
  STACK_END (state);
}

} // namespace zorba
/* vim:set ts=2 sw=2: */
<commit_msg>cleanup of the fn:node-name code<commit_after>/*
 * Copyright 2006-2008 The FLWOR Foundation.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
 #include "stdafx.h"

#include "diagnostics/xquery_diagnostics.h"
#include "diagnostics/assert.h"

#include "system/globalenv.h"

#include "context/namespace_context.h"
#include "context/static_context.h"

#include "runtime/accessors/accessors.h"

#include "runtime/visitors/planiter_visitor.h"

#include "store/api/item.h"
#include "store/api/iterator.h"
#include "store/api/item_factory.h"

#include "api/dynamiccontextimpl.h"
#include "api/unmarshaller.h"
#include "api/xqueryimpl.h"

namespace zorba {

/*******************************************************************************
  2.1 fn:node-name
********************************************************************************/
bool NodeNameIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t inNode;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (consumeNext(inNode, theChildren[0].getp(), planState))
  {
    if( inNode->getNodeKind() == store::StoreConsts::elementNode ||
        inNode->getNodeKind() == store::StoreConsts::attributeNode)
    {
      result = inNode->getNodeName();
      STACK_PUSH(true, state);
    }
    else if(inNode->getNodeKind() == store::StoreConsts::piNode)
    {
      GENV_ITEMFACTORY->createQName(result, zstring(), zstring(), inNode->getTarget());
      STACK_PUSH(true, state);
    }
  }
  STACK_END (state);
}

/*******************************************************************************
  2.2 fn:nilled
********************************************************************************/
bool NilledIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t inNode;

  PlanIteratorState *state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (consumeNext(inNode, theChildren[0].getp(), planState))
  {
    if (inNode->isNode()) {
      result = inNode->getNilled();
      STACK_PUSH(result != NULL, state);
    } else
			throw XQUERY_EXCEPTION(
				err::XPTY0004,
				ERROR_PARAMS( ZED( FnNilledArgNotNode ) ),
				ERROR_LOC( loc )
			);
  }

  STACK_END (state);
}

/*******************************************************************************
  2.3 fn:string
********************************************************************************/
bool FnStringIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t inVal;
  zstring strval;

  FnStringIteratorState* state;
  DEFAULT_STACK_INIT(FnStringIteratorState, state, planState);

  while(consumeNext(inVal, theChildren[0], planState))
  {
    if (inVal->isFunction())
    {
			throw XQUERY_EXCEPTION( err::FOTY0014, ERROR_LOC( loc ) );
    }
    state->hasOutput = true;
    inVal->getStringValue2(strval);
    GENV_ITEMFACTORY->createString(result, strval);
    STACK_PUSH(true, state);
  }

  if (!state->hasOutput && theEmptyStringOnNULL)
  {
    state->hasOutput = true;
    GENV_ITEMFACTORY->createString(result, strval);
    STACK_PUSH(true, state);
  }

  STACK_END (state);
}

/*******************************************************************************
  2.3 fn:data
********************************************************************************/
bool FnDataIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  PlanIter_t iter;
  store::Item_t itemNode;

  FnDataIteratorState* state;
  DEFAULT_STACK_INIT(FnDataIteratorState, state, planState);

  while (true)
  {
    if (!consumeNext(result, theChildren[0], planState))
      break;

    if (result->isFunction())
    {
			throw XQUERY_EXCEPTION( err::FOTY0013, ERROR_LOC( loc ) );
    }
    if (result->isAtomic())
    {
      STACK_PUSH(true, state);
    }
    else
    {
      assert(result->isNode());

      itemNode.transfer(result);
      try {
        itemNode->getTypedValue(result, state->theTypedValueIter);
      } catch (XQueryException& e) {
				set_source( e, loc );
				throw;
      }

      if (state->theTypedValueIter == NULL)
      {
        if (result == NULL)
          continue;

        STACK_PUSH(true, state );
      }
      else
      {
        state->theTypedValueIter->open();

        while (true)
        {
          if (!state->theTypedValueIter->next(result))
            break;

          assert(!result->isNode());
          STACK_PUSH(true, state );
        }
      }
    }
  }

  state->theTypedValueIter = 0; // TODO remove???
  STACK_END (state);
}

/*******************************************************************************
2.5 fn:base-uri
********************************************************************************/
bool BaseUriIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t inNode;
  zstring baseuri;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (consumeNext(inNode, theChildren[0].getp(), planState))
  {
    inNode->getBaseURI(baseuri);
    if (!baseuri.empty())
    {
      GENV_ITEMFACTORY->createAnyURI(result, baseuri);
      STACK_PUSH(true, state);
    }
  }

  STACK_END (state);
}

/*******************************************************************************
  2.6 fn:document-uri
********************************************************************************/
bool DocumentUriIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  zstring docuri;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (consumeNext(result, theChildren[0].getp(), planState))
  {
    result->getDocumentURI(docuri);
    if (!docuri.empty())
    {
      STACK_PUSH(GENV_ITEMFACTORY->createAnyURI(result, docuri), state);
    }
  }

  STACK_END (state);
}

/*******************************************************************************
  14.9 fn:root
********************************************************************************/
bool RootIterator::nextImpl(store::Item_t& result, PlanState& planState) const
{
  store::Item_t contextNode;
  store::Item_t parentNode;

  PlanIteratorState* state;
  DEFAULT_STACK_INIT(PlanIteratorState, state, planState);

  if (!consumeNext(result, theChildren[0].getp(), planState))
    return false;

  parentNode = result->getParent();

  while (parentNode != NULL)
  {
    result = parentNode;
    parentNode = parentNode->getParent();
  }

  STACK_PUSH(true, state);
  STACK_END (state);
}

} // namespace zorba
/* vim:set ts=2 sw=2: */
<|endoftext|>