<commit_before>
#include <s2sinputstream.h>
#include <s2soutputstream.h>
#include <virtualhost.h>
#include <functions.h>
#include <nanosoft/asyncdns.h>
#include <iostream>

using namespace std;

/**
* Конструктор потока
*/
S2SInputStream::S2SInputStream(XMPPServer *srv, int sock): XMPPStream(srv, sock)
{
}

/**
* Деструктор потока
*/
S2SInputStream::~S2SInputStream()
{
}

/**
* Событие: начало потока
*/
void S2SInputStream::onStartStream(const std::string &name, const attributes_t &attributes)
{
	fprintf(stderr, "#%d new s2s stream\n", getWorkerId());
	initXML();
	startElement("stream:stream");
	setAttribute("xmlns:stream", "http://etherx.jabber.org/streams");
	setAttribute("xmlns", "jabber:server");
	setAttribute("xmlns:db", "jabber:server:dialback");
	setAttribute("id", id = getUniqueId());
	setAttribute("xml:lang", "en");
	flush();
}

/**
* Событие: конец потока
*/
void S2SInputStream::onEndStream()
{
	fprintf(stderr, "#%d: [S2SInputStream: %d] end of stream\n", getWorkerId(), fd);
	terminate();
}

/**
* Обработчик станзы
*/
void S2SInputStream::onStanza(Stanza stanza)
{
	fprintf(stderr, "#%d s2s-input stanza: %s\n", getWorkerId(), stanza->name().c_str());
	if ( stanza->name() == "verify" ) onDBVerifyStanza(stanza);
	else if ( stanza->name() == "result" ) onDBResultStanza(stanza);
	else if ( state != authorized )
	{
		fprintf(stderr, "#%d unexpected s2s-input stanza: %s\n", getWorkerId(), stanza->name().c_str());
		Stanza error = Stanza::streamError("not-authoized");
		sendStanza(error);
		delete error;
		terminate();
	}
	else if ( stanza.from().hostname() != remote_host )
	{
		fprintf(stderr, "#%d [s2s-input: %s] invalid from: %s\n", getWorkerId(), remote_host.c_str(), stanza->getAttribute("from").c_str());
		Stanza error = Stanza::streamError("improper-addressing");
		sendStanza(error);
		delete error;
		terminate();
	}
	else
	{
		// доставить станзу по назначению
		XMPPDomain *vhost = server->getHostByName(stanza.to().hostname());
		if ( ! vhost )
		{
			fprintf(stderr, "#%d [s2s-input: %s] invalid to: %s\n", getWorkerId(), remote_host.c_str(), stanza->getAttribute("to").c_str());
			Stanza error = Stanza::streamError("improper-addressing");
			sendStanza(error);
			delete error;
			terminate();
		}
		vhost->routeStanza(stanza);
	}
}

/**
* Обработка <db:verify>
*/
void S2SInputStream::onDBVerifyStanza(Stanza stanza)
{
	Stanza verify = new ATXmlTag("db:verify");
	verify->setAttribute("from", stanza->getAttribute("to"));
	verify->setAttribute("to", stanza->getAttribute("from"));
	verify->setAttribute("type", "valid");
	verify->setAttribute("id", stanza->getAttribute("id"));
	sendStanza(verify);
	delete verify;
}

/**
* Резолвер s2s хоста, запись A (IPv4)
*/
static void on_s2s_a4(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data)
{
  printf("on_s2s_a4\n");
  if ( result )
  for(int i = 0; i < result->dnsa4_nrr; i++)
  {
    char buf[40];
    printf("  addr: %s\n", dns_ntop(AF_INET, &result->dnsa4_addr[i], buf, sizeof(buf)));
  }
  printf("\n");
}

/**
* Резолвер s2s хоста, запись SRV (_jabber._tcp)
*/
static void on_s2s_srv_jabber(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
{
  printf("on_s2s_srv_jabber\n");
  if ( result )
  for(int i = 0; i < result->dnssrv_nrr; i++)
  {
    char buf[40];
    printf("  SRV priority: %d, weight: %d, port: %d, name: %s\n",
      result->dnssrv_srv[i].priority,
      result->dnssrv_srv[i].weight,
      result->dnssrv_srv[i].port,
      result->dnssrv_srv[i].name);
  }
  printf("\n");
}

/**
* Резолвер s2s хоста, запись SRV (_xmpp-server._tcp)
*/
static void on_srv_xmpp_server(struct dns_ctx *ctx, struct dns_rr_srv *result, void *data)
{
  printf("on_srv_xmpp_server\n");
  if ( result )
  for(int i = 0; i < result->dnssrv_nrr; i++)
  {
    char buf[40];
    printf("  SRV priority: %d, weight: %d, port: %d, name: %s\n",
      result->dnssrv_srv[i].priority,
      result->dnssrv_srv[i].weight,
      result->dnssrv_srv[i].port,
      result->dnssrv_srv[i].name);
  }
  printf("\n");
}

/**
* Резолвер s2s хоста, запись RBL
*/
static void on_s2s_rbl(struct dns_ctx *ctx, struct dns_rr_a4 *result, void *data)
{
  printf("on_s2s_rbl\n");
  if ( result ) {
  for(int i = 0; i < result->dnsa4_nrr; i++)
  {
    char buf[40];
    printf("  addr: %s\n", dns_ntop(AF_INET, &result->dnsa4_addr[i], buf, sizeof(buf)));
  }
  }
  printf("\n");
}

/**
* Обработка <db:result>
*/
void S2SInputStream::onDBResultStanza(Stanza stanza)
{
	string to = stanza->getAttribute("to");
	string from = stanza->getAttribute("from");
	cerr << "[s2s-input] db:result to: " << to << ", from: " << from << endl;

	// Шаг 1. проверка: "to" должен быть нашим виртуальным хостом
	XMPPDomain *host = server->getHostByName(to);
	if ( ! host || dynamic_cast<S2SOutputStream*>(host) )
	{
		Stanza stanza = Stanza::streamError("host-unknown");
		sendStanza(stanza);
		delete stanza;
		terminate();
		return;
	}

	// Шаг 2. проверка "from"
	//
	// RFC 3920 не запрещает делать повторные коннекты (8.3.4).
	//
	// До завершения авторизации нужно поддерживать старое соединение,
	// пока не авторизуется новое. Но можно блокировать повторные
	// коннекты с ошибкой <not-authorized />, что мы и делаем.
	//
	// NOTE: В любом случае, логично блокировать попытки представиться
	// нашим хостом - мы сами к себе никогда не коннектимся.
	// Так что, если будете открывать повторные коннекты, то забудьте
	// блокировать попытки коннекта к самим себе.
	if ( server->getHostByName(from) )
	{
		Stanza stanza = Stanza::streamError("not-authorized");
		sendStanza(stanza);
		delete stanza;
		terminate();
		return;
	}
	remote_host = from;

	// Шаг 3. резолвим DNS записи сервера
	// NOTE для оптимизации отправляем все DNS (асинхронные) запросы сразу
	server->adns->a4(from.c_str(), on_s2s_a4, this);
	server->adns->srv(from.c_str(), "jabber", "tcp", on_s2s_srv_jabber, this);
	server->adns->srv(from.c_str(), "xmpp-server", "tcp", on_srv_xmpp_server, this);
	// TODO извлекать список DNSBL из конфига
	server->adns->a4((from + ".dnsbl.jabber.ru").c_str(), on_s2s_rbl, this);

	// Шаг X. костыль - ответить сразу "authorized"
	state = authorized;
	Stanza result = new ATXmlTag("db:result");
	result->setAttribute("to", from);
	result->setAttribute("from", to);
	result->setAttribute("type", "valid");
	sendStanza(result);
	delete result;
}

/**
* Сигнал завершения работы
*
* Сервер решил закрыть соединение, здесь ещё есть время
* корректно попрощаться с пиром (peer).
*/
void S2SInputStream::onTerminate()
{
	fprintf(stderr, "#%d: [S2SInputStream: %d] onTerminate\n", getWorkerId(), fd);

	// if ( state == authorized ) server->onOffline(this);

	mutex.lock();
		endElement("stream:stream");
		flush();
		shutdown(WRITE);
	mutex.unlock();
}
<commit_msg>cleanup<commit_after>
#include <s2sinputstream.h>
#include <s2soutputstream.h>
#include <virtualhost.h>
#include <functions.h>
#include <nanosoft/asyncdns.h>
#include <iostream>

using namespace std;

/**
* Конструктор потока
*/
S2SInputStream::S2SInputStream(XMPPServer *srv, int sock): XMPPStream(srv, sock)
{
}

/**
* Деструктор потока
*/
S2SInputStream::~S2SInputStream()
{
}

/**
* Событие: начало потока
*/
void S2SInputStream::onStartStream(const std::string &name, const attributes_t &attributes)
{
	fprintf(stderr, "#%d new s2s stream\n", getWorkerId());
	initXML();
	startElement("stream:stream");
	setAttribute("xmlns:stream", "http://etherx.jabber.org/streams");
	setAttribute("xmlns", "jabber:server");
	setAttribute("xmlns:db", "jabber:server:dialback");
	setAttribute("id", id = getUniqueId());
	setAttribute("xml:lang", "en");
	flush();
}

/**
* Событие: конец потока
*/
void S2SInputStream::onEndStream()
{
	fprintf(stderr, "#%d: [S2SInputStream: %d] end of stream\n", getWorkerId(), fd);
	terminate();
}

/**
* Обработчик станзы
*/
void S2SInputStream::onStanza(Stanza stanza)
{
	fprintf(stderr, "#%d s2s-input stanza: %s\n", getWorkerId(), stanza->name().c_str());
	if ( stanza->name() == "verify" ) onDBVerifyStanza(stanza);
	else if ( stanza->name() == "result" ) onDBResultStanza(stanza);
	else if ( state != authorized )
	{
		fprintf(stderr, "#%d unexpected s2s-input stanza: %s\n", getWorkerId(), stanza->name().c_str());
		Stanza error = Stanza::streamError("not-authoized");
		sendStanza(error);
		delete error;
		terminate();
	}
	else if ( stanza.from().hostname() != remote_host )
	{
		fprintf(stderr, "#%d [s2s-input: %s] invalid from: %s\n", getWorkerId(), remote_host.c_str(), stanza->getAttribute("from").c_str());
		Stanza error = Stanza::streamError("improper-addressing");
		sendStanza(error);
		delete error;
		terminate();
	}
	else
	{
		// доставить станзу по назначению
		XMPPDomain *vhost = server->getHostByName(stanza.to().hostname());
		if ( ! vhost )
		{
			fprintf(stderr, "#%d [s2s-input: %s] invalid to: %s\n", getWorkerId(), remote_host.c_str(), stanza->getAttribute("to").c_str());
			Stanza error = Stanza::streamError("improper-addressing");
			sendStanza(error);
			delete error;
			terminate();
		}
		vhost->routeStanza(stanza);
	}
}

/**
* Обработка <db:verify>
*/
void S2SInputStream::onDBVerifyStanza(Stanza stanza)
{
	Stanza verify = new ATXmlTag("db:verify");
	verify->setAttribute("from", stanza->getAttribute("to"));
	verify->setAttribute("to", stanza->getAttribute("from"));
	verify->setAttribute("type", "valid");
	verify->setAttribute("id", stanza->getAttribute("id"));
	sendStanza(verify);
	delete verify;
}

/**
* Обработка <db:result>
*/
void S2SInputStream::onDBResultStanza(Stanza stanza)
{
	string to = stanza->getAttribute("to");
	string from = stanza->getAttribute("from");
	cerr << "[s2s-input] db:result to: " << to << ", from: " << from << endl;

	// Шаг 1. проверка: "to" должен быть нашим виртуальным хостом
	XMPPDomain *host = server->getHostByName(to);
	if ( ! host || dynamic_cast<S2SOutputStream*>(host) )
	{
		Stanza stanza = Stanza::streamError("host-unknown");
		sendStanza(stanza);
		delete stanza;
		terminate();
		return;
	}

	// Шаг 2. проверка "from"
	//
	// RFC 3920 не запрещает делать повторные коннекты (8.3.4).
	//
	// До завершения авторизации нужно поддерживать старое соединение,
	// пока не авторизуется новое. Но можно блокировать повторные
	// коннекты с ошибкой <not-authorized />, что мы и делаем.
	//
	// NOTE: В любом случае, логично блокировать попытки представиться
	// нашим хостом - мы сами к себе никогда не коннектимся.
	// Так что, если будете открывать повторные коннекты, то забудьте
	// блокировать попытки коннекта к самим себе.
	if ( server->getHostByName(from) )
	{
		Stanza stanza = Stanza::streamError("not-authorized");
		sendStanza(stanza);
		delete stanza;
		terminate();
		return;
	}
	remote_host = from;

	// Шаг 3. резолвим DNS записи сервера
	// NOTE для оптимизации отправляем все DNS (асинхронные) запросы сразу
	//server->adns->a4(from.c_str(), on_s2s_a4, this);
	//server->adns->srv(from.c_str(), "jabber", "tcp", on_s2s_srv_jabber, this);
	//server->adns->srv(from.c_str(), "xmpp-server", "tcp", on_srv_xmpp_server, this);
	// TODO извлекать список DNSBL из конфига
	//server->adns->a4((from + ".dnsbl.jabber.ru").c_str(), on_s2s_rbl, this);

	// Шаг X. костыль - ответить сразу "authorized"
	state = authorized;
	Stanza result = new ATXmlTag("db:result");
	result->setAttribute("to", from);
	result->setAttribute("from", to);
	result->setAttribute("type", "valid");
	sendStanza(result);
	delete result;
}

/**
* Сигнал завершения работы
*
* Сервер решил закрыть соединение, здесь ещё есть время
* корректно попрощаться с пиром (peer).
*/
void S2SInputStream::onTerminate()
{
	fprintf(stderr, "#%d: [S2SInputStream: %d] onTerminate\n", getWorkerId(), fd);

	// if ( state == authorized ) server->onOffline(this);

	mutex.lock();
		endElement("stream:stream");
		flush();
		shutdown(WRITE);
	mutex.unlock();
}
<|endoftext|>


<commit_before>/*
 * Simulation.cpp
 *
 *  The box2d simulation of the pinball machine
 */

#ifndef PINBALL_BOT_SIMULATION
#define PINBALL_BOT_SIMULATION

#include <stdio.h>
#include <Box2D/Box2D.h>

#include <cmath>

#include "../agent/Ball.cpp"
#include "../agent/State.cpp"

const int32			VELOCITY_ITERATIONS					= 6;
const int32			POSITION_ITERATIONS					= 2;
const int32			PLAYINGFIELD_VERTEX_NUMBER			= 10;

const float			GRAVITY_X							= 0;
const float			GRAVITY_Y							= 5.0f; /* positive, cause we start in the top left corner */

const float			FLIPPER_HEIGHT						= 1.0f;
const float			FLIPPER_WIDTH						= 0.5f;

const float			WALL_THICKNESS						= 0.05f;

const float			BALL_RADIUS							= 0.025f;
const float			BALL_DENSITY						= 0.0001f;
const float			BALL_FRICTION						= 0.01f;
const float			BALL_RESTITUTION					= 0.9f;

const float			FLIPPER_DENSITY						= 0.0001f;
const float			FLIPPER_FRICTION					= 0.01f;
const float			FLIPPER_RESTITUTION					= 0.3f;
const float			FLIPPER_REV_JOINT_LOWER_ANGLE		= (float) 0.0f * b2_pi;
const float			FLIPPER_REV_JOINT_UPPER_ANGLE		= (float) 0.1f * b2_pi;

const float			FLIPPER_REV_MOTOR_SPEED				= (float) 1.5 * b2_pi; /* rad^-1 */
const float			FLIPPER_REV_MOTOR_MAX_TORQUE		= 5.0f;

/**
 * Class used to simulate a pinball machine using Box2D
 */
class PinballSimulation{
	private:

		//The Box2D world where all the things take place
		b2Vec2											gravity;
		b2World											world;

		//The playing field
		b2BodyDef										playingFieldDef[PLAYINGFIELD_VERTEX_NUMBER];
		b2Body*											playingFieldBody[PLAYINGFIELD_VERTEX_NUMBER];
		b2EdgeShape										playingFieldEdge[PLAYINGFIELD_VERTEX_NUMBER];

		//The ball used to play the game
		b2BodyDef										ballDef;
		b2Body*											ballBody;
		b2CircleShape									ballSphere;
		b2FixtureDef									ballFixtureDef;

		//The flipper on the left hand side
		b2BodyDef										flipperLeftDef;
		b2Body*											flipperLeftBody;
		b2PolygonShape									flipperLeftTriangle;
		b2FixtureDef									flipperLeftFixtureDef;
		b2RevoluteJointDef								flipperLeftRevJointDef;
		b2RevoluteJoint*								flipperLeftRevJoint;

		//The flipper on the right hand side
		b2BodyDef										flipperRightDef;
		b2Body*											flipperRightBody;
		b2PolygonShape									flipperRightTriangle;
		b2FixtureDef									flipperRightFixtureDef;
		b2RevoluteJointDef								flipperRightRevJointDef;
		b2RevoluteJoint*								flipperRightRevJoint;

	public:

		/**
		 * Inits the world and all of the needed objects
		 */
		PinballSimulation() : gravity(GRAVITY_X, GRAVITY_Y), world(this->gravity){
			/* Initializes a world with gravity pulling downwards */

			/* Remember: The origin (0|0) is the top left corner! */

			/* Define edge shape of the playing field */
			b2Vec2 playingFieldVertices[PLAYINGFIELD_VERTEX_NUMBER];
			playingFieldVertices[0].Set(0, FLIPPER_HEIGHT / 8);
			playingFieldVertices[1].Set((std::sin(b2_pi/20)*FLIPPER_HEIGHT/8), (FLIPPER_HEIGHT / 8) - (std::cos(b2_pi/20)*FLIPPER_HEIGHT / 8) );
			playingFieldVertices[2].Set((std::sin(2 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(2 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[3].Set((std::sin(3 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(3 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[4].Set((std::sin(4 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(4 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[5].Set((std::sin(5 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(5 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[6].Set((std::sin(6 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(6 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[7].Set((std::sin(7 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(7 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[8].Set((std::sin(8 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(8 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[9].Set((std::sin(9 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(9 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			drawPlayingField(playingFieldVertices);

			/* Add 2 flippers */
			flipperLeftDef.type							= b2_dynamicBody;
			flipperRightDef.type						= b2_dynamicBody;

			flipperLeftDef.position.Set(WALL_THICKNESS, (3*FLIPPER_HEIGHT/4));
			flipperRightDef.position.Set(FLIPPER_WIDTH-WALL_THICKNESS, (3*FLIPPER_HEIGHT/4));

			/* Triangle */
			b2Vec2 leftFlipperVertices[3];
			leftFlipperVertices[0].Set(0.0f, 0.0f);
			leftFlipperVertices[1].Set(0.0f, 0.05f);
			leftFlipperVertices[2].Set(0.15f, 0.05f);

			flipperLeftTriangle.Set(leftFlipperVertices, 3);

			/* Triangle */
			b2Vec2 rightFlipperVertices[3];
			rightFlipperVertices[0].Set(0.0f, 0.0f);
			rightFlipperVertices[1].Set(0.0f, 0.05f);
			rightFlipperVertices[2].Set(-0.15f, 0.05f);

			flipperRightTriangle.Set(rightFlipperVertices, 3);

			flipperLeftBody								= world.CreateBody(&this->flipperLeftDef);
			flipperRightBody							= world.CreateBody(&this->flipperRightDef);

			this->flipperLeftFixtureDef.shape			= &this->flipperLeftTriangle;
			this->flipperRightFixtureDef.shape			= &this->flipperRightTriangle;

			this->flipperLeftFixtureDef.density			= this->flipperRightFixtureDef.density = FLIPPER_DENSITY;
			this->flipperLeftFixtureDef.friction		= this->flipperRightFixtureDef.friction = FLIPPER_FRICTION;
			this->flipperLeftFixtureDef.restitution		= this->flipperRightFixtureDef.restitution = FLIPPER_RESTITUTION;

			this->flipperLeftBody->CreateFixture(&this->flipperLeftFixtureDef);
			this->flipperRightBody->CreateFixture(&this->flipperRightFixtureDef);

			/* Connect the flippers to the walls with a joint */
			flipperLeftRevJointDef.bodyA				= playingFieldBody[0];
			flipperLeftRevJointDef.bodyB				= flipperLeftBody;

			flipperRightRevJointDef.bodyA				= playingFieldBody[0];
			flipperRightRevJointDef.bodyB				= flipperRightBody;

			flipperLeftRevJointDef.localAnchorA			= b2Vec2((WALL_THICKNESS/2), 0.0f);
			flipperLeftRevJointDef.localAnchorB			= b2Vec2(0.0f, 0.0f);

			flipperRightRevJointDef.localAnchorA		= b2Vec2((-WALL_THICKNESS/2), 0.0f);
			flipperRightRevJointDef.localAnchorB		= b2Vec2(0.0f, 0.0f);

			flipperLeftRevJointDef.collideConnected		= flipperRightRevJointDef.collideConnected		= false;

			flipperLeftRevJointDef.lowerAngle			= -1 * FLIPPER_REV_JOINT_UPPER_ANGLE;
			flipperLeftRevJointDef.upperAngle			= FLIPPER_REV_JOINT_LOWER_ANGLE;

			flipperRightRevJointDef.lowerAngle			= FLIPPER_REV_JOINT_LOWER_ANGLE;
			flipperRightRevJointDef.upperAngle			= FLIPPER_REV_JOINT_UPPER_ANGLE;

			flipperLeftRevJointDef.enableLimit			= flipperRightRevJointDef.enableLimit				= true;

			flipperLeftRevJointDef.maxMotorTorque		= flipperRightRevJointDef.maxMotorTorque			= FLIPPER_REV_MOTOR_MAX_TORQUE;
			flipperLeftRevJointDef.enableMotor			= flipperRightRevJointDef.enableMotor				= false; // Not enabled by default

			flipperLeftRevJointDef.motorSpeed 			= -1 * FLIPPER_REV_MOTOR_SPEED;
			flipperRightRevJointDef.motorSpeed 			= FLIPPER_REV_MOTOR_SPEED;

			flipperLeftRevJoint							= (b2RevoluteJoint*)this->world.CreateJoint(&flipperLeftRevJointDef);
			flipperRightRevJoint						= (b2RevoluteJoint*)this->world.CreateJoint(&flipperRightRevJointDef);

			/* Init playing ball */
			ballDef.type								= b2_dynamicBody;
			ballDef.position.Set((FLIPPER_WIDTH/2), (FLIPPER_HEIGHT/2));
			ballBody									= world.CreateBody(&this->ballDef);

			this->ballSphere.m_p.Set(0.0f, 0.0f);
			this->ballSphere.m_radius					= BALL_RADIUS;

			this->ballFixtureDef.shape					= &this->ballSphere;
			this->ballFixtureDef.density				= BALL_DENSITY;
			this->ballFixtureDef.friction				= BALL_FRICTION;
			this->ballFixtureDef.restitution			= BALL_RESTITUTION;

			this->ballBody->CreateFixture(&this->ballFixtureDef);
		}

		void drawPlayingField(const b2Vec2* points){
			for(int i=0;i<PLAYINGFIELD_VERTEX_NUMBER;i++){

				playingFieldDef[i].type			=	b2_staticBody;
				playingFieldDef[i].position.Set(0, 0);

				playingFieldEdge[i].Set(points[i], points[i+1]);

				playingFieldBody[i]				= world.CreateBody(&playingFieldDef[i]);

				playingFieldBody[i]->CreateFixture(&playingFieldEdge[i], 0.0f);

			}
		}

		/**
		 * Steps a specific value forward in time
		 * @param	time_step	float32		The amount of time to step
		 * @return	void
		 */
		void step(const float32 &time_step){
			world.Step(time_step, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
		}

		/**
		 * Sets the DebugDraw renderer of the Box2D world
		 * @param	draw		b2Draw		A pointer to a class implementing the b2Draw functions
		 * @return	void
		 */
		void setRenderer(b2Draw* draw){
			this->world.SetDebugDraw( draw );
		}

		/**
		 * Renders the scene by calling the DrawDebugData function inside the Box2D world,
		 * which calls back to the initially set b2Draw class
		 * @return	void
		 */
		void render(){
			this->world.DrawDebugData();
		}

		/**
		 * Activates the left hand flipper. Will stay active until disableLeftFlipper() is called
		 * @return	void
		 */
		void enableLeftFlipper(){
			flipperLeftRevJoint->EnableMotor(true);
		}
		/**
		 * Deactivates the left hand flipper. Gravity will do it's job again
		 * @return	void
		 */
		void disableLeftFlipper(){
			flipperLeftRevJoint->EnableMotor(false);
		}

		/**
		 * Activates the right hand flipper. Will stay active until disableLeftFlipper() is called
		 * @return	void
		 */
		void enableRightFlipper(){
			flipperRightRevJoint->EnableMotor(true);
		}
		/**
		 * Deactivates the right hand flipper. Gravity will do it's job again
		 * @return	void
		 */
		void disableRightFlipper(){
			flipperRightRevJoint->EnableMotor(false);
		}

		/**
		 * Prints debugging information about the playing ball
		 * @return	void
		 */
		void debugPlayingBall(){
			b2Vec2 position								= this->ballBody->GetPosition();
			float32 angle								= this->ballBody->GetAngle();

			printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
		}

		State getCurrentState(){
			return State(Ball(this->ballBody->GetPosition(), this->ballBody->GetLinearVelocity()), flipperLeftRevJoint->IsMotorEnabled(), flipperRightRevJoint->IsMotorEnabled());
		}

		class s{

		};

};

#endif /* PINBALL_BOT_SIMULATION */
<commit_msg>Fixed "IndexOutOfBoundException"<commit_after>/*
 * Simulation.cpp
 *
 *  The box2d simulation of the pinball machine
 */

#ifndef PINBALL_BOT_SIMULATION
#define PINBALL_BOT_SIMULATION

#include <stdio.h>
#include <Box2D/Box2D.h>

#include <cmath>

#include "../agent/Ball.cpp"
#include "../agent/State.cpp"

const int32			VELOCITY_ITERATIONS					= 6;
const int32			POSITION_ITERATIONS					= 2;
const int32			PLAYINGFIELD_VERTEX_NUMBER			= 10;

const float			GRAVITY_X							= 0;
const float			GRAVITY_Y							= 5.0f; /* positive, cause we start in the top left corner */

const float			FLIPPER_HEIGHT						= 1.0f;
const float			FLIPPER_WIDTH						= 0.5f;

const float			WALL_THICKNESS						= 0.05f;

const float			BALL_RADIUS							= 0.025f;
const float			BALL_DENSITY						= 0.0001f;
const float			BALL_FRICTION						= 0.01f;
const float			BALL_RESTITUTION					= 0.9f;

const float			FLIPPER_DENSITY						= 0.0001f;
const float			FLIPPER_FRICTION					= 0.01f;
const float			FLIPPER_RESTITUTION					= 0.3f;
const float			FLIPPER_REV_JOINT_LOWER_ANGLE		= (float) 0.0f * b2_pi;
const float			FLIPPER_REV_JOINT_UPPER_ANGLE		= (float) 0.1f * b2_pi;

const float			FLIPPER_REV_MOTOR_SPEED				= (float) 1.5 * b2_pi; /* rad^-1 */
const float			FLIPPER_REV_MOTOR_MAX_TORQUE		= 5.0f;

/**
 * Class used to simulate a pinball machine using Box2D
 */
class PinballSimulation{
	private:

		//The Box2D world where all the things take place
		b2Vec2											gravity;
		b2World											world;

		//The playing field
		b2BodyDef										playingFieldDef[PLAYINGFIELD_VERTEX_NUMBER];
		b2Body*											playingFieldBody[PLAYINGFIELD_VERTEX_NUMBER];
		b2EdgeShape										playingFieldEdge[PLAYINGFIELD_VERTEX_NUMBER];

		//The ball used to play the game
		b2BodyDef										ballDef;
		b2Body*											ballBody;
		b2CircleShape									ballSphere;
		b2FixtureDef									ballFixtureDef;

		//The flipper on the left hand side
		b2BodyDef										flipperLeftDef;
		b2Body*											flipperLeftBody;
		b2PolygonShape									flipperLeftTriangle;
		b2FixtureDef									flipperLeftFixtureDef;
		b2RevoluteJointDef								flipperLeftRevJointDef;
		b2RevoluteJoint*								flipperLeftRevJoint;

		//The flipper on the right hand side
		b2BodyDef										flipperRightDef;
		b2Body*											flipperRightBody;
		b2PolygonShape									flipperRightTriangle;
		b2FixtureDef									flipperRightFixtureDef;
		b2RevoluteJointDef								flipperRightRevJointDef;
		b2RevoluteJoint*								flipperRightRevJoint;

	public:

		/**
		 * Inits the world and all of the needed objects
		 */
		PinballSimulation() : gravity(GRAVITY_X, GRAVITY_Y), world(this->gravity){
			/* Initializes a world with gravity pulling downwards */

			/* Remember: The origin (0|0) is the top left corner! */

			/* Define edge shape of the playing field */
			b2Vec2 playingFieldVertices[PLAYINGFIELD_VERTEX_NUMBER];
			playingFieldVertices[0].Set(0, FLIPPER_HEIGHT / 8);
			playingFieldVertices[1].Set((std::sin(b2_pi/20)*FLIPPER_HEIGHT/8), (FLIPPER_HEIGHT / 8) - (std::cos(b2_pi/20)*FLIPPER_HEIGHT / 8) );
			playingFieldVertices[2].Set((std::sin(2 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(2 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[3].Set((std::sin(3 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(3 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[4].Set((std::sin(4 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(4 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[5].Set((std::sin(5 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(5 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[6].Set((std::sin(6 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(6 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[7].Set((std::sin(7 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(7 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[8].Set((std::sin(8 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(8 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			playingFieldVertices[9].Set((std::sin(9 * b2_pi / 20)*FLIPPER_HEIGHT / 8), (FLIPPER_HEIGHT / 8) - (std::cos(9 * b2_pi / 20)*FLIPPER_HEIGHT / 8));
			drawPlayingField(playingFieldVertices);

			/* Add 2 flippers */
			flipperLeftDef.type							= b2_dynamicBody;
			flipperRightDef.type						= b2_dynamicBody;

			flipperLeftDef.position.Set(WALL_THICKNESS, (3*FLIPPER_HEIGHT/4));
			flipperRightDef.position.Set(FLIPPER_WIDTH-WALL_THICKNESS, (3*FLIPPER_HEIGHT/4));

			/* Triangle */
			b2Vec2 leftFlipperVertices[3];
			leftFlipperVertices[0].Set(0.0f, 0.0f);
			leftFlipperVertices[1].Set(0.0f, 0.05f);
			leftFlipperVertices[2].Set(0.15f, 0.05f);

			flipperLeftTriangle.Set(leftFlipperVertices, 3);

			/* Triangle */
			b2Vec2 rightFlipperVertices[3];
			rightFlipperVertices[0].Set(0.0f, 0.0f);
			rightFlipperVertices[1].Set(0.0f, 0.05f);
			rightFlipperVertices[2].Set(-0.15f, 0.05f);

			flipperRightTriangle.Set(rightFlipperVertices, 3);

			flipperLeftBody								= world.CreateBody(&this->flipperLeftDef);
			flipperRightBody							= world.CreateBody(&this->flipperRightDef);

			this->flipperLeftFixtureDef.shape			= &this->flipperLeftTriangle;
			this->flipperRightFixtureDef.shape			= &this->flipperRightTriangle;

			this->flipperLeftFixtureDef.density			= this->flipperRightFixtureDef.density = FLIPPER_DENSITY;
			this->flipperLeftFixtureDef.friction		= this->flipperRightFixtureDef.friction = FLIPPER_FRICTION;
			this->flipperLeftFixtureDef.restitution		= this->flipperRightFixtureDef.restitution = FLIPPER_RESTITUTION;

			this->flipperLeftBody->CreateFixture(&this->flipperLeftFixtureDef);
			this->flipperRightBody->CreateFixture(&this->flipperRightFixtureDef);

			/* Connect the flippers to the walls with a joint */
			flipperLeftRevJointDef.bodyA				= playingFieldBody[0];
			flipperLeftRevJointDef.bodyB				= flipperLeftBody;

			flipperRightRevJointDef.bodyA				= playingFieldBody[0];
			flipperRightRevJointDef.bodyB				= flipperRightBody;

			flipperLeftRevJointDef.localAnchorA			= b2Vec2((WALL_THICKNESS/2), 0.0f);
			flipperLeftRevJointDef.localAnchorB			= b2Vec2(0.0f, 0.0f);

			flipperRightRevJointDef.localAnchorA		= b2Vec2((-WALL_THICKNESS/2), 0.0f);
			flipperRightRevJointDef.localAnchorB		= b2Vec2(0.0f, 0.0f);

			flipperLeftRevJointDef.collideConnected		= flipperRightRevJointDef.collideConnected		= false;

			flipperLeftRevJointDef.lowerAngle			= -1 * FLIPPER_REV_JOINT_UPPER_ANGLE;
			flipperLeftRevJointDef.upperAngle			= FLIPPER_REV_JOINT_LOWER_ANGLE;

			flipperRightRevJointDef.lowerAngle			= FLIPPER_REV_JOINT_LOWER_ANGLE;
			flipperRightRevJointDef.upperAngle			= FLIPPER_REV_JOINT_UPPER_ANGLE;

			flipperLeftRevJointDef.enableLimit			= flipperRightRevJointDef.enableLimit				= true;

			flipperLeftRevJointDef.maxMotorTorque		= flipperRightRevJointDef.maxMotorTorque			= FLIPPER_REV_MOTOR_MAX_TORQUE;
			flipperLeftRevJointDef.enableMotor			= flipperRightRevJointDef.enableMotor				= false; // Not enabled by default

			flipperLeftRevJointDef.motorSpeed 			= -1 * FLIPPER_REV_MOTOR_SPEED;
			flipperRightRevJointDef.motorSpeed 			= FLIPPER_REV_MOTOR_SPEED;

			flipperLeftRevJoint							= (b2RevoluteJoint*)this->world.CreateJoint(&flipperLeftRevJointDef);
			flipperRightRevJoint						= (b2RevoluteJoint*)this->world.CreateJoint(&flipperRightRevJointDef);

			/* Init playing ball */
			ballDef.type								= b2_dynamicBody;
			ballDef.position.Set((FLIPPER_WIDTH/2), (FLIPPER_HEIGHT/2));
			ballBody									= world.CreateBody(&this->ballDef);

			this->ballSphere.m_p.Set(0.0f, 0.0f);
			this->ballSphere.m_radius					= BALL_RADIUS;

			this->ballFixtureDef.shape					= &this->ballSphere;
			this->ballFixtureDef.density				= BALL_DENSITY;
			this->ballFixtureDef.friction				= BALL_FRICTION;
			this->ballFixtureDef.restitution			= BALL_RESTITUTION;

			this->ballBody->CreateFixture(&this->ballFixtureDef);
		}

		void drawPlayingField(const b2Vec2* points){
			for(int i=0;i<PLAYINGFIELD_VERTEX_NUMBER-1;i++){

				playingFieldDef[i].type			=	b2_staticBody;
				playingFieldDef[i].position.Set(0, 0);

				playingFieldEdge[i].Set(points[i], points[i+1]);

				playingFieldBody[i]				= world.CreateBody(&playingFieldDef[i]);

				playingFieldBody[i]->CreateFixture(&playingFieldEdge[i], 0.0f);

			}
		}

		/**
		 * Steps a specific value forward in time
		 * @param	time_step	float32		The amount of time to step
		 * @return	void
		 */
		void step(const float32 &time_step){
			world.Step(time_step, VELOCITY_ITERATIONS, POSITION_ITERATIONS);
		}

		/**
		 * Sets the DebugDraw renderer of the Box2D world
		 * @param	draw		b2Draw		A pointer to a class implementing the b2Draw functions
		 * @return	void
		 */
		void setRenderer(b2Draw* draw){
			this->world.SetDebugDraw( draw );
		}

		/**
		 * Renders the scene by calling the DrawDebugData function inside the Box2D world,
		 * which calls back to the initially set b2Draw class
		 * @return	void
		 */
		void render(){
			this->world.DrawDebugData();
		}

		/**
		 * Activates the left hand flipper. Will stay active until disableLeftFlipper() is called
		 * @return	void
		 */
		void enableLeftFlipper(){
			flipperLeftRevJoint->EnableMotor(true);
		}
		/**
		 * Deactivates the left hand flipper. Gravity will do it's job again
		 * @return	void
		 */
		void disableLeftFlipper(){
			flipperLeftRevJoint->EnableMotor(false);
		}

		/**
		 * Activates the right hand flipper. Will stay active until disableLeftFlipper() is called
		 * @return	void
		 */
		void enableRightFlipper(){
			flipperRightRevJoint->EnableMotor(true);
		}
		/**
		 * Deactivates the right hand flipper. Gravity will do it's job again
		 * @return	void
		 */
		void disableRightFlipper(){
			flipperRightRevJoint->EnableMotor(false);
		}

		/**
		 * Prints debugging information about the playing ball
		 * @return	void
		 */
		void debugPlayingBall(){
			b2Vec2 position								= this->ballBody->GetPosition();
			float32 angle								= this->ballBody->GetAngle();

			printf("%4.2f %4.2f %4.2f\n", position.x, position.y, angle);
		}

		State getCurrentState(){
			return State(Ball(this->ballBody->GetPosition(), this->ballBody->GetLinearVelocity()), flipperLeftRevJoint->IsMotorEnabled(), flipperRightRevJoint->IsMotorEnabled());
		}

		class s{

		};

};

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


<commit_before>/*
 * Copyright (c) 2013 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * 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 holders 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.
 */

/**
 * @file This file describes the base components used for the probe system.
 * There are currently 3 components:
 *
 * ProbePoint:          an event probe point i.e. send a notify from the point
 *                      at which an instruction was committed.
 *
 * ProbeListener:       a listener provide a notify method that is called when
 *                      a probe point event occurs. Multiple ProbeListeners
 *                      can be added to each ProbePoint.
 *
 * ProbeListenerObject: a wrapper around a SimObject that can connect to another
 *                      SimObject on which is will add ProbeListeners.
 *
 * ProbeManager:        used to match up ProbeListeners and ProbePoints.
 *                      At simulation init this is handled by regProbePoints
 *                      followed by regProbeListeners being called on each
 *                      SimObject in hierarchical ordering.
 *                      ProbeListeners can be added/removed dynamically at runtime.
 */

#ifndef __SIM_PROBE_PROBE_HH__
#define __SIM_PROBE_PROBE_HH__

#include <string>
#include <vector>

#include "base/compiler.hh"
#include "base/trace.hh"
#include "sim/sim_object.hh"

/** Forward declare the ProbeManager. */
class ProbeManager;
class ProbeListener;
class ProbeListenerObjectParams;

/**
 * Name space containing shared probe point declarations.
 *
 * Probe types that are shared between multiple types of SimObjects
 * should live in this name space. This makes it possible to use a
 * common instrumentation interface for devices such as PMUs that have
 * different implementations in different ISAs.
 */
namespace ProbePoints {
/* Note: This is only here for documentation purposes, new probe
 * points should normally be declared in their own header files. See
 * for example pmu.hh.
 */
}

/**
 * This class is a minimal wrapper around SimObject. It is used to declare
 * a python derived object that can be added as a ProbeListener to any other
 * SimObject.
 *
 * It instantiates manager from a call to Parent.any.
 * The vector of listeners is used simply to hold onto listeners until the
 * ProbeListenerObject is destroyed.
 */
class ProbeListenerObject : public SimObject
{
  protected:
    ProbeManager *manager;
    std::vector<ProbeListener *> listeners;

  public:
    ProbeListenerObject(const ProbeListenerObjectParams &params);
    virtual ~ProbeListenerObject();
    ProbeManager* getProbeManager() { return manager; }
};

/**
 * ProbeListener base class; here to simplify things like containers
 * containing multiple types of ProbeListener.
 *
 * Note a ProbeListener is added to the ProbePoint in constructor by
 * using the ProbeManager passed in.
 */
class ProbeListener
{
  public:
    ProbeListener(ProbeManager *manager, const std::string &name);
    virtual ~ProbeListener();
    ProbeListener(const ProbeListener& other) = delete;
    ProbeListener& operator=(const ProbeListener& other) = delete;
    ProbeListener(ProbeListener&& other) noexcept = delete;
    ProbeListener& operator=(ProbeListener&& other) noexcept = delete;

  protected:
    ProbeManager *const manager;
    const std::string name;
};

/**
 * ProbeListener base class; again used to simplify use of ProbePoints
 * in containers and used as to define interface for adding removing
 * listeners to the ProbePoint.
 */
class ProbePoint
{
  protected:
    const std::string name;
  public:
    ProbePoint(ProbeManager *manager, const std::string &name);
    virtual ~ProbePoint() {}

    virtual void addListener(ProbeListener *listener) = 0;
    virtual void removeListener(ProbeListener *listener) = 0;
    std::string getName() const { return name; }
};

/**
 * ProbeManager is a conduit class that lives on each SimObject,
 *  and is used to match up probe listeners with probe points.
 */
class ProbeManager
{
  private:
    /** Required for sensible debug messages.*/
    M5_CLASS_VAR_USED const SimObject *object;
    /** Vector for name look-up. */
    std::vector<ProbePoint *> points;

  public:
    ProbeManager(SimObject *obj)
        : object(obj)
    {}
    virtual ~ProbeManager() {}

    /**
     * @brief Add a ProbeListener to the ProbePoint named by pointName.
     *        If the name doesn't resolve a ProbePoint return false.
     * @param pointName the name of the ProbePoint to add the ProbeListener to.
     * @param listener the ProbeListener to add.
     * @return true if added, false otherwise.
     */
    bool addListener(std::string pointName, ProbeListener &listener);

    /**
     * @brief Remove a ProbeListener from the ProbePoint named by pointName.
     *        If the name doesn't resolve a ProbePoint return false.
     * @param pointName the name of the ProbePoint to remove the ProbeListener
     *        from.
     * @param listener the ProbeListener to remove.
     * @return true if removed, false otherwise.
     */
    bool removeListener(std::string pointName, ProbeListener &listener);

    /**
     * @brief Add a ProbePoint to this SimObject ProbeManager.
     * @param point the ProbePoint to add.
     */
    void addPoint(ProbePoint &point);
};

/**
 * ProbeListenerArgBase is used to define the base interface to a
 * ProbeListenerArg (i.e the notify method on specific type).
 *
 * It is necessary to split this out from ProbeListenerArg, as that
 * templates off the class containing the function that notify calls.
 */
template <class Arg>
class ProbeListenerArgBase : public ProbeListener
{
  public:
    ProbeListenerArgBase(ProbeManager *pm, const std::string &name)
        : ProbeListener(pm, name)
    {}
    virtual void notify(const Arg &val) = 0;
};

/**
 * ProbeListenerArg generates a listener for the class of Arg and the
 * class type T which is the class containing the function that notify will
 * call.
 *
 * Note that the function is passed as a pointer on construction.
 */
template <class T, class Arg>
class ProbeListenerArg : public ProbeListenerArgBase<Arg>
{
  private:
    T *object;
    void (T::* function)(const Arg &);

  public:
    /**
     * @param obj the class of type Tcontaining the method to call on notify.
     * @param name the name of the ProbePoint to add this listener to.
     * @param func a pointer to the function on obj (called on notify).
     */
    ProbeListenerArg(T *obj, const std::string &name, void (T::* func)(const Arg &))
        : ProbeListenerArgBase<Arg>(obj->getProbeManager(), name),
          object(obj),
          function(func)
    {}

    /**
     * @brief called when the ProbePoint calls notify. This is a shim through to
     *        the function passed during construction.
     * @param val the argument value to pass.
     */
    virtual void notify(const Arg &val) { (object->*function)(val); }
};

/**
 * ProbePointArg generates a point for the class of Arg. As ProbePointArgs talk
 * directly to ProbeListenerArgs of the same type, we can store the vector of
 * ProbeListeners as their Arg type (and not as base type).
 *
 * Methods are provided to addListener, removeListener and notify.
 */
template <typename Arg>
class ProbePointArg : public ProbePoint
{
    /** The attached listeners. */
    std::vector<ProbeListenerArgBase<Arg> *> listeners;

  public:
    ProbePointArg(ProbeManager *manager, std::string name)
        : ProbePoint(manager, name)
    {
    }

    /**
     * @brief adds a ProbeListener to this ProbePoints notify list.
     * @param l the ProbeListener to add to the notify list.
     */
    void addListener(ProbeListener *l)
    {
        // check listener not already added
        if (std::find(listeners.begin(), listeners.end(), l) == listeners.end()) {
            listeners.push_back(static_cast<ProbeListenerArgBase<Arg> *>(l));
        }
    }

    /**
     * @brief remove a ProbeListener from this ProbePoints notify list.
     * @param l the ProbeListener to remove from the notify list.
     */
    void removeListener(ProbeListener *l)
    {
        listeners.erase(std::remove(listeners.begin(), listeners.end(), l),
                        listeners.end());
    }

    /**
     * @brief called at the ProbePoint call site, passes arg to each listener.
     * @param arg the argument to pass to each listener.
     */
    void notify(const Arg &arg)
    {
        for (auto l = listeners.begin(); l != listeners.end(); ++l) {
            (*l)->notify(arg);
        }
    }
};
#endif//__SIM_PROBE_PROBE_HH__
<commit_msg>sim: Add a listener checker to probes<commit_after>/*
 * Copyright (c) 2013 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * 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 holders 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.
 */

/**
 * @file This file describes the base components used for the probe system.
 * There are currently 3 components:
 *
 * ProbePoint:          an event probe point i.e. send a notify from the point
 *                      at which an instruction was committed.
 *
 * ProbeListener:       a listener provide a notify method that is called when
 *                      a probe point event occurs. Multiple ProbeListeners
 *                      can be added to each ProbePoint.
 *
 * ProbeListenerObject: a wrapper around a SimObject that can connect to another
 *                      SimObject on which is will add ProbeListeners.
 *
 * ProbeManager:        used to match up ProbeListeners and ProbePoints.
 *                      At simulation init this is handled by regProbePoints
 *                      followed by regProbeListeners being called on each
 *                      SimObject in hierarchical ordering.
 *                      ProbeListeners can be added/removed dynamically at runtime.
 */

#ifndef __SIM_PROBE_PROBE_HH__
#define __SIM_PROBE_PROBE_HH__

#include <string>
#include <vector>

#include "base/compiler.hh"
#include "base/trace.hh"
#include "sim/sim_object.hh"

/** Forward declare the ProbeManager. */
class ProbeManager;
class ProbeListener;
class ProbeListenerObjectParams;

/**
 * Name space containing shared probe point declarations.
 *
 * Probe types that are shared between multiple types of SimObjects
 * should live in this name space. This makes it possible to use a
 * common instrumentation interface for devices such as PMUs that have
 * different implementations in different ISAs.
 */
namespace ProbePoints {
/* Note: This is only here for documentation purposes, new probe
 * points should normally be declared in their own header files. See
 * for example pmu.hh.
 */
}

/**
 * This class is a minimal wrapper around SimObject. It is used to declare
 * a python derived object that can be added as a ProbeListener to any other
 * SimObject.
 *
 * It instantiates manager from a call to Parent.any.
 * The vector of listeners is used simply to hold onto listeners until the
 * ProbeListenerObject is destroyed.
 */
class ProbeListenerObject : public SimObject
{
  protected:
    ProbeManager *manager;
    std::vector<ProbeListener *> listeners;

  public:
    ProbeListenerObject(const ProbeListenerObjectParams &params);
    virtual ~ProbeListenerObject();
    ProbeManager* getProbeManager() { return manager; }
};

/**
 * ProbeListener base class; here to simplify things like containers
 * containing multiple types of ProbeListener.
 *
 * Note a ProbeListener is added to the ProbePoint in constructor by
 * using the ProbeManager passed in.
 */
class ProbeListener
{
  public:
    ProbeListener(ProbeManager *manager, const std::string &name);
    virtual ~ProbeListener();
    ProbeListener(const ProbeListener& other) = delete;
    ProbeListener& operator=(const ProbeListener& other) = delete;
    ProbeListener(ProbeListener&& other) noexcept = delete;
    ProbeListener& operator=(ProbeListener&& other) noexcept = delete;

  protected:
    ProbeManager *const manager;
    const std::string name;
};

/**
 * ProbeListener base class; again used to simplify use of ProbePoints
 * in containers and used as to define interface for adding removing
 * listeners to the ProbePoint.
 */
class ProbePoint
{
  protected:
    const std::string name;
  public:
    ProbePoint(ProbeManager *manager, const std::string &name);
    virtual ~ProbePoint() {}

    virtual void addListener(ProbeListener *listener) = 0;
    virtual void removeListener(ProbeListener *listener) = 0;
    std::string getName() const { return name; }
};

/**
 * ProbeManager is a conduit class that lives on each SimObject,
 *  and is used to match up probe listeners with probe points.
 */
class ProbeManager
{
  private:
    /** Required for sensible debug messages.*/
    M5_CLASS_VAR_USED const SimObject *object;
    /** Vector for name look-up. */
    std::vector<ProbePoint *> points;

  public:
    ProbeManager(SimObject *obj)
        : object(obj)
    {}
    virtual ~ProbeManager() {}

    /**
     * @brief Add a ProbeListener to the ProbePoint named by pointName.
     *        If the name doesn't resolve a ProbePoint return false.
     * @param pointName the name of the ProbePoint to add the ProbeListener to.
     * @param listener the ProbeListener to add.
     * @return true if added, false otherwise.
     */
    bool addListener(std::string pointName, ProbeListener &listener);

    /**
     * @brief Remove a ProbeListener from the ProbePoint named by pointName.
     *        If the name doesn't resolve a ProbePoint return false.
     * @param pointName the name of the ProbePoint to remove the ProbeListener
     *        from.
     * @param listener the ProbeListener to remove.
     * @return true if removed, false otherwise.
     */
    bool removeListener(std::string pointName, ProbeListener &listener);

    /**
     * @brief Add a ProbePoint to this SimObject ProbeManager.
     * @param point the ProbePoint to add.
     */
    void addPoint(ProbePoint &point);
};

/**
 * ProbeListenerArgBase is used to define the base interface to a
 * ProbeListenerArg (i.e the notify method on specific type).
 *
 * It is necessary to split this out from ProbeListenerArg, as that
 * templates off the class containing the function that notify calls.
 */
template <class Arg>
class ProbeListenerArgBase : public ProbeListener
{
  public:
    ProbeListenerArgBase(ProbeManager *pm, const std::string &name)
        : ProbeListener(pm, name)
    {}
    virtual void notify(const Arg &val) = 0;
};

/**
 * ProbeListenerArg generates a listener for the class of Arg and the
 * class type T which is the class containing the function that notify will
 * call.
 *
 * Note that the function is passed as a pointer on construction.
 */
template <class T, class Arg>
class ProbeListenerArg : public ProbeListenerArgBase<Arg>
{
  private:
    T *object;
    void (T::* function)(const Arg &);

  public:
    /**
     * @param obj the class of type Tcontaining the method to call on notify.
     * @param name the name of the ProbePoint to add this listener to.
     * @param func a pointer to the function on obj (called on notify).
     */
    ProbeListenerArg(T *obj, const std::string &name, void (T::* func)(const Arg &))
        : ProbeListenerArgBase<Arg>(obj->getProbeManager(), name),
          object(obj),
          function(func)
    {}

    /**
     * @brief called when the ProbePoint calls notify. This is a shim through to
     *        the function passed during construction.
     * @param val the argument value to pass.
     */
    virtual void notify(const Arg &val) { (object->*function)(val); }
};

/**
 * ProbePointArg generates a point for the class of Arg. As ProbePointArgs talk
 * directly to ProbeListenerArgs of the same type, we can store the vector of
 * ProbeListeners as their Arg type (and not as base type).
 *
 * Methods are provided to addListener, removeListener and notify.
 */
template <typename Arg>
class ProbePointArg : public ProbePoint
{
    /** The attached listeners. */
    std::vector<ProbeListenerArgBase<Arg> *> listeners;

  public:
    ProbePointArg(ProbeManager *manager, std::string name)
        : ProbePoint(manager, name)
    {
    }

    /**
     * Informs whether any listeners are attached to this probe. This can
     * be used to avoid performing costly tasks needed by the probe when
     * nobody is listening.
     *
     * @return Whether this probe has any listener.
     */
    bool hasListeners() const { return listeners.size() > 0; }

    /**
     * @brief adds a ProbeListener to this ProbePoints notify list.
     * @param l the ProbeListener to add to the notify list.
     */
    void addListener(ProbeListener *l)
    {
        // check listener not already added
        if (std::find(listeners.begin(), listeners.end(), l) == listeners.end()) {
            listeners.push_back(static_cast<ProbeListenerArgBase<Arg> *>(l));
        }
    }

    /**
     * @brief remove a ProbeListener from this ProbePoints notify list.
     * @param l the ProbeListener to remove from the notify list.
     */
    void removeListener(ProbeListener *l)
    {
        listeners.erase(std::remove(listeners.begin(), listeners.end(), l),
                        listeners.end());
    }

    /**
     * @brief called at the ProbePoint call site, passes arg to each listener.
     * @param arg the argument to pass to each listener.
     */
    void notify(const Arg &arg)
    {
        for (auto l = listeners.begin(); l != listeners.end(); ++l) {
            (*l)->notify(arg);
        }
    }
};
#endif//__SIM_PROBE_PROBE_HH__
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2003-2006 The Regents of The University of Michigan
 * 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 holders 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.
 *
 * Authors: Nathan Binkert
 */

class ThreadContext;

//We need the "Tick" and "Addr" data types from here
#include "base/types.hh"

namespace PseudoInst {

/**
 * @todo these externs are only here for a hack in fullCPU::takeOver...
 */
extern bool doStatisticsInsts;
extern bool doCheckpointInsts;
extern bool doQuiesce;

#if FULL_SYSTEM
void arm(ThreadContext *tc);
void quiesce(ThreadContext *tc);
void quiesceSkip(ThreadContext *tc);
void quiesceNs(ThreadContext *tc, uint64_t ns);
void quiesceCycles(ThreadContext *tc, uint64_t cycles);
uint64_t quiesceTime(ThreadContext *tc);
uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len,
    uint64_t offset);
void loadsymbol(ThreadContext *xc);
void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr);
#endif

uint64_t rpns(ThreadContext *tc);
void wakeCPU(ThreadContext *tc, uint64_t cpuid);
void m5exit(ThreadContext *tc, Tick delay);
void resetstats(ThreadContext *tc, Tick delay, Tick period);
void dumpstats(ThreadContext *tc, Tick delay, Tick period);
void dumpresetstats(ThreadContext *tc, Tick delay, Tick period);
void m5checkpoint(ThreadContext *tc, Tick delay, Tick period);
void debugbreak(ThreadContext *tc);
void switchcpu(ThreadContext *tc);
void workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid);
void workend(ThreadContext *tc, uint64_t workid, uint64_t threadid);

} // namespace PseudoInst
<commit_msg>PseudoInst: Add compiler guards to pseudo_inst.hh.<commit_after>/*
 * Copyright (c) 2003-2006 The Regents of The University of Michigan
 * 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 holders 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.
 *
 * Authors: Nathan Binkert
 */

#ifndef __SIM_PSEUDO_INST_HH__
#define __SIM_PSEUDO_INST_HH__

class ThreadContext;

//We need the "Tick" and "Addr" data types from here
#include "base/types.hh"

namespace PseudoInst {

/**
 * @todo these externs are only here for a hack in fullCPU::takeOver...
 */
extern bool doStatisticsInsts;
extern bool doCheckpointInsts;
extern bool doQuiesce;

#if FULL_SYSTEM
void arm(ThreadContext *tc);
void quiesce(ThreadContext *tc);
void quiesceSkip(ThreadContext *tc);
void quiesceNs(ThreadContext *tc, uint64_t ns);
void quiesceCycles(ThreadContext *tc, uint64_t cycles);
uint64_t quiesceTime(ThreadContext *tc);
uint64_t readfile(ThreadContext *tc, Addr vaddr, uint64_t len,
    uint64_t offset);
void loadsymbol(ThreadContext *xc);
void addsymbol(ThreadContext *tc, Addr addr, Addr symbolAddr);
#endif

uint64_t rpns(ThreadContext *tc);
void wakeCPU(ThreadContext *tc, uint64_t cpuid);
void m5exit(ThreadContext *tc, Tick delay);
void resetstats(ThreadContext *tc, Tick delay, Tick period);
void dumpstats(ThreadContext *tc, Tick delay, Tick period);
void dumpresetstats(ThreadContext *tc, Tick delay, Tick period);
void m5checkpoint(ThreadContext *tc, Tick delay, Tick period);
void debugbreak(ThreadContext *tc);
void switchcpu(ThreadContext *tc);
void workbegin(ThreadContext *tc, uint64_t workid, uint64_t threadid);
void workend(ThreadContext *tc, uint64_t workid, uint64_t threadid);

} // namespace PseudoInst

#endif // __SIM_PSEUDO_INST_HH__
<|endoftext|>


<commit_before>// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// The common functionality when building with or without snapshots.

#include "src/v8.h"

#include "src/api.h"
#include "src/base/platform/platform.h"
#include "src/full-codegen.h"
#include "src/snapshot.h"

namespace v8 {
namespace internal {

#ifdef DEBUG
bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
  return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() &&
         !Snapshot::ExtractContextData(snapshot_blob).is_empty();
}
#endif  // DEBUG

bool Snapshot::EmbedsScript(Isolate* isolate) {
  if (!isolate->snapshot_available()) return false;
  return ExtractMetadata(isolate->snapshot_blob()).embeds_script();
}

uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) {
  DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE);
  if (!isolate->snapshot_available()) {
    return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
  }
  uint32_t size;
  int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
  memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
  return size;
}

bool Snapshot::Initialize(Isolate* isolate) {
  if (!isolate->snapshot_available()) return false;
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization) timer.Start();

  const v8::StartupData* blob = isolate->snapshot_blob();
  Vector<const byte> startup_data = ExtractStartupData(blob);
  SnapshotData snapshot_data(startup_data);
  Deserializer deserializer(&snapshot_data);
  bool success = isolate->Init(&deserializer);
  if (FLAG_profile_deserialization) {
    double ms = timer.Elapsed().InMillisecondsF();
    int bytes = startup_data.length();
    PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
  }
  return success;
}

MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
    Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
    Handle<FixedArray>* outdated_contexts_out) {
  if (!isolate->snapshot_available()) return Handle<Context>();
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization) timer.Start();

  const v8::StartupData* blob = isolate->snapshot_blob();
  Vector<const byte> context_data = ExtractContextData(blob);
  SnapshotData snapshot_data(context_data);
  Deserializer deserializer(&snapshot_data);

  MaybeHandle<Object> maybe_context = deserializer.DeserializePartial(
      isolate, global_proxy, outdated_contexts_out);
  Handle<Object> result;
  if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
  CHECK(result->IsContext());
  // If the snapshot does not contain a custom script, we need to update
  // the global object for exactly one context.
  CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 1);
  if (FLAG_profile_deserialization) {
    double ms = timer.Elapsed().InMillisecondsF();
    int bytes = context_data.length();
    PrintF("[Deserializing context (%d bytes) took %0.3f ms]\n", bytes, ms);
  }
  return Handle<Context>::cast(result);
}

void CalculateFirstPageSizes(bool is_default_snapshot,
                             const SnapshotData& startup_snapshot,
                             const SnapshotData& context_snapshot,
                             uint32_t* sizes_out) {
  Vector<const SerializedData::Reservation> startup_reservations =
      startup_snapshot.Reservations();
  Vector<const SerializedData::Reservation> context_reservations =
      context_snapshot.Reservations();
  int startup_index = 0;
  int context_index = 0;
  for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
    bool single_chunk = true;
    while (!startup_reservations[startup_index].is_last()) {
      single_chunk = false;
      startup_index++;
    }
    while (!context_reservations[context_index].is_last()) {
      single_chunk = false;
      context_index++;
    }

    uint32_t required = kMaxUInt32;
    if (single_chunk) {
      // If both the startup snapshot data and the context snapshot data on
      // this space fit in a single page, then we consider limiting the size
      // of the first page. For this, we add the chunk sizes and some extra
      // allowance. This way we achieve a smaller startup memory footprint.
      required = (startup_reservations[startup_index].chunk_size() +
                  2 * context_reservations[context_index].chunk_size()) +
                 Page::kObjectStartOffset;
    } else {
      // We expect the vanilla snapshot to only require on page per space.
      DCHECK(!is_default_snapshot);
    }

    if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) {
      uint32_t max_size =
          MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space));
      sizes_out[space - FIRST_PAGED_SPACE] = Min(required, max_size);
    } else {
      DCHECK(single_chunk);
    }
    startup_index++;
    context_index++;
  }

  DCHECK_EQ(startup_reservations.length(), startup_index);
  DCHECK_EQ(context_reservations.length(), context_index);
}

v8::StartupData Snapshot::CreateSnapshotBlob(
    const i::StartupSerializer& startup_ser,
    const i::PartialSerializer& context_ser, Snapshot::Metadata metadata) {
  SnapshotData startup_snapshot(startup_ser);
  SnapshotData context_snapshot(context_ser);
  Vector<const byte> startup_data = startup_snapshot.RawData();
  Vector<const byte> context_data = context_snapshot.RawData();

  uint32_t first_page_sizes[kNumPagedSpaces];

  CalculateFirstPageSizes(metadata.embeds_script(), startup_snapshot,
                          context_snapshot, first_page_sizes);

  int startup_length = startup_data.length();
  int context_length = context_data.length();
  int context_offset = ContextOffset(startup_length);

  int length = context_offset + context_length;
  char* data = new char[length];

  memcpy(data + kMetadataOffset, &metadata.RawValue(), kInt32Size);
  memcpy(data + kFirstPageSizesOffset, first_page_sizes,
         kNumPagedSpaces * kInt32Size);
  memcpy(data + kStartupLengthOffset, &startup_length, kInt32Size);
  memcpy(data + kStartupDataOffset, startup_data.begin(), startup_length);
  memcpy(data + context_offset, context_data.begin(), context_length);
  v8::StartupData result = {data, length};
  return result;
}

Snapshot::Metadata Snapshot::ExtractMetadata(const v8::StartupData* data) {
  uint32_t raw;
  memcpy(&raw, data->data + kMetadataOffset, kInt32Size);
  return Metadata(raw);
}

Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
  DCHECK_LT(kIntSize, data->raw_size);
  int startup_length;
  memcpy(&startup_length, data->data + kStartupLengthOffset, kInt32Size);
  DCHECK_LT(startup_length, data->raw_size);
  const byte* startup_data =
      reinterpret_cast<const byte*>(data->data + kStartupDataOffset);
  return Vector<const byte>(startup_data, startup_length);
}

Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data) {
  DCHECK_LT(kIntSize, data->raw_size);
  int startup_length;
  memcpy(&startup_length, data->data + kStartupLengthOffset, kIntSize);
  int context_offset = ContextOffset(startup_length);
  const byte* context_data =
      reinterpret_cast<const byte*>(data->data + context_offset);
  DCHECK_LT(context_offset, data->raw_size);
  int context_length = data->raw_size - context_offset;
  return Vector<const byte>(context_data, context_length);
}
} }  // namespace v8::internal
<commit_msg>Fix assertion when creating custom startup snapshots.<commit_after>// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// The common functionality when building with or without snapshots.

#include "src/v8.h"

#include "src/api.h"
#include "src/base/platform/platform.h"
#include "src/full-codegen.h"
#include "src/snapshot.h"

namespace v8 {
namespace internal {

#ifdef DEBUG
bool Snapshot::SnapshotIsValid(v8::StartupData* snapshot_blob) {
  return !Snapshot::ExtractStartupData(snapshot_blob).is_empty() &&
         !Snapshot::ExtractContextData(snapshot_blob).is_empty();
}
#endif  // DEBUG

bool Snapshot::EmbedsScript(Isolate* isolate) {
  if (!isolate->snapshot_available()) return false;
  return ExtractMetadata(isolate->snapshot_blob()).embeds_script();
}

uint32_t Snapshot::SizeOfFirstPage(Isolate* isolate, AllocationSpace space) {
  DCHECK(space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE);
  if (!isolate->snapshot_available()) {
    return static_cast<uint32_t>(MemoryAllocator::PageAreaSize(space));
  }
  uint32_t size;
  int offset = kFirstPageSizesOffset + (space - FIRST_PAGED_SPACE) * kInt32Size;
  memcpy(&size, isolate->snapshot_blob()->data + offset, kInt32Size);
  return size;
}

bool Snapshot::Initialize(Isolate* isolate) {
  if (!isolate->snapshot_available()) return false;
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization) timer.Start();

  const v8::StartupData* blob = isolate->snapshot_blob();
  Vector<const byte> startup_data = ExtractStartupData(blob);
  SnapshotData snapshot_data(startup_data);
  Deserializer deserializer(&snapshot_data);
  bool success = isolate->Init(&deserializer);
  if (FLAG_profile_deserialization) {
    double ms = timer.Elapsed().InMillisecondsF();
    int bytes = startup_data.length();
    PrintF("[Deserializing isolate (%d bytes) took %0.3f ms]\n", bytes, ms);
  }
  return success;
}

MaybeHandle<Context> Snapshot::NewContextFromSnapshot(
    Isolate* isolate, Handle<JSGlobalProxy> global_proxy,
    Handle<FixedArray>* outdated_contexts_out) {
  if (!isolate->snapshot_available()) return Handle<Context>();
  base::ElapsedTimer timer;
  if (FLAG_profile_deserialization) timer.Start();

  const v8::StartupData* blob = isolate->snapshot_blob();
  Vector<const byte> context_data = ExtractContextData(blob);
  SnapshotData snapshot_data(context_data);
  Deserializer deserializer(&snapshot_data);

  MaybeHandle<Object> maybe_context = deserializer.DeserializePartial(
      isolate, global_proxy, outdated_contexts_out);
  Handle<Object> result;
  if (!maybe_context.ToHandle(&result)) return MaybeHandle<Context>();
  CHECK(result->IsContext());
  // If the snapshot does not contain a custom script, we need to update
  // the global object for exactly one context.
  CHECK(EmbedsScript(isolate) || (*outdated_contexts_out)->length() == 1);
  if (FLAG_profile_deserialization) {
    double ms = timer.Elapsed().InMillisecondsF();
    int bytes = context_data.length();
    PrintF("[Deserializing context (%d bytes) took %0.3f ms]\n", bytes, ms);
  }
  return Handle<Context>::cast(result);
}

void CalculateFirstPageSizes(bool is_default_snapshot,
                             const SnapshotData& startup_snapshot,
                             const SnapshotData& context_snapshot,
                             uint32_t* sizes_out) {
  Vector<const SerializedData::Reservation> startup_reservations =
      startup_snapshot.Reservations();
  Vector<const SerializedData::Reservation> context_reservations =
      context_snapshot.Reservations();
  int startup_index = 0;
  int context_index = 0;
  for (int space = 0; space < i::Serializer::kNumberOfSpaces; space++) {
    bool single_chunk = true;
    while (!startup_reservations[startup_index].is_last()) {
      single_chunk = false;
      startup_index++;
    }
    while (!context_reservations[context_index].is_last()) {
      single_chunk = false;
      context_index++;
    }

    uint32_t required = kMaxUInt32;
    if (single_chunk) {
      // If both the startup snapshot data and the context snapshot data on
      // this space fit in a single page, then we consider limiting the size
      // of the first page. For this, we add the chunk sizes and some extra
      // allowance. This way we achieve a smaller startup memory footprint.
      required = (startup_reservations[startup_index].chunk_size() +
                  2 * context_reservations[context_index].chunk_size()) +
                 Page::kObjectStartOffset;
    } else {
      // We expect the vanilla snapshot to only require on page per space.
      DCHECK(!is_default_snapshot);
    }

    if (space >= FIRST_PAGED_SPACE && space <= LAST_PAGED_SPACE) {
      uint32_t max_size =
          MemoryAllocator::PageAreaSize(static_cast<AllocationSpace>(space));
      sizes_out[space - FIRST_PAGED_SPACE] = Min(required, max_size);
    } else {
      DCHECK(single_chunk);
    }
    startup_index++;
    context_index++;
  }

  DCHECK_EQ(startup_reservations.length(), startup_index);
  DCHECK_EQ(context_reservations.length(), context_index);
}

v8::StartupData Snapshot::CreateSnapshotBlob(
    const i::StartupSerializer& startup_ser,
    const i::PartialSerializer& context_ser, Snapshot::Metadata metadata) {
  SnapshotData startup_snapshot(startup_ser);
  SnapshotData context_snapshot(context_ser);
  Vector<const byte> startup_data = startup_snapshot.RawData();
  Vector<const byte> context_data = context_snapshot.RawData();

  uint32_t first_page_sizes[kNumPagedSpaces];

  CalculateFirstPageSizes(!metadata.embeds_script(), startup_snapshot,
                          context_snapshot, first_page_sizes);

  int startup_length = startup_data.length();
  int context_length = context_data.length();
  int context_offset = ContextOffset(startup_length);

  int length = context_offset + context_length;
  char* data = new char[length];

  memcpy(data + kMetadataOffset, &metadata.RawValue(), kInt32Size);
  memcpy(data + kFirstPageSizesOffset, first_page_sizes,
         kNumPagedSpaces * kInt32Size);
  memcpy(data + kStartupLengthOffset, &startup_length, kInt32Size);
  memcpy(data + kStartupDataOffset, startup_data.begin(), startup_length);
  memcpy(data + context_offset, context_data.begin(), context_length);
  v8::StartupData result = {data, length};
  return result;
}

Snapshot::Metadata Snapshot::ExtractMetadata(const v8::StartupData* data) {
  uint32_t raw;
  memcpy(&raw, data->data + kMetadataOffset, kInt32Size);
  return Metadata(raw);
}

Vector<const byte> Snapshot::ExtractStartupData(const v8::StartupData* data) {
  DCHECK_LT(kIntSize, data->raw_size);
  int startup_length;
  memcpy(&startup_length, data->data + kStartupLengthOffset, kInt32Size);
  DCHECK_LT(startup_length, data->raw_size);
  const byte* startup_data =
      reinterpret_cast<const byte*>(data->data + kStartupDataOffset);
  return Vector<const byte>(startup_data, startup_length);
}

Vector<const byte> Snapshot::ExtractContextData(const v8::StartupData* data) {
  DCHECK_LT(kIntSize, data->raw_size);
  int startup_length;
  memcpy(&startup_length, data->data + kStartupLengthOffset, kIntSize);
  int context_offset = ContextOffset(startup_length);
  const byte* context_data =
      reinterpret_cast<const byte*>(data->data + context_offset);
  DCHECK_LT(context_offset, data->raw_size);
  int context_length = data->raw_size - context_offset;
  return Vector<const byte>(context_data, context_length);
}
} }  // namespace v8::internal
<|endoftext|>


<commit_before>#include "mdns.hpp"

// poor mans conditional compilation. is there a better way to do this with gyp?
#ifdef NODE_MDNS_USE_SOCKET_WATCHER

#include "socket_watcher.hpp"

#include <string.h> // needed for memset() with node v0.7.9 on Mac OS
#include <node.h>
#include <node_version.h>

using namespace v8;

#if NODE_VERSION_AT_LEAST(0, 7, 8)
// Nothing
#else
namespace node {

Handle<Value>
MakeCallback(const Handle<Object> object, const Handle<Function> callback,
        int argc, Handle<Value> argv[])
{
    HandleScope scope;

    // TODO Hook for long stack traces to be made here.

    TryCatch try_catch;

    Local<Value> ret = callback->Call(object, argc, argv);

    if (try_catch.HasCaught()) {
        FatalException(try_catch);
        return Undefined();
    }

    return scope.Close(ret);
}

}  // end of namespace node
#endif

namespace node_mdns {

    Persistent<String> callback_symbol;

    Handle<Value> Calleback(const Arguments& args) {
        return Undefined();
    };

    SocketWatcher::SocketWatcher() : poll_(NULL), fd_(0), events_(0) {
    }

    void SocketWatcher::Initialize(Handle<Object> target) {
        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        Local<String> symbol = String::NewSymbol("SocketWatcher");
        t->SetClassName(symbol);
        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(t, "set", SocketWatcher::Set);
        NODE_SET_PROTOTYPE_METHOD(t, "start", SocketWatcher::Start);
        NODE_SET_PROTOTYPE_METHOD(t, "stop", SocketWatcher::Stop);

        target->Set(symbol, t->GetFunction());

        callback_symbol = NODE_PSYMBOL("callback");
    }

    Handle<Value> SocketWatcher::Start(const Arguments& args) {
        HandleScope scope;
        SocketWatcher *watcher = ObjectWrap::Unwrap<SocketWatcher>(args.Holder());
        watcher->Start();
        return Undefined();
    }

    void SocketWatcher::Start() {
        if (poll_ == NULL) {
            poll_ = new uv_poll_t;
            memset(poll_,0,sizeof(uv_poll_t));
            poll_->data = this;
            uv_poll_init_socket(uv_default_loop(), poll_, fd_);

            Ref();
        }

        if (!uv_is_active((uv_handle_t*)poll_)) {
            uv_poll_start(poll_, events_, &SocketWatcher::Callback);
        }
    }

    void SocketWatcher::Callback(uv_poll_t *w, int status, int revents) {
        HandleScope scope;

        SocketWatcher *watcher = static_cast<SocketWatcher*>(w->data);
        assert(w == watcher->poll_);

        Local<Value> callback_v = watcher->handle_->Get(callback_symbol);
        if (!callback_v->IsFunction()) {
            watcher->Stop();
            return;
        }

        Local<Function> callback = Local<Function>::Cast(callback_v);

        Local<Value> argv[2];
        argv[0] = Local<Value>::New(revents & UV_READABLE ? True() : False());
        argv[1] = Local<Value>::New(revents & UV_WRITABLE ? True() : False());

        node::MakeCallback(watcher->handle_, callback, 2, argv);
    }

    Handle<Value> SocketWatcher::Stop(const Arguments& args) {
        HandleScope scope;
        SocketWatcher *watcher = ObjectWrap::Unwrap<SocketWatcher>(args.Holder());
        watcher->Stop();
        return Undefined();
    }

    void SocketWatcher::Stop() {
        if (poll_ != NULL) {
            uv_poll_stop(poll_);
            Unref();
        }
    }

    v8::Handle<v8::Value>
        SocketWatcher::New(const v8::Arguments & args) {
            HandleScope scope;
            SocketWatcher *s = new SocketWatcher();
            s->Wrap(args.This());
            return args.This();
    }

    Handle<Value> SocketWatcher::Set(const Arguments& args) {
        HandleScope scope;
        SocketWatcher *watcher = ObjectWrap::Unwrap<SocketWatcher>(args.Holder());
        if (!args[0]->IsInt32()) {
            return ThrowException(Exception::TypeError(
                String::New("First arg should be a file descriptor.")));
        }
        int fd = args[0]->Int32Value();
        if (!args[1]->IsBoolean()) {
            return ThrowException(Exception::TypeError(
                String::New("Second arg should boolean (readable).")));
        }
        int events = 0;

        if (args[1]->IsTrue()) events |= UV_READABLE;

        if (!args[2]->IsBoolean()) {
            return ThrowException(Exception::TypeError(
                String::New("Third arg should boolean (writable).")));
        }

        if (args[2]->IsTrue()) events |= UV_WRITABLE;

        assert(watcher->poll_ == NULL);

        watcher->fd_ = fd;
        watcher->events_ = events;

        return Undefined();
    }

} // end of namespace node_mdns

#endif // NODE_MDNS_USE_SOCKET_WATCHER
<commit_msg>[socket_watcher] cleaned up preprocessor logic<commit_after>#include "mdns.hpp"

// poor mans conditional compilation. is there a better way to do this with gyp?
#ifdef NODE_MDNS_USE_SOCKET_WATCHER

#include "socket_watcher.hpp"

#include <string.h> // needed for memset() with node v0.7.9 on Mac OS
#include <node.h>
#include <node_version.h>

using namespace v8;

#if ! NODE_VERSION_AT_LEAST(0, 7, 8)
namespace node {

Handle<Value>
MakeCallback(const Handle<Object> object, const Handle<Function> callback,
        int argc, Handle<Value> argv[])
{
    HandleScope scope;

    // TODO Hook for long stack traces to be made here.

    TryCatch try_catch;

    Local<Value> ret = callback->Call(object, argc, argv);

    if (try_catch.HasCaught()) {
        FatalException(try_catch);
        return Undefined();
    }

    return scope.Close(ret);
}

}  // end of namespace node
#endif

namespace node_mdns {

    Persistent<String> callback_symbol;

    Handle<Value> Calleback(const Arguments& args) {
        return Undefined();
    };

    SocketWatcher::SocketWatcher() : poll_(NULL), fd_(0), events_(0) {
    }

    void SocketWatcher::Initialize(Handle<Object> target) {
        Local<FunctionTemplate> t = FunctionTemplate::New(New);

        Local<String> symbol = String::NewSymbol("SocketWatcher");
        t->SetClassName(symbol);
        t->InstanceTemplate()->SetInternalFieldCount(1);

        NODE_SET_PROTOTYPE_METHOD(t, "set", SocketWatcher::Set);
        NODE_SET_PROTOTYPE_METHOD(t, "start", SocketWatcher::Start);
        NODE_SET_PROTOTYPE_METHOD(t, "stop", SocketWatcher::Stop);

        target->Set(symbol, t->GetFunction());

        callback_symbol = NODE_PSYMBOL("callback");
    }

    Handle<Value> SocketWatcher::Start(const Arguments& args) {
        HandleScope scope;
        SocketWatcher *watcher = ObjectWrap::Unwrap<SocketWatcher>(args.Holder());
        watcher->Start();
        return Undefined();
    }

    void SocketWatcher::Start() {
        if (poll_ == NULL) {
            poll_ = new uv_poll_t;
            memset(poll_,0,sizeof(uv_poll_t));
            poll_->data = this;
            uv_poll_init_socket(uv_default_loop(), poll_, fd_);

            Ref();
        }

        if (!uv_is_active((uv_handle_t*)poll_)) {
            uv_poll_start(poll_, events_, &SocketWatcher::Callback);
        }
    }

    void SocketWatcher::Callback(uv_poll_t *w, int status, int revents) {
        HandleScope scope;

        SocketWatcher *watcher = static_cast<SocketWatcher*>(w->data);
        assert(w == watcher->poll_);

        Local<Value> callback_v = watcher->handle_->Get(callback_symbol);
        if (!callback_v->IsFunction()) {
            watcher->Stop();
            return;
        }

        Local<Function> callback = Local<Function>::Cast(callback_v);

        Local<Value> argv[2];
        argv[0] = Local<Value>::New(revents & UV_READABLE ? True() : False());
        argv[1] = Local<Value>::New(revents & UV_WRITABLE ? True() : False());

        node::MakeCallback(watcher->handle_, callback, 2, argv);
    }

    Handle<Value> SocketWatcher::Stop(const Arguments& args) {
        HandleScope scope;
        SocketWatcher *watcher = ObjectWrap::Unwrap<SocketWatcher>(args.Holder());
        watcher->Stop();
        return Undefined();
    }

    void SocketWatcher::Stop() {
        if (poll_ != NULL) {
            uv_poll_stop(poll_);
            Unref();
        }
    }

    v8::Handle<v8::Value>
        SocketWatcher::New(const v8::Arguments & args) {
            HandleScope scope;
            SocketWatcher *s = new SocketWatcher();
            s->Wrap(args.This());
            return args.This();
    }

    Handle<Value> SocketWatcher::Set(const Arguments& args) {
        HandleScope scope;
        SocketWatcher *watcher = ObjectWrap::Unwrap<SocketWatcher>(args.Holder());
        if (!args[0]->IsInt32()) {
            return ThrowException(Exception::TypeError(
                String::New("First arg should be a file descriptor.")));
        }
        int fd = args[0]->Int32Value();
        if (!args[1]->IsBoolean()) {
            return ThrowException(Exception::TypeError(
                String::New("Second arg should boolean (readable).")));
        }
        int events = 0;

        if (args[1]->IsTrue()) events |= UV_READABLE;

        if (!args[2]->IsBoolean()) {
            return ThrowException(Exception::TypeError(
                String::New("Third arg should boolean (writable).")));
        }

        if (args[2]->IsTrue()) events |= UV_WRITABLE;

        assert(watcher->poll_ == NULL);

        watcher->fd_ = fd;
        watcher->events_ = events;

        return Undefined();
    }

} // end of namespace node_mdns

#endif // NODE_MDNS_USE_SOCKET_WATCHER
<|endoftext|>


<commit_before><commit_msg>Fix: 2021-11-07<commit_after><|endoftext|>


<commit_before>#include <QTest>
#include "teststringutils.hpp"

int main()
{
    QTest::qExec(new TestStringUtils());
}
<commit_msg>Implements test selection via command line. To select tests, add the names of the test case classes as arguments to the command. No arguments or including the argument 'all' will run all tests.<commit_after>#include <QTest>
#include "teststringutils.hpp"
#include <vector>
#include <algorithm>
#include <iostream>

void RunTestCase(QObject* testCase, std::vector<std::string> args)
{
    if(args.size() == 0 || std::find(args.begin(), args.end(), testCase->metaObject()->className()) != args.end())
    {
        QTest::qExec(testCase);
    }
}

int main(int argc, const char* argv[])
{
    // Setup arguments vector
    std::vector<std::string> args;
    for(int i = 0; i < argc; i++)
        if(argv[i][0] != '/')
            args.push_back(argv[i]);
    if(std::find(args.begin(), args.end(), "all") != args.end())
        args.clear();
    if(args.size() == 0)
    {
        std::cout << "Running all tests." << std::endl;
    }
    else
    {
        std::cout << "Running ";
        for(uint i = 0; i < args.size() - 1; i++)
            std::cout << args[i] << ", ";
        std::cout << (args.size() > 1 ? "and " : "") << args[args.size()-1] << "." << std::endl;
    }

    // Execute selected test cases
    RunTestCase(new TestStringUtils(), args);
}
<|endoftext|>