<commit_before>// ------------------------------------------------------------------
// pion-net: a C++ framework for building lightweight HTTP interfaces
// ------------------------------------------------------------------
// Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/test/unit_test.hpp>
#include <pion/PionConfig.hpp>
#include <pion/PionScheduler.hpp>
#include <pion/net/TCPStream.hpp>

using namespace std;
using namespace pion;
using namespace pion::net;
using boost::asio::ip::tcp;

///
/// TCPStreamTests_F: fixture used for performing TCPStream tests
///
class TCPStreamTests_F {
public:

	/// data type for a function that handles TCPStream connections
	typedef boost::function1<void,TCPStream&>	ConnectionHandler;

	// default constructor and destructor
	TCPStreamTests_F() {
	}
	virtual ~TCPStreamTests_F() {}

	/**
	 * listen for a TCP connection and call the connection handler when connected
	 *
	 * @param conn_handler function to call after a connection is established
	 */
	void acceptConnection(ConnectionHandler conn_handler) {
		// configure the acceptor service
		tcp::acceptor	tcp_acceptor(m_scheduler.getIOService());
		tcp::endpoint	tcp_endpoint(tcp::v4(), 0);
		tcp_acceptor.open(tcp_endpoint.protocol());

		// allow the acceptor to reuse the address (i.e. SO_REUSEADDR)
		tcp_acceptor.set_option(tcp::acceptor::reuse_address(true));
		tcp_acceptor.bind(tcp_endpoint);
		tcp_acceptor.listen();

		// notify test thread that we are ready to accept a connection
		{
			// wait for test thread to be waiting on the signal
			boost::unique_lock<boost::mutex> accept_lock(m_accept_mutex);
			// trigger signal to wake test thread
			m_port = tcp_acceptor.local_endpoint().port();
			m_accept_ready.notify_one();
		}

		// schedule another thread to listen for a TCP connection
		TCPStream listener_stream(m_scheduler.getIOService());
		boost::system::error_code ec = listener_stream.accept(tcp_acceptor);
		tcp_acceptor.close();
		BOOST_REQUIRE(! ec);

		// call the connection handler
		conn_handler(listener_stream);
	}

	/// sends a "Hello" to a TCPStream
	static void sendHello(TCPStream& str) {
		str << "Hello" << std::endl;
		str.flush();
	}

	/// port where acceptor listens
	int		m_port;

	/// used to schedule work across multiple threads
	PionSingleServiceScheduler		m_scheduler;

	/// used to notify test thread when acceptConnection() is ready
	boost::condition				m_accept_ready;

	/// used to sync test thread with acceptConnection()
	boost::mutex					m_accept_mutex;
};

// TCPStream Test Cases

BOOST_FIXTURE_TEST_SUITE(TCPStreamTests_S, TCPStreamTests_F)

BOOST_AUTO_TEST_CASE(checkTCPConnectToAnotherStream) {
	boost::unique_lock<boost::mutex> accept_lock(m_accept_mutex);

	// schedule another thread to listen for a TCP connection
	ConnectionHandler conn_handler(boost::bind(&TCPStreamTests_F::sendHello, _1));
	boost::thread listener_thread(boost::bind(&TCPStreamTests_F::acceptConnection,
											  this, conn_handler) );
	m_scheduler.addActiveUser();
	m_accept_ready.wait(accept_lock);

	// connect to the listener
	TCPStream client_str(m_scheduler.getIOService());
	boost::system::error_code ec;
	ec = client_str.connect(boost::asio::ip::address::from_string("127.0.0.1"), m_port);
	BOOST_REQUIRE(! ec);

	// get the hello message
	std::string response_msg;
	client_str >> response_msg;
	BOOST_CHECK_EQUAL(response_msg, "Hello");

	m_scheduler.removeActiveUser();
}

BOOST_AUTO_TEST_SUITE_END()

#define BIG_BUF_SIZE (12 * 1024)

///
/// TCPStreamBufferTests_F: fixture that includes a big data buffer used for tests
///
class TCPStreamBufferTests_F
	: public TCPStreamTests_F
{
public:
	// default constructor and destructor
	TCPStreamBufferTests_F() {
		// fill the buffer with non-random characters
		for (unsigned long n = 0; n < BIG_BUF_SIZE; ++n) {
			m_big_buf[n] = char(n);
		}
	}
	virtual ~TCPStreamBufferTests_F() {}

	/// sends the big buffer contents to a TCPStream
	void sendBigBuffer(TCPStream& str) {
		str.write(m_big_buf, BIG_BUF_SIZE);
		str.flush();
	}

	/// big data buffer used for the tests
	char m_big_buf[BIG_BUF_SIZE];
};

BOOST_FIXTURE_TEST_SUITE(TCPStreamBufferTests_S, TCPStreamBufferTests_F)

BOOST_AUTO_TEST_CASE(checkSendAndReceiveBiggerThanBuffers) {
	boost::unique_lock<boost::mutex> accept_lock(m_accept_mutex);

	// schedule another thread to listen for a TCP connection
	ConnectionHandler conn_handler(boost::bind(&TCPStreamBufferTests_F::sendBigBuffer, this, _1));
	boost::thread listener_thread(boost::bind(&TCPStreamBufferTests_F::acceptConnection,
											  this, conn_handler) );
	m_scheduler.addActiveUser();
	m_accept_ready.wait(accept_lock);

	// connect to the listener
	TCPStream client_str(m_scheduler.getIOService());
	boost::system::error_code ec;
	ec = client_str.connect(boost::asio::ip::address::from_string("127.0.0.1"), m_port);
	BOOST_REQUIRE(! ec);

	// read the big buffer contents
	char another_buf[BIG_BUF_SIZE];
	BOOST_REQUIRE(client_str.read(another_buf, BIG_BUF_SIZE));
	BOOST_CHECK_EQUAL(memcmp(m_big_buf, another_buf, BIG_BUF_SIZE), 0);

	m_scheduler.removeActiveUser();
}

BOOST_AUTO_TEST_SUITE_END()
<commit_msg>Fixing TCPStreamTests in PionNetUnitTests -- would not run on Ubuntu VM's<commit_after>// ------------------------------------------------------------------
// pion-net: a C++ framework for building lightweight HTTP interfaces
// ------------------------------------------------------------------
// Copyright (C) 2007-2008 Atomic Labs, Inc.  (http://www.atomiclabs.com)
//
// Distributed under the Boost Software License, Version 1.0.
// See http://www.boost.org/LICENSE_1_0.txt
//

#include <boost/asio.hpp>
#include <boost/bind.hpp>
#include <boost/thread.hpp>
#include <boost/function.hpp>
#include <boost/test/unit_test.hpp>
#include <pion/PionConfig.hpp>
#include <pion/PionScheduler.hpp>
#include <pion/net/TCPStream.hpp>

using namespace std;
using namespace pion;
using namespace pion::net;
using boost::asio::ip::tcp;

///
/// TCPStreamTests_F: fixture used for performing TCPStream tests
///
class TCPStreamTests_F {
public:

	/// data type for a function that handles TCPStream connections
	typedef boost::function1<void,TCPStream&>	ConnectionHandler;

	// default constructor and destructor
	TCPStreamTests_F() {
	}
	virtual ~TCPStreamTests_F() {}

	/**
	 * listen for a TCP connection and call the connection handler when connected
	 *
	 * @param conn_handler function to call after a connection is established
	 */
	void acceptConnection(ConnectionHandler conn_handler) {
		// configure the acceptor service
		tcp::acceptor	tcp_acceptor(m_scheduler.getIOService());
		tcp::endpoint	tcp_endpoint(tcp::v4(), 0);
		tcp_acceptor.open(tcp_endpoint.protocol());

		// allow the acceptor to reuse the address (i.e. SO_REUSEADDR)
		tcp_acceptor.set_option(tcp::acceptor::reuse_address(true));
		tcp_acceptor.bind(tcp_endpoint);
		tcp_acceptor.listen();

		// notify test thread that we are ready to accept a connection
		{
			// wait for test thread to be waiting on the signal
			boost::unique_lock<boost::mutex> accept_lock(m_accept_mutex);
			// trigger signal to wake test thread
			m_port = tcp_acceptor.local_endpoint().port();
			m_accept_ready.notify_one();
		}

		// schedule another thread to listen for a TCP connection
		TCPStream listener_stream(m_scheduler.getIOService());
		boost::system::error_code ec = listener_stream.accept(tcp_acceptor);
		tcp_acceptor.close();
		BOOST_REQUIRE(! ec);

		// call the connection handler
		conn_handler(listener_stream);
	}

	/// sends a "Hello" to a TCPStream
	static void sendHello(TCPStream& str) {
		str << "Hello" << std::endl;
		str.flush();
	}

	/// port where acceptor listens
	int		m_port;

	/// used to schedule work across multiple threads
	PionSingleServiceScheduler		m_scheduler;

	/// used to notify test thread when acceptConnection() is ready
	boost::condition				m_accept_ready;

	/// used to sync test thread with acceptConnection()
	boost::mutex					m_accept_mutex;
};

// TCPStream Test Cases

BOOST_FIXTURE_TEST_SUITE(TCPStreamTests_S, TCPStreamTests_F)

BOOST_AUTO_TEST_CASE(checkTCPConnectToAnotherStream) {
	boost::unique_lock<boost::mutex> accept_lock(m_accept_mutex);

	// schedule another thread to listen for a TCP connection
	ConnectionHandler conn_handler(boost::bind(&TCPStreamTests_F::sendHello, _1));
	boost::thread listener_thread(boost::bind(&TCPStreamTests_F::acceptConnection,
											  this, conn_handler) );
	m_scheduler.addActiveUser();
	m_accept_ready.wait(accept_lock);

	// connect to the listener
	TCPStream client_str(m_scheduler.getIOService());
	boost::system::error_code ec;
	ec = client_str.connect(boost::asio::ip::address::from_string("127.0.0.1"), m_port);
	BOOST_REQUIRE(! ec);

	// get the hello message
	std::string response_msg;
	client_str >> response_msg;
	BOOST_CHECK_EQUAL(response_msg, "Hello");

	client_str.close();
	listener_thread.join();
	m_scheduler.removeActiveUser();
}

BOOST_AUTO_TEST_SUITE_END()

#define BIG_BUF_SIZE (12 * 1024)

///
/// TCPStreamBufferTests_F: fixture that includes a big data buffer used for tests
///
class TCPStreamBufferTests_F
	: public TCPStreamTests_F
{
public:
	// default constructor and destructor
	TCPStreamBufferTests_F() {
		// fill the buffer with non-random characters
		for (unsigned long n = 0; n < BIG_BUF_SIZE; ++n) {
			m_big_buf[n] = char(n);
		}
	}
	virtual ~TCPStreamBufferTests_F() {}

	/// sends the big buffer contents to a TCPStream
	void sendBigBuffer(TCPStream& str) {
		str.write(m_big_buf, BIG_BUF_SIZE);
		str.flush();
	}

	/// big data buffer used for the tests
	char m_big_buf[BIG_BUF_SIZE];
};

BOOST_FIXTURE_TEST_SUITE(TCPStreamBufferTests_S, TCPStreamBufferTests_F)

BOOST_AUTO_TEST_CASE(checkSendAndReceiveBiggerThanBuffers) {
	boost::unique_lock<boost::mutex> accept_lock(m_accept_mutex);

	// schedule another thread to listen for a TCP connection
	ConnectionHandler conn_handler(boost::bind(&TCPStreamBufferTests_F::sendBigBuffer, this, _1));
	boost::thread listener_thread(boost::bind(&TCPStreamBufferTests_F::acceptConnection,
											  this, conn_handler) );
	m_scheduler.addActiveUser();
	m_accept_ready.wait(accept_lock);

	// connect to the listener
	TCPStream client_str(m_scheduler.getIOService());
	boost::system::error_code ec;
	ec = client_str.connect(boost::asio::ip::address::from_string("127.0.0.1"), m_port);
	BOOST_REQUIRE(! ec);

	// read the big buffer contents
	char another_buf[BIG_BUF_SIZE];
	BOOST_REQUIRE(client_str.read(another_buf, BIG_BUF_SIZE));
	BOOST_CHECK_EQUAL(memcmp(m_big_buf, another_buf, BIG_BUF_SIZE), 0);

	client_str.close();
	listener_thread.join();
	m_scheduler.removeActiveUser();
}

BOOST_AUTO_TEST_SUITE_END()
<|endoftext|>


<commit_before>#include "systems/collision.hpp"
#include "components/id.hpp"
#include "core/exception.hpp"

#include <anax/System.hpp>

#include <cassert>
#include <cmath>

namespace systems
{

Collision::Collision()
{
    m_sp_logger = core::logging_get_logger("collision");
}

Manifold* Collision::check_rect_collision(
    const core::Rectangle& rect1, const core::Rectangle& rect2)
{
    Manifold* p_manifold = nullptr;
    // TODO(Keegan): Don't ignore bounding box x/y positions)
    float pos_dx = rect1.x - rect2.x;
    float pos_dy = rect1.y - rect2.y;

    float x_overlap = rect1.w / 2.0f + rect2.w / 2.0f - std::abs(pos_dx);

    if (x_overlap > 0.0f)
    {
        float y_overlap = rect1.h / 2.0f + rect2.h / 2.0f - std::abs(pos_dy);
        if (y_overlap > 0.0f)
        {
            m_sp_logger->debug(
                " collision - x overlap {} y overlap {}", x_overlap, y_overlap);
            p_manifold = new Manifold();
            if (x_overlap < y_overlap)
            {
                if (pos_dx < 0)
                {
                    m_sp_logger->debug("Normal in -y");
                    p_manifold->normal.x = 1;
                    p_manifold->normal.y = 0;
                }
                else
                {
                    m_sp_logger->debug("Normal in +y");
                    p_manifold->normal.x = -1;
                    p_manifold->normal.y = 0;
                }
                p_manifold->penetration.x = x_overlap;
            }
            else
            {
                if (pos_dy < 0)
                {
                    m_sp_logger->debug("Normal in -x");
                    p_manifold->normal.x = 0;
                    p_manifold->normal.y = 1;
                }
                else
                {
                    m_sp_logger->debug("Normal in +x");
                    p_manifold->normal.x = 0;
                    p_manifold->normal.y = -1;
                }
                p_manifold->penetration.y = y_overlap;
            }
        }
    }
    return p_manifold;
}

Manifold* systems::Collision::check_collision(
    anax::Entity& e1, anax::Entity& e2)
{
    throw_if_missing_component<components::TransformComponent>(e1);
    auto& transform1 = e1.getComponent<components::TransformComponent>();

    throw_if_missing_component<components::TransformComponent>(e2);
    auto& transform2 = e2.getComponent<components::TransformComponent>();

    throw_if_missing_component<components::Collision>(e1);
    auto& bbox1 = e1.getComponent<components::Collision>().bounding_box;

    throw_if_missing_component<components::Collision>(e2);
    auto& bbox2 = e2.getComponent<components::Collision>().bounding_box;

    core::Rectangle rect1{transform1.pos_x + bbox1.x,
        transform1.pos_y + bbox1.y,
        bbox1.w,
        bbox1.h};
    core::Rectangle rect2{transform2.pos_x + bbox2.x,
        transform2.pos_y + bbox2.y,
        bbox2.w,
        bbox2.h};

    return check_rect_collision(rect1, rect2);
}

Manifold* Collision::check_level_collision(
    anax::Entity& e, core::Level* p_level)
{
    throw_if_missing_component<components::TransformComponent>(e);
    auto& transform = e.getComponent<components::TransformComponent>();

    throw_if_missing_component<components::Collision>(e);
    auto& bbox = e.getComponent<components::Collision>().bounding_box;

    auto p_manifold = new Manifold();
    bool collision = false;

    int level_x, level_y, level_layers;
    assert(p_level != nullptr);
    p_level->get_size(level_x, level_y, level_layers);
    level_x *= p_level->get_scale();
    level_y *= p_level->get_scale();
    if (transform.pos_x - bbox.w / 2.0f < 0.0f)
    {
        collision = true;
        p_manifold->normal.x = -1.0f;
        p_manifold->penetration.x = 0.0 - (transform.pos_x - bbox.w / 2.0f);
    }
    else if (transform.pos_x + bbox.w / 2.0f > level_x)
    {
        collision = true;
        p_manifold->normal.x = 1.0f;
        p_manifold->penetration.x = level_x - transform.pos_x + bbox.w / 2.0f;
    }
    if (transform.pos_y - bbox.h / 2.0f < 0.0f)
    {
        collision = true;
        p_manifold->normal.y = -1.0f;
        p_manifold->penetration.y = 0.0f - transform.pos_y - bbox.h / 2.0f;
    }
    else if (transform.pos_y + bbox.h / 2.0f > level_y)
    {
        collision = true;
        p_manifold->normal.y = 1.0f;
        p_manifold->penetration.y = level_y - transform.pos_y + bbox.h / 2.0f;
    }
    if (collision)
    {
        return p_manifold;
    }
    else
    {
        delete p_manifold;
        return nullptr;
    }
}

void Collision::resolve_collision(
    anax::Entity& e1, anax::Entity& e2, Manifold* p_manifold)
{
    assert(p_manifold != nullptr);

    if (!e1.hasComponent<components::PhysicsComponent>() ||
        !e2.hasComponent<components::PhysicsComponent>())
    {
        return;
    }
    auto& physics2 = e2.getComponent<components::PhysicsComponent>();
    auto& physics1 = e1.getComponent<components::PhysicsComponent>();

    throw_if_missing_component<components::TransformComponent>(e1);
    auto& transform1 = e1.getComponent<components::TransformComponent>();

    throw_if_missing_component<components::TransformComponent>(e2);
    auto& transform2 = e2.getComponent<components::TransformComponent>();
    do_resolve_collision(
        &physics1, &transform1, &physics2, &transform2, p_manifold);
}

void Collision::resolve_collision(anax::Entity& e1, Manifold* p_manifold)
{
    const float level_mass = 0.0f;
    const float level_friction = 0.0f;
    const float level_restitution = 0.0f;
    const float level_vel_x = 0.0f;
    const float level_vel_y = 0.0f;
    const float level_force_x = 0.0f;
    const float level_force_y = 0.0f;

    const float level_pos_x = 0.0f;
    const float level_pos_y = 0.0f;
    const float level_size_x = 0.0f;
    const float level_size_y = 0.0f;
    const float level_rotation = 0.0f;
    const bool level_flip_vert = false;
    const bool level_flip_horiz = false;
    assert(p_manifold != nullptr);

    if (!e1.hasComponent<components::PhysicsComponent>())
    {
        return;
    }
    auto& physics1 = e1.getComponent<components::PhysicsComponent>();
    auto physics2 = components::PhysicsComponent{level_mass,
        level_friction,
        level_restitution,
        level_vel_x,
        level_vel_y,
        level_force_x,
        level_force_y};

    throw_if_missing_component<components::TransformComponent>(e1);
    auto& transform1 = e1.getComponent<components::TransformComponent>();
    auto transform2 = components::TransformComponent{level_pos_x,
        level_pos_y,
        level_size_x,
        level_size_y,
        level_rotation,
        level_flip_vert,
        level_flip_horiz};

    do_resolve_collision(
        &physics1, &transform1, &physics2, &transform2, p_manifold);
}

void Collision::do_resolve_collision(components::PhysicsComponent* p_physics1,
    components::TransformComponent* p_transform1,
    components::PhysicsComponent* p_physics2,
    components::TransformComponent* p_transform2,
    Manifold* p_manifold)
{
    assert(p_manifold != nullptr);
    assert(p_physics1 != nullptr);
    assert(p_transform1 != nullptr);
    assert(p_physics2 != nullptr);
    assert(p_transform2 != nullptr);

    float vel_dx = p_physics2->velocity.x - p_physics1->velocity.x;
    float vel_dy = p_physics2->velocity.y - p_physics1->velocity.y;

    float vel_normal =
        vel_dx * p_manifold->normal.x + vel_dy * p_manifold->normal.y;

    m_sp_logger->debug("Normal velocity is {}", vel_normal);
    m_sp_logger->debug("rel velocity is x{}, y{}", vel_dx, vel_dy);
    if (vel_normal > 0)
    {
        m_sp_logger->debug("Objects are moving away");
        return;
    }
    // TODO(Keegan): Add restitution calculation
    const float restitution =
        std::max(p_physics1->restitution, p_physics2->restitution);

    float impulse = -(1.0f * restitution) * vel_normal;

    // TODO(Keegan): Add mass consideration? Or keep in movement?

    float impulse_x = impulse * p_manifold->normal.x;
    float impulse_y = impulse * p_manifold->normal.y;

    m_sp_logger->debug("impulse is x{}, y{}", impulse_x, impulse_y);

    p_physics1->force.x -= impulse_x;
    p_physics2->force.x += impulse_x;

    p_physics1->force.y -= impulse_y;
    p_physics2->force.y += impulse_y;

    m_sp_logger->debug(
        "entity1 force is x{}, y{}", p_physics1->force.x, p_physics1->force.y);
    m_sp_logger->debug(
        "entity2 force is x{}, y{}", p_physics2->force.x, p_physics2->force.y);

    const float positional_percent = 0.2;
    const float positional_slop = 0.01;
    float x_correction =
        std::max(p_manifold->penetration.x - positional_slop, 0.0f) /
        (p_physics1->inv_mass + p_physics2->inv_mass) * positional_percent *
        p_manifold->normal.x;
    float y_correction =
        std::max(p_manifold->penetration.y - positional_slop, 0.0f) /
        (p_physics1->inv_mass + p_physics2->inv_mass) * positional_percent *
        p_manifold->normal.y;
    p_transform1->pos_x -= p_physics1->inv_mass * x_correction;
    p_transform1->pos_y -= p_physics1->inv_mass * y_correction;
    p_transform2->pos_x += p_physics2->inv_mass * x_correction;
    p_transform2->pos_y += p_physics2->inv_mass * y_correction;
}

void Collision::update(core::Level* p_level)
{
    auto colliders = getEntities();

    for (std::size_t i = 0; i < colliders.size(); ++i)
    {
        auto& e1 = colliders[i];

        // No hasComponent check needed since system filters entities
        if (!e1.getComponent<components::Collision>().can_cause_events)
        {
            continue;
        }
        if (p_level != nullptr)
        {
            auto up_manifold =
                std::unique_ptr<Manifold>(check_level_collision(e1, p_level));
            if (up_manifold)
            {
                resolve_collision(e1, up_manifold.get());
            }
        }
        for (std::size_t j = i + 1; j < colliders.size(); ++j)
        {
            auto& e2 = colliders[j];
            auto up_manifold =
                std::unique_ptr<Manifold>(check_collision(e1, e2));
            if (up_manifold)
            {
                resolve_collision(e1, e2, up_manifold.get());
                check_trigger(e1, e2, up_manifold.get());
            }
        }
    }
}

void Collision::check_trigger(
    anax::Entity& e1, anax::Entity& e2, Manifold* p_manifold)
{
    if (e1.hasComponent<components::Trigger>())
    {
        auto msg = e1.getComponent<components::Trigger>().trigger_msg;
        m_trigger_signal.emit(msg, e2);
    }
    else if (e2.hasComponent<components::Trigger>())
    {
        auto msg = e2.getComponent<components::Trigger>().trigger_msg;
        m_trigger_signal.emit(msg, e1);
    }
}

} // namespace systems
<commit_msg>Collision: Check collision against level<commit_after>#include "systems/collision.hpp"
#include "components/id.hpp"
#include "core/exception.hpp"

#include <anax/System.hpp>

#include <cassert>
#include <cmath>

namespace systems
{

Collision::Collision()
{
    m_sp_logger = core::logging_get_logger("collision");
}

Manifold* Collision::check_rect_collision(
    const core::Rectangle& rect1, const core::Rectangle& rect2)
{
    Manifold* p_manifold = nullptr;
    // TODO(Keegan): Don't ignore bounding box x/y positions)
    float pos_dx = rect1.x - rect2.x;
    float pos_dy = rect1.y - rect2.y;

    float x_overlap = rect1.w / 2.0f + rect2.w / 2.0f - std::abs(pos_dx);

    if (x_overlap > 0.0f)
    {
        float y_overlap = rect1.h / 2.0f + rect2.h / 2.0f - std::abs(pos_dy);
        if (y_overlap > 0.0f)
        {
            m_sp_logger->debug(
                " collision - x overlap {} y overlap {}", x_overlap, y_overlap);
            p_manifold = new Manifold();
            if (x_overlap < y_overlap)
            {
                if (pos_dx < 0)
                {
                    m_sp_logger->debug("Normal in -y");
                    p_manifold->normal.x = 1;
                    p_manifold->normal.y = 0;
                }
                else
                {
                    m_sp_logger->debug("Normal in +y");
                    p_manifold->normal.x = -1;
                    p_manifold->normal.y = 0;
                }
                p_manifold->penetration.x = x_overlap;
            }
            else
            {
                if (pos_dy < 0)
                {
                    m_sp_logger->debug("Normal in -x");
                    p_manifold->normal.x = 0;
                    p_manifold->normal.y = 1;
                }
                else
                {
                    m_sp_logger->debug("Normal in +x");
                    p_manifold->normal.x = 0;
                    p_manifold->normal.y = -1;
                }
                p_manifold->penetration.y = y_overlap;
            }
        }
    }
    return p_manifold;
}

Manifold* systems::Collision::check_collision(
    anax::Entity& e1, anax::Entity& e2)
{
    throw_if_missing_component<components::TransformComponent>(e1);
    auto& transform1 = e1.getComponent<components::TransformComponent>();

    throw_if_missing_component<components::TransformComponent>(e2);
    auto& transform2 = e2.getComponent<components::TransformComponent>();

    throw_if_missing_component<components::Collision>(e1);
    auto& bbox1 = e1.getComponent<components::Collision>().bounding_box;

    throw_if_missing_component<components::Collision>(e2);
    auto& bbox2 = e2.getComponent<components::Collision>().bounding_box;

    core::Rectangle rect1{transform1.pos_x + bbox1.x,
        transform1.pos_y + bbox1.y,
        bbox1.w,
        bbox1.h};
    core::Rectangle rect2{transform2.pos_x + bbox2.x,
        transform2.pos_y + bbox2.y,
        bbox2.w,
        bbox2.h};

    return check_rect_collision(rect1, rect2);
}

Manifold* Collision::check_level_collision(
    anax::Entity& e, core::Level* p_level)
{
    throw_if_missing_component<components::TransformComponent>(e);
    auto& transform = e.getComponent<components::TransformComponent>();

    throw_if_missing_component<components::Collision>(e);
    auto& bbox = e.getComponent<components::Collision>().bounding_box;

    auto p_manifold = new Manifold();
    bool collision = false;

    int level_x1, level_y1, level_x2, level_y2, level_layers;
    assert(p_level != nullptr);
    float world_x1 = transform.pos_x - (bbox.w / 2.0f);
    float world_y1 = transform.pos_y - (bbox.h / 2.0f);
    float world_x2 = transform.pos_x + (bbox.w / 2.0f);
    float world_y2 = transform.pos_y + (bbox.h / 2.0f);
    /* m_sp_logger->info( */
    /*     "World coordinates {},{}-{},{}", world_x1, world_y1, world_x2,
     * world_y2); */
    p_level->get_tile_coords(world_x1, world_y1, level_x1, level_y1);
    p_level->get_tile_coords(world_x2, world_y2, level_x2, level_y2);
    /* m_sp_logger->info( */
    /* "Checking tiles {},{}-{},{}", level_x1, level_y1, level_x2, level_y2); */
    for (int x = level_x1; x <= level_x2; x++)
    {
        for (int y = level_y1; y <= level_y2; y++)
        {
            if (p_level->get_collision(x, y))
            {

                float world_x, world_y, tile_size;
                /* m_sp_logger->info("Collision"); */
                p_level->get_world_coords(x, y, world_x, world_y);
                tile_size = p_level->get_scale();
                core::Rectangle rect1{transform.pos_x + bbox.x,
                    transform.pos_y + bbox.y,
                    bbox.w,
                    bbox.h};
                core::Rectangle rect2{world_x, world_y, tile_size, tile_size};

                auto p_new_manifold = check_rect_collision(rect1, rect2);
                if (p_new_manifold)
                {
                    collision = true;
                    /* if (p_new_manifold->penetration >
                     * p_manifold->penetration) */
                    /* { */
                    /*     *p_manifold = *p_new_manifold; */
                    /* } */
                    p_manifold->normal += p_new_manifold->normal;
                    p_manifold->penetration += p_new_manifold->penetration;
                }
                delete p_new_manifold;
            }
            /* m_sp_logger->info("Checking tile {},{}", x, y); */
        }
    }
    if (collision)
    {
        p_manifold->penetration = p_manifold->penetration.normalize();
        return p_manifold;
    }
    else
    {
        delete p_manifold;
        return nullptr;
    }
}

void Collision::resolve_collision(
    anax::Entity& e1, anax::Entity& e2, Manifold* p_manifold)
{
    assert(p_manifold != nullptr);

    if (!e1.hasComponent<components::PhysicsComponent>() ||
        !e2.hasComponent<components::PhysicsComponent>())
    {
        return;
    }
    auto& physics2 = e2.getComponent<components::PhysicsComponent>();
    auto& physics1 = e1.getComponent<components::PhysicsComponent>();

    throw_if_missing_component<components::TransformComponent>(e1);
    auto& transform1 = e1.getComponent<components::TransformComponent>();

    throw_if_missing_component<components::TransformComponent>(e2);
    auto& transform2 = e2.getComponent<components::TransformComponent>();
    do_resolve_collision(
        &physics1, &transform1, &physics2, &transform2, p_manifold);
}

void Collision::resolve_collision(anax::Entity& e1, Manifold* p_manifold)
{
    const float level_mass = 0.0f;
    const float level_friction = 0.0f;
    const float level_restitution = 0.0f;
    const float level_vel_x = 0.0f;
    const float level_vel_y = 0.0f;
    const float level_force_x = 0.0f;
    const float level_force_y = 0.0f;

    const float level_pos_x = 0.0f;
    const float level_pos_y = 0.0f;
    const float level_size_x = 0.0f;
    const float level_size_y = 0.0f;
    const float level_rotation = 0.0f;
    const bool level_flip_vert = false;
    const bool level_flip_horiz = false;
    assert(p_manifold != nullptr);

    if (!e1.hasComponent<components::PhysicsComponent>())
    {
        return;
    }
    auto& physics1 = e1.getComponent<components::PhysicsComponent>();
    auto physics2 = components::PhysicsComponent{level_mass,
        level_friction,
        level_restitution,
        level_vel_x,
        level_vel_y,
        level_force_x,
        level_force_y};

    throw_if_missing_component<components::TransformComponent>(e1);
    auto& transform1 = e1.getComponent<components::TransformComponent>();
    auto transform2 = components::TransformComponent{level_pos_x,
        level_pos_y,
        level_size_x,
        level_size_y,
        level_rotation,
        level_flip_vert,
        level_flip_horiz};

    do_resolve_collision(
        &physics1, &transform1, &physics2, &transform2, p_manifold);
}

void Collision::do_resolve_collision(components::PhysicsComponent* p_physics1,
    components::TransformComponent* p_transform1,
    components::PhysicsComponent* p_physics2,
    components::TransformComponent* p_transform2,
    Manifold* p_manifold)
{
    assert(p_manifold != nullptr);
    assert(p_physics1 != nullptr);
    assert(p_transform1 != nullptr);
    assert(p_physics2 != nullptr);
    assert(p_transform2 != nullptr);

    float vel_dx = p_physics2->velocity.x - p_physics1->velocity.x;
    float vel_dy = p_physics2->velocity.y - p_physics1->velocity.y;

    float vel_normal =
        vel_dx * p_manifold->normal.x + vel_dy * p_manifold->normal.y;

    m_sp_logger->debug("Normal velocity is {}", vel_normal);
    m_sp_logger->debug("rel velocity is x{}, y{}", vel_dx, vel_dy);
    if (vel_normal > 0)
    {
        m_sp_logger->debug("Objects are moving away");
        return;
    }
    // TODO(Keegan): Add restitution calculation
    const float restitution =
        std::max(p_physics1->restitution, p_physics2->restitution);

    float impulse = -(1.0f * restitution) * vel_normal;

    // TODO(Keegan): Add mass consideration? Or keep in movement?

    float impulse_x = impulse * p_manifold->normal.x;
    float impulse_y = impulse * p_manifold->normal.y;

    m_sp_logger->debug("impulse is x{}, y{}", impulse_x, impulse_y);

    p_physics1->force.x -= impulse_x;
    p_physics2->force.x += impulse_x;

    p_physics1->force.y -= impulse_y;
    p_physics2->force.y += impulse_y;

    m_sp_logger->debug(
        "entity1 force is x{}, y{}", p_physics1->force.x, p_physics1->force.y);
    m_sp_logger->debug(
        "entity2 force is x{}, y{}", p_physics2->force.x, p_physics2->force.y);

    const float positional_percent = 0.2;
    const float positional_slop = 0.01;
    float x_correction =
        std::max(p_manifold->penetration.x - positional_slop, 0.0f) /
        (p_physics1->inv_mass + p_physics2->inv_mass) * positional_percent *
        p_manifold->normal.x;
    float y_correction =
        std::max(p_manifold->penetration.y - positional_slop, 0.0f) /
        (p_physics1->inv_mass + p_physics2->inv_mass) * positional_percent *
        p_manifold->normal.y;
    p_transform1->pos_x -= p_physics1->inv_mass * x_correction;
    p_transform1->pos_y -= p_physics1->inv_mass * y_correction;
    p_transform2->pos_x += p_physics2->inv_mass * x_correction;
    p_transform2->pos_y += p_physics2->inv_mass * y_correction;
}

void Collision::update(core::Level* p_level)
{
    auto colliders = getEntities();

    for (std::size_t i = 0; i < colliders.size(); ++i)
    {
        auto& e1 = colliders[i];

        // No hasComponent check needed since system filters entities
        if (!e1.getComponent<components::Collision>().can_cause_events)
        {
            continue;
        }
        if (p_level != nullptr)
        {
            auto up_manifold =
                std::unique_ptr<Manifold>(check_level_collision(e1, p_level));
            if (up_manifold)
            {
                resolve_collision(e1, up_manifold.get());
            }
        }
        for (std::size_t j = i + 1; j < colliders.size(); ++j)
        {
            auto& e2 = colliders[j];
            auto up_manifold =
                std::unique_ptr<Manifold>(check_collision(e1, e2));
            if (up_manifold)
            {
                resolve_collision(e1, e2, up_manifold.get());
                check_trigger(e1, e2, up_manifold.get());
            }
        }
    }
}

void Collision::check_trigger(
    anax::Entity& e1, anax::Entity& e2, Manifold* p_manifold)
{
    if (e1.hasComponent<components::Trigger>())
    {
        auto msg = e1.getComponent<components::Trigger>().trigger_msg;
        m_trigger_signal.emit(msg, e2);
    }
    else if (e2.hasComponent<components::Trigger>())
    {
        auto msg = e2.getComponent<components::Trigger>().trigger_msg;
        m_trigger_signal.emit(msg, e1);
    }
}

} // namespace systems
<|endoftext|>


<commit_before><commit_msg>svarray: #i112395#: change SvBools from vector to deque<commit_after><|endoftext|>


<commit_before>#include <tasks/task-invoker.hh>

namespace tasks
{
    TaskInvoker::TaskInvoker()
    {}

    TaskInvoker::~TaskInvoker()
    {}

    TaskInvoker& TaskInvoker::instance()
    {
        static TaskInvoker inst;

        return inst;
    }

    static error_t parse_opt(int key, char* arg, struct argp_state* state)
    {
        switch (key)
        {
            case ARGP_KEY_ARG:
                if (state->arg_num >= 1)
                    argp_usage(state);
                else
                    *((char**)state->input) = arg;

                return 0;
            case ARGP_KEY_END:
                if (state->arg_num < 1)
                    argp_usage(state);

                return 0;
            default:
                for (auto it : TaskRegister::instance().registered_tasks_get())
                {
                    if (it->key_get() == key)
                    {
                        TaskInvoker::instance().enable_task(it);
                        return 0;
                    }
                }

                return ARGP_ERR_UNKNOWN;
        }
    }

    char* TaskInvoker::parse_argv(int argc, char* argv[])
    {
        const std::list<BasicTask*>* tasks_list = nullptr;
        tasks_list = &TaskRegister::instance().registered_tasks_get();

        size_t tasks_size = tasks_list->size() + 1;
        struct argp_option available_options[tasks_size];
        size_t task_counter = 0;

        std::memset(available_options, 0, sizeof (argp_option) * tasks_size);

        for (auto it : *tasks_list)
        {
            available_options[task_counter].name = it->long_opt_get().c_str();
            available_options[task_counter].key = it->key_get();
            available_options[task_counter].arg = nullptr;
            available_options[task_counter].flags = 0;
            available_options[task_counter].doc = it->description_get().c_str();
            available_options[task_counter].group = 0;

            ++task_counter;
        }

        argp_child child[1] = { {nullptr, 0, nullptr, 0} };

        struct argp argp =
        {
            available_options,
            parse_opt,
            "INPUT",
            "TyPy is a python compiler.",
            child,
            nullptr,
            nullptr
        };

        char* input_filename;
        argp_parse(&argp, argc, argv, 0, 0, &input_filename);

        return input_filename;
    }

    void TaskInvoker::run()
    {
        for (auto it : tasks_to_run_)
            it->run();
    }

    void TaskInvoker::enable_task(BasicTask* task)
    {
        // TODO resolve dependancies
        tasks_to_run_.push_back(task);
    }
} // namespace tasks
<commit_msg>Add task dependency<commit_after>#include <tasks/task-invoker.hh>

namespace tasks
{
    TaskInvoker::TaskInvoker()
    {}

    TaskInvoker::~TaskInvoker()
    {}

    TaskInvoker& TaskInvoker::instance()
    {
        static TaskInvoker inst;

        return inst;
    }

    static error_t parse_opt(int key, char* arg, struct argp_state* state)
    {
        switch (key)
        {
            case ARGP_KEY_ARG:
                if (state->arg_num >= 1)
                    argp_usage(state);
                else
                    *((char**)state->input) = arg;

                return 0;
            case ARGP_KEY_END:
                if (state->arg_num < 1)
                    argp_usage(state);

                return 0;
            default:
                for (auto it : TaskRegister::instance().registered_tasks_get())
                {
                    if (it->key_get() == key)
                    {
                        TaskInvoker::instance().enable_task(it);
                        return 0;
                    }
                }

                return ARGP_ERR_UNKNOWN;
        }
    }

    char* TaskInvoker::parse_argv(int argc, char* argv[])
    {
        const std::list<BasicTask*>* tasks_list = nullptr;
        tasks_list = &TaskRegister::instance().registered_tasks_get();

        size_t tasks_size = tasks_list->size() + 1;
        struct argp_option available_options[tasks_size];
        size_t task_counter = 0;

        std::memset(available_options, 0, sizeof (argp_option) * tasks_size);

        for (auto it : *tasks_list)
        {
            available_options[task_counter].name = it->long_opt_get().c_str();
            available_options[task_counter].key = it->key_get();
            available_options[task_counter].arg = nullptr;
            available_options[task_counter].flags = 0;
            available_options[task_counter].doc = it->description_get().c_str();
            available_options[task_counter].group = 0;

            ++task_counter;
        }

        argp_child child[1] = { {nullptr, 0, nullptr, 0} };

        struct argp argp =
        {
            available_options,
            parse_opt,
            "INPUT",
            "TyPy is a python compiler.",
            child,
            nullptr,
            nullptr
        };

        char* input_filename;
        argp_parse(&argp, argc, argv, 0, 0, &input_filename);

        return input_filename;
    }

    void TaskInvoker::run()
    {
        for (auto it : tasks_to_run_)
            it->run();
    }

    void TaskInvoker::enable_task(BasicTask* task)
    {
        if (task->dep_get() != "")
        {
            for (auto t : TaskRegister::instance().registered_tasks_get())
            {
                if (t->long_opt_get() == task->dep_get())
                {
                    enable_task(t);
                    break;
                }
            }
        }
        tasks_to_run_.push_back(task);
    }
} // namespace tasks
<|endoftext|>


<commit_before>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** 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 ETH Zurich 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "VProject.h"

#include "VisualizationBase/src/layouts/PositionLayout.h"
#include "VisualizationBase/src/items/VText.h"
#include "VisualizationBase/src/items/Static.h"
#include "VisualizationBase/src/items/VList.h"
#include "VisualizationBase/src/declarative/DeclarativeItemDef.h"

using namespace Visualization;
using namespace OOModel;

namespace OOVisualization {

ITEM_COMMON_DEFINITIONS(VProject, "item")

VProject::VProject(Item* parent, NodeType* node, const StyleType* style) :Super(parent, node, style)
{
	body_ = new PositionLayout(this, &style->body());
}

void VProject::determineChildren()
{
	// manually update the body item
	if (body_->needsUpdate() == FullUpdate) body_->clear(true);
	QList<Model::Node*> bodyItems = node()->projects()->nodes().toList();
	bodyItems << node()->modules()->nodes().toList();
	bodyItems << node()->classes()->nodes().toList();
	bodyItems << node()->methods()->nodes().toList();
	body_->synchronizeWithNodes(bodyItems, renderer());

	// call determineChildren of super class
	Super::determineChildren();
	setDefaultMoveCursorProxy(name_);
}

void VProject::initializeForms()
{
	auto headerElement = (new GridLayoutFormElement())
				->setHorizontalSpacing(10)
				->setColumnStretchFactor(0, 1)
				->setColumnStretchFactor(3, 1)
				->setVerticalAlignment(LayoutStyle::Alignment::Center)
				->setNoBoundaryCursors([](Item*){return true;})->setNoInnerCursors([](Item*){return true;})
				->put(1, 0, item<Static>(&I::icon_, [](I* v) { return &v->style()->icon(); }))
				->put(2, 0, item<VText>(&I::name_,	[](I* v){return v->node()->nameNode();},
																[](I* v) { return &v->style()->name();	}));

	auto contentElement = (new GridLayoutFormElement())
				->setSpacing(5)
				->setColumnStretchFactor(1, 0)
				->setNoBoundaryCursors([](Item*){return true;})
				->setNoInnerCursors([](Item*){return true;})
				->put(0, 0, item<VList>(&I::libraries_,
						[](I* v) {return v->node()->libraries()->size() > 0 ? v->node()->libraries() : nullptr;},
						[](I* v){return &v->style()->libraries();}))
				->put(0, 1, item<VList>(&I::fields_,
						[](I* v) {return v->node()->fields()->size() > 0 ? v->node()->fields() : nullptr;},
						[](I* v){return &v->style()->fields();}))
				->put(0, 2, item<VList>(&I::declarations_,
						[](I* v) {return v->node()->subDeclarations()->size() > 0 ? v->node()->subDeclarations() : nullptr;},
						[](I* v){return &v->style()->declarations();}))
				->put(0, 3, item<PositionLayout>(&I::body_, [](I* v){return &v->style()->body();}));

	auto shapeElement = new ShapeFormElement();

	addForm((new AnchorLayoutFormElement())
		// place the top left corner of the content element
		->put(TheLeftOf, headerElement, 10, FromLeftOf, contentElement)
		->put(TheTopOf, contentElement, AtBottomOf, headerElement)
		// align content and header on their right side
		->put(TheRightOf, contentElement, AtRightOf, headerElement)
		// put the shape element at the right place
		->put(TheTopOf, shapeElement, AtCenterOf, headerElement)
		->put(TheLeftOf, shapeElement, AtLeftOf, headerElement)
		->put(TheBottomOf, shapeElement, 10, FromBottomOf, contentElement)
		->put(TheRightOf, shapeElement, 10, FromRightOf, headerElement));
}

}
<commit_msg>Use the simpler methods for defining item elements in VProject forms<commit_after>/***********************************************************************************************************************
**
** Copyright (c) 2011, 2014 ETH Zurich
** 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 ETH Zurich 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 HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
** SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
** WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
**
***********************************************************************************************************************/

#include "VProject.h"

#include "VisualizationBase/src/layouts/PositionLayout.h"
#include "VisualizationBase/src/items/VText.h"
#include "VisualizationBase/src/items/Static.h"
#include "VisualizationBase/src/items/VList.h"
#include "VisualizationBase/src/declarative/DeclarativeItemDef.h"

using namespace Visualization;
using namespace OOModel;

namespace OOVisualization {

ITEM_COMMON_DEFINITIONS(VProject, "item")

VProject::VProject(Item* parent, NodeType* node, const StyleType* style) :Super(parent, node, style)
{
	body_ = new PositionLayout(this, &style->body());
}

void VProject::determineChildren()
{
	// manually update the body item
	if (body_->needsUpdate() == FullUpdate) body_->clear(true);
	QList<Model::Node*> bodyItems = node()->projects()->nodes().toList();
	bodyItems << node()->modules()->nodes().toList();
	bodyItems << node()->classes()->nodes().toList();
	bodyItems << node()->methods()->nodes().toList();
	body_->synchronizeWithNodes(bodyItems, renderer());

	// call determineChildren of super class
	Super::determineChildren();
	setDefaultMoveCursorProxy(name_);
}

void VProject::initializeForms()
{
	auto headerElement = (new GridLayoutFormElement())
				->setHorizontalSpacing(10)
				->setColumnStretchFactor(0, 1)
				->setColumnStretchFactor(3, 1)
				->setVerticalAlignment(LayoutStyle::Alignment::Center)
				->setNoBoundaryCursors([](Item*){return true;})->setNoInnerCursors([](Item*){return true;})
				->put(1, 0, item<Static>(&I::icon_, &StyleType::icon))
				->put(2, 0, item<VText>(&I::name_, &NodeType::nameNode, &StyleType::name));

	auto contentElement = (new GridLayoutFormElement())
				->setSpacing(5)
				->setColumnStretchFactor(1, 0)
				->setNoBoundaryCursors([](Item*){return true;})
				->setNoInnerCursors([](Item*){return true;})
				->put(0, 0, item<VList>(&I::libraries_,
						[](I* v) {return v->node()->libraries()->size() > 0 ? v->node()->libraries() : nullptr;},
						&StyleType::libraries))
				->put(0, 1, item<VList>(&I::fields_,
						[](I* v) {return v->node()->fields()->size() > 0 ? v->node()->fields() : nullptr;},
						&StyleType::fields))
				->put(0, 2, item<VList>(&I::declarations_,
						[](I* v) {return v->node()->subDeclarations()->size() > 0 ? v->node()->subDeclarations() : nullptr;},
						&StyleType::declarations))
				->put(0, 3, item<PositionLayout>(&I::body_, &StyleType::body));

	auto shapeElement = new ShapeFormElement();

	addForm((new AnchorLayoutFormElement())
		// place the top left corner of the content element
		->put(TheLeftOf, headerElement, 10, FromLeftOf, contentElement)
		->put(TheTopOf, contentElement, AtBottomOf, headerElement)
		// align content and header on their right side
		->put(TheRightOf, contentElement, AtRightOf, headerElement)
		// put the shape element at the right place
		->put(TheTopOf, shapeElement, AtCenterOf, headerElement)
		->put(TheLeftOf, shapeElement, AtLeftOf, headerElement)
		->put(TheBottomOf, shapeElement, 10, FromBottomOf, contentElement)
		->put(TheRightOf, shapeElement, 10, FromRightOf, headerElement));
}

}
<|endoftext|>


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

#ifndef PCL_COMMON_IMPL_DETAIL_ACCUMULATORS_HPP
#define PCL_COMMON_IMPL_DETAIL_ACCUMULATORS_HPP

#include <map>

#include <boost/mpl/filter_view.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/as_vector.hpp>

#include <pcl/point_types.h>

namespace pcl
{

  namespace detail
  {

    /* Below are several helper accumulator structures that are used by the
     * `CentroidPoint` class. Each of them is capable of accumulating
     * information from a particular field(s) of a point. The points are
     * inserted via `add()` and extracted via `get()` functions. Note that the
     * accumulators are not templated on point type, so in principle it is
     * possible to insert and extract points of different types. It is the
     * responsibility of the user to make sure that points have corresponding
     * fields. */

    struct AccumulatorXYZ
    {

      // Requires that point type has x, y, and z fields
      typedef pcl::traits::has_xyz<boost::mpl::_1> IsCompatible;

      // Storage
      Eigen::Vector3f xyz;

      AccumulatorXYZ () : xyz (Eigen::Vector3f::Zero ()) { }

      template <typename PointT> void
      add (const PointT& t) { xyz += t.getVector3fMap (); }

      template <typename PointT> void
      get (PointT& t, size_t n) const { t.getVector3fMap () = xyz / n; }

      EIGEN_MAKE_ALIGNED_OPERATOR_NEW

    };

    struct AccumulatorNormal
    {

      // Requires that point type has normal_x, normal_y, and normal_z fields
      typedef pcl::traits::has_normal<boost::mpl::_1> IsCompatible;

      // Storage
      Eigen::Vector4f normal;

      AccumulatorNormal () : normal (Eigen::Vector4f::Zero ()) { }

      // Requires that the normal of the given point is normalized, otherwise it
      // does not make sense to sum it up with the accumulated value.
      template <typename PointT> void
      add (const PointT& t) { normal += t.getNormalVector4fMap (); }

      template <typename PointT> void
      get (PointT& t, size_t n) const
      {
        t.getNormalVector4fMap () = normal;
        t.getNormalVector4fMap ().normalize ();
      }

      EIGEN_MAKE_ALIGNED_OPERATOR_NEW

    };

    struct AccumulatorCurvature
    {

      // Requires that point type has curvature field
      typedef pcl::traits::has_curvature<boost::mpl::_1> IsCompatible;

      // Storage
      float curvature;

      AccumulatorCurvature () : curvature (0) { }

      template <typename PointT> void
      add (const PointT& t) { curvature += t.curvature; }

      template <typename PointT> void
      get (PointT& t, size_t n) const { t.curvature = curvature / n; }

    };

    struct AccumulatorRGBA
    {

      // Requires that point type has rgb or rgba field
      typedef pcl::traits::has_color<boost::mpl::_1> IsCompatible;

      // Storage
      float r, g, b, a;

      AccumulatorRGBA () : r (0), g (0), b (0), a (0) { }

      template <typename PointT> void
      add (const PointT& t)
      {
        r += static_cast<float> (t.r);
        g += static_cast<float> (t.g);
        b += static_cast<float> (t.b);
        a += static_cast<float> (t.a);
      }

      template <typename PointT> void
      get (PointT& t, size_t n) const
      {
        t.rgba = static_cast<uint32_t> (a / n) << 24 |
                 static_cast<uint32_t> (r / n) << 16 |
                 static_cast<uint32_t> (g / n) <<  8 |
                 static_cast<uint32_t> (b / n);
      }

    };

    struct AccumulatorIntensity
    {

      // Requires that point type has intensity field
      typedef pcl::traits::has_intensity<boost::mpl::_1> IsCompatible;

      // Storage
      float intensity;

      AccumulatorIntensity () : intensity (0) { }

      template <typename PointT> void
      add (const PointT& t) { intensity += t.intensity; }

      template <typename PointT> void
      get (PointT& t, size_t n) const { t.intensity = intensity / n; }

    };

    struct AccumulatorLabel
    {

      // Requires that point type has label field
      typedef pcl::traits::has_label<boost::mpl::_1> IsCompatible;

      // Storage
      // A better performance may be achieved with a heap structure
      std::map<uint32_t, size_t> labels;

      AccumulatorLabel () { }

      template <typename PointT> void
      add (const PointT& t)
      {
        std::map<uint32_t, size_t>::iterator itr = labels.find (t.label);
        if (itr == labels.end ())
          labels.insert (std::make_pair (t.label, 1));
        else
          ++itr->second;
      }

      template <typename PointT> void
      get (PointT& t, size_t n) const
      {
        size_t max = 0;
        std::map<uint32_t, size_t>::const_iterator itr;
        for (itr = labels.begin (); itr != labels.end (); ++itr)
          if (itr->second > max)
          {
            max = itr->second;
            t.label = itr->first;
          }
      }

    };

    /* This is a meta-function that may be used to create a Fusion vector of
     * those accumulator types that are compatible with given point type(s). */

    template <typename Point1T, typename Point2T = Point1T>
    struct Accumulators
    {

      // Check if a given accumulator type is compatible with a given point type
      template <typename AccumulatorT, typename PointT>
      struct IsCompatible : boost::mpl::apply<typename AccumulatorT::IsCompatible, PointT> { };

      // A Fusion vector with accumulator types that are compatible with given
      // point types
      typedef
        typename boost::fusion::result_of::as_vector<
          typename boost::mpl::filter_view<
            boost::mpl::vector<
              AccumulatorXYZ
            , AccumulatorNormal
            , AccumulatorCurvature
            , AccumulatorRGBA
            , AccumulatorIntensity
            , AccumulatorLabel
            >
          , boost::mpl::and_<
              IsCompatible<boost::mpl::_1, Point1T>
            , IsCompatible<boost::mpl::_1, Point2T>
            >
          >
        >::type
      type;
    };

    /* Fusion function object to invoke point addition on every accumulator in
     * a fusion sequence. */

    template <typename PointT>
    struct AddPoint
    {

      const PointT& p;

      AddPoint (const PointT& point) : p (point) { }

      template <typename AccumulatorT> void
      operator () (AccumulatorT& accumulator) const
      {
        accumulator.add (p);
      }

    };

    /* Fusion function object to invoke get point on every accumulator in a
     * fusion sequence. */

    template <typename PointT>
    struct GetPoint
    {

      PointT& p;
      size_t n;

      GetPoint (PointT& point, size_t num) : p (point), n (num) { }

      template <typename AccumulatorT> void
      operator () (AccumulatorT& accumulator) const
      {
        accumulator.get (p, n);
      }

    };

  }

}

#endif /* PCL_COMMON_IMPL_DETAIL_ACCUMULATORS_HPP */

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

#ifndef PCL_COMMON_IMPL_DETAIL_ACCUMULATORS_HPP
#define PCL_COMMON_IMPL_DETAIL_ACCUMULATORS_HPP

#include <map>

#include <boost/mpl/filter_view.hpp>
#include <boost/fusion/include/mpl.hpp>
#include <boost/fusion/include/for_each.hpp>
#include <boost/fusion/include/as_vector.hpp>

#include <pcl/point_types.h>

namespace pcl
{

  namespace detail
  {

    /* Below are several helper accumulator structures that are used by the
     * `CentroidPoint` class. Each of them is capable of accumulating
     * information from a particular field(s) of a point. The points are
     * inserted via `add()` and extracted via `get()` functions. Note that the
     * accumulators are not templated on point type, so in principle it is
     * possible to insert and extract points of different types. It is the
     * responsibility of the user to make sure that points have corresponding
     * fields. */

    struct AccumulatorXYZ
    {

      // Requires that point type has x, y, and z fields
      typedef pcl::traits::has_xyz<boost::mpl::_1> IsCompatible;

      // Storage
      Eigen::Vector3f xyz;

      AccumulatorXYZ () : xyz (Eigen::Vector3f::Zero ()) { }

      template <typename PointT> void
      add (const PointT& t) { xyz += t.getVector3fMap (); }

      template <typename PointT> void
      get (PointT& t, size_t n) const { t.getVector3fMap () = xyz / n; }

      EIGEN_MAKE_ALIGNED_OPERATOR_NEW

    };

    struct AccumulatorNormal
    {

      // Requires that point type has normal_x, normal_y, and normal_z fields
      typedef pcl::traits::has_normal<boost::mpl::_1> IsCompatible;

      // Storage
      Eigen::Vector4f normal;

      AccumulatorNormal () : normal (Eigen::Vector4f::Zero ()) { }

      // Requires that the normal of the given point is normalized, otherwise it
      // does not make sense to sum it up with the accumulated value.
      template <typename PointT> void
      add (const PointT& t) { normal += t.getNormalVector4fMap (); }

      template <typename PointT> void
      get (PointT& t, size_t) const
      {
        t.getNormalVector4fMap () = normal;
        t.getNormalVector4fMap ().normalize ();
      }

      EIGEN_MAKE_ALIGNED_OPERATOR_NEW

    };

    struct AccumulatorCurvature
    {

      // Requires that point type has curvature field
      typedef pcl::traits::has_curvature<boost::mpl::_1> IsCompatible;

      // Storage
      float curvature;

      AccumulatorCurvature () : curvature (0) { }

      template <typename PointT> void
      add (const PointT& t) { curvature += t.curvature; }

      template <typename PointT> void
      get (PointT& t, size_t n) const { t.curvature = curvature / n; }

    };

    struct AccumulatorRGBA
    {

      // Requires that point type has rgb or rgba field
      typedef pcl::traits::has_color<boost::mpl::_1> IsCompatible;

      // Storage
      float r, g, b, a;

      AccumulatorRGBA () : r (0), g (0), b (0), a (0) { }

      template <typename PointT> void
      add (const PointT& t)
      {
        r += static_cast<float> (t.r);
        g += static_cast<float> (t.g);
        b += static_cast<float> (t.b);
        a += static_cast<float> (t.a);
      }

      template <typename PointT> void
      get (PointT& t, size_t n) const
      {
        t.rgba = static_cast<uint32_t> (a / n) << 24 |
                 static_cast<uint32_t> (r / n) << 16 |
                 static_cast<uint32_t> (g / n) <<  8 |
                 static_cast<uint32_t> (b / n);
      }

    };

    struct AccumulatorIntensity
    {

      // Requires that point type has intensity field
      typedef pcl::traits::has_intensity<boost::mpl::_1> IsCompatible;

      // Storage
      float intensity;

      AccumulatorIntensity () : intensity (0) { }

      template <typename PointT> void
      add (const PointT& t) { intensity += t.intensity; }

      template <typename PointT> void
      get (PointT& t, size_t n) const { t.intensity = intensity / n; }

    };

    struct AccumulatorLabel
    {

      // Requires that point type has label field
      typedef pcl::traits::has_label<boost::mpl::_1> IsCompatible;

      // Storage
      // A better performance may be achieved with a heap structure
      std::map<uint32_t, size_t> labels;

      AccumulatorLabel () { }

      template <typename PointT> void
      add (const PointT& t)
      {
        std::map<uint32_t, size_t>::iterator itr = labels.find (t.label);
        if (itr == labels.end ())
          labels.insert (std::make_pair (t.label, 1));
        else
          ++itr->second;
      }

      template <typename PointT> void
      get (PointT& t, size_t) const
      {
        size_t max = 0;
        std::map<uint32_t, size_t>::const_iterator itr;
        for (itr = labels.begin (); itr != labels.end (); ++itr)
          if (itr->second > max)
          {
            max = itr->second;
            t.label = itr->first;
          }
      }

    };

    /* This is a meta-function that may be used to create a Fusion vector of
     * those accumulator types that are compatible with given point type(s). */

    template <typename Point1T, typename Point2T = Point1T>
    struct Accumulators
    {

      // Check if a given accumulator type is compatible with a given point type
      template <typename AccumulatorT, typename PointT>
      struct IsCompatible : boost::mpl::apply<typename AccumulatorT::IsCompatible, PointT> { };

      // A Fusion vector with accumulator types that are compatible with given
      // point types
      typedef
        typename boost::fusion::result_of::as_vector<
          typename boost::mpl::filter_view<
            boost::mpl::vector<
              AccumulatorXYZ
            , AccumulatorNormal
            , AccumulatorCurvature
            , AccumulatorRGBA
            , AccumulatorIntensity
            , AccumulatorLabel
            >
          , boost::mpl::and_<
              IsCompatible<boost::mpl::_1, Point1T>
            , IsCompatible<boost::mpl::_1, Point2T>
            >
          >
        >::type
      type;
    };

    /* Fusion function object to invoke point addition on every accumulator in
     * a fusion sequence. */

    template <typename PointT>
    struct AddPoint
    {

      const PointT& p;

      AddPoint (const PointT& point) : p (point) { }

      template <typename AccumulatorT> void
      operator () (AccumulatorT& accumulator) const
      {
        accumulator.add (p);
      }

    };

    /* Fusion function object to invoke get point on every accumulator in a
     * fusion sequence. */

    template <typename PointT>
    struct GetPoint
    {

      PointT& p;
      size_t n;

      GetPoint (PointT& point, size_t num) : p (point), n (num) { }

      template <typename AccumulatorT> void
      operator () (AccumulatorT& accumulator) const
      {
        accumulator.get (p, n);
      }

    };

  }

}

#endif /* PCL_COMMON_IMPL_DETAIL_ACCUMULATORS_HPP */

<|endoftext|>


<commit_before>#include "sensor.h"

<commit_msg>removing sensor.cpp from qubo_sim<commit_after><|endoftext|>


<commit_before>#include <set>
#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <map>
#include <stack>

#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/Config/llvm-config.h>

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
 #include <llvm/DebugInfo.h>
#else
 #include <llvm/DebugInfo/DIContext.h>
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

using namespace llvm;

// lines with matching braces
std::vector<std::pair<unsigned, unsigned>> matching_braces;
// mapping line->index in matching_braces
std::map<unsigned, unsigned> nesting_structure;

static void get_lines_from_module(const Module *M, std::set<unsigned>& lines)
{
    // iterate over all instructions
    for (const Function& F : *M) {
        for (const BasicBlock& B : F) {
            for (const Instruction& I : B) {
                const DebugLoc& Loc = I.getDebugLoc();
                //Make sure that the llvm istruction has corresponding dbg LOC
#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR > 5))
                if (Loc)
#else
                if (Loc.getLine() > 0)
                    lines.insert(Loc.getLine());
#endif
            }
        }
    }

    // iterate over all globals
    /*
    for (const GlobalVariable& G : M->globals()) {
        const DebugLoc& Loc = G.getDebugLoc();
        lines.insert(Loc.getLine());
    }
    */
}

static void get_nesting_structure(const char *source)
{
    std::ifstream ifs(source);
    if (!ifs.is_open() || ifs.bad()) {
        errs() << "Failed opening given source file: " << source << "\n";
        abort();
    }

    char ch;
    unsigned cur_line = 1;
    unsigned idx;
    std::stack<unsigned> nesting;
    while (ifs.get(ch)) {
        switch(ch) {
        case '\n':
            ++cur_line;
            if (!nesting.empty())
                nesting_structure.emplace(cur_line, nesting.top());
            break;
        case '{':
            nesting.push(matching_braces.size());
            matching_braces.push_back({cur_line, 0});
            break;
        case '}':
            idx = nesting.top();
            assert(idx < matching_braces.size());
            assert(matching_braces[idx].second == 0);
            matching_braces[idx].second = cur_line;
            nesting.pop();
            break;
        default:
            break;
        }
    }

    ifs.close();
}

static void print_lines(std::ifstream& ifs, std::set<unsigned>& lines)
{
    char buf[1024];
    unsigned cur_line = 1;
    while (!ifs.eof()) {
        ifs.getline(buf, sizeof buf);

        if (lines.count(cur_line) > 0) {
            std::cout << cur_line << ": ";
            std::cout << buf << "\n";
        }

        if (ifs.bad()) {
            errs() << "An error occured\n";
            break;
        }

        ++cur_line;
    }
}

static void print_lines_numbers(std::set<unsigned>& lines)
{
    for (unsigned ln : lines)
        std::cout << ln << "\n";
}

int main(int argc, char *argv[])
{
    llvm::Module *M;
    LLVMContext context;
    SMDiagnostic SMD;

    const char *source = nullptr;
    const char *module = nullptr;

    if (argc < 2 || argc > 3 ) {
        errs() << "Usage: module [source_code]\n";
        return 1;
    }

    module = argv[1];
    if (argc == 3)
        source = argv[2];

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 5))
    M = llvm::ParseIRFile(module, SMD, context);
#else
    auto _M = llvm::parseIRFile(module, SMD, context);
    // _M is unique pointer, we need to get Module *
    M = _M.get();
#endif

    if (!M) {
        llvm::errs() << "Failed parsing '" << module << "' file:\n";
        SMD.print(argv[0], errs());
        return 1;
    }

    // FIXME find out if we have debugging info at all
    // no difficult machineris - just find out
    // which lines are in our module and print them
    std::set<unsigned> lines;
    get_lines_from_module(M, lines);

    if (!source)
        print_lines_numbers(lines);
    else {
        get_nesting_structure(source);
        /* fill in the lines with braces */
        /* really not efficient, but easy */
        size_t old_size;
        do {
            old_size = lines.size();
            std::set<unsigned> new_lines;

            for (unsigned i : lines) {
                new_lines.insert(i);
                auto it = nesting_structure.find(i);
                if (it != nesting_structure.end()) {
                    auto& pr = matching_braces[it->second];
                    new_lines.insert(pr.first);
                    new_lines.insert(pr.second);
                }
            }

            lines.swap(new_lines);
        } while(lines.size() > old_size);

        std::ifstream ifs(source);
        if (!ifs.is_open() || ifs.bad()) {
            errs() << "Failed opening given source file: " << source << "\n";
            return 1;
        }

        //print_lines_numbers(lines);
        print_lines(ifs, lines);
        ifs.close();
    }

    return 0;
}
<commit_msg>llvm-to-source: fix incorrect conditional compilation guard<commit_after>#include <set>
#include <iostream>
#include <fstream>
#include <sstream>
#include <limits>
#include <map>
#include <stack>

#ifndef HAVE_LLVM
#error "This code needs LLVM enabled"
#endif

// ignore unused parameters in LLVM libraries
#if (__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#else
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif

#include <llvm/Config/llvm-config.h>

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR < 5))
 #include <llvm/DebugInfo.h>
#else
 #include <llvm/DebugInfo/DIContext.h>
#endif

#include <llvm/IR/LLVMContext.h>
#include <llvm/IR/Module.h>
#include <llvm/Support/SourceMgr.h>
#include <llvm/Support/raw_os_ostream.h>
#include <llvm/IRReader/IRReader.h>

#if (__clang__)
#pragma clang diagnostic pop // ignore -Wunused-parameter
#else
#pragma GCC diagnostic pop
#endif

using namespace llvm;

// lines with matching braces
std::vector<std::pair<unsigned, unsigned>> matching_braces;
// mapping line->index in matching_braces
std::map<unsigned, unsigned> nesting_structure;

static void get_lines_from_module(const Module *M, std::set<unsigned>& lines)
{
    // iterate over all instructions
    for (const Function& F : *M) {
        for (const BasicBlock& B : F) {
            for (const Instruction& I : B) {
                const DebugLoc& Loc = I.getDebugLoc();
                //Make sure that the llvm istruction has corresponding dbg LOC
#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR > 5))
                if (Loc)
#else
                if (Loc.getLine() > 0)
#endif
                    lines.insert(Loc.getLine());
            }
        }
    }

    // iterate over all globals
    /*
    for (const GlobalVariable& G : M->globals()) {
        const DebugLoc& Loc = G.getDebugLoc();
        lines.insert(Loc.getLine());
    }
    */
}

static void get_nesting_structure(const char *source)
{
    std::ifstream ifs(source);
    if (!ifs.is_open() || ifs.bad()) {
        errs() << "Failed opening given source file: " << source << "\n";
        abort();
    }

    char ch;
    unsigned cur_line = 1;
    unsigned idx;
    std::stack<unsigned> nesting;
    while (ifs.get(ch)) {
        switch(ch) {
        case '\n':
            ++cur_line;
            if (!nesting.empty())
                nesting_structure.emplace(cur_line, nesting.top());
            break;
        case '{':
            nesting.push(matching_braces.size());
            matching_braces.push_back({cur_line, 0});
            break;
        case '}':
            idx = nesting.top();
            assert(idx < matching_braces.size());
            assert(matching_braces[idx].second == 0);
            matching_braces[idx].second = cur_line;
            nesting.pop();
            break;
        default:
            break;
        }
    }

    ifs.close();
}

static void print_lines(std::ifstream& ifs, std::set<unsigned>& lines)
{
    char buf[1024];
    unsigned cur_line = 1;
    while (!ifs.eof()) {
        ifs.getline(buf, sizeof buf);

        if (lines.count(cur_line) > 0) {
            std::cout << cur_line << ": ";
            std::cout << buf << "\n";
        }

        if (ifs.bad()) {
            errs() << "An error occured\n";
            break;
        }

        ++cur_line;
    }
}

static void print_lines_numbers(std::set<unsigned>& lines)
{
    for (unsigned ln : lines)
        std::cout << ln << "\n";
}

int main(int argc, char *argv[])
{
    llvm::Module *M;
    LLVMContext context;
    SMDiagnostic SMD;

    const char *source = nullptr;
    const char *module = nullptr;

    if (argc < 2 || argc > 3 ) {
        errs() << "Usage: module [source_code]\n";
        return 1;
    }

    module = argv[1];
    if (argc == 3)
        source = argv[2];

#if ((LLVM_VERSION_MAJOR == 3) && (LLVM_VERSION_MINOR <= 5))
    M = llvm::ParseIRFile(module, SMD, context);
#else
    auto _M = llvm::parseIRFile(module, SMD, context);
    // _M is unique pointer, we need to get Module *
    M = _M.get();
#endif

    if (!M) {
        llvm::errs() << "Failed parsing '" << module << "' file:\n";
        SMD.print(argv[0], errs());
        return 1;
    }

    // FIXME find out if we have debugging info at all
    // no difficult machineris - just find out
    // which lines are in our module and print them
    std::set<unsigned> lines;
    get_lines_from_module(M, lines);

    if (!source)
        print_lines_numbers(lines);
    else {
        get_nesting_structure(source);
        /* fill in the lines with braces */
        /* really not efficient, but easy */
        size_t old_size;
        do {
            old_size = lines.size();
            std::set<unsigned> new_lines;

            for (unsigned i : lines) {
                new_lines.insert(i);
                auto it = nesting_structure.find(i);
                if (it != nesting_structure.end()) {
                    auto& pr = matching_braces[it->second];
                    new_lines.insert(pr.first);
                    new_lines.insert(pr.second);
                }
            }

            lines.swap(new_lines);
        } while(lines.size() > old_size);

        std::ifstream ifs(source);
        if (!ifs.is_open() || ifs.bad()) {
            errs() << "Failed opening given source file: " << source << "\n";
            return 1;
        }

        //print_lines_numbers(lines);
        print_lines(ifs, lines);
        ifs.close();
    }

    return 0;
}
<|endoftext|>


<commit_before>/*
 * SessionExecuteChunkOperation.hpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */
#ifndef SESSION_MODULES_RMARKDOWN_SESSION_EXECUTE_CHUNK_OPERATIONR_HPP
#define SESSION_MODULES_RMARKDOWN_SESSION_EXECUTE_CHUNK_OPERATIONR_HPP

#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>

#include <core/FileSerializer.hpp>
#include <core/StringUtils.hpp>
#include <core/text/CsvParser.hpp>
#include <core/system/Process.hpp>
#include <core/system/ShellUtils.hpp>
#include <core/system/System.hpp>

#include "NotebookOutput.hpp"
#include "NotebookExec.hpp"
#include "SessionRmdNotebook.hpp"

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {

core::shell_utils::ShellCommand shellCommandForEngine(
      const std::string& engine,
      const core::FilePath& scriptPath)
{
   core::shell_utils::ShellCommand command(engine);

   if (engine == "Rscript")
      command << "-f";

   command << core::string_utils::utf8ToSystem(scriptPath.absolutePathNative());

   return command;
}

class ExecuteChunkOperation : boost::noncopyable,
                              public boost::enable_shared_from_this<ExecuteChunkOperation>
{
   typedef core::shell_utils::ShellCommand ShellCommand;
   typedef core::system::ProcessCallbacks ProcessCallbacks;
   typedef core::system::ProcessOperations ProcessOperations;

public:
   static boost::shared_ptr<ExecuteChunkOperation> create(const std::string& docId,
                                                          const std::string& chunkId,
                                                          const std::string& nbCtxId,
                                                          const ShellCommand& command,
                                                          const core::FilePath& scriptPath)
   {
      boost::shared_ptr<ExecuteChunkOperation> pProcess =
            boost::shared_ptr<ExecuteChunkOperation>(new ExecuteChunkOperation(
                                                        docId,
                                                        chunkId,
                                                        nbCtxId,
                                                        command,
                                                        scriptPath));
      pProcess->registerProcess();
      return pProcess;
   }

private:

   ExecuteChunkOperation(const std::string& docId,
                         const std::string& chunkId,
                         const std::string& nbCtxId,
                         const ShellCommand& command,
                         const core::FilePath& scriptPath)
      : terminationRequested_(false),
        docId_(docId),
        chunkId_(chunkId),
        nbCtxId_(nbCtxId),
        command_(command),
        scriptPath_(scriptPath)
   {
      using namespace core;
      Error error = Success();

      // ensure regular directory
      FilePath outputPath = chunkOutputPath(
               docId_,
               chunkId_,
               ContextExact);

      error = outputPath.removeIfExists();
      if (error)
         LOG_ERROR(error);

      error = outputPath.ensureDirectory();
      if (error)
         LOG_ERROR(error);

      // clean old chunk output
      error = cleanChunkOutput(docId_, chunkId_, nbCtxId_, true);
      if (error)
         LOG_ERROR(error);
   }

public:

   ProcessCallbacks processCallbacks()
   {
      ProcessCallbacks callbacks;

      callbacks.onStarted = boost::bind(
               &ExecuteChunkOperation::onStarted,
               shared_from_this());

      callbacks.onContinue = boost::bind(
               &ExecuteChunkOperation::onContinue,
               shared_from_this());

      callbacks.onStdout = boost::bind(
               &ExecuteChunkOperation::onStdout,
               shared_from_this(),
               _2);

      callbacks.onStderr = boost::bind(
               &ExecuteChunkOperation::onStderr,
               shared_from_this(),
               _2);

      callbacks.onExit = boost::bind(
               &ExecuteChunkOperation::onExit,
               shared_from_this(),
               _1);

      return callbacks;
   }

private:

   enum OutputType { OUTPUT_STDOUT, OUTPUT_STDERR };

   void onStarted()
   {
   }

   bool onContinue()
   {
      return !terminationRequested_;
   }

   void onExit(int exitStatus)
   {
      events().onChunkExecCompleted(docId_, chunkId_, notebookCtxId());
      deregisterProcess();
      scriptPath_.removeIfExists();
   }

   void onStdout(const std::string& output)
   {
      onText(output, OUTPUT_STDOUT);
   }

   void onStderr(const std::string& output)
   {
      onText(output, OUTPUT_STDERR);
   }

   void onText(const std::string& output, OutputType outputType)
   {
      using namespace core;

      // get path to cache file
      FilePath target = chunkOutputFile(docId_, chunkId_, nbCtxId_,
            kChunkOutputText);

      // append console data
      notebook::appendConsoleOutput(
               outputType == OUTPUT_STDOUT ? kChunkConsoleOutput : kChunkConsoleError,
               output,
               target);

      // emit client event
      enqueueChunkOutput(
               docId_,
               chunkId_,
               nbCtxId_,
               kChunkOutputText,
               target);
   }

public:

   void terminate() { terminationRequested_ = true; }
   bool terminationRequested() const { return terminationRequested_; }
   const std::string& chunkId() const { return chunkId_; }

private:
   bool terminationRequested_;
   std::string docId_;
   std::string chunkId_;
   std::string nbCtxId_;
   ShellCommand command_;
   core::FilePath scriptPath_;

private:

   typedef std::map<
      std::string,
      boost::shared_ptr<ExecuteChunkOperation>
   > ProcessRegistry;

   static ProcessRegistry& registry()
   {
      static ProcessRegistry instance;
      return instance;
   }

   void registerProcess()
   {
      registry()[docId_ + "-" + chunkId_] = shared_from_this();
   }

   void deregisterProcess()
   {
      registry().erase(docId_ + "-" + chunkId_);
   }

public:
   static boost::shared_ptr<ExecuteChunkOperation> getProcess(
         const std::string& docId,
         const std::string& chunkId)
   {
      return registry()[docId + "-" + chunkId];
   }
};

core::Error runChunk(const std::string& docId,
                     const std::string& chunkId,
                     const std::string& nbCtxId,
                     const std::string& engine,
                     const std::string& code)
{
   using namespace core;
   typedef core::shell_utils::ShellCommand ShellCommand;

   // write code to temporary file
   FilePath scriptPath = module_context::tempFile("chunk-code", "");
   Error error = core::writeStringToFile(scriptPath, code);
   if (error)
   {
      LOG_ERROR(error);
      return error;
   }

   // get command
   ShellCommand command = notebook::shellCommandForEngine(engine, scriptPath);

   // create process
   boost::shared_ptr<ExecuteChunkOperation> operation =
         ExecuteChunkOperation::create(docId, chunkId, nbCtxId, command,
               scriptPath);

   // write input code to cache
   FilePath cacheFilePath = notebook::chunkOutputFile(
            docId,
            chunkId,
            nbCtxId,
            kChunkOutputText);

   error = notebook::appendConsoleOutput(
            kChunkConsoleInput,
            code,
            cacheFilePath);

   if (error)
      LOG_ERROR(error);

   // generate process options
   core::system::ProcessOptions options;
   options.terminateChildren = true;

   // run it
   error = module_context::processSupervisor().runCommand(
            command,
            options,
            operation->processCallbacks());

   if (error)
      LOG_ERROR(error);

   return Success();
}

void interruptChunk(const std::string& docId,
                    const std::string& chunkId)
{
   boost::shared_ptr<ExecuteChunkOperation> pOperation =
         ExecuteChunkOperation::getProcess(docId, chunkId);

   if (pOperation)
      pOperation->terminate();
}

} // end namespace notebook
} // end namespace rmarkdown
} // end namespace modules
} // end namespace session
} // end namespace rstudio

#endif /* SESSION_MODULES_RMARKDOWN_SESSION_EXECUTE_CHUNK_OPERATIONR_HPP */
<commit_msg>Rscript does not need '-f' when invoked for files<commit_after>/*
 * SessionExecuteChunkOperation.hpp
 *
 * Copyright (C) 2009-16 by RStudio, Inc.
 *
 * Unless you have received this program directly from RStudio pursuant
 * to the terms of a commercial license agreement with RStudio, then
 * this program is licensed to you under the terms of version 3 of the
 * GNU Affero General Public License. This program is distributed WITHOUT
 * ANY EXPRESS OR IMPLIED WARRANTY, INCLUDING THOSE OF NON-INFRINGEMENT,
 * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. Please refer to the
 * AGPL (http://www.gnu.org/licenses/agpl-3.0.txt) for more details.
 *
 */
#ifndef SESSION_MODULES_RMARKDOWN_SESSION_EXECUTE_CHUNK_OPERATIONR_HPP
#define SESSION_MODULES_RMARKDOWN_SESSION_EXECUTE_CHUNK_OPERATIONR_HPP

#include <boost/bind.hpp>
#include <boost/enable_shared_from_this.hpp>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>

#include <core/FileSerializer.hpp>
#include <core/StringUtils.hpp>
#include <core/text/CsvParser.hpp>
#include <core/system/Process.hpp>
#include <core/system/ShellUtils.hpp>
#include <core/system/System.hpp>

#include "NotebookOutput.hpp"
#include "NotebookExec.hpp"
#include "SessionRmdNotebook.hpp"

namespace rstudio {
namespace session {
namespace modules {
namespace rmarkdown {
namespace notebook {

core::shell_utils::ShellCommand shellCommandForEngine(
      const std::string& engine,
      const core::FilePath& scriptPath)
{
   core::shell_utils::ShellCommand command(engine);

   command << core::string_utils::utf8ToSystem(scriptPath.absolutePathNative());

   return command;
}

class ExecuteChunkOperation : boost::noncopyable,
                              public boost::enable_shared_from_this<ExecuteChunkOperation>
{
   typedef core::shell_utils::ShellCommand ShellCommand;
   typedef core::system::ProcessCallbacks ProcessCallbacks;
   typedef core::system::ProcessOperations ProcessOperations;

public:
   static boost::shared_ptr<ExecuteChunkOperation> create(const std::string& docId,
                                                          const std::string& chunkId,
                                                          const std::string& nbCtxId,
                                                          const ShellCommand& command,
                                                          const core::FilePath& scriptPath)
   {
      boost::shared_ptr<ExecuteChunkOperation> pProcess =
            boost::shared_ptr<ExecuteChunkOperation>(new ExecuteChunkOperation(
                                                        docId,
                                                        chunkId,
                                                        nbCtxId,
                                                        command,
                                                        scriptPath));
      pProcess->registerProcess();
      return pProcess;
   }

private:

   ExecuteChunkOperation(const std::string& docId,
                         const std::string& chunkId,
                         const std::string& nbCtxId,
                         const ShellCommand& command,
                         const core::FilePath& scriptPath)
      : terminationRequested_(false),
        docId_(docId),
        chunkId_(chunkId),
        nbCtxId_(nbCtxId),
        command_(command),
        scriptPath_(scriptPath)
   {
      using namespace core;
      Error error = Success();

      // ensure regular directory
      FilePath outputPath = chunkOutputPath(
               docId_,
               chunkId_,
               ContextExact);

      error = outputPath.removeIfExists();
      if (error)
         LOG_ERROR(error);

      error = outputPath.ensureDirectory();
      if (error)
         LOG_ERROR(error);

      // clean old chunk output
      error = cleanChunkOutput(docId_, chunkId_, nbCtxId_, true);
      if (error)
         LOG_ERROR(error);
   }

public:

   ProcessCallbacks processCallbacks()
   {
      ProcessCallbacks callbacks;

      callbacks.onStarted = boost::bind(
               &ExecuteChunkOperation::onStarted,
               shared_from_this());

      callbacks.onContinue = boost::bind(
               &ExecuteChunkOperation::onContinue,
               shared_from_this());

      callbacks.onStdout = boost::bind(
               &ExecuteChunkOperation::onStdout,
               shared_from_this(),
               _2);

      callbacks.onStderr = boost::bind(
               &ExecuteChunkOperation::onStderr,
               shared_from_this(),
               _2);

      callbacks.onExit = boost::bind(
               &ExecuteChunkOperation::onExit,
               shared_from_this(),
               _1);

      return callbacks;
   }

private:

   enum OutputType { OUTPUT_STDOUT, OUTPUT_STDERR };

   void onStarted()
   {
   }

   bool onContinue()
   {
      return !terminationRequested_;
   }

   void onExit(int exitStatus)
   {
      events().onChunkExecCompleted(docId_, chunkId_, notebookCtxId());
      deregisterProcess();
      scriptPath_.removeIfExists();
   }

   void onStdout(const std::string& output)
   {
      onText(output, OUTPUT_STDOUT);
   }

   void onStderr(const std::string& output)
   {
      onText(output, OUTPUT_STDERR);
   }

   void onText(const std::string& output, OutputType outputType)
   {
      using namespace core;

      // get path to cache file
      FilePath target = chunkOutputFile(docId_, chunkId_, nbCtxId_,
            kChunkOutputText);

      // append console data
      notebook::appendConsoleOutput(
               outputType == OUTPUT_STDOUT ? kChunkConsoleOutput : kChunkConsoleError,
               output,
               target);

      // emit client event
      enqueueChunkOutput(
               docId_,
               chunkId_,
               nbCtxId_,
               kChunkOutputText,
               target);
   }

public:

   void terminate() { terminationRequested_ = true; }
   bool terminationRequested() const { return terminationRequested_; }
   const std::string& chunkId() const { return chunkId_; }

private:
   bool terminationRequested_;
   std::string docId_;
   std::string chunkId_;
   std::string nbCtxId_;
   ShellCommand command_;
   core::FilePath scriptPath_;

private:

   typedef std::map<
      std::string,
      boost::shared_ptr<ExecuteChunkOperation>
   > ProcessRegistry;

   static ProcessRegistry& registry()
   {
      static ProcessRegistry instance;
      return instance;
   }

   void registerProcess()
   {
      registry()[docId_ + "-" + chunkId_] = shared_from_this();
   }

   void deregisterProcess()
   {
      registry().erase(docId_ + "-" + chunkId_);
   }

public:
   static boost::shared_ptr<ExecuteChunkOperation> getProcess(
         const std::string& docId,
         const std::string& chunkId)
   {
      return registry()[docId + "-" + chunkId];
   }
};

core::Error runChunk(const std::string& docId,
                     const std::string& chunkId,
                     const std::string& nbCtxId,
                     const std::string& engine,
                     const std::string& code)
{
   using namespace core;
   typedef core::shell_utils::ShellCommand ShellCommand;

   // write code to temporary file
   FilePath scriptPath = module_context::tempFile("chunk-code", "");
   Error error = core::writeStringToFile(scriptPath, code);
   if (error)
   {
      LOG_ERROR(error);
      return error;
   }

   // get command
   ShellCommand command = notebook::shellCommandForEngine(engine, scriptPath);

   // create process
   boost::shared_ptr<ExecuteChunkOperation> operation =
         ExecuteChunkOperation::create(docId, chunkId, nbCtxId, command,
               scriptPath);

   // write input code to cache
   FilePath cacheFilePath = notebook::chunkOutputFile(
            docId,
            chunkId,
            nbCtxId,
            kChunkOutputText);

   error = notebook::appendConsoleOutput(
            kChunkConsoleInput,
            code,
            cacheFilePath);

   if (error)
      LOG_ERROR(error);

   // generate process options
   core::system::ProcessOptions options;
   options.terminateChildren = true;

   // run it
   error = module_context::processSupervisor().runCommand(
            command,
            options,
            operation->processCallbacks());

   if (error)
      LOG_ERROR(error);

   return Success();
}

void interruptChunk(const std::string& docId,
                    const std::string& chunkId)
{
   boost::shared_ptr<ExecuteChunkOperation> pOperation =
         ExecuteChunkOperation::getProcess(docId, chunkId);

   if (pOperation)
      pOperation->terminate();
}

} // end namespace notebook
} // end namespace rmarkdown
} // end namespace modules
} // end namespace session
} // end namespace rstudio

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