<commit_before>#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
#include <sstream>

////////////////////////////////////////////////////////////
/// \brief Helper to transform a line into a case description
///
/// \param line String of space-separated integers
///
/// \return Vector describing the case
////////////////////////////////////////////////////////////
template <typename T>
std::vector<T> line_to_vect(std::string& line) {
    std::vector<T> v;
    std::istringstream iss(line);
    return std::vector<T>(std::istream_iterator<T>(iss), std::istream_iterator<T>());
}

////////////////////////////////////////////////////////////
/// \brief Read a casebase from a file
///
/// \param path Path to the casebase file
///
/// \return The casebase description
////////////////////////////////////////////////////////////
std::vector<std::vector<int>> read_case_base(std::string path) {
    std::ifstream file(path);
    std::vector<std::vector<int>> cb;
    std::string line;

    if (file) {
        while (std::getline(file, line)) {
            cb.push_back(line_to_vect<int>(line));
        }
    }
    return cb;
}

////////////////////////////////////////////////////////////
/// \brief Read the outcomes from a file
///
/// \param path Path to the outcomes file
///
/// \return The outcomes
////////////////////////////////////////////////////////////
std::vector<bool> read_mapping(std::string path) {
    std::ifstream file(path);
    std::vector<bool> v;
    std::string line;
    if (file) {
        while (std::getline(file, line)) {
            v.push_back(bool(std::stoi(line)));
        }
    }
    return v;
}
<commit_msg>Function to parse features dictionnary<commit_after>#include <fstream>
#include <iostream>
#include <iterator>
#include <vector>
#include <sstream>

////////////////////////////////////////////////////////////
/// \brief Helper to transform a line into a case description
///
/// \param line String of space-separated integers
///
/// \return Vector describing the case
////////////////////////////////////////////////////////////
template <typename T>
std::vector<T> line_to_vect(std::string& line) {
    std::vector<T> v;
    std::istringstream iss(line);
    return std::vector<T>(std::istream_iterator<T>(iss), std::istream_iterator<T>());
}

////////////////////////////////////////////////////////////
/// \brief Read a casebase from a file
///
/// \param path Path to the casebase file
///
/// \return The casebase description
////////////////////////////////////////////////////////////
std::vector<std::vector<int>> read_case_base(std::string path) {
    std::ifstream file(path);
    std::vector<std::vector<int>> cb;
    std::string line;

    if (file) {
        while (std::getline(file, line)) {
            cb.push_back(line_to_vect<int>(line));
        }
    }
    return cb;
}

////////////////////////////////////////////////////////////
/// \brief Read the outcomes from a file
///
/// \param path Path to the outcomes file
///
/// \return The outcomes
////////////////////////////////////////////////////////////
std::vector<bool> read_mapping(std::string path) {
    std::ifstream file(path);
    std::vector<bool> v;
    std::string line;
    if (file) {
        while (std::getline(file, line)) {
            v.push_back(bool(std::stoi(line)));
        }
    }
    return v;
}

////////////////////////////////////////////////////////////
/// \brief Read features
///
/// \param path Path to the casebase file
///
/// \return The casebase description
////////////////////////////////////////////////////////////
std::map<int, std::string> read_features(std::string path) {
    std::ifstream file(path);
    std::map<int, std::string> f;
    std::string line;

    if (file) {
        while (std::getline(file, line)) {
            std::istringstream iss(line);
            auto i = 0;
            std::string c;
            std::string v;
            iss >> i;
            iss >> c;
            iss >> v;
            f[i] = c + "=" + v;
            //std::cout << i << " " <<  c + "=" + v << std::endl;
        }
    }
    return f;
}<|endoftext|>


<commit_before>#include "p0optimize/remove_dead_code.hpp"
#include "p0i/emitter.hpp"
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(remove_dead_code_empty)
{
	p0::intermediate::function::instruction_vector original_code;
	p0::intermediate::function::instruction_vector const living_code = p0::remove_dead_code(original_code);
	p0::intermediate::function::instruction_vector expected_code;
	BOOST_CHECK(expected_code == living_code);
}

BOOST_AUTO_TEST_CASE(remove_dead_code_jump)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.jump(3); //return
		emitter.set_constant(0, 3);
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const living_code = p0::remove_dead_code(original_function.body());
	p0::intermediate::function::instruction_vector expected_code;
	{
		p0::intermediate::emitter emitter(expected_code);
		emitter.set_constant(0, 2);
		emitter.jump(2); //the dead code pass is not responsible for removing redundant jumps
	}
	BOOST_CHECK(expected_code == living_code);
}

BOOST_AUTO_TEST_CASE(remove_dead_code_jump_if)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.jump_if(3, 1);
		emitter.set_constant(0, 3);
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const living_code = p0::remove_dead_code(original_function.body());
	BOOST_CHECK(original_code == living_code);
}

BOOST_AUTO_TEST_CASE(remove_dead_code_jump_if_not)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.jump_if_not(3, 1);
		emitter.set_constant(0, 3);
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const living_code = p0::remove_dead_code(original_function.body());
	BOOST_CHECK(original_code == living_code);
}
<commit_msg>clarify the intentions of some dead code tests with comments<commit_after>#include "p0optimize/remove_dead_code.hpp"
#include "p0i/emitter.hpp"
#include <boost/test/unit_test.hpp>

BOOST_AUTO_TEST_CASE(remove_dead_code_empty)
{
	p0::intermediate::function::instruction_vector original_code;
	p0::intermediate::function::instruction_vector const living_code = p0::remove_dead_code(original_code);
	p0::intermediate::function::instruction_vector expected_code;
	BOOST_CHECK(expected_code == living_code);
}

BOOST_AUTO_TEST_CASE(remove_dead_code_jump)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.jump(3); //return
		emitter.set_constant(0, 3);
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const living_code = p0::remove_dead_code(original_function.body());
	p0::intermediate::function::instruction_vector expected_code;
	{
		p0::intermediate::emitter emitter(expected_code);
		emitter.set_constant(0, 2);
		emitter.jump(2);
		//the redundant jump stays here because the dead code pass only removes instructions that are not executed
	}
	BOOST_CHECK(expected_code == living_code);
}

BOOST_AUTO_TEST_CASE(remove_dead_code_jump_if)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.jump_if(3, 1);
		emitter.set_constant(0, 3); //nothing is dead here
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const living_code = p0::remove_dead_code(original_function.body());
	BOOST_CHECK(original_code == living_code);
}

BOOST_AUTO_TEST_CASE(remove_dead_code_jump_if_not)
{
	p0::intermediate::function::instruction_vector original_code;
	{
		p0::intermediate::emitter emitter(original_code);
		emitter.set_constant(0, 2);
		emitter.jump_if_not(3, 1);
		emitter.set_constant(0, 3); //nothing is dead here
	}
	p0::intermediate::function original_function(original_code, 0, 0);
	p0::intermediate::function::instruction_vector const living_code = p0::remove_dead_code(original_function.body());
	BOOST_CHECK(original_code == living_code);
}
<|endoftext|>


<commit_before>/* BZWorkbench
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
#include "model/Primitives.h"

#include <osg/Vec3>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/StateSet>
#include <osg/Group>
#include <osgDB/ReadFile>

// build a primitive given its name
osg::Node* Primitives::BuildByName( const char* name ) {
	string str(name);

	if (str == "box")
		return BuildBox( &osg::Vec3( 1, 1, 1 ) );
	else
		return NULL;
}

// build a box
osg::Node* Primitives::BuildBox(osg::Vec3* size) {
	osg::Group* group = new osg::Group();
	// separate geometry nodes are needed so that each side
	// can have a separate material
	// array is in the order +x -x +y -y +z -z in bzflag coordinates
	osg::Geode* sideNodes[6];
	for (int i = 0; i < 6; i++)
		sideNodes[i] = new osg::Geode();

	// assign geometry nodes to group
	for (int i = 0; i < 6; i++)
		group->addChild(sideNodes[i]);

	// create geometry and assign it to the nodes
	osg::Geometry* sideGeometry[6];
	for (int i = 0; i < 6; i++) {
		sideGeometry[i] = new osg::Geometry();
		sideNodes[i]->addDrawable(sideGeometry[i]);
	}

	// add vertices for all sides
	osg::Vec3Array* pxVerts = new osg::Vec3Array();
	pxVerts->push_back( osg::Vec3( size->x(), -size->y(), 0 ) );
	pxVerts->push_back( osg::Vec3( size->x(), -size->y(), size->z() ) );
	pxVerts->push_back( osg::Vec3( size->x(), size->y(), size->z() ) );
	pxVerts->push_back( osg::Vec3( size->x(), size->y(), 0 ) );
	sideGeometry[0]->setVertexArray(pxVerts);

	osg::Vec3Array* nxVerts = new osg::Vec3Array();
	nxVerts->push_back( osg::Vec3( -size->x(), size->y(), 0 ) );
	nxVerts->push_back( osg::Vec3( -size->x(), size->y(), size->z() ) );
	nxVerts->push_back( osg::Vec3( -size->x(), -size->y(), size->z() ) );
	nxVerts->push_back( osg::Vec3( -size->x(), -size->y(), 0 ) );
	sideGeometry[1]->setVertexArray(nxVerts);

	osg::Vec3Array* pyVerts = new osg::Vec3Array();
	pyVerts->push_back( osg::Vec3( size->x(), size->y(), 0 ) );
	pyVerts->push_back( osg::Vec3( size->x(), size->y(), size->z() ) );
	pyVerts->push_back( osg::Vec3( -size->x(), size->y(), size->z() ) );
	pyVerts->push_back( osg::Vec3( -size->x(), size->y(), 0 ) );
	sideGeometry[2]->setVertexArray(pyVerts);

	osg::Vec3Array* nyVerts = new osg::Vec3Array();
	nyVerts->push_back( osg::Vec3( -size->x(), -size->y(), 0 ) );
	nyVerts->push_back( osg::Vec3( -size->x(), -size->y(), size->z() ) );
	nyVerts->push_back( osg::Vec3( size->x(), -size->y(), size->z() ) );
	nyVerts->push_back( osg::Vec3( size->x(), -size->y(), 0 ) );
	sideGeometry[3]->setVertexArray(nyVerts);

	osg::Vec3Array* pzVerts = new osg::Vec3Array();
	pzVerts->push_back( osg::Vec3( size->x(), size->y(), size->z() ) );
	pzVerts->push_back( osg::Vec3( size->x(), -size->y(), size->z() ) );
	pzVerts->push_back( osg::Vec3( -size->x(), -size->y(), size->z() ) );
	pzVerts->push_back( osg::Vec3( -size->x(), size->y(), size->z() ) );
	sideGeometry[4]->setVertexArray(pzVerts);

	osg::Vec3Array* nzVerts = new osg::Vec3Array();
	nzVerts->push_back( osg::Vec3( size->x(), size->y(), 0 ) );
	nzVerts->push_back( osg::Vec3( size->x(), -size->y(), 0 ) );
	nzVerts->push_back( osg::Vec3( -size->x(), -size->y(), 0 ) );
	nzVerts->push_back( osg::Vec3( -size->x(), size->y(), 0 ) );
	sideGeometry[5]->setVertexArray(nzVerts);

	// generate UV coordinates
	RebuildBoxUV(group, size);

	osg::DrawElementsUInt* side =
		new osg::DrawElementsUInt( osg::PrimitiveSet::QUADS, 0 );
	side->push_back( 0 );
	side->push_back( 1 );
	side->push_back( 2 );
	side->push_back( 3 );

	for (int i = 0; i < 6; i++) {
		sideGeometry[i]->setVertexAttribBinding( 0, osg::Geometry::BIND_PER_VERTEX );
		sideGeometry[i]->addPrimitiveSet(side);
	}

	// load side texture
	osg::Texture2D* sideTexture = new osg::Texture2D();
	sideTexture->setDataVariance( osg::Object::DYNAMIC );
	osg::Image* sideImg = osgDB::readImageFile("share/box/boxwall.png");
	// only set image if it was loaded properly
	if (sideImg)
		sideTexture->setImage(sideImg);

	sideTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
	sideTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);

	// load roof texture
	osg::Texture2D* roofTexture = new osg::Texture2D();
	sideTexture->setDataVariance( osg::Object::DYNAMIC );
	osg::Image* roofImg = osgDB::readImageFile("share/box/roof.png");
	// only set image if it was loaded properly
	if (roofImg)
		roofTexture->setImage(roofImg);

	roofTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
	roofTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);

	// make a state set for associating the textures with the box
	osg::StateSet* state[6];
	for (int i = 0; i < 6; i++) {
		state[i] = new osg::StateSet();

		if (i < 4)
			state[i]->setTextureAttributeAndModes( 0, sideTexture, osg::StateAttribute::ON );
		else
			state[i]->setTextureAttributeAndModes( 0, roofTexture, osg::StateAttribute::ON );

		sideNodes[i]->setStateSet(state[i]);
	}

	return group;
}

void Primitives::RebuildBoxUV(osg::Group* box, const osg::Vec3* size)
{
	// generate UVs
	osg::Vec2Array* sideUVs[6];
	for (int i = 0; i < 6; i++)
		sideUVs[i] = new osg::Vec2Array();

	float xSideScale = size->x()*2/9.42f;
	float ySideScale = size->y()*2/9.42f;
	float zSideScale = size->z()/9.42f;
	float xTopScale = xSideScale*5;
	float yTopScale = ySideScale*5;

	// +x -x
	sideUVs[0]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[0]->push_back( osg::Vec2( 0, ySideScale ) );
	sideUVs[0]->push_back( osg::Vec2( zSideScale, ySideScale ) );
	sideUVs[0]->push_back( osg::Vec2( zSideScale, 0 ) );
	sideUVs[1]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[1]->push_back( osg::Vec2( 0, ySideScale ) );
	sideUVs[1]->push_back( osg::Vec2( zSideScale, ySideScale ) );
	sideUVs[1]->push_back( osg::Vec2( zSideScale, 0 ) );

	// +y -y
	sideUVs[2]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[2]->push_back( osg::Vec2( 0, xSideScale ) );
	sideUVs[2]->push_back( osg::Vec2( zSideScale, xSideScale ) );
	sideUVs[2]->push_back( osg::Vec2( zSideScale, 0 ) );
	sideUVs[3]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[3]->push_back( osg::Vec2( 0, xSideScale ) );
	sideUVs[3]->push_back( osg::Vec2( zSideScale, xSideScale ) );
	sideUVs[3]->push_back( osg::Vec2( zSideScale, 0 ) );

	// +z -z
	sideUVs[4]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[4]->push_back( osg::Vec2( 0, yTopScale ) );
	sideUVs[4]->push_back( osg::Vec2( xTopScale, yTopScale ) );
	sideUVs[4]->push_back( osg::Vec2( xTopScale, 0 ) );
	sideUVs[5]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[5]->push_back( osg::Vec2( 0, yTopScale ) );
	sideUVs[5]->push_back( osg::Vec2( xTopScale, yTopScale ) );
	sideUVs[5]->push_back( osg::Vec2( xTopScale, 0 ) );

	for (int i = 0; i < 6; i++) {
		osg::Geode* geode = (osg::Geode*)box->getChild(i);
		osg::Geometry* geom = (osg::Geometry*)geode->getDrawable(0);
		geom->setTexCoordArray(0, sideUVs[i]);
	}
}

// build a pyramid
osg::Geode* Primitives::BuildPyramid() {
	return NULL; // FIXME: implement
}

// build a teleporter
osg::Geode* Primitives::BuildTeleporter() {
	return NULL; // FIXME: implement
}

// build a blue base
osg::Geode* Primitives::BuildBlueBase() {
	return NULL; // FIXME: implement
}

// build a green base
osg::Geode* Primitives::BuildGreenBase() {
	return NULL; // FIXME: implement
}

// build a red base
osg::Geode* Primitives::BuildRedBase() {
	return NULL; // FIXME: implement
}

// build a purple base
osg::Geode* Primitives::BuildPurpleBase() {
	return NULL; // FIXME: implement
}
<commit_msg>UVs for box should now be generated correctly but they still need to be compared to bzflag and tweaked if necessary<commit_after>/* BZWorkbench
 * Copyright (c) 1993 - 2008 Tim Riker
 *
 * This package is free software;  you can redistribute it and/or
 * modify it under the terms of the license found in the file
 * named COPYING that should have accompanied this file.
 *
 * THIS PACKAGE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
 */
#include "model/Primitives.h"

#include <osg/Vec3>
#include <osg/Geometry>
#include <osg/Texture2D>
#include <osg/StateSet>
#include <osg/Group>
#include <osgDB/ReadFile>

// build a primitive given its name
osg::Node* Primitives::BuildByName( const char* name ) {
	string str(name);

	if (str == "box")
		return BuildBox( &osg::Vec3( 1, 1, 1 ) );
	else
		return NULL;
}

// build a box
osg::Node* Primitives::BuildBox(osg::Vec3* size) {
	osg::Group* group = new osg::Group();
	// separate geometry nodes are needed so that each side
	// can have a separate material
	// array is in the order +x -x +y -y +z -z in bzflag coordinates
	osg::Geode* sideNodes[6];
	for (int i = 0; i < 6; i++)
		sideNodes[i] = new osg::Geode();

	// assign geometry nodes to group
	for (int i = 0; i < 6; i++)
		group->addChild(sideNodes[i]);

	// create geometry and assign it to the nodes
	osg::Geometry* sideGeometry[6];
	for (int i = 0; i < 6; i++) {
		sideGeometry[i] = new osg::Geometry();
		sideNodes[i]->addDrawable(sideGeometry[i]);
	}

	// add vertices for all sides
	osg::Vec3Array* pxVerts = new osg::Vec3Array();
	pxVerts->push_back( osg::Vec3( size->x(), -size->y(), 0 ) );
	pxVerts->push_back( osg::Vec3( size->x(), -size->y(), size->z() ) );
	pxVerts->push_back( osg::Vec3( size->x(), size->y(), size->z() ) );
	pxVerts->push_back( osg::Vec3( size->x(), size->y(), 0 ) );
	sideGeometry[0]->setVertexArray(pxVerts);

	osg::Vec3Array* nxVerts = new osg::Vec3Array();
	nxVerts->push_back( osg::Vec3( -size->x(), size->y(), 0 ) );
	nxVerts->push_back( osg::Vec3( -size->x(), size->y(), size->z() ) );
	nxVerts->push_back( osg::Vec3( -size->x(), -size->y(), size->z() ) );
	nxVerts->push_back( osg::Vec3( -size->x(), -size->y(), 0 ) );
	sideGeometry[1]->setVertexArray(nxVerts);

	osg::Vec3Array* pyVerts = new osg::Vec3Array();
	pyVerts->push_back( osg::Vec3( size->x(), size->y(), 0 ) );
	pyVerts->push_back( osg::Vec3( size->x(), size->y(), size->z() ) );
	pyVerts->push_back( osg::Vec3( -size->x(), size->y(), size->z() ) );
	pyVerts->push_back( osg::Vec3( -size->x(), size->y(), 0 ) );
	sideGeometry[2]->setVertexArray(pyVerts);

	osg::Vec3Array* nyVerts = new osg::Vec3Array();
	nyVerts->push_back( osg::Vec3( -size->x(), -size->y(), 0 ) );
	nyVerts->push_back( osg::Vec3( -size->x(), -size->y(), size->z() ) );
	nyVerts->push_back( osg::Vec3( size->x(), -size->y(), size->z() ) );
	nyVerts->push_back( osg::Vec3( size->x(), -size->y(), 0 ) );
	sideGeometry[3]->setVertexArray(nyVerts);

	osg::Vec3Array* pzVerts = new osg::Vec3Array();
	pzVerts->push_back( osg::Vec3( size->x(), size->y(), size->z() ) );
	pzVerts->push_back( osg::Vec3( size->x(), -size->y(), size->z() ) );
	pzVerts->push_back( osg::Vec3( -size->x(), -size->y(), size->z() ) );
	pzVerts->push_back( osg::Vec3( -size->x(), size->y(), size->z() ) );
	sideGeometry[4]->setVertexArray(pzVerts);

	osg::Vec3Array* nzVerts = new osg::Vec3Array();
	nzVerts->push_back( osg::Vec3( size->x(), size->y(), 0 ) );
	nzVerts->push_back( osg::Vec3( size->x(), -size->y(), 0 ) );
	nzVerts->push_back( osg::Vec3( -size->x(), -size->y(), 0 ) );
	nzVerts->push_back( osg::Vec3( -size->x(), size->y(), 0 ) );
	sideGeometry[5]->setVertexArray(nzVerts);

	// generate UV coordinates
	RebuildBoxUV(group, size);

	osg::DrawElementsUInt* side =
		new osg::DrawElementsUInt( osg::PrimitiveSet::QUADS, 0 );
	side->push_back( 0 );
	side->push_back( 1 );
	side->push_back( 2 );
	side->push_back( 3 );

	for (int i = 0; i < 6; i++) {
		sideGeometry[i]->setVertexAttribBinding( 0, osg::Geometry::BIND_PER_VERTEX );
		sideGeometry[i]->addPrimitiveSet(side);
	}

	// load side texture
	osg::Texture2D* sideTexture = new osg::Texture2D();
	sideTexture->setDataVariance( osg::Object::DYNAMIC );
	osg::Image* sideImg = osgDB::readImageFile("share/box/boxwall.png");
	// only set image if it was loaded properly
	if (sideImg)
		sideTexture->setImage(sideImg);

	sideTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
	sideTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);

	// load roof texture
	osg::Texture2D* roofTexture = new osg::Texture2D();
	sideTexture->setDataVariance( osg::Object::DYNAMIC );
	osg::Image* roofImg = osgDB::readImageFile("share/box/roof.png");
	// only set image if it was loaded properly
	if (roofImg)
		roofTexture->setImage(roofImg);

	roofTexture->setWrap(osg::Texture::WRAP_S, osg::Texture::REPEAT);
	roofTexture->setWrap(osg::Texture::WRAP_T, osg::Texture::REPEAT);

	// make a state set for associating the textures with the box
	osg::StateSet* state[6];
	for (int i = 0; i < 6; i++) {
		state[i] = new osg::StateSet();

		if (i < 4)
			state[i]->setTextureAttributeAndModes( 0, sideTexture, osg::StateAttribute::ON );
		else
			state[i]->setTextureAttributeAndModes( 0, roofTexture, osg::StateAttribute::ON );

		sideNodes[i]->setStateSet(state[i]);
	}

	return group;
}

void Primitives::RebuildBoxUV(osg::Group* box, const osg::Vec3* size)
{
	// generate UVs
	osg::Vec2Array* sideUVs[6];
	for (int i = 0; i < 6; i++)
		sideUVs[i] = new osg::Vec2Array();

	float xSideScale = size->x()*2/9.42f;
	float ySideScale = size->y()*2/9.42f;
	float zSideScale = size->z()/9.42f;
	float xTopScale = xSideScale*5;
	float yTopScale = ySideScale*5;

	// +x -x
	sideUVs[0]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[0]->push_back( osg::Vec2( 0, zSideScale ) );
	sideUVs[0]->push_back( osg::Vec2( ySideScale, zSideScale ) );
	sideUVs[0]->push_back( osg::Vec2( ySideScale, 0 ) );
	sideUVs[1]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[1]->push_back( osg::Vec2( 0, zSideScale ) );
	sideUVs[1]->push_back( osg::Vec2( ySideScale, zSideScale ) );
	sideUVs[1]->push_back( osg::Vec2( ySideScale, 0 ) );

	// +y -y
	sideUVs[2]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[2]->push_back( osg::Vec2( 0, zSideScale ) );
	sideUVs[2]->push_back( osg::Vec2( xSideScale, zSideScale ) );
	sideUVs[2]->push_back( osg::Vec2( xSideScale, 0 ) );
	sideUVs[3]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[3]->push_back( osg::Vec2( 0, zSideScale ) );
	sideUVs[3]->push_back( osg::Vec2( xSideScale, zSideScale ) );
	sideUVs[3]->push_back( osg::Vec2( xSideScale, 0 ) );

	// +z -z
	sideUVs[4]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[4]->push_back( osg::Vec2( 0, yTopScale ) );
	sideUVs[4]->push_back( osg::Vec2( xTopScale, yTopScale ) );
	sideUVs[4]->push_back( osg::Vec2( xTopScale, 0 ) );
	sideUVs[5]->push_back( osg::Vec2( 0, 0 ) );
	sideUVs[5]->push_back( osg::Vec2( 0, yTopScale ) );
	sideUVs[5]->push_back( osg::Vec2( xTopScale, yTopScale ) );
	sideUVs[5]->push_back( osg::Vec2( xTopScale, 0 ) );

	for (int i = 0; i < 6; i++) {
		osg::Geode* geode = (osg::Geode*)box->getChild(i);
		osg::Geometry* geom = (osg::Geometry*)geode->getDrawable(0);
		geom->setTexCoordArray(0, sideUVs[i]);
	}
}

// build a pyramid
osg::Geode* Primitives::BuildPyramid() {
	return NULL; // FIXME: implement
}

// build a teleporter
osg::Geode* Primitives::BuildTeleporter() {
	return NULL; // FIXME: implement
}

// build a blue base
osg::Geode* Primitives::BuildBlueBase() {
	return NULL; // FIXME: implement
}

// build a green base
osg::Geode* Primitives::BuildGreenBase() {
	return NULL; // FIXME: implement
}

// build a red base
osg::Geode* Primitives::BuildRedBase() {
	return NULL; // FIXME: implement
}

// build a purple base
osg::Geode* Primitives::BuildPurpleBase() {
	return NULL; // FIXME: implement
}
<|endoftext|>


<commit_before>#include "rapid_perception/template_matching_heat_mapper.h"

#include <algorithm>
#include <iostream>
#include <math.h>
#include <vector>

#include "Eigen/Core"
#include "pcl/PointIndices.h"
#include "pcl/common/common.h"
#include "pcl/filters/extract_indices.h"
#include "pcl/filters/random_sample.h"
#include "pcl/registration/icp.h"
#include "pcl/point_cloud.h"
#include "pcl/point_types.h"
#include "pcl/recognition/line_rgbd.h"

#include "rapid_msgs/Roi3D.h"
#include "rapid_perception/icp_fitness_functions.h"
#include "rapid_viz/publish.h"

typedef pcl::PointXYZRGB PointC;
typedef pcl::PointCloud<PointC> PointCloudC;
using std::vector;

namespace rapid {
namespace perception {
TemplateMatchingHeatMapper::TemplateMatchingHeatMapper()
    : scene_(),
      object_(),
      object_roi_(),
      sample_ratio_(0.05),
      max_samples_(1000) {}

void TemplateMatchingHeatMapper::Compute(pcl::PointIndicesPtr indices,
                                         Eigen::VectorXd* importances) {
  indices->indices.clear();
  int num_samples = static_cast<int>(round(sample_ratio_ * scene_->size()));
  num_samples = std::min(num_samples, max_samples_);
  int points_between_samples =
      round(scene_->size() / static_cast<double>(num_samples));
  size_t sample_index = 0;
  while (sample_index < scene_->size()) {
    indices->indices.push_back(sample_index);
    sample_index += points_between_samples;
  }
  ROS_INFO("Randomly sampled %ld points", indices->indices.size());

  PointCloudC::Ptr working_object(new PointCloudC);
  PointCloudC::Ptr aligned_object(new PointCloudC);
  importances->resize(indices->indices.size());
  pcl::IterativeClosestPoint<PointC, PointC> icp;
  icp.setMaximumIterations(0);
  icp.setInputTarget(scene_);
  for (size_t indices_i = 0; indices_i < indices->indices.size(); ++indices_i) {
    int index = indices->indices[indices_i];
    const PointC& center = scene_->points[index];
    // Transform the object to be centered on the center point
    // So far we just use a translation offset
    // Also assume that the object and scene are in the same frame
    Eigen::Vector3d translation;
    translation.x() = center.x - object_center_.x();
    translation.y() = center.y - object_center_.y();
    translation.z() = center.z - object_center_.z();
    pcl::transformPointCloud(*object_, *working_object, translation,
                             Eigen::Quaterniond::Identity());

    // Run ICP
    icp.setInputSource(working_object);
    icp.align(*aligned_object);

    rapid_msgs::Roi3D roi = object_roi_;
    roi.transform.translation.x += translation.x();
    roi.transform.translation.y += translation.y();
    roi.transform.translation.z += translation.z();
    double fitness = ComputeIcpFitness(scene_, aligned_object, roi);
    (*importances)(indices_i) = fitness;

    // viz::PublishCloud(heatmap_pub_, *aligned_object);
    // if (debug_) {
    //  std::cout << "Score: " << fitness;
    //  std::string input;
    //  std::getline(std::cin, input);
    //}
  }

  double min = importances->minCoeff();
  importances->array() -= min;
  double max = importances->maxCoeff();
  (*importances) /= max;
  importances->array() = 1 - importances->array();

  // Color point cloud for visualization
  PointCloudC::Ptr working_scene(new PointCloudC);
  *working_scene = *scene_;
  for (size_t indices_i = 0; indices_i < indices->indices.size(); ++indices_i) {
    int color = static_cast<int>(round(255 * (*importances)(indices_i)));
    int index = indices->indices[indices_i];
    working_scene->points[index].r = color;
    working_scene->points[index].g = color;
    working_scene->points[index].b = color;
  }
  PointCloudC::Ptr viz_cloud(new PointCloudC());
  pcl::ExtractIndices<PointC> extract;
  extract.setInputCloud(working_scene);
  extract.setIndices(indices);
  extract.filter(*viz_cloud);
  viz::PublishCloud(heatmap_pub_, *viz_cloud);
}

void TemplateMatchingHeatMapper::set_scene(PointCloudC::Ptr scene) {
  scene_ = scene;
}

void TemplateMatchingHeatMapper::set_object(PointCloudC::Ptr object) {
  object_ = object;
  Eigen::Vector4f min_pt;
  Eigen::Vector4f max_pt;
  pcl::getMinMax3D(*object_, min_pt, max_pt);
  object_center_.x() = (max_pt.x() + min_pt.x()) / 2;
  object_center_.y() = (max_pt.y() + min_pt.y()) / 2;
  object_center_.z() = (max_pt.z() + min_pt.z()) / 2;
}

void TemplateMatchingHeatMapper::set_object_roi(const rapid_msgs::Roi3D& roi) {
  object_roi_ = roi;
}

void TemplateMatchingHeatMapper::set_sample_ratio(double val) {
  sample_ratio_ = val;
}

void TemplateMatchingHeatMapper::set_max_samples(int val) {
  max_samples_ = val;
}
}  // namespace perception
}  // namespace rapid
<commit_msg>Use a different method of sampling deterministically. (#83)<commit_after>#include "rapid_perception/template_matching_heat_mapper.h"

#include <algorithm>
#include <iostream>
#include <math.h>
#include <vector>

#include "Eigen/Core"
#include "pcl/PointIndices.h"
#include "pcl/common/common.h"
#include "pcl/filters/extract_indices.h"
#include "pcl/filters/random_sample.h"
#include "pcl/registration/icp.h"
#include "pcl/point_cloud.h"
#include "pcl/point_types.h"
#include "pcl/recognition/line_rgbd.h"

#include "rapid_msgs/Roi3D.h"
#include "rapid_perception/icp_fitness_functions.h"
#include "rapid_viz/publish.h"

typedef pcl::PointXYZRGB PointC;
typedef pcl::PointCloud<PointC> PointCloudC;
using std::vector;

namespace rapid {
namespace perception {
TemplateMatchingHeatMapper::TemplateMatchingHeatMapper()
    : scene_(),
      object_(),
      object_roi_(),
      sample_ratio_(0.05),
      max_samples_(1000) {}

void TemplateMatchingHeatMapper::Compute(pcl::PointIndicesPtr indices,
                                         Eigen::VectorXd* importances) {
  indices->indices.clear();

  // Sample randomly
  int num_samples = static_cast<int>(round(sample_ratio_ * scene_->size()));
  num_samples = std::min(num_samples, max_samples_);
  pcl::RandomSample<PointC> random;
  random.setSeed(0);
  random.setInputCloud(scene_);
  random.setSample(num_samples);
  random.filter(indices->indices);
  ROS_INFO("Randomly sampled %ld points", indices->indices.size());

  PointCloudC::Ptr working_object(new PointCloudC);
  PointCloudC::Ptr aligned_object(new PointCloudC);
  importances->resize(indices->indices.size());
  pcl::IterativeClosestPoint<PointC, PointC> icp;
  icp.setMaximumIterations(0);
  icp.setInputTarget(scene_);
  for (size_t indices_i = 0; indices_i < indices->indices.size(); ++indices_i) {
    int index = indices->indices[indices_i];
    const PointC& center = scene_->points[index];
    // Transform the object to be centered on the center point
    // So far we just use a translation offset
    // Also assume that the object and scene are in the same frame
    Eigen::Vector3d translation;
    translation.x() = center.x - object_center_.x();
    translation.y() = center.y - object_center_.y();
    translation.z() = center.z - object_center_.z();
    pcl::transformPointCloud(*object_, *working_object, translation,
                             Eigen::Quaterniond::Identity());

    // Run ICP
    icp.setInputSource(working_object);
    icp.align(*aligned_object);

    rapid_msgs::Roi3D roi = object_roi_;
    roi.transform.translation.x += translation.x();
    roi.transform.translation.y += translation.y();
    roi.transform.translation.z += translation.z();
    double fitness = ComputeIcpFitness(scene_, aligned_object, roi);
    (*importances)(indices_i) = fitness;

    // viz::PublishCloud(heatmap_pub_, *aligned_object);
    // if (debug_) {
    //  std::cout << "Score: " << fitness;
    //  std::string input;
    //  std::getline(std::cin, input);
    //}
  }

  double min = importances->minCoeff();
  importances->array() -= min;
  double max = importances->maxCoeff();
  (*importances) /= max;
  importances->array() = 1 - importances->array();

  // Color point cloud for visualization
  PointCloudC::Ptr working_scene(new PointCloudC);
  *working_scene = *scene_;
  for (size_t indices_i = 0; indices_i < indices->indices.size(); ++indices_i) {
    int color = static_cast<int>(round(255 * (*importances)(indices_i)));
    int index = indices->indices[indices_i];
    working_scene->points[index].r = color;
    working_scene->points[index].g = color;
    working_scene->points[index].b = color;
  }
  PointCloudC::Ptr viz_cloud(new PointCloudC());
  pcl::ExtractIndices<PointC> extract;
  extract.setInputCloud(working_scene);
  extract.setIndices(indices);
  extract.filter(*viz_cloud);
  viz::PublishCloud(heatmap_pub_, *viz_cloud);
}

void TemplateMatchingHeatMapper::set_scene(PointCloudC::Ptr scene) {
  scene_ = scene;
}

void TemplateMatchingHeatMapper::set_object(PointCloudC::Ptr object) {
  object_ = object;
  Eigen::Vector4f min_pt;
  Eigen::Vector4f max_pt;
  pcl::getMinMax3D(*object_, min_pt, max_pt);
  object_center_.x() = (max_pt.x() + min_pt.x()) / 2;
  object_center_.y() = (max_pt.y() + min_pt.y()) / 2;
  object_center_.z() = (max_pt.z() + min_pt.z()) / 2;
}

void TemplateMatchingHeatMapper::set_object_roi(const rapid_msgs::Roi3D& roi) {
  object_roi_ = roi;
}

void TemplateMatchingHeatMapper::set_sample_ratio(double val) {
  sample_ratio_ = val;
}

void TemplateMatchingHeatMapper::set_max_samples(int val) {
  max_samples_ = val;
}
}  // namespace perception
}  // namespace rapid
<|endoftext|>


<commit_before>#include "GLFWController.hpp"
#include "ModelView.hpp"
#include "AffinePoint.hpp"
#include "AffineVector.hpp"
#include "ModelViewWithShader.hpp"
#include "Block.hpp"
#include "DependencyContainer.hpp"
#include "otuchaConfig.h"

#include <memory>
#include <iostream>

using namespace otucha;

void set3DViewingInformation(double xyz[6])
{
	ModelView::setMCRegionOfInterest(xyz);

	s1::AffinePoint eye(1.0, 1.0, 1.0);
	s1::AffinePoint center(0, 0, 0);
	s1::AffineVector up(0, 1, 0);

	ModelView::setEyeCenterUp(eye, center, up);

	double zpp = -1.0;
	double zmin = -99.0;
	double zmax = -0.01;

	ModelView::setProjectionType(PERSPECTIVE);
	ModelView::setZProjectionPlane(zpp);
	ModelView::setEyeCoordinatesZMinZMax(zmin, zmax);
}

int main(int argc, char* argv[])
{
	fprintf(stdout, "%s Version %d.%d\n", argv[0], otucha_VERSION_MAJOR, otucha_VERSION_MINOR);
	GLFWController c("otucha", Controller::DEPTH);
	c.reportVersions(std::cout);
	std::string appPath(argv[0]);
	unsigned found = appPath.find_last_of("/\\");
	std::string appDir = appPath.substr(0, found + 1);
	DependencyContainer::getSingleton()->setAppDir(appDir);
	ModelViewWithShader::setShaderSources(appDir + "simple.vsh", appDir + "simple.fsh");
	c.addModel(std::make_shared<Block>(-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f));

	glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
	double xyz[6];
	c.getOverallMCBoundingBox(xyz);
	set3DViewingInformation(xyz);

	// test console code to be removed later
	DependencyContainer::getSingleton()->getConsole()->registerCommand(L"test", [](warbler::t_consoleArgs_ptr args) {
		std::cout << "Console online" << std::endl;
	}, std::make_shared<warbler::t_consoleArgTypes>());
	DependencyContainer::getSingleton()->getConsole()->executeCommand(L"test");
	// end test console code

	auto fontFace = DependencyContainer::getSingleton()->getFontFace();

	c.run();

	return 0;
}
<commit_msg>Switch to rffalcon from s1 in otucha main<commit_after>#include "GLFWController.hpp"
#include "ModelView.hpp"
#include "AffinePoint.hpp"
#include "AffineVector.hpp"
#include "ModelViewWithShader.hpp"
#include "Block.hpp"
#include "DependencyContainer.hpp"
#include "otuchaConfig.h"

#include <memory>
#include <iostream>

using namespace otucha;

void set3DViewingInformation(double xyz[6])
{
	ModelView::setMCRegionOfInterest(xyz);

	rffalcon::AffinePoint eye(1.0, 1.0, 1.0);
	rffalcon::AffinePoint center(0, 0, 0);
	rffalcon::AffineVector up(0, 1, 0);

	ModelView::setEyeCenterUp(eye, center, up);

	double zpp = -1.0;
	double zmin = -99.0;
	double zmax = -0.01;

	ModelView::setProjectionType(PERSPECTIVE);
	ModelView::setZProjectionPlane(zpp);
	ModelView::setEyeCoordinatesZMinZMax(zmin, zmax);
}

int main(int argc, char* argv[])
{
	fprintf(stdout, "%s Version %d.%d\n", argv[0], otucha_VERSION_MAJOR, otucha_VERSION_MINOR);
	GLFWController c("otucha", Controller::DEPTH);
	c.reportVersions(std::cout);
	std::string appPath(argv[0]);
	unsigned found = appPath.find_last_of("/\\");
	std::string appDir = appPath.substr(0, found + 1);
	DependencyContainer::getSingleton()->setAppDir(appDir);
	ModelViewWithShader::setShaderSources(appDir + "simple.vsh", appDir + "simple.fsh");
	c.addModel(std::make_shared<Block>(-0.5f, -0.5f, -0.5f, 1.0f, 1.0f, 1.0f));

	glClearColor(0.9f, 0.9f, 0.9f, 1.0f);
	double xyz[6];
	c.getOverallMCBoundingBox(xyz);
	set3DViewingInformation(xyz);

	// test console code to be removed later
	DependencyContainer::getSingleton()->getConsole()->registerCommand(L"test", [](warbler::t_consoleArgs_ptr args) {
		std::cout << "Console online" << std::endl;
	}, std::make_shared<warbler::t_consoleArgTypes>());
	DependencyContainer::getSingleton()->getConsole()->executeCommand(L"test");
	// end test console code

	auto fontFace = DependencyContainer::getSingleton()->getFontFace();

	c.run();

	return 0;
}
<|endoftext|>


<commit_before>/**
 *  @author Koen Wolters <koen.wolters@cern.ch>
 */

#include "Messenger.hpp"

#include <string>

#include "../utils/type.h"
#include "../utils/log.h"

#include "../module/Module.hpp"
#include "Message.hpp"

using namespace allpix;

// Constructor
Messenger::Messenger(): delegates_() {}

// Destructor
Messenger::~Messenger() {
    // delete all delegates
    for (auto &type_delegates : delegates_) {
        for (auto &name_delegates : type_delegates.second) {
            for (auto &delegate : name_delegates.second) {
                delete delegate;
            }
        }
    }
}

// Dispatch the message
void Messenger::dispatchMessage(std::shared_ptr<Message> msg, std::string name) {
    bool send = false;

    // create type identifier from typeid
    const Message *inst = msg.get();
    std::type_index type_idx = typeid(inst);

    // NOTE: we are not sending messages with unspecified names to everyone listening
    if (!name.empty()) {
        for (auto &delegate : delegates_[type_idx][name]) {
            delegate->call(msg);
            send = true;
        }
    }

    // NOTE: we do send all messages also to general listeners
    for (auto &delegate : delegates_[type_idx][""]) {
        delegate->call(msg);
        send = true;
    }

    if (!send) {
        LOG(WARNING) << "Dispatched message of type " << allpix::demangle(type_idx.name()) << " has no receivers... this is probably not what you want!";
    }
}
<commit_msg>fix bug in messenger dispatching<commit_after>/**
 *  @author Koen Wolters <koen.wolters@cern.ch>
 */

#include "Messenger.hpp"

#include <string>

#include "../utils/type.h"
#include "../utils/log.h"

#include "../module/Module.hpp"
#include "Message.hpp"

using namespace allpix;

// Constructor
Messenger::Messenger(): delegates_() {}

// Destructor
Messenger::~Messenger() {
    // delete all delegates
    for (auto &type_delegates : delegates_) {
        for (auto &name_delegates : type_delegates.second) {
            for (auto &delegate : name_delegates.second) {
                delete delegate;
            }
        }
    }
}

// Dispatch the message
void Messenger::dispatchMessage(std::shared_ptr<Message> msg, std::string name) {
    bool send = false;

    // create type identifier from typeid
    const Message *inst = msg.get();
    std::type_index type_idx = typeid(*inst);

    // NOTE: we are not sending messages with unspecified names to everyone listening
    if (!name.empty()) {
        for (auto &delegate : delegates_[type_idx][name]) {
            delegate->call(msg);
            send = true;
        }
    }

    // NOTE: we do send all messages also to general listeners
    for (auto &delegate : delegates_[type_idx][""]) {
        delegate->call(msg);
        send = true;
    }

    if (!send) {
        LOG(WARNING) << "Dispatched message of type " << allpix::demangle(type_idx.name()) << " has no receivers... this is probably not what you want!";
    }
}
<|endoftext|>


<commit_before>#include "game/race_tracker.h"

using game::Position;
using game::Race;

namespace game {

RaceTracker::RaceTracker(game::CarTracker& car_tracker,
          const game::Race& race, const std::string& color)
  : car_tracker_(car_tracker), race_(race), color_(color),
    crash_time_(-1), crash_recorded_(false) {
}

void RaceTracker::Record(const std::map<std::string, Position>& positions) {
  if (!crash_recorded_ && crash_time_ != -1)
    crash_time_++;

  DetectBumps(positions);
  for (auto& p : positions) {
    if (indexes_.find(p.first) == indexes_.end()) {
      indexes_[p.first] = enemies_.size();
      enemies_.push_back(EnemyTracker(car_tracker_, race_,  p.first, p.second));
    } else {
      enemies_[indexes_[p.first]].RecordPosition(p.second);
    }
  }
}

void RaceTracker::DetectBumps(const std::map<std::string, Position>& positions) {
  bumps_.clear();

  const double kCarLength = race_.cars()[0].length();
  for (auto& a : positions) {
    if (indexes_.find(a.first) == indexes_.end()) continue;
    for (auto& b : positions) {
      if (indexes_.find(b.first) == indexes_.end()) continue;

      if (a.first == b.first) continue;
      if (enemy(a.first).is_dead() ||
          enemy(b.first).is_dead())
        continue;

      double distance = car_tracker_.DistanceBetween(a.second, b.second);
      // We need to change start lane and endlane, as for switches,
      // bump only occurs if those 2 params are equal for both cars
      if (distance <= kCarLength + 1e-9 &&
          a.second.start_lane() == b.second.start_lane() &&
          a.second.end_lane() == b.second.end_lane()) {
        bumps_.push_back({ a.first, b.first });
        printf("Bump detected! %s %s\n", a.first.c_str(), b.first.c_str());
      }
    }
  }
}

bool RaceTracker::BumpOccured(const std::string& color, const std::string& color2) {
  for (auto& b : bumps_) {
    if ((b.first == color && b.second == color2) ||
        (b.second == color && b.first == color2))
      return true;
  }
  return false;
}

void RaceTracker::RecordLapTime(const std::string& color, int time) {
  if (indexes_.find(color) == indexes_.end())
    return;

  enemies_[indexes_[color]].RecordLapTime(time);
}

// TODO test
std::vector<std::string> RaceTracker::CarsBetween(int from, int to, int lane) {
  std::vector<std::string> result;
  for (auto& i : indexes_) {
    if (i.first == color_) continue;
    if (race_.track().IsBetween(enemies_[i.second].state().position(), from, to) &&
        enemies_[i.second].state().position().end_lane() == lane)
      result.push_back(i.first);
  }
  return result;
}

std::vector<EnemyTracker*> RaceTracker::PredictedCarsBetween(int from, int to, int lane) {
  auto& me = enemies_[indexes_[color_]];
  Position position;
  position.set_piece(to);
  position.set_piece_distance(0);
  int time = me.TimeToPosition(position);

  std::vector<EnemyTracker*> result;
  for (auto& i : indexes_) {
    if (i.first == color_) continue;
    auto& enemy = enemies_[i.second];

    if (enemy.is_dead() && enemy.time_to_spawn() > 10000)
      continue;

    // If Im already ahead - ignore
    if (race_.track().IsFirstInFront(me.state().position(), enemy.state().position()))
      continue;

    // Check lane
    if (enemy.state().position().end_lane() == lane) {

      // If dead, check if he respawns after I pass him
      if (enemy.is_dead()) {
        if (!race_.track().IsFirstInFront(
            me.PositionAfterTime(enemy.time_to_spawn() - 15),
            enemy.state().position())) {
          result.push_back(&enemies_[i.second]);
        }
        continue;
      }

      if (race_.track().IsBetween(enemy.PositionAfterTime(time), from, to))
        result.push_back(&enemies_[i.second]);
    }
  }
  return result;
}

// Check if I can die by just going all out
bool RaceTracker::IsSafeAttack(const Command& command, Command* safe_command) {
  return IsSafe(command, safe_command, Command(1));
}

// Check if I can die if he brakes and me either
bool RaceTracker::IsSafeInFront(const Command& command, Command* safe_command) {
  return IsSafe(command, safe_command, Command(0));
}

bool RaceTracker::IsSafe(const Command& command, Command* safe_command, const Command& our_command) {
  const auto& my_state = car_tracker_.current_state();
  bool attack = our_command.throttle() == 1.0;

  std::map<std::string, CarState> states;
  for (const auto& enemy : enemies_) {
    if (enemy.color() == color_) {
      states[color_] = my_state;
      continue;
    }

    if (enemy.is_dead()) {
      continue;
    }

    states[enemy.color()] = enemy.state();
  }
  const double kCarLength = race_.cars().at(0).length();

  bool middle_state_not_safe = false;
  bool bump_inevitable = false;
  bool attack_not_successful = false;
  std::set<string> cars_bumped;
  for (int ticks_after = 0; ticks_after < 100; ++ticks_after) {
    CarState my_prev = states[color_];
    Command c = our_command;
    if (ticks_after == 0) c = command;
    CarState my_new = car_tracker_.Predict(my_prev, c);
    states[color_] = my_new;

    if (!car_tracker_.crash_model().IsSafe(my_new.position().angle())) {
      *safe_command = Command(0);
      return false;
    }

    bool bumped = false;
    double min_velocity = 100000.0;
    for (const auto& p : states) {
      if (p.first == color_) continue;

      double velocity = 0.0;
      int full_throttle_ticks = 0;
      Position bump_position = car_tracker_.PredictPosition(my_new.position(), kCarLength);
      if (car_tracker_.MinVelocity(p.second, ticks_after + 1, bump_position, &velocity, &full_throttle_ticks)) {
        // std::cout << "possible bump in " << i + 1 << " ticks" << std::endl;
        // std::cout << "min_velocity = " << velocity << std::endl;
        // If the velocity is higher than ours, he probably was behind us.
        if (velocity < my_new.velocity()) {
          cars_bumped.insert(p.first);
          bumped = true;
          min_velocity = fmin(min_velocity, velocity);

          // TODO make sure he actually will crash
          if (attack) {
            CarState s = p.second;
            for (int i = 0; i < full_throttle_ticks; ++i) { s = car_tracker_.Predict(s, Command(1)); }
            for (int i = 0; i < ticks_after - full_throttle_ticks; ++i) { s = car_tracker_.Predict(s, Command(0)); }
            s.set_velocity(my_new.velocity() * 0.9);
            if (car_tracker_.IsSafe(s)) {
              attack_not_successful = true;
            }
          }
        }
      } else {
        // This means, he is not able to run away from us, so there is no point
        // in simulating more ticks.
        if (cars_bumped.count(p.first) > 0) {
          bump_inevitable = true;
        }
      }
    }

    if (bump_inevitable) {
      std::cout << "He is not able to run away from us, we got this :)." << std::endl;
      break;
    }
    if (!bumped) continue;

    if (!car_tracker_.IsSafe(my_new)) {
      middle_state_not_safe = true;
    }

    CarState state = my_prev;
    state.set_velocity(0.8 * min_velocity);
    if (!car_tracker_.IsSafe(state)) {
      if (our_command.throttle() != 1) {
        std::cout << "WE ARE TOO CLOSE AND WILL DIE. Slowing down (prev)." << std::endl;
      }
      *safe_command = Command(0);
      return false;
    }

    state = my_new;
    state.set_velocity(0.8 * min_velocity);
    if (!car_tracker_.IsSafe(state)) {
      if (our_command.throttle() != 1) {
        std::cout << "WE ARE TOO CLOSE AND WILL DIE. Slowing down (new)." << std::endl;
      }
      *safe_command = Command(0);
      return false;
    }
  }

  if (middle_state_not_safe && !bump_inevitable) {
    std::cout << "middle_state_not_safe && !bump_inevitable" << std::endl;
    *safe_command = Command(0);
    return false;
  }

  if (attack && attack_not_successful) {
    std::cout << "Attack would not crash the opponent." << std::endl;
    *safe_command = command;
    return false;
  }

  // We survived 50 ticks, we should be ok.
  return true;
}

bool RaceTracker::IsSafeBehind(const Command& command, Command* safe_command) {
  const auto& my_state = car_tracker_.current_state();
  const double kCarLength = race_.cars().at(0).length();
  const double kDangerousDistance = 20;
  const int kTicks = 10;

  for (const auto& enemy : enemies_) {
    if (enemy.color() == color_) {
      // states[color_] = car_tracker_.Predict(my_state, command);
      continue;
    }

    if (enemy.is_dead()) {
      continue;
    }

    double distance = car_tracker_.DistanceBetween(enemy.state().position(), my_state.position());
    if (distance > kDangerousDistance + kCarLength) {
      // std::cout << "He is too far, assuming safe" << std::endl;
      continue;
    }

    CarState my_prev = car_tracker_.Predict(my_state, command);
    CarState his_prev = car_tracker_.Predict(enemy.state(), Command(1));

    for (int i = 0; i < kTicks; ++i) {
      CarState my_new = car_tracker_.Predict(my_prev, Command(0));
      CarState his_new = car_tracker_.Predict(his_prev, Command(1));

      // BUMP
      if (car_tracker_.DistanceBetween(his_new.position(), my_new.position()) < kCarLength) {
        CarState tmp = my_new;
        tmp.set_velocity(0.9 * his_new.velocity());
        if (!car_tracker_.IsSafe(tmp)) {
          std::cout << "Not safe, he can bump into me :(" << std::endl;
          *safe_command = Command(0);
          return false;
        }
        break;
      }

      if (!car_tracker_.crash_model().IsSafe(his_new.position().angle()))
        break;

      my_prev = my_new;
      his_prev = his_new;
    }
  }

  return true;
}

void RaceTracker::FinishedRace(const std::string& color) {
  if (indexes_.find(color) == indexes_.end())
    return;
  enemies_[indexes_[color]].FinishedRace();
}

void RaceTracker::DNF(const std::string& color) {
  if (indexes_.find(color) == indexes_.end())
    return;
  enemies_[indexes_[color]].DNF();
}

void RaceTracker::ResurrectCars() {
  for (auto& enemy : enemies_)
    enemy.Resurrect();
}

bool RaceTracker::ShouldTryToOvertake(const std::string& color, int from, int to) {
 if (enemy(color).is_dead()) {
    if (race_.track().IsFirstInFront(
        enemy(color_).PositionAfterTime(enemy(color).time_to_spawn() - 15),
        enemy(color).state().position()))
      return false;
    else
      return true;
  }

  // Overtake everyone in the beginning
  if (car_tracker_.current_state().position().lap() < 1)
    return true;

  return enemy(color_).CanOvertake(enemy(color), from, to);
}

void RaceTracker::TurboForEveryone(const game::Turbo& turbo) {
  for (auto& enemy : enemies_)
    enemy.NewTurbo(turbo);
}

void RaceTracker::CarSpawned(const std::string& color) {
  enemy(color).Spawned();
  if (crash_recorded_ == false) {
    for (auto& e : enemies_) {
      e.set_crash_length(crash_time_);
    }
    printf("Calculated Crash Length: %d\n", crash_time_);
  }

  crash_recorded_ = true;
}

void RaceTracker::RecordCrash(const std::string& color) {
  if (indexes_.find(color) == indexes_.end())
    return;

  enemies_[indexes_[color]].RecordCrash();

  if (crash_time_ == -1)
    crash_time_ = 0;
}

void RaceTracker::TurboStarted(const std::string& color) {
  enemy(color).TurboStarted();
}

bool RaceTracker::WorthBumping(const std::string& color) {
  if (enemy(color).is_dead())
    return false;

  int from = race_.track().NextSwitch(car_tracker_.current_state().position().piece());
  int to = race_.track().NextSwitch(from);

  bool result = !enemy(color_).CanOvertake(enemy(color), from, to);

  if (!result)
    printf("Could do Turbo bumping, but the guy (%s) is not worth it\n", color.c_str());

  return result;
}

/* Position RaceTracker::BumpPosition(const std::string& color) {
  int index = indexes_[color];

  // TODO optimize:D
  for (int i = 0; i < 100; i++) {
    auto me = enemies_[indexes_[color_]].PositionAfterTime(i);
    auto he = enemies_[indexes_[color]].PositionAfterTime(i);

    if ((me.piece() == he.piece() && me.piece_distance() > he.piece_distance())
        || (me.piece() + 1) % race_.track().pieces().size() == he.piece())
      return me;
  }
  // This shouldnt reach here
  return enemies_[indexes_[color_]].state().position();
} */

}  // namespace game
<commit_msg>Fix comment spelling mistake<commit_after>#include "game/race_tracker.h"

using game::Position;
using game::Race;

namespace game {

RaceTracker::RaceTracker(game::CarTracker& car_tracker,
          const game::Race& race, const std::string& color)
  : car_tracker_(car_tracker), race_(race), color_(color),
    crash_time_(-1), crash_recorded_(false) {
}

void RaceTracker::Record(const std::map<std::string, Position>& positions) {
  if (!crash_recorded_ && crash_time_ != -1)
    crash_time_++;

  DetectBumps(positions);
  for (auto& p : positions) {
    if (indexes_.find(p.first) == indexes_.end()) {
      indexes_[p.first] = enemies_.size();
      enemies_.push_back(EnemyTracker(car_tracker_, race_,  p.first, p.second));
    } else {
      enemies_[indexes_[p.first]].RecordPosition(p.second);
    }
  }
}

void RaceTracker::DetectBumps(const std::map<std::string, Position>& positions) {
  bumps_.clear();

  const double kCarLength = race_.cars()[0].length();
  for (auto& a : positions) {
    if (indexes_.find(a.first) == indexes_.end()) continue;
    for (auto& b : positions) {
      if (indexes_.find(b.first) == indexes_.end()) continue;

      if (a.first == b.first) continue;
      if (enemy(a.first).is_dead() ||
          enemy(b.first).is_dead())
        continue;

      double distance = car_tracker_.DistanceBetween(a.second, b.second);
      // We need to compare start_lane and end_lane, as for switches,
      // bump only occurs if those 2 params are equal for both cars
      if (distance <= kCarLength + 1e-9 &&
          a.second.start_lane() == b.second.start_lane() &&
          a.second.end_lane() == b.second.end_lane()) {
        bumps_.push_back({ a.first, b.first });
        printf("Bump detected! %s %s\n", a.first.c_str(), b.first.c_str());
      }
    }
  }
}

bool RaceTracker::BumpOccured(const std::string& color, const std::string& color2) {
  for (auto& b : bumps_) {
    if ((b.first == color && b.second == color2) ||
        (b.second == color && b.first == color2))
      return true;
  }
  return false;
}

void RaceTracker::RecordLapTime(const std::string& color, int time) {
  if (indexes_.find(color) == indexes_.end())
    return;

  enemies_[indexes_[color]].RecordLapTime(time);
}

// TODO test
std::vector<std::string> RaceTracker::CarsBetween(int from, int to, int lane) {
  std::vector<std::string> result;
  for (auto& i : indexes_) {
    if (i.first == color_) continue;
    if (race_.track().IsBetween(enemies_[i.second].state().position(), from, to) &&
        enemies_[i.second].state().position().end_lane() == lane)
      result.push_back(i.first);
  }
  return result;
}

std::vector<EnemyTracker*> RaceTracker::PredictedCarsBetween(int from, int to, int lane) {
  auto& me = enemies_[indexes_[color_]];
  Position position;
  position.set_piece(to);
  position.set_piece_distance(0);
  int time = me.TimeToPosition(position);

  std::vector<EnemyTracker*> result;
  for (auto& i : indexes_) {
    if (i.first == color_) continue;
    auto& enemy = enemies_[i.second];

    if (enemy.is_dead() && enemy.time_to_spawn() > 10000)
      continue;

    // If Im already ahead - ignore
    if (race_.track().IsFirstInFront(me.state().position(), enemy.state().position()))
      continue;

    // Check lane
    if (enemy.state().position().end_lane() == lane) {

      // If dead, check if he respawns after I pass him
      if (enemy.is_dead()) {
        if (!race_.track().IsFirstInFront(
            me.PositionAfterTime(enemy.time_to_spawn() - 15),
            enemy.state().position())) {
          result.push_back(&enemies_[i.second]);
        }
        continue;
      }

      if (race_.track().IsBetween(enemy.PositionAfterTime(time), from, to))
        result.push_back(&enemies_[i.second]);
    }
  }
  return result;
}

// Check if I can die by just going all out
bool RaceTracker::IsSafeAttack(const Command& command, Command* safe_command) {
  return IsSafe(command, safe_command, Command(1));
}

// Check if I can die if he brakes and me either
bool RaceTracker::IsSafeInFront(const Command& command, Command* safe_command) {
  return IsSafe(command, safe_command, Command(0));
}

bool RaceTracker::IsSafe(const Command& command, Command* safe_command, const Command& our_command) {
  const auto& my_state = car_tracker_.current_state();
  bool attack = our_command.throttle() == 1.0;

  std::map<std::string, CarState> states;
  for (const auto& enemy : enemies_) {
    if (enemy.color() == color_) {
      states[color_] = my_state;
      continue;
    }

    if (enemy.is_dead()) {
      continue;
    }

    states[enemy.color()] = enemy.state();
  }
  const double kCarLength = race_.cars().at(0).length();

  bool middle_state_not_safe = false;
  bool bump_inevitable = false;
  bool attack_not_successful = false;
  std::set<string> cars_bumped;
  for (int ticks_after = 0; ticks_after < 100; ++ticks_after) {
    CarState my_prev = states[color_];
    Command c = our_command;
    if (ticks_after == 0) c = command;
    CarState my_new = car_tracker_.Predict(my_prev, c);
    states[color_] = my_new;

    if (!car_tracker_.crash_model().IsSafe(my_new.position().angle())) {
      *safe_command = Command(0);
      return false;
    }

    bool bumped = false;
    double min_velocity = 100000.0;
    for (const auto& p : states) {
      if (p.first == color_) continue;

      double velocity = 0.0;
      int full_throttle_ticks = 0;
      Position bump_position = car_tracker_.PredictPosition(my_new.position(), kCarLength);
      if (car_tracker_.MinVelocity(p.second, ticks_after + 1, bump_position, &velocity, &full_throttle_ticks)) {
        // std::cout << "possible bump in " << i + 1 << " ticks" << std::endl;
        // std::cout << "min_velocity = " << velocity << std::endl;
        // If the velocity is higher than ours, he probably was behind us.
        if (velocity < my_new.velocity()) {
          cars_bumped.insert(p.first);
          bumped = true;
          min_velocity = fmin(min_velocity, velocity);

          // TODO make sure he actually will crash
          if (attack) {
            CarState s = p.second;
            for (int i = 0; i < full_throttle_ticks; ++i) { s = car_tracker_.Predict(s, Command(1)); }
            for (int i = 0; i < ticks_after - full_throttle_ticks; ++i) { s = car_tracker_.Predict(s, Command(0)); }
            s.set_velocity(my_new.velocity() * 0.9);
            if (car_tracker_.IsSafe(s)) {
              attack_not_successful = true;
            }
          }
        }
      } else {
        // This means, he is not able to run away from us, so there is no point
        // in simulating more ticks.
        if (cars_bumped.count(p.first) > 0) {
          bump_inevitable = true;
        }
      }
    }

    if (bump_inevitable) {
      std::cout << "He is not able to run away from us, we got this :)." << std::endl;
      break;
    }
    if (!bumped) continue;

    if (!car_tracker_.IsSafe(my_new)) {
      middle_state_not_safe = true;
    }

    CarState state = my_prev;
    state.set_velocity(0.8 * min_velocity);
    if (!car_tracker_.IsSafe(state)) {
      if (our_command.throttle() != 1) {
        std::cout << "WE ARE TOO CLOSE AND WILL DIE. Slowing down (prev)." << std::endl;
      }
      *safe_command = Command(0);
      return false;
    }

    state = my_new;
    state.set_velocity(0.8 * min_velocity);
    if (!car_tracker_.IsSafe(state)) {
      if (our_command.throttle() != 1) {
        std::cout << "WE ARE TOO CLOSE AND WILL DIE. Slowing down (new)." << std::endl;
      }
      *safe_command = Command(0);
      return false;
    }
  }

  if (middle_state_not_safe && !bump_inevitable) {
    std::cout << "middle_state_not_safe && !bump_inevitable" << std::endl;
    *safe_command = Command(0);
    return false;
  }

  if (attack && attack_not_successful) {
    std::cout << "Attack would not crash the opponent." << std::endl;
    *safe_command = command;
    return false;
  }

  // We survived 50 ticks, we should be ok.
  return true;
}

bool RaceTracker::IsSafeBehind(const Command& command, Command* safe_command) {
  const auto& my_state = car_tracker_.current_state();
  const double kCarLength = race_.cars().at(0).length();
  const double kDangerousDistance = 20;
  const int kTicks = 10;

  for (const auto& enemy : enemies_) {
    if (enemy.color() == color_) {
      // states[color_] = car_tracker_.Predict(my_state, command);
      continue;
    }

    if (enemy.is_dead()) {
      continue;
    }

    double distance = car_tracker_.DistanceBetween(enemy.state().position(), my_state.position());
    if (distance > kDangerousDistance + kCarLength) {
      // std::cout << "He is too far, assuming safe" << std::endl;
      continue;
    }

    CarState my_prev = car_tracker_.Predict(my_state, command);
    CarState his_prev = car_tracker_.Predict(enemy.state(), Command(1));

    for (int i = 0; i < kTicks; ++i) {
      CarState my_new = car_tracker_.Predict(my_prev, Command(0));
      CarState his_new = car_tracker_.Predict(his_prev, Command(1));

      // BUMP
      if (car_tracker_.DistanceBetween(his_new.position(), my_new.position()) < kCarLength) {
        CarState tmp = my_new;
        tmp.set_velocity(0.9 * his_new.velocity());
        if (!car_tracker_.IsSafe(tmp)) {
          std::cout << "Not safe, he can bump into me :(" << std::endl;
          *safe_command = Command(0);
          return false;
        }
        break;
      }

      if (!car_tracker_.crash_model().IsSafe(his_new.position().angle()))
        break;

      my_prev = my_new;
      his_prev = his_new;
    }
  }

  return true;
}

void RaceTracker::FinishedRace(const std::string& color) {
  if (indexes_.find(color) == indexes_.end())
    return;
  enemies_[indexes_[color]].FinishedRace();
}

void RaceTracker::DNF(const std::string& color) {
  if (indexes_.find(color) == indexes_.end())
    return;
  enemies_[indexes_[color]].DNF();
}

void RaceTracker::ResurrectCars() {
  for (auto& enemy : enemies_)
    enemy.Resurrect();
}

bool RaceTracker::ShouldTryToOvertake(const std::string& color, int from, int to) {
 if (enemy(color).is_dead()) {
    if (race_.track().IsFirstInFront(
        enemy(color_).PositionAfterTime(enemy(color).time_to_spawn() - 15),
        enemy(color).state().position()))
      return false;
    else
      return true;
  }

  // Overtake everyone in the beginning
  if (car_tracker_.current_state().position().lap() < 1)
    return true;

  return enemy(color_).CanOvertake(enemy(color), from, to);
}

void RaceTracker::TurboForEveryone(const game::Turbo& turbo) {
  for (auto& enemy : enemies_)
    enemy.NewTurbo(turbo);
}

void RaceTracker::CarSpawned(const std::string& color) {
  enemy(color).Spawned();
  if (crash_recorded_ == false) {
    for (auto& e : enemies_) {
      e.set_crash_length(crash_time_);
    }
    printf("Calculated Crash Length: %d\n", crash_time_);
  }

  crash_recorded_ = true;
}

void RaceTracker::RecordCrash(const std::string& color) {
  if (indexes_.find(color) == indexes_.end())
    return;

  enemies_[indexes_[color]].RecordCrash();

  if (crash_time_ == -1)
    crash_time_ = 0;
}

void RaceTracker::TurboStarted(const std::string& color) {
  enemy(color).TurboStarted();
}

bool RaceTracker::WorthBumping(const std::string& color) {
  if (enemy(color).is_dead())
    return false;

  int from = race_.track().NextSwitch(car_tracker_.current_state().position().piece());
  int to = race_.track().NextSwitch(from);

  bool result = !enemy(color_).CanOvertake(enemy(color), from, to);

  if (!result)
    printf("Could do Turbo bumping, but the guy (%s) is not worth it\n", color.c_str());

  return result;
}

/* Position RaceTracker::BumpPosition(const std::string& color) {
  int index = indexes_[color];

  // TODO optimize:D
  for (int i = 0; i < 100; i++) {
    auto me = enemies_[indexes_[color_]].PositionAfterTime(i);
    auto he = enemies_[indexes_[color]].PositionAfterTime(i);

    if ((me.piece() == he.piece() && me.piece_distance() > he.piece_distance())
        || (me.piece() + 1) % race_.track().pieces().size() == he.piece())
      return me;
  }
  // This shouldnt reach here
  return enemies_[indexes_[color_]].state().position();
} */

}  // namespace game
<|endoftext|>


<commit_before>// Copyright 2015 Google Inc. All Rights Reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <asm/prctl.h>
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>

#include <list>
#include <map>
#include <sstream>

// This is an example of using ptrace() to log syscalls called by a
// child process.

namespace {

// Flag which is set in the signal number for syscall entry/exit when
// the option PTRACE_O_TRACESYSGOOD is enabled.
const int kSysFlag = 0x80;

uintptr_t RoundUpPageSize(uintptr_t val) {
  uintptr_t page_size = getpagesize();
  return (val + page_size - 1) & ~(page_size - 1);
}

class SyscallParams {
 public:
  SyscallParams(const struct user_regs_struct *regs) {
    sysnum = regs->orig_rax;
    result = regs->rax;
    args[0] = regs->rdi;
    args[1] = regs->rsi;
    args[2] = regs->rdx;
    args[3] = regs->r10;
    args[4] = regs->r8;
    args[5] = regs->r9;
  }

  uintptr_t sysnum;
  uintptr_t args[6];
  uintptr_t result;
};

class MmapInfo {
 public:
  uintptr_t addr;
  size_t size;
  // Current access permissions.
  int prot;
  // Maximum access permissions that this mapping has ever been
  // mmap()'d or mprotect()'d with.  This is used to determine whether
  // mapping could have been written to.
  int max_prot;
  std::string filename;
  uint64_t file_offset;
};

class Ptracer {
  int pid_;
  std::list<MmapInfo> mappings_;
  std::map<int, std::string> fds_;
  uint64_t fs_segment_base_;
  uintptr_t tid_address_;
  FILE *info_fp_;

  uintptr_t ReadWord(uintptr_t addr) {
    errno = 0;
    uintptr_t value = ptrace(PTRACE_PEEKDATA, pid_, addr, 0);
    assert(errno == 0);
    return value;
  }

  char ReadByte(uintptr_t addr) {
    uintptr_t mask = sizeof(uintptr_t) - 1;
    uintptr_t word = ReadWord(addr & ~mask);
    return word >> ((addr & mask) * 8);
  }

  std::string ReadString(uintptr_t addr) {
    // TODO: Reading one byte at a time is inefficient (though reading
    // one word at a time is not great either).
    std::stringbuf buf;
    for (;;) {
      char ch = ReadByte(addr++);
      if (!ch)
        break;
      buf.sputc(ch);
    }
    return buf.str();
  }

  void ChangeMapping(uintptr_t change_start, size_t change_size,
                     bool do_unmap, int new_prot) {
    change_size = RoundUpPageSize(change_size);
    uintptr_t change_end = change_start + change_size;
    assert(change_end >= change_start);
    for (std::list<MmapInfo>::iterator iter = mappings_.begin();
         iter != mappings_.end(); ) {
      std::list<MmapInfo>::iterator mapping = iter++;
      uintptr_t mapping_end = mapping->addr + mapping->size;
      // Does this existing mapping overlap with the range we are
      // unmapping?
      if (mapping_end <= change_start ||
          change_end <= mapping->addr) {
        // No overlap.
        continue;
      }
      // Do we need to keep the start and/or end of the existing
      // mapping?
      if (change_start > mapping->addr) {
        // Keep the start of the mapping.
        MmapInfo new_part(*mapping);
        new_part.size = change_start - mapping->addr;
        mappings_.insert(mapping, new_part);
      }
      if (change_end < mapping_end) {
        // Keep the end of the mapping.
        MmapInfo new_part(*mapping);
        size_t diff = change_end - mapping->addr;
        new_part.addr += diff;
        new_part.size -= diff;
        new_part.file_offset += diff;
        mappings_.insert(mapping, new_part);
      }
      if (do_unmap) {
        // munmap() case.
        mappings_.erase(mapping);
      } else {
        // mprotect() case.
        uintptr_t new_start = std::max(change_start, mapping->addr);
        uintptr_t new_end = std::min(change_end, mapping_end);
        mapping->file_offset += new_start - mapping->addr;
        mapping->addr = new_start;
        mapping->size = new_end - new_start;
        mapping->prot = new_prot;
        mapping->max_prot |= new_prot;
      }
    }
  }

  void HandleMunmap(uintptr_t addr, size_t size) {
    ChangeMapping(addr, size, true, 0);
  }

  void HandleMprotect(uintptr_t addr, size_t size, int prot) {
    ChangeMapping(addr, size, false, prot);
  }

 public:
  Ptracer(int pid): pid_(pid), fs_segment_base_(0), tid_address_(0) {}

  // Returns whether we should allow the syscall to proceed.
  // Returning false indicates that we should snapshot the process.
  bool CanHandleSyscall(struct user_regs_struct *regs) {
    SyscallParams params(regs);

    switch (params.sysnum) {
      case __NR_arch_prctl:
        return params.args[0] == ARCH_SET_FS;

      case __NR_mmap: {
        // TODO: Be stricter about which flags we allow.
        uintptr_t flags = params.args[3];
        return (flags & MAP_SHARED) == 0;
      }

      case __NR_open: {
        uintptr_t flags = params.args[1];
        uintptr_t allowed_flags = O_ACCMODE | O_CLOEXEC;
        return (flags & O_ACCMODE) == O_RDONLY &&
               (flags & ~allowed_flags) == 0;
      }

      // These are handled below.
      case __NR_close:
      case __NR_mprotect:
      case __NR_munmap:
      case __NR_set_tid_address:

      case __NR_access:
      case __NR_fstat:
      case __NR_futex:
      case __NR_getcwd:
      case __NR_getdents:
      case __NR_getegid:
      case __NR_geteuid:
      case __NR_getgid:
      case __NR_getrlimit:
      case __NR_getuid:
      case __NR_ioctl:
      case __NR_lseek:
      case __NR_lstat:
      case __NR_pread64:
      case __NR_read:
      case __NR_readlink:
      case __NR_stat:
      case __NR_uname:

      // TODO: The following will require further handling.
      case __NR_openat:
      case __NR_rt_sigaction:
      case __NR_rt_sigprocmask:
      case __NR_set_robust_list:
        return true;
    }
    return false;
  }

  // Handle a syscall after it has executed.
  void HandleSyscall(struct user_regs_struct *regs) {
    SyscallParams params(regs);

    if (params.result > -(uintptr_t) 0x1000) {
      // Syscall returned an error so should have had no effect.
      return;
    }

    switch (params.sysnum) {
      case __NR_open: {
        std::string filename(ReadString(params.args[0]));
        int fd_result = params.result;
        if (fd_result >= 0)
          fds_[fd_result] = filename;
        break;
      }
      case __NR_close: {
        fds_.erase(params.args[0]);
        break;
      }
      case __NR_mmap: {
        uintptr_t addr = params.result;
        size_t size = RoundUpPageSize(params.args[1]);
        assert(addr + size >= addr);
        // Record overwriting of any existing mappings in this range
        // in case this mmap() call uses MAP_FIXED.
        HandleMunmap(addr, size);

        MmapInfo map;
        map.addr = addr;
        map.size = size;
        map.prot = params.args[2];
        map.max_prot = map.prot;
        // assert(arg4 == (MAP_ANON | MAP_PRIVATE));
        int fd_arg = params.args[4];
        if (fd_arg != -1) {
          assert(fds_.find(fd_arg) != fds_.end());
          map.filename = fds_[fd_arg];
        }
        map.file_offset = params.args[5];
        mappings_.push_back(map);
        break;
      }
      case __NR_munmap: {
        HandleMunmap(params.args[0], params.args[1]);
        break;
      }
      case __NR_mprotect: {
        HandleMprotect(params.args[0], params.args[1], params.args[2]);
        break;
      }
      case __NR_arch_prctl: {
        if (params.args[0] == ARCH_SET_FS) {
          fs_segment_base_ = params.args[1];
        }
        break;
      }
      case __NR_set_tid_address: {
        tid_address_ = params.args[0];
        break;
      }
    }
  }

  void Put(uint64_t val) {
    fwrite(&val, sizeof(val), 1, info_fp_);
  }

  void PutString(const std::string &str) {
    Put(str.size());
    fwrite(str.c_str(), str.size() + 1, 1, info_fp_);
  }

  void Dump(const struct user_regs_struct *regs) {
    // We don't support restoring FDs yet, so no FDs must be left open.
    assert(fds_.size() == 0);

    FILE *mapfile = fopen("out_pages", "w");
    assert(mapfile);
    uintptr_t mapfile_offset = 0;

    info_fp_ = fopen("out_info", "w");
    assert(info_fp_);

    Put(regs->rax);
    Put(regs->rcx);
    Put(regs->rdx);
    Put(regs->rbx);
    Put(regs->rsp);
    Put(regs->rbp);
    Put(regs->rsi);
    Put(regs->rdi);
    Put(regs->r8);
    Put(regs->r9);
    Put(regs->r10);
    Put(regs->r11);
    Put(regs->r12);
    Put(regs->r13);
    Put(regs->r14);
    Put(regs->r15);
    Put(regs->rip);
    Put(regs->eflags);
    Put(fs_segment_base_);
    Put(tid_address_);

    Put(mappings_.size());
    for (auto &map : mappings_) {
      Put(map.addr);
      Put(map.size);
      Put(map.prot);
      PutString(map.filename);
      Put(map.file_offset);

      if (map.max_prot & PROT_WRITE) {
        Put(1);
        Put(mapfile_offset);
        for (uintptr_t offset = 0; offset < map.size;
             offset += sizeof(uintptr_t)) {
          uintptr_t word = ReadWord(map.addr + offset);
          fwrite(&word, sizeof(word), 1, mapfile);
        }
        mapfile_offset += map.size;
      } else {
        Put(0);
      }
    }
    fclose(mapfile);
    fclose(info_fp_);
  }

  void TerminateSubprocess() {
    int rc = kill(pid_, SIGKILL);
    assert(rc == 0);

    // Wait for the SIGKILL signal to take effect.
    int status;
    int pid2 = waitpid(pid_, &status, 0);
    assert(pid2 == pid_);
    assert(WIFSIGNALED(status));
    assert(WTERMSIG(status) == SIGKILL);
  }
};

}

int main(int argc, char **argv) {
  assert(argc >= 2);

  int pid = fork();
  assert(pid >= 0);
  if (pid == 0) {
    // Start tracing of the current process by the parent process.
    int rc = ptrace(PTRACE_TRACEME);
    assert(rc == 0);

    // This will trigger a SIGTRAP signal, which the parent will catch.
    execv(argv[1], argv + 1);
    perror("exec");

    _exit(1);
  }

  // Wait for the initial SIGTRAP signal generated by the child's
  // execve() call.  Since we haven't done PTRACE_SETOPTIONS yet,
  // kSysFlag isn't set in the signal number yet.
  int status;
  int pid2 = waitpid(pid, &status, 0);
  assert(pid2 == pid);
  assert(WIFSTOPPED(status));
  assert(WSTOPSIG(status) == SIGTRAP);

  // Enable kSysFlag.
  int rc = ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD);
  assert(rc == 0);

  // Allow the process to continue until the next syscall entry/exit.
  rc = ptrace(PTRACE_SYSCALL, pid, 0, 0);
  assert(rc == 0);

  // Whether the next signal will indicate a syscall entry.  If false,
  // the next signal will indicate a syscall exit.
  bool syscall_entry = true;

  Ptracer ptracer(pid);
  for (;;) {
    int status;
    int rc = waitpid(pid, &status, 0);
    assert(rc == pid);

    assert(WIFSTOPPED(status));

    if (WSTOPSIG(status) == (SIGTRAP | kSysFlag)) {
      struct user_regs_struct regs;
      rc = ptrace(PTRACE_GETREGS, pid, 0, &regs);
      assert(rc == 0);
      if (syscall_entry) {
        // Disable use of the brk() heap so that we don't have to save
        // and restore the brk() heap pointer and heap contents.
        if (regs.orig_rax == __NR_brk) {
          regs.orig_rax = -1;
          rc = ptrace(PTRACE_SETREGS, pid, 0, &regs);
          assert(rc == 0);
        } else if (!ptracer.CanHandleSyscall(&regs)) {
          // Unrecognised syscall: trigger snapshotting.

          // Rewind instruction pointer to before the syscall instruction.
          regs.rip -= 2;
          regs.rax = regs.orig_rax;

          ptracer.Dump(&regs);
          ptracer.TerminateSubprocess();
          break;
        }
      } else {
        ptracer.HandleSyscall(&regs);
      }
      syscall_entry = !syscall_entry;

      // Allow the process to continue until the next syscall entry/exit.
      rc = ptrace(PTRACE_SYSCALL, pid, 0, 0);
      assert(rc == 0);
    }
  }
  return 0;
}
<commit_msg>Cleanup: Remove commented-out assertion<commit_after>// Copyright 2015 Google Inc. All Rights Reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include <asm/prctl.h>
#include <assert.h>
#include <fcntl.h>
#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <sys/mman.h>
#include <sys/ptrace.h>
#include <sys/syscall.h>
#include <sys/user.h>
#include <sys/wait.h>
#include <unistd.h>

#include <list>
#include <map>
#include <sstream>

// This is an example of using ptrace() to log syscalls called by a
// child process.

namespace {

// Flag which is set in the signal number for syscall entry/exit when
// the option PTRACE_O_TRACESYSGOOD is enabled.
const int kSysFlag = 0x80;

uintptr_t RoundUpPageSize(uintptr_t val) {
  uintptr_t page_size = getpagesize();
  return (val + page_size - 1) & ~(page_size - 1);
}

class SyscallParams {
 public:
  SyscallParams(const struct user_regs_struct *regs) {
    sysnum = regs->orig_rax;
    result = regs->rax;
    args[0] = regs->rdi;
    args[1] = regs->rsi;
    args[2] = regs->rdx;
    args[3] = regs->r10;
    args[4] = regs->r8;
    args[5] = regs->r9;
  }

  uintptr_t sysnum;
  uintptr_t args[6];
  uintptr_t result;
};

class MmapInfo {
 public:
  uintptr_t addr;
  size_t size;
  // Current access permissions.
  int prot;
  // Maximum access permissions that this mapping has ever been
  // mmap()'d or mprotect()'d with.  This is used to determine whether
  // mapping could have been written to.
  int max_prot;
  std::string filename;
  uint64_t file_offset;
};

class Ptracer {
  int pid_;
  std::list<MmapInfo> mappings_;
  std::map<int, std::string> fds_;
  uint64_t fs_segment_base_;
  uintptr_t tid_address_;
  FILE *info_fp_;

  uintptr_t ReadWord(uintptr_t addr) {
    errno = 0;
    uintptr_t value = ptrace(PTRACE_PEEKDATA, pid_, addr, 0);
    assert(errno == 0);
    return value;
  }

  char ReadByte(uintptr_t addr) {
    uintptr_t mask = sizeof(uintptr_t) - 1;
    uintptr_t word = ReadWord(addr & ~mask);
    return word >> ((addr & mask) * 8);
  }

  std::string ReadString(uintptr_t addr) {
    // TODO: Reading one byte at a time is inefficient (though reading
    // one word at a time is not great either).
    std::stringbuf buf;
    for (;;) {
      char ch = ReadByte(addr++);
      if (!ch)
        break;
      buf.sputc(ch);
    }
    return buf.str();
  }

  void ChangeMapping(uintptr_t change_start, size_t change_size,
                     bool do_unmap, int new_prot) {
    change_size = RoundUpPageSize(change_size);
    uintptr_t change_end = change_start + change_size;
    assert(change_end >= change_start);
    for (std::list<MmapInfo>::iterator iter = mappings_.begin();
         iter != mappings_.end(); ) {
      std::list<MmapInfo>::iterator mapping = iter++;
      uintptr_t mapping_end = mapping->addr + mapping->size;
      // Does this existing mapping overlap with the range we are
      // unmapping?
      if (mapping_end <= change_start ||
          change_end <= mapping->addr) {
        // No overlap.
        continue;
      }
      // Do we need to keep the start and/or end of the existing
      // mapping?
      if (change_start > mapping->addr) {
        // Keep the start of the mapping.
        MmapInfo new_part(*mapping);
        new_part.size = change_start - mapping->addr;
        mappings_.insert(mapping, new_part);
      }
      if (change_end < mapping_end) {
        // Keep the end of the mapping.
        MmapInfo new_part(*mapping);
        size_t diff = change_end - mapping->addr;
        new_part.addr += diff;
        new_part.size -= diff;
        new_part.file_offset += diff;
        mappings_.insert(mapping, new_part);
      }
      if (do_unmap) {
        // munmap() case.
        mappings_.erase(mapping);
      } else {
        // mprotect() case.
        uintptr_t new_start = std::max(change_start, mapping->addr);
        uintptr_t new_end = std::min(change_end, mapping_end);
        mapping->file_offset += new_start - mapping->addr;
        mapping->addr = new_start;
        mapping->size = new_end - new_start;
        mapping->prot = new_prot;
        mapping->max_prot |= new_prot;
      }
    }
  }

  void HandleMunmap(uintptr_t addr, size_t size) {
    ChangeMapping(addr, size, true, 0);
  }

  void HandleMprotect(uintptr_t addr, size_t size, int prot) {
    ChangeMapping(addr, size, false, prot);
  }

 public:
  Ptracer(int pid): pid_(pid), fs_segment_base_(0), tid_address_(0) {}

  // Returns whether we should allow the syscall to proceed.
  // Returning false indicates that we should snapshot the process.
  bool CanHandleSyscall(struct user_regs_struct *regs) {
    SyscallParams params(regs);

    switch (params.sysnum) {
      case __NR_arch_prctl:
        return params.args[0] == ARCH_SET_FS;

      case __NR_mmap: {
        // TODO: Be stricter about which flags we allow.
        uintptr_t flags = params.args[3];
        return (flags & MAP_SHARED) == 0;
      }

      case __NR_open: {
        uintptr_t flags = params.args[1];
        uintptr_t allowed_flags = O_ACCMODE | O_CLOEXEC;
        return (flags & O_ACCMODE) == O_RDONLY &&
               (flags & ~allowed_flags) == 0;
      }

      // These are handled below.
      case __NR_close:
      case __NR_mprotect:
      case __NR_munmap:
      case __NR_set_tid_address:

      case __NR_access:
      case __NR_fstat:
      case __NR_futex:
      case __NR_getcwd:
      case __NR_getdents:
      case __NR_getegid:
      case __NR_geteuid:
      case __NR_getgid:
      case __NR_getrlimit:
      case __NR_getuid:
      case __NR_ioctl:
      case __NR_lseek:
      case __NR_lstat:
      case __NR_pread64:
      case __NR_read:
      case __NR_readlink:
      case __NR_stat:
      case __NR_uname:

      // TODO: The following will require further handling.
      case __NR_openat:
      case __NR_rt_sigaction:
      case __NR_rt_sigprocmask:
      case __NR_set_robust_list:
        return true;
    }
    return false;
  }

  // Handle a syscall after it has executed.
  void HandleSyscall(struct user_regs_struct *regs) {
    SyscallParams params(regs);

    if (params.result > -(uintptr_t) 0x1000) {
      // Syscall returned an error so should have had no effect.
      return;
    }

    switch (params.sysnum) {
      case __NR_open: {
        std::string filename(ReadString(params.args[0]));
        int fd_result = params.result;
        if (fd_result >= 0)
          fds_[fd_result] = filename;
        break;
      }
      case __NR_close: {
        fds_.erase(params.args[0]);
        break;
      }
      case __NR_mmap: {
        uintptr_t addr = params.result;
        size_t size = RoundUpPageSize(params.args[1]);
        assert(addr + size >= addr);
        // Record overwriting of any existing mappings in this range
        // in case this mmap() call uses MAP_FIXED.
        HandleMunmap(addr, size);

        MmapInfo map;
        map.addr = addr;
        map.size = size;
        map.prot = params.args[2];
        map.max_prot = map.prot;
        int fd_arg = params.args[4];
        if (fd_arg != -1) {
          assert(fds_.find(fd_arg) != fds_.end());
          map.filename = fds_[fd_arg];
        }
        map.file_offset = params.args[5];
        mappings_.push_back(map);
        break;
      }
      case __NR_munmap: {
        HandleMunmap(params.args[0], params.args[1]);
        break;
      }
      case __NR_mprotect: {
        HandleMprotect(params.args[0], params.args[1], params.args[2]);
        break;
      }
      case __NR_arch_prctl: {
        if (params.args[0] == ARCH_SET_FS) {
          fs_segment_base_ = params.args[1];
        }
        break;
      }
      case __NR_set_tid_address: {
        tid_address_ = params.args[0];
        break;
      }
    }
  }

  void Put(uint64_t val) {
    fwrite(&val, sizeof(val), 1, info_fp_);
  }

  void PutString(const std::string &str) {
    Put(str.size());
    fwrite(str.c_str(), str.size() + 1, 1, info_fp_);
  }

  void Dump(const struct user_regs_struct *regs) {
    // We don't support restoring FDs yet, so no FDs must be left open.
    assert(fds_.size() == 0);

    FILE *mapfile = fopen("out_pages", "w");
    assert(mapfile);
    uintptr_t mapfile_offset = 0;

    info_fp_ = fopen("out_info", "w");
    assert(info_fp_);

    Put(regs->rax);
    Put(regs->rcx);
    Put(regs->rdx);
    Put(regs->rbx);
    Put(regs->rsp);
    Put(regs->rbp);
    Put(regs->rsi);
    Put(regs->rdi);
    Put(regs->r8);
    Put(regs->r9);
    Put(regs->r10);
    Put(regs->r11);
    Put(regs->r12);
    Put(regs->r13);
    Put(regs->r14);
    Put(regs->r15);
    Put(regs->rip);
    Put(regs->eflags);
    Put(fs_segment_base_);
    Put(tid_address_);

    Put(mappings_.size());
    for (auto &map : mappings_) {
      Put(map.addr);
      Put(map.size);
      Put(map.prot);
      PutString(map.filename);
      Put(map.file_offset);

      if (map.max_prot & PROT_WRITE) {
        Put(1);
        Put(mapfile_offset);
        for (uintptr_t offset = 0; offset < map.size;
             offset += sizeof(uintptr_t)) {
          uintptr_t word = ReadWord(map.addr + offset);
          fwrite(&word, sizeof(word), 1, mapfile);
        }
        mapfile_offset += map.size;
      } else {
        Put(0);
      }
    }
    fclose(mapfile);
    fclose(info_fp_);
  }

  void TerminateSubprocess() {
    int rc = kill(pid_, SIGKILL);
    assert(rc == 0);

    // Wait for the SIGKILL signal to take effect.
    int status;
    int pid2 = waitpid(pid_, &status, 0);
    assert(pid2 == pid_);
    assert(WIFSIGNALED(status));
    assert(WTERMSIG(status) == SIGKILL);
  }
};

}

int main(int argc, char **argv) {
  assert(argc >= 2);

  int pid = fork();
  assert(pid >= 0);
  if (pid == 0) {
    // Start tracing of the current process by the parent process.
    int rc = ptrace(PTRACE_TRACEME);
    assert(rc == 0);

    // This will trigger a SIGTRAP signal, which the parent will catch.
    execv(argv[1], argv + 1);
    perror("exec");

    _exit(1);
  }

  // Wait for the initial SIGTRAP signal generated by the child's
  // execve() call.  Since we haven't done PTRACE_SETOPTIONS yet,
  // kSysFlag isn't set in the signal number yet.
  int status;
  int pid2 = waitpid(pid, &status, 0);
  assert(pid2 == pid);
  assert(WIFSTOPPED(status));
  assert(WSTOPSIG(status) == SIGTRAP);

  // Enable kSysFlag.
  int rc = ptrace(PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACESYSGOOD);
  assert(rc == 0);

  // Allow the process to continue until the next syscall entry/exit.
  rc = ptrace(PTRACE_SYSCALL, pid, 0, 0);
  assert(rc == 0);

  // Whether the next signal will indicate a syscall entry.  If false,
  // the next signal will indicate a syscall exit.
  bool syscall_entry = true;

  Ptracer ptracer(pid);
  for (;;) {
    int status;
    int rc = waitpid(pid, &status, 0);
    assert(rc == pid);

    assert(WIFSTOPPED(status));

    if (WSTOPSIG(status) == (SIGTRAP | kSysFlag)) {
      struct user_regs_struct regs;
      rc = ptrace(PTRACE_GETREGS, pid, 0, &regs);
      assert(rc == 0);
      if (syscall_entry) {
        // Disable use of the brk() heap so that we don't have to save
        // and restore the brk() heap pointer and heap contents.
        if (regs.orig_rax == __NR_brk) {
          regs.orig_rax = -1;
          rc = ptrace(PTRACE_SETREGS, pid, 0, &regs);
          assert(rc == 0);
        } else if (!ptracer.CanHandleSyscall(&regs)) {
          // Unrecognised syscall: trigger snapshotting.

          // Rewind instruction pointer to before the syscall instruction.
          regs.rip -= 2;
          regs.rax = regs.orig_rax;

          ptracer.Dump(&regs);
          ptracer.TerminateSubprocess();
          break;
        }
      } else {
        ptracer.HandleSyscall(&regs);
      }
      syscall_entry = !syscall_entry;

      // Allow the process to continue until the next syscall entry/exit.
      rc = ptrace(PTRACE_SYSCALL, pid, 0, 0);
      assert(rc == 0);
    }
  }
  return 0;
}
<|endoftext|>