<commit_before>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2017 Intel Corporation. All Rights Reserved.

#ifndef LIBREALSENSE_RS2_EXPORT_HPP
#define LIBREALSENSE_RS2_EXPORT_HPP

#include <map>
#include <fstream>
#include <cmath>
#include <sstream>
#include <cassert>
#include "rs_processing.hpp"
#include "rs_internal.hpp"

namespace rs2
{
    class save_to_ply : public filter
    {
    public:
        save_to_ply(std::string filename = "RealSense Pointcloud ", pointcloud pc = pointcloud())
            : filter([this](frame f, frame_source& s) { func(f, s); }),
            _pc(std::move(pc)), fname(filename)
        {
            register_simple_option(OPTION_IGNORE_COLOR, option_range{ 0, 1, 0, 1 });
        }

        DECLARE_PB_OPTION(OPTION_IGNORE_COLOR, 1);
    private:
        void func(frame data, frame_source& source)
        {
            frame depth, color;
            if (auto fs = data.as<frameset>()) {
                for (auto f : fs) {
                    if (f.is<points>()) depth = f;
                    else if (!depth && f.is<depth_frame>()) depth = f;
                    else if (!color && f.is<video_frame>()) color = f;
                }
            } else if (data.is<depth_frame>() || data.is<points>()) {
                depth = data;
            }

            if (!depth) throw std::runtime_error("Need depth data to save PLY");
            if (!depth.is<points>()) {
                if (color) _pc.map_to(color);
                depth = _pc.calculate(depth);
            }

            export_to_ply(depth, color);
            source.frame_ready(data); // passthrough filter because processing_block::process doesn't support sinks
        }

        void export_to_ply(points p, video_frame color) {
            const bool use_texcoords = color && get_option(OPTION_IGNORE_COLOR);
            const auto verts = p.get_vertices();
            const auto texcoords = p.get_texture_coordinates();
            std::vector<rs2::vertex> new_verts;
            std::vector<std::array<uint8_t, 3>> new_tex;
            std::map<int, int> idx_map;

            new_verts.reserve(p.size());
            if (use_texcoords) new_tex.reserve(p.size());

            static const auto min_distance = 1e-6;

            for (size_t i = 0; i < p.size(); ++i) {
                if (fabs(verts[i].x) >= min_distance || fabs(verts[i].y) >= min_distance ||
                    fabs(verts[i].z) >= min_distance)
                {
                    idx_map[i] = new_verts.size();
                    new_verts.push_back(verts[i]);
                    if (use_texcoords)
                    {
                        auto rgb = get_texcolor(color, texcoords[i].u, texcoords[i].v);
                        new_tex.push_back(rgb);
                    }
                }
            }

            auto profile = p.get_profile().as<video_stream_profile>();
            auto width = profile.width(), height = profile.height();
            static const auto threshold = 0.05f;
            std::vector<std::array<int, 3>> faces;
            for (int x = 0; x < width - 1; ++x) {
                for (int y = 0; y < height - 1; ++y) {
                    auto a = y * width + x, b = y * width + x + 1, c = (y + 1)*width + x, d = (y + 1)*width + x + 1;
                    if (verts[a].z && verts[b].z && verts[c].z && verts[d].z
                        && fabs(verts[a].z - verts[b].z) < threshold && fabs(verts[a].z - verts[c].z) < threshold
                        && fabs(verts[b].z - verts[d].z) < threshold && fabs(verts[c].z - verts[d].z) < threshold)
                    {
                        if (idx_map.count(a) == 0 || idx_map.count(b) == 0 || idx_map.count(c) == 0 ||
                            idx_map.count(d) == 0)
                            continue;
                        faces.push_back({ idx_map[a], idx_map[b], idx_map[d] });
                        faces.push_back({ idx_map[d], idx_map[c], idx_map[a] });
                    }
                }
            }

            std::stringstream name;
            name << fname << p.get_frame_number() << ".ply";
            std::ofstream out(name.str());
            out << "ply\n";
            out << "format binary_little_endian 1.0\n";
            out << "comment pointcloud saved from Realsense Viewer\n";
            out << "element vertex " << new_verts.size() << "\n";
            out << "property float" << sizeof(float) * 8 << " x\n";
            out << "property float" << sizeof(float) * 8 << " y\n";
            out << "property float" << sizeof(float) * 8 << " z\n";
            if (use_texcoords)
            {
                out << "property uchar red\n";
                out << "property uchar green\n";
                out << "property uchar blue\n";
            }
            out << "element face " << faces.size() << "\n";
            out << "property list uchar int vertex_indices\n";
            out << "end_header\n";
            out.close();

            out.open(name.str(), std::ios_base::app | std::ios_base::binary);
            for (int i = 0; i < new_verts.size(); ++i)
            {
                // we assume little endian architecture on your device
                out.write(reinterpret_cast<const char*>(&(new_verts[i].x)), sizeof(float));
                out.write(reinterpret_cast<const char*>(&(new_verts[i].y)), sizeof(float));
                out.write(reinterpret_cast<const char*>(&(new_verts[i].z)), sizeof(float));

                if (use_texcoords)
                {
                    out.write(reinterpret_cast<const char*>(&(new_tex[i][0])), sizeof(uint8_t));
                    out.write(reinterpret_cast<const char*>(&(new_tex[i][1])), sizeof(uint8_t));
                    out.write(reinterpret_cast<const char*>(&(new_tex[i][2])), sizeof(uint8_t));
                }
            }
            auto size = faces.size();
            for (int i = 0; i < size; ++i) {
                static const int three = 3;
                out.write(reinterpret_cast<const char*>(&three), sizeof(uint8_t));
                out.write(reinterpret_cast<const char*>(&(faces[i][0])), sizeof(int));
                out.write(reinterpret_cast<const char*>(&(faces[i][1])), sizeof(int));
                out.write(reinterpret_cast<const char*>(&(faces[i][2])), sizeof(int));
            }
        }

        // TODO: get_texcolor, options API
        std::array<uint8_t, 3> get_texcolor(const video_frame& texture, float u, float v)
        {
            const int w = texture.get_width(), h = texture.get_height();
            int x = std::min(std::max(int(u*w + .5f), 0), w - 1);
            int y = std::min(std::max(int(v*h + .5f), 0), h - 1);
            int idx = x * texture.get_bytes_per_pixel() + y * texture.get_stride_in_bytes();
            const auto texture_data = reinterpret_cast<const uint8_t*>(texture.get_data());
            return { texture_data[idx], texture_data[idx + 1], texture_data[idx + 2] };
        }

        std::string fname;
        pointcloud _pc;
    };

    class save_single_frameset : public filter {
    public:
        save_single_frameset(std::string filename = "RealSense Frameset ")
            : filter([this](frame f, frame_source& s) { save(f, s); }), fname(filename)
        {}

    private:
        void save(frame data, frame_source& source, bool do_signal=true)
        {
            software_device dev;

            std::vector<std::tuple<software_sensor, stream_profile, int>> sensors;
            if (auto fs = data.as<frameset>()) {
                int uid = 0;
                for (int i = 0; i < fs.size(); ++i) {
                    frame f = fs[i];
                    auto profile = f.get_profile();
                    auto s = dev.add_sensor(profile.stream_name() + "Sensor (" + std::to_string(uid) + ")");
                    stream_profile software_profile;

                    if (auto vf = f.as<video_frame>()) {
                        auto vp = profile.as<video_stream_profile>();
                        rs2_video_stream stream{ vp.stream_type(), vp.stream_index(), uid++, vp.width(), vp.height(), vp.fps(), vf.get_bytes_per_pixel(), vp.format(), vp.get_intrinsics() };
                        software_profile = s.add_video_stream(stream);
                    } else if (f.is<motion_frame>()) {
                        auto mp = profile.as<motion_stream_profile>();
                        rs2_motion_stream stream{ mp.stream_type(), mp.stream_index(), uid++, mp.fps(), mp.format(), mp.get_motion_intrinsics() };
                        software_profile = s.add_motion_stream(stream);
                    } else if (f.is<pose_frame>()) {
                        rs2_pose_stream stream{ profile.stream_type(), profile.stream_index(), uid++, profile.fps(), profile.format() };
                        software_profile = s.add_pose_stream(stream);
                    } else {
                        // TODO: How to handle other frame types? (e.g. points)
                        assert(false);
                    }
                    sensors.emplace_back(s, software_profile, i);
                }

                // Recorder needs sensors to already exist when its created
                recorder rec(fname + std::to_string(data.get_frame_number()) + ".bag", dev);

                for (auto group : sensors) {
                    auto s = std::get<software_sensor>(group);
                    auto profile = std::get<stream_profile>(group);
                    s.open(profile);
                    s.start([](frame) {});
                    frame f = fs[std::get<int>(group)];
                    if (auto vf = f.as<video_frame>()) {
                        s.on_video_frame({ const_cast<void*>(vf.get_data()), [](void*) {}, vf.get_stride_in_bytes(), vf.get_bytes_per_pixel(),
                                           vf.get_timestamp(), vf.get_frame_timestamp_domain(), static_cast<int>(vf.get_frame_number()), profile });
                    } else if (f.is<motion_frame>()) {
                        s.on_motion_frame({ const_cast<void*>(f.get_data()), [](void*) {}, f.get_timestamp(),
                                            f.get_frame_timestamp_domain(), static_cast<int>(f.get_frame_number()), profile });
                    } else if (f.is<pose_frame>()) {
                        s.on_pose_frame({ const_cast<void*>(f.get_data()), [](void*) {}, f.get_timestamp(),
                                          f.get_frame_timestamp_domain(), static_cast<int>(f.get_frame_number()), profile });
                    }
                }
            } else {
                // single frame
                auto set = source.allocate_composite_frame({ data });
                save(set, source, false);
            }

            if (do_signal)
                source.frame_ready(data);
        }

        std::string fname;
    };
}

#endif<commit_msg>Android fix<commit_after>// License: Apache 2.0. See LICENSE file in root directory.
// Copyright(c) 2017 Intel Corporation. All Rights Reserved.

#ifndef LIBREALSENSE_RS2_EXPORT_HPP
#define LIBREALSENSE_RS2_EXPORT_HPP

#include <map>
#include <fstream>
#include <cmath>
#include <sstream>
#include <cassert>
#include "rs_processing.hpp"
#include "rs_internal.hpp"

namespace rs2
{
    class save_to_ply : public filter
    {
    public:
        save_to_ply(std::string filename = "RealSense Pointcloud ", pointcloud pc = pointcloud())
            : filter([this](frame f, frame_source& s) { func(f, s); }),
            _pc(std::move(pc)), fname(filename)
        {
            register_simple_option(OPTION_IGNORE_COLOR, option_range{ 0, 1, 0, 1 });
        }

        DECLARE_PB_OPTION(OPTION_IGNORE_COLOR, 1);
    private:
        void func(frame data, frame_source& source)
        {
            frame depth, color;
            if (auto fs = data.as<frameset>()) {
                for (auto f : fs) {
                    if (f.is<points>()) depth = f;
                    else if (!depth && f.is<depth_frame>()) depth = f;
                    else if (!color && f.is<video_frame>()) color = f;
                }
            } else if (data.is<depth_frame>() || data.is<points>()) {
                depth = data;
            }

            if (!depth) throw std::runtime_error("Need depth data to save PLY");
            if (!depth.is<points>()) {
                if (color) _pc.map_to(color);
                depth = _pc.calculate(depth);
            }

            export_to_ply(depth, color);
            source.frame_ready(data); // passthrough filter because processing_block::process doesn't support sinks
        }

        void export_to_ply(points p, video_frame color) {
            const bool use_texcoords = color && get_option(OPTION_IGNORE_COLOR);
            const auto verts = p.get_vertices();
            const auto texcoords = p.get_texture_coordinates();
            std::vector<rs2::vertex> new_verts;
            std::vector<std::array<uint8_t, 3>> new_tex;
            std::map<int, int> idx_map;

            new_verts.reserve(p.size());
            if (use_texcoords) new_tex.reserve(p.size());

            static const auto min_distance = 1e-6;

            for (size_t i = 0; i < p.size(); ++i) {
                if (fabs(verts[i].x) >= min_distance || fabs(verts[i].y) >= min_distance ||
                    fabs(verts[i].z) >= min_distance)
                {
                    idx_map[i] = new_verts.size();
                    new_verts.push_back(verts[i]);
                    if (use_texcoords)
                    {
                        auto rgb = get_texcolor(color, texcoords[i].u, texcoords[i].v);
                        new_tex.push_back(rgb);
                    }
                }
            }

            auto profile = p.get_profile().as<video_stream_profile>();
            auto width = profile.width(), height = profile.height();
            static const auto threshold = 0.05f;
            std::vector<std::array<int, 3>> faces;
            for (int x = 0; x < width - 1; ++x) {
                for (int y = 0; y < height - 1; ++y) {
                    auto a = y * width + x, b = y * width + x + 1, c = (y + 1)*width + x, d = (y + 1)*width + x + 1;
                    if (verts[a].z && verts[b].z && verts[c].z && verts[d].z
                        && fabs(verts[a].z - verts[b].z) < threshold && fabs(verts[a].z - verts[c].z) < threshold
                        && fabs(verts[b].z - verts[d].z) < threshold && fabs(verts[c].z - verts[d].z) < threshold)
                    {
                        if (idx_map.count(a) == 0 || idx_map.count(b) == 0 || idx_map.count(c) == 0 ||
                            idx_map.count(d) == 0)
                            continue;
                        faces.push_back({ idx_map[a], idx_map[b], idx_map[d] });
                        faces.push_back({ idx_map[d], idx_map[c], idx_map[a] });
                    }
                }
            }

            std::stringstream name;
            name << fname << p.get_frame_number() << ".ply";
            std::ofstream out(name.str());
            out << "ply\n";
            out << "format binary_little_endian 1.0\n";
            out << "comment pointcloud saved from Realsense Viewer\n";
            out << "element vertex " << new_verts.size() << "\n";
            out << "property float" << sizeof(float) * 8 << " x\n";
            out << "property float" << sizeof(float) * 8 << " y\n";
            out << "property float" << sizeof(float) * 8 << " z\n";
            if (use_texcoords)
            {
                out << "property uchar red\n";
                out << "property uchar green\n";
                out << "property uchar blue\n";
            }
            out << "element face " << faces.size() << "\n";
            out << "property list uchar int vertex_indices\n";
            out << "end_header\n";
            out.close();

            out.open(name.str(), std::ios_base::app | std::ios_base::binary);
            for (int i = 0; i < new_verts.size(); ++i)
            {
                // we assume little endian architecture on your device
                out.write(reinterpret_cast<const char*>(&(new_verts[i].x)), sizeof(float));
                out.write(reinterpret_cast<const char*>(&(new_verts[i].y)), sizeof(float));
                out.write(reinterpret_cast<const char*>(&(new_verts[i].z)), sizeof(float));

                if (use_texcoords)
                {
                    out.write(reinterpret_cast<const char*>(&(new_tex[i][0])), sizeof(uint8_t));
                    out.write(reinterpret_cast<const char*>(&(new_tex[i][1])), sizeof(uint8_t));
                    out.write(reinterpret_cast<const char*>(&(new_tex[i][2])), sizeof(uint8_t));
                }
            }
            auto size = faces.size();
            for (int i = 0; i < size; ++i) {
                static const int three = 3;
                out.write(reinterpret_cast<const char*>(&three), sizeof(uint8_t));
                out.write(reinterpret_cast<const char*>(&(faces[i][0])), sizeof(int));
                out.write(reinterpret_cast<const char*>(&(faces[i][1])), sizeof(int));
                out.write(reinterpret_cast<const char*>(&(faces[i][2])), sizeof(int));
            }
        }

        // TODO: get_texcolor, options API
        std::array<uint8_t, 3> get_texcolor(const video_frame& texture, float u, float v)
        {
            const int w = texture.get_width(), h = texture.get_height();
            int x = std::min(std::max(int(u*w + .5f), 0), w - 1);
            int y = std::min(std::max(int(v*h + .5f), 0), h - 1);
            int idx = x * texture.get_bytes_per_pixel() + y * texture.get_stride_in_bytes();
            const auto texture_data = reinterpret_cast<const uint8_t*>(texture.get_data());
            return { texture_data[idx], texture_data[idx + 1], texture_data[idx + 2] };
        }

        std::string fname;
        pointcloud _pc;
    };

    class save_single_frameset : public filter {
    public:
        save_single_frameset(std::string filename = "RealSense Frameset ")
            : filter([this](frame f, frame_source& s) { save(f, s); }), fname(filename)
        {}

    private:
        void save(frame data, frame_source& source, bool do_signal=true)
        {
            software_device dev;

            std::vector<std::tuple<software_sensor, stream_profile, int>> sensors;
            if (auto fs = data.as<frameset>()) {
                int uid = 0;
                for (int i = 0; i < fs.size(); ++i) {
                    frame f = fs[i];
                    auto profile = f.get_profile();
                    std::stringstream sname;
                    sname << "Sensor (" << uid << ")";
                    auto s = dev.add_sensor(sname.str());
                    stream_profile software_profile;

                    if (auto vf = f.as<video_frame>()) {
                        auto vp = profile.as<video_stream_profile>();
                        rs2_video_stream stream{ vp.stream_type(), vp.stream_index(), uid++, vp.width(), vp.height(), vp.fps(), vf.get_bytes_per_pixel(), vp.format(), vp.get_intrinsics() };
                        software_profile = s.add_video_stream(stream);
                    } else if (f.is<motion_frame>()) {
                        auto mp = profile.as<motion_stream_profile>();
                        rs2_motion_stream stream{ mp.stream_type(), mp.stream_index(), uid++, mp.fps(), mp.format(), mp.get_motion_intrinsics() };
                        software_profile = s.add_motion_stream(stream);
                    } else if (f.is<pose_frame>()) {
                        rs2_pose_stream stream{ profile.stream_type(), profile.stream_index(), uid++, profile.fps(), profile.format() };
                        software_profile = s.add_pose_stream(stream);
                    } else {
                        // TODO: How to handle other frame types? (e.g. points)
                        assert(false);
                    }
                    sensors.emplace_back(s, software_profile, i);
                }

                // Recorder needs sensors to already exist when its created
                std::stringstream name;
                name << fname << data.get_frame_number() << ".bag";
                recorder rec(name.str(), dev);

                for (auto group : sensors) {
                    auto s = std::get<software_sensor>(group);
                    auto profile = std::get<stream_profile>(group);
                    s.open(profile);
                    s.start([](frame) {});
                    frame f = fs[std::get<int>(group)];
                    if (auto vf = f.as<video_frame>()) {
                        s.on_video_frame({ const_cast<void*>(vf.get_data()), [](void*) {}, vf.get_stride_in_bytes(), vf.get_bytes_per_pixel(),
                                           vf.get_timestamp(), vf.get_frame_timestamp_domain(), static_cast<int>(vf.get_frame_number()), profile });
                    } else if (f.is<motion_frame>()) {
                        s.on_motion_frame({ const_cast<void*>(f.get_data()), [](void*) {}, f.get_timestamp(),
                                            f.get_frame_timestamp_domain(), static_cast<int>(f.get_frame_number()), profile });
                    } else if (f.is<pose_frame>()) {
                        s.on_pose_frame({ const_cast<void*>(f.get_data()), [](void*) {}, f.get_timestamp(),
                                          f.get_frame_timestamp_domain(), static_cast<int>(f.get_frame_number()), profile });
                    }
                }
            } else {
                // single frame
                auto set = source.allocate_composite_frame({ data });
                save(set, source, false);
            }

            if (do_signal)
                source.frame_ready(data);
        }

        std::string fname;
    };
}

#endif<|endoftext|>


<commit_before>/*

Copyright (c) 2007, Arvid Norberg
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 author 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.

*/

#ifndef TORRENT_BROADCAST_SOCKET_HPP_INCLUDED
#define TORRENT_BROADCAST_SOCKET_HPP_INCLUDED

#include "libtorrent/socket.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <list>

namespace libtorrent
{

	bool is_local(address const& a);
	bool is_loopback(address const& addr);
	bool is_multicast(address const& addr);
	bool is_any(address const& addr);

	address guess_local_address(asio::io_service&);

	typedef boost::function<void(udp::endpoint const& from
		, char* buffer, int size)> receive_handler_t;

	class broadcast_socket
	{
	public:
		broadcast_socket(asio::io_service& ios, udp::endpoint const& multicast_endpoint
			, receive_handler_t const& handler, bool loopback = true);
		~broadcast_socket() { close(); }

		void send(char const* buffer, int size, asio::error_code& ec);
		void close();

	private:

		struct socket_entry
		{
			socket_entry(boost::shared_ptr<datagram_socket> const& s): socket(s) {}
			boost::shared_ptr<datagram_socket> socket;
			char buffer[1024];
			udp::endpoint remote;
			void close() { socket->close(); }
		};

		void on_receive(socket_entry* s, asio::error_code const& ec
			, std::size_t bytes_transferred);
		void open_unicast_socket(io_service& ios, address const& addr);

		// these sockets are used to
		// join the multicast group (on each interface)
		// and receive multicast messages
		std::list<socket_entry> m_sockets;
		// these sockets are not bound to any
		// specific port and are used to
		// send messages to the multicast group
		// and receive unicast responses
		std::list<socket_entry> m_unicast_sockets;
		udp::endpoint m_multicast_endpoint;
		receive_handler_t m_on_receive;

	};
}

#endif

<commit_msg>support in broadcast_socket to be built without exception support<commit_after>/*

Copyright (c) 2007, Arvid Norberg
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 author 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.

*/

#ifndef TORRENT_BROADCAST_SOCKET_HPP_INCLUDED
#define TORRENT_BROADCAST_SOCKET_HPP_INCLUDED

#include "libtorrent/socket.hpp"
#include <boost/shared_ptr.hpp>
#include <boost/function.hpp>
#include <list>

namespace libtorrent
{

	bool is_local(address const& a);
	bool is_loopback(address const& addr);
	bool is_multicast(address const& addr);
	bool is_any(address const& addr);

	address guess_local_address(asio::io_service&);

	typedef boost::function<void(udp::endpoint const& from
		, char* buffer, int size)> receive_handler_t;

	class broadcast_socket
	{
	public:
		broadcast_socket(asio::io_service& ios, udp::endpoint const& multicast_endpoint
			, receive_handler_t const& handler, bool loopback = true);
		~broadcast_socket() { close(); }

		void send(char const* buffer, int size, asio::error_code& ec);
		void close();

	private:

		struct socket_entry
		{
			socket_entry(boost::shared_ptr<datagram_socket> const& s): socket(s) {}
			boost::shared_ptr<datagram_socket> socket;
			char buffer[1024];
			udp::endpoint remote;
			void close()
			{
				asio::error_code ec;
				socket->close(ec);
			}
		};

		void on_receive(socket_entry* s, asio::error_code const& ec
			, std::size_t bytes_transferred);
		void open_unicast_socket(io_service& ios, address const& addr);

		// these sockets are used to
		// join the multicast group (on each interface)
		// and receive multicast messages
		std::list<socket_entry> m_sockets;
		// these sockets are not bound to any
		// specific port and are used to
		// send messages to the multicast group
		// and receive unicast responses
		std::list<socket_entry> m_unicast_sockets;
		udp::endpoint m_multicast_endpoint;
		receive_handler_t m_on_receive;

	};
}

#endif

<|endoftext|>


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

// mapnik
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/text_line.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/text/itemizer.hpp>
#include <mapnik/safe_cast.hpp>
#include <mapnik/font_engine_freetype.hpp>

// stl
#include <list>
#include <type_traits>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>
#include <unicode/uscript.h>
#pragma GCC diagnostic pop

namespace mapnik { namespace detail {

static inline hb_script_t _icu_script_to_script(UScriptCode script)
{
    if (script == USCRIPT_INVALID_CODE) return HB_SCRIPT_INVALID;
        return hb_script_from_string(uscript_getShortName(script), -1);
}

static inline const uint16_t * uchar_to_utf16(const UChar* src)
{
   static_assert(sizeof(UChar) == sizeof(uint16_t),"UChar is eq size to uint16_t");
#if defined(_MSC_VER)
   return reinterpret_cast<const uint16_t *>(src);
#else
   return src;
#endif
}

static hb_language_t script_to_language(hb_script_t script)
{
    switch (script)
    {
    // Unicode 1.1
    case HB_SCRIPT_ARABIC: return hb_language_from_string("ar", -1); break;
    case HB_SCRIPT_ARMENIAN: return hb_language_from_string("hy", -1); break;
    case HB_SCRIPT_BENGALI: return hb_language_from_string("bn", -1); break;
    case HB_SCRIPT_CANADIAN_ABORIGINAL: return hb_language_from_string("iu", -1); break;
    case HB_SCRIPT_CHEROKEE: return hb_language_from_string("chr", -1); break;
    case HB_SCRIPT_COPTIC: return hb_language_from_string("cop", -1); break;
    case HB_SCRIPT_CYRILLIC: return hb_language_from_string("ru", -1); break;
    case HB_SCRIPT_DEVANAGARI: return hb_language_from_string("hi", -1); break;
    case HB_SCRIPT_GEORGIAN: return hb_language_from_string("ka", -1); break;
    case HB_SCRIPT_GREEK: return hb_language_from_string("el", -1); break;
    case HB_SCRIPT_GUJARATI: return hb_language_from_string("gu", -1); break;
    case HB_SCRIPT_GURMUKHI: return hb_language_from_string("pa", -1); break;
    case HB_SCRIPT_HANGUL: return hb_language_from_string("ko", -1); break;
    case HB_SCRIPT_HAN: return hb_language_from_string("zh-Hans", -1); break;
    case HB_SCRIPT_HEBREW: return hb_language_from_string("he", -1); break;
    case HB_SCRIPT_HIRAGANA: return hb_language_from_string("ja", -1); break;
    case HB_SCRIPT_KANNADA: return hb_language_from_string("kn", -1); break;
    case HB_SCRIPT_KATAKANA: return hb_language_from_string("ja", -1); break;
    case HB_SCRIPT_LAO: return hb_language_from_string("lo", -1); break;
    case HB_SCRIPT_LATIN: return hb_language_from_string("en", -1); break;
    case HB_SCRIPT_MALAYALAM: return hb_language_from_string("ml", -1); break;
    case HB_SCRIPT_MONGOLIAN: return hb_language_from_string("mn", -1); break;
    case HB_SCRIPT_ORIYA: return hb_language_from_string("or", -1); break;
    case HB_SCRIPT_SYRIAC: return hb_language_from_string("syr", -1); break;
    case HB_SCRIPT_TAMIL: return hb_language_from_string("ta", -1); break;
    case HB_SCRIPT_TELUGU: return hb_language_from_string("te", -1); break;
    case HB_SCRIPT_THAI: return hb_language_from_string("th", -1); break;

    // Unicode 2.0
    case HB_SCRIPT_TIBETAN: return hb_language_from_string("bo", -1); break;

    // Unicode 3.0
    case HB_SCRIPT_ETHIOPIC: return hb_language_from_string("am", -1); break;
    case HB_SCRIPT_KHMER: return hb_language_from_string("km", -1); break;
    case HB_SCRIPT_MYANMAR: return hb_language_from_string("my", -1); break;
    case HB_SCRIPT_SINHALA: return hb_language_from_string("si", -1); break;
    case HB_SCRIPT_THAANA: return hb_language_from_string("dv", -1); break;

    // Unicode 3.2
    case HB_SCRIPT_BUHID: return hb_language_from_string("bku", -1); break;
    case HB_SCRIPT_HANUNOO: return hb_language_from_string("hnn", -1); break;
    case HB_SCRIPT_TAGALOG: return hb_language_from_string("tl", -1); break;
    case HB_SCRIPT_TAGBANWA: return hb_language_from_string("tbw", -1); break;

    // Unicode 4.0
    case HB_SCRIPT_UGARITIC: return hb_language_from_string("uga", -1); break;

    // Unicode 4.1
    case HB_SCRIPT_BUGINESE: return hb_language_from_string("bug", -1); break;
    case HB_SCRIPT_OLD_PERSIAN: return hb_language_from_string("peo", -1); break;
    case HB_SCRIPT_SYLOTI_NAGRI: return hb_language_from_string("syl", -1); break;

    // Unicode 5.0
    case HB_SCRIPT_NKO: return hb_language_from_string("nko", -1); break;

    // no representative language exists
    default: return HB_LANGUAGE_INVALID; break;
    }
}

} // ns detail

struct harfbuzz_shaper
{
static void shape_text(text_line & line,
                       text_itemizer & itemizer,
                       std::map<unsigned,double> & width_map,
                       face_manager_freetype & font_manager,
                       double scale_factor)
{
    unsigned start = line.first_char();
    unsigned end = line.last_char();
    std::size_t length = end - start;
    if (!length) return;

    std::list<text_item> const& list = itemizer.itemize(start, end);

    line.reserve(length);

    auto hb_buffer_deleter = [](hb_buffer_t * buffer) { hb_buffer_destroy(buffer);};
    const std::unique_ptr<hb_buffer_t, decltype(hb_buffer_deleter)> buffer(hb_buffer_create(), hb_buffer_deleter);
    hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length));
    mapnik::value_unicode_string const& text = itemizer.text();
    for (auto const& text_item : list)
    {
        face_set_ptr face_set = font_manager.get_face_set(text_item.format_->face_name, text_item.format_->fontset);
        double size = text_item.format_->text_size * scale_factor;
        face_set->set_unscaled_character_sizes();
        std::size_t num_faces = face_set->size();

        font_feature_settings const& ff_settings = text_item.format_->ff_settings;
        int ff_count = safe_cast<int>(ff_settings.count());

        // rendering information for a single glyph
        struct glyph_face_info
        {
            face_ptr face;
            hb_glyph_info_t glyph;
            hb_glyph_position_t position;
        };

        // this table is filled with information for rendering each glyph, so that
        // several font faces can be used in a single text_item
        std::size_t pos = 0;
        std::vector<std::vector<glyph_face_info>> glyphinfos;

        glyphinfos.resize(text.length());
        for (auto const& face : *face_set)
        {
            ++pos;
            hb_buffer_clear_contents(buffer.get());
            hb_buffer_add_utf16(buffer.get(), detail::uchar_to_utf16(text.getBuffer()), text.length(), text_item.start, static_cast<int>(text_item.end - text_item.start));
            hb_buffer_set_direction(buffer.get(), (text_item.dir == UBIDI_RTL) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);

            hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr));
            auto script = detail::_icu_script_to_script(text_item.script);
            auto language = detail::script_to_language(script);
            if (language != HB_LANGUAGE_INVALID)
            {
                hb_buffer_set_language(buffer.get(), language); // set most common language for the run based script
            }
            hb_buffer_set_script(buffer.get(), script);

            // https://github.com/mapnik/test-data-visual/pull/25
#if HB_VERSION_MAJOR > 0
#if HB_VERSION_ATLEAST(1, 0 , 5)
            hb_ft_font_set_load_flags(font,FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
#endif
#endif
            hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count);
            hb_font_destroy(font);

            unsigned num_glyphs = hb_buffer_get_length(buffer.get());
            hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer.get(), &num_glyphs);
            hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), &num_glyphs);

            unsigned cluster = 0;
            bool in_cluster = false;
            std::vector<unsigned> clusters;

            for (unsigned i = 0; i < num_glyphs; ++i)
            {
                if (i == 0)
                {
                    cluster = glyphs[0].cluster;
                    clusters.push_back(cluster);
                }
                if (cluster != glyphs[i].cluster)
                {
                    cluster = glyphs[i].cluster;
                    clusters.push_back(cluster);
                    in_cluster = false;
                }
                else if (i != 0)
                {
                    in_cluster = true;
                }
                if (glyphinfos.size() <= cluster)
                {
                    glyphinfos.resize(cluster + 1);
                }
                auto & c = glyphinfos[cluster];
                if (c.empty())
                {
                    c.push_back({face, glyphs[i], positions[i]});
                }
                else if (c.front().glyph.codepoint == 0)
                {
                    c.front() = { face, glyphs[i], positions[i] };
                }
                else if (in_cluster)
                {
                    c.push_back({ face, glyphs[i], positions[i] });
                }
            }
            bool all_set = true;
            for (auto c_id : clusters)
            {
                auto const& c = glyphinfos[c_id];
                if (c.empty() || c.front().glyph.codepoint == 0)
                {
                    all_set = false;
                    break;
                }
            }
            if (!all_set && (pos < num_faces))
            {
                //Try next font in fontset
                continue;
            }
            double max_glyph_height = 0;
            for (auto const& c_id : clusters)
            {
                auto const& c = glyphinfos[c_id];
                for (auto const& info : c)
                {
                    auto const& gpos = info.position;
                    auto const& glyph = info.glyph;
                    unsigned char_index = glyph.cluster;
                    glyph_info g(glyph.codepoint,char_index,text_item.format_);
                    if (info.glyph.codepoint != 0) g.face = info.face;
                    else g.face = face;
                    if (g.face->glyph_dimensions(g))
                    {
                        g.scale_multiplier = g.face->get_face()->units_per_EM > 0 ?
                            (size / g.face->get_face()->units_per_EM) : (size / 2048.0) ;
                        //Overwrite default advance with better value provided by HarfBuzz
                        g.unscaled_advance = gpos.x_advance;
                        g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier);
                        double tmp_height = g.height();
                        if (g.face->is_color())
                        {
                            tmp_height = size;
                        }
                        if (tmp_height > max_glyph_height) max_glyph_height = tmp_height;
                        width_map[char_index] += g.advance();
                        line.add_glyph(std::move(g), scale_factor);
                    }
                }
            }
            line.update_max_char_height(max_glyph_height);
            break; //When we reach this point the current font had all glyphs.
        }
    }
}
};
} // namespace mapnik

#endif // MAPNIK_HARFBUZZ_SHAPER_HPP
<commit_msg>add debug log<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2016 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_HARFBUZZ_SHAPER_HPP
#define MAPNIK_HARFBUZZ_SHAPER_HPP

// mapnik
#include <mapnik/text/text_properties.hpp>
#include <mapnik/text/text_line.hpp>
#include <mapnik/text/face.hpp>
#include <mapnik/text/font_feature_settings.hpp>
#include <mapnik/text/itemizer.hpp>
#include <mapnik/safe_cast.hpp>
#include <mapnik/font_engine_freetype.hpp>

// stl
#include <list>
#include <type_traits>

#pragma GCC diagnostic push
#include <mapnik/warning_ignore.hpp>
#include <harfbuzz/hb.h>
#include <harfbuzz/hb-ft.h>
#include <unicode/uscript.h>
#pragma GCC diagnostic pop

namespace mapnik { namespace detail {

static inline hb_script_t _icu_script_to_script(UScriptCode script)
{
    if (script == USCRIPT_INVALID_CODE) return HB_SCRIPT_INVALID;
        return hb_script_from_string(uscript_getShortName(script), -1);
}

static inline const uint16_t * uchar_to_utf16(const UChar* src)
{
   static_assert(sizeof(UChar) == sizeof(uint16_t),"UChar is eq size to uint16_t");
#if defined(_MSC_VER)
   return reinterpret_cast<const uint16_t *>(src);
#else
   return src;
#endif
}

static hb_language_t script_to_language(hb_script_t script)
{
    switch (script)
    {
    // Unicode 1.1
    case HB_SCRIPT_ARABIC: return hb_language_from_string("ar", -1); break;
    case HB_SCRIPT_ARMENIAN: return hb_language_from_string("hy", -1); break;
    case HB_SCRIPT_BENGALI: return hb_language_from_string("bn", -1); break;
    case HB_SCRIPT_CANADIAN_ABORIGINAL: return hb_language_from_string("iu", -1); break;
    case HB_SCRIPT_CHEROKEE: return hb_language_from_string("chr", -1); break;
    case HB_SCRIPT_COPTIC: return hb_language_from_string("cop", -1); break;
    case HB_SCRIPT_CYRILLIC: return hb_language_from_string("ru", -1); break;
    case HB_SCRIPT_DEVANAGARI: return hb_language_from_string("hi", -1); break;
    case HB_SCRIPT_GEORGIAN: return hb_language_from_string("ka", -1); break;
    case HB_SCRIPT_GREEK: return hb_language_from_string("el", -1); break;
    case HB_SCRIPT_GUJARATI: return hb_language_from_string("gu", -1); break;
    case HB_SCRIPT_GURMUKHI: return hb_language_from_string("pa", -1); break;
    case HB_SCRIPT_HANGUL: return hb_language_from_string("ko", -1); break;
    case HB_SCRIPT_HAN: return hb_language_from_string("zh-hans", -1); break;
    case HB_SCRIPT_HEBREW: return hb_language_from_string("he", -1); break;
    case HB_SCRIPT_HIRAGANA: return hb_language_from_string("ja", -1); break;
    case HB_SCRIPT_KANNADA: return hb_language_from_string("kn", -1); break;
    case HB_SCRIPT_KATAKANA: return hb_language_from_string("ja", -1); break;
    case HB_SCRIPT_LAO: return hb_language_from_string("lo", -1); break;
    case HB_SCRIPT_LATIN: return hb_language_from_string("en", -1); break;
    case HB_SCRIPT_MALAYALAM: return hb_language_from_string("ml", -1); break;
    case HB_SCRIPT_MONGOLIAN: return hb_language_from_string("mn", -1); break;
    case HB_SCRIPT_ORIYA: return hb_language_from_string("or", -1); break;
    case HB_SCRIPT_SYRIAC: return hb_language_from_string("syr", -1); break;
    case HB_SCRIPT_TAMIL: return hb_language_from_string("ta", -1); break;
    case HB_SCRIPT_TELUGU: return hb_language_from_string("te", -1); break;
    case HB_SCRIPT_THAI: return hb_language_from_string("th", -1); break;

    // Unicode 2.0
    case HB_SCRIPT_TIBETAN: return hb_language_from_string("bo", -1); break;

    // Unicode 3.0
    case HB_SCRIPT_ETHIOPIC: return hb_language_from_string("am", -1); break;
    case HB_SCRIPT_KHMER: return hb_language_from_string("km", -1); break;
    case HB_SCRIPT_MYANMAR: return hb_language_from_string("my", -1); break;
    case HB_SCRIPT_SINHALA: return hb_language_from_string("si", -1); break;
    case HB_SCRIPT_THAANA: return hb_language_from_string("dv", -1); break;

    // Unicode 3.2
    case HB_SCRIPT_BUHID: return hb_language_from_string("bku", -1); break;
    case HB_SCRIPT_HANUNOO: return hb_language_from_string("hnn", -1); break;
    case HB_SCRIPT_TAGALOG: return hb_language_from_string("tl", -1); break;
    case HB_SCRIPT_TAGBANWA: return hb_language_from_string("tbw", -1); break;

    // Unicode 4.0
    case HB_SCRIPT_UGARITIC: return hb_language_from_string("uga", -1); break;

    // Unicode 4.1
    case HB_SCRIPT_BUGINESE: return hb_language_from_string("bug", -1); break;
    case HB_SCRIPT_OLD_PERSIAN: return hb_language_from_string("peo", -1); break;
    case HB_SCRIPT_SYLOTI_NAGRI: return hb_language_from_string("syl", -1); break;

    // Unicode 5.0
    case HB_SCRIPT_NKO: return hb_language_from_string("nko", -1); break;

    // no representative language exists
    default: return HB_LANGUAGE_INVALID; break;
    }
}

} // ns detail

struct harfbuzz_shaper
{
static void shape_text(text_line & line,
                       text_itemizer & itemizer,
                       std::map<unsigned,double> & width_map,
                       face_manager_freetype & font_manager,
                       double scale_factor)
{
    unsigned start = line.first_char();
    unsigned end = line.last_char();
    std::size_t length = end - start;
    if (!length) return;

    std::list<text_item> const& list = itemizer.itemize(start, end);

    line.reserve(length);

    auto hb_buffer_deleter = [](hb_buffer_t * buffer) { hb_buffer_destroy(buffer);};
    const std::unique_ptr<hb_buffer_t, decltype(hb_buffer_deleter)> buffer(hb_buffer_create(), hb_buffer_deleter);
    hb_buffer_pre_allocate(buffer.get(), safe_cast<int>(length));
    mapnik::value_unicode_string const& text = itemizer.text();
    for (auto const& text_item : list)
    {
        face_set_ptr face_set = font_manager.get_face_set(text_item.format_->face_name, text_item.format_->fontset);
        double size = text_item.format_->text_size * scale_factor;
        face_set->set_unscaled_character_sizes();
        std::size_t num_faces = face_set->size();

        font_feature_settings const& ff_settings = text_item.format_->ff_settings;
        int ff_count = safe_cast<int>(ff_settings.count());

        // rendering information for a single glyph
        struct glyph_face_info
        {
            face_ptr face;
            hb_glyph_info_t glyph;
            hb_glyph_position_t position;
        };

        // this table is filled with information for rendering each glyph, so that
        // several font faces can be used in a single text_item
        std::size_t pos = 0;
        std::vector<std::vector<glyph_face_info>> glyphinfos;

        glyphinfos.resize(text.length());
        for (auto const& face : *face_set)
        {
            ++pos;
            hb_buffer_clear_contents(buffer.get());
            hb_buffer_add_utf16(buffer.get(), detail::uchar_to_utf16(text.getBuffer()), text.length(), text_item.start, static_cast<int>(text_item.end - text_item.start));
            hb_buffer_set_direction(buffer.get(), (text_item.dir == UBIDI_RTL) ? HB_DIRECTION_RTL : HB_DIRECTION_LTR);

            hb_font_t *font(hb_ft_font_create(face->get_face(), nullptr));
            auto script = detail::_icu_script_to_script(text_item.script);
            auto language = detail::script_to_language(script);
            MAPNIK_LOG_DEBUG(harfbuzz_shaper) << "RUN:[" << text_item.start << "," << text_item.end << "]"
                                              << " LANGUAGE:" << hb_language_to_string(language)
                                              << " SCRIPT:" << script << "(" << text_item.script << ") " << uscript_getShortName(text_item.script)
                                              << " FONT:" << face->family_name();
            if (language != HB_LANGUAGE_INVALID)
            {
                hb_buffer_set_language(buffer.get(), language); // set most common language for the run based script
            }
            hb_buffer_set_script(buffer.get(), script);

            // https://github.com/mapnik/test-data-visual/pull/25
#if HB_VERSION_MAJOR > 0
#if HB_VERSION_ATLEAST(1, 0 , 5)
            hb_ft_font_set_load_flags(font,FT_LOAD_DEFAULT | FT_LOAD_NO_HINTING);
#endif
#endif
            hb_shape(font, buffer.get(), ff_settings.get_features(), ff_count);
            hb_font_destroy(font);

            unsigned num_glyphs = hb_buffer_get_length(buffer.get());
            hb_glyph_info_t *glyphs = hb_buffer_get_glyph_infos(buffer.get(), &num_glyphs);
            hb_glyph_position_t *positions = hb_buffer_get_glyph_positions(buffer.get(), &num_glyphs);

            unsigned cluster = 0;
            bool in_cluster = false;
            std::vector<unsigned> clusters;

            for (unsigned i = 0; i < num_glyphs; ++i)
            {
                if (i == 0)
                {
                    cluster = glyphs[0].cluster;
                    clusters.push_back(cluster);
                }
                if (cluster != glyphs[i].cluster)
                {
                    cluster = glyphs[i].cluster;
                    clusters.push_back(cluster);
                    in_cluster = false;
                }
                else if (i != 0)
                {
                    in_cluster = true;
                }
                if (glyphinfos.size() <= cluster)
                {
                    glyphinfos.resize(cluster + 1);
                }
                auto & c = glyphinfos[cluster];
                if (c.empty())
                {
                    c.push_back({face, glyphs[i], positions[i]});
                }
                else if (c.front().glyph.codepoint == 0)
                {
                    c.front() = { face, glyphs[i], positions[i] };
                }
                else if (in_cluster)
                {
                    c.push_back({ face, glyphs[i], positions[i] });
                }
            }
            bool all_set = true;
            for (auto c_id : clusters)
            {
                auto const& c = glyphinfos[c_id];
                if (c.empty() || c.front().glyph.codepoint == 0)
                {
                    all_set = false;
                    break;
                }
            }
            if (!all_set && (pos < num_faces))
            {
                //Try next font in fontset
                continue;
            }
            double max_glyph_height = 0;
            for (auto const& c_id : clusters)
            {
                auto const& c = glyphinfos[c_id];
                for (auto const& info : c)
                {
                    auto const& gpos = info.position;
                    auto const& glyph = info.glyph;
                    unsigned char_index = glyph.cluster;
                    glyph_info g(glyph.codepoint,char_index,text_item.format_);
                    if (info.glyph.codepoint != 0) g.face = info.face;
                    else g.face = face;
                    if (g.face->glyph_dimensions(g))
                    {
                        g.scale_multiplier = g.face->get_face()->units_per_EM > 0 ?
                            (size / g.face->get_face()->units_per_EM) : (size / 2048.0) ;
                        //Overwrite default advance with better value provided by HarfBuzz
                        g.unscaled_advance = gpos.x_advance;
                        g.offset.set(gpos.x_offset * g.scale_multiplier, gpos.y_offset * g.scale_multiplier);
                        double tmp_height = g.height();
                        if (g.face->is_color())
                        {
                            tmp_height = size;
                        }
                        if (tmp_height > max_glyph_height) max_glyph_height = tmp_height;
                        width_map[char_index] += g.advance();
                        line.add_glyph(std::move(g), scale_factor);
                    }
                }
            }
            line.update_max_char_height(max_glyph_height);
            break; //When we reach this point the current font had all glyphs.
        }
    }
}
};
} // namespace mapnik

#endif // MAPNIK_HARFBUZZ_SHAPER_HPP
<|endoftext|>


<commit_before>#pragma once

#include <microscopes/common/type_helper.hpp>
#include <microscopes/common/random_fwd.hpp>
#include <microscopes/common/macros.hpp>
#include <microscopes/common/assert.hpp>

#include <vector>
#include <cstring>
#include <iostream>

namespace microscopes {
namespace common {

class row_accessor {
  friend class row_mutator;
public:
  row_accessor()
    : data_(), mask_(), types_(),
      cursor_(), mask_cursor_(), pos_() {}
  row_accessor(const uint8_t *data,
               const bool *mask,
               const std::vector<runtime_type> *types)
    : data_(data), mask_(mask), types_(types),
      cursor_(data), mask_cursor_(mask), pos_()
  {
    MICROSCOPES_ASSERT(data);
    MICROSCOPES_ASSERT(types);
  }

  inline size_t tell() const { return pos_; }
  inline size_t nfeatures() const { return types_->size(); }

  inline const runtime_type & curtype() const { return (*types_)[pos_]; }
  inline unsigned curshape() const { return curtype().n(); }

  inline bool
  ismasked(size_t idx) const
  {
    MICROSCOPES_ASSERT(idx < curshape());
    return !mask_ ? false : *(mask_cursor_ + idx);
  }

  template <typename T>
  inline T
  get(size_t idx) const
  {
    MICROSCOPES_ASSERT(pos_ < nfeatures());
    MICROSCOPES_ASSERT(cursor_);
    MICROSCOPES_ASSERT(idx < curshape());
    const size_t s = runtime_type_traits::PrimitiveTypeSize(curtype().t());
    return runtime_cast::cast<T>(cursor_ + idx * s, curtype().t());
  }

  inline void
  bump()
  {
    MICROSCOPES_ASSERT(pos_ <= nfeatures());
    cursor_ += runtime_type_traits::RuntimeTypeSize(curtype());
    mask_cursor_ += curtype().n();
    pos_++;
  }

  inline bool end() const { return pos_ == nfeatures(); }

  inline void
  reset()
  {
    cursor_ = data_;
    mask_cursor_ = mask_;
    pos_ = 0;
  }

  std::string debug_str() const;

protected:
  inline const uint8_t * cursor() const { return cursor_; }

private:
  const uint8_t *data_;
  const bool *mask_;
  const std::vector<runtime_type> *types_;

  const uint8_t *cursor_;
  const bool *mask_cursor_;
  size_t pos_;
};

class row_mutator {
public:
  row_mutator()
    : data_(), types_(), cursor_(), pos_() {}
  row_mutator(uint8_t *data,
              const std::vector<runtime_type> *types)
    : data_(data), types_(types),
      cursor_(data), pos_()
  {
    MICROSCOPES_ASSERT(data);
    MICROSCOPES_ASSERT(types);
  }

  inline size_t tell() const { return pos_; }
  inline size_t nfeatures() const { return types_->size(); }

  inline const runtime_type & curtype() const { return (*types_)[pos_]; }
  inline unsigned curshape() const { return curtype().n(); }

  template <typename T>
  inline void
  set(T t, size_t idx)
  {
    MICROSCOPES_ASSERT(pos_ < nfeatures());
    MICROSCOPES_ASSERT(cursor_);
    MICROSCOPES_ASSERT(idx < curshape());
    const size_t s = runtime_type_traits::PrimitiveTypeSize(curtype().t());
    runtime_cast::uncast<T>(cursor_ + idx * s, curtype().t(), t);
  }

  void
  set(const row_accessor &acc)
  {
    MICROSCOPES_DCHECK(curshape() == acc.curshape(), "shapes do not match");
    MICROSCOPES_ASSERT(cursor_);
    MICROSCOPES_ASSERT(acc.cursor());
    const size_t s0 = runtime_type_traits::PrimitiveTypeSize(curtype().t());
    const size_t s1 = runtime_type_traits::PrimitiveTypeSize(acc.curtype().t());
    for (unsigned i = 0; i < curshape(); i++)
      runtime_cast::copy(
          cursor_ + i * s0, curtype().t(),
          acc.cursor() + i * s1, acc.curtype().t());
  }

  inline void
  bump()
  {
    MICROSCOPES_ASSERT(pos_ <= nfeatures());
    cursor_ += runtime_type_traits::RuntimeTypeSize(curtype());
    pos_++;
  }

  inline bool end() const { return pos_ == nfeatures(); }

  inline void
  reset()
  {
    cursor_ = data_;
    pos_ = 0;
  }

  std::string debug_str() const;

private:
  uint8_t *data_;
  const std::vector<runtime_type> *types_;

  uint8_t *cursor_;
  size_t pos_;
};

class dataview {
protected:
  dataview(size_t n, const std::vector<runtime_type> &types);

  inline const std::vector<size_t> & offsets() const { return offsets_; }

  // in bytes
  inline size_t rowsize() const { return rowsize_; }
  inline size_t maskrowsize() const { return maskrowsize_; }

public:
  virtual ~dataview() {}

  // implementations need to provide the following API
  virtual row_accessor get() const = 0;
  virtual size_t index() const = 0;
  virtual void next() = 0;
  virtual void reset() = 0;
  virtual bool end() const = 0;

  inline size_t size() const { return n_; }
  inline const std::vector<runtime_type> & types() const { return types_; }

private:
  size_t n_;

  std::vector<runtime_type> types_;
  std::vector<size_t> offsets_;
  size_t rowsize_;
  size_t maskrowsize_;
};

class row_major_dataview : public dataview {
public:
  row_major_dataview(const uint8_t *data,
                     const bool *mask,
                     size_t n,
                     const std::vector<runtime_type> &types);
  row_accessor get() const override;
  size_t index() const override;
  void next() override;
  void reset() override;
  bool end() const override;

  inline void reset_permutation() { pi_.clear(); }
  void permute(rng_t &rng);

private:
  const uint8_t *data_;
  const bool *mask_;
  size_t pos_;

  std::vector<size_t> pi_;
};

} // namespace common
} // namespace microscopes
<commit_msg>helper function anymasked()<commit_after>#pragma once

#include <microscopes/common/type_helper.hpp>
#include <microscopes/common/random_fwd.hpp>
#include <microscopes/common/macros.hpp>
#include <microscopes/common/assert.hpp>

#include <vector>
#include <cstring>
#include <iostream>

namespace microscopes {
namespace common {

class row_accessor {
  friend class row_mutator;
public:
  row_accessor()
    : data_(), mask_(), types_(),
      cursor_(), mask_cursor_(), pos_() {}
  row_accessor(const uint8_t *data,
               const bool *mask,
               const std::vector<runtime_type> *types)
    : data_(data), mask_(mask), types_(types),
      cursor_(data), mask_cursor_(mask), pos_()
  {
    MICROSCOPES_ASSERT(data);
    MICROSCOPES_ASSERT(types);
  }

  inline size_t tell() const { return pos_; }
  inline size_t nfeatures() const { return types_->size(); }

  inline const runtime_type & curtype() const { return (*types_)[pos_]; }
  inline unsigned curshape() const { return curtype().n(); }

  inline bool
  ismasked(size_t idx) const
  {
    MICROSCOPES_ASSERT(idx < curshape());
    return !mask_ ? false : *(mask_cursor_ + idx);
  }

  inline bool
  anymasked() const
  {
    if (!mask_)
      return false;
    // XXX: more efficient ways to do this!
    for (size_t i = 0; i < curshape(); i++)
      if (ismasked(i))
        return true;
    return false;
  }

  template <typename T>
  inline T
  get(size_t idx) const
  {
    MICROSCOPES_ASSERT(pos_ < nfeatures());
    MICROSCOPES_ASSERT(cursor_);
    MICROSCOPES_ASSERT(idx < curshape());
    const size_t s = runtime_type_traits::PrimitiveTypeSize(curtype().t());
    return runtime_cast::cast<T>(cursor_ + idx * s, curtype().t());
  }

  inline void
  bump()
  {
    MICROSCOPES_ASSERT(pos_ <= nfeatures());
    cursor_ += runtime_type_traits::RuntimeTypeSize(curtype());
    mask_cursor_ += curtype().n();
    pos_++;
  }

  inline bool end() const { return pos_ == nfeatures(); }

  inline void
  reset()
  {
    cursor_ = data_;
    mask_cursor_ = mask_;
    pos_ = 0;
  }

  std::string debug_str() const;

protected:
  inline const uint8_t * cursor() const { return cursor_; }

private:
  const uint8_t *data_;
  const bool *mask_;
  const std::vector<runtime_type> *types_;

  const uint8_t *cursor_;
  const bool *mask_cursor_;
  size_t pos_;
};

class row_mutator {
public:
  row_mutator()
    : data_(), types_(), cursor_(), pos_() {}
  row_mutator(uint8_t *data,
              const std::vector<runtime_type> *types)
    : data_(data), types_(types),
      cursor_(data), pos_()
  {
    MICROSCOPES_ASSERT(data);
    MICROSCOPES_ASSERT(types);
  }

  inline size_t tell() const { return pos_; }
  inline size_t nfeatures() const { return types_->size(); }

  inline const runtime_type & curtype() const { return (*types_)[pos_]; }
  inline unsigned curshape() const { return curtype().n(); }

  template <typename T>
  inline void
  set(T t, size_t idx)
  {
    MICROSCOPES_ASSERT(pos_ < nfeatures());
    MICROSCOPES_ASSERT(cursor_);
    MICROSCOPES_ASSERT(idx < curshape());
    const size_t s = runtime_type_traits::PrimitiveTypeSize(curtype().t());
    runtime_cast::uncast<T>(cursor_ + idx * s, curtype().t(), t);
  }

  void
  set(const row_accessor &acc)
  {
    MICROSCOPES_DCHECK(curshape() == acc.curshape(), "shapes do not match");
    MICROSCOPES_ASSERT(cursor_);
    MICROSCOPES_ASSERT(acc.cursor());
    const size_t s0 = runtime_type_traits::PrimitiveTypeSize(curtype().t());
    const size_t s1 = runtime_type_traits::PrimitiveTypeSize(acc.curtype().t());
    for (unsigned i = 0; i < curshape(); i++)
      runtime_cast::copy(
          cursor_ + i * s0, curtype().t(),
          acc.cursor() + i * s1, acc.curtype().t());
  }

  inline void
  bump()
  {
    MICROSCOPES_ASSERT(pos_ <= nfeatures());
    cursor_ += runtime_type_traits::RuntimeTypeSize(curtype());
    pos_++;
  }

  inline bool end() const { return pos_ == nfeatures(); }

  inline void
  reset()
  {
    cursor_ = data_;
    pos_ = 0;
  }

  std::string debug_str() const;

private:
  uint8_t *data_;
  const std::vector<runtime_type> *types_;

  uint8_t *cursor_;
  size_t pos_;
};

class dataview {
protected:
  dataview(size_t n, const std::vector<runtime_type> &types);

  inline const std::vector<size_t> & offsets() const { return offsets_; }

  // in bytes
  inline size_t rowsize() const { return rowsize_; }
  inline size_t maskrowsize() const { return maskrowsize_; }

public:
  virtual ~dataview() {}

  // implementations need to provide the following API
  virtual row_accessor get() const = 0;
  virtual size_t index() const = 0;
  virtual void next() = 0;
  virtual void reset() = 0;
  virtual bool end() const = 0;

  inline size_t size() const { return n_; }
  inline const std::vector<runtime_type> & types() const { return types_; }

private:
  size_t n_;

  std::vector<runtime_type> types_;
  std::vector<size_t> offsets_;
  size_t rowsize_;
  size_t maskrowsize_;
};

class row_major_dataview : public dataview {
public:
  row_major_dataview(const uint8_t *data,
                     const bool *mask,
                     size_t n,
                     const std::vector<runtime_type> &types);
  row_accessor get() const override;
  size_t index() const override;
  void next() override;
  void reset() override;
  bool end() const override;

  inline void reset_permutation() { pi_.clear(); }
  void permute(rng_t &rng);

private:
  const uint8_t *data_;
  const bool *mask_;
  size_t pos_;

  std::vector<size_t> pi_;
};

} // namespace common
} // namespace microscopes
<|endoftext|>


<commit_before>//
// Copyright Antoine Leblanc 2010 - 2015
// Distributed under the MIT license.
//
// http://nauths.fr
// http://github.com/nicuveo
// mailto://antoine.jp.leblanc@gmail.com
//

#ifndef TOOLS_DUAL_ITERATOR_HH_
# define TOOLS_DUAL_ITERATOR_HH_

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Includes

# include <boost/iterator/iterator_adaptor.hpp>
# include <boost/tuple/tuple.hpp>
# include <boost/call_traits.hpp>

//HHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHHH
// Declarations

namespace tools
{

  namespace il
  {

    template <typename C>
    struct DualTrait
    {
      public:
        typedef C ContainerType;
        typedef typename ContainerType::value_type ValueType;
        typedef typename ContainerType::const_iterator IteratorType;
        typedef typename boost::call_traits<ValueType>::param_type RefType;
        typedef boost::tuple<RefType, RefType> DualType;
    };

    template <typename E, typename C>
    struct AdaptorTrait
    {
      public:
        typedef boost::iterator_adaptor<
        E,
        typename DualTrait<C>::IteratorType,
        typename DualTrait<C>::DualType,
        boost::use_default,
        typename DualTrait<C>::DualType> AdaptorType;
    };

  }

  template <typename C>
  class DualIterator : public il::AdaptorTrait<DualIterator<C>, C>::AdaptorType
  {
    public:
      // types

      typedef DualIterator<C> SelfType;
      typedef il::DualTrait<C> TraitType;
      typedef typename il::AdaptorTrait<SelfType, C>::AdaptorType AdaptorType;
      typedef typename TraitType::IteratorType IteratorType;
      typedef typename TraitType::DualType DualType;
      typedef typename TraitType::RefType RefType;

      // constructors

      DualIterator()
      {
      }

      template <typename I>
      DualIterator(I const& other)
      : AdaptorType(other), b_(other.b_), e_(other.e_)
      {
      }

      template <typename I>
      DualIterator(I const& b, I const& e, I const& i)
        : AdaptorType(i), b_(b), e_(e)
      {
      }

    private:
      friend class boost::iterator_core_access;

      // data

      IteratorType b_;
      IteratorType e_;

      // internal operations

      DualType dereference() const
      {
        IteratorType i1 = this->base_reference();
        IteratorType i2 = i1;

        if (++i2 == e_)
          i2 = b_;

        return boost::tie(*i1, *i2);
      }
  };

  template <typename C>
  struct DualType
  {
    public:
      typedef typename DualIterator<C>::DualType Type;
  };

  template <typename C>
  inline DualIterator<C> begin(C const& c)
  {
    return DualIterator<C>(c.begin(), c.end(), c.begin());
  }

  template <typename C>
  inline DualIterator<C> end(C const& c)
  {
    return DualIterator<C>(c.begin(), c.end(), c.end());
  }

  template <typename C>
  inline std::pair<DualIterator<C>, DualIterator<C> > range(C const& c)
  {
    return std::make_pair(begin(c), end(c));
  }

  template <typename T1, typename T2>
  inline typename boost::call_traits<T1>::const_reference
  first(boost::tuple<T1, T2> const& dt)
  {
    return dt.template get<0>();
  }

  template <typename T1, typename T2>
  inline typename boost::call_traits<T2>::const_reference
  second(boost::tuple<T1, T2> const& dt)
  {
    return dt.template get<1>();
  }

}

#endif /* !TOOLS_DUAL_ITERATOR_HH_ */
<commit_msg>Removed unused file.<commit_after><|endoftext|>


<commit_before>#include "ros/ros.h"
#include "std_msgs/String.h"
#include <uranus_dp/JoystickUranus.h>
#include <iostream>
#include <string.h>
#include "geometry_msgs/Twist.h"

class SetpointProcessing{
public:
    SetpointProcessing(){
        pub = n.advertise<std_msgs::String>("s1", 1);
        sub = n.subscribe("joy_input", 1, &SetpointProcessing::callback, this);
    }

    void callback(const uranus_dp::JoystickUranus& input)
    {
        geometry_msgs::Twist output;
        output.linear.x = input.surge;
        output.linear.y = input.sway;
        output.linear.z = input.heave;
        output.angular.x = input.roll;
        output.angular.y = input.pitch;
        output.angular.z = input.yaw;
    }

private:
    ros::NodeHandle n;
    ros::Publisher  pub;
    ros::Subscriber sub;
};

int main(int argc, char** argv){
    ros::init(argc, argv, "setpoint_processing");

    SetpointProcessing f;

    ros::spin();

    return 0;
}
<commit_msg>Add code for processing movement joystick input<commit_after>#include "ros/ros.h"
#include "std_msgs/String.h"
#include <uranus_dp/JoystickUranus.h>
#include <iostream>
#include <string.h>
#include "geometry_msgs/Twist.h"
#include <joystick/directional_input.h>

// Delivers twist.msg

class SetpointProcessing{
public:
    SetpointProcessing(){
        pub = n.advertise<geometry_msgs::Twist>("temp", 1);
        sub = n.subscribe("joy_input", 1, &SetpointProcessing::callback, this);
    }

    void callback(const joystick::directional_input& input)
    {
        geometry_msgs::Twist output;

        output.linear.x = (input.strafe_X/STRAFE_RANGE)*MAX_LINEAR_X;
        output.linear.y = (input.strafe_Y/STRAFE_RANGE)*MAX_LINEAR_Y;
        output.linear.z = (input.ascend/ASCEND_RANGE)*MAX_LINEAR_Z;
        output.angular.x = 0.0;
        output.angular.y = (input.turn_Y/TURN_RANGE)*MAX_ANGULAR_X;
        output.angular.z = (input.turn_X/TURN_RANGE)*MAX_ANGULAR_Z;

        pub.publish(output);
    }

private:
    ros::NodeHandle n;
    ros::Publisher  pub;
    ros::Subscriber sub;

    static const double MAX_LINEAR_X  = 1.0;
    static const double MAX_LINEAR_Y  = 1.0;
    static const double MAX_LINEAR_Z  = 1.0;
    static const double MAX_ANGULAR_X = 1.0;
    static const double MAX_ANGULAR_Y = 1.0;
    static const double MAX_ANGULAR_Z = 1.0;

    static const int STRAFE_RANGE = (2 << 16);
    static const int TURN_RANGE   = (2 << 16);
    static const int ASCEND_RANGE = (2 << 16);
};

int main(int argc, char** argv){
    ros::init(argc, argv, "setpoint_processing");

    SetpointProcessing f;

    ros::spin();

    return 0;
}
<|endoftext|>


<commit_before>#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include <tacopie/typedefs.hpp>

namespace tacopie {

class tcp_socket {
public:
  //! possible types of a TCP socket, either a client or a server
  //! type is used to prevent the used of client specific operations on a server socket (and vice-versa)
  //!
  //! UNKNOWN is used when socket type could not be determined for now
  //! for example, when
  enum class type {
    CLIENT,
    SERVER,
    UNKNOWN
  };

public:
  //! ctor & dtor
  tcp_socket(void);
  ~tcp_socket(void) = default;

  //! custom ctor
  //! build socket from existing file descriptor
  tcp_socket(fd_t fd, const std::string& host, std::uint32_t port, type t);

  //! move ctor
  tcp_socket(tcp_socket&&);

  //! copy ctor & assignment operator
  tcp_socket(const tcp_socket&) = delete;
  tcp_socket& operator=(const tcp_socket&) = delete;

public:
  //! comparison operator
  bool operator==(const tcp_socket& rhs) const;
  bool operator!=(const tcp_socket& rhs) const;

public:
  //! client socket operations
  std::vector<char> recv(std::size_t size_to_read);
  std::size_t send(const std::vector<char>& data, std::size_t size_to_write);
  void connect(const std::string& host, std::uint32_t port);

  //! server socket operations
  void bind(const std::string& host, std::uint32_t port);
  void listen(std::size_t max_connection_queue);
  tcp_socket accept(void);

  //! general socket operations
  void close(void);

public:
  //! get socket name information
  const std::string& get_host(void) const;
  std::uint32_t get_port(void) const;

  //! get socket type
  type get_type(void) const;
  //! set type, should be used if some operations determining socket type
  //! have been done on the behalf of the tcp_socket instance
  void set_type(type t);

  //! direct access to the underlying fd
  fd_t get_fd(void) const;

private:
  //! create a new socket if no socket has been initialized yet
  void create_socket_if_necessary(void);

  //! check whether the current socket has an approriate type for that kind of operation
  //! if current type is UNKNOWN, update internal type with given type
  void check_or_set_type(type t);

private:
  //! fd associated to the socket
  fd_t m_fd;

  //! socket name information
  std::string m_host;
  std::uint32_t m_port;

  //! type of the socket
  type m_type;
};

} //! tacopie
<commit_msg>comment typo<commit_after>#pragma once

#include <cstdint>
#include <string>
#include <vector>

#include <tacopie/typedefs.hpp>

namespace tacopie {

class tcp_socket {
public:
  //! possible types of a TCP socket, either a client or a server
  //! type is used to prevent the used of client specific operations on a server socket (and vice-versa)
  //!
  //! UNKNOWN is used when socket type could not be determined for now
  enum class type {
    CLIENT,
    SERVER,
    UNKNOWN
  };

public:
  //! ctor & dtor
  tcp_socket(void);
  ~tcp_socket(void) = default;

  //! custom ctor
  //! build socket from existing file descriptor
  tcp_socket(fd_t fd, const std::string& host, std::uint32_t port, type t);

  //! move ctor
  tcp_socket(tcp_socket&&);

  //! copy ctor & assignment operator
  tcp_socket(const tcp_socket&) = delete;
  tcp_socket& operator=(const tcp_socket&) = delete;

public:
  //! comparison operator
  bool operator==(const tcp_socket& rhs) const;
  bool operator!=(const tcp_socket& rhs) const;

public:
  //! client socket operations
  std::vector<char> recv(std::size_t size_to_read);
  std::size_t send(const std::vector<char>& data, std::size_t size_to_write);
  void connect(const std::string& host, std::uint32_t port);

  //! server socket operations
  void bind(const std::string& host, std::uint32_t port);
  void listen(std::size_t max_connection_queue);
  tcp_socket accept(void);

  //! general socket operations
  void close(void);

public:
  //! get socket name information
  const std::string& get_host(void) const;
  std::uint32_t get_port(void) const;

  //! get socket type
  type get_type(void) const;
  //! set type, should be used if some operations determining socket type
  //! have been done on the behalf of the tcp_socket instance
  void set_type(type t);

  //! direct access to the underlying fd
  fd_t get_fd(void) const;

private:
  //! create a new socket if no socket has been initialized yet
  void create_socket_if_necessary(void);

  //! check whether the current socket has an approriate type for that kind of operation
  //! if current type is UNKNOWN, update internal type with given type
  void check_or_set_type(type t);

private:
  //! fd associated to the socket
  fd_t m_fd;

  //! socket name information
  std::string m_host;
  std::uint32_t m_port;

  //! type of the socket
  type m_type;
};

} //! tacopie
<|endoftext|>


<commit_before>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/ClangInternalState.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/SourceManager.h"

#include "llvm/ADT/SmallString.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"

#include <cstdio>
#include <string>
#include <time.h>

using namespace clang;

namespace cling {
  ClangInternalState::ClangInternalState(ASTContext& C, llvm::Module& M,
                                         const std::string& name)
    : m_ASTContext(C), m_Module(M), m_DiffCommand("diff -u "), m_Name(name) {
    store();
  }

  ClangInternalState::~ClangInternalState() {
    // cleanup the temporary files:
    remove(m_LookupTablesFile.c_str());
    remove(m_IncludedFilesFile.c_str());
    remove(m_ASTFile.c_str());
    remove(m_LLVMModuleFile.c_str());
  }

  void ClangInternalState::store() {
    m_LookupTablesOS.reset(createOutputFile("lookup", &m_LookupTablesFile));
    m_IncludedFilesOS.reset(createOutputFile("included", &m_IncludedFilesFile));
    m_ASTOS.reset(createOutputFile("ast", &m_ASTFile));
    m_LLVMModuleOS.reset(createOutputFile("module", &m_LLVMModuleFile));

    printLookupTables(*m_LookupTablesOS.get(), m_ASTContext);
    printIncludedFiles(*m_IncludedFilesOS.get(),
                       m_ASTContext.getSourceManager());
    printAST(*m_ASTOS.get(), m_ASTContext);
    printLLVMModule(*m_LLVMModuleOS.get(), m_Module);
  }
  namespace {
    std::string getCurrentTimeAsString() {
      time_t rawtime;
      struct tm * timeinfo;
      char buffer [80];

      time (&rawtime);
      timeinfo = localtime (&rawtime);

      strftime (buffer, 80, "%I_%M_%S", timeinfo);
      return buffer;
    }
  }

  // Copied with modifications from CompilerInstance.cpp
  llvm::raw_fd_ostream*
  ClangInternalState::createOutputFile(llvm::StringRef OutFile,
                                       std::string *TempPathName/*=0*/,
                                       bool RemoveFileOnSignal/*=true*/) {
    llvm::OwningPtr<llvm::raw_fd_ostream> OS;
    std::string OSFile;
    llvm::SmallString<256> OutputPath;
    llvm::sys::path::system_temp_directory(/*erasedOnReboot*/false, OutputPath);

    // Only create the temporary if the parent directory exists (or create
    // missing directories is true) and we can actually write to OutPath,
    // otherwise we want to fail early.
    llvm::SmallString<256> TempPath(OutputPath);
    llvm::sys::fs::make_absolute(TempPath);
    assert(llvm::sys::fs::is_directory(TempPath.str()) && "Must be a folder.");
    // Create a temporary file.
    llvm::sys::path::append(TempPath, OutFile);
    TempPath += "-" + getCurrentTimeAsString();
    TempPath += "-%%%%%%%%";
    int fd;
    if (llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath)
        == llvm::errc::success) {
      OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
      OSFile = TempPath.str();
    }

    // Make sure the out stream file gets removed if we crash.
    if (RemoveFileOnSignal)
      llvm::sys::RemoveFileOnSignal(OSFile);

    if (TempPathName)
      *TempPathName = OSFile;

    return OS.take();
  }

  void ClangInternalState::compare(ClangInternalState& other) {
    std::string differences = "";
    if (differentContent(m_LookupTablesFile, other.m_LookupTablesFile,
                         differences)) {
      llvm::errs() << "Differences in the lookup tablse\n";
      llvm::errs() << differences << "\n";
      differences = "";
    }

    if (differentContent(m_IncludedFilesFile, other.m_IncludedFilesFile,
                         differences)) {
      llvm::errs() << "Differences in the included files\n";
      llvm::errs() << differences << "\n";
      differences = "";
    }

    if (differentContent(m_ASTFile, other.m_ASTFile, differences)) {
      llvm::errs() << "Differences in the AST \n";
      llvm::errs() << differences << "\n";
      differences = "";
    }

    if (differentContent(m_LLVMModuleFile, other.m_LLVMModuleFile, differences)){
      llvm::errs() << "Differences in the llvm Module \n";
      llvm::errs() << differences << "\n";
      differences = "";
    }
  }

  bool ClangInternalState::differentContent(const std::string& file1,
                                            const std::string& file2,
                                            std::string& differences) const {
    FILE* pipe = popen((m_DiffCommand + file1 + " " + file2).c_str() , "r");
    assert(pipe && "Error creating the pipe");
    assert(differences.empty() && "Must be empty");

    char buffer[128];
    while(!feof(pipe)) {
      if(fgets(buffer, 128, pipe) != NULL)
        differences += buffer;
    }
    pclose(pipe);
    return !differences.empty();
  }

  class DumpLookupTables : public RecursiveASTVisitor<DumpLookupTables> {
  private:
    //llvm::raw_ostream& m_OS;
  public:
    //DumpLookupTables(llvm::raw_ostream& OS) : m_OS(OS) { }
    DumpLookupTables(llvm::raw_ostream&) { }
    bool VisitDeclContext(DeclContext* DC) {
      //DC->dumpLookups(m_OS);
      return true;
    }
  };

  void ClangInternalState::printLookupTables(llvm::raw_ostream& Out,
                                             ASTContext& C) {
    DumpLookupTables dumper(Out);
    dumper.TraverseDecl(C.getTranslationUnitDecl());
  }

  void ClangInternalState::printIncludedFiles(llvm::raw_ostream& Out,
                                              SourceManager& SM) {
    for (clang::SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
           E = SM.fileinfo_end(); I != E; ++I) {
      const clang::SrcMgr::ContentCache &C = *I->second;
      const clang::FileEntry *FE = C.OrigEntry;
      // Our error recovery purges the cache of the FileEntry, but keeps
      // the FileEntry's pointer so that if it was used by smb (like the
      // SourceManager) it wouldn't be dangling. In that case we shouldn't
      // print the FileName, because semantically it is not there.
      if (!FE->getSize() && !FE->getModificationTime())
        continue;
      std::string fileName(FE->getName());
      if (!(fileName.compare(0, 5, "/usr/") == 0 &&
            fileName.find("/bits/") != std::string::npos)) {
        Out << fileName << '\n';
      }
    }
  }

  void ClangInternalState::printAST(llvm::raw_ostream& Out, ASTContext& C) {
    TranslationUnitDecl* TU = C.getTranslationUnitDecl();
    unsigned Indentation = 0;
    bool PrintInstantiation = false;
    std::string ErrMsg;
    clang::PrintingPolicy policy = C.getPrintingPolicy();
    TU->print(Out, policy, Indentation, PrintInstantiation);
    Out.flush();
  }

  void ClangInternalState::printLLVMModule(llvm::raw_ostream& Out,
                                           llvm::Module& M) {
    M.print(Out, /*AssemblyAnnotationWriter*/ 0);
  }
} // end namespace cling
<commit_msg>Add future wanna-track property.<commit_after>//------------------------------------------------------------------------------
// CLING - the C++ LLVM-based InterpreterG :)
// version: $Id$
// author:  Vassil Vassilev <vasil.georgiev.vasilev@cern.ch>
//------------------------------------------------------------------------------

#include "cling/Interpreter/ClangInternalState.h"

#include "clang/AST/ASTContext.h"
#include "clang/AST/RecursiveASTVisitor.h"
#include "clang/Basic/SourceManager.h"

#include "llvm/ADT/SmallString.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/FileSystem.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include "llvm/Support/Signals.h"

#include <cstdio>
#include <string>
#include <time.h>

using namespace clang;

namespace cling {
  ClangInternalState::ClangInternalState(ASTContext& C, llvm::Module& M,
                                         const std::string& name)
    : m_ASTContext(C), m_Module(M), m_DiffCommand("diff -u "), m_Name(name) {
    store();
  }

  ClangInternalState::~ClangInternalState() {
    // cleanup the temporary files:
    remove(m_LookupTablesFile.c_str());
    remove(m_IncludedFilesFile.c_str());
    remove(m_ASTFile.c_str());
    remove(m_LLVMModuleFile.c_str());
  }

  void ClangInternalState::store() {
    m_LookupTablesOS.reset(createOutputFile("lookup", &m_LookupTablesFile));
    m_IncludedFilesOS.reset(createOutputFile("included", &m_IncludedFilesFile));
    m_ASTOS.reset(createOutputFile("ast", &m_ASTFile));
    m_LLVMModuleOS.reset(createOutputFile("module", &m_LLVMModuleFile));

    printLookupTables(*m_LookupTablesOS.get(), m_ASTContext);
    printIncludedFiles(*m_IncludedFilesOS.get(),
                       m_ASTContext.getSourceManager());
    printAST(*m_ASTOS.get(), m_ASTContext);
    printLLVMModule(*m_LLVMModuleOS.get(), m_Module);
  }
  namespace {
    std::string getCurrentTimeAsString() {
      time_t rawtime;
      struct tm * timeinfo;
      char buffer [80];

      time (&rawtime);
      timeinfo = localtime (&rawtime);

      strftime (buffer, 80, "%I_%M_%S", timeinfo);
      return buffer;
    }
  }

  // Copied with modifications from CompilerInstance.cpp
  llvm::raw_fd_ostream*
  ClangInternalState::createOutputFile(llvm::StringRef OutFile,
                                       std::string *TempPathName/*=0*/,
                                       bool RemoveFileOnSignal/*=true*/) {
    llvm::OwningPtr<llvm::raw_fd_ostream> OS;
    std::string OSFile;
    llvm::SmallString<256> OutputPath;
    llvm::sys::path::system_temp_directory(/*erasedOnReboot*/false, OutputPath);

    // Only create the temporary if the parent directory exists (or create
    // missing directories is true) and we can actually write to OutPath,
    // otherwise we want to fail early.
    llvm::SmallString<256> TempPath(OutputPath);
    llvm::sys::fs::make_absolute(TempPath);
    assert(llvm::sys::fs::is_directory(TempPath.str()) && "Must be a folder.");
    // Create a temporary file.
    llvm::sys::path::append(TempPath, OutFile);
    TempPath += "-" + getCurrentTimeAsString();
    TempPath += "-%%%%%%%%";
    int fd;
    if (llvm::sys::fs::createUniqueFile(TempPath.str(), fd, TempPath)
        == llvm::errc::success) {
      OS.reset(new llvm::raw_fd_ostream(fd, /*shouldClose=*/true));
      OSFile = TempPath.str();
    }

    // Make sure the out stream file gets removed if we crash.
    if (RemoveFileOnSignal)
      llvm::sys::RemoveFileOnSignal(OSFile);

    if (TempPathName)
      *TempPathName = OSFile;

    return OS.take();
  }

  void ClangInternalState::compare(ClangInternalState& other) {
    std::string differences = "";
    if (differentContent(m_LookupTablesFile, other.m_LookupTablesFile,
                         differences)) {
      llvm::errs() << "Differences in the lookup tablse\n";
      llvm::errs() << differences << "\n";
      differences = "";
    }

    if (differentContent(m_IncludedFilesFile, other.m_IncludedFilesFile,
                         differences)) {
      llvm::errs() << "Differences in the included files\n";
      llvm::errs() << differences << "\n";
      differences = "";
    }

    if (differentContent(m_ASTFile, other.m_ASTFile, differences)) {
      llvm::errs() << "Differences in the AST \n";
      llvm::errs() << differences << "\n";
      differences = "";
    }

    if (differentContent(m_LLVMModuleFile, other.m_LLVMModuleFile, differences)){
      llvm::errs() << "Differences in the llvm Module \n";
      llvm::errs() << differences << "\n";
      differences = "";
    }
  }

  bool ClangInternalState::differentContent(const std::string& file1,
                                            const std::string& file2,
                                            std::string& differences) const {
    FILE* pipe = popen((m_DiffCommand + file1 + " " + file2).c_str() , "r");
    assert(pipe && "Error creating the pipe");
    assert(differences.empty() && "Must be empty");

    char buffer[128];
    while(!feof(pipe)) {
      if(fgets(buffer, 128, pipe) != NULL)
        differences += buffer;
    }
    pclose(pipe);
    return !differences.empty();
  }

  class DumpLookupTables : public RecursiveASTVisitor<DumpLookupTables> {
  private:
    //llvm::raw_ostream& m_OS;
  public:
    //DumpLookupTables(llvm::raw_ostream& OS) : m_OS(OS) { }
    DumpLookupTables(llvm::raw_ostream&) { }
    bool VisitDeclContext(DeclContext* DC) {
      //DC->dumpLookups(m_OS);
      return true;
    }
  };

  void ClangInternalState::printLookupTables(llvm::raw_ostream& Out,
                                             ASTContext& C) {
    DumpLookupTables dumper(Out);
    dumper.TraverseDecl(C.getTranslationUnitDecl());
  }

  void ClangInternalState::printIncludedFiles(llvm::raw_ostream& Out,
                                              SourceManager& SM) {
    for (clang::SourceManager::fileinfo_iterator I = SM.fileinfo_begin(),
           E = SM.fileinfo_end(); I != E; ++I) {
      const clang::SrcMgr::ContentCache &C = *I->second;
      const clang::FileEntry *FE = C.OrigEntry;
      // Our error recovery purges the cache of the FileEntry, but keeps
      // the FileEntry's pointer so that if it was used by smb (like the
      // SourceManager) it wouldn't be dangling. In that case we shouldn't
      // print the FileName, because semantically it is not there.
      if (!FE->getSize() && !FE->getModificationTime())
        continue;
      std::string fileName(FE->getName());
      if (!(fileName.compare(0, 5, "/usr/") == 0 &&
            fileName.find("/bits/") != std::string::npos)) {
        Out << fileName << '\n';
      }
    }
  }

  void ClangInternalState::printAST(llvm::raw_ostream& Out, ASTContext& C) {
    TranslationUnitDecl* TU = C.getTranslationUnitDecl();
    unsigned Indentation = 0;
    bool PrintInstantiation = false;
    std::string ErrMsg;
    clang::PrintingPolicy policy = C.getPrintingPolicy();
    TU->print(Out, policy, Indentation, PrintInstantiation);
    // TODO: For future when we relpace the bump allocation with slab.
    //
    //Out << "Allocated memory: " << C.getAllocatedMemory();
    //Out << "Side table allocated memory: " << C.getSideTableAllocatedMemory();
    Out.flush();
  }

  void ClangInternalState::printLLVMModule(llvm::raw_ostream& Out,
                                           llvm::Module& M) {
    M.print(Out, /*AssemblyAnnotationWriter*/ 0);
  }
} // end namespace cling
<|endoftext|>