<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 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
 *
 *****************************************************************************/

#ifndef MAPNIK_JSON_TOPOJSON_GRAMMAR_X3_DEF_HPP
#define MAPNIK_JSON_TOPOJSON_GRAMMAR_X3_DEF_HPP

#include <mapnik/json/topojson_grammar_x3.hpp>
#include <mapnik/json/unicode_string_grammar_x3.hpp>
#include <mapnik/json/generic_json_grammar_x3.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#pragma GCC diagnostic pop

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::topojson::coordinate,
    (double, x)
    (double, y)
    )

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::topojson::arc,
    (std::list<mapnik::topojson::coordinate>, coordinates)
    )

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::topojson::transform,
    (double, scale_x)
    (double, scale_y)
    (double, translate_x)
    (double, translate_y)
    )

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::topojson::bounding_box,
    (double, minx)
    (double, miny)
    (double, maxx)
    (double, maxy)
    )

namespace mapnik { namespace json { namespace grammar {

using index_type = topojson::index_type;
struct create_point
{
    using result_type = mapnik::topojson::point;
    template <typename T0, typename T1>
    result_type operator()(T0 & coord, T1 & props) const
    {
        mapnik::topojson::point pt;
        if (coord.template is<mapnik::topojson::coordinate>())
        {
            auto const& coord_ = coord.template get<mapnik::topojson::coordinate>();
            pt.coord = coord_;
            pt.props = props;
        }
        return pt;
    }
};

struct create_multi_point
{
    using result_type = mapnik::topojson::multi_point;
    template <typename T0, typename T1>
    result_type operator()(T0 & coords, T1 & props) const
    {
        mapnik::topojson::multi_point mpt;
        if (coords.template is<std::vector<mapnik::topojson::coordinate>>())
        {
            auto const& points = coords.template get<std::vector<mapnik::topojson::coordinate>>();
            mpt. points = points;
            mpt.props = props;
        }
        return mpt;
    }
};

struct create_line_string
{
    using result_type = mapnik::topojson::linestring;
    template <typename T0, typename T1>
    result_type operator()(T0 & arcs, T1 & props) const
    {
        mapnik::topojson::linestring line;
        if (arcs.template is<std::vector<index_type>>())
        {
            auto const& arcs_ = arcs.template get<std::vector<index_type>>();
            line.rings = arcs_;
            line.props = props;
        }
        return line;
    }
};

struct create_multi_line_string
{
    using result_type = mapnik::topojson::multi_linestring;
    template <typename T0, typename T1>
    result_type operator()(T0 & arcs, T1 & props) const
    {
        mapnik::topojson::multi_linestring mline;
        if (arcs.template is<std::vector<std::vector<index_type>>>())
        {
            auto const& arcs_ = arcs.template get<std::vector<std::vector<index_type>>>();
            mline.lines = arcs_;
            mline.props = props;
        }
        return mline;
    }
};

struct create_polygon
{
    using result_type = mapnik::topojson::polygon;
    template <typename T0, typename T1>
    result_type operator()(T0 & arcs, T1 & props) const
    {
        mapnik::topojson::polygon poly;
        if (arcs.template is<std::vector<std::vector<index_type>>>())
        {
            auto const& arcs_ = arcs.template get<std::vector<std::vector<index_type>>>();
            poly.rings = arcs_;
            poly.props = props;
        }
        return poly;
    }
};

struct create_multi_polygon
{
    using result_type = mapnik::topojson::multi_polygon;
    template <typename T0, typename T1>
    result_type operator()(T0 & arcs, T1 & props) const
    {
        mapnik::topojson::multi_polygon mpoly;
        if (arcs.template is<std::vector<std::vector<std::vector<index_type>>>>())
        {
            auto const& arcs_ = arcs.template get<std::vector<std::vector<std::vector<index_type>>>>();
            mpoly.polygons = arcs_;
            mpoly.props = props;
        }
        return mpoly;
    }
};

auto create_geometry = [] (auto const& ctx)
{
    auto const geom_type = std::get<0>(_attr(ctx));
    auto const& coord = std::get<1>(_attr(ctx));
    auto const& arcs = std::get<2>(_attr(ctx));
    auto const& props = std::get<3>(_attr(ctx));
    mapnik::topojson::geometry geom; //empty
    switch (geom_type)
    {
    case 1: //Point
        geom = create_point()(coord, props);
        break;
    case 2: //LineString
        geom = create_line_string()(arcs, props);
        break;
    case 3: //Polygon
        geom = create_polygon()(arcs, props);
        break;
    case 4: //MultiPoint
        geom = create_multi_point()(coord, props);
        break;
    case 5: //MultiLineString
        geom = create_multi_line_string()(arcs, props);
        break;
    case 6: //MultiPolygon
        geom = create_multi_polygon()(arcs, props);
        break;
    }
    _val(ctx) = std::move(geom);
};

auto assign_bbox = [] (auto const& ctx)
{
    _val(ctx).bbox = std::move(_attr(ctx));
};

auto assign_transform = [] (auto const& ctx)
{
    _val(ctx).tr = std::move(_attr(ctx));
};

auto assign_arcs = [] (auto const& ctx)
{
    _val(ctx).arcs = std::move(_attr(ctx));
};

auto assign_objects = [] (auto const& ctx)
{
    _val(ctx).geometries = std::move(_attr(ctx));
};

auto push_geometry = [] (auto const& ctx)
{
    _val(ctx).push_back(std::move(_attr(ctx)));
};

auto push_collection = [] (auto const& ctx)
{
    auto & dest = _val(ctx);
    auto & src = _attr(ctx);
    if (dest.empty()) dest = std::move(src);
    else
    {
        dest.reserve(dest.size() + src.size());
        dest.insert(std::end(dest),
                    std::make_move_iterator(std::begin(src)),
                    std::make_move_iterator(std::end(src)));
    }
};

auto assign_geometry_type = [] (auto const& ctx)
{
    std::get<0>(_val(ctx)) = _attr(ctx);
};

auto assign_coordinates = [] (auto const& ctx)
{
    std::get<1>(_val(ctx)) = std::move(_attr(ctx));
};

auto assign_rings = [] (auto const& ctx)
{
    std::get<2>(_val(ctx)) = std::move(_attr(ctx));
};

auto assign_properties = [] (auto const& ctx)
{
    std::get<3>(_val(ctx)) = std::move(_attr(ctx));
};

auto assign_prop_name = [] (auto const& ctx)
{
    std::get<0>(_val(ctx)) = std::move(_attr(ctx));
};

auto assign_prop_value = [] (auto const& ctx)
{
    std::get<1>(_val(ctx)) = std::move(_attr(ctx));
};

namespace x3 = boost::spirit::x3;

using x3::lit;
using x3::double_;
using x3::int_;
using x3::omit;
using x3::char_;
namespace
{
// import unicode string rule
auto const& json_string = json::unicode_string_grammar();
// json value
auto const& json_value = json::generic_json_grammar();
}

using coordinates_type = util::variant<topojson::coordinate,std::vector<topojson::coordinate>>;
using arcs_type = util::variant<std::vector<index_type>,
                                std::vector<std::vector<index_type>>,
                                std::vector<std::vector<std::vector<index_type>>>>;

struct geometry_type_ : x3::symbols<int>
{
    geometry_type_()
    {
        add
            ("\"Point\"",1)
            ("\"LineString\"",2)
            ("\"Polygon\"",3)
            ("\"MultiPoint\"",4)
            ("\"MultiLineString\"",5)
            ("\"MultiPolygon\"",6)
            ;
    }
} geometry_type;

// start rule
topojson_grammar_type const topology = "Topology";
// rules
x3::rule<class transform_tag, mapnik::topojson::transform> const transform = "Transform";
x3::rule<class bbox_tag, mapnik::topojson::bounding_box> const bbox = "Bounding Box";
x3::rule<class objects_tag, std::vector<mapnik::topojson::geometry>> const objects= "Objects";
x3::rule<class property_tag, mapnik::topojson::property> const property = "Property";
x3::rule<class properties_tag, mapnik::topojson::properties> const properties = "Properties";
x3::rule<class geometry_tag, mapnik::topojson::geometry> const geometry = "Geometry";
x3::rule<class geometry_collection_tag, std::vector<mapnik::topojson::geometry>> const geometry_collection = "Geometry Collection";
x3::rule<class geometry_tuple_tag,
         std::tuple<int,
                    coordinates_type,
                    arcs_type,
                    mapnik::topojson::properties>> const geometry_tuple = "Geometry Tuple";
x3::rule<class coordinate_tag, mapnik::topojson::coordinate> const coordinate = "Coordinate";
x3::rule<class coordinates_tag, coordinates_type> const coordinates = "Coordinates";
x3::rule<class arc_tag, mapnik::topojson::arc> const arc = "Arc";
x3::rule<class arcs_tag, std::vector<mapnik::topojson::arc>> const arcs = "Arcs";
x3::rule<class ring_type, std::vector<index_type>> const ring = "Ring";
x3::rule<class rings_type, std::vector<std::vector<index_type>>> const rings = "Rings";
x3::rule<class rings_array_type, arcs_type> const rings_array = "Rings Array";

// defs
auto const topology_def = lit('{') >
    -(((lit("\"type\"") > lit(':') > lit("\"Topology\""))
       |
       bbox[assign_bbox]
       |
       transform[assign_transform]
       |
       objects[assign_objects]
       |
       arcs[assign_arcs]) % lit(','))
      > lit('}')
      ;

auto const transform_def = lit("\"transform\"") > lit(':') > lit('{')
    > lit("\"scale\"") > lit(':')
    > lit('[')
    > double_ > lit(',')
    > double_ > lit(']') > lit(',')
    > lit("\"translate\"") > lit(':')
    > lit('[') > double_ > lit(',') > double_ > lit(']')
    > lit('}')
    ;

auto const  bbox_def = lit("\"bbox\"") > lit(':')
    > lit('[') > double_ > lit(',') > double_
    > lit(',') > double_ > lit(',') > double_
    > lit(']')
    ;

auto const objects_def = lit("\"objects\"") > lit(':')
    > lit('{')
    > ((omit[*~char_(':')] > lit(':') > ((geometry_collection[push_collection] | geometry[push_geometry]))) % lit(','))
    > lit('}')
    ;

auto const geometry_tuple_def =
    ((lit("\"type\"") > lit(':') > geometry_type[assign_geometry_type])
     |
     (lit("\"coordinates\"") > lit(':') > coordinates[assign_coordinates])
     |
     (lit("\"arcs\"") > lit(':') > rings_array[assign_rings])
     |
     properties[assign_properties]
     |
     (omit[json_string] > lit(':') > omit[json_value])) % lit(',')
    ;

auto const geometry_def = lit("{") > geometry_tuple[create_geometry] > lit("}");

auto const geometry_collection_def = (lit('{') >> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"") >> -omit[lit(',') >> bbox])
    > lit(',') > lit("\"geometries\"") > lit(':')
    > lit('[')
    > -(geometry[push_geometry] % lit(','))
    > lit(']')
    > lit('}')
    ;

auto const ring_def = lit('[') >> (int_ % lit(',')) >> lit(']')
    ;
auto const rings_def = lit('[') >> (ring % lit(',')) >> lit(']')
    ;
auto const rings_array_def = (lit('[') >> (rings % lit(',')) >> lit(']'))
    |
    rings
    |
    ring
    ;

auto const property_def = json_string[assign_prop_name] > lit(':') > json_value[assign_prop_value]
    ;

auto const properties_def = lit("\"properties\"")
    > lit(':')
    > lit('{') > (property % lit(',')) > lit('}')
    ;

auto const arcs_def = lit("\"arcs\"") >> lit(':') >> lit('[') >> -( arc % lit(',')) >> lit(']') ;

auto const arc_def = lit('[') >> -(coordinate % lit(',')) >> lit(']') ;

auto const coordinate_def = lit('[') >> double_ >> lit(',') >> double_ >> omit[*(lit(',') >> double_)] >> lit(']');

auto const coordinates_def = (lit('[') >> coordinate % lit(',') >> lit(']')) | coordinate;

BOOST_SPIRIT_DEFINE(
    topology,
    transform,
    bbox,
    objects,
    geometry_tuple,
    geometry,
    geometry_collection,
    ring,
    rings,
    rings_array,
    property,
    properties,
    arcs,
    arc,
    coordinate,
    coordinates
    );

}}}

namespace mapnik { namespace json {
grammar::topojson_grammar_type const& topojson_grammar()
{
    return grammar::topology;
}
}}

#endif //MAPNIK_TOPOJSON_GRAMMAR_X3_DEF_HPP
<commit_msg>rename 'geometry_type' to 'topojson_geometry_type' to avoid names clashing (this was causing miscompilation on linux (ubuntu 17.04/clang))<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2017 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
 *
 *****************************************************************************/

#ifndef MAPNIK_JSON_TOPOJSON_GRAMMAR_X3_DEF_HPP
#define MAPNIK_JSON_TOPOJSON_GRAMMAR_X3_DEF_HPP

#include <mapnik/json/topojson_grammar_x3.hpp>
#include <mapnik/json/unicode_string_grammar_x3.hpp>
#include <mapnik/json/generic_json_grammar_x3.hpp>
#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <boost/fusion/adapted/struct.hpp>
#include <boost/fusion/adapted/std_tuple.hpp>
#pragma GCC diagnostic pop

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::topojson::coordinate,
    (double, x)
    (double, y)
    )

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::topojson::arc,
    (std::list<mapnik::topojson::coordinate>, coordinates)
    )

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::topojson::transform,
    (double, scale_x)
    (double, scale_y)
    (double, translate_x)
    (double, translate_y)
    )

BOOST_FUSION_ADAPT_STRUCT(
    mapnik::topojson::bounding_box,
    (double, minx)
    (double, miny)
    (double, maxx)
    (double, maxy)
    )

namespace mapnik { namespace json { namespace grammar {

using index_type = topojson::index_type;
struct create_point
{
    using result_type = mapnik::topojson::point;
    template <typename T0, typename T1>
    result_type operator()(T0 & coord, T1 & props) const
    {
        mapnik::topojson::point pt;
        if (coord.template is<mapnik::topojson::coordinate>())
        {
            auto const& coord_ = coord.template get<mapnik::topojson::coordinate>();
            pt.coord = coord_;
            pt.props = props;
        }
        return pt;
    }
};

struct create_multi_point
{
    using result_type = mapnik::topojson::multi_point;
    template <typename T0, typename T1>
    result_type operator()(T0 & coords, T1 & props) const
    {
        mapnik::topojson::multi_point mpt;
        if (coords.template is<std::vector<mapnik::topojson::coordinate>>())
        {
            auto const& points = coords.template get<std::vector<mapnik::topojson::coordinate>>();
            mpt. points = points;
            mpt.props = props;
        }
        return mpt;
    }
};

struct create_line_string
{
    using result_type = mapnik::topojson::linestring;
    template <typename T0, typename T1>
    result_type operator()(T0 & arcs, T1 & props) const
    {
        mapnik::topojson::linestring line;
        if (arcs.template is<std::vector<index_type>>())
        {
            auto const& arcs_ = arcs.template get<std::vector<index_type>>();
            line.rings = arcs_;
            line.props = props;
        }
        return line;
    }
};

struct create_multi_line_string
{
    using result_type = mapnik::topojson::multi_linestring;
    template <typename T0, typename T1>
    result_type operator()(T0 & arcs, T1 & props) const
    {
        mapnik::topojson::multi_linestring mline;
        if (arcs.template is<std::vector<std::vector<index_type>>>())
        {
            auto const& arcs_ = arcs.template get<std::vector<std::vector<index_type>>>();
            mline.lines = arcs_;
            mline.props = props;
        }
        return mline;
    }
};

struct create_polygon
{
    using result_type = mapnik::topojson::polygon;
    template <typename T0, typename T1>
    result_type operator()(T0 & arcs, T1 & props) const
    {
        mapnik::topojson::polygon poly;
        if (arcs.template is<std::vector<std::vector<index_type>>>())
        {
            auto const& arcs_ = arcs.template get<std::vector<std::vector<index_type>>>();
            poly.rings = arcs_;
            poly.props = props;
        }
        return poly;
    }
};

struct create_multi_polygon
{
    using result_type = mapnik::topojson::multi_polygon;
    template <typename T0, typename T1>
    result_type operator()(T0 & arcs, T1 & props) const
    {
        mapnik::topojson::multi_polygon mpoly;
        if (arcs.template is<std::vector<std::vector<std::vector<index_type>>>>())
        {
            auto const& arcs_ = arcs.template get<std::vector<std::vector<std::vector<index_type>>>>();
            mpoly.polygons = arcs_;
            mpoly.props = props;
        }
        return mpoly;
    }
};

auto create_geometry = [] (auto const& ctx)
{
    auto const geom_type = std::get<0>(_attr(ctx));
    auto const& coord = std::get<1>(_attr(ctx));
    auto const& arcs = std::get<2>(_attr(ctx));
    auto const& props = std::get<3>(_attr(ctx));
    mapnik::topojson::geometry geom; //empty
    switch (geom_type)
    {
    case 1: //Point
        geom = create_point()(coord, props);
        break;
    case 2: //LineString
        geom = create_line_string()(arcs, props);
        break;
    case 3: //Polygon
        geom = create_polygon()(arcs, props);
        break;
    case 4: //MultiPoint
        geom = create_multi_point()(coord, props);
        break;
    case 5: //MultiLineString
        geom = create_multi_line_string()(arcs, props);
        break;
    case 6: //MultiPolygon
        geom = create_multi_polygon()(arcs, props);
        break;
    }
    _val(ctx) = std::move(geom);
};

auto assign_bbox = [] (auto const& ctx)
{
    _val(ctx).bbox = std::move(_attr(ctx));
};

auto assign_transform = [] (auto const& ctx)
{
    _val(ctx).tr = std::move(_attr(ctx));
};

auto assign_arcs = [] (auto const& ctx)
{
    _val(ctx).arcs = std::move(_attr(ctx));
};

auto assign_objects = [] (auto const& ctx)
{
    _val(ctx).geometries = std::move(_attr(ctx));
};

auto push_geometry = [] (auto const& ctx)
{
    _val(ctx).push_back(std::move(_attr(ctx)));
};

auto push_collection = [] (auto const& ctx)
{
    auto & dest = _val(ctx);
    auto & src = _attr(ctx);
    if (dest.empty()) dest = std::move(src);
    else
    {
        dest.reserve(dest.size() + src.size());
        dest.insert(std::end(dest),
                    std::make_move_iterator(std::begin(src)),
                    std::make_move_iterator(std::end(src)));
    }
};

auto assign_geometry_type = [] (auto const& ctx)
{
    std::get<0>(_val(ctx)) = _attr(ctx);
};

auto assign_coordinates = [] (auto const& ctx)
{
    std::get<1>(_val(ctx)) = std::move(_attr(ctx));
};

auto assign_rings = [] (auto const& ctx)
{
    std::get<2>(_val(ctx)) = std::move(_attr(ctx));
};

auto assign_properties = [] (auto const& ctx)
{
    std::get<3>(_val(ctx)) = std::move(_attr(ctx));
};

auto assign_prop_name = [] (auto const& ctx)
{
    std::get<0>(_val(ctx)) = std::move(_attr(ctx));
};

auto assign_prop_value = [] (auto const& ctx)
{
    std::get<1>(_val(ctx)) = std::move(_attr(ctx));
};

namespace x3 = boost::spirit::x3;

using x3::lit;
using x3::double_;
using x3::int_;
using x3::omit;
using x3::char_;
namespace
{
// import unicode string rule
auto const& json_string = json::unicode_string_grammar();
// json value
auto const& json_value = json::generic_json_grammar();
}

using coordinates_type = util::variant<topojson::coordinate,std::vector<topojson::coordinate>>;
using arcs_type = util::variant<std::vector<index_type>,
                                std::vector<std::vector<index_type>>,
                                std::vector<std::vector<std::vector<index_type>>>>;

struct topojson_geometry_type_ : x3::symbols<int>
{
    topojson_geometry_type_()
    {
        add
            ("\"Point\"",1)
            ("\"LineString\"",2)
            ("\"Polygon\"",3)
            ("\"MultiPoint\"",4)
            ("\"MultiLineString\"",5)
            ("\"MultiPolygon\"",6)
            ;
    }
} topojson_geometry_type;

// start rule
topojson_grammar_type const topology = "Topology";
// rules
x3::rule<class transform_tag, mapnik::topojson::transform> const transform = "Transform";
x3::rule<class bbox_tag, mapnik::topojson::bounding_box> const bbox = "Bounding Box";
x3::rule<class objects_tag, std::vector<mapnik::topojson::geometry>> const objects= "Objects";
x3::rule<class property_tag, mapnik::topojson::property> const property = "Property";
x3::rule<class properties_tag, mapnik::topojson::properties> const properties = "Properties";
x3::rule<class geometry_tag, mapnik::topojson::geometry> const geometry = "Geometry";
x3::rule<class geometry_collection_tag, std::vector<mapnik::topojson::geometry>> const geometry_collection = "Geometry Collection";
x3::rule<class geometry_tuple_tag,
         std::tuple<int,
                    coordinates_type,
                    arcs_type,
                    mapnik::topojson::properties>> const geometry_tuple = "Geometry Tuple";
x3::rule<class coordinate_tag, mapnik::topojson::coordinate> const coordinate = "Coordinate";
x3::rule<class coordinates_tag, coordinates_type> const coordinates = "Coordinates";
x3::rule<class arc_tag, mapnik::topojson::arc> const arc = "Arc";
x3::rule<class arcs_tag, std::vector<mapnik::topojson::arc>> const arcs = "Arcs";
x3::rule<class ring_type, std::vector<index_type>> const ring = "Ring";
x3::rule<class rings_type, std::vector<std::vector<index_type>>> const rings = "Rings";
x3::rule<class rings_array_type, arcs_type> const rings_array = "Rings Array";

// defs
auto const topology_def = lit('{') >
    -(((lit("\"type\"") > lit(':') > lit("\"Topology\""))
       |
       bbox[assign_bbox]
       |
       transform[assign_transform]
       |
       objects[assign_objects]
       |
       arcs[assign_arcs]) % lit(','))
      > lit('}')
      ;

auto const transform_def = lit("\"transform\"") > lit(':') > lit('{')
    > lit("\"scale\"") > lit(':')
    > lit('[')
    > double_ > lit(',')
    > double_ > lit(']') > lit(',')
    > lit("\"translate\"") > lit(':')
    > lit('[') > double_ > lit(',') > double_ > lit(']')
    > lit('}')
    ;

auto const  bbox_def = lit("\"bbox\"") > lit(':')
    > lit('[') > double_ > lit(',') > double_
    > lit(',') > double_ > lit(',') > double_
    > lit(']')
    ;

auto const objects_def = lit("\"objects\"") > lit(':')
    > lit('{')
    > ((omit[*~char_(':')] > lit(':') > ((geometry_collection[push_collection] | geometry[push_geometry]))) % lit(','))
    > lit('}')
    ;

auto const geometry_tuple_def =
    ((lit("\"type\"") > lit(':') > topojson_geometry_type[assign_geometry_type])
     |
     (lit("\"coordinates\"") > lit(':') > coordinates[assign_coordinates])
     |
     (lit("\"arcs\"") > lit(':') > rings_array[assign_rings])
     |
     properties[assign_properties]
     |
     (omit[json_string] > lit(':') > omit[json_value])) % lit(',')
    ;

auto const geometry_def = lit("{") > geometry_tuple[create_geometry] > lit("}");

auto const geometry_collection_def = (lit('{') >> lit("\"type\"") >> lit(':') >> lit("\"GeometryCollection\"") >> -omit[lit(',') >> bbox])
    > lit(',') > lit("\"geometries\"") > lit(':')
    > lit('[')
    > -(geometry[push_geometry] % lit(','))
    > lit(']')
    > lit('}')
    ;

auto const ring_def = lit('[') >> (int_ % lit(',')) >> lit(']')
    ;
auto const rings_def = lit('[') >> (ring % lit(',')) >> lit(']')
    ;
auto const rings_array_def = (lit('[') >> (rings % lit(',')) >> lit(']'))
    |
    rings
    |
    ring
    ;

auto const property_def = json_string[assign_prop_name] > lit(':') > json_value[assign_prop_value]
    ;

auto const properties_def = lit("\"properties\"")
    > lit(':')
    > lit('{') > (property % lit(',')) > lit('}')
    ;

auto const arcs_def = lit("\"arcs\"") >> lit(':') >> lit('[') >> -( arc % lit(',')) >> lit(']') ;

auto const arc_def = lit('[') >> -(coordinate % lit(',')) >> lit(']') ;

auto const coordinate_def = lit('[') >> double_ >> lit(',') >> double_ >> omit[*(lit(',') >> double_)] >> lit(']');

auto const coordinates_def = (lit('[') >> coordinate % lit(',') >> lit(']')) | coordinate;

BOOST_SPIRIT_DEFINE(
    topology,
    transform,
    bbox,
    objects,
    geometry_tuple,
    geometry,
    geometry_collection,
    ring,
    rings,
    rings_array,
    property,
    properties,
    arcs,
    arc,
    coordinate,
    coordinates
    );

}}}

namespace mapnik { namespace json {
grammar::topojson_grammar_type const& topojson_grammar()
{
    return grammar::topology;
}
}}

#endif //MAPNIK_TOPOJSON_GRAMMAR_X3_DEF_HPP
<|endoftext|>


<commit_before>/*
============================================================================
DELLY: Structural variant discovery by integrated PE mapping and SR analysis
============================================================================
Copyright (C) 2012 Tobias Rausch

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

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

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
============================================================================
Contact: Tobias Rausch (rausch@embl.de)
============================================================================
*/

#include <iostream>
#include <fstream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/tokenizer.hpp>
#include <boost/progress.hpp>
#include "api/BamReader.h"
#include "api/BamIndex.h"

#ifdef OPENMP
#include <omp.h>
#endif

#include "tags.h"
#include "coverage.h"
#include "version.h"
#include "util.h"

using namespace torali;

struct Config {
  unsigned int window_size;
  unsigned int window_offset;
  uint16_t minMapQual;
  bool bp_flag;
  bool avg_flag;
  bool inclCigar;
  boost::filesystem::path outfile;
  boost::filesystem::path int_file;
  std::vector<boost::filesystem::path> files;
};

template<typename TSingleHit, typename TCoverageType>
inline int
run(Config const& c, TSingleHit, TCoverageType covType)
{
  // Create library objects
  typedef std::map<std::string, LibraryInfo> TLibraryMap;
  typedef std::map<std::string, TLibraryMap> TSampleLibrary;
  TSampleLibrary sampleLib;

  // Scan libraries
  for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
    // Get a sample name
    std::string sampleName(c.files[file_c].stem().string());

    // Check that all input bam files exist
    BamTools::BamReader reader;
    if ( ! reader.Open(c.files[file_c].string()) ) {
      std::cerr << "Could not open input bam file: " << c.files[file_c].string() << std::endl;
      reader.Close();
      return -1;
    }

    // Check that all input bam files are indexed
    reader.LocateIndex();
    if ( !reader.HasIndex() ) {
      std::cerr << "Missing bam index file: " << c.files[file_c].string() << std::endl;
      reader.Close();
      return -1;
    }

    // Get library parameters and overall maximum insert size
    TLibraryMap libInfo;
    getLibraryParams(c.files[file_c], libInfo, 0, 5);
    sampleLib.insert(std::make_pair(sampleName, libInfo));
  }

  // Get references
  BamTools::BamReader readerRef;
  if ( ! readerRef.Open(c.files[0].string()) ) return -1;
  BamTools::RefVector references = readerRef.GetReferenceData();

  // Read all SV intervals
  typedef std::vector<StructuralVariantRecord> TSVs;
  TSVs svs;
  std::map<unsigned int, std::string> idToName;
  unsigned int intervalCount=1;
  if (boost::filesystem::exists(c.int_file) && boost::filesystem::is_regular_file(c.int_file) && boost::filesystem::file_size(c.int_file)) {
    typedef boost::unordered_map<std::string, unsigned int> TMapChr;
    TMapChr mapChr;
    typename BamTools::RefVector::const_iterator itRef = references.begin();
    for(unsigned int i = 0;itRef!=references.end();++itRef, ++i) mapChr[ itRef->RefName ] = i;
    std::ifstream interval_file(c.int_file.string().c_str(), std::ifstream::in);
    if (interval_file.is_open()) {
      while (interval_file.good()) {
	std::string intervalLine;
	getline(interval_file, intervalLine);
	typedef boost::tokenizer< boost::char_separator<char> > Tokenizer;
	boost::char_separator<char> sep(" \t,;");
	Tokenizer tokens(intervalLine, sep);
	Tokenizer::iterator tokIter = tokens.begin();
	if (tokIter!=tokens.end()) {
	  std::string chrName=*tokIter++;
	  TMapChr::const_iterator mapChrIt = mapChr.find(chrName);
	  if (mapChrIt != mapChr.end()) {
	    if (tokIter!=tokens.end()) {
	      StructuralVariantRecord sv;
	      sv.chr = mapChrIt->second;
	      sv.chr2 = mapChrIt->second;
	      sv.svStart = boost::lexical_cast<int32_t>(*tokIter++);
	      sv.svEnd = boost::lexical_cast<int32_t>(*tokIter++) + 1;
	      std::string svName = *tokIter;
	      idToName.insert(std::make_pair(intervalCount, svName));
	      sv.id = intervalCount++;
	      svs.push_back(sv);
	    }
	  }
	}
      }
      interval_file.close();
    }
  } else {
    // Create artificial intervals
    typename BamTools::RefVector::const_iterator itRef = references.begin();
    for(int refIndex=0;itRef!=references.end();++itRef, ++refIndex) {
      int32_t pos = 0;
      while (pos < references[refIndex].RefLength) {
	int32_t window_len = pos+c.window_size;
	if (window_len > references[refIndex].RefLength) window_len = references[refIndex].RefLength;
	StructuralVariantRecord sv;
	sv.chr = refIndex;
	sv.chr2 = refIndex;
	sv.svStart = pos;
	sv.svEnd = window_len;
	std::stringstream s;
	s << references[sv.chr].RefName << ":" << sv.svStart << "-" << sv.svEnd;
	idToName.insert(std::make_pair(intervalCount, s.str()));
	sv.id = intervalCount++;
	svs.push_back(sv);
	pos += c.window_offset;
      }
    }
  }

  // Output data types
  typedef std::pair<std::string, int> TSampleSVPair;
  typedef std::pair<int, int> TBpRead;
  typedef std::map<TSampleSVPair, TBpRead> TCountMap;
  TCountMap countMap;

  // Annotate coverage
  annotateCoverage(c.files, c.minMapQual, c.inclCigar, sampleLib, svs, countMap, TSingleHit(), covType);

  // Output library statistics
  std::cout << "Library statistics" << std::endl;
  TSampleLibrary::const_iterator sampleIt=sampleLib.begin();
  for(;sampleIt!=sampleLib.end();++sampleIt) {
    std::cout << "Sample: " << sampleIt->first << std::endl;
    TLibraryMap::const_iterator libIt=sampleIt->second.begin();
    for(;libIt!=sampleIt->second.end();++libIt) {
      std::cout << "RG: ID=" << libIt->first << ",Median=" << libIt->second.median << ",MAD=" << libIt->second.mad << ",Orientation=" << (int) libIt->second.defaultOrient << ",MappedReads=" << libIt->second.mappedReads << ",DuplicatePairs=" << libIt->second.non_unique_pairs << ",UniquePairs=" << libIt->second.unique_pairs << std::endl;
    }
  }

  // Output file
  boost::iostreams::filtering_ostream dataOut;
  dataOut.push(boost::iostreams::gzip_compressor());
  dataOut.push(boost::iostreams::file_sink(c.outfile.string().c_str(), std::ios_base::out | std::ios_base::binary));

  // Print header
  dataOut << "#chr\tstart\tend\tid";
  for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
    std::string sampleName(c.files[file_c].stem().string());
    dataOut << "\t";
    if (c.avg_flag) dataOut << sampleName << "_avgcov" << "\t";
    if (c.bp_flag) dataOut << sampleName << "_bpcount" << "\t";
    dataOut << sampleName << "_readcount";
  }
  dataOut << std::endl;

  // Iterate all SVs
  typename TSVs::const_iterator itSV = svs.begin();
  typename TSVs::const_iterator itSVEnd = svs.end();
  for(;itSV!=itSVEnd;++itSV) {
    dataOut << references[itSV->chr].RefName << "\t" << itSV->svStart << "\t" << itSV->svEnd << "\t" << idToName.find(itSV->id)->second;
    // Iterate all samples
    for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
      // Get the sample name
      std::string sampleName(c.files[file_c].stem().string());
      TSampleSVPair sampleSVPair = std::make_pair(sampleName, itSV->id);
      typename TCountMap::iterator countMapIt=countMap.find(sampleSVPair);
      dataOut << "\t";
      if (c.avg_flag) dataOut << ( (countMapIt->second.first) / (double) (itSV->svEnd - itSV->svStart)) << "\t";
      if (c.bp_flag) dataOut << countMapIt->second.first << "\t";
      dataOut << countMapIt->second.second;
    }
    dataOut << std::endl;
  }

  // End
  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
  std::cout << '[' << boost::posix_time::to_simple_string(now) << "] Done." << std::endl;;
  return 0;
}

int main(int argc, char **argv) {
  Config c;

  // Define generic options
  boost::program_options::options_description generic("Generic options");
  generic.add_options()
    ("help,?", "show help message")
    ("bp-count,b", "show base pair count")
    ("avg-cov,a", "show average coverage")
    ("disable-redundancy,d", "disable redundancy filtering")
    ("quality-cut,q", boost::program_options::value<uint16_t>(&c.minMapQual)->default_value(0), "exclude all alignments with quality < q")
    ("outfile,f", boost::program_options::value<boost::filesystem::path>(&c.outfile)->default_value("cov.gz"), "coverage output file")
    ;

  // Define window options
  boost::program_options::options_description window("Window options");
  window.add_options()
    ("window-size,s", boost::program_options::value<unsigned int>(&c.window_size)->default_value(10000), "window size")
    ("window-offset,o", boost::program_options::value<unsigned int>(&c.window_offset)->default_value(10000), "window offset")
    ;

  // Define interval options
  boost::program_options::options_description interval("Interval options");
  interval.add_options()
    ("interval-file,i", boost::program_options::value<boost::filesystem::path>(&c.int_file), "interval file")
    ;

  // Define hidden options
  boost::program_options::options_description hidden("Hidden options");
  hidden.add_options()
    ("input-file", boost::program_options::value< std::vector<boost::filesystem::path> >(&c.files), "input file")
    ("license,l", "show license")
    ("warranty,w", "show warranty")
    ;
  boost::program_options::positional_options_description pos_args;
  pos_args.add("input-file", -1);

  // Set the visibility
  boost::program_options::options_description cmdline_options;
  cmdline_options.add(generic).add(window).add(interval).add(hidden);
  boost::program_options::options_description visible_options;
  visible_options.add(generic).add(window).add(interval);
  boost::program_options::variables_map vm;
  boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(cmdline_options).positional(pos_args).run(), vm);
  boost::program_options::notify(vm);

  // Check command line arguments
  if ((vm.count("help")) || (!vm.count("input-file"))) {
    printTitle("Coverage calculation");
    if (vm.count("warranty")) {
      displayWarranty();
    } else if (vm.count("license")) {
      gplV3();
    } else {
      std::cout << "Usage: " << argv[0] << " [OPTIONS] <sample1.bam> <sample2.bam> ..." << std::endl;
      std::cout << visible_options << "\n";
    }
    return 1;
  }
  bool disableRedFilter=false;
  if (vm.count("disable-redundancy")) disableRedFilter=true;
  if (vm.count("bp-count")) c.bp_flag = true;
  else c.bp_flag = false;
  if (vm.count("avg-cov")) c.avg_flag = true;
  else c.avg_flag = false;
  if ((c.bp_flag) || (c.avg_flag)) c.inclCigar = true;
  else c.inclCigar = false;

  // Show cmd
  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
  std::cout << '[' << boost::posix_time::to_simple_string(now) << "] ";
  for(int i=0; i<argc; ++i) { std::cout << argv[i] << ' '; }
  std::cout << std::endl;

  // Run coverage annotation
  if (c.inclCigar) {
    if (disableRedFilter) return run(c, SingleHit<int32_t, std::string>(), CoverageType<NoRedundancyFilterTag>());
    else return run(c, SingleHit<int32_t, std::string>(), CoverageType<RedundancyFilterTag>());
  } else {
    if (disableRedFilter) run(c, SingleHit<int32_t, void>(), CoverageType<NoRedundancyFilterTag>());
    else return run(c, SingleHit<int32_t, void>(), CoverageType<RedundancyFilterTag>());
  }
}
<commit_msg>Removed _readcount in the header.<commit_after>/*
============================================================================
DELLY: Structural variant discovery by integrated PE mapping and SR analysis
============================================================================
Copyright (C) 2012 Tobias Rausch

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

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

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.
============================================================================
Contact: Tobias Rausch (rausch@embl.de)
============================================================================
*/

#include <iostream>
#include <fstream>
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>
#include <boost/program_options/cmdline.hpp>
#include <boost/program_options/options_description.hpp>
#include <boost/program_options/parsers.hpp>
#include <boost/program_options/variables_map.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/date_time/gregorian/gregorian.hpp>
#include <boost/iostreams/stream.hpp>
#include <boost/iostreams/stream_buffer.hpp>
#include <boost/iostreams/device/file.hpp>
#include <boost/iostreams/filtering_stream.hpp>
#include <boost/iostreams/filter/zlib.hpp>
#include <boost/iostreams/filter/gzip.hpp>
#include <boost/tokenizer.hpp>
#include <boost/progress.hpp>
#include "api/BamReader.h"
#include "api/BamIndex.h"

#ifdef OPENMP
#include <omp.h>
#endif

#include "tags.h"
#include "coverage.h"
#include "version.h"
#include "util.h"

using namespace torali;

struct Config {
  unsigned int window_size;
  unsigned int window_offset;
  uint16_t minMapQual;
  bool bp_flag;
  bool avg_flag;
  bool inclCigar;
  boost::filesystem::path outfile;
  boost::filesystem::path int_file;
  std::vector<boost::filesystem::path> files;
};

template<typename TSingleHit, typename TCoverageType>
inline int
run(Config const& c, TSingleHit, TCoverageType covType)
{
  // Create library objects
  typedef std::map<std::string, LibraryInfo> TLibraryMap;
  typedef std::map<std::string, TLibraryMap> TSampleLibrary;
  TSampleLibrary sampleLib;

  // Scan libraries
  for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
    // Get a sample name
    std::string sampleName(c.files[file_c].stem().string());

    // Check that all input bam files exist
    BamTools::BamReader reader;
    if ( ! reader.Open(c.files[file_c].string()) ) {
      std::cerr << "Could not open input bam file: " << c.files[file_c].string() << std::endl;
      reader.Close();
      return -1;
    }

    // Check that all input bam files are indexed
    reader.LocateIndex();
    if ( !reader.HasIndex() ) {
      std::cerr << "Missing bam index file: " << c.files[file_c].string() << std::endl;
      reader.Close();
      return -1;
    }

    // Get library parameters and overall maximum insert size
    TLibraryMap libInfo;
    getLibraryParams(c.files[file_c], libInfo, 0, 5);
    sampleLib.insert(std::make_pair(sampleName, libInfo));
  }

  // Get references
  BamTools::BamReader readerRef;
  if ( ! readerRef.Open(c.files[0].string()) ) return -1;
  BamTools::RefVector references = readerRef.GetReferenceData();

  // Read all SV intervals
  typedef std::vector<StructuralVariantRecord> TSVs;
  TSVs svs;
  std::map<unsigned int, std::string> idToName;
  unsigned int intervalCount=1;
  if (boost::filesystem::exists(c.int_file) && boost::filesystem::is_regular_file(c.int_file) && boost::filesystem::file_size(c.int_file)) {
    typedef boost::unordered_map<std::string, unsigned int> TMapChr;
    TMapChr mapChr;
    typename BamTools::RefVector::const_iterator itRef = references.begin();
    for(unsigned int i = 0;itRef!=references.end();++itRef, ++i) mapChr[ itRef->RefName ] = i;
    std::ifstream interval_file(c.int_file.string().c_str(), std::ifstream::in);
    if (interval_file.is_open()) {
      while (interval_file.good()) {
	std::string intervalLine;
	getline(interval_file, intervalLine);
	typedef boost::tokenizer< boost::char_separator<char> > Tokenizer;
	boost::char_separator<char> sep(" \t,;");
	Tokenizer tokens(intervalLine, sep);
	Tokenizer::iterator tokIter = tokens.begin();
	if (tokIter!=tokens.end()) {
	  std::string chrName=*tokIter++;
	  TMapChr::const_iterator mapChrIt = mapChr.find(chrName);
	  if (mapChrIt != mapChr.end()) {
	    if (tokIter!=tokens.end()) {
	      StructuralVariantRecord sv;
	      sv.chr = mapChrIt->second;
	      sv.chr2 = mapChrIt->second;
	      sv.svStart = boost::lexical_cast<int32_t>(*tokIter++);
	      sv.svEnd = boost::lexical_cast<int32_t>(*tokIter++) + 1;
	      std::string svName = *tokIter;
	      idToName.insert(std::make_pair(intervalCount, svName));
	      sv.id = intervalCount++;
	      svs.push_back(sv);
	    }
	  }
	}
      }
      interval_file.close();
    }
  } else {
    // Create artificial intervals
    typename BamTools::RefVector::const_iterator itRef = references.begin();
    for(int refIndex=0;itRef!=references.end();++itRef, ++refIndex) {
      int32_t pos = 0;
      while (pos < references[refIndex].RefLength) {
	int32_t window_len = pos+c.window_size;
	if (window_len > references[refIndex].RefLength) window_len = references[refIndex].RefLength;
	StructuralVariantRecord sv;
	sv.chr = refIndex;
	sv.chr2 = refIndex;
	sv.svStart = pos;
	sv.svEnd = window_len;
	std::stringstream s;
	s << references[sv.chr].RefName << ":" << sv.svStart << "-" << sv.svEnd;
	idToName.insert(std::make_pair(intervalCount, s.str()));
	sv.id = intervalCount++;
	svs.push_back(sv);
	pos += c.window_offset;
      }
    }
  }

  // Output data types
  typedef std::pair<std::string, int> TSampleSVPair;
  typedef std::pair<int, int> TBpRead;
  typedef std::map<TSampleSVPair, TBpRead> TCountMap;
  TCountMap countMap;

  // Annotate coverage
  annotateCoverage(c.files, c.minMapQual, c.inclCigar, sampleLib, svs, countMap, TSingleHit(), covType);

  // Output library statistics
  std::cout << "Library statistics" << std::endl;
  TSampleLibrary::const_iterator sampleIt=sampleLib.begin();
  for(;sampleIt!=sampleLib.end();++sampleIt) {
    std::cout << "Sample: " << sampleIt->first << std::endl;
    TLibraryMap::const_iterator libIt=sampleIt->second.begin();
    for(;libIt!=sampleIt->second.end();++libIt) {
      std::cout << "RG: ID=" << libIt->first << ",Median=" << libIt->second.median << ",MAD=" << libIt->second.mad << ",Orientation=" << (int) libIt->second.defaultOrient << ",MappedReads=" << libIt->second.mappedReads << ",DuplicatePairs=" << libIt->second.non_unique_pairs << ",UniquePairs=" << libIt->second.unique_pairs << std::endl;
    }
  }

  // Output file
  boost::iostreams::filtering_ostream dataOut;
  dataOut.push(boost::iostreams::gzip_compressor());
  dataOut.push(boost::iostreams::file_sink(c.outfile.string().c_str(), std::ios_base::out | std::ios_base::binary));

  // Print header
  dataOut << "#chr\tstart\tend\tid";
  for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
    std::string sampleName(c.files[file_c].stem().string());
    dataOut << "\t";
    if (c.avg_flag) dataOut << sampleName << "_avgcov" << "\t";
    if (c.bp_flag) dataOut << sampleName << "_bpcount" << "\t";
    if ((c.bp_flag) || (c.avg_flag)) dataOut << sampleName << "_readcount";
    else dataOut << sampleName;
  }
  dataOut << std::endl;

  // Iterate all SVs
  typename TSVs::const_iterator itSV = svs.begin();
  typename TSVs::const_iterator itSVEnd = svs.end();
  for(;itSV!=itSVEnd;++itSV) {
    dataOut << references[itSV->chr].RefName << "\t" << itSV->svStart << "\t" << itSV->svEnd << "\t" << idToName.find(itSV->id)->second;
    // Iterate all samples
    for(unsigned int file_c = 0; file_c < c.files.size(); ++file_c) {
      // Get the sample name
      std::string sampleName(c.files[file_c].stem().string());
      TSampleSVPair sampleSVPair = std::make_pair(sampleName, itSV->id);
      typename TCountMap::iterator countMapIt=countMap.find(sampleSVPair);
      dataOut << "\t";
      if (c.avg_flag) dataOut << ( (countMapIt->second.first) / (double) (itSV->svEnd - itSV->svStart)) << "\t";
      if (c.bp_flag) dataOut << countMapIt->second.first << "\t";
      dataOut << countMapIt->second.second;
    }
    dataOut << std::endl;
  }

  // End
  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
  std::cout << '[' << boost::posix_time::to_simple_string(now) << "] Done." << std::endl;;
  return 0;
}

int main(int argc, char **argv) {
  Config c;

  // Define generic options
  boost::program_options::options_description generic("Generic options");
  generic.add_options()
    ("help,?", "show help message")
    ("bp-count,b", "show base pair count")
    ("avg-cov,a", "show average coverage")
    ("disable-redundancy,d", "disable redundancy filtering")
    ("quality-cut,q", boost::program_options::value<uint16_t>(&c.minMapQual)->default_value(0), "exclude all alignments with quality < q")
    ("outfile,f", boost::program_options::value<boost::filesystem::path>(&c.outfile)->default_value("cov.gz"), "coverage output file")
    ;

  // Define window options
  boost::program_options::options_description window("Window options");
  window.add_options()
    ("window-size,s", boost::program_options::value<unsigned int>(&c.window_size)->default_value(10000), "window size")
    ("window-offset,o", boost::program_options::value<unsigned int>(&c.window_offset)->default_value(10000), "window offset")
    ;

  // Define interval options
  boost::program_options::options_description interval("Interval options");
  interval.add_options()
    ("interval-file,i", boost::program_options::value<boost::filesystem::path>(&c.int_file), "interval file")
    ;

  // Define hidden options
  boost::program_options::options_description hidden("Hidden options");
  hidden.add_options()
    ("input-file", boost::program_options::value< std::vector<boost::filesystem::path> >(&c.files), "input file")
    ("license,l", "show license")
    ("warranty,w", "show warranty")
    ;
  boost::program_options::positional_options_description pos_args;
  pos_args.add("input-file", -1);

  // Set the visibility
  boost::program_options::options_description cmdline_options;
  cmdline_options.add(generic).add(window).add(interval).add(hidden);
  boost::program_options::options_description visible_options;
  visible_options.add(generic).add(window).add(interval);
  boost::program_options::variables_map vm;
  boost::program_options::store(boost::program_options::command_line_parser(argc, argv).options(cmdline_options).positional(pos_args).run(), vm);
  boost::program_options::notify(vm);

  // Check command line arguments
  if ((vm.count("help")) || (!vm.count("input-file"))) {
    printTitle("Coverage calculation");
    if (vm.count("warranty")) {
      displayWarranty();
    } else if (vm.count("license")) {
      gplV3();
    } else {
      std::cout << "Usage: " << argv[0] << " [OPTIONS] <sample1.bam> <sample2.bam> ..." << std::endl;
      std::cout << visible_options << "\n";
    }
    return 1;
  }
  bool disableRedFilter=false;
  if (vm.count("disable-redundancy")) disableRedFilter=true;
  if (vm.count("bp-count")) c.bp_flag = true;
  else c.bp_flag = false;
  if (vm.count("avg-cov")) c.avg_flag = true;
  else c.avg_flag = false;
  if ((c.bp_flag) || (c.avg_flag)) c.inclCigar = true;
  else c.inclCigar = false;

  // Show cmd
  boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
  std::cout << '[' << boost::posix_time::to_simple_string(now) << "] ";
  for(int i=0; i<argc; ++i) { std::cout << argv[i] << ' '; }
  std::cout << std::endl;

  // Run coverage annotation
  if (c.inclCigar) {
    if (disableRedFilter) return run(c, SingleHit<int32_t, std::string>(), CoverageType<NoRedundancyFilterTag>());
    else return run(c, SingleHit<int32_t, std::string>(), CoverageType<RedundancyFilterTag>());
  } else {
    if (disableRedFilter) run(c, SingleHit<int32_t, void>(), CoverageType<NoRedundancyFilterTag>());
    else return run(c, SingleHit<int32_t, void>(), CoverageType<RedundancyFilterTag>());
  }
}
<|endoftext|>


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

#include <boost/lexical_cast.hpp>

#include <pcl/common/io.h>
#include <pcl/io/depth_sense_grabber.h>
#include <pcl/io/depth_sense/depth_sense_grabber_impl.h>
#include <pcl/io/depth_sense/depth_sense_device_manager.h>

pcl::io::depth_sense::DepthSenseGrabberImpl::DepthSenseGrabberImpl (DepthSenseGrabber* parent, const std::string& device_id)
: p_ (parent)
, is_running_ (false)
, confidence_threshold_ (50)
, temporal_filtering_type_ (DepthSenseGrabber::DepthSense_None)
, color_data_ (COLOR_SIZE * 3)
, depth_buffer_ (new pcl::io::SingleBuffer<float> (SIZE))
{
  if (device_id == "")
    device_id_ = DepthSenseDeviceManager::getInstance ()->captureDevice (this);
  else if (device_id[0] == '#')
    device_id_ = DepthSenseDeviceManager::getInstance ()->captureDevice (this, boost::lexical_cast<int> (device_id.substr (1)) - 1);
  else
    device_id_ = DepthSenseDeviceManager::getInstance ()->captureDevice (this, device_id);

  point_cloud_signal_ = p_->createSignal<sig_cb_depth_sense_point_cloud> ();
  point_cloud_rgba_signal_ = p_->createSignal<sig_cb_depth_sense_point_cloud_rgba> ();
}

pcl::io::depth_sense::DepthSenseGrabberImpl::~DepthSenseGrabberImpl () throw ()
{
  stop ();

  DepthSenseDeviceManager::getInstance ()->releaseDevice (device_id_);

  p_->disconnect_all_slots<sig_cb_depth_sense_point_cloud> ();
  p_->disconnect_all_slots<sig_cb_depth_sense_point_cloud_rgba> ();
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::start ()
{
  need_xyz_ = p_->num_slots<sig_cb_depth_sense_point_cloud> () > 0;
  need_xyzrgba_ = p_->num_slots<sig_cb_depth_sense_point_cloud_rgba> () > 0;

  if (!is_running_)
  {
    DepthSenseDeviceManager::getInstance ()->reconfigureDevice (device_id_);
    DepthSenseDeviceManager::getInstance ()->startDevice (device_id_);
    frequency_.reset ();
    is_running_ = true;
  }
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::stop ()
{
  if (is_running_)
  {
    DepthSenseDeviceManager::getInstance ()->stopDevice (device_id_);
    is_running_ = false;
  }
}

float
pcl::io::depth_sense::DepthSenseGrabberImpl::getFramesPerSecond () const
{
  boost::mutex::scoped_lock lock (fps_mutex_);
  return (frequency_.getFrequency ());
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::setConfidenceThreshold (int threshold)
{
  confidence_threshold_ = threshold;
  DepthSenseDeviceManager::getInstance ()->reconfigureDevice (device_id_);
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::enableTemporalFiltering (DepthSenseGrabber::TemporalFilteringType type, size_t window_size)
{
  if (temporal_filtering_type_ != type ||
      (type != DepthSenseGrabber::DepthSense_None && depth_buffer_->size () != window_size))
  {
    bool was_running = is_running_;
    if (was_running)
      stop ();
    switch (type)
    {
      case DepthSenseGrabber::DepthSense_None:
        {
          depth_buffer_.reset (new pcl::io::SingleBuffer<float> (SIZE));
          break;
        }
      case DepthSenseGrabber::DepthSense_Median:
        {
          depth_buffer_.reset (new pcl::io::MedianBuffer<float> (SIZE, window_size));
          break;
        }
      case DepthSenseGrabber::DepthSense_Average:
        {
          depth_buffer_.reset (new pcl::io::AverageBuffer<float> (SIZE, window_size));
          break;
        }
    }
    temporal_filtering_type_ = type;
    if (was_running)
      start ();
  }
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::setCameraParameters (const DepthSense::StereoCameraParameters& parameters)
{
  projection_.reset (new DepthSense::ProjectionHelper (parameters));
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::configureDepthNode (DepthSense::DepthNode node) const
{
  DepthSense::DepthNode::Configuration config = node.getConfiguration ();
  config.frameFormat = DepthSense::FRAME_FORMAT_QVGA;
  config.framerate = FRAMERATE;
  config.mode = DepthSense::DepthNode::CAMERA_MODE_CLOSE_MODE;
  config.saturation = false;
  node.setEnableDepthMapFloatingPoint (true);
  node.setEnableUvMap (true);
  node.setEnableConfidenceMap (true);
  node.setConfiguration (config);
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::configureColorNode (DepthSense::ColorNode node) const
{
  DepthSense::ColorNode::Configuration config = node.getConfiguration ();
  config.frameFormat = DepthSense::FRAME_FORMAT_VGA;
  config.compression = DepthSense::COMPRESSION_TYPE_MJPEG;
  config.powerLineFrequency = DepthSense::POWER_LINE_FREQUENCY_50HZ;
  config.framerate = FRAMERATE;
  node.setEnableColorMap (true);
  node.setConfiguration (config);
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::onDepthDataReceived (DepthSense::DepthNode node, DepthSense::DepthNode::NewSampleReceivedData data)
{
  fps_mutex_.lock ();
  frequency_.event ();
  fps_mutex_.unlock ();

  static const float nan = std::numeric_limits<float>::quiet_NaN ();

  std::vector<float> depth_data (SIZE);
  memcpy (depth_data.data (), &data.depthMapFloatingPoint[0], SIZE * sizeof (float));
  for (int i = 0; i < SIZE; i++)
    if (data.confidenceMap[i] < confidence_threshold_)
      depth_data[i] = nan;
  depth_buffer_->push (depth_data);

  pcl::PointCloud<pcl::PointXYZ>::Ptr xyz_cloud;
  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr xyzrgba_cloud;

  if (need_xyz_)
  {
    xyz_cloud.reset (new pcl::PointCloud<pcl::PointXYZ> (WIDTH, HEIGHT));
    xyz_cloud->is_dense = false;

    computeXYZ (*xyz_cloud);

    point_cloud_signal_->operator () (xyz_cloud);
  }

  if (need_xyzrgba_)
  {
    xyzrgba_cloud.reset (new pcl::PointCloud<pcl::PointXYZRGBA> (WIDTH, HEIGHT));
    xyzrgba_cloud->is_dense = false;

    if (need_xyz_)
      copyPointCloud (*xyz_cloud, *xyzrgba_cloud);
    else
      computeXYZ (*xyzrgba_cloud);

    for (int i = 0; i < SIZE; i++)
    {
      const DepthSense::UV& uv = data.uvMap[i];
      int row = static_cast<int> (uv.v * COLOR_HEIGHT);
      int col = static_cast<int> (uv.u * COLOR_WIDTH);
      int pixel = row * COLOR_WIDTH + col;
      if (pixel >=0 && pixel < COLOR_WIDTH * COLOR_HEIGHT)
        memcpy (&xyzrgba_cloud->points[i].rgba, &color_data_[pixel * 3], 3);
    }

    point_cloud_rgba_signal_->operator () (xyzrgba_cloud);
  }
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::onColorDataReceived (DepthSense::ColorNode node, DepthSense::ColorNode::NewSampleReceivedData data)
{
  if (need_xyzrgba_)
    memcpy (&color_data_[0], data.colorMap, color_data_.size ());
}

template <typename Point> void
pcl::io::depth_sense::DepthSenseGrabberImpl::computeXYZ (PointCloud<Point>& cloud)
{
  static const float nan = std::numeric_limits<float>::quiet_NaN ();

  int i = 0;
  DepthSense::FPExtended2DPoint point (DepthSense::Point2D (0, 0), 0);
  DepthSense::FPVertex vertex;
  while (point.point.y < HEIGHT)
  {
    point.point.x = 0;
    while (point.point.x < WIDTH)
    {
      point.depth = (*depth_buffer_)[i];
      if (pcl_isnan (point.depth))
      {
        cloud.points[i].x = nan;
        cloud.points[i].y = nan;
        cloud.points[i].z = nan;
      }
      else
      {
        projection_->get3DCoordinates (&point, &vertex, 1);
        cloud.points[i].x = vertex.x;
        cloud.points[i].y = vertex.y;
        cloud.points[i].z = vertex.z;
      }
      point.point.x += 1;
      ++i;
    }
    point.point.y += 1;
  }
}

<commit_msg>Fix warnings: unused parameter ‘node’<commit_after>/*
 * Software License Agreement (BSD License)
 *
 *  Point Cloud Library (PCL) - www.pointclouds.org
 *  Copyright (c) 2014-, Open Perception, Inc.
 *
 *  All rights reserved.
 *
 *  Redistribution and use in source and binary forms, with or without
 *  modification, are permitted provided that the following conditions
 *  are met:
 *
 *   * Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *   * Redistributions in binary form must reproduce the above
 *     copyright notice, this list of conditions and the following
 *     disclaimer in the documentation and/or other materials provided
 *     with the distribution.
 *   * Neither the name of the copyright holder(s) nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 *  LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 *  FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
 *  COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 *  INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 *  BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 *  LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 *  CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 *  LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
 *  ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 *  POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <boost/lexical_cast.hpp>

#include <pcl/common/io.h>
#include <pcl/io/depth_sense_grabber.h>
#include <pcl/io/depth_sense/depth_sense_grabber_impl.h>
#include <pcl/io/depth_sense/depth_sense_device_manager.h>

pcl::io::depth_sense::DepthSenseGrabberImpl::DepthSenseGrabberImpl (DepthSenseGrabber* parent, const std::string& device_id)
: p_ (parent)
, is_running_ (false)
, confidence_threshold_ (50)
, temporal_filtering_type_ (DepthSenseGrabber::DepthSense_None)
, color_data_ (COLOR_SIZE * 3)
, depth_buffer_ (new pcl::io::SingleBuffer<float> (SIZE))
{
  if (device_id == "")
    device_id_ = DepthSenseDeviceManager::getInstance ()->captureDevice (this);
  else if (device_id[0] == '#')
    device_id_ = DepthSenseDeviceManager::getInstance ()->captureDevice (this, boost::lexical_cast<int> (device_id.substr (1)) - 1);
  else
    device_id_ = DepthSenseDeviceManager::getInstance ()->captureDevice (this, device_id);

  point_cloud_signal_ = p_->createSignal<sig_cb_depth_sense_point_cloud> ();
  point_cloud_rgba_signal_ = p_->createSignal<sig_cb_depth_sense_point_cloud_rgba> ();
}

pcl::io::depth_sense::DepthSenseGrabberImpl::~DepthSenseGrabberImpl () throw ()
{
  stop ();

  DepthSenseDeviceManager::getInstance ()->releaseDevice (device_id_);

  p_->disconnect_all_slots<sig_cb_depth_sense_point_cloud> ();
  p_->disconnect_all_slots<sig_cb_depth_sense_point_cloud_rgba> ();
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::start ()
{
  need_xyz_ = p_->num_slots<sig_cb_depth_sense_point_cloud> () > 0;
  need_xyzrgba_ = p_->num_slots<sig_cb_depth_sense_point_cloud_rgba> () > 0;

  if (!is_running_)
  {
    DepthSenseDeviceManager::getInstance ()->reconfigureDevice (device_id_);
    DepthSenseDeviceManager::getInstance ()->startDevice (device_id_);
    frequency_.reset ();
    is_running_ = true;
  }
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::stop ()
{
  if (is_running_)
  {
    DepthSenseDeviceManager::getInstance ()->stopDevice (device_id_);
    is_running_ = false;
  }
}

float
pcl::io::depth_sense::DepthSenseGrabberImpl::getFramesPerSecond () const
{
  boost::mutex::scoped_lock lock (fps_mutex_);
  return (frequency_.getFrequency ());
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::setConfidenceThreshold (int threshold)
{
  confidence_threshold_ = threshold;
  DepthSenseDeviceManager::getInstance ()->reconfigureDevice (device_id_);
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::enableTemporalFiltering (DepthSenseGrabber::TemporalFilteringType type, size_t window_size)
{
  if (temporal_filtering_type_ != type ||
      (type != DepthSenseGrabber::DepthSense_None && depth_buffer_->size () != window_size))
  {
    bool was_running = is_running_;
    if (was_running)
      stop ();
    switch (type)
    {
      case DepthSenseGrabber::DepthSense_None:
        {
          depth_buffer_.reset (new pcl::io::SingleBuffer<float> (SIZE));
          break;
        }
      case DepthSenseGrabber::DepthSense_Median:
        {
          depth_buffer_.reset (new pcl::io::MedianBuffer<float> (SIZE, window_size));
          break;
        }
      case DepthSenseGrabber::DepthSense_Average:
        {
          depth_buffer_.reset (new pcl::io::AverageBuffer<float> (SIZE, window_size));
          break;
        }
    }
    temporal_filtering_type_ = type;
    if (was_running)
      start ();
  }
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::setCameraParameters (const DepthSense::StereoCameraParameters& parameters)
{
  projection_.reset (new DepthSense::ProjectionHelper (parameters));
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::configureDepthNode (DepthSense::DepthNode node) const
{
  DepthSense::DepthNode::Configuration config = node.getConfiguration ();
  config.frameFormat = DepthSense::FRAME_FORMAT_QVGA;
  config.framerate = FRAMERATE;
  config.mode = DepthSense::DepthNode::CAMERA_MODE_CLOSE_MODE;
  config.saturation = false;
  node.setEnableDepthMapFloatingPoint (true);
  node.setEnableUvMap (true);
  node.setEnableConfidenceMap (true);
  node.setConfiguration (config);
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::configureColorNode (DepthSense::ColorNode node) const
{
  DepthSense::ColorNode::Configuration config = node.getConfiguration ();
  config.frameFormat = DepthSense::FRAME_FORMAT_VGA;
  config.compression = DepthSense::COMPRESSION_TYPE_MJPEG;
  config.powerLineFrequency = DepthSense::POWER_LINE_FREQUENCY_50HZ;
  config.framerate = FRAMERATE;
  node.setEnableColorMap (true);
  node.setConfiguration (config);
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::onDepthDataReceived (DepthSense::DepthNode, DepthSense::DepthNode::NewSampleReceivedData data)
{
  fps_mutex_.lock ();
  frequency_.event ();
  fps_mutex_.unlock ();

  static const float nan = std::numeric_limits<float>::quiet_NaN ();

  std::vector<float> depth_data (SIZE);
  memcpy (depth_data.data (), &data.depthMapFloatingPoint[0], SIZE * sizeof (float));
  for (int i = 0; i < SIZE; i++)
    if (data.confidenceMap[i] < confidence_threshold_)
      depth_data[i] = nan;
  depth_buffer_->push (depth_data);

  pcl::PointCloud<pcl::PointXYZ>::Ptr xyz_cloud;
  pcl::PointCloud<pcl::PointXYZRGBA>::Ptr xyzrgba_cloud;

  if (need_xyz_)
  {
    xyz_cloud.reset (new pcl::PointCloud<pcl::PointXYZ> (WIDTH, HEIGHT));
    xyz_cloud->is_dense = false;

    computeXYZ (*xyz_cloud);

    point_cloud_signal_->operator () (xyz_cloud);
  }

  if (need_xyzrgba_)
  {
    xyzrgba_cloud.reset (new pcl::PointCloud<pcl::PointXYZRGBA> (WIDTH, HEIGHT));
    xyzrgba_cloud->is_dense = false;

    if (need_xyz_)
      copyPointCloud (*xyz_cloud, *xyzrgba_cloud);
    else
      computeXYZ (*xyzrgba_cloud);

    for (int i = 0; i < SIZE; i++)
    {
      const DepthSense::UV& uv = data.uvMap[i];
      int row = static_cast<int> (uv.v * COLOR_HEIGHT);
      int col = static_cast<int> (uv.u * COLOR_WIDTH);
      int pixel = row * COLOR_WIDTH + col;
      if (pixel >=0 && pixel < COLOR_WIDTH * COLOR_HEIGHT)
        memcpy (&xyzrgba_cloud->points[i].rgba, &color_data_[pixel * 3], 3);
    }

    point_cloud_rgba_signal_->operator () (xyzrgba_cloud);
  }
}

void
pcl::io::depth_sense::DepthSenseGrabberImpl::onColorDataReceived (DepthSense::ColorNode, DepthSense::ColorNode::NewSampleReceivedData data)
{
  if (need_xyzrgba_)
    memcpy (&color_data_[0], data.colorMap, color_data_.size ());
}

template <typename Point> void
pcl::io::depth_sense::DepthSenseGrabberImpl::computeXYZ (PointCloud<Point>& cloud)
{
  static const float nan = std::numeric_limits<float>::quiet_NaN ();

  int i = 0;
  DepthSense::FPExtended2DPoint point (DepthSense::Point2D (0, 0), 0);
  DepthSense::FPVertex vertex;
  while (point.point.y < HEIGHT)
  {
    point.point.x = 0;
    while (point.point.x < WIDTH)
    {
      point.depth = (*depth_buffer_)[i];
      if (pcl_isnan (point.depth))
      {
        cloud.points[i].x = nan;
        cloud.points[i].y = nan;
        cloud.points[i].z = nan;
      }
      else
      {
        projection_->get3DCoordinates (&point, &vertex, 1);
        cloud.points[i].x = vertex.x;
        cloud.points[i].y = vertex.y;
        cloud.points[i].z = vertex.z;
      }
      point.point.x += 1;
      ++i;
    }
    point.point.y += 1;
  }
}

<|endoftext|>


<commit_before>/*
** Copyright 1994 by Miron Livny, and Mike Litzkow
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation, and that the names of the University of
** Wisconsin and the copyright holders not be used in advertising or
** publicity pertaining to distribution of the software without specific,
** written prior permission.  The University of Wisconsin and the
** copyright holders make no representations about the suitability of this
** software for any purpose.  It is provided "as is" without express
** or implied warranty.
**
** THE UNIVERSITY OF WISCONSIN AND THE COPYRIGHT HOLDERS DISCLAIM ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE UNIVERSITY OF
** WISCONSIN OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
** OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
** OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
** OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
** OR PERFORMANCE OF THIS SOFTWARE.
**
** Author:  Mike Litzkow
**
*/

#define _POSIX_SOURCE
#include <sys/types.h>
#include <stdlib.h>

void * operator new(size_t size)
{
	return (void *)malloc(size);
}

void operator delete( void *to_free )
{
	if( to_free ) {
		(void)free( to_free );
	}
}
<commit_msg>Add routines __builtin_vec_new() and __builtin_vec_delete() needed for G++ version 2.6.0.<commit_after>/*
** Copyright 1994 by Miron Livny, and Mike Litzkow
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted,
** provided that the above copyright notice appear in all copies and that
** both that copyright notice and this permission notice appear in
** supporting documentation, and that the names of the University of
** Wisconsin and the copyright holders not be used in advertising or
** publicity pertaining to distribution of the software without specific,
** written prior permission.  The University of Wisconsin and the
** copyright holders make no representations about the suitability of this
** software for any purpose.  It is provided "as is" without express
** or implied warranty.
**
** THE UNIVERSITY OF WISCONSIN AND THE COPYRIGHT HOLDERS DISCLAIM ALL
** WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES
** OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE UNIVERSITY OF
** WISCONSIN OR THE COPYRIGHT HOLDERS BE LIABLE FOR ANY SPECIAL, INDIRECT
** OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
** OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
** OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE
** OR PERFORMANCE OF THIS SOFTWARE.
**
** Author:  Mike Litzkow
**
*/

#define _POSIX_SOURCE
#include <sys/types.h>
#include <stdlib.h>

void * operator new(size_t size)
{
	return (void *)malloc(size);
}

void operator delete( void *to_free )
{
	if( to_free ) {
		(void)free( to_free );
	}
}

#if defined( __GNUC__ )
#	if __GNUG__== 2 && __GNUC_MINOR__ == 6
		extern "C" {
			void *__builtin_new( size_t );
			void __builtin_delete( void * );
			void *
			__builtin_vec_new (size_t sz)
			{
				return __builtin_new( sz );
			}

			void
			__builtin_vec_delete( void *to_free )
			{
				__builtin_delete( to_free );
			}
		}
#	endif
#endif
<|endoftext|>


<commit_before>// Copyright (c) 2020 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <avalanche/peermanager.h>

#include <avalanche/delegation.h>
#include <avalanche/validation.h>
#include <random.h>
#include <validation.h> // For ChainstateActive()

#include <cassert>

namespace avalanche {

bool PeerManager::addNode(NodeId nodeid, const ProofId &proofid) {
    auto &pview = peers.get<proof_index>();
    auto it = pview.find(proofid);
    if (it == pview.end()) {
        return false;
    }

    return addOrUpdateNode(peers.project<0>(it), nodeid);
}

bool PeerManager::addOrUpdateNode(const PeerSet::iterator &it, NodeId nodeid) {
    assert(it != peers.end());

    const PeerId peerid = it->peerid;

    auto nit = nodes.find(nodeid);
    if (nit == nodes.end()) {
        if (!nodes.emplace(nodeid, peerid).second) {
            return false;
        }
    } else {
        const PeerId oldpeerid = nit->peerid;
        if (!nodes.modify(nit, [&](Node &n) { n.peerid = peerid; })) {
            return false;
        }

        // We actually have this node already, we need to update it.
        bool success = removeNodeFromPeer(peers.find(oldpeerid));
        assert(success);
    }

    bool success = addNodeToPeer(it);
    assert(success);

    return true;
}

bool PeerManager::addNodeToPeer(const PeerSet::iterator &it) {
    assert(it != peers.end());
    return peers.modify(it, [&](Peer &p) {
        if (p.node_count++ > 0) {
            // We are done.
            return;
        }

        // We need to allocate this peer.
        p.index = uint32_t(slots.size());
        const uint32_t score = p.getScore();
        const uint64_t start = slotCount;
        slots.emplace_back(start, score, it->peerid);
        slotCount = start + score;
    });
}

bool PeerManager::removeNode(NodeId nodeid) {
    auto it = nodes.find(nodeid);
    if (it == nodes.end()) {
        return false;
    }

    const PeerId peerid = it->peerid;
    nodes.erase(it);

    // Keep the track of the reference count.
    bool success = removeNodeFromPeer(peers.find(peerid));
    assert(success);

    return true;
}

bool PeerManager::removeNodeFromPeer(const PeerSet::iterator &it,
                                     uint32_t count) {
    assert(it != peers.end());
    assert(count <= it->node_count);
    if (count == 0) {
        // This is a NOOP.
        return false;
    }

    const uint32_t new_count = it->node_count - count;
    if (!peers.modify(it, [&](Peer &p) { p.node_count = new_count; })) {
        return false;
    }

    if (new_count > 0) {
        // We are done.
        return true;
    }

    // There are no more node left, we need to cleanup.
    const size_t i = it->index;
    assert(i < slots.size());
    if (i + 1 == slots.size()) {
        slots.pop_back();
        slotCount = slots.empty() ? 0 : slots.back().getStop();
    } else {
        fragmentation += slots[i].getScore();
        slots[i] = slots[i].withPeerId(NO_PEER);
    }

    return true;
}

bool PeerManager::updateNextRequestTime(NodeId nodeid, TimePoint timeout) {
    auto it = nodes.find(nodeid);
    if (it == nodes.end()) {
        return false;
    }

    return nodes.modify(it, [&](Node &n) { n.nextRequestTime = timeout; });
}

bool PeerManager::registerProof(const std::shared_ptr<Proof> &proof) {
    return !getProof(proof->getId()) && getPeerId(proof) != NO_PEER;
}

NodeId PeerManager::selectNode() {
    for (int retry = 0; retry < SELECT_NODE_MAX_RETRY; retry++) {
        const PeerId p = selectPeer();

        // If we cannot find a peer, it may be due to the fact that it is
        // unlikely due to high fragmentation, so compact and retry.
        if (p == NO_PEER) {
            compact();
            continue;
        }

        // See if that peer has an available node.
        auto &nview = nodes.get<next_request_time>();
        auto it = nview.lower_bound(boost::make_tuple(p, TimePoint()));
        if (it != nview.end() && it->peerid == p &&
            it->nextRequestTime <= std::chrono::steady_clock::now()) {
            return it->nodeid;
        }
    }

    return NO_NODE;
}

static bool isOrphanState(const ProofValidationState &state) {
    return state.GetResult() == ProofValidationResult::MISSING_UTXO ||
           state.GetResult() == ProofValidationResult::HEIGHT_MISMATCH;
}

void PeerManager::updatedBlockTip() {
    std::vector<PeerId> invalidPeers;
    std::vector<std::shared_ptr<Proof>> newOrphans;

    {
        LOCK(cs_main);

        const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip();
        for (const auto &p : peers) {
            ProofValidationState state;
            if (!p.proof->verify(state, coins)) {
                if (isOrphanState(state)) {
                    newOrphans.push_back(p.proof);
                }
                invalidPeers.push_back(p.peerid);
            }
        }
    }

    orphanProofs.rescan(*this);

    for (auto &p : newOrphans) {
        orphanProofs.addProof(p);
    }

    for (const auto &pid : invalidPeers) {
        removePeer(pid);
    }
}

PeerId PeerManager::getPeerId(const std::shared_ptr<Proof> &proof) {
    auto it = fetchOrCreatePeer(proof);
    return it == peers.end() ? NO_PEER : it->peerid;
}

std::shared_ptr<Proof> PeerManager::getProof(const ProofId &proofid) const {
    std::shared_ptr<Proof> proof = nullptr;

    forPeer(proofid, [&](const Peer &p) {
        proof = p.proof;
        return true;
    });

    return proof;
}

PeerManager::PeerSet::iterator
PeerManager::fetchOrCreatePeer(const std::shared_ptr<Proof> &proof) {
    {
        // Check if we already know of that peer.
        auto &pview = peers.get<proof_index>();
        auto it = pview.find(proof->getId());
        if (it != pview.end()) {
            return peers.project<0>(it);
        }
    }

    // Check the proof's validity.
    ProofValidationState state;
    bool valid = [&](ProofValidationState &state) {
        LOCK(cs_main);
        const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip();
        return proof->verify(state, coins);
    }(state);

    if (!valid) {
        if (isOrphanState(state)) {
            orphanProofs.addProof(proof);
        }

        // Reject invalid proof.
        return peers.end();
    }

    orphanProofs.removeProof(proof->getId());

    // New peer means new peerid!
    const PeerId peerid = nextPeerId++;

    // Attach UTXOs to this proof.
    std::unordered_set<PeerId> conflicting_peerids;
    for (const auto &s : proof->getStakes()) {
        auto p = utxos.emplace(s.getStake().getUTXO(), peerid);
        if (!p.second) {
            // We have a collision with an existing proof.
            conflicting_peerids.insert(p.first->second);
        }
    }

    // For now, if there is a conflict, just cleanup the mess.
    if (conflicting_peerids.size() > 0) {
        for (const auto &s : proof->getStakes()) {
            auto it = utxos.find(s.getStake().getUTXO());
            assert(it != utxos.end());

            // We need to delete that one.
            if (it->second == peerid) {
                utxos.erase(it);
            }
        }

        return peers.end();
    }

    // We have no peer for this proof, time to create it.
    auto inserted = peers.emplace(peerid, proof);
    assert(inserted.second);

    return inserted.first;
}

bool PeerManager::removePeer(const PeerId peerid) {
    auto it = peers.find(peerid);
    if (it == peers.end()) {
        return false;
    }

    // Remove all nodes from this peer.
    removeNodeFromPeer(it, it->node_count);

    // Remove nodes associated with this peer, unless their timeout is still
    // active. This ensure that we don't overquery them in case they are
    // subsequently added to another peer.
    auto &nview = nodes.get<next_request_time>();
    nview.erase(nview.lower_bound(boost::make_tuple(peerid, TimePoint())),
                nview.upper_bound(boost::make_tuple(
                    peerid, std::chrono::steady_clock::now())));

    // Release UTXOs attached to this proof.
    for (const auto &s : it->proof->getStakes()) {
        bool deleted = utxos.erase(s.getStake().getUTXO()) > 0;
        assert(deleted);
    }

    m_unbroadcast_proofids.erase(it->proof->getId());

    peers.erase(it);
    return true;
}

PeerId PeerManager::selectPeer() const {
    if (slots.empty() || slotCount == 0) {
        return NO_PEER;
    }

    const uint64_t max = slotCount;
    for (int retry = 0; retry < SELECT_PEER_MAX_RETRY; retry++) {
        size_t i = selectPeerImpl(slots, GetRand(max), max);
        if (i != NO_PEER) {
            return i;
        }
    }

    return NO_PEER;
}

uint64_t PeerManager::compact() {
    // There is nothing to compact.
    if (fragmentation == 0) {
        return 0;
    }

    std::vector<Slot> newslots;
    newslots.reserve(peers.size());

    uint64_t prevStop = 0;
    uint32_t i = 0;
    for (auto it = peers.begin(); it != peers.end(); it++) {
        if (it->node_count == 0) {
            continue;
        }

        newslots.emplace_back(prevStop, it->getScore(), it->peerid);
        prevStop = slots[i].getStop();
        if (!peers.modify(it, [&](Peer &p) { p.index = i++; })) {
            return 0;
        }
    }

    slots = std::move(newslots);

    const uint64_t saved = slotCount - prevStop;
    slotCount = prevStop;
    fragmentation = 0;

    return saved;
}

bool PeerManager::verify() const {
    uint64_t prevStop = 0;
    for (size_t i = 0; i < slots.size(); i++) {
        const Slot &s = slots[i];

        // Slots must be in correct order.
        if (s.getStart() < prevStop) {
            return false;
        }

        prevStop = s.getStop();

        // If this is a dead slot, then nothing more needs to be checked.
        if (s.getPeerId() == NO_PEER) {
            continue;
        }

        // We have a live slot, verify index.
        auto it = peers.find(s.getPeerId());
        if (it == peers.end() || it->index != i) {
            return false;
        }
    }

    for (const auto &p : peers) {
        // Count node attached to this peer.
        const auto count_nodes = [&]() {
            size_t count = 0;
            auto &nview = nodes.get<next_request_time>();
            auto begin =
                nview.lower_bound(boost::make_tuple(p.peerid, TimePoint()));
            auto end =
                nview.upper_bound(boost::make_tuple(p.peerid + 1, TimePoint()));

            for (auto it = begin; it != end; ++it) {
                count++;
            }

            return count;
        };

        if (p.node_count != count_nodes()) {
            return false;
        }

        // If there are no nodes attached to this peer, then we are done.
        if (p.node_count == 0) {
            continue;
        }

        // The index must point to a slot refering to this peer.
        if (p.index >= slots.size() || slots[p.index].getPeerId() != p.peerid) {
            return false;
        }

        // If the score do not match, same thing.
        if (slots[p.index].getScore() != p.getScore()) {
            return false;
        }
    }

    return true;
}

PeerId selectPeerImpl(const std::vector<Slot> &slots, const uint64_t slot,
                      const uint64_t max) {
    assert(slot <= max);

    size_t begin = 0, end = slots.size();
    uint64_t bottom = 0, top = max;

    // Try to find the slot using dichotomic search.
    while ((end - begin) > 8) {
        // The slot we picked in not allocated.
        if (slot < bottom || slot >= top) {
            return NO_PEER;
        }

        // Guesstimate the position of the slot.
        size_t i = begin + ((slot - bottom) * (end - begin) / (top - bottom));
        assert(begin <= i && i < end);

        // We have a match.
        if (slots[i].contains(slot)) {
            return slots[i].getPeerId();
        }

        // We undershooted.
        if (slots[i].precedes(slot)) {
            begin = i + 1;
            if (begin >= end) {
                return NO_PEER;
            }

            bottom = slots[begin].getStart();
            continue;
        }

        // We overshooted.
        if (slots[i].follows(slot)) {
            end = i;
            top = slots[end].getStart();
            continue;
        }

        // We have an unalocated slot.
        return NO_PEER;
    }

    // Enough of that nonsense, let fallback to linear search.
    for (size_t i = begin; i < end; i++) {
        // We have a match.
        if (slots[i].contains(slot)) {
            return slots[i].getPeerId();
        }
    }

    // We failed to find a slot, retry.
    return NO_PEER;
}

bool PeerManager::isOrphan(const ProofId &id) const {
    return orphanProofs.getProof(id) != nullptr;
}

std::shared_ptr<Proof> PeerManager::getOrphan(const ProofId &id) const {
    return orphanProofs.getProof(id);
}

void PeerManager::addUnbroadcastProof(const ProofId &proofid) {
    // The proof should be known
    if (getProof(proofid)) {
        m_unbroadcast_proofids.insert(proofid);
    }
}

void PeerManager::removeUnbroadcastProof(const ProofId &proofid) {
    m_unbroadcast_proofids.erase(proofid);
}

} // namespace avalanche
<commit_msg>[avalanche]  Minor simplification in the fetchOrCreatePeer method<commit_after>// Copyright (c) 2020 The Bitcoin developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include <avalanche/peermanager.h>

#include <avalanche/delegation.h>
#include <avalanche/validation.h>
#include <random.h>
#include <validation.h> // For ChainstateActive()

#include <cassert>

namespace avalanche {

bool PeerManager::addNode(NodeId nodeid, const ProofId &proofid) {
    auto &pview = peers.get<proof_index>();
    auto it = pview.find(proofid);
    if (it == pview.end()) {
        return false;
    }

    return addOrUpdateNode(peers.project<0>(it), nodeid);
}

bool PeerManager::addOrUpdateNode(const PeerSet::iterator &it, NodeId nodeid) {
    assert(it != peers.end());

    const PeerId peerid = it->peerid;

    auto nit = nodes.find(nodeid);
    if (nit == nodes.end()) {
        if (!nodes.emplace(nodeid, peerid).second) {
            return false;
        }
    } else {
        const PeerId oldpeerid = nit->peerid;
        if (!nodes.modify(nit, [&](Node &n) { n.peerid = peerid; })) {
            return false;
        }

        // We actually have this node already, we need to update it.
        bool success = removeNodeFromPeer(peers.find(oldpeerid));
        assert(success);
    }

    bool success = addNodeToPeer(it);
    assert(success);

    return true;
}

bool PeerManager::addNodeToPeer(const PeerSet::iterator &it) {
    assert(it != peers.end());
    return peers.modify(it, [&](Peer &p) {
        if (p.node_count++ > 0) {
            // We are done.
            return;
        }

        // We need to allocate this peer.
        p.index = uint32_t(slots.size());
        const uint32_t score = p.getScore();
        const uint64_t start = slotCount;
        slots.emplace_back(start, score, it->peerid);
        slotCount = start + score;
    });
}

bool PeerManager::removeNode(NodeId nodeid) {
    auto it = nodes.find(nodeid);
    if (it == nodes.end()) {
        return false;
    }

    const PeerId peerid = it->peerid;
    nodes.erase(it);

    // Keep the track of the reference count.
    bool success = removeNodeFromPeer(peers.find(peerid));
    assert(success);

    return true;
}

bool PeerManager::removeNodeFromPeer(const PeerSet::iterator &it,
                                     uint32_t count) {
    assert(it != peers.end());
    assert(count <= it->node_count);
    if (count == 0) {
        // This is a NOOP.
        return false;
    }

    const uint32_t new_count = it->node_count - count;
    if (!peers.modify(it, [&](Peer &p) { p.node_count = new_count; })) {
        return false;
    }

    if (new_count > 0) {
        // We are done.
        return true;
    }

    // There are no more node left, we need to cleanup.
    const size_t i = it->index;
    assert(i < slots.size());
    if (i + 1 == slots.size()) {
        slots.pop_back();
        slotCount = slots.empty() ? 0 : slots.back().getStop();
    } else {
        fragmentation += slots[i].getScore();
        slots[i] = slots[i].withPeerId(NO_PEER);
    }

    return true;
}

bool PeerManager::updateNextRequestTime(NodeId nodeid, TimePoint timeout) {
    auto it = nodes.find(nodeid);
    if (it == nodes.end()) {
        return false;
    }

    return nodes.modify(it, [&](Node &n) { n.nextRequestTime = timeout; });
}

bool PeerManager::registerProof(const std::shared_ptr<Proof> &proof) {
    return !getProof(proof->getId()) && getPeerId(proof) != NO_PEER;
}

NodeId PeerManager::selectNode() {
    for (int retry = 0; retry < SELECT_NODE_MAX_RETRY; retry++) {
        const PeerId p = selectPeer();

        // If we cannot find a peer, it may be due to the fact that it is
        // unlikely due to high fragmentation, so compact and retry.
        if (p == NO_PEER) {
            compact();
            continue;
        }

        // See if that peer has an available node.
        auto &nview = nodes.get<next_request_time>();
        auto it = nview.lower_bound(boost::make_tuple(p, TimePoint()));
        if (it != nview.end() && it->peerid == p &&
            it->nextRequestTime <= std::chrono::steady_clock::now()) {
            return it->nodeid;
        }
    }

    return NO_NODE;
}

static bool isOrphanState(const ProofValidationState &state) {
    return state.GetResult() == ProofValidationResult::MISSING_UTXO ||
           state.GetResult() == ProofValidationResult::HEIGHT_MISMATCH;
}

void PeerManager::updatedBlockTip() {
    std::vector<PeerId> invalidPeers;
    std::vector<std::shared_ptr<Proof>> newOrphans;

    {
        LOCK(cs_main);

        const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip();
        for (const auto &p : peers) {
            ProofValidationState state;
            if (!p.proof->verify(state, coins)) {
                if (isOrphanState(state)) {
                    newOrphans.push_back(p.proof);
                }
                invalidPeers.push_back(p.peerid);
            }
        }
    }

    orphanProofs.rescan(*this);

    for (auto &p : newOrphans) {
        orphanProofs.addProof(p);
    }

    for (const auto &pid : invalidPeers) {
        removePeer(pid);
    }
}

PeerId PeerManager::getPeerId(const std::shared_ptr<Proof> &proof) {
    auto it = fetchOrCreatePeer(proof);
    return it == peers.end() ? NO_PEER : it->peerid;
}

std::shared_ptr<Proof> PeerManager::getProof(const ProofId &proofid) const {
    std::shared_ptr<Proof> proof = nullptr;

    forPeer(proofid, [&](const Peer &p) {
        proof = p.proof;
        return true;
    });

    return proof;
}

PeerManager::PeerSet::iterator
PeerManager::fetchOrCreatePeer(const std::shared_ptr<Proof> &proof) {
    assert(proof);
    const ProofId &proofid = proof->getId();
    {
        // Check if we already know of that peer.
        auto &pview = peers.get<proof_index>();
        auto it = pview.find(proofid);
        if (it != pview.end()) {
            return peers.project<0>(it);
        }
    }

    // Check the proof's validity.
    ProofValidationState state;
    bool valid = [&](ProofValidationState &state) {
        LOCK(cs_main);
        const CCoinsViewCache &coins = ::ChainstateActive().CoinsTip();
        return proof->verify(state, coins);
    }(state);

    if (!valid) {
        if (isOrphanState(state)) {
            orphanProofs.addProof(proof);
        }

        // Reject invalid proof.
        return peers.end();
    }

    orphanProofs.removeProof(proofid);

    // New peer means new peerid!
    const PeerId peerid = nextPeerId++;

    // Attach UTXOs to this proof.
    std::unordered_set<PeerId> conflicting_peerids;
    for (const auto &s : proof->getStakes()) {
        auto p = utxos.emplace(s.getStake().getUTXO(), peerid);
        if (!p.second) {
            // We have a collision with an existing proof.
            conflicting_peerids.insert(p.first->second);
        }
    }

    // For now, if there is a conflict, just cleanup the mess.
    if (conflicting_peerids.size() > 0) {
        for (const auto &s : proof->getStakes()) {
            auto it = utxos.find(s.getStake().getUTXO());
            assert(it != utxos.end());

            // We need to delete that one.
            if (it->second == peerid) {
                utxos.erase(it);
            }
        }

        return peers.end();
    }

    // We have no peer for this proof, time to create it.
    auto inserted = peers.emplace(peerid, proof);
    assert(inserted.second);

    return inserted.first;
}

bool PeerManager::removePeer(const PeerId peerid) {
    auto it = peers.find(peerid);
    if (it == peers.end()) {
        return false;
    }

    // Remove all nodes from this peer.
    removeNodeFromPeer(it, it->node_count);

    // Remove nodes associated with this peer, unless their timeout is still
    // active. This ensure that we don't overquery them in case they are
    // subsequently added to another peer.
    auto &nview = nodes.get<next_request_time>();
    nview.erase(nview.lower_bound(boost::make_tuple(peerid, TimePoint())),
                nview.upper_bound(boost::make_tuple(
                    peerid, std::chrono::steady_clock::now())));

    // Release UTXOs attached to this proof.
    for (const auto &s : it->proof->getStakes()) {
        bool deleted = utxos.erase(s.getStake().getUTXO()) > 0;
        assert(deleted);
    }

    m_unbroadcast_proofids.erase(it->proof->getId());

    peers.erase(it);
    return true;
}

PeerId PeerManager::selectPeer() const {
    if (slots.empty() || slotCount == 0) {
        return NO_PEER;
    }

    const uint64_t max = slotCount;
    for (int retry = 0; retry < SELECT_PEER_MAX_RETRY; retry++) {
        size_t i = selectPeerImpl(slots, GetRand(max), max);
        if (i != NO_PEER) {
            return i;
        }
    }

    return NO_PEER;
}

uint64_t PeerManager::compact() {
    // There is nothing to compact.
    if (fragmentation == 0) {
        return 0;
    }

    std::vector<Slot> newslots;
    newslots.reserve(peers.size());

    uint64_t prevStop = 0;
    uint32_t i = 0;
    for (auto it = peers.begin(); it != peers.end(); it++) {
        if (it->node_count == 0) {
            continue;
        }

        newslots.emplace_back(prevStop, it->getScore(), it->peerid);
        prevStop = slots[i].getStop();
        if (!peers.modify(it, [&](Peer &p) { p.index = i++; })) {
            return 0;
        }
    }

    slots = std::move(newslots);

    const uint64_t saved = slotCount - prevStop;
    slotCount = prevStop;
    fragmentation = 0;

    return saved;
}

bool PeerManager::verify() const {
    uint64_t prevStop = 0;
    for (size_t i = 0; i < slots.size(); i++) {
        const Slot &s = slots[i];

        // Slots must be in correct order.
        if (s.getStart() < prevStop) {
            return false;
        }

        prevStop = s.getStop();

        // If this is a dead slot, then nothing more needs to be checked.
        if (s.getPeerId() == NO_PEER) {
            continue;
        }

        // We have a live slot, verify index.
        auto it = peers.find(s.getPeerId());
        if (it == peers.end() || it->index != i) {
            return false;
        }
    }

    for (const auto &p : peers) {
        // Count node attached to this peer.
        const auto count_nodes = [&]() {
            size_t count = 0;
            auto &nview = nodes.get<next_request_time>();
            auto begin =
                nview.lower_bound(boost::make_tuple(p.peerid, TimePoint()));
            auto end =
                nview.upper_bound(boost::make_tuple(p.peerid + 1, TimePoint()));

            for (auto it = begin; it != end; ++it) {
                count++;
            }

            return count;
        };

        if (p.node_count != count_nodes()) {
            return false;
        }

        // If there are no nodes attached to this peer, then we are done.
        if (p.node_count == 0) {
            continue;
        }

        // The index must point to a slot refering to this peer.
        if (p.index >= slots.size() || slots[p.index].getPeerId() != p.peerid) {
            return false;
        }

        // If the score do not match, same thing.
        if (slots[p.index].getScore() != p.getScore()) {
            return false;
        }
    }

    return true;
}

PeerId selectPeerImpl(const std::vector<Slot> &slots, const uint64_t slot,
                      const uint64_t max) {
    assert(slot <= max);

    size_t begin = 0, end = slots.size();
    uint64_t bottom = 0, top = max;

    // Try to find the slot using dichotomic search.
    while ((end - begin) > 8) {
        // The slot we picked in not allocated.
        if (slot < bottom || slot >= top) {
            return NO_PEER;
        }

        // Guesstimate the position of the slot.
        size_t i = begin + ((slot - bottom) * (end - begin) / (top - bottom));
        assert(begin <= i && i < end);

        // We have a match.
        if (slots[i].contains(slot)) {
            return slots[i].getPeerId();
        }

        // We undershooted.
        if (slots[i].precedes(slot)) {
            begin = i + 1;
            if (begin >= end) {
                return NO_PEER;
            }

            bottom = slots[begin].getStart();
            continue;
        }

        // We overshooted.
        if (slots[i].follows(slot)) {
            end = i;
            top = slots[end].getStart();
            continue;
        }

        // We have an unalocated slot.
        return NO_PEER;
    }

    // Enough of that nonsense, let fallback to linear search.
    for (size_t i = begin; i < end; i++) {
        // We have a match.
        if (slots[i].contains(slot)) {
            return slots[i].getPeerId();
        }
    }

    // We failed to find a slot, retry.
    return NO_PEER;
}

bool PeerManager::isOrphan(const ProofId &id) const {
    return orphanProofs.getProof(id) != nullptr;
}

std::shared_ptr<Proof> PeerManager::getOrphan(const ProofId &id) const {
    return orphanProofs.getProof(id);
}

void PeerManager::addUnbroadcastProof(const ProofId &proofid) {
    // The proof should be known
    if (getProof(proofid)) {
        m_unbroadcast_proofids.insert(proofid);
    }
}

void PeerManager::removeUnbroadcastProof(const ProofId &proofid) {
    m_unbroadcast_proofids.erase(proofid);
}

} // namespace avalanche
<|endoftext|>