text:
#include "contractor/contractor.hpp"
#include "contractor/crc32_processor.hpp"
#include "contractor/graph_contractor.hpp"

#include "extractor/compressed_edge_container.hpp"
#include "extractor/edge_based_graph_factory.hpp"
#include "extractor/node_based_edge.hpp"

#include "util/exception.hpp"
#include "util/graph_loader.hpp"
#include "util/integer_range.hpp"
#include "util/io.hpp"
#include "util/simple_logger.hpp"
#include "util/static_graph.hpp"
#include "util/static_rtree.hpp"
#include "util/string_util.hpp"
#include "util/timing_util.hpp"
#include "util/typedefs.hpp"

#include <boost/assert.hpp>
#include <boost/filesystem/fstream.hpp>
#include <boost/functional/hash.hpp>
#include <boost/interprocess/file_mapping.hpp>
#include <boost/interprocess/mapped_region.hpp>
#include <boost/spirit/include/qi.hpp>

#include <tbb/blocked_range.h>
#include <tbb/concurrent_unordered_map.h>
#include <tbb/enumerable_thread_specific.h>
#include <tbb/parallel_for.h>
#include <tbb/parallel_for_each.h>
#include <tbb/parallel_invoke.h>
#include <tbb/parallel_sort.h>
#include <tbb/spin_mutex.h>

#include <algorithm>
#include <bitset>
#include <cstdint>
#include <fstream>
#include <iterator>
#include <memory>
#include <thread>
#include <tuple>
#include <vector>

namespace std
{

template <> struct hash<std::pair<OSMNodeID, OSMNodeID>>
{
    std::size_t operator()(const std::pair<OSMNodeID, OSMNodeID> &k) const noexcept
    {
        return static_cast<uint64_t>(k.first) ^ (static_cast<uint64_t>(k.second) << 12);
    }
};

template <> struct hash<std::tuple<OSMNodeID, OSMNodeID, OSMNodeID>>
{
    std::size_t operator()(const std::tuple<OSMNodeID, OSMNodeID, OSMNodeID> &k) const noexcept
    {
        std::size_t seed = 0;
        boost::hash_combine(seed, static_cast<uint64_t>(std::get<0>(k)));
        boost::hash_combine(seed, static_cast<uint64_t>(std::get<1>(k)));
        boost::hash_combine(seed, static_cast<uint64_t>(std::get<2>(k)));
        return seed;
    }
};
}

namespace osrm
{
namespace contractor
{

// Returns duration in deci-seconds
inline EdgeWeight distanceAndSpeedToWeight(double distance_in_meters, double speed_in_kmh)
{
    BOOST_ASSERT(speed_in_kmh > 0);
    const double speed_in_ms = speed_in_kmh / 3.6;
    const double duration = distance_in_meters / speed_in_ms;
    return std::max<EdgeWeight>(1, static_cast<EdgeWeight>(std::round(duration * 10)));
}

int Contractor::Run()
{
#ifdef WIN32
#pragma message("Memory consumption on Windows can be higher due to different bit packing")
#else
    static_assert(sizeof(extractor::NodeBasedEdge) == 24,
                  "changing extractor::NodeBasedEdge type has influence on memory consumption!");
    static_assert(sizeof(extractor::EdgeBasedEdge) == 16,
                  "changing EdgeBasedEdge type has influence on memory consumption!");
#endif

    if (config.core_factor > 1.0 || config.core_factor < 0)
    {
        throw util::exception("Core factor must be between 0.0 to 1.0 (inclusive)");
    }

    TIMER_START(preparing);

    util::SimpleLogger().Write() << "Loading edge-expanded graph representation";

    util::DeallocatingVector<extractor::EdgeBasedEdge> edge_based_edge_list;

    EdgeID max_edge_id = LoadEdgeExpandedGraph(config.edge_based_graph_path,
                                               edge_based_edge_list,
                                               config.edge_segment_lookup_path,
                                               config.edge_penalty_path,
                                               config.segment_speed_lookup_paths,
                                               config.turn_penalty_lookup_paths,
                                               config.node_based_graph_path,
                                               config.geometry_path,
                                               config.datasource_names_path,
                                               config.datasource_indexes_path,
                                               config.rtree_leaf_path);

    // Contracting the edge-expanded graph

    TIMER_START(contraction);
    std::vector<bool> is_core_node;
    std::vector<float> node_levels;
    if (config.use_cached_priority)
    {
        ReadNodeLevels(node_levels);
    }

    util::SimpleLogger().Write() << "Reading node weights.";
    std::vector<EdgeWeight> node_weights;
    std::string node_file_name = config.osrm_input_path.string() + ".enw";
    if (util::deserializeVector(node_file_name, node_weights))
    {
        util::SimpleLogger().Write() << "Done reading node weights.";
    }
    else
    {
        throw util::exception("Failed reading node weights.");
    }

    util::DeallocatingVector<QueryEdge> contracted_edge_list;
    ContractGraph(max_edge_id,
                  edge_based_edge_list,
                  contracted_edge_list,
                  std::move(node_weights),
                  is_core_node,
                  node_levels);
    TIMER_STOP(contraction);

    util::SimpleLogger().Write() << "Contraction took " << TIMER_SEC(contraction) << " sec";

    std::size_t number_of_used_edges = WriteContractedGraph(max_edge_id, contracted_edge_list);
    WriteCoreNodeMarker(std::move(is_core_node));
    if (!config.use_cached_priority)
    {
        WriteNodeLevels(std::move(node_levels));
    }

    TIMER_STOP(preparing);

    util::SimpleLogger().Write() << "Preprocessing : " << TIMER_SEC(preparing) << " seconds";
    util::SimpleLogger().Write() << "Contraction: " << ((max_edge_id + 1) / TIMER_SEC(contraction))
                                 << " nodes/sec and "
                                 << number_of_used_edges / TIMER_SEC(contraction) << " edges/sec";

    util::SimpleLogger().Write() << "finished preprocessing";

    return 0;
}

// Utilities for LoadEdgeExpandedGraph to restore my sanity
namespace
{

struct Segment final
{
    OSMNodeID from, to;
};

struct SpeedSource final
{
    unsigned speed;
    std::uint8_t source;
};

struct SegmentSpeedSource final
{
    Segment segment;
    SpeedSource speed_source;
};

using SegmentSpeedSourceFlatMap = std::vector<SegmentSpeedSource>;

// Binary Search over a flattened key,val Segment storage
SegmentSpeedSourceFlatMap::iterator find(SegmentSpeedSourceFlatMap &map, const Segment &key)
{
    const auto last = end(map);

    const auto by_segment = [](const SegmentSpeedSource &lhs, const SegmentSpeedSource &rhs) {
        return std::tie(lhs.segment.from, lhs.segment.to) >
               std::tie(rhs.segment.from, rhs.segment.to);
    };

    auto it = std::lower_bound(begin(map), last, SegmentSpeedSource{key, {0, 0}}, by_segment);

    if (it != last && (std::tie(it->segment.from, it->segment.to) == std::tie(key.from, key.to)))
        return it;

    return last;
}

// Convenience aliases. TODO: make actual types at some point in time.
// TODO: turn penalties need flat map + binary search optimization, take a look at segment speeds

using Turn = std::tuple<OSMNodeID, OSMNodeID, OSMNodeID>;
using TurnHasher = std::hash<Turn>;
using PenaltySource = std::pair<double, std::uint8_t>;
using TurnPenaltySourceMap = tbb::concurrent_unordered_map<Turn, PenaltySource, TurnHasher>;

// Functions for parsing files and creating lookup tables

SegmentSpeedSourceFlatMap
parse_segment_lookup_from_csv_files(const std::vector<std::string> &segment_speed_filenames)
{
    // TODO: shares code with turn penalty lookup parse function

    using Mutex = tbb::spin_mutex;

    // Loaded and parsed in parallel, at the end we combine results in a flattened map-ish view
    SegmentSpeedSourceFlatMap flatten;
    Mutex flatten_mutex;

    const auto parse_segment_speed_file = [&](const std::size_t idx) {
        const auto file_id = idx + 1; // starts at one, zero means we assigned the weight
        const auto filename = segment_speed_filenames[idx];

        std::ifstream segment_speed_file{filename, std::ios::binary};
        if (!segment_speed_file)
            throw util::exception{"Unable to open segment speed file " + filename};

        SegmentSpeedSourceFlatMap local;

        std::uint64_t from_node_id{};
        std::uint64_t to_node_id{};
        unsigned speed{};

        for (std::string line; std::getline(segment_speed_file, line);)
        {
            using namespace boost::spirit::qi;

            auto it = begin(line);
            const auto last = end(line);

            // The ulong_long -> uint64_t will likely break on 32bit platforms
            const auto ok = parse(it,
                                  last,                                              //
                                  (ulong_long >> ',' >> ulong_long >> ',' >> uint_), //
                                  from_node_id,
                                  to_node_id,
                                  speed); //

            if (!ok || it != last)
                throw util::exception{"Segment speed file " + filename + " malformed"};

            SegmentSpeedSource val{
                {OSMNodeID{from_node_id}, OSMNodeID{to_node_id}},
                {speed, static_cast<std::uint8_t>(file_id)}};

            local.push_back(std::move(val));
        }

        util::SimpleLogger().Write() << "Loaded speed file " << filename << " with " << local.size()
                                     << " speeds";

        {
            Mutex::scoped_lock _{flatten_mutex};

            flatten.insert(end(flatten),
                           std::make_move_iterator(begin(local)),
                           std::make_move_iterator(end(local)));
        }
    };

    tbb::parallel_for(std::size_t{0}, segment_speed_filenames.size(), parse_segment_speed_file);

    // With flattened map-ish view of all the files, sort and unique them on from,to,source
    // The greater '>' is used here since we want to give files later on higher precedence
    const auto sort_by = [](const SegmentSpeedSource &lhs, const SegmentSpeedSource &rhs) {
        return std::tie(lhs.segment.from, lhs.segment.to, lhs.speed_source.source) >
               std::tie(rhs.segment.from, rhs.segment.to, rhs.speed_source.source);
    };

    std::stable_sort(begin(flatten), end(flatten), sort_by);

    // Unique only on from,to to take the source precedence into account and remove duplicates
    const auto unique_by = [](const SegmentSpeedSource &lhs, const SegmentSpeedSource &rhs) {
        return std::tie(lhs.segment.from, lhs.segment.to) ==
               std::tie(rhs.segment.from, rhs.segment.to);
    };

    const auto it = std::unique(begin(flatten), end(flatten), unique_by);

    flatten.erase(it, end(flatten));

    util::SimpleLogger().Write() << "In total loaded " << segment_speed_filenames.size()
                                 << " speed file(s) with a total of " << flatten.size()
                                 << " unique values";

    return flatten;
}

TurnPenaltySourceMap
parse_turn_penalty_lookup_from_csv_files(const std::vector<std::string> &turn_penalty_filenames)
{
    // TODO: shares code with turn penalty lookup parse function
    TurnPenaltySourceMap map;

    const auto parse_turn_penalty_file = [&](const std::size_t idx) {
        const auto file_id = idx + 1; // starts at one, zero means we assigned the weight
        const auto filename = turn_penalty_filenames[idx];

        std::ifstream turn_penalty_file{filename, std::ios::binary};
        if (!turn_penalty_file)
            throw util::exception{"Unable to open turn penalty file " + filename};

        std::uint64_t from_node_id{};
        std::uint64_t via_node_id{};
        std::uint64_t to_node_id{};
        double penalty{};

        for (std::string line; std::getline(turn_penalty_file, line);)
        {
            using namespace boost::spirit::qi;

            auto it = begin(line);
            const auto last = end(line);

            // The ulong_long -> uint64_t will likely break on 32bit platforms
            const auto ok =
                parse(it,
                      last,                                                                     //
                      (ulong_long >> ',' >> ulong_long >> ',' >> ulong_long >> ',' >> double_), //
                      from_node_id,
                      via_node_id,
                      to_node_id,
                      penalty); //

            if (!ok || it != last)
                throw util::exception{"Turn penalty file " + filename + " malformed"};

            map[std::make_tuple(
                OSMNodeID{from_node_id}, OSMNodeID{via_node_id}, OSMNodeID{to_node_id})] =
                std::make_pair(penalty, file_id);
        }
    };

    tbb::parallel_for(std::size_t{0}, turn_penalty_filenames.size(), parse_turn_penalty_file);

    return map;
}
} // anon ns

EdgeID Contractor::LoadEdgeExpandedGraph(
    std::string const &edge_based_graph_filename,
    util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
    const std::string &edge_segment_lookup_filename,
    const std::string &edge_penalty_filename,
    const std::vector<std::string> &segment_speed_filenames,
    const std::vector<std::string> &turn_penalty_filenames,
    const std::string &nodes_filename,
    const std::string &geometry_filename,
    const std::string &datasource_names_filename,
    const std::string &datasource_indexes_filename,
    const std::string &rtree_leaf_filename)
{
    if (segment_speed_filenames.size() > 255 || turn_penalty_filenames.size() > 255)
        throw util::exception("Limit of 255 segment speed and turn penalty files each reached");

    util::SimpleLogger().Write() << "Opening " << edge_based_graph_filename;

    auto mmap_file = [](const std::string &filename) {
        using boost::interprocess::file_mapping;
        using boost::interprocess::mapped_region;
        using boost::interprocess::read_only;

        const file_mapping mapping{ filename.c_str(), read_only };
        mapped_region region{mapping, read_only};
        region.advise(mapped_region::advice_sequential);
        return region;
    };

    const auto edge_based_graph_region = mmap_file(edge_based_graph_filename);

    const bool update_edge_weights = !segment_speed_filenames.empty();
    const bool update_turn_penalties = !turn_penalty_filenames.empty();

    const auto edge_penalty_region = [&] {
        if (update_edge_weights || update_turn_penalties)
        {
            return mmap_file(edge_penalty_filename);
        }
        return boost::interprocess::mapped_region();
    }();

    const auto edge_segment_region = [&] {
        if (update_edge_weights || update_turn_penalties)
        {
            return mmap_file(edge_segment_lookup_filename);
        }
        return boost::interprocess::mapped_region();
    }();

    // Set the struct packing to 1 byte word sizes.  This prevents any padding.  We only use
    // this struct once, so any alignment penalty is trivial.  If this is *not* done, then
    // the struct will be padded out by an extra 4 bytes, and sizeof() will mean we read
    // too much data from the original file.
    #pragma pack(push, r1, 1)
    struct EdgeBasedGraphHeader {
        util::FingerPrint fingerprint;
        std::uint64_t number_of_edges;
        EdgeID max_edge_id;
    };
    #pragma pack(pop, r1)

    const EdgeBasedGraphHeader graph_header = *(reinterpret_cast<const EdgeBasedGraphHeader *>(edge_based_graph_region.get_address()));

    const util::FingerPrint fingerprint_valid = util::FingerPrint::GetValid();
    graph_header.fingerprint.TestContractor(fingerprint_valid);

    edge_based_edge_list.resize(graph_header.number_of_edges);
    util::SimpleLogger().Write() << "Reading " << graph_header.number_of_edges
                                 << " edges from the edge based graph";

    SegmentSpeedSourceFlatMap segment_speed_lookup;
    TurnPenaltySourceMap turn_penalty_lookup;

    const auto parse_segment_speeds = [&] {
        if (update_edge_weights)
            segment_speed_lookup = parse_segment_lookup_from_csv_files(segment_speed_filenames);
    };

    const auto parse_turn_penalties = [&] {
        if (update_turn_penalties)
            turn_penalty_lookup = parse_turn_penalty_lookup_from_csv_files(turn_penalty_filenames);
    };

    // If we update the edge weights, this file will hold the datasource information for each
    // segment; the other files will also be conditionally filled concurrently if we make an update
    std::vector<uint8_t> m_geometry_datasource;

    std::vector<extractor::QueryNode> internal_to_external_node_map;
    std::vector<unsigned> m_geometry_indices;
    std::vector<extractor::CompressedEdgeContainer::CompressedEdge> m_geometry_list;

    const auto maybe_load_internal_to_external_node_map = [&] {
        if (!(update_edge_weights || update_turn_penalties))
            return;

        boost::filesystem::ifstream nodes_input_stream(nodes_filename, std::ios::binary);

        if (!nodes_input_stream)
        {
            throw util::exception("Failed to open " + nodes_filename);
        }

        unsigned number_of_nodes = 0;
        nodes_input_stream.read((char *)&number_of_nodes, sizeof(unsigned));
        internal_to_external_node_map.resize(number_of_nodes);

        // Load all the query nodes into a vector
        nodes_input_stream.read(reinterpret_cast<char *>(&(internal_to_external_node_map[0])),
                                number_of_nodes * sizeof(extractor::QueryNode));
    };

    const auto maybe_load_geometries = [&] {
        if (!(update_edge_weights || update_turn_penalties))
            return;

        std::ifstream geometry_stream(geometry_filename, std::ios::binary);
        if (!geometry_stream)
        {
            throw util::exception("Failed to open " + geometry_filename);
        }
        unsigned number_of_indices = 0;
        unsigned number_of_compressed_geometries = 0;

        geometry_stream.read((char *)&number_of_indices, sizeof(unsigned));

        m_geometry_indices.resize(number_of_indices);
        if (number_of_indices > 0)
        {
            geometry_stream.read((char *)&(m_geometry_indices[0]),
                                 number_of_indices * sizeof(unsigned));
        }

        geometry_stream.read((char *)&number_of_compressed_geometries, sizeof(unsigned));

        BOOST_ASSERT(m_geometry_indices.back() == number_of_compressed_geometries);
        m_geometry_list.resize(number_of_compressed_geometries);

        if (number_of_compressed_geometries > 0)
        {
            geometry_stream.read((char *)&(m_geometry_list[0]),
                                 number_of_compressed_geometries *
                                     sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
        }
    };

    // Folds all our actions into independently concurrently executing lambdas
    tbb::parallel_invoke(parse_segment_speeds,
                         parse_turn_penalties, //
                         maybe_load_internal_to_external_node_map,
                         maybe_load_geometries);

    if (update_edge_weights || update_turn_penalties)
    {
        // Here, we have to update the compressed geometry weights
        // First, we need the external-to-internal node lookup table

        // This is a list of the "data source id" for every segment in the compressed
        // geometry container.  We assume that everything so far has come from the
        // profile (data source 0).  Here, we replace the 0's with the index of the
        // CSV file that supplied the value that gets used for that segment, then
        // we write out this list so that it can be returned by the debugging
        // vector tiles later on.
        m_geometry_datasource.resize(m_geometry_list.size(), 0);

        // Now, we iterate over all the segments stored in the StaticRTree, updating
        // the packed geometry weights in the `.geometries` file (note: we do not
        // update the RTree itself, we just use the leaf nodes to iterate over all segments)
        using LeafNode = util::StaticRTree<extractor::EdgeBasedNode>::LeafNode;

        using boost::interprocess::mapped_region;

        auto region = mmap_file(rtree_leaf_filename.c_str());
        region.advise(mapped_region::advice_willneed);

        const auto bytes = region.get_size();
        const auto first = static_cast<const LeafNode *>(region.get_address());
        const auto last = first + (bytes / sizeof(LeafNode));

        // vector to count used speeds for logging
        // size offset by one since index 0 is used for speeds not from external file
        using counters_type = std::vector<std::size_t>;
        std::size_t num_counters = segment_speed_filenames.size() + 1;
        tbb::enumerable_thread_specific<counters_type> segment_speeds_counters(
            counters_type(num_counters, 0));
        const constexpr auto LUA_SOURCE = 0;

        tbb::parallel_for_each(first, last, [&](const LeafNode &current_node) {
            auto &counters = segment_speeds_counters.local();
            for (size_t i = 0; i < current_node.object_count; i++)
            {
                const auto &leaf_object = current_node.objects[i];
                extractor::QueryNode *u;
                extractor::QueryNode *v;

                if (leaf_object.forward_packed_geometry_id != SPECIAL_EDGEID)
                {
                    const unsigned forward_begin =
                        m_geometry_indices.at(leaf_object.forward_packed_geometry_id);

                    if (leaf_object.fwd_segment_position == 0)
                    {
                        u = &(internal_to_external_node_map[leaf_object.u]);
                        v = &(
                            internal_to_external_node_map[m_geometry_list[forward_begin].node_id]);
                    }
                    else
                    {
                        u = &(internal_to_external_node_map
                                  [m_geometry_list[forward_begin +
                                                   leaf_object.fwd_segment_position - 1]
                                       .node_id]);
                        v = &(internal_to_external_node_map
                                  [m_geometry_list[forward_begin + leaf_object.fwd_segment_position]
                                       .node_id]);
                    }
                    const double segment_length = util::coordinate_calculation::greatCircleDistance(
                        util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});

                    auto forward_speed_iter =
                        find(segment_speed_lookup, Segment{u->node_id, v->node_id});
                    if (forward_speed_iter != segment_speed_lookup.end())
                    {
                        auto new_segment_weight =
                            (forward_speed_iter->speed_source.speed > 0)
                                ? distanceAndSpeedToWeight(segment_length,
                                                           forward_speed_iter->speed_source.speed)
                                : INVALID_EDGE_WEIGHT;
                        m_geometry_list[forward_begin + leaf_object.fwd_segment_position].weight =
                            new_segment_weight;
                        m_geometry_datasource[forward_begin + leaf_object.fwd_segment_position] =
                            forward_speed_iter->speed_source.source;

                        // count statistics for logging
                        counters[forward_speed_iter->speed_source.source] += 1;
                    }
                    else
                    {
                        // count statistics for logging
                        counters[LUA_SOURCE] += 1;
                    }
                }
                if (leaf_object.reverse_packed_geometry_id != SPECIAL_EDGEID)
                {
                    const unsigned reverse_begin =
                        m_geometry_indices.at(leaf_object.reverse_packed_geometry_id);
                    const unsigned reverse_end =
                        m_geometry_indices.at(leaf_object.reverse_packed_geometry_id + 1);

                    int rev_segment_position =
                        (reverse_end - reverse_begin) - leaf_object.fwd_segment_position - 1;
                    if (rev_segment_position == 0)
                    {
                        u = &(internal_to_external_node_map[leaf_object.v]);
                        v = &(
                            internal_to_external_node_map[m_geometry_list[reverse_begin].node_id]);
                    }
                    else
                    {
                        u = &(
                            internal_to_external_node_map[m_geometry_list[reverse_begin +
                                                                          rev_segment_position - 1]
                                                              .node_id]);
                        v = &(internal_to_external_node_map
                                  [m_geometry_list[reverse_begin + rev_segment_position].node_id]);
                    }
                    const double segment_length = util::coordinate_calculation::greatCircleDistance(
                        util::Coordinate{u->lon, u->lat}, util::Coordinate{v->lon, v->lat});

                    auto reverse_speed_iter =
                        find(segment_speed_lookup, Segment{u->node_id, v->node_id});
                    if (reverse_speed_iter != segment_speed_lookup.end())
                    {
                        auto new_segment_weight =
                            (reverse_speed_iter->speed_source.speed > 0)
                                ? distanceAndSpeedToWeight(segment_length,
                                                           reverse_speed_iter->speed_source.speed)
                                : INVALID_EDGE_WEIGHT;
                        m_geometry_list[reverse_begin + rev_segment_position].weight =
                            new_segment_weight;
                        m_geometry_datasource[reverse_begin + rev_segment_position] =
                            reverse_speed_iter->speed_source.source;

                        // count statistics for logging
                        counters[reverse_speed_iter->speed_source.source] += 1;
                    }
                    else
                    {
                        // count statistics for logging
                        counters[LUA_SOURCE] += 1;
                    }
                }
            }
        }); // parallel_for_each

        counters_type merged_counters(num_counters, 0);
        for (const auto &counters : segment_speeds_counters)
        {
            for (std::size_t i = 0; i < counters.size(); i++)
            {
                merged_counters[i] += counters[i];
            }
        }

        for (std::size_t i = 0; i < merged_counters.size(); i++)
        {
            if (i == LUA_SOURCE)
            {
                util::SimpleLogger().Write() << "Used " << merged_counters[LUA_SOURCE]
                                             << " speeds from LUA profile or input map";
            }
            else
            {
                // segments_speeds_counters has 0 as LUA, segment_speed_filenames not, thus we need
                // to susbstract 1 to avoid off-by-one error
                util::SimpleLogger().Write() << "Used " << merged_counters[i] << " speeds from "
                                             << segment_speed_filenames[i - 1];
            }
        }
    }

    const auto maybe_save_geometries = [&] {
        if (!(update_edge_weights || update_turn_penalties))
            return;

        // Now save out the updated compressed geometries
        std::ofstream geometry_stream(geometry_filename, std::ios::binary);
        if (!geometry_stream)
        {
            throw util::exception("Failed to open " + geometry_filename + " for writing");
        }
        const unsigned number_of_indices = m_geometry_indices.size();
        const unsigned number_of_compressed_geometries = m_geometry_list.size();
        geometry_stream.write(reinterpret_cast<const char *>(&number_of_indices), sizeof(unsigned));
        geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_indices[0])),
                              number_of_indices * sizeof(unsigned));
        geometry_stream.write(reinterpret_cast<const char *>(&number_of_compressed_geometries),
                              sizeof(unsigned));
        geometry_stream.write(reinterpret_cast<char *>(&(m_geometry_list[0])),
                              number_of_compressed_geometries *
                                  sizeof(extractor::CompressedEdgeContainer::CompressedEdge));
    };

    const auto save_datasource_indexes = [&] {
        std::ofstream datasource_stream(datasource_indexes_filename, std::ios::binary);
        if (!datasource_stream)
        {
            throw util::exception("Failed to open " + datasource_indexes_filename + " for writing");
        }
        std::uint64_t number_of_datasource_entries = m_geometry_datasource.size();
        datasource_stream.write(reinterpret_cast<const char *>(&number_of_datasource_entries),
                                sizeof(number_of_datasource_entries));
        if (number_of_datasource_entries > 0)
        {
            datasource_stream.write(reinterpret_cast<char *>(&(m_geometry_datasource[0])),
                                    number_of_datasource_entries * sizeof(uint8_t));
        }
    };

    const auto save_datastore_names = [&] {
        std::ofstream datasource_stream(datasource_names_filename, std::ios::binary);
        if (!datasource_stream)
        {
            throw util::exception("Failed to open " + datasource_names_filename + " for writing");
        }
        datasource_stream << "lua profile" << std::endl;
        for (auto const &name : segment_speed_filenames)
        {
            // Only write the filename, without path or extension.
            // This prevents information leakage, and keeps names short
            // for rendering in the debug tiles.
            const boost::filesystem::path p(name);
            datasource_stream << p.stem().string() << std::endl;
        }
    };

    tbb::parallel_invoke(maybe_save_geometries, save_datasource_indexes, save_datastore_names);

    auto penaltyblock =
        reinterpret_cast<const extractor::lookup::PenaltyBlock *>(edge_penalty_region.get_address());
    auto edge_segment_byte_ptr = reinterpret_cast<const char *>(edge_segment_region.get_address());
    auto edge_based_edge_ptr = reinterpret_cast<extractor::EdgeBasedEdge *>(
        reinterpret_cast<char *>(edge_based_graph_region.get_address()) + sizeof(EdgeBasedGraphHeader));

    const auto edge_based_edge_last = reinterpret_cast<extractor::EdgeBasedEdge *>(
        reinterpret_cast<char *>(edge_based_graph_region.get_address()) + sizeof(EdgeBasedGraphHeader) + sizeof(extractor::EdgeBasedEdge) * graph_header.number_of_edges);

    while (edge_based_edge_ptr != edge_based_edge_last)
    {
        // Make a copy of the data from the memory map
        extractor::EdgeBasedEdge inbuffer = *edge_based_edge_ptr;
        edge_based_edge_ptr++;

        if (update_edge_weights || update_turn_penalties)
        {
            auto header = reinterpret_cast<const extractor::lookup::SegmentHeaderBlock *>(
                edge_segment_byte_ptr);
            edge_segment_byte_ptr += sizeof(extractor::lookup::SegmentHeaderBlock);

            auto previous_osm_node_id = header->previous_osm_node_id;
            int new_weight = 0;
            int compressed_edge_nodes = static_cast<int>(header->num_osm_nodes);

            auto segmentblocks =
                reinterpret_cast<const extractor::lookup::SegmentBlock *>(edge_segment_byte_ptr);
            edge_segment_byte_ptr +=
                sizeof(extractor::lookup::SegmentBlock) * (header->num_osm_nodes - 1);

            const auto num_segments = header->num_osm_nodes - 1;
            for (auto i : util::irange<std::size_t>(0, num_segments))
            {
                auto speed_iter =
                    find(segment_speed_lookup,
                         Segment{previous_osm_node_id, segmentblocks[i].this_osm_node_id});
                if (speed_iter != segment_speed_lookup.end())
                {
                    if (speed_iter->speed_source.speed > 0)
                    {
                        auto new_segment_weight = distanceAndSpeedToWeight(segmentblocks[i].segment_length, speed_iter->speed_source.speed);
                        new_weight += new_segment_weight;
                    }
                    else
                    {
                        // This edge is blocked, we don't need to continue updating
                        new_weight = INVALID_EDGE_WEIGHT;
                        break;
                    }
                }
                else
                {
                    // If no lookup found, use the original weight value for this segment
                    new_weight += segmentblocks[i].segment_weight;
                }

                previous_osm_node_id = segmentblocks[i].this_osm_node_id;
            }

            const auto turn_iter = turn_penalty_lookup.find(
                std::make_tuple(penaltyblock->from_id, penaltyblock->via_id, penaltyblock->to_id));
            if (turn_iter != turn_penalty_lookup.end())
            {
                int new_turn_weight = static_cast<int>(turn_iter->second.first * 10);

                if (new_turn_weight + new_weight < compressed_edge_nodes)
                {
                    util::SimpleLogger().Write(logWARNING)
                        << "turn penalty " << turn_iter->second.first << " for turn "
                        << penaltyblock->from_id << ", " << penaltyblock->via_id << ", "
                        << penaltyblock->to_id << " is too negative: clamping turn weight to "
                        << compressed_edge_nodes;
                }

                inbuffer.weight = std::max(new_turn_weight + new_weight, compressed_edge_nodes);
            }
            else
            {
                inbuffer.weight = penaltyblock->fixed_penalty + new_weight;
            }

            // Increment the pointer
            penaltyblock++;
        }

        edge_based_edge_list.emplace_back(std::move(inbuffer));
    }

    util::SimpleLogger().Write() << "Done reading edges";
    return graph_header.max_edge_id;
}

void Contractor::ReadNodeLevels(std::vector<float> &node_levels) const
{
    boost::filesystem::ifstream order_input_stream(config.level_output_path, std::ios::binary);

    unsigned level_size;
    order_input_stream.read((char *)&level_size, sizeof(unsigned));
    node_levels.resize(level_size);
    order_input_stream.read((char *)node_levels.data(), sizeof(float) * node_levels.size());
}

void Contractor::WriteNodeLevels(std::vector<float> &&in_node_levels) const
{
    std::vector<float> node_levels(std::move(in_node_levels));

    boost::filesystem::ofstream order_output_stream(config.level_output_path, std::ios::binary);

    unsigned level_size = node_levels.size();
    order_output_stream.write((char *)&level_size, sizeof(unsigned));
    order_output_stream.write((char *)node_levels.data(), sizeof(float) * node_levels.size());
}

void Contractor::WriteCoreNodeMarker(std::vector<bool> &&in_is_core_node) const
{
    std::vector<bool> is_core_node(std::move(in_is_core_node));
    std::vector<char> unpacked_bool_flags(std::move(is_core_node.size()));
    for (auto i = 0u; i < is_core_node.size(); ++i)
    {
        unpacked_bool_flags[i] = is_core_node[i] ? 1 : 0;
    }

    boost::filesystem::ofstream core_marker_output_stream(config.core_output_path,
                                                          std::ios::binary);
    unsigned size = unpacked_bool_flags.size();
    core_marker_output_stream.write((char *)&size, sizeof(unsigned));
    core_marker_output_stream.write((char *)unpacked_bool_flags.data(),
                                    sizeof(char) * unpacked_bool_flags.size());
}

std::size_t
Contractor::WriteContractedGraph(unsigned max_node_id,
                                 const util::DeallocatingVector<QueryEdge> &contracted_edge_list)
{
    // Sorting contracted edges in a way that the static query graph can read some in in-place.
    tbb::parallel_sort(contracted_edge_list.begin(), contracted_edge_list.end());
    const unsigned contracted_edge_count = contracted_edge_list.size();
    util::SimpleLogger().Write() << "Serializing compacted graph of " << contracted_edge_count
                                 << " edges";

    const util::FingerPrint fingerprint = util::FingerPrint::GetValid();
    boost::filesystem::ofstream hsgr_output_stream(config.graph_output_path, std::ios::binary);
    hsgr_output_stream.write((char *)&fingerprint, sizeof(util::FingerPrint));
    const NodeID max_used_node_id = [&contracted_edge_list] {
        NodeID tmp_max = 0;
        for (const QueryEdge &edge : contracted_edge_list)
        {
            BOOST_ASSERT(SPECIAL_NODEID != edge.source);
            BOOST_ASSERT(SPECIAL_NODEID != edge.target);
            tmp_max = std::max(tmp_max, edge.source);
            tmp_max = std::max(tmp_max, edge.target);
        }
        return tmp_max;
    }();

    util::SimpleLogger().Write(logDEBUG) << "input graph has " << (max_node_id + 1) << " nodes";
    util::SimpleLogger().Write(logDEBUG) << "contracted graph has " << (max_used_node_id + 1)
                                         << " nodes";

    std::vector<util::StaticGraph<EdgeData>::NodeArrayEntry> node_array;
    // make sure we have at least one sentinel
    node_array.resize(max_node_id + 2);

    util::SimpleLogger().Write() << "Building node array";
    util::StaticGraph<EdgeData>::EdgeIterator edge = 0;
    util::StaticGraph<EdgeData>::EdgeIterator position = 0;
    util::StaticGraph<EdgeData>::EdgeIterator last_edge;

    // initializing 'first_edge'-field of nodes:
    for (const auto node : util::irange(0u, max_used_node_id + 1))
    {
        last_edge = edge;
        while ((edge < contracted_edge_count) && (contracted_edge_list[edge].source == node))
        {
            ++edge;
        }
        node_array[node].first_edge = position; //=edge
        position += edge - last_edge;           // remove
    }

    for (const auto sentinel_counter :
         util::irange<unsigned>(max_used_node_id + 1, node_array.size()))
    {
        // sentinel element, guarded against underflow
        node_array[sentinel_counter].first_edge = contracted_edge_count;
    }

    util::SimpleLogger().Write() << "Serializing node array";

    RangebasedCRC32 crc32_calculator;
    const unsigned edges_crc32 = crc32_calculator(contracted_edge_list);
    util::SimpleLogger().Write() << "Writing CRC32: " << edges_crc32;

    const unsigned node_array_size = node_array.size();
    // serialize crc32, aka checksum
    hsgr_output_stream.write((char *)&edges_crc32, sizeof(unsigned));
    // serialize number of nodes
    hsgr_output_stream.write((char *)&node_array_size, sizeof(unsigned));
    // serialize number of edges
    hsgr_output_stream.write((char *)&contracted_edge_count, sizeof(unsigned));
    // serialize all nodes
    if (node_array_size > 0)
    {
        hsgr_output_stream.write((char *)&node_array[0],
                                 sizeof(util::StaticGraph<EdgeData>::NodeArrayEntry) *
                                     node_array_size);
    }

    // serialize all edges
    util::SimpleLogger().Write() << "Building edge array";
    std::size_t number_of_used_edges = 0;

    util::StaticGraph<EdgeData>::EdgeArrayEntry current_edge;
    for (const auto edge : util::irange<std::size_t>(0UL, contracted_edge_list.size()))
    {
        // some self-loops are required for oneway handling. Need to assertthat we only keep these
        // (TODO)
        // no eigen loops
        // BOOST_ASSERT(contracted_edge_list[edge].source != contracted_edge_list[edge].target ||
        // node_represents_oneway[contracted_edge_list[edge].source]);
        current_edge.target = contracted_edge_list[edge].target;
        current_edge.data = contracted_edge_list[edge].data;

        // every target needs to be valid
        BOOST_ASSERT(current_edge.target <= max_used_node_id);
#ifndef NDEBUG
        if (current_edge.data.distance <= 0)
        {
            util::SimpleLogger().Write(logWARNING)
                << "Edge: " << edge << ",source: " << contracted_edge_list[edge].source
                << ", target: " << contracted_edge_list[edge].target
                << ", dist: " << current_edge.data.distance;

            util::SimpleLogger().Write(logWARNING) << "Failed at adjacency list of node "
                                                   << contracted_edge_list[edge].source << "/"
                                                   << node_array.size() - 1;
            return 1;
        }
#endif
        hsgr_output_stream.write((char *)&current_edge,
                                 sizeof(util::StaticGraph<EdgeData>::EdgeArrayEntry));

        ++number_of_used_edges;
    }

    return number_of_used_edges;
}

/**
 \brief Build contracted graph.
 */
void Contractor::ContractGraph(
    const EdgeID max_edge_id,
    util::DeallocatingVector<extractor::EdgeBasedEdge> &edge_based_edge_list,
    util::DeallocatingVector<QueryEdge> &contracted_edge_list,
    std::vector<EdgeWeight> &&node_weights,
    std::vector<bool> &is_core_node,
    std::vector<float> &inout_node_levels) const
{
    std::vector<float> node_levels;
    node_levels.swap(inout_node_levels);

    GraphContractor graph_contractor(
        max_edge_id + 1, edge_based_edge_list, std::move(node_levels), std::move(node_weights));
    graph_contractor.Run(config.core_factor);
    graph_contractor.GetEdges(contracted_edge_list);
    graph_contractor.GetCoreMarker(is_core_node);
    graph_contractor.GetNodeLevels(inout_node_levels);
}
}
}

ext: cpp

max_stars_repo_name: motis-project/osrm-backend

max_issues_repo_name: motis-project/osrm-backend

max_forks_repo_name: motis-project/osrm-backend


text:
#include <boost/test/unit_test.hpp>

#include "scylla_blas/queue/scylla_queue.hh"
#include "scylla_blas/matrix.hh"
#include "scylla_blas/vector.hh"
#include "scylla_blas/config.hh"
#include "fixture.hh"

BOOST_FIXTURE_TEST_SUITE(structure_tests, scylla_fixture)

BOOST_AUTO_TEST_CASE(matrices)
{
    scylla_blas::matrix<float>::init(session, 0, 5, 4, true);

    auto matrix = scylla_blas::matrix<float>(session, 0);
    auto matrix_2 = scylla_blas::matrix<float>(session, 0);

    matrix.insert_value(1, 0, M_PI);
    matrix.insert_value(1, 1, 42);
    BOOST_REQUIRE_EQUAL(std::ceil(matrix.get_value(1, 0) * 10000), std::ceil(M_PI * 10000));
    BOOST_REQUIRE_EQUAL(matrix.get_value(1, 1), 42);

    matrix.insert_value(1, 0, M_PI);
    BOOST_REQUIRE_EQUAL(std::ceil(matrix.get_value(1, 0) * 10000), std::ceil(M_PI * 10000));

    matrix.insert_value(1, 1, 100);
    BOOST_REQUIRE_EQUAL(std::ceil(matrix.get_value(1, 0) * 10000), std::ceil(M_PI * 10000));
    BOOST_REQUIRE_EQUAL(matrix.get_value(1, 1), 100);

    BOOST_REQUIRE_EQUAL(matrix.get_row_count(), 5);
    BOOST_REQUIRE_EQUAL(matrix.get_column_count(), 4);

    BOOST_REQUIRE_EQUAL(matrix.get_row_count(), matrix_2.get_row_count());
    BOOST_REQUIRE_EQUAL(matrix.get_column_count(), matrix_2.get_column_count());
}

BOOST_AUTO_TEST_CASE(vector_segments)
{
    auto vector_1 = scylla_blas::vector_segment<float>();

    for (int i = 0; i < 10; i++) {
        vector_1.emplace_back(i, 10);
    }

    std::cout << "Vec_1: ";
    for (auto entry : vector_1) {
        std::cout << "(" << entry.index << ": " << entry.value << "), ";
    }
    std::cout << std::endl;

    auto vector_2 = scylla_blas::vector_segment<float>();
    for (int i = 0; i < 5; i++) {
        vector_2.emplace_back(i, (float)M_PI * i * i);
    }
    for (int i = 15; i < 20; i++) {
        vector_2.emplace_back(i, (float) M_PI * i * i);
    }

    std::cout << "Vec_2: ";
    for (auto entry : vector_2) {
        std::cout << "(" << entry.index << ": " << entry.value << "), ";
    }
    std::cout << std::endl;

    vector_1 *= M_E;
    std::cout << "Vec_1 * e: ";
    for (auto entry : vector_1) {
        std::cout << "(" << entry.index << ": " << entry.value << "), ";
    }
    std::cout << std::endl;

    vector_1 += vector_2;
    std::cout << "Vec_1 * e + Vec_2: ";
    for (auto entry : vector_1) {
        std::cout << "(" << entry.index << ": " << entry.value << "), ";
    }
    std::cout << std::endl;
}

BOOST_AUTO_TEST_CASE(vectors)
{
    /* init */
    auto vector_1 = scylla_blas::vector<float>::init_and_return(session, 0, 2*DEFAULT_BLOCK_SIZE+1);

    BOOST_REQUIRE_EQUAL(vector_1.get_segment_count(), 3);

    /* update_values */
    std::vector<scylla_blas::vector_value<float>> values_1;
    for (int i = 1; i <= vector_1.get_length(); i++) {
        values_1.emplace_back(i, M_PI);
    }
    vector_1.update_values(values_1);

    BOOST_REQUIRE_EQUAL(std::ceil(vector_1.get_value(1) * 10000), std::ceil(M_PI * 10000));
    BOOST_REQUIRE_EQUAL(std::ceil(vector_1.get_value(vector_1.get_length()) * 10000), std::ceil(M_PI * 10000));

    /* get_segment */
    auto seg_1 = vector_1.get_segment(2);

    BOOST_REQUIRE_EQUAL(std::ceil(seg_1[0].value * 10000), std::ceil(M_PI * 10000));
    BOOST_REQUIRE_EQUAL(std::ceil(seg_1[vector_1.get_block_size()-1].value * 10000), std::ceil(M_PI * 10000));

    BOOST_REQUIRE_EQUAL(seg_1[0].index, 1);
    BOOST_REQUIRE_EQUAL(seg_1[vector_1.get_block_size()-1].index, vector_1.get_block_size());

    BOOST_REQUIRE_EQUAL(seg_1.size(), vector_1.get_block_size());

    /* get_segment last */
    auto seg_end = vector_1.get_segment(3);

    BOOST_REQUIRE_EQUAL(seg_end.size(), 1);

    /* update_value */
    vector_1.update_value(1, M_E);
    vector_1.update_value(2, 0);

    BOOST_REQUIRE_EQUAL(std::ceil(vector_1.get_value(1) * 10000), std::ceil(M_E * 10000));
    BOOST_REQUIRE_EQUAL(vector_1.get_value(2), 0);

    /* update_segment */
    scylla_blas::vector_segment<float> seg_2;
    seg_2.emplace_back(1, M_E);
    seg_2.emplace_back(2, 0);
    vector_1.update_segment(2, seg_2);

    BOOST_REQUIRE_EQUAL(std::ceil(vector_1.get_value(vector_1.get_block_size()+1) * 10000), std::ceil(M_E * 10000));
    BOOST_REQUIRE_EQUAL(vector_1.get_value(vector_1.get_block_size()+2), 0);
    BOOST_REQUIRE_EQUAL(vector_1.get_value(vector_1.get_block_size()+3), 0);

    /* get_segment with zeros */
    auto seg_3 = vector_1.get_segment(2);

    BOOST_REQUIRE_EQUAL(std::ceil(seg_3[0].value * 10000), std::ceil(M_E * 10000));
    BOOST_REQUIRE_EQUAL(seg_3[0].index, 1);

    BOOST_REQUIRE_EQUAL(seg_3.size(), 1);

    /* update_values overwriting */
    std::vector<scylla_blas::vector_value<float>> values_2;
    values_2.emplace_back(1, 0);
    values_2.emplace_back(2, M_PI);
    values_2.emplace_back(3, M_E);
    vector_1.update_values(values_2);

    BOOST_REQUIRE_EQUAL(vector_1.get_value(1), 0);
    BOOST_REQUIRE_EQUAL(std::ceil(vector_1.get_value(2) * 10000), std::ceil(M_PI * 10000));
    BOOST_REQUIRE_EQUAL(std::ceil(vector_1.get_value(3) * 10000), std::ceil(M_E * 10000));

    /* clear */
    vector_1.clear_value(2);

    BOOST_REQUIRE_EQUAL(vector_1.get_value(2), 0);

    vector_1.clear_segment(1);

    BOOST_REQUIRE_EQUAL(vector_1.get_value(3), 0);
}

BOOST_AUTO_TEST_SUITE_END();

ext: cc

max_stars_repo_name: scylla-zpp-blas/linear-algebra

max_issues_repo_name: scylla-zpp-blas/linear-algebra

max_forks_repo_name: scylla-zpp-blas/linear-algebra


text:
/*
 Boost Logging library

 Author: John Torjo, www.torjo.com

 Copyright (C) 2007 John Torjo (see www.torjo.com for email)

 Distributed under the Boost Software License, Version 1.0.
    (See accompanying file LICENSE_1_0.txt or copy at
          http://www.boost.org/LICENSE_1_0.txt)

 See http://www.boost.org for updates, documentation, and revision history.
 See http://www.torjo.com/log2/ for more details
*/

/**
@example custom_fmt_dest.cpp

@copydoc custom_fmt_dest

@page custom_fmt_dest custom_fmt_dest.cpp Example

This example shows you how easy it is to add your custom formatter /destination classes.

This usage:
- you have one logger
- you have one filter, which can be turned on or off
- you want to format the message before it's written
- the logger has several log destinations
    - the output goes to console, debug output window, and a file called out.txt - as XML
    - formatting - prefix each message by its start time, its index, and append newline

\n\n
Custom classes:
- secs_since_start - custom formatter
- as_xml - custom destination

\n\n
Optimizations:
- use a cache string (from boost::logging::optimize namespace), in order to make formatting the message faster

\n\n
The output will look similar to this one:

The console and the debug window will be the same:
@code
+6s [1] this is so cool 1
+6s [2] this is so cool again 2
+7s [3] hello, world
+7s [4] good to be back ;) 3
@endcode

The out.txt file will look like this:

@code
<msg>+6s [1] this is so cool 1
</msg>
<msg>+6s [2] this is so cool again 2
</msg>
<msg>+7s [3] hello, world
</msg>
<msg>+7s [4] good to be back ;) 3
</msg>
@endcode

*/

#include <boost/logging/format_fwd.hpp>

BOOST_LOG_FORMAT_MSG( optimize::cache_string_one_str<> )

#include <boost/logging/format.hpp>
using namespace boost::logging;

typedef logger_format_write< default_, default_, writer::threading::no_ts > logger_type;

BOOST_DECLARE_LOG_FILTER(g_log_filter, filter::no_ts )
BOOST_DECLARE_LOG(g_l, logger_type)

#define L_ BOOST_LOG_USE_LOG_IF_FILTER(g_l(), g_log_filter()->is_enabled() )

BOOST_DEFINE_LOG(g_l, logger_type)
BOOST_DEFINE_LOG_FILTER(g_log_filter, filter::no_ts )

// Example of custom formatter:
// dump the no. of seconds since start of program
struct secs_since_start : formatter::class_<secs_since_start, formatter::implement_op_equal::no_context> {
    ::time_t m_start;
    secs_since_start() : m_start( ::time(0) ) {}
    void operator()(param str) const {
        ::time_t now = ::time(0);
        std::stringstream out;
        out << "+" << (int)(now-m_start) << "s ";
        str.prepend_string( out.str() );
    }
};

// Example of custom destination:
// Dump each message as XML
struct as_xml :
        destination::class_<as_xml, destination::implement_op_equal::has_context>,
        destination::non_const_context<std::ofstream> {

    std::string m_name;
    as_xml(const char* name) : non_const_context_base(name), m_name(name) {}
    void operator()(param str) const {
        context() << "<msg>" << str << "</msg>" << std::endl;
    }

    bool operator==(const as_xml& other) const { return m_name == other.m_name; }
};

void custom_fmt_dest_example() {
    //         add formatters and destinations
    //         That is, how the message is to be formatted and where should it be written to
    g_l()->writer().add_formatter( formatter::idx(), "[%] " );
    g_l()->writer().add_formatter( formatter::append_newline() );
    g_l()->writer().add_formatter( secs_since_start() );

    g_l()->writer().add_destination( destination::cout() );
    g_l()->writer().add_destination( destination::dbg_window() );
    g_l()->writer().add_destination( as_xml("out.txt") );
    g_l()->mark_as_initialized();

    int i = 1;
    L_ << "this is so cool " << i++;
    L_ << "this is so cool again " << i++;

    std::string hello = "hello", world = "world";
    L_ << hello << ", " << world;

    g_log_filter()->set_enabled(false);
    L_ << "this will not be written to the log";
    L_ << "this won't be written to the log";

    g_log_filter()->set_enabled(true);
    L_ << "good to be back ;) " << i++;
}

int main() {
    custom_fmt_dest_example();
}

// End of file

max_stars_repo_name: saga-project/saga-cpp

max_issues_repo_name: saga-project/saga-cpp

max_forks_repo_name: saga-project/saga-cpp


text:
//
// multiple_exceptions.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2020 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP
#define BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP

#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)

#include <boost/asio/detail/config.hpp>
#include <exception>
#include <boost/asio/detail/push_options.hpp>

namespace boost {
namespace asio {

#if defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR) \
  || defined(GENERATING_DOCUMENTATION)

/// Exception thrown when there are multiple pending exceptions to rethrow.
class multiple_exceptions
  : public std::exception
{
public:
  /// Constructor.
  BOOST_ASIO_DECL multiple_exceptions(
      std::exception_ptr first) BOOST_ASIO_NOEXCEPT;

  /// Obtain message associated with exception.
  BOOST_ASIO_DECL virtual const char* what() const
    BOOST_ASIO_NOEXCEPT_OR_NOTHROW;

  /// Obtain a pointer to the first exception.
  BOOST_ASIO_DECL std::exception_ptr first_exception() const;

private:
  std::exception_ptr first_;
};

#endif // defined(BOOST_ASIO_HAS_STD_EXCEPTION_PTR)
       //   || defined(GENERATING_DOCUMENTATION)

} // namespace asio
} // namespace boost

#include <boost/asio/detail/pop_options.hpp>

#if defined(BOOST_ASIO_HEADER_ONLY)
# include <boost/asio/impl/multiple_exceptions.ipp>
#endif // defined(BOOST_ASIO_HEADER_ONLY)

#endif // BOOST_ASIO_MULTIPLE_EXCEPTIONS_HPP

ext: hpp

max_stars_repo_name: kindlychung/mediasoup-sfu-cpp

max_issues_repo_name: kindlychung/mediasoup-sfu-cpp

max_forks_repo_name: kindlychung/mediasoup-sfu-cpp


text:
//
// Variable - Permutation integration tests
//
#include <boost/test/unit_test.hpp>

#include "Permutation.hpp"
#include "Variable.hpp"

using namespace mist;

BOOST_AUTO_TEST_CASE(Permute_Variable_direct)
{
  auto* data_0{ new Variable::data_t[3]{ 1, 2, 3 } };
  ;
  auto* data_1{ new Variable::data_t[3]{ 1, 3, 2 } };
  auto* data_2{ new Variable::data_t[3]{ 2, 1, 3 } };
  Variable::data_ptr p_0(data_0);
  Variable::data_ptr p_1(data_1);
  Variable::data_ptr p_2(data_2);

  Variable v0(p_0, 3, 0, 3);
  Variable v1(p_1, 3, 0, 3);
  Variable v2(p_2, 3, 0, 3);

  Variable v = v0.deepCopy();

  BOOST_ASSERT(v == v0);
  BOOST_TEST(permutation::next(v));
  BOOST_ASSERT(v == v1);
  BOOST_TEST(permutation::next(v));
  BOOST_ASSERT(v == v2);
}

BOOST_AUTO_TEST_CASE(Permute_Variable_copy)
{
  Permutation<int> perm = { 2, 1, 0 };
  auto* data_3{ new Variable::data_t[3]{ 1, 2, 3 } };
  ;
  auto* data_3_exp{ new Variable::data_t[3]{ 3, 2, 1 } };

  Variable::data_ptr p3(data_3);
  Variable::data_ptr p3_exp(data_3_exp);
  Variable original(p3, 3, 0, 3);
  Variable expected(p3_exp, 3, 0, 3);
  Variable permuted = original.deepCopy();

  perm.apply(original, permuted);
  BOOST_ASSERT(permuted == expected);
}

max_stars_repo_name: andbanman/mist

max_issues_repo_name: andbanman/mist

max_forks_repo_name: andbanman/mist


text:
#include <stan/math/rev.hpp>
#include <boost/mp11.hpp>
#include <gtest/gtest.h>
#include <test/unit/math/rev/functor/test_fixture_ode.hpp>
#include <test/unit/math/rev/functor/test_fixture_ode_lorenz.hpp>
#include <stan/math/torsten/test/unit/dsolve/ode_test_functors.hpp>

/**
 *
 * Use same solver functor type for both w & w/o tolerance control
 */
template <typename solve_type, typename... Ts>
using ode_test_tuple = std::tuple<solve_type, solve_type, Ts...>;

/**
 * Outer product of test types
 */
using lorenz_test_types = boost::mp11::mp_product<
    ode_test_tuple,
    ::testing::Types<pmx_ode_adams_functor, pmx_ode_bdf_functor, pmx_ode_ckrk_functor,
                     pmx_ode_rk45_functor>>;

TYPED_TEST_SUITE_P(lorenz_test);
TYPED_TEST_P(lorenz_test, param_and_data_finite_diff) {
  if (std::is_same<TypeParam,
                   std::tuple<pmx_ode_rk45_functor, pmx_ode_rk45_functor>>::value) {
    this->test_fd_vd(1.e-6, 3e-2);
    this->test_fd_dv(1.e-6, 3e-2);
    this->test_fd_vv(1.e-6, 3e-2);
  } else if (std::is_same<TypeParam, std::tuple<pmx_ode_ckrk_functor,
                                                pmx_ode_ckrk_functor>>::value) {
    this->test_fd_vd(1.e-6, 5e-2);
    this->test_fd_dv(1.e-6, 5e-2);
    this->test_fd_vv(1.e-6, 5e-2);
  } else {
    this->test_fd_vd(1.e-6, 1e-2);
    this->test_fd_dv(1.e-6, 1e-2);
    this->test_fd_vv(1.e-6, 1e-2);
  }
}
REGISTER_TYPED_TEST_SUITE_P(lorenz_test, param_and_data_finite_diff);
INSTANTIATE_TYPED_TEST_SUITE_P(StanOde, lorenz_test, lorenz_test_types);


text:
#ifndef OPENGM_PYTHON_INTERFACE
#define OPENGM_PYTHON_INTERFACE 1
#endif

#include <stdexcept>
#include <stddef.h>
#include <string>
#include <boost/python.hpp>
#include <opengm/graphicalmodel/graphicalmodel.hxx>
#include <opengm/utilities/tribool.hxx>
#include <opengm/inference/inference.hxx>
#include <opengm/inference/icm.hxx>
#include "nifty_iterator.hxx"
#include"../export_typedes.hxx"
using namespace boost::python;

void export_enum(){

enum_<pyenums::AStarHeuristic > ("Heuristic")
   .value("fast", pyenums::FAST_HEURISTIC)
   .value("standard", pyenums::STANDARD_HEURISTIC)
   .value("default", pyenums::DEFAULT_HEURISTIC)
   ;
enum_<pyenums::IcmMoveType > ("MoveType")
   .value("variable", pyenums::SINGLE_VARIABLE)
   .value("factor", pyenums::FACTOR)
   ;
enum_<pyenums::GibbsVariableProposal > ("VariableProposal")
   .value("random", pyenums::RANDOM)
   .value("cyclic", pyenums::CYCLIC)
   ;
enum_<opengm::Tribool::State> ("Tribool")
   .value("true", opengm::Tribool::True)
   .value("false", opengm::Tribool::False)
   .value("maybe", opengm::Tribool::Maybe)
   ;

#ifdef WITH_LIBDAI
enum_<pyenums::libdai::UpdateRule> ("UpdateRule")
   .value("parall", pyenums::libdai::PARALL)
   .value("seqfix", pyenums::libdai::SEQFIX)
   .value("seqrnd", pyenums::libdai::SEQRND)
   .value("seqmax", pyenums::libdai::SEQMAX)
   ;
#endif
}

ext: cxx

max_stars_repo_name: amueller/opengm

max_issues_repo_name: amueller/opengm

max_forks_repo_name: amueller/opengm


text:
/*=============================================================================
    Copyright (c) 2001-2007 Joel de Guzman

    Distributed under the Boost Software License, Version 1.0. (See accompanying
    file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
==============================================================================*/
#ifndef PHOENIX_OPERATOR_DETAIL_IO_HPP
#define PHOENIX_OPERATOR_DETAIL_IO_HPP

#include <boost/spirit/home/phoenix/operator/bitwise.hpp>
#include <boost/spirit/home/phoenix/core/reference.hpp>
#include <boost/utility/addressof.hpp>
#include <boost/utility/enable_if.hpp>
#include <iostream>

namespace boost { namespace phoenix { namespace detail
{
    typedef char(&no)[1];
    typedef char(&yes)[2];

    template <typename CharType, typename CharTrait>
    yes ostream_test(std::basic_ostream<CharType, CharTrait>*);
    no ostream_test(...);

    template <typename CharType, typename CharTrait>
    yes istream_test(std::basic_istream<CharType, CharTrait>*);
    no istream_test(...);

    template <typename T>
    struct is_ostream
    {
        static T x;
        BOOST_STATIC_CONSTANT(bool,
            value = sizeof(detail::ostream_test(addressof(x))) == sizeof(yes));
    };

    template <typename T>
    struct is_istream
    {
        static T x;
        BOOST_STATIC_CONSTANT(bool,
            value = sizeof(detail::istream_test(addressof(x))) == sizeof(yes));
    };

    template <typename T0, typename T1>
    struct enable_if_ostream :
        enable_if<
            detail::is_ostream<T0>
          , actor<
                typename as_composite<
                    shift_left_eval
                  , actor<reference<T0> >
                  , actor<T1>
                >::type
            >
        >
    {};

    template <typename T0, typename T1>
    struct enable_if_istream :
        enable_if<
            detail::is_istream<T0>
          , actor<
                typename as_composite<
                    shift_right_eval
                  , actor<reference<T0> >
                  , actor<T1>
                >::type
            >
        >
    {};

    typedef std::ios_base&  (*iomanip_type)(std::ios_base&);
    typedef std::istream&   (*imanip_type)(std::istream&);
    typedef std::ostream&   (*omanip_type)(std::ostream&);
}}}

#endif

max_stars_repo_name: jaredhoberock/gotham

max_issues_repo_name: jaredhoberock/gotham

max_forks_repo_name: jaredhoberock/gotham


text:
#include <boost/test/unit_test.hpp>

#include <fstream>
#include <streambuf>
#include <string>

// xerces
#include <xercesc/sax2/SAX2XMLReader.hpp>
#include <xercesc/sax2/XMLReaderFactory.hpp>
#include <xercesc/sax2/DefaultHandler.hpp>
#include <xercesc/util/XMLString.hpp>

// wiki xml dump lib
#include "../helpers/buildArtificialDump.h"
#include "../../../core/wikiDataCache.h"
#include "../../../core/graph.h"
#include "../../helpers/sortTitlesHelper.h"
#include "../../wikiArticleHandlers/articleDatesAndCategoriesHandler.h"
#include "../../wikiArticleHandlers/allLinksArticleHandler.h"
#include "../../../../libs/wiki_xml_dump_xerces/src/parsers/singleCoreParser.hpp"
#include "../../../../libs/wiki_xml_dump_xerces/src/handlers/wikiDumpHandlerProperties.hpp"
#include "../../../../libs/wiki_xml_dump_xerces/src/handlers/basicTitleFilters.hpp"

BOOST_AUTO_TEST_SUITE(article_network_tests)

BOOST_AUTO_TEST_CASE(there_should_be_links_between_the_articles)
{
	std::string path("../../src/parsers/tests/articlesAndCategories/data/1789_events_french_revolution.xml");

	WikiXmlDumpXerces::WikiDumpHandlerProperties parser_properties;
	parser_properties.TitleFilter = WikiXmlDumpXerces::only_articles_and_categories();

	// init xerces
	xercesc::XMLPlatformUtils::Initialize();

	// run parsing
	auto article_titles_stream = std::make_shared<std::stringstream>();
	auto article_dates_stream = std::make_shared<std::stringstream>();
	auto category_titles_stream = std::make_shared<std::stringstream>();
	auto redirects_stream = std::make_shared<std::stringstream>();
	std::mutex article_titles_mutex;
	std::mutex category_titles_mutex;
	std::mutex redirect_mutex;
	ArticleDatesAndCategoriesHandler art_handler(*article_titles_stream, *article_dates_stream, *category_titles_stream, *redirects_stream, article_titles_mutex, category_titles_mutex, redirect_mutex);
	art_handler.ExtractOnlyArticlesWithDates = false;
	WikiXmlDumpXerces::SingleCoreParser parser(art_handler, parser_properties);
	parser.Run(path);

	article_titles_stream->seekg(0);
	article_dates_stream->seekg(0);
	category_titles_stream->seekg(0);
	redirects_stream->seekg(0);

	// terminate xerces

	auto article_titles_sorted_stream = std::make_shared<std::stringstream>();
	auto article_dates_sorted_stream = std::make_shared<std::stringstream>();
	auto category_titles_sorted_stream = std::make_shared<std::stringstream>();
	sort_article_files(*article_titles_stream, *article_dates_stream, *article_titles_sorted_stream, *article_dates_sorted_stream);
	sort_category_files(*category_titles_stream, *category_titles_sorted_stream);

	WikiMainPath::WikiDataCache wiki_data_cache(article_titles_sorted_stream, article_dates_sorted_stream, category_titles_stream, redirects_stream);
	auto& article_titles = wiki_data_cache.article_titles();
	auto& category_titles = wiki_data_cache.category_titles();
	auto& redirects = wiki_data_cache.redirects();
	std::vector<boost::container::flat_set<std::size_t>> category_has_article(category_titles.size());
	CategoryHirachyGraph category_hirachy_graph(category_titles.size());
	std::vector<boost::container::flat_set<std::size_t>> article_adjacency_list(article_titles.size());
	VectorMutex<1000> vector_mutex;

	AllLinksArticleHander all_links_handler(article_titles, category_titles, redirects, category_has_article, category_hirachy_graph, article_adjacency_list, vector_mutex);
	WikiXmlDumpXerces::SingleCoreParser parser2(all_links_handler, parser_properties);
	parser2.Run(path);

	xercesc::XMLPlatformUtils::Terminate();

	// in this test the direction of the edge is determined by the lexicographic sort
	std::vector<std::pair<std::string,std::string>> expected_links = {
		{ "National Assembly (French Revolution)", "Storming of the Bastille" },
		{ "Women's March on Versailles", "National Constituent Assembly" },
		{ "August Decrees", "National Constituent Assembly" }
	};

	for (auto link : expected_links) {
		auto it_1 = std::find(article_titles.begin(), article_titles.end(), link.first);
		auto it_2 = std::find(article_titles.begin(), article_titles.end(), link.second);

		bool found_article1 = it_1 != article_titles.end();
		bool found_article2 = it_2 != article_titles.end();

		BOOST_CHECK(found_article1);
		BOOST_CHECK(found_article2);

		if(found_article1 && found_article2)
		{
			bool found_link = article_adjacency_list[it_1 - article_titles.begin()].find(it_2 - article_titles.begin()) != article_adjacency_list[it_1 - article_titles.begin()].end();
			if(!found_link)
				std::cout << link.first << " - " << link.second << std::endl;
			BOOST_CHECK(found_link);
		}

	}
}

BOOST_AUTO_TEST_CASE(there_should_be_links_between_the_articles_articial)
{
	std::vector<std::string> titles = { "A", "B", "C", "D", "E" };
	std::vector<std::pair<std::string,std::string>> expected_links = {
		{ "A", "C" },
		{ "A", "D" },
		{ "C", "D" },
		{ "D", "E" },
		{ "D", "A" },
		{ "D", "C" },
		{ "E", "A" },
	};
	std::string content = build_artificial_dump(titles, expected_links);

	WikiXmlDumpXerces::WikiDumpHandlerProperties parser_properties;
	parser_properties.TitleFilter = WikiXmlDumpXerces::only_articles_and_categories();

	// init xerces
	xercesc::XMLPlatformUtils::Initialize();

	// run parsing
	auto article_titles_stream = std::make_shared<std::stringstream>();
	auto article_dates_stream = std::make_shared<std::stringstream>();
	auto category_titles_stream = std::make_shared<std::stringstream>();
	auto redirects_stream = std::make_shared<std::stringstream>();
	std::mutex article_titles_mutex;
	std::mutex category_titles_mutex;
	std::mutex redirect_mutex;
	ArticleDatesAndCategoriesHandler art_handler(*article_titles_stream, *article_dates_stream, *category_titles_stream, *redirects_stream, article_titles_mutex, category_titles_mutex, redirect_mutex);
	art_handler.ExtractOnlyArticlesWithDates = false;
	WikiXmlDumpXerces::SingleCoreParser parser(art_handler, parser_properties);
	parser.RunOnString(content);

	article_titles_stream->seekg(0);
	article_dates_stream->seekg(0);
	category_titles_stream->seekg(0);
	redirects_stream->seekg(0);

	// terminate xerces

	auto article_titles_sorted_stream = std::make_shared<std::stringstream>();
	auto article_dates_sorted_stream = std::make_shared<std::stringstream>();
	auto category_titles_sorted_stream = std::make_shared<std::stringstream>();
	sort_article_files(*article_titles_stream, *article_dates_stream, *article_titles_sorted_stream, *article_dates_sorted_stream);
	sort_category_files(*category_titles_stream, *category_titles_sorted_stream);

	article_titles_sorted_stream->seekg(0);
	category_titles_sorted_stream->seekg(0);

	WikiMainPath::WikiDataCache wiki_data_cache(article_titles_sorted_stream, article_dates_sorted_stream, category_titles_sorted_stream, redirects_stream);
	auto& article_titles = wiki_data_cache.article_titles();
	auto& category_titles = wiki_data_cache.category_titles();
	auto& redirects = wiki_data_cache.redirects();
	std::vector<boost::container::flat_set<std::size_t>> category_has_article(category_titles.size());
	CategoryHirachyGraph category_hirachy_graph(category_titles.size());
	std::vector<boost::container::flat_set<std::size_t>> article_adjacency_list(article_titles.size());
	VectorMutex<1000> vector_mutex;

	AllLinksArticleHander all_links_handler(article_titles, category_titles, redirects, category_has_article, category_hirachy_graph, article_adjacency_list, vector_mutex);
	WikiXmlDumpXerces::SingleCoreParser parser2(all_links_handler, parser_properties);
	parser2.RunOnString(content);

	xercesc::XMLPlatformUtils::Terminate();

	for (auto link : expected_links) {
		auto it_1 = std::find(article_titles.begin(), article_titles.end(), link.first);
		auto it_2 = std::find(article_titles.begin(), article_titles.end(), link.second);

		bool found_article1 = it_1 != article_titles.end();
		bool found_article2 = it_2 != article_titles.end();

		BOOST_CHECK(found_article1);
		BOOST_CHECK(found_article2);

		if(found_article1 && found_article2)
		{
			bool found_link = article_adjacency_list[it_1 - article_titles.begin()].find(it_2 - article_titles.begin()) != article_adjacency_list[it_1 - article_titles.begin()].end();
			if(!found_link)
				std::cout << link.first << " - " << link.second << std::endl;
			BOOST_CHECK(found_link);
		}

	}
}

BOOST_AUTO_TEST_SUITE_END()

max_stars_repo_name: bencabrera/wikiMainPath

max_issues_repo_name: bencabrera/wikiMainPath

max_forks_repo_name: bencabrera/wikiMainPath


text:
#pragma once
#include <trajopt_utils/macros.h>
TRAJOPT_IGNORE_WARNINGS_PUSH
#include <Eigen/Core>
#include <qpOASES.hpp>
TRAJOPT_IGNORE_WARNINGS_POP

#include <trajopt_sco/solver_interface.hpp>
#include <trajopt_utils/macros.h>

namespace sco
{
/**
 * qpOASESModel uses the LGPL solver qpOASES to solve a linearly constrained QP.
 * qpOASES solves a problem in the form:
 * ```
 * min   1/2*x'Hx + x'g
 * s.t.  lb  <=  x <= ub
 * lbA <= Ax <= ubA
 * ```
 *
 * More informations about the solver are available at:
 * https://projects.coin-or.org/qpOASES
 */
class qpOASESModel : public Model
{
  /** pointer to a qpOASES Sequential Quadratic Problem*/
  std::shared_ptr<qpOASES::SQProblem> qpoases_problem_;
  qpOASES::Options qpoases_options_; /**< qpOASES solver options */

  qpOASES::SymSparseMat H_; /**< Quadratic cost matrix */
  qpOASES::SparseMatrix A_; /**< Constraints matrix */

  /** Updates qpOASES Hessian matrix from QuadExpr expression.
   *  Transforms QuadExpr objective_ into the qpOASES sparse matrix H_*/
  void updateObjective();

  /** Updates qpOASES constraints from AffExpr expression.
   *  Transforms AffExpr cntr_exprs_ into the qpOASES sparse matrix A_, and
   *  vectors lbA_ and ubA_ */
  void updateConstraints();

  /**
   * Instantiates a new qpOASES problem if it has not been instantiated yet
   * or if the size of the problem has changed.
   *
   * @returns true if a new qpOASES problem has been instantiated
   */
  bool updateSolver();

  /**
   * Instantiates a new qpOASES problem
   */
  void createSolver();

  VarVector vars_;                 /**< model variables */
  CntVector cnts_;                 /**< model's constraints sizes */
  DblVec lb_, ub_;                 /**< variables bounds */
  AffExprVector cnt_exprs_;        /**< constraints expressions */
  ConstraintTypeVector cnt_types_; /**< constraints types */
  DblVec solution_;                /**< optimizizer's solution for current model */

  IntVec H_row_indices_;     /**< row indices for Hessian, CSC format */
  IntVec H_column_pointers_; /**< column pointers for Hessian, CSC format */
  DblVec H_csc_data_;        /**< Hessian values in CSC format */
  Eigen::VectorXd g_;        /**< gradient of the optimization problem */

  IntVec A_row_indices_;     /**< row indices for constraint matrix, CSC format */
  IntVec A_column_pointers_; /**< column pointers for constraint matrix, CSC format */
  DblVec A_csc_data_;        /**< constraint matrix values in CSC format */
  DblVec lbA_, ubA_;         /**< linear constraints upper and lower limits */

  QuadExpr objective_; /**< objective QuadExpr expression */

public:
  qpOASESModel();
  virtual ~qpOASESModel();

  Var addVar(const std::string& name) override;
  Cnt addEqCnt(const AffExpr&, const std::string& name) override;
  Cnt addIneqCnt(const AffExpr&, const std::string& name) override;
  Cnt addIneqCnt(const QuadExpr&, const std::string& name) override;
  void removeVars(const VarVector& vars) override;
  void removeCnts(const CntVector& cnts) override;

  void update() override;
  void setVarBounds(const VarVector& vars, const DblVec& lower, const DblVec& upper) override;
  DblVec getVarValues(const VarVector& vars) const override;
  virtual CvxOptStatus optimize() override;
  virtual void setObjective(const AffExpr&) override;
  virtual void setObjective(const QuadExpr&) override;
  virtual void writeToFile(const std::string& fname) override;
  virtual VarVector getVars() const override;
};
}

max_stars_repo_name: adam-vonderviszt/moveit

max_issues_repo_name: adam-vonderviszt/moveit

max_forks_repo_name: adam-vonderviszt/moveit


text:
/* renderer.hpp - abstract renderer class. */

// Copyright (c) NVIDIA Corporation. All rights reserved.

#ifndef __renderer_hpp__
#define __renderer_hpp__

#if defined(_MSC_VER) && (_MSC_VER >= 1020)
# pragma once
#endif

#include <vector>

#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/weak_ptr.hpp>

#if __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/freeglut.h>
#endif

#include <Cg/vector.hpp>
#include <Cg/matrix.hpp>

using std::vector;
using namespace boost;

// Path scene graph classes to which a Renderer implementation can attach a RenderState
struct Shape;
typedef shared_ptr<struct Shape> ShapePtr;
struct Group;
typedef shared_ptr<Group> GroupPtr;
struct Paint;
typedef shared_ptr<struct Paint> PaintPtr;
struct Path;
typedef shared_ptr<struct Path> PathPtr;
struct Text;
typedef shared_ptr<struct Text> TextPtr;

// Forward declaration
template <typename T> struct RendererState;

// Abstract base class for a path renderer with support for allocating
// Renderer-specific path and shape renderer states.
struct Renderer : enable_shared_from_this<Renderer> {
    virtual const char *getWindowTitle() = 0;
    virtual const char *getName() = 0;
    virtual void reportFPS() = 0;
    virtual void swapBuffers() = 0;
    virtual shared_ptr<RendererState<Path> > alloc(Path *owner) = 0;
    virtual shared_ptr<RendererState<Shape> > alloc(Shape *owner) = 0;
    virtual shared_ptr<RendererState<Paint> > alloc(Paint *owner) = 0;
    virtual ~Renderer() { };
};
typedef shared_ptr<struct Renderer> RendererPtr;
typedef weak_ptr<struct Renderer> WeakRendererPtr;

typedef shared_ptr<struct BlitRenderer> BlitRendererPtr;
typedef shared_ptr<class Visitor> VisitorPtr;
struct BlitRenderer : Renderer {
    virtual void configureSurface(int width, int height) = 0;
    virtual void beginDraw() { }
    virtual void clear(Cg::float3 clear_color) = 0;
    virtual void setView(Cg::float4x4 view) = 0;
    virtual VisitorPtr makeVisitor() = 0;
    virtual void endDraw() { }
    //virtual void draw(GroupPtr scene, RendererPtr renderer) = 0;
    virtual void copyImageToWindow() = 0;
    virtual void shutdown() = 0;
};

struct GLBlitRenderer : BlitRenderer {
    void reportFPS();
    void swapBuffers();
};

// A RendererState is associated with a Towner object in the path scene graph.
//
// The SpecificRendererState class derives from this abstract base class.
// Implementations of renderer states for a specific Renderer should
// derive from SpecificRendererState (not RendererState itself).
//
// Users of a RendererState (typically the path scene graph) are expected to
// have no knowledge of what renderer actually implements this base class.
template <typename Towner>
struct RendererState {
    typedef Towner *OwnerPtr;  // intentionally not a SharedPtr

    // I know who my owner instance is.
    OwnerPtr owner;
    // I (weakly) know what Renderer implementation instance I am for.
    WeakRendererPtr renderer;

    RendererState(RendererPtr renderer_, OwnerPtr owner_)
        : owner(owner_)
        , renderer(renderer_)
    {}
    virtual ~RendererState() {}

    // Am I a RendererState that belongs to the specified Renderer?
    bool sameRenderer(const RendererPtr renderer_) {
        RendererPtr locked_renderer = renderer.lock();

        if (locked_renderer) {
            return locked_renderer == renderer_;
        } else {
            return false;
        }
    }
    // The scene graph can invalidate my state at anytime.
    virtual void invalidate() = 0;
};

// The SpecificRendererState base class allows all specific
// renderer state implementations to access their appropriately
// specialized RendererPtr (CairoRendererPtr, etc.)
template <typename Towner, typename Trenderer>
struct SpecificRendererState : RendererState<Towner> {
    typedef Towner *OwnerPtr;  // intentionally not a SharedPtr
    SpecificRendererState(RendererPtr renderer_, OwnerPtr owner_)
        : RendererState<Towner>(renderer_, owner_)
    {}
    ~SpecificRendererState() {}

    // Returns a (strong) pointer to my specific Renderer.
    shared_ptr<Trenderer> getRenderer() {
        RendererPtr locked_renderer = RendererState<Towner>::renderer.lock();
        assert(locked_renderer);
        shared_ptr<Trenderer> specific_renderer = dynamic_pointer_cast<Trenderer>(locked_renderer);
        assert(specific_renderer);
        return specific_renderer;
    }
};

// Objects that want to have per-renderer state should derive from this class.
//
// This class provides a generic vector of RendererState instances for
// various Renderer implementations.
template <typename T>
struct HasRendererState {
    typedef shared_ptr<T> OwnerType;
    typedef RendererState<T> RenderStateType;
    typedef shared_ptr<RenderStateType> RendererStatePtr;

    // The "this" pointer for my owner.
    T *owner;
    // The vector of RendererState instances, the details of which I am ignorant about.
    vector<RendererStatePtr> renderer_states;

    HasRendererState(T *owner_)
        : owner(owner_)  // I expect owner_ to be my owener's "this" pointer.
    { }

    // Given a shape in the path scene graph, return the specific
    // renderer state for this renderer implementation instance.
    RendererStatePtr getRendererState(RendererPtr renderer) {
        typename vector<RendererStatePtr>::iterator iter;

        for (iter = renderer_states.begin(); iter != renderer_states.end(); iter++) {
            RendererStatePtr renderer_state = *iter;

            if (renderer_state && renderer_state->sameRenderer(renderer) ) {
                return renderer_state;
            }
        }
        RendererStatePtr renderer_state = renderer->alloc(owner);
        renderer_states.push_back(renderer_state);
        return renderer_state;
    }
    // Force all renderers to revalidate their renderer states.
    //
    // Invalidation doesn't necessarily free any memory associated with
    // the renderer state implementations.
    void invalidateRenderStates() {
        typename vector<RendererStatePtr>::iterator iter;

        for (iter = renderer_states.begin(); iter != renderer_states.end(); iter++) {
            RendererStatePtr renderer_state = *iter;

            if (renderer_state) {
                renderer_state->invalidate();
            }
        }
    }

    // Force a particular renderer to revalidate its renderer state.
    void invalidateRenderState(RendererPtr renderer) {
        typename vector<RendererStatePtr>::iterator iter;

        for (iter = renderer_states.begin(); iter != renderer_states.end(); iter++) {
            RendererStatePtr renderer_state = *iter;

            if (renderer_state && renderer_state->sameRenderer(renderer) ) {
                renderer_state->invalidate();
                return;
            }
        }
    }

    // More expensive than simply invalidating the associated renderer
    // states of this object because the renderer states themselves
    // are forgotten.
    void flushRenderStates() {
        // assign empty vector; side-effect will destruct all RendererState in old vector.
        renderer_states = vector<RendererStatePtr>();
    }

    void flushRenderState(RendererPtr renderer) {
        typename vector<RendererStatePtr>::iterator iter;

        for (iter = renderer_states.begin(); iter != renderer_states.end(); iter++) {
            if (*iter && (*iter)->sameRenderer(renderer) ) {
                *iter = RendererStatePtr();
                return;
            }
        }
    }
};

#endif // __renderer_hpp__

max_stars_repo_name: dolphin-li/ClothDesigner

max_issues_repo_name: dolphin-li/ClothDesigner

max_forks_repo_name: dolphin-li/ClothDesigner