<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/marker_helpers.hpp>
#include <mapnik/svg/svg_renderer.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/markers_placement.hpp>
#include <mapnik/markers_symbolizer.hpp>

// agg
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
#include "agg_path_storage.h"
#include "agg_conv_clip_polyline.h"
#include "agg_conv_transform.h"

// boost
#include <boost/optional.hpp>

namespace mapnik {

template <typename T>
void agg_renderer<T>::process(markers_symbolizer const& sym,
                              mapnik::feature_impl & feature,
                              proj_transform const& prj_trans)
{
    typedef agg::rgba8 color_type;
    typedef agg::order_rgba order_type;
    typedef agg::pixel32_type pixel_type;
    typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
    typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
    typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
    typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;

    std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);

    if (!filename.empty())
    {
        boost::optional<marker_ptr> mark = mapnik::marker_cache::instance()->find(filename, true);
        if (mark && *mark)
        {
            if (!(*mark)->is_vector())
            {
                MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer does not yet support non-SVG markers";
                return;
            }

            ras_ptr->reset();
            ras_ptr->gamma(agg::gamma_power());
            agg::scanline_u8 sl;
            agg::rendering_buffer buf(current_buffer_->raw_data(), width_, height_, width_ * 4);
            pixfmt_comp_type pixf(buf);
            pixf.comp_op(static_cast<agg::comp_op_e>(sym.comp_op()));
            renderer_base renb(pixf);
            renderer_type ren(renb);

            agg::trans_affine geom_tr;
            evaluate_transform(geom_tr, feature, sym.get_transform());

            boost::optional<path_ptr> marker = (*mark)->get_vector_data();
            box2d<double> const& bbox = (*marker)->bounding_box();

            agg::trans_affine tr;
            setup_label_transform(tr, bbox, feature, sym);
            tr = agg::trans_affine_scaling(scale_factor_) * tr;

            coord2d center = bbox.center();
            agg::trans_affine_translation recenter(-center.x, -center.y);
            agg::trans_affine marker_trans = recenter * tr;

            using namespace mapnik::svg;
            vertex_stl_adapter<svg_path_storage> stl_storage((*marker)->source());
            svg_path_adapter svg_path(stl_storage);

            agg::pod_bvector<path_attributes> attributes;
            bool result = push_explicit_style( (*marker)->attributes(), attributes, sym);

            svg_renderer<svg_path_adapter,
                         agg::pod_bvector<path_attributes>,
                         renderer_type,
                         agg::pixfmt_rgba32 > svg_renderer(svg_path, result ? attributes : (*marker)->attributes());

            marker_placement_e placement_method = sym.get_marker_placement();

            BOOST_FOREACH( geometry_type & geom, feature.paths())
            {
                // TODO - merge this code with point_symbolizer rendering
                if (placement_method == MARKER_POINT_PLACEMENT || geom.num_points() <= 1)
                {
                    double x;
                    double y;
                    double z=0;
                    geom.label_interior_position(&x, &y);
                    prj_trans.backward(x,y,z);
                    t_.forward(&x,&y);
                    geom_tr.transform(&x,&y);
                    agg::trans_affine matrix = marker_trans;
                    matrix.translate(x,y);
                    box2d<double> transformed_bbox = bbox * matrix;

                    if (sym.get_allow_overlap() ||
                        detector_->has_placement(transformed_bbox))
                    {
                        svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox);
                        if (/* DEBUG */ 0)
                        {
                            debug_draw_box(buf, transformed_bbox, 0, 0, 0.0);
                        }

                        if (!sym.get_ignore_placement())
                            detector_->insert(transformed_bbox);
                    }
                }
                else if (sym.clip())
                {
                    typedef agg::conv_clip_polyline<geometry_type> clipped_geometry_type;
                    typedef coord_transform<CoordTransform,clipped_geometry_type> path_type;
                    typedef agg::conv_transform<path_type, agg::trans_affine> transformed_path_type;

                    clipped_geometry_type clipped(geom);
                    clipped.clip_box(query_extent_.minx(),query_extent_.miny(),query_extent_.maxx(),query_extent_.maxy());
                    path_type path(t_,clipped,prj_trans);
                    transformed_path_type path_transformed(path,geom_tr);
                    markers_placement<transformed_path_type, label_collision_detector4> placement(path_transformed, bbox, marker_trans, *detector_,
                                                                                sym.get_spacing() * scale_factor_,
                                                                                sym.get_max_error(),
                                                                                sym.get_allow_overlap());
                    double x, y, angle;
                    while (placement.get_point(x, y, angle))
                    {
                        agg::trans_affine matrix = marker_trans;
                        matrix.rotate(angle);
                        matrix.translate(x, y);
                        svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox);

                        if (/* DEBUG */ 0)
                        {
                            debug_draw_box(buf, bbox*matrix, 0, 0, 0.0);
                        }
                    }
                }
                else
                {
                    typedef coord_transform<CoordTransform,geometry_type> path_type;
                    typedef agg::conv_transform<path_type, agg::trans_affine> transformed_path_type;
                    path_type path(t_,geom,prj_trans);
                    transformed_path_type path_transformed(path,geom_tr);
                    markers_placement<transformed_path_type, label_collision_detector4> placement(path_transformed, bbox, marker_trans, *detector_,
                                                                                sym.get_spacing() * scale_factor_,
                                                                                sym.get_max_error(),
                                                                                sym.get_allow_overlap());
                    double x, y, angle;
                    while (placement.get_point(x, y, angle))
                    {
                        agg::trans_affine matrix = marker_trans;
                        matrix.rotate(angle);
                        matrix.translate(x, y);
                        svg_renderer.render(*ras_ptr, sl, renb, matrix, sym.get_opacity(), bbox);

                        if (/* DEBUG */ 0)
                        {
                            debug_draw_box(buf, bbox*matrix, 0, 0, 0.0);
                        }
                    }
                }
            }
        }
    }
}

template void agg_renderer<image_32>::process(markers_symbolizer const&,
                                              mapnik::feature_impl &,
                                              proj_transform const&);
}
<commit_msg>+ AGG: refactor process_markers_symbolizer to use vertex_converters<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2011 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/

// mapnik
#include <mapnik/debug.hpp>
#include <mapnik/graphics.hpp>
#include <mapnik/geom_util.hpp>
#include <mapnik/agg_renderer.hpp>
#include <mapnik/agg_rasterizer.hpp>
#include <mapnik/expression_evaluator.hpp>
#include <mapnik/vertex_converters.hpp>
#include <mapnik/marker.hpp>
#include <mapnik/marker_cache.hpp>
#include <mapnik/marker_helpers.hpp>
#include <mapnik/svg/svg_renderer.hpp>
#include <mapnik/svg/svg_path_adapter.hpp>
#include <mapnik/markers_placement.hpp>
#include <mapnik/markers_symbolizer.hpp>

// agg
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"
#include "agg_path_storage.h"
#include "agg_conv_clip_polyline.h"
#include "agg_conv_transform.h"

// boost
#include <boost/optional.hpp>

namespace mapnik {

template <typename BufferType, typename SvgRenderer, typename Rasterizer, typename Detector>
struct markers_rasterizer_dispatch
{
    typedef agg::rgba8 color_type;
    typedef agg::order_rgba order_type;
    typedef agg::pixel32_type pixel_type;
    typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
    typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
    typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
    typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;

    markers_rasterizer_dispatch(BufferType & image_buffer,
                                SvgRenderer & svg_renderer,
                                Rasterizer & ras,
                                box2d<double> const& bbox,
                                agg::trans_affine const& marker_trans,
                                markers_symbolizer const& sym,
                                Detector & detector,
                                double scale_factor)
        : buf_(image_buffer.raw_data(), image_buffer.width(), image_buffer.height(), image_buffer.width() * 4),
        pixf_(buf_),
        renb_(pixf_),
        svg_renderer_(svg_renderer),
        ras_(ras),
        bbox_(bbox),
        marker_trans_(marker_trans),
        sym_(sym),
        detector_(detector),
        scale_factor_(scale_factor)
    {
        pixf_.comp_op(static_cast<agg::comp_op_e>(sym_.comp_op()));
    }

    template <typename T>
    void add_path(T & path)
    {
        marker_placement_e placement_method = sym_.get_marker_placement();
//        std::cout << "add_path called -> " << placement_method  << std::endl;
//        std::cout << typeid(path).name() << std::endl;
        if (placement_method == MARKER_POINT_PLACEMENT)
        {

            double x,y;
            path.rewind(0);
            label_interior_position(path, x, y);
//            std::cout << "pos -> " << x << "," << y << std::endl;
            agg::trans_affine matrix = marker_trans_;
            matrix.translate(x,y);
            box2d<double> transformed_bbox = bbox_ * matrix;

            if (sym_.get_allow_overlap() ||
                detector_.has_placement(transformed_bbox))
            {
                svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);

                if (!sym_.get_ignore_placement())
                    detector_.insert(transformed_bbox);
            }
        }
        else
        {
            markers_placement<T, label_collision_detector4> placement(path, bbox_, marker_trans_, detector_,
                                                                      sym_.get_spacing() * scale_factor_,
                                                                      sym_.get_max_error(),
                                                                      sym_.get_allow_overlap());
            double x, y, angle;
            while (placement.get_point(x, y, angle))
            {
                agg::trans_affine matrix = marker_trans_;
                matrix.rotate(angle);
                matrix.translate(x, y);
                svg_renderer_.render(ras_, sl_, renb_, matrix, sym_.get_opacity(), bbox_);
            }
        }
    }

private:
    agg::scanline_u8 sl_;
    agg::rendering_buffer buf_;
    pixfmt_comp_type pixf_;
    renderer_base renb_;
    SvgRenderer & svg_renderer_;
    Rasterizer & ras_;
    box2d<double> const& bbox_;
    agg::trans_affine const& marker_trans_;
    markers_symbolizer const& sym_;
    Detector & detector_;
    double scale_factor_;
};

template <typename T>
void agg_renderer<T>::process(markers_symbolizer const& sym,
                              mapnik::feature_impl & feature,
                              proj_transform const& prj_trans)
{
    typedef agg::rgba8 color_type;
    typedef agg::order_rgba order_type;
    typedef agg::pixel32_type pixel_type;
    typedef agg::comp_op_adaptor_rgba_pre<color_type, order_type> blender_type; // comp blender
    typedef agg::pixfmt_custom_blend_rgba<blender_type, agg::rendering_buffer> pixfmt_comp_type;
    typedef agg::renderer_base<pixfmt_comp_type> renderer_base;
    typedef agg::renderer_scanline_aa_solid<renderer_base> renderer_type;

    std::string filename = path_processor_type::evaluate(*sym.get_filename(), feature);

    if (!filename.empty())
    {
        boost::optional<marker_ptr> mark = mapnik::marker_cache::instance()->find(filename, true);
        if (mark && *mark)
        {
            if (!(*mark)->is_vector())
            {
                MAPNIK_LOG_DEBUG(agg_renderer) << "agg_renderer: markers_symbolizer does not yet support non-SVG markers";
                return;
            }

            ras_ptr->reset();
            ras_ptr->gamma(agg::gamma_power());

            agg::trans_affine geom_tr;
            evaluate_transform(geom_tr, feature, sym.get_transform());

            boost::optional<path_ptr> marker = (*mark)->get_vector_data();
            box2d<double> const& bbox = (*marker)->bounding_box();

            agg::trans_affine tr;
            setup_label_transform(tr, bbox, feature, sym);
            tr = agg::trans_affine_scaling(scale_factor_) * tr;

            coord2d center = bbox.center();
            agg::trans_affine_translation recenter(-center.x, -center.y);
            agg::trans_affine marker_trans = recenter * tr;

            using namespace mapnik::svg;
            vertex_stl_adapter<svg_path_storage> stl_storage((*marker)->source());
            svg_path_adapter svg_path(stl_storage);

            agg::pod_bvector<path_attributes> attributes;
            bool result = push_explicit_style( (*marker)->attributes(), attributes, sym);

            typedef label_collision_detector4 detector_type;
            typedef svg_renderer<svg_path_adapter,
                                 agg::pod_bvector<path_attributes>,
                                 renderer_type,
                                 agg::pixfmt_rgba32 > svg_renderer_type;
            typedef markers_rasterizer_dispatch<buffer_type, svg_renderer_type, rasterizer, detector_type>  markers_rasterizer_dispatch_type;
            typedef boost::mpl::vector<clip_line_tag,transform_tag,smooth_tag> conv_types;

            svg_renderer_type svg_renderer(svg_path, result ? attributes : (*marker)->attributes());

            markers_rasterizer_dispatch_type rasterizer_dispatch(*current_buffer_,svg_renderer,*ras_ptr,
                                                                 bbox, marker_trans, sym, *detector_, scale_factor_);

            vertex_converter<box2d<double>, markers_rasterizer_dispatch_type, markers_symbolizer,
                             CoordTransform, proj_transform, agg::trans_affine, conv_types>
                converter(query_extent_* 1.1,rasterizer_dispatch, sym,t_,prj_trans,tr,scale_factor_);

            if (sym.clip()) converter.template set<clip_line_tag>(); //optional clip (default: true)
            converter.template set<transform_tag>(); //always transform
            if (sym.smooth() > 0.0) converter.template set<smooth_tag>(); // optional smooth converter

            BOOST_FOREACH(geometry_type & geom, feature.paths())
            {
                converter.apply(geom);
            }
        }
    }
}

template void agg_renderer<image_32>::process(markers_symbolizer const&,
                                              mapnik::feature_impl &,
                                              proj_transform const&);
}
<|endoftext|>


<commit_before>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: 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
(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 Affero 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, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "astar_path_finder.h"
#include "visitor.h"

#include <boost/graph/astar_search.hpp>
#include <boost/graph/filtered_graph.hpp>

namespace navitia {
namespace georef {

AstarPathFinder::~AstarPathFinder() = default;

void AstarPathFinder::init(const type::GeographicalCoord& start_coord,
                           const type::GeographicalCoord& dest_projected_coord,
                           nt::Mode_e mode,
                           const float speed_factor) {
    PathFinder::init_start(start_coord, mode, speed_factor);

    // we initialize the costs to the maximum value
    size_t n = boost::num_vertices(geo_ref.graph);
    costs.assign(n, bt::pos_infin);

    if (starting_edge.found) {
        costs.at(starting_edge[source_e]) =
            compute_cost_from_starting_edge_to_dist(starting_edge[source_e], dest_projected_coord);
        costs.at(starting_edge[target_e]) =
            compute_cost_from_starting_edge_to_dist(starting_edge[target_e], dest_projected_coord);
    }
}

void AstarPathFinder::start_distance_or_target_astar(const navitia::time_duration& radius,
                                                     const type::GeographicalCoord& dest_projected,
                                                     const std::vector<vertex_t>& destinations) {
    if (!starting_edge.found)
        return;
    computation_launch = true;
    // We start astar from source and target nodes
    try {
        astar({starting_edge[source_e], starting_edge[target_e]},
              astar_distance_heuristic(geo_ref.graph, dest_projected, 1. / double(default_speed[mode] * speed_factor)),
              astar_distance_or_target_visitor(radius, distances, destinations));
    } catch (DestinationFound&) {
    }
}

/**
 * Launch an astar without initializing the data structure
 * Warning, it modifies the distances and the predecessors
 **/
void AstarPathFinder::astar(const std::array<georef::vertex_t, 2>& origin_vertexes,
                            const astar_distance_heuristic& heuristic,
                            const astar_distance_or_target_visitor& visitor) {
    // Note: the predecessors have been updated in init

    // Fill color map in white before A*
    std::fill(color.data.get(), color.data.get() + (color.n + color.elements_per_char - 1) / color.elements_per_char,
              0);

    // we filter the graph to only use certain mean of transport
    using filtered_graph = boost::filtered_graph<georef::Graph, boost::keep_all, TransportationModeFilter>;
    auto g = filtered_graph(geo_ref.graph, {}, TransportationModeFilter(mode, geo_ref));
    auto weight_map = boost::get(&Edge::duration, geo_ref.graph);
    auto combiner = SpeedDistanceCombiner(speed_factor);

    astar_shortest_paths_no_init_with_heap(g, origin_vertexes.front(), origin_vertexes.back(), heuristic, visitor,
                                           weight_map, combiner);
}

template <class Graph, class WeightMap, class Compare>
void AstarPathFinder::astar_shortest_paths_no_init_with_heap(const Graph& g,
                                                             const vertex_t& s_begin,
                                                             const vertex_t& s_end,
                                                             const astar_distance_heuristic& h,
                                                             const astar_distance_or_target_visitor& vis,
                                                             const WeightMap& weight,
                                                             const SpeedDistanceCombiner& combine,
                                                             const Compare& compare) {
    typedef boost::d_ary_heap_indirect<vertex_t, 4, vertex_t*, navitia::time_duration*, Compare> MutableQueue;
    MutableQueue Q(&costs[0], &index_in_heap_map[0], compare);

    boost::detail::astar_bfs_visitor<astar_distance_heuristic, astar_distance_or_target_visitor, MutableQueue,
                                     vertex_t*, navitia::time_duration*, navitia::time_duration*, WeightMap,
                                     boost::two_bit_color_map<>, SpeedDistanceCombiner, Compare>
        bfs_vis(h, vis, Q, &predecessors[0], &costs[0], &distances[0], weight, color, combine, compare,
                navitia::seconds(0));

    breadth_first_visit(g, &s_begin, &s_end, Q, bfs_vis, color);
}

// The cost of a starting edge is the distance from this edge to the projected destination point (distance_to_dest)
// Plus the distance from this edge to the projected starting point (distances[v])
navitia::time_duration AstarPathFinder::compute_cost_from_starting_edge_to_dist(
    const vertex_t& v,
    const type::GeographicalCoord& dest_coord) const {
    auto const& edge_coords = geo_ref.graph[v].coord;
    auto const distance_to_dest = edge_coords.distance_to(dest_coord);
    return navitia::seconds(distance_to_dest / double(default_speed[mode] * speed_factor)) + distances[v];
}

}  // namespace georef
}  // namespace navitia
<commit_msg>Revert "Revert "[Kraken] Fix A* heuristic cost""<commit_after>/* Copyright © 2001-2014, Canal TP and/or its affiliates. All rights reserved.

This file is part of Navitia,
    the software to build cool stuff with public transport.

Hope you'll enjoy and contribute to this project,
    powered by Canal TP (www.canaltp.fr).
Help us simplify mobility and open public transport:
    a non ending quest to the responsive locomotion way of traveling!

LICENCE: 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
(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 Affero 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, see <http://www.gnu.org/licenses/>.

Stay tuned using
twitter @navitia
channel `#navitia` on riot https://riot.im/app/#/room/#navitia:matrix.org
https://groups.google.com/d/forum/navitia
www.navitia.io
*/

#include "astar_path_finder.h"
#include "visitor.h"

#include <boost/graph/astar_search.hpp>
#include <boost/graph/filtered_graph.hpp>

namespace navitia {
namespace georef {

AstarPathFinder::~AstarPathFinder() = default;

void AstarPathFinder::init(const type::GeographicalCoord& start_coord,
                           const type::GeographicalCoord& dest_projected_coord,
                           nt::Mode_e mode,
                           const float speed_factor) {
    PathFinder::init_start(start_coord, mode, speed_factor);

    // we initialize the costs to the maximum value
    size_t n = boost::num_vertices(geo_ref.graph);
    costs.assign(n, bt::pos_infin);

    if (starting_edge.found) {
        costs.at(starting_edge[source_e]) =
            compute_cost_from_starting_edge_to_dist(starting_edge[source_e], dest_projected_coord);
        costs.at(starting_edge[target_e]) =
            compute_cost_from_starting_edge_to_dist(starting_edge[target_e], dest_projected_coord);
    }
}

void AstarPathFinder::start_distance_or_target_astar(const navitia::time_duration& radius,
                                                     const type::GeographicalCoord& dest_projected,
                                                     const std::vector<vertex_t>& destinations) {
    if (!starting_edge.found)
        return;
    computation_launch = true;
    // We start astar from source and target nodes
    try {
        astar({starting_edge[source_e], starting_edge[target_e]},
              astar_distance_heuristic(geo_ref.graph, dest_projected, 1. / double(default_speed[mode])),
              astar_distance_or_target_visitor(radius, distances, destinations));
    } catch (DestinationFound&) {
    }
}

/**
 * Launch an astar without initializing the data structure
 * Warning, it modifies the distances and the predecessors
 **/
void AstarPathFinder::astar(const std::array<georef::vertex_t, 2>& origin_vertexes,
                            const astar_distance_heuristic& heuristic,
                            const astar_distance_or_target_visitor& visitor) {
    // Note: the predecessors have been updated in init

    // Fill color map in white before A*
    std::fill(color.data.get(), color.data.get() + (color.n + color.elements_per_char - 1) / color.elements_per_char,
              0);

    // we filter the graph to only use certain mean of transport
    using filtered_graph = boost::filtered_graph<georef::Graph, boost::keep_all, TransportationModeFilter>;
    auto g = filtered_graph(geo_ref.graph, {}, TransportationModeFilter(mode, geo_ref));
    auto weight_map = boost::get(&Edge::duration, geo_ref.graph);
    auto combiner = SpeedDistanceCombiner(speed_factor);

    astar_shortest_paths_no_init_with_heap(g, origin_vertexes.front(), origin_vertexes.back(), heuristic, visitor,
                                           weight_map, combiner);
}

template <class Graph, class WeightMap, class Compare>
void AstarPathFinder::astar_shortest_paths_no_init_with_heap(const Graph& g,
                                                             const vertex_t& s_begin,
                                                             const vertex_t& s_end,
                                                             const astar_distance_heuristic& h,
                                                             const astar_distance_or_target_visitor& vis,
                                                             const WeightMap& weight,
                                                             const SpeedDistanceCombiner& combine,
                                                             const Compare& compare) {
    typedef boost::d_ary_heap_indirect<vertex_t, 4, vertex_t*, navitia::time_duration*, Compare> MutableQueue;
    MutableQueue Q(&costs[0], &index_in_heap_map[0], compare);

    boost::detail::astar_bfs_visitor<astar_distance_heuristic, astar_distance_or_target_visitor, MutableQueue,
                                     vertex_t*, navitia::time_duration*, navitia::time_duration*, WeightMap,
                                     boost::two_bit_color_map<>, SpeedDistanceCombiner, Compare>
        bfs_vis(h, vis, Q, &predecessors[0], &costs[0], &distances[0], weight, color, combine, compare,
                navitia::seconds(0));

    breadth_first_visit(g, &s_begin, &s_end, Q, bfs_vis, color);
}

// The cost of a starting edge is the distance from this edge to the projected destination point (distance_to_dest)
// Plus the distance from this edge to the projected starting point (distances[v])
navitia::time_duration AstarPathFinder::compute_cost_from_starting_edge_to_dist(
    const vertex_t& v,
    const type::GeographicalCoord& dest_coord) const {
    auto const& edge_coords = geo_ref.graph[v].coord;
    auto const distance_to_dest = edge_coords.distance_to(dest_coord);
    return navitia::seconds(distance_to_dest / double(default_speed[mode] * speed_factor)) + distances[v];
}

}  // namespace georef
}  // namespace navitia
<|endoftext|>


<commit_before>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005-2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#ifndef GEOS_LINESEGMENT_INL
#define GEOS_LINESEGMENT_INL

#include <cassert>
#include <geos/geosAlgorithm.h>

namespace geos {

INLINE
LineSegment::LineSegment(const LineSegment& ls)
	:
	p0(ls.p0),
	p1(ls.p1)
{
}

INLINE
LineSegment::LineSegment(const Coordinate& c0, const Coordinate& c1)
	:
	p0(c0),
	p1(c1)
{
}

INLINE
LineSegment::LineSegment()
{
}

INLINE
LineSegment::~LineSegment()
{
}

INLINE double
LineSegment::distancePerpendicular(const Coordinate& p) const
{
	return algorithm::CGAlgorithms::distancePointLinePerpendicular(p, p0, p1);
}

INLINE void
LineSegment::setCoordinates(const Coordinate& c0, const Coordinate& c1)
{
	p0=c0; p1=c1;
}

INLINE const Coordinate&
LineSegment::getCoordinate(unsigned int i) const
{
	if (i==0) return p0;
	assert(i==1);
	return p1;
}

INLINE void
LineSegment::setCoordinates(const LineSegment& ls)
{
	setCoordinates(ls.p0,ls.p1);
}

INLINE double
LineSegment::getLength() const
{
	return p0.distance(p1);
}

INLINE bool
LineSegment::isHorizontal() const
{
	return p0.y == p1.y;
}

INLINE bool
LineSegment::isVertical() const
{
	return p0.x == p1.x;
}

INLINE int
LineSegment::orientationIndex(const LineSegment* seg) const
{
	assert(seg);
	return orientationIndex(*seg);
}

INLINE CoordinateSequence*
LineSegment::closestPoints(const LineSegment* line)
{
	assert(line);
	return closestPoints(*line);
}

INLINE ostream&
operator<< (ostream& o, const LineSegment& l) {
	return o<<"LINESTRING("<<l.p0.x<<" "<<l.p0.y<<","<<l.p1.x<<" "<<l.p1.y<<")";
}

} // namespace geos

#endif // GEOS_LINESEGMENT_INL
<commit_msg>Changed LineSegment output to use 'LINESEGMENT' label rather then 'LINESTRING'<commit_after>/**********************************************************************
 * $Id$
 *
 * GEOS - Geometry Engine Open Source
 * http://geos.refractions.net
 *
 * Copyright (C) 2005-2006 Refractions Research Inc.
 *
 * This is free software; you can redistribute and/or modify it under
 * the terms of the GNU Lesser General Public Licence as published
 * by the Free Software Foundation.
 * See the COPYING file for more information.
 *
 **********************************************************************/

#ifndef GEOS_LINESEGMENT_INL
#define GEOS_LINESEGMENT_INL

#include <cassert>
#include <geos/geosAlgorithm.h>

namespace geos {

INLINE
LineSegment::LineSegment(const LineSegment& ls)
	:
	p0(ls.p0),
	p1(ls.p1)
{
}

INLINE
LineSegment::LineSegment(const Coordinate& c0, const Coordinate& c1)
	:
	p0(c0),
	p1(c1)
{
}

INLINE
LineSegment::LineSegment()
{
}

INLINE
LineSegment::~LineSegment()
{
}

INLINE double
LineSegment::distancePerpendicular(const Coordinate& p) const
{
	return algorithm::CGAlgorithms::distancePointLinePerpendicular(p, p0, p1);
}

INLINE void
LineSegment::setCoordinates(const Coordinate& c0, const Coordinate& c1)
{
	p0=c0; p1=c1;
}

INLINE const Coordinate&
LineSegment::getCoordinate(unsigned int i) const
{
	if (i==0) return p0;
	assert(i==1);
	return p1;
}

INLINE void
LineSegment::setCoordinates(const LineSegment& ls)
{
	setCoordinates(ls.p0,ls.p1);
}

INLINE double
LineSegment::getLength() const
{
	return p0.distance(p1);
}

INLINE bool
LineSegment::isHorizontal() const
{
	return p0.y == p1.y;
}

INLINE bool
LineSegment::isVertical() const
{
	return p0.x == p1.x;
}

INLINE int
LineSegment::orientationIndex(const LineSegment* seg) const
{
	assert(seg);
	return orientationIndex(*seg);
}

INLINE CoordinateSequence*
LineSegment::closestPoints(const LineSegment* line)
{
	assert(line);
	return closestPoints(*line);
}

INLINE ostream&
operator<< (ostream& o, const LineSegment& l) {
	return o<<"LINESEGMENT("<<l.p0.x<<" "<<l.p0.y<<","<<l.p1.x<<" "<<l.p1.y<<")";
}

} // namespace geos

#endif // GEOS_LINESEGMENT_INL
<|endoftext|>


<commit_before>/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "MicroBit.h"
#include "microbitobj.h"

extern "C" {

#include "py/runtime.h"
#include "modmicrobit.h"

typedef struct _microbit_display_obj_t {
    mp_obj_base_t base;
    MicroBitDisplay *display;
} microbit_display_obj_t;

mp_obj_t microbit_display_print(mp_uint_t n_args, const mp_obj_t *args) {
    microbit_display_obj_t *self = (microbit_display_obj_t*)args[0];
    mp_uint_t len;
    const char *str = mp_obj_str_get_data(args[1], &len);
    if (len == 0) {
        // no chars, do nothing
    } else if (len == 1) {
        // single char
        char c = str[0];
        if (n_args == 2) {
            self->display->print(c);
        } else {
            self->display->print(c, mp_obj_get_int(args[2]));
        }
    } else {
        // a string
        ManagedString s(str, len);
        if (n_args == 2) {
            self->display->print(s);
        } else {
            self->display->print(s, mp_obj_get_int(args[2]));
        }
    }
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_display_print_obj, 2, 3, microbit_display_print);

mp_obj_t microbit_display_scroll(mp_uint_t n_args, const mp_obj_t *args) {
    microbit_display_obj_t *self = (microbit_display_obj_t*)args[0];
    ManagedString s(mp_obj_str_get_str(args[1]));
    if (n_args == 2) {
        self->display->scroll(s);
    } else {
        self->display->scroll(s, mp_obj_get_int(args[2]));
    }
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_display_scroll_obj, 2, 3, microbit_display_scroll);

static int async_delay;
static int async_stride;
static int async_start;

void microbit_display_event(void) {
    if (MP_STATE_PORT(async_data)[0] != NULL && MP_STATE_PORT(async_data)[1] != NULL) {
        microbit_display_obj_t *display = (microbit_display_obj_t*)MP_STATE_PORT(async_data)[0];
        MicroBitImage *image = (MicroBitImage*)MP_STATE_PORT(async_data)[1];
        MicroBitImage img(*image);
        display->display->animateAsync(img, async_delay, async_stride, async_start);
    }
}

STATIC mp_obj_t microbit_display_animate(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_image,    MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
        { MP_QSTR_delay,    MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
        { MP_QSTR_stride,   MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
        { MP_QSTR_start,    MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS} },
        { MP_QSTR_async,    MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
        { MP_QSTR_repeat,   MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
    };

    // parse args
    microbit_display_obj_t *self = (microbit_display_obj_t*)pos_args[0];
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
    MicroBitImage *image = microbit_obj_get_image(args[0].u_obj);

    // reset repeat state
    MP_STATE_PORT(async_data)[0] = NULL;
    MP_STATE_PORT(async_data)[1] = NULL;

    MicroBitImage img(*image);
    if (!args[4].u_bool) {
        self->display->animate(img, args[1].u_int, args[2].u_int, args[3].u_int);
    } else {
        self->display->animateAsync(img, args[1].u_int, args[2].u_int, args[3].u_int);
    }

    if (args[5].u_bool) {
        // enable repeat
        MP_STATE_PORT(async_data)[0] = self;
        MP_STATE_PORT(async_data)[1] = image;
        async_delay = args[1].u_int;
        async_stride = args[2].u_int;
        async_start = args[3].u_int;
    }

    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(microbit_display_animate_obj, 1, microbit_display_animate);

mp_obj_t microbit_display_clear(void) {
    // reset repeat state, cancel animation and clear screen
    MP_STATE_PORT(async_data)[0] = NULL;
    MP_STATE_PORT(async_data)[1] = NULL;
    uBit.display.resetAnimation(0);
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_clear_obj, microbit_display_clear);

mp_obj_t microbit_display_set_brightness(mp_obj_t self_in, mp_obj_t br_in) {
    microbit_display_obj_t *self = (microbit_display_obj_t*)self_in;
    self->display->setBrightness(mp_obj_get_int(br_in));
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(microbit_display_set_brightness_obj, microbit_display_set_brightness);

mp_obj_t microbit_display_set_display_mode(mp_obj_t self_in, mp_obj_t mode_in) {
    microbit_display_obj_t *self = (microbit_display_obj_t*)self_in;
    self->display->setDisplayMode((DisplayMode)mp_obj_get_int(mode_in));
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(microbit_display_set_display_mode_obj, microbit_display_set_display_mode);

STATIC const mp_map_elem_t microbit_display_locals_dict_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR_image), (mp_obj_t)&microbit_image_obj },

    { MP_OBJ_NEW_QSTR(MP_QSTR_set_brightness), (mp_obj_t)&microbit_display_set_brightness_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_set_display_mode), (mp_obj_t)&microbit_display_set_display_mode_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_print), (mp_obj_t)&microbit_display_print_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_scroll), (mp_obj_t)&microbit_display_scroll_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_animate), (mp_obj_t)&microbit_display_animate_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&microbit_display_clear_obj },
};

STATIC MP_DEFINE_CONST_DICT(microbit_display_locals_dict, microbit_display_locals_dict_table);

STATIC const mp_obj_type_t microbit_display_type = {
    { &mp_type_type },
    .name = MP_QSTR_MicroBitDisplay,
    .print = NULL,
    .make_new = NULL,
    .call = NULL,
    .unary_op = NULL,
    .binary_op = NULL,
    .attr = NULL,
    .subscr = NULL,
    .getiter = NULL,
    .iternext = NULL,
    .buffer_p = {NULL},
    .stream_p = NULL,
    .bases_tuple = MP_OBJ_NULL,
    /* .locals_dict = */ (mp_obj_t)&microbit_display_locals_dict,
};

const microbit_display_obj_t microbit_display_obj = {
    {&microbit_display_type},
    .display = &uBit.display
};

}
<commit_msg>Allow images to be passed to display.print.<commit_after>/*
 * This file is part of the Micro Python project, http://micropython.org/
 *
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 Damien P. George
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 * THE SOFTWARE.
 */

#include "MicroBit.h"
#include "microbitobj.h"

extern "C" {

#include "py/runtime.h"
#include "modmicrobit.h"

typedef struct _microbit_display_obj_t {
    mp_obj_base_t base;
    MicroBitDisplay *display;
} microbit_display_obj_t;

mp_obj_t microbit_display_print(mp_uint_t n_args, const mp_obj_t *args) {
    // TODO support async mode

    microbit_display_obj_t *self = (microbit_display_obj_t*)args[0];

    // cancel any animations
    MP_STATE_PORT(async_data)[0] = NULL;
    MP_STATE_PORT(async_data)[1] = NULL;

    if (MP_OBJ_IS_STR(args[1])) {
        // arg is a string object
        mp_uint_t len;
        const char *str = mp_obj_str_get_data(args[1], &len);
        if (len == 0) {
            // no chars, do nothing
        } else if (len == 1) {
            // single char
            char c = str[0];
            if (n_args == 2) {
                self->display->print(c);
            } else {
                self->display->print(c, mp_obj_get_int(args[2]));
            }
        } else {
            // a long string
            ManagedString s(str, len);
            if (n_args == 2) {
                self->display->print(s);
            } else {
                self->display->print(s, mp_obj_get_int(args[2]));
            }
        }
    } else {
        // arg should be an image
        MicroBitImage *image = microbit_obj_get_image(args[1]);
        MicroBitImage img(*image);
        self->display->print(img, 0, 0, 0, 0);
    }
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_display_print_obj, 2, 3, microbit_display_print);

mp_obj_t microbit_display_scroll(mp_uint_t n_args, const mp_obj_t *args) {
    // TODO support async mode
    // TODO support images

    microbit_display_obj_t *self = (microbit_display_obj_t*)args[0];

    // cancel any animations
    MP_STATE_PORT(async_data)[0] = NULL;
    MP_STATE_PORT(async_data)[1] = NULL;

    ManagedString s(mp_obj_str_get_str(args[1]));
    if (n_args == 2) {
        self->display->scroll(s);
    } else {
        self->display->scroll(s, mp_obj_get_int(args[2]));
    }
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(microbit_display_scroll_obj, 2, 3, microbit_display_scroll);

static int async_delay;
static int async_stride;
static int async_start;

void microbit_display_event(void) {
    if (MP_STATE_PORT(async_data)[0] != NULL && MP_STATE_PORT(async_data)[1] != NULL) {
        microbit_display_obj_t *display = (microbit_display_obj_t*)MP_STATE_PORT(async_data)[0];
        MicroBitImage *image = (MicroBitImage*)MP_STATE_PORT(async_data)[1];
        MicroBitImage img(*image);
        display->display->animateAsync(img, async_delay, async_stride, async_start);
    }
}

STATIC mp_obj_t microbit_display_animate(mp_uint_t n_args, const mp_obj_t *pos_args, mp_map_t *kw_args) {
    static const mp_arg_t allowed_args[] = {
        { MP_QSTR_image,    MP_ARG_REQUIRED | MP_ARG_OBJ, {.u_obj = MP_OBJ_NULL} },
        { MP_QSTR_delay,    MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
        { MP_QSTR_stride,   MP_ARG_REQUIRED | MP_ARG_INT, {.u_int = 0} },
        { MP_QSTR_start,    MP_ARG_KW_ONLY | MP_ARG_INT, {.u_int = MICROBIT_DISPLAY_ANIMATE_DEFAULT_POS} },
        { MP_QSTR_async,    MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
        { MP_QSTR_repeat,   MP_ARG_KW_ONLY | MP_ARG_BOOL, {.u_bool = false} },
    };

    // parse args
    microbit_display_obj_t *self = (microbit_display_obj_t*)pos_args[0];
    mp_arg_val_t args[MP_ARRAY_SIZE(allowed_args)];
    mp_arg_parse_all(n_args - 1, pos_args + 1, kw_args, MP_ARRAY_SIZE(allowed_args), allowed_args, args);
    MicroBitImage *image = microbit_obj_get_image(args[0].u_obj);

    // reset repeat state
    MP_STATE_PORT(async_data)[0] = NULL;
    MP_STATE_PORT(async_data)[1] = NULL;

    MicroBitImage img(*image);
    if (!args[4].u_bool) {
        self->display->animate(img, args[1].u_int, args[2].u_int, args[3].u_int);
    } else {
        self->display->animateAsync(img, args[1].u_int, args[2].u_int, args[3].u_int);
    }

    if (args[5].u_bool) {
        // enable repeat
        MP_STATE_PORT(async_data)[0] = self;
        MP_STATE_PORT(async_data)[1] = image;
        async_delay = args[1].u_int;
        async_stride = args[2].u_int;
        async_start = args[3].u_int;
    }

    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_KW(microbit_display_animate_obj, 1, microbit_display_animate);

mp_obj_t microbit_display_clear(void) {
    // reset repeat state, cancel animation and clear screen
    MP_STATE_PORT(async_data)[0] = NULL;
    MP_STATE_PORT(async_data)[1] = NULL;
    uBit.display.resetAnimation(0);
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_1(microbit_display_clear_obj, microbit_display_clear);

mp_obj_t microbit_display_set_brightness(mp_obj_t self_in, mp_obj_t br_in) {
    microbit_display_obj_t *self = (microbit_display_obj_t*)self_in;
    self->display->setBrightness(mp_obj_get_int(br_in));
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(microbit_display_set_brightness_obj, microbit_display_set_brightness);

mp_obj_t microbit_display_set_display_mode(mp_obj_t self_in, mp_obj_t mode_in) {
    microbit_display_obj_t *self = (microbit_display_obj_t*)self_in;
    self->display->setDisplayMode((DisplayMode)mp_obj_get_int(mode_in));
    return mp_const_none;
}
MP_DEFINE_CONST_FUN_OBJ_2(microbit_display_set_display_mode_obj, microbit_display_set_display_mode);

STATIC const mp_map_elem_t microbit_display_locals_dict_table[] = {
    { MP_OBJ_NEW_QSTR(MP_QSTR_image), (mp_obj_t)&microbit_image_obj },

    { MP_OBJ_NEW_QSTR(MP_QSTR_set_brightness), (mp_obj_t)&microbit_display_set_brightness_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_set_display_mode), (mp_obj_t)&microbit_display_set_display_mode_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_print), (mp_obj_t)&microbit_display_print_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_scroll), (mp_obj_t)&microbit_display_scroll_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_animate), (mp_obj_t)&microbit_display_animate_obj },
    { MP_OBJ_NEW_QSTR(MP_QSTR_clear), (mp_obj_t)&microbit_display_clear_obj },
};

STATIC MP_DEFINE_CONST_DICT(microbit_display_locals_dict, microbit_display_locals_dict_table);

STATIC const mp_obj_type_t microbit_display_type = {
    { &mp_type_type },
    .name = MP_QSTR_MicroBitDisplay,
    .print = NULL,
    .make_new = NULL,
    .call = NULL,
    .unary_op = NULL,
    .binary_op = NULL,
    .attr = NULL,
    .subscr = NULL,
    .getiter = NULL,
    .iternext = NULL,
    .buffer_p = {NULL},
    .stream_p = NULL,
    .bases_tuple = MP_OBJ_NULL,
    /* .locals_dict = */ (mp_obj_t)&microbit_display_locals_dict,
};

const microbit_display_obj_t microbit_display_obj = {
    {&microbit_display_type},
    .display = &uBit.display
};

}
<|endoftext|>


<commit_before>#include <cstring>
#include <iostream>
#include <iomanip>
#include <vector>
#include <utility>

#include "smf.hpp"

uint32_t SmfReader::readVarLen()
{
    uint8_t c = read_type<uint8_t>(*m_smf);
    uint32_t value = c & 0x7F;

    if (c & 0x80) {

        do {
            c = read_type<uint8_t>(*m_smf);
            value = (value << 7) + (c & 0x7F);

        } while (c & 0x80);

    }
    return value;
}

void SmfReader::readMidiEvent(SmfEventInfo &event)
{

    MidiEvent midiEvent;
    midiEvent.info = event;
    midiEvent.message = event.status & 0xF0;
    midiEvent.channel = event.status & 0xF;
    midiEvent.data1 = read_type<uint8_t>(*m_smf);
    midiEvent.data2 = read_type<uint8_t>(*m_smf);

    m_currentTrack->midiEvents.push_back(midiEvent);
}

void SmfReader::readMetaEvent(SmfEventInfo &event)
{
    auto metaType = read_type<uint8_t>(*m_smf);
    uint32_t len = readVarLen();

    switch(metaType)
    {
        case meta_SequenceNumber:
        {
            auto sequenceNumber = read_type<uint16_t>(*m_smf);
            std::cout << "Sequence Number: " << " " << std::hex << sequenceNumber << std::endl;
            break;
        }
        case meta_Text:
        case meta_Copyright:
        case meta_InstrumentName:
        case meta_Lyrics:
        case meta_Marker:
        case meta_CuePoint:
        // The midi spec says the following text events exist and act the same as meta_Text.
        case meta_TextReserved1:
        case meta_TextReserved2:
        case meta_TextReserved3:
        case meta_TextReserved4:
        case meta_TextReserved5:
        case meta_TextReserved6:
        case meta_TextReserved7:
        case meta_TextReserved8:
        {
            char textData[128];
            textData[len] = '\0';

            read_type<char>(*m_smf, textData, len);
            std::cout << "text: " << +metaType << " "  << textData << std::endl;
            break;
        }
        case meta_TrackName:
        {
            char textData[128];
            textData[len] = '\0';

            read_type<char>(*m_smf, textData, len);
            m_currentTrack->name = textData;
            break;
        }
        case meta_MIDIChannelPrefix: {
            auto midiChannel = read_type<uint8_t>(*m_smf);
            std::cout << "Midi Channel " << midiChannel << std::hex << std::endl;
            break;
        }
        case meta_EndOfTrack:
        {
            std::cout << "End of Track " << std::endl;
            break;
        }
        case meta_Tempo:
        {
            uint8_t bpmcharr[3];
            read_type<uint8_t>(*m_smf, bpmcharr, 3);
            uint32_t bpmChange = (bpmcharr[0] << 16) | (bpmcharr[1] << 8)  | bpmcharr[2];
            std::cout << "Tempo Change " << bpmChange << std::endl;
            break;
        }
        case meta_SMPTEOffset:
        case meta_TimeSignature:
        case meta_KeySignature:
        case meta_SequencerSpecific:
        {
            m_smf->seekg(len, std::ios::cur);
        }
        default:
        {
            m_smf->seekg(len, std::ios::cur);
            break;
        }
    }
}

void SmfReader::readSysExEvent(SmfEventInfo &event)
{
    auto length = readVarLen();
    std::cout << "sysex event " << m_smf->tellg() << std::endl;
    m_smf->seekg(length, std::ios::cur);
}

void SmfReader::readFile()
{

    int fileEnd = m_smf->tellg();
    m_smf->seekg(0, std::ios::beg);
    int fileBeg = m_smf->tellg();

    int chunkStart = fileBeg;
    int pos = 0;

    SmfChunkInfo chunk;

    read_type<char>(*m_smf, chunk.chunkType, 4);
    chunk.length = read_type<uint32_t>(*m_smf);

    if (strcmp(chunk.chunkType, "MThd") == 0)  {

        m_header.info = chunk;
        m_header.format = read_type<uint16_t>(*m_smf);
        m_header.trackNum = read_type<uint16_t>(*m_smf);
        m_header.division = read_type<int16_t>(*m_smf);

        // seek to the end of the chunk
        // 8 is the length of the type plus length fields
        pos = chunkStart + (8 + chunk.length);

        m_smf->seekg(pos);

        if (m_header.format == smfType0 && m_header.trackNum != 1) {
            std::cout << "Not a valid type 0 midi." << std::endl;
        }
    } else {
        std::cout << "File not a valid MIDI." << std::endl;
    }

    for (int i = 0; i < m_header.trackNum; i++) {

        read_type<char>(*m_smf, chunk.chunkType, 4);
        chunk.length = read_type<uint32_t>(*m_smf);

        // seek to the end of the chunk
        // 8 is the length of the type plus length fields
        chunkStart = pos;
        pos = chunkStart + (8 + chunk.length);

        if (strcmp(chunk.chunkType, "MTrk") == 0) {

            uint8_t prevStatus;

            auto track = std::make_unique<SmfTrack>();
            m_currentTrack = track.get();

            m_tracks.push_back(std::move(track));

            while (m_smf->tellg() < pos)
            {
                SmfEventInfo event;

                event.deltaTime = readVarLen();

                auto status = peek_type<uint8_t>(*m_smf);

                if (status == status_MetaEvent) {
                    event.status = read_type<uint8_t>(*m_smf);
                    readMetaEvent(event);
                } else if (status == status_SysexEvent || status == status_SysexEvent2) {
                    event.status = read_type<uint8_t>(*m_smf);
                    readSysExEvent(event);
                } else {

                    if ((status & 0xF0) >= 0x80) {
                        event.status = read_type<uint8_t>(*m_smf);
                    } else {
                        event.status = prevStatus;
                    }
                    readMidiEvent(event);
                    prevStatus = event.status;
                }
            }
            std::cout << m_currentTrack->midiEvents.size() << std::endl;

        } else {
            std::cout << "Supported track chunk not found." << std::endl;
        }

        m_smf->seekg(pos);
    }

    if (pos == fileEnd) {
        std::cout << "End of MIDI reached." << std::endl;
    } else {
        std::cout << "Warning: Reached end of last track chunk, there is possibly data located outside of a track." << std::endl;
    }

}

SmfReader::SmfReader(std::string filename)
{
    m_smf = std::make_unique<std::ifstream>(filename, std::ios_base::ate  | std::ios_base::binary);

    if (*m_smf) {
        readFile();
        m_smf->close();
    } else {
        std::cout << "Failed to load MIDI file." << std::endl;
    }
}

std::vector<SmfTrack*> SmfReader::getTracks()
{

    std::vector<SmfTrack*> tracks;

    for (int i = 0; i < m_tracks.size(); i++) {
        tracks.push_back(m_tracks[i].get());
    }
    return tracks;
}<commit_msg>Add check to skip midi's using SMPTE time divisions.<commit_after>#include <cstring>
#include <iostream>
#include <iomanip>
#include <vector>
#include <utility>

#include "smf.hpp"

uint32_t SmfReader::readVarLen()
{
    uint8_t c = read_type<uint8_t>(*m_smf);
    uint32_t value = c & 0x7F;

    if (c & 0x80) {

        do {
            c = read_type<uint8_t>(*m_smf);
            value = (value << 7) + (c & 0x7F);

        } while (c & 0x80);

    }
    return value;
}

void SmfReader::readMidiEvent(SmfEventInfo &event)
{

    MidiEvent midiEvent;
    midiEvent.info = event;
    midiEvent.message = event.status & 0xF0;
    midiEvent.channel = event.status & 0xF;
    midiEvent.data1 = read_type<uint8_t>(*m_smf);
    midiEvent.data2 = read_type<uint8_t>(*m_smf);

    m_currentTrack->midiEvents.push_back(midiEvent);
}

void SmfReader::readMetaEvent(SmfEventInfo &event)
{
    auto metaType = read_type<uint8_t>(*m_smf);
    uint32_t len = readVarLen();

    switch(metaType)
    {
        case meta_SequenceNumber:
        {
            auto sequenceNumber = read_type<uint16_t>(*m_smf);
            std::cout << "Sequence Number: " << " " << std::hex << sequenceNumber << std::endl;
            break;
        }
        case meta_Text:
        case meta_Copyright:
        case meta_InstrumentName:
        case meta_Lyrics:
        case meta_Marker:
        case meta_CuePoint:
        // The midi spec says the following text events exist and act the same as meta_Text.
        case meta_TextReserved1:
        case meta_TextReserved2:
        case meta_TextReserved3:
        case meta_TextReserved4:
        case meta_TextReserved5:
        case meta_TextReserved6:
        case meta_TextReserved7:
        case meta_TextReserved8:
        {
            char textData[128];
            textData[len] = '\0';

            read_type<char>(*m_smf, textData, len);
            std::cout << "text: " << +metaType << " "  << textData << std::endl;
            break;
        }
        case meta_TrackName:
        {
            char textData[128];
            textData[len] = '\0';

            read_type<char>(*m_smf, textData, len);
            m_currentTrack->name = textData;
            break;
        }
        case meta_MIDIChannelPrefix: {
            auto midiChannel = read_type<uint8_t>(*m_smf);
            std::cout << "Midi Channel " << midiChannel << std::hex << std::endl;
            break;
        }
        case meta_EndOfTrack:
        {
            std::cout << "End of Track " << std::endl;
            break;
        }
        case meta_Tempo:
        {
            uint8_t bpmcharr[3];
            read_type<uint8_t>(*m_smf, bpmcharr, 3);
            uint32_t bpmChange = (bpmcharr[0] << 16) | (bpmcharr[1] << 8)  | bpmcharr[2];
            std::cout << "Tempo Change " << bpmChange << std::endl;
            break;
        }
        case meta_SMPTEOffset:
        case meta_TimeSignature:
        case meta_KeySignature:
        case meta_SequencerSpecific:
        {
            m_smf->seekg(len, std::ios::cur);
        }
        default:
        {
            m_smf->seekg(len, std::ios::cur);
            break;
        }
    }
}

void SmfReader::readSysExEvent(SmfEventInfo &event)
{
    auto length = readVarLen();
    std::cout << "sysex event " << m_smf->tellg() << std::endl;
    m_smf->seekg(length, std::ios::cur);
}

void SmfReader::readFile()
{

    int fileEnd = m_smf->tellg();
    m_smf->seekg(0, std::ios::beg);
    int fileBeg = m_smf->tellg();

    int chunkStart = fileBeg;
    int pos = 0;

    SmfChunkInfo chunk;

    read_type<char>(*m_smf, chunk.chunkType, 4);
    chunk.length = read_type<uint32_t>(*m_smf);

    if (strcmp(chunk.chunkType, "MThd") == 0)  {

        m_header.info = chunk;
        m_header.format = read_type<uint16_t>(*m_smf);
        m_header.trackNum = read_type<uint16_t>(*m_smf);
        m_header.division = read_type<int16_t>(*m_smf);

        // seek to the end of the chunk
        // 8 is the length of the type plus length fields
        pos = chunkStart + (8 + chunk.length);

        m_smf->seekg(pos);

        if (m_header.format == smfType0 && m_header.trackNum != 1) {
            std::cout << "Not a valid type 0 midi." << std::endl;
        }
    } else {
        std::cout << "File not a valid MIDI." << std::endl;
        return;
    }

    if (m_header.division & 0x8000 != 0) {
        std::cout << "SMPTE division mode is currently not supported" << std::endl;
        return;
    }

    for (int i = 0; i < m_header.trackNum; i++) {

        read_type<char>(*m_smf, chunk.chunkType, 4);
        chunk.length = read_type<uint32_t>(*m_smf);

        // seek to the end of the chunk
        // 8 is the length of the type plus length fields
        chunkStart = pos;
        pos = chunkStart + (8 + chunk.length);

        if (strcmp(chunk.chunkType, "MTrk") == 0) {

            uint8_t prevStatus;

            auto track = std::make_unique<SmfTrack>();
            m_currentTrack = track.get();

            m_tracks.push_back(std::move(track));

            while (m_smf->tellg() < pos)
            {
                SmfEventInfo event;

                event.deltaTime = readVarLen();

                auto status = peek_type<uint8_t>(*m_smf);

                if (status == status_MetaEvent) {
                    event.status = read_type<uint8_t>(*m_smf);
                    readMetaEvent(event);
                } else if (status == status_SysexEvent || status == status_SysexEvent2) {
                    event.status = read_type<uint8_t>(*m_smf);
                    readSysExEvent(event);
                } else {

                    if ((status & 0xF0) >= 0x80) {
                        event.status = read_type<uint8_t>(*m_smf);
                    } else {
                        event.status = prevStatus;
                    }
                    readMidiEvent(event);
                    prevStatus = event.status;
                }
            }
            std::cout << m_currentTrack->midiEvents.size() << std::endl;

        } else {
            std::cout << "Supported track chunk not found." << std::endl;
        }

        m_smf->seekg(pos);
    }

    if (pos == fileEnd) {
        std::cout << "End of MIDI reached." << std::endl;
    } else {
        std::cout << "Warning: Reached end of last track chunk, there is possibly data located outside of a track." << std::endl;
    }

}

SmfReader::SmfReader(std::string filename)
{
    m_smf = std::make_unique<std::ifstream>(filename, std::ios_base::ate  | std::ios_base::binary);

    if (*m_smf) {
        readFile();
        m_smf->close();
    } else {
        std::cout << "Failed to load MIDI file." << std::endl;
    }
}

std::vector<SmfTrack*> SmfReader::getTracks()
{

    std::vector<SmfTrack*> tracks;

    for (int i = 0; i < m_tracks.size(); i++) {
        tracks.push_back(m_tracks[i].get());
    }
    return tracks;
}
<|endoftext|>


<commit_before>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library 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
 * OpenSceneGraph Public License for more details.
*/
#if 0 // defined(__APPLE__)
#include "FileUtils_Mac.cpp" // this is not functional yet -- fix!
#else

// currently this impl is for _all_ platforms, execpt as defined.
// the mac version will change soon to reflect the path scheme under osx, but
// for now, the above include is commented out, and the below code takes precedence.

#if defined(WIN32) && !defined(__CYGWIN__)
    #include <Io.h>
    #include <Windows.h>
    #include <Winbase.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    // set up for windows so acts just like unix access().
    #define F_OK 4
#else // unix
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
#endif

#include <osg/Notify>

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>

bool osgDB::fileExists(const std::string& filename)
{
    return access( filename.c_str(), F_OK ) == 0;
}

osgDB::FileType osgDB::fileType(const std::string& filename)
{
#if defined(WIN32) && !defined(__CYGWIN__)
    struct _stat fileStat;
    if ( _stat(filename.c_str(), &fileStat) != 0 )
    {
        return FILE_NOT_FOUND;
    } // end if

    if ( fileStat.st_mode & _S_IFDIR )
        return DIRECTORY;
    else if ( fileStat.st_mode & _S_IFREG )
        return REGULAR_FILE;

    return FILE_NOT_FOUND;

#else
    struct stat fileStat;

    if(stat(filename.c_str(), &fileStat) == -1)
    {
	return FILE_NOT_FOUND;
    }

    if(S_ISREG(fileStat.st_mode))
    {
	return REGULAR_FILE;
    }

    if(S_ISDIR(fileStat.st_mode))
    {
	return DIRECTORY;
    }

    return FILE_NOT_FOUND;
#endif
}

std::string osgDB::findFileInPath(const std::string& filename, const FilePathList& filepath,CaseSensitivity caseSensitivity)
{
    if (filename.empty())
        return filename;

    if(fileExists(filename))
    {
        osg::notify(osg::DEBUG_INFO) << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
        return filename;
    }

    for(FilePathList::const_iterator itr=filepath.begin();
        itr!=filepath.end();
        ++itr)
    {
        std::string path = *itr + '/'+ filename;
        osg::notify(osg::DEBUG_INFO) << "FindFileInPath() : trying " << path << " ...\n";
        if(fileExists(path))
        {
            osg::notify(osg::DEBUG_INFO) << "FindFileInPath() : USING " << path << "\n";
            return path;
        }
#ifndef WIN32
// windows already case insensitive so no need to retry..
        else if (caseSensitivity==CASE_INSENSITIVE)
        {
            std::string foundfile = findFileInDirectory(filename,*itr,CASE_INSENSITIVE);
            if (!foundfile.empty()) return foundfile;
        }
#endif

    }

    return std::string();
}

std::string osgDB::findDataFile(const std::string& filename,CaseSensitivity caseSensitivity)
{
    if (filename.empty()) return filename;

    const FilePathList& filepath = Registry::instance()->getDataFilePathList();

    std::string fileFound = findFileInPath(filename, filepath,caseSensitivity);
    if (!fileFound.empty()) return fileFound;

    // if a directory is included in the filename, get just the (simple) filename itself and try that
    std::string simpleFileName = getSimpleFileName(filename);
    if (simpleFileName!=filename)
    {
        std::string fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity);
        if (!fileFound.empty()) return fileFound;
    }

    // return empty string.
    return std::string();
}

std::string osgDB::findLibraryFile(const std::string& filename,CaseSensitivity caseSensitivity)
{
    if (filename.empty())
        return filename;

    const FilePathList& filepath = Registry::instance()->getLibraryFilePathList();

    std::string fileFound = findFileInPath(filename, filepath,caseSensitivity);
    if (!fileFound.empty())
        return fileFound;

    // if a directory is included in the filename, get just the (simple) filename itself and try that
    std::string simpleFileName = getSimpleFileName(filename);
    if (simpleFileName!=filename)
    {
        std::string fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity);
        if (!fileFound.empty()) return fileFound;
    }

    // failed with direct paths,
    // now try prepending the filename with "osgPlugins/"
    return findFileInPath("osgPlugins/"+simpleFileName,filepath,caseSensitivity);
}

std::string osgDB::findFileInDirectory(const std::string& fileName,const std::string& dirName,CaseSensitivity caseSensitivity)
{
    bool needFollowingBackslash = false;
    bool needDirectoryName = true;
    osgDB::DirectoryContents dc;

    if (dirName.empty())
    {
        dc = osgDB::getDirectoryContents(".");
        needFollowingBackslash = false;
        needDirectoryName = false;
    }
    else if (dirName=="." || dirName=="./" || dirName==".\\")
    {
        dc = osgDB::getDirectoryContents(".");
        needFollowingBackslash = false;
        needDirectoryName = false;
    }
    else
    {
        dc = osgDB::getDirectoryContents(dirName);
        char lastChar = dirName[dirName.size()-1];
        if (lastChar=='/') needFollowingBackslash = false;
        else if (lastChar=='\\') needFollowingBackslash = false;
        else needFollowingBackslash = true;
        needDirectoryName = true;
    }

    for(osgDB::DirectoryContents::iterator itr=dc.begin();
        itr!=dc.end();
        ++itr)
    {
        if ((caseSensitivity==CASE_INSENSITIVE && osgDB::equalCaseInsensitive(fileName,*itr)) ||
            (fileName==*itr))
        {
            if (!needDirectoryName) return *itr;
            else if (needFollowingBackslash) return dirName+'/'+*itr;
            else return dirName+*itr;
        }
    }
    return "";
}

#if defined(WIN32) && !defined(__CYGWIN__)
    #include <io.h>
    #include <direct.h>

    osgDB::DirectoryContents osgDB::getDirectoryContents(const std::string& dirName)
    {
        osgDB::DirectoryContents contents;

        WIN32_FIND_DATA data;
        HANDLE handle = FindFirstFile((dirName + "\\*").c_str(), &data);
        if (handle != INVALID_HANDLE_VALUE)
        {
            do
            {
                contents.push_back(data.cFileName);
            }
            while (FindNextFile(handle, &data) != 0);

            FindClose(handle);
        }
        return contents;
    }

#else

    #include <dirent.h>
    osgDB::DirectoryContents osgDB::getDirectoryContents(const std::string& dirName)
    {
        osgDB::DirectoryContents contents;

        DIR *handle = opendir(dirName.c_str());
        if (handle)
        {
            dirent *rc;
            while((rc = readdir(handle))!=NULL)
            {
                contents.push_back(rc->d_name);
            }
            closedir(handle);
        }

        return contents;
    }

#endif // unix getDirectoryContexts

#endif // ! target mac carbon
<commit_msg>From Bruce Clay, cross platform implemention of fileType(..)<commit_after>/* -*-c++-*- OpenSceneGraph - Copyright (C) 1998-2003 Robert Osfield
 *
 * This library is open source and may be redistributed and/or modified under
 * the terms of the OpenSceneGraph Public License (OSGPL) version 0.0 or
 * (at your option) any later version.  The full license is in LICENSE file
 * included with this distribution, and on the openscenegraph.org website.
 *
 * This library 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
 * OpenSceneGraph Public License for more details.
*/
#if 0 // defined(__APPLE__)
#include "FileUtils_Mac.cpp" // this is not functional yet -- fix!
#else

// currently this impl is for _all_ platforms, execpt as defined.
// the mac version will change soon to reflect the path scheme under osx, but
// for now, the above include is commented out, and the below code takes precedence.

#if defined(WIN32) && !defined(__CYGWIN__)
    #include <Io.h>
    #include <Windows.h>
    #include <Winbase.h>
    #include <sys/types.h>
    #include <sys/stat.h>
    // set up for windows so acts just like unix access().
    #define F_OK 4
#else // unix
    #include <unistd.h>
    #include <sys/types.h>
    #include <sys/stat.h>
#endif

#include <osg/Notify>

#include <osgDB/FileUtils>
#include <osgDB/FileNameUtils>
#include <osgDB/Registry>

bool osgDB::fileExists(const std::string& filename)
{
    return access( filename.c_str(), F_OK ) == 0;
}

osgDB::FileType osgDB::fileType(const std::string& filename)
{
#if 1

    // proposed single code path, from Bruce Clay.
    struct stat fileStat;
    if ( stat(filename.c_str(), &fileStat) != 0 )
    {
        return FILE_NOT_FOUND;
    } // end if

    if ( fileStat.st_mode & S_IFDIR )
        return DIRECTORY;
    else if ( fileStat.st_mode & S_IFREG )
        return REGULAR_FILE;

    return FILE_NOT_FOUND;

#else
    #if defined(WIN32) && !defined(__CYGWIN__)
        struct _stat fileStat;
        if ( _stat(filename.c_str(), &fileStat) != 0 )
        {
            return FILE_NOT_FOUND;
        } // end if

        if ( fileStat.st_mode & _S_IFDIR )
            return DIRECTORY;
        else if ( fileStat.st_mode & _S_IFREG )
            return REGULAR_FILE;

        return FILE_NOT_FOUND;

    #else
        struct stat fileStat;

        if(stat(filename.c_str(), &fileStat) == -1)
        {
	    return FILE_NOT_FOUND;
        }

        if(S_ISREG(fileStat.st_mode))
        {
	    return REGULAR_FILE;
        }

        if(S_ISDIR(fileStat.st_mode))
        {
	    return DIRECTORY;
        }

        return FILE_NOT_FOUND;
    #endif
#endif
}

std::string osgDB::findFileInPath(const std::string& filename, const FilePathList& filepath,CaseSensitivity caseSensitivity)
{
    if (filename.empty())
        return filename;

    if(fileExists(filename))
    {
        osg::notify(osg::DEBUG_INFO) << "FindFileInPath(" << filename << "): returning " << filename << std::endl;
        return filename;
    }

    for(FilePathList::const_iterator itr=filepath.begin();
        itr!=filepath.end();
        ++itr)
    {
        std::string path = *itr + '/'+ filename;
        osg::notify(osg::DEBUG_INFO) << "FindFileInPath() : trying " << path << " ...\n";
        if(fileExists(path))
        {
            osg::notify(osg::DEBUG_INFO) << "FindFileInPath() : USING " << path << "\n";
            return path;
        }
#ifndef WIN32
// windows already case insensitive so no need to retry..
        else if (caseSensitivity==CASE_INSENSITIVE)
        {
            std::string foundfile = findFileInDirectory(filename,*itr,CASE_INSENSITIVE);
            if (!foundfile.empty()) return foundfile;
        }
#endif

    }

    return std::string();
}

std::string osgDB::findDataFile(const std::string& filename,CaseSensitivity caseSensitivity)
{
    if (filename.empty()) return filename;

    const FilePathList& filepath = Registry::instance()->getDataFilePathList();

    std::string fileFound = findFileInPath(filename, filepath,caseSensitivity);
    if (!fileFound.empty()) return fileFound;

    // if a directory is included in the filename, get just the (simple) filename itself and try that
    std::string simpleFileName = getSimpleFileName(filename);
    if (simpleFileName!=filename)
    {
        std::string fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity);
        if (!fileFound.empty()) return fileFound;
    }

    // return empty string.
    return std::string();
}

std::string osgDB::findLibraryFile(const std::string& filename,CaseSensitivity caseSensitivity)
{
    if (filename.empty())
        return filename;

    const FilePathList& filepath = Registry::instance()->getLibraryFilePathList();

    std::string fileFound = findFileInPath(filename, filepath,caseSensitivity);
    if (!fileFound.empty())
        return fileFound;

    // if a directory is included in the filename, get just the (simple) filename itself and try that
    std::string simpleFileName = getSimpleFileName(filename);
    if (simpleFileName!=filename)
    {
        std::string fileFound = findFileInPath(simpleFileName, filepath,caseSensitivity);
        if (!fileFound.empty()) return fileFound;
    }

    // failed with direct paths,
    // now try prepending the filename with "osgPlugins/"
    return findFileInPath("osgPlugins/"+simpleFileName,filepath,caseSensitivity);
}

std::string osgDB::findFileInDirectory(const std::string& fileName,const std::string& dirName,CaseSensitivity caseSensitivity)
{
    bool needFollowingBackslash = false;
    bool needDirectoryName = true;
    osgDB::DirectoryContents dc;

    if (dirName.empty())
    {
        dc = osgDB::getDirectoryContents(".");
        needFollowingBackslash = false;
        needDirectoryName = false;
    }
    else if (dirName=="." || dirName=="./" || dirName==".\\")
    {
        dc = osgDB::getDirectoryContents(".");
        needFollowingBackslash = false;
        needDirectoryName = false;
    }
    else
    {
        dc = osgDB::getDirectoryContents(dirName);
        char lastChar = dirName[dirName.size()-1];
        if (lastChar=='/') needFollowingBackslash = false;
        else if (lastChar=='\\') needFollowingBackslash = false;
        else needFollowingBackslash = true;
        needDirectoryName = true;
    }

    for(osgDB::DirectoryContents::iterator itr=dc.begin();
        itr!=dc.end();
        ++itr)
    {
        if ((caseSensitivity==CASE_INSENSITIVE && osgDB::equalCaseInsensitive(fileName,*itr)) ||
            (fileName==*itr))
        {
            if (!needDirectoryName) return *itr;
            else if (needFollowingBackslash) return dirName+'/'+*itr;
            else return dirName+*itr;
        }
    }
    return "";
}

#if defined(WIN32) && !defined(__CYGWIN__)
    #include <io.h>
    #include <direct.h>

    osgDB::DirectoryContents osgDB::getDirectoryContents(const std::string& dirName)
    {
        osgDB::DirectoryContents contents;

        WIN32_FIND_DATA data;
        HANDLE handle = FindFirstFile((dirName + "\\*").c_str(), &data);
        if (handle != INVALID_HANDLE_VALUE)
        {
            do
            {
                contents.push_back(data.cFileName);
            }
            while (FindNextFile(handle, &data) != 0);

            FindClose(handle);
        }
        return contents;
    }

#else

    #include <dirent.h>
    osgDB::DirectoryContents osgDB::getDirectoryContents(const std::string& dirName)
    {
        osgDB::DirectoryContents contents;

        DIR *handle = opendir(dirName.c_str());
        if (handle)
        {
            dirent *rc;
            while((rc = readdir(handle))!=NULL)
            {
                contents.push_back(rc->d_name);
            }
            closedir(handle);
        }

        return contents;
    }

#endif // unix getDirectoryContexts

#endif // ! target mac carbon
<|endoftext|>


<commit_before>#ifndef PARSE_REFERENCE_HPP_
#define PARSE_REFERENCE_HPP_

#include "symbol.hpp"

#include <boost/optional.hpp>

namespace parse_reference_detail
{

inline bool is_letter(char c)
{
    return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z');
}
inline bool is_alpha_numeric(char c)
{
    return is_letter(c) || ('0' <= c && c <= '9');
}
inline bool is_operator(char c)
{
    static const char operators[] = "+-*^/%~<>=!|&.$";
    static const char* end = operators + sizeof(operators) - 1; // zero-terminated string
    return std::find(operators, end, c) != end;
}

}

template <class State>
boost::optional<ref_symbol> parse_reference(State& state)
{
    using namespace parse_reference_detail;
    if(state.empty())
        return boost::none;
    else if(is_letter(state.front()))
    {
        std::string identifier;
        file_position begin = state.position();

        while(!state.empty() && is_alpha_numeric(state.front()))
        {
            identifier.push_back(state.front());
            state.pop_front();
        }

        file_position end = state.position();
        identifier_id_t identifier_id = state.identifier_id(identifier);
        #ifdef NDEBUG
        ref_symbol result{identifier_id};
        #else
        ref_symbol result{identifier_id, identifier, 0};
        #endif
        result.source(file_source{begin, end, state.file()});
        return result;
    }
    else if(is_operator(state.front()))
    {
        std::string identifier;
        file_position begin = state.position();

        while(!state.empty() && is_operator(state.front()))
        {
            identifier.push_back(state.front());
            state.pop_front();
        }

        file_position end = state.position();
        identifier_id_t identifier_id = state.identifier_id(identifier);

        ref_symbol result{identifier_id};
        result.source(file_source{begin, end, state.file()});
        return result;
    }
    else
        return boost::none;
}

#endif

<commit_msg>allow '_' in ref symbols (hacky)<commit_after>#ifndef PARSE_REFERENCE_HPP_
#define PARSE_REFERENCE_HPP_

#include "symbol.hpp"

#include <boost/optional.hpp>

namespace parse_reference_detail
{

inline bool is_letter(char c)
{
    return ('a' <= c && c <= 'z') || ('A' <= c && c <= 'Z') || c == '_';
}
inline bool is_alpha_numeric(char c)
{
    return is_letter(c) || ('0' <= c && c <= '9');
}
inline bool is_operator(char c)
{
    static const char operators[] = "+-*^/%~<>=!|&.$";
    static const char* end = operators + sizeof(operators) - 1; // zero-terminated string
    return std::find(operators, end, c) != end;
}

}

template <class State>
boost::optional<ref_symbol> parse_reference(State& state)
{
    using namespace parse_reference_detail;
    if(state.empty())
        return boost::none;
    else if(is_letter(state.front()))
    {
        std::string identifier;
        file_position begin = state.position();

        while(!state.empty() && is_alpha_numeric(state.front()))
        {
            identifier.push_back(state.front());
            state.pop_front();
        }

        file_position end = state.position();
        identifier_id_t identifier_id = state.identifier_id(identifier);
        #ifdef NDEBUG
        ref_symbol result{identifier_id};
        #else
        ref_symbol result{identifier_id, identifier, 0};
        #endif
        result.source(file_source{begin, end, state.file()});
        return result;
    }
    else if(is_operator(state.front()))
    {
        std::string identifier;
        file_position begin = state.position();

        while(!state.empty() && is_operator(state.front()))
        {
            identifier.push_back(state.front());
            state.pop_front();
        }

        file_position end = state.position();
        identifier_id_t identifier_id = state.identifier_id(identifier);

        ref_symbol result{identifier_id};
        result.source(file_source{begin, end, state.file()});
        return result;
    }
    else
        return boost::none;
}

#endif

<|endoftext|>


<commit_before>#include "platform.hpp"

#ifdef WIN32

#include "../classes/string.hpp"
#include "../collector.hpp"
#include "../runtime.hpp"

namespace Mirb
{
	namespace Platform
	{
		void raise(const CharArray &message)
		{
			TCHAR *msg_buffer;
			DWORD err_no = GetLastError();

			FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |	FORMAT_MESSAGE_IGNORE_INSERTS, 0, err_no, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&msg_buffer, 0, 0);

			CharArray msg = message + "\nError #" + CharArray::uint(err_no) + ": "   + from_tchar(msg_buffer);

			LocalFree(msg_buffer);

			throw create_exception(context->system_call_error, msg);
		}

		std::string BenchmarkResult::format()
		{
			std::stringstream result;

			result << (((double)1000 * time.QuadPart) / (double)freq.QuadPart) << " ms";

			return result.str();
		}

		void *allocate_region(size_t bytes)
		{
			void *result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

			mirb_runtime_assert(result != 0);

			return result;
		}

		void free_region(void *region, size_t)
		{
			VirtualFree(region, 0, MEM_RELEASE);
		}

		CharArray from_tchar(const TCHAR *buffer, size_t tchars)
		{
			#ifdef _UNICODE
				size_t size = WideCharToMultiByte(CP_UTF8, 0, buffer, tchars, nullptr, 0, NULL, NULL);

				char *new_buffer = (char *)alloca(size);

				size = WideCharToMultiByte(CP_UTF8, 0, buffer, tchars, new_buffer, size, NULL, NULL);

				if(size == 0)
					raise("Unable to convert UCS-2 pathname to UTF-8");

				return CharArray((const char_t *)new_buffer, size);
			#else
				return CharArray((const char_t *)buffer, tchars);
			#endif
		}

		CharArray from_tchar(const TCHAR *buffer)
		{
			return from_tchar(buffer, _tcslen(buffer));
		}

		BOOL WINAPI ctrl_handler(DWORD ctrl_type)
		{
			switch(ctrl_type)
			{
				case CTRL_C_EVENT:
					Collector::signal();
					return TRUE;

				default:
					return FALSE;
			}
		}

		CharArray normalize_separator_to(const CharArray &path)
		{
			CharArray result = path;

			result.localize();

			for(size_t i = 0; i < result.size(); ++i)
				if(result[i] == '/')
					result[i] = '\\';

			if(result[result.size()-1] == '\\')
				result.shrink(result.size() - 1);

			return result;
		}

		CharArray normalize_separator_from(const CharArray &path)
		{
			CharArray result = path;

			result.localize();

			for(size_t i = 0; i < result.size(); ++i)
				if(result[i] == '\\')
					result[i] = '/';

			if(result[result.size()-1] == '/')
				result.shrink(result.size() - 1);

			return result;
		}

		CharArray from_win_path(const CharArray &path)
		{
			#ifdef _UNICODE
				CharArray result = (path.copy(0, 4) == "\\\\?\\") ? path.copy(4, path.size()) : path;

				return normalize_separator_from(result);
			#else
				return normalize_separator_from(path);
			#endif
		}

		CharArray to_win_path(const CharArray &path)
		{
			#ifdef _UNICODE
				return "\\\\?\\" + normalize_separator_to(path);
			#else
				return normalize_separator_to(path);
			#endif
		}

		CharArray from_short_win_path(const TCHAR *buffer)
		{
			#ifdef _UNICODE
				size_t size = GetLongPathName(buffer, 0, 0);

				TCHAR *long_buffer = (TCHAR *)alloca((size + 1) * sizeof(TCHAR));

				if(GetLongPathName(buffer, long_buffer, size + 1) == 0)
					raise("Unable to convert short pathname to a long pathname");

				return from_win_path(from_tchar(long_buffer));
			#else
				return from_win_path(from_tchar(buffer));
			#endif
		}

		DWORD attributes(const CharArray &path)
		{
			DWORD attrib;

			to_tchar(to_win_path(path), [&](const TCHAR *buffer, size_t) {
				attrib = GetFileAttributes(buffer);
			});

			return attrib;
		}

		CharArray cwd()
		{
			size_t size = GetCurrentDirectory(0, 0);

			TCHAR *buffer = (TCHAR *)alloca(size * sizeof(TCHAR));

			if(GetCurrentDirectory(size, buffer) == 0)
				raise("Unable to get the current directory");

			return from_short_win_path(buffer);
		}

		void cd(const CharArray &path)
		{
			to_short_win_path(path, [&](const TCHAR *buffer) {
				if(SetCurrentDirectory(buffer) == 0)
					raise("Unable change the current directory to '" + path + "'");
			});
		}

		bool file_exists(const CharArray &path)
		{
			return (attributes(path) != INVALID_FILE_ATTRIBUTES);
		}

		bool is_directory(const CharArray &path)
		{
			DWORD attrib = attributes(path);

			return ((attrib != INVALID_FILE_ATTRIBUTES) && (attrib & FILE_ATTRIBUTE_DIRECTORY));
		}

		bool is_file(const CharArray &path)
		{
			DWORD attrib = attributes(path);

			return ((attrib != INVALID_FILE_ATTRIBUTES) && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
		}

		PVOID exception_handler;

		LONG CALLBACK vectored_handler(_EXCEPTION_POINTERS *info)
		{
			if(info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW && context && context->frame)
			{
				throw Collector::allocate<Exception>(context->system_stack_error, String::get("Stack overflow"), backtrace(context->frame->prev));
			}

			return EXCEPTION_CONTINUE_SEARCH;
		}

		void initialize(bool console)
		{
			if(console)
			{
				SetConsoleTitle(TEXT("mirb"));

				if(!SetConsoleCtrlHandler(ctrl_handler, TRUE))
					std::cerr << "Unable to register console handler" << std::endl;
			}

			exception_handler = AddVectoredExceptionHandler(0, vectored_handler);

			if(!exception_handler)
				std::cerr << "Unable to register vectored exception handler" << std::endl;
		}

		void finalize()
		{
			if(exception_handler)
				RemoveVectoredExceptionHandler(exception_handler);
		}
	};
};

#endif<commit_msg>Stack overflows on Windows aren't handled correctly.<commit_after>#include "platform.hpp"

#ifdef WIN32

#include "../classes/string.hpp"
#include "../collector.hpp"
#include "../runtime.hpp"

namespace Mirb
{
	namespace Platform
	{
		void raise(const CharArray &message)
		{
			TCHAR *msg_buffer;
			DWORD err_no = GetLastError();

			FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |	FORMAT_MESSAGE_IGNORE_INSERTS, 0, err_no, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&msg_buffer, 0, 0);

			CharArray msg = message + "\nError #" + CharArray::uint(err_no) + ": "   + from_tchar(msg_buffer);

			LocalFree(msg_buffer);

			throw create_exception(context->system_call_error, msg);
		}

		std::string BenchmarkResult::format()
		{
			std::stringstream result;

			result << (((double)1000 * time.QuadPart) / (double)freq.QuadPart) << " ms";

			return result.str();
		}

		void *allocate_region(size_t bytes)
		{
			void *result = VirtualAlloc(0, bytes, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);

			mirb_runtime_assert(result != 0);

			return result;
		}

		void free_region(void *region, size_t)
		{
			VirtualFree(region, 0, MEM_RELEASE);
		}

		CharArray from_tchar(const TCHAR *buffer, size_t tchars)
		{
			#ifdef _UNICODE
				size_t size = WideCharToMultiByte(CP_UTF8, 0, buffer, tchars, nullptr, 0, NULL, NULL);

				char *new_buffer = (char *)alloca(size);

				size = WideCharToMultiByte(CP_UTF8, 0, buffer, tchars, new_buffer, size, NULL, NULL);

				if(size == 0)
					raise("Unable to convert UCS-2 pathname to UTF-8");

				return CharArray((const char_t *)new_buffer, size);
			#else
				return CharArray((const char_t *)buffer, tchars);
			#endif
		}

		CharArray from_tchar(const TCHAR *buffer)
		{
			return from_tchar(buffer, _tcslen(buffer));
		}

		BOOL WINAPI ctrl_handler(DWORD ctrl_type)
		{
			switch(ctrl_type)
			{
				case CTRL_C_EVENT:
					Collector::signal();
					return TRUE;

				default:
					return FALSE;
			}
		}

		CharArray normalize_separator_to(const CharArray &path)
		{
			CharArray result = path;

			result.localize();

			for(size_t i = 0; i < result.size(); ++i)
				if(result[i] == '/')
					result[i] = '\\';

			if(result[result.size()-1] == '\\')
				result.shrink(result.size() - 1);

			return result;
		}

		CharArray normalize_separator_from(const CharArray &path)
		{
			CharArray result = path;

			result.localize();

			for(size_t i = 0; i < result.size(); ++i)
				if(result[i] == '\\')
					result[i] = '/';

			if(result[result.size()-1] == '/')
				result.shrink(result.size() - 1);

			return result;
		}

		CharArray from_win_path(const CharArray &path)
		{
			#ifdef _UNICODE
				CharArray result = (path.copy(0, 4) == "\\\\?\\") ? path.copy(4, path.size()) : path;

				return normalize_separator_from(result);
			#else
				return normalize_separator_from(path);
			#endif
		}

		CharArray to_win_path(const CharArray &path)
		{
			#ifdef _UNICODE
				return "\\\\?\\" + normalize_separator_to(path);
			#else
				return normalize_separator_to(path);
			#endif
		}

		CharArray from_short_win_path(const TCHAR *buffer)
		{
			#ifdef _UNICODE
				size_t size = GetLongPathName(buffer, 0, 0);

				TCHAR *long_buffer = (TCHAR *)alloca((size + 1) * sizeof(TCHAR));

				if(GetLongPathName(buffer, long_buffer, size + 1) == 0)
					raise("Unable to convert short pathname to a long pathname");

				return from_win_path(from_tchar(long_buffer));
			#else
				return from_win_path(from_tchar(buffer));
			#endif
		}

		DWORD attributes(const CharArray &path)
		{
			DWORD attrib;

			to_tchar(to_win_path(path), [&](const TCHAR *buffer, size_t) {
				attrib = GetFileAttributes(buffer);
			});

			return attrib;
		}

		CharArray cwd()
		{
			size_t size = GetCurrentDirectory(0, 0);

			TCHAR *buffer = (TCHAR *)alloca(size * sizeof(TCHAR));

			if(GetCurrentDirectory(size, buffer) == 0)
				raise("Unable to get the current directory");

			return from_short_win_path(buffer);
		}

		void cd(const CharArray &path)
		{
			to_short_win_path(path, [&](const TCHAR *buffer) {
				if(SetCurrentDirectory(buffer) == 0)
					raise("Unable change the current directory to '" + path + "'");
			});
		}

		bool file_exists(const CharArray &path)
		{
			return (attributes(path) != INVALID_FILE_ATTRIBUTES);
		}

		bool is_directory(const CharArray &path)
		{
			DWORD attrib = attributes(path);

			return ((attrib != INVALID_FILE_ATTRIBUTES) && (attrib & FILE_ATTRIBUTE_DIRECTORY));
		}

		bool is_file(const CharArray &path)
		{
			DWORD attrib = attributes(path);

			return ((attrib != INVALID_FILE_ATTRIBUTES) && !(attrib & FILE_ATTRIBUTE_DIRECTORY));
		}

		PVOID exception_handler;

		void __fastcall stack_overflow_handler(_EXCEPTION_POINTERS *info)
		{
			// Restore guard page as described on http://support.microsoft.com/kb/315937

			LPBYTE stack;
			SYSTEM_INFO system_info;
			MEMORY_BASIC_INFORMATION mem_info;
			DWORD old_protect;

			// Get page size of system

			GetSystemInfo(&system_info);

			#ifdef _AMD64_
				stack = (LPBYTE)info->ContextRecord->Rsp;
			#else
				stack = (LPBYTE)info->ContextRecord->Esp;
			#endif

			// Get allocation base of stack

			mirb_runtime_assert(VirtualQuery(stack, &mem_info, sizeof(mem_info)) != 0);

			// Go to page beyond current page

			stack = (LPBYTE)(mem_info.BaseAddress) - system_info.dwPageSize;

			// Free portion of stack just abandoned

			mirb_runtime_assert(VirtualFree(mem_info.AllocationBase, stack - (LPBYTE)mem_info.AllocationBase, MEM_DECOMMIT) != 0);

			// Reintroduce the guard page

			mirb_runtime_assert(VirtualProtect(stack, system_info.dwPageSize, PAGE_GUARD | PAGE_READWRITE, &old_protect) != 0);

			auto exception = Collector::allocate<Exception>(context->system_stack_error, String::get("Stack overflow"), backtrace(context->frame->prev));

			throw exception;
		}

		const size_t overflow_stack_pages = 10;

		LONG CALLBACK vectored_handler(_EXCEPTION_POINTERS *info)
		{
			if(info->ExceptionRecord->ExceptionCode == EXCEPTION_STACK_OVERFLOW && context && context->frame)
			{
				static DWORD old_protect;

				auto new_stack = VirtualAlloc(0, 0x1000 * (overflow_stack_pages + 2), MEM_COMMIT, PAGE_READWRITE);

				mirb_runtime_assert(new_stack != 0);

				mirb_runtime_assert(VirtualProtect(new_stack, 0x1000, PAGE_GUARD | PAGE_READWRITE, &old_protect) != 0);

				new_stack = (LPVOID)((char *)new_stack + 0x1000 * (overflow_stack_pages + 1));

				mirb_runtime_assert(VirtualProtect(new_stack, 0x1000, PAGE_GUARD | PAGE_READWRITE, &old_protect) != 0);

#ifdef _MSC_VER
				__asm
				{
					mov ecx, info
					mov esp, new_stack
					call stack_overflow_handler
				};
#else
				asm("mov %0, %%rcx\nmov %1, %%rsp\ncall *%2" :: "g" (info), "g" (new_stack), "r" (&stack_overflow_handler));
#endif
			}

			return EXCEPTION_CONTINUE_SEARCH;
		}

		void initialize(bool console)
		{
			if(console)
			{
				SetConsoleTitle(TEXT("mirb"));

				if(!SetConsoleCtrlHandler(ctrl_handler, TRUE))
					std::cerr << "Unable to register console handler" << std::endl;
			}

			exception_handler = AddVectoredExceptionHandler(0, vectored_handler);

			if(!exception_handler)
				std::cerr << "Unable to register vectored exception handler" << std::endl;
		}

		void finalize()
		{
			if(exception_handler)
				RemoveVectoredExceptionHandler(exception_handler);
		}
	};
};

#endif<|endoftext|>