<commit_before>#include "model.h"
#include "octree.h"
#include "shapes.h"
#include <typeindex>
#include <typeinfo>
#include <iostream>
#include <sstream>
#include <GL/gl.h>

using namespace tnw;
using namespace tnw::octree;

//Octree com raiz vazia
tnw::Octree::Octree(const BoundingBox& _bb) : bb(_bb) {}
//Octree com raiz pronta
tnw::Octree::Octree(std::unique_ptr<Tree>&& tree, const BoundingBox& _bb) : tree(std::move(tree)), bb(_bb) {}
//Octree a partir de um forma e uma Bounding Box
tnw::Octree::Octree(const Shape& s, const BoundingBox& _bb, unsigned int depth) : bb(_bb) {
	tree = std::unique_ptr<Tree>(octree::classify(s, _bb, depth, 0));
}
//Octree a partir de um arquivo
tnw::Octree::Octree(FILE *f) : bb(glm::vec3(), 1) {
	float x,y,z,d;
	fscanf(f,"%f,%f,%f,%f ",&x,&y,&z,&d);
	bb = BoundingBox({x,y,z},d);
	tree = unique_ptr<Tree>(make_from_file(f));
}

owner_ptr<Model> tnw::Octree::clone() const {
	auto c = new Octree(bb);
	c->tree.reset(new Tree(*tree));
	return c;
}

void tnw::Octree::rdraw() {
	//Desenha a bounding box
	glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
	glColor3f(0,0,0);
	bb.draw();
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
	//Desenha a árvore
	if (tree) {
		tree->draw(bb);
	}
}
// Geometric operations
void tnw::Octree::translate(const glm::vec3& dv) {
	bb.translate(dv);
}
void tnw::Octree::scale(const float dx) {
	bb.scale(dx);
}

Color tnw::Octree::intersect_box(const BoundingBox& b2) const {
	if (tree)
		return std::get<0>(tree->intersect_box(bb,b2));
	else return Color::white;
}

Color tnw::Octree::intersect_point(const glm::vec3& x) const {
	if (tree)
		return tree->intersect_point(bb,x);
	else return Color::white;
}

IntersectionList tnw::Octree::intersect_ray(const Ray& r) const {
	throw 0;
}

// Boolean operations
tnw::BooleanErrorCodes tnw::Octree::bool_and(const Model& y) {
	if (std::type_index(typeid(y)) == std::type_index(typeid(Octree))) {
		auto&& y_oct = static_cast<const Octree&>(y);
		if (bb != y_oct.bb) { return tnw::BooleanErrorCodes::boundingboxMismatch;}
		tree = std::unique_ptr<Tree>(octree::tree_and(tree.get(), y_oct.tree.get()));
		return tnw::BooleanErrorCodes::success;
	} else return tnw::BooleanErrorCodes::unimplementedType;
}
tnw::BooleanErrorCodes tnw::Octree::bool_or(const Model& y) {
	if (std::type_index(typeid(y)) == std::type_index(typeid(Octree))) {
		auto&& y_oct = static_cast<const Octree&>(y);
		if (bb != y_oct.bb) { return tnw::BooleanErrorCodes::boundingboxMismatch;}
		tree = std::unique_ptr<Tree>(octree::tree_or(tree.get(), y_oct.tree.get()));
		return tnw::BooleanErrorCodes::success;
	} else return tnw::BooleanErrorCodes::unimplementedType;
}
// Geometric analysis

BoundingBox tnw::Octree::boundingBox() const {
	return bb;
}

double tnw::Octree::volume() const{
	if (tree) {
		return bb.volume() * tree->volume();
	} else {
		return 0;
	}
}

//Serialize
std::string tnw::Octree::serialize() const {
	std::stringstream ss;
	ss << bb.corner[0] << ',';
	ss << bb.corner[1] << ',';
	ss << bb.corner[2] << ',';
	ss << bb.depth << ' ';
	ss << octree::serialize(tree.get());
	return ss.str();
}

//Set color
void tnw::Octree::setColor(const float c[3]){
	if (tree) {
		tree->setColor(c);
	}
}

PaintColor tnw::Octree::getColor() const {
	std::array<float, 3> color;
	if (tree) {
		for (int i = 0; i < 3; ++i) {
			color[i] = tree->drawColor[i];
		}
		return color;
	} else {
		for (int i = 0; i < 3; ++i) {
			color[i] = 0.0;
		}
		return color;
	}
}
<commit_msg>Adicionado failsafe para intersecção em Octree<commit_after>#include "model.h"
#include "octree.h"
#include "shapes.h"
#include <typeindex>
#include <typeinfo>
#include <iostream>
#include <sstream>
#include <GL/gl.h>

using namespace tnw;
using namespace tnw::octree;

//Octree com raiz vazia
tnw::Octree::Octree(const BoundingBox& _bb) : bb(_bb) {}
//Octree com raiz pronta
tnw::Octree::Octree(std::unique_ptr<Tree>&& tree, const BoundingBox& _bb) : tree(std::move(tree)), bb(_bb) {}
//Octree a partir de um forma e uma Bounding Box
tnw::Octree::Octree(const Shape& s, const BoundingBox& _bb, unsigned int depth) : bb(_bb) {
	tree = std::unique_ptr<Tree>(octree::classify(s, _bb, depth, 0));
}
//Octree a partir de um arquivo
tnw::Octree::Octree(FILE *f) : bb(glm::vec3(), 1) {
	float x,y,z,d;
	fscanf(f,"%f,%f,%f,%f ",&x,&y,&z,&d);
	bb = BoundingBox({x,y,z},d);
	tree = unique_ptr<Tree>(make_from_file(f));
}

owner_ptr<Model> tnw::Octree::clone() const {
	auto c = new Octree(bb);
	c->tree.reset(new Tree(*tree));
	return c;
}

void tnw::Octree::rdraw() {
	//Desenha a bounding box
	glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
	glColor3f(0,0,0);
	bb.draw();
	glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
	//Desenha a árvore
	if (tree) {
		tree->draw(bb);
	}
}
// Geometric operations
void tnw::Octree::translate(const glm::vec3& dv) {
	bb.translate(dv);
}
void tnw::Octree::scale(const float dx) {
	bb.scale(dx);
}

Color tnw::Octree::intersect_box(const BoundingBox& b2) const {
	if (tree)
		return std::get<0>(tree->intersect_box(bb,b2));
	else return Color::white;
}

Color tnw::Octree::intersect_point(const glm::vec3& x) const {
	if (tree)
		return tree->intersect_point(bb,x);
	else return Color::white;
}

IntersectionList tnw::Octree::intersect_ray(const Ray& r) const {
	// TODO intersecção em octree
	return IntersectionList({std::make_tuple(Color::white,r.length())});
}

// Boolean operations
tnw::BooleanErrorCodes tnw::Octree::bool_and(const Model& y) {
	if (std::type_index(typeid(y)) == std::type_index(typeid(Octree))) {
		auto&& y_oct = static_cast<const Octree&>(y);
		if (bb != y_oct.bb) { return tnw::BooleanErrorCodes::boundingboxMismatch;}
		tree = std::unique_ptr<Tree>(octree::tree_and(tree.get(), y_oct.tree.get()));
		return tnw::BooleanErrorCodes::success;
	} else return tnw::BooleanErrorCodes::unimplementedType;
}
tnw::BooleanErrorCodes tnw::Octree::bool_or(const Model& y) {
	if (std::type_index(typeid(y)) == std::type_index(typeid(Octree))) {
		auto&& y_oct = static_cast<const Octree&>(y);
		if (bb != y_oct.bb) { return tnw::BooleanErrorCodes::boundingboxMismatch;}
		tree = std::unique_ptr<Tree>(octree::tree_or(tree.get(), y_oct.tree.get()));
		return tnw::BooleanErrorCodes::success;
	} else return tnw::BooleanErrorCodes::unimplementedType;
}
// Geometric analysis

BoundingBox tnw::Octree::boundingBox() const {
	return bb;
}

double tnw::Octree::volume() const{
	if (tree) {
		return bb.volume() * tree->volume();
	} else {
		return 0;
	}
}

//Serialize
std::string tnw::Octree::serialize() const {
	std::stringstream ss;
	ss << bb.corner[0] << ',';
	ss << bb.corner[1] << ',';
	ss << bb.corner[2] << ',';
	ss << bb.depth << ' ';
	ss << octree::serialize(tree.get());
	return ss.str();
}

//Set color
void tnw::Octree::setColor(const float c[3]){
	if (tree) {
		tree->setColor(c);
	}
}

PaintColor tnw::Octree::getColor() const {
	std::array<float, 3> color;
	if (tree) {
		for (int i = 0; i < 3; ++i) {
			color[i] = tree->drawColor[i];
		}
		return color;
	} else {
		for (int i = 0; i < 3; ++i) {
			color[i] = 0.0;
		}
		return color;
	}
}
<|endoftext|>


<commit_before>/*
 *  RudeControl.cpp
 *
 *  Bork3D Game Engine
 *  Copyright (c) 2009 Bork 3D LLC. All rights reserved.
 *
 */

#include "RudeControl.h"

#include "RudeDebug.h"
#include "RudeFile.h"

#include "RudeTextControl.h"
#include "RudeButtonControl.h"
#include "RudeButtonAnimControl.h"

RudeControl::RudeControl()
: m_rect(0,0,0,0)
, m_hitStart(0,0)
, m_hitMove(0,0)
, m_hitMoveDelta(0,0)
, m_hitDelta(0,0)
, m_hitDistanceTraveled(0,0)
, m_hitId(-1)
, m_translation(0,0,0)
, m_desiredTranslation(0,0,0)
, m_animSpeed(3.0f)
, m_animType(kAnimNone)
{
}

RudeControl::~RudeControl()
{
	unsigned int size = m_children.size();

	for(unsigned int i = 0; i < size; i++)
	{
		RUDE_ASSERT(m_children[i], "Invalid child discovered");

		delete m_children[i];
		m_children[i] = 0;
	}

	m_children.clear();
}

void RudeControl::Load(const char *name)
{
	char filename[256];
	snprintf(filename, 256, "%s.ui", name);

	char buffer[512];
	RudeFileGetFile(filename, buffer, 512, false);

	FILE *file = fopen(buffer, "r");
	RUDE_ASSERT(file, "Could not open %s", buffer);

	char line[512];
	while(fgets(line, 512, file) != 0)
	{
		RUDE_ASSERT(line, "Failed to parse %s\n", buffer);

		if(line[0] == '\n')
			continue;
		if(line[0] == '#')
			continue;

		ConstructChild(line);
	}

}

/**
 * Returns the RudeControl matching the given name.
 * If the control is not found this method asserts.
 * Make sure you dynamic_cast the control to the type
 * you expect.
 */
RudeControl * RudeControl::GetChildControl(const std::string &name)
{
	unsigned int size = m_children.size();

	for(unsigned int i = 0; i < size; i++)
	{
		RudeControl *child = m_children[i];
		RUDE_ASSERT(child, "Invalid child discovered");

		if(child->GetName() == name)
			return child;
	}

	RUDE_ASSERT(0, "Child not found '%s'", name.c_str());

	return 0;
}

bool RudeControl::Contains(const RudeScreenVertex &p)
{
	return m_rect.Contains(p);
}

bool RudeControl::TouchDown(RudeTouch *t)
{
	if(!Contains(t->m_location))
		return false;

	m_hitId = t->m_touchId;
	m_hitStart = t->m_location;
	m_hitMove = m_hitStart;
	m_hitMoveDelta = RudeScreenVertex(0,0);
	m_hitDelta = RudeScreenVertex(0,0);
	m_hitDistanceTraveled = RudeScreenVertex(0,0);

	return true;
}

bool RudeControl::TouchMove(RudeTouch *t)
{
	if(m_hitId != t->m_touchId)
		return false;

	m_hitMoveDelta = t->m_location - m_hitMove;
	m_hitMove = t->m_location;
	m_hitDelta = t->m_location - m_hitStart;

	m_hitDistanceTraveled.m_x += abs(m_hitDelta.m_x);
	m_hitDistanceTraveled.m_y += abs(m_hitDelta.m_y);

	return true;
}

bool RudeControl::TouchUp(RudeTouch *t)
{
	if(m_hitId != t->m_touchId)
		return false;

	m_hitId = -1;

	m_hitMoveDelta = t->m_location - m_hitMove;
	m_hitMove = t->m_location;
	m_hitDelta = t->m_location - m_hitStart;

	return true;
}

void RudeControl::NextFrame(float delta)
{
	switch(m_animType)
	{
		default:
		case kAnimNone:
			break;
		case kAnimPopSlide:
			{
				m_translation += (m_desiredTranslation - m_translation) * delta * m_animSpeed;
			}
			break;
	}

	unsigned int size = m_children.size();
	for(unsigned int i = 0; i < size; i++)
		m_children[i]->NextFrame(delta);
}

void RudeControl::Render()
{
	unsigned int size = m_children.size();
	for(unsigned int i = 0; i < size; i++)
		m_children[i]->Render();

	RGL.LoadIdentity();

	if(m_animType != kAnimNone)
		RGL.Translate(m_translation.x(), m_translation.y(), m_translation.z());
}

void RudeControl::ConstructChild(char *desc)
{
	RUDE_ASSERT(desc, "Invalid description");

	// Store description in case we need to print it
	std::string originalDesc(desc);

	// Split description string into tokens
	std::list<std::string> tokens;

	const char *kDelimStr = "\t\n\r";
	const char *token = strtok(desc, kDelimStr);

	while(token)
	{
		tokens.push_back(std::string(token));
		token = strtok(0, kDelimStr);
	}

	// First token designates the type of Control
	std::string type = PopToken(tokens, originalDesc, "type");

	// Second token designates the name of the Control
	std::string name = PopToken(tokens, originalDesc, "name");

	// Construct the control based on it's type
	RudeControl *control = 0;

	ConstructRudeControlFuncPtr funcptr = RudeControlRegistration::GetConstructor(type);

	control = (*funcptr)(tokens, originalDesc);

	RUDE_ASSERT(control, "Failed to create Control type: %s", type.c_str());

	control->SetName(name);

	// Add control to list of children
	m_children.push_back(control);

}

std::string RudeControl::PopToken(std::list<std::string> &tokens, const std::string &desc, const std::string &explanation)
{
	RUDE_ASSERT(tokens.size() > 0, "Invalid description: '%s', Expected %s", desc.c_str(), explanation.c_str());
	std::string token = tokens.front();
	tokens.pop_front();

	return token;
}

void RudeControl::ParseRect(std::string &str, RudeRect &rect)
{
	char rectstr[256];
	snprintf(rectstr, 256, "%s", str.c_str());

	// Split rect string into tokens
	std::list<std::string> tokens;

	const char *kDelimStr = "{, }";
	const char *token = strtok(rectstr, kDelimStr);

	while(token)
	{
		tokens.push_back(std::string(token));
		token = strtok(0, kDelimStr);
	}

	std::string top = PopToken(tokens, str, "top (t,l,b,r)");
	std::string left = PopToken(tokens, str, "left (t,l,b,r)");
	std::string bottom = PopToken(tokens, str, "bottom (t,l,b,r)");
	std::string right = PopToken(tokens, str, "right (t,l,b,r)");

	rect.m_top = atoi(top.c_str());
	rect.m_left = atoi(left.c_str());
	rect.m_bottom = atoi(bottom.c_str());
	rect.m_right = atoi(right.c_str());
}

void RudeControl::ParseOffset(std::string &str, int &offx, int &offy)
{
	char offsetstr[256];
	snprintf(offsetstr, 256, "%s", str.c_str());

	// Split rect string into tokens
	std::list<std::string> tokens;

	const char *kDelimStr = "{, }";
	const char *token = strtok(offsetstr, kDelimStr);

	while(token)
	{
		tokens.push_back(std::string(token));
		token = strtok(0, kDelimStr);
	}

	std::string offxstr = PopToken(tokens, str, "x (x,y)");
	std::string offystr = PopToken(tokens, str, "y (x,y)");

	offx = atoi(offxstr.c_str());
	offy = atoi(offystr.c_str());
}

void RudeControl::ParseColor(std::string &str, unsigned int &color)
{
	int result = sscanf(str.c_str(), "0x%x", &color);

	RUDE_ASSERT(result == 1, "Failed to parse color (0xAARRGGBB), got %s\n", str.c_str());
}

/**
 * RudeControl factory assistant for RudeControl.  This is called by RudeControl::Load()
 * Sometimes all you need is a Control.
 */
RudeControl * ConstructControl(std::list<std::string> &tokens, const std::string &originalDesc)
{
	RudeControl *c = new RudeControl();
	RUDE_ASSERT(c, "Failed to construct control");

	// Rect {t,l,b,r}
	std::string rectstr = RudeControl::PopToken(tokens, originalDesc, "rect");

	RudeRect rect;
	RudeControl::ParseRect(rectstr, rect);
	c->SetRect(rect);

	return c;
}

RudeControlRegistration controlRegistration("RudeControl", ConstructControl);

<commit_msg>.ui files can be UTF8 now<commit_after>/*
 *  RudeControl.cpp
 *
 *  Bork3D Game Engine
 *  Copyright (c) 2009 Bork 3D LLC. All rights reserved.
 *
 */

#include "RudeControl.h"

#include "RudeDebug.h"
#include "RudeFile.h"

#include "RudeTextControl.h"
#include "RudeButtonControl.h"
#include "RudeButtonAnimControl.h"

RudeControl::RudeControl()
: m_rect(0,0,0,0)
, m_hitStart(0,0)
, m_hitMove(0,0)
, m_hitMoveDelta(0,0)
, m_hitDelta(0,0)
, m_hitDistanceTraveled(0,0)
, m_hitId(-1)
, m_translation(0,0,0)
, m_desiredTranslation(0,0,0)
, m_animSpeed(3.0f)
, m_animType(kAnimNone)
{
}

RudeControl::~RudeControl()
{
	unsigned int size = m_children.size();

	for(unsigned int i = 0; i < size; i++)
	{
		RUDE_ASSERT(m_children[i], "Invalid child discovered");

		delete m_children[i];
		m_children[i] = 0;
	}

	m_children.clear();
}

void RudeControl::Load(const char *name)
{
	char filename[256];
	snprintf(filename, 256, "%s.ui", name);

	char buffer[512];
	RudeFileGetFile(filename, buffer, 512, false);

	FILE *file = fopen(buffer, "r");
	RUDE_ASSERT(file, "Could not open %s", buffer);

	char line[512];
	while(fgets(line, 512, file) != 0)
	{
		RUDE_ASSERT(line, "Failed to parse %s\n", buffer);

		int len = strlen(line);

		if(len <= 0)
			continue;

		if(line[0] == '\n')
			// Blank line
			continue;
		if(line[0] == '#')
			// Comment
			continue;

		if(line[0] == char(0xEF))
			// UTF-8 escape sequence
			continue;

		ConstructChild(line);
	}

}

/**
 * Returns the RudeControl matching the given name.
 * If the control is not found this method asserts.
 * Make sure you dynamic_cast the control to the type
 * you expect.
 */
RudeControl * RudeControl::GetChildControl(const std::string &name)
{
	unsigned int size = m_children.size();

	for(unsigned int i = 0; i < size; i++)
	{
		RudeControl *child = m_children[i];
		RUDE_ASSERT(child, "Invalid child discovered");

		if(child->GetName() == name)
			return child;
	}

	RUDE_ASSERT(0, "Child not found '%s'", name.c_str());

	return 0;
}

bool RudeControl::Contains(const RudeScreenVertex &p)
{
	return m_rect.Contains(p);
}

bool RudeControl::TouchDown(RudeTouch *t)
{
	if(!Contains(t->m_location))
		return false;

	m_hitId = t->m_touchId;
	m_hitStart = t->m_location;
	m_hitMove = m_hitStart;
	m_hitMoveDelta = RudeScreenVertex(0,0);
	m_hitDelta = RudeScreenVertex(0,0);
	m_hitDistanceTraveled = RudeScreenVertex(0,0);

	return true;
}

bool RudeControl::TouchMove(RudeTouch *t)
{
	if(m_hitId != t->m_touchId)
		return false;

	m_hitMoveDelta = t->m_location - m_hitMove;
	m_hitMove = t->m_location;
	m_hitDelta = t->m_location - m_hitStart;

	m_hitDistanceTraveled.m_x += abs(m_hitDelta.m_x);
	m_hitDistanceTraveled.m_y += abs(m_hitDelta.m_y);

	return true;
}

bool RudeControl::TouchUp(RudeTouch *t)
{
	if(m_hitId != t->m_touchId)
		return false;

	m_hitId = -1;

	m_hitMoveDelta = t->m_location - m_hitMove;
	m_hitMove = t->m_location;
	m_hitDelta = t->m_location - m_hitStart;

	return true;
}

void RudeControl::NextFrame(float delta)
{
	switch(m_animType)
	{
		default:
		case kAnimNone:
			break;
		case kAnimPopSlide:
			{
				m_translation += (m_desiredTranslation - m_translation) * delta * m_animSpeed;
			}
			break;
	}

	unsigned int size = m_children.size();
	for(unsigned int i = 0; i < size; i++)
		m_children[i]->NextFrame(delta);
}

void RudeControl::Render()
{
	unsigned int size = m_children.size();
	for(unsigned int i = 0; i < size; i++)
		m_children[i]->Render();

	RGL.LoadIdentity();

	if(m_animType != kAnimNone)
		RGL.Translate(m_translation.x(), m_translation.y(), m_translation.z());
}

void RudeControl::ConstructChild(char *desc)
{
	RUDE_ASSERT(desc, "Invalid description");

	// Store description in case we need to print it
	std::string originalDesc(desc);

	// Split description string into tokens
	std::list<std::string> tokens;

	const char *kDelimStr = "\t\n\r";
	const char *token = strtok(desc, kDelimStr);

	while(token)
	{
		tokens.push_back(std::string(token));
		token = strtok(0, kDelimStr);
	}

	// First token designates the type of Control
	std::string type = PopToken(tokens, originalDesc, "type");

	// Second token designates the name of the Control
	std::string name = PopToken(tokens, originalDesc, "name");

	// Construct the control based on it's type
	RudeControl *control = 0;

	ConstructRudeControlFuncPtr funcptr = RudeControlRegistration::GetConstructor(type);

	control = (*funcptr)(tokens, originalDesc);

	RUDE_ASSERT(control, "Failed to create Control type: %s", type.c_str());

	control->SetName(name);

	// Add control to list of children
	m_children.push_back(control);

}

std::string RudeControl::PopToken(std::list<std::string> &tokens, const std::string &desc, const std::string &explanation)
{
	RUDE_ASSERT(tokens.size() > 0, "Invalid description: '%s', Expected %s", desc.c_str(), explanation.c_str());
	std::string token = tokens.front();
	tokens.pop_front();

	return token;
}

void RudeControl::ParseRect(std::string &str, RudeRect &rect)
{
	char rectstr[256];
	snprintf(rectstr, 256, "%s", str.c_str());

	// Split rect string into tokens
	std::list<std::string> tokens;

	const char *kDelimStr = "{, }";
	const char *token = strtok(rectstr, kDelimStr);

	while(token)
	{
		tokens.push_back(std::string(token));
		token = strtok(0, kDelimStr);
	}

	std::string top = PopToken(tokens, str, "top (t,l,b,r)");
	std::string left = PopToken(tokens, str, "left (t,l,b,r)");
	std::string bottom = PopToken(tokens, str, "bottom (t,l,b,r)");
	std::string right = PopToken(tokens, str, "right (t,l,b,r)");

	rect.m_top = atoi(top.c_str());
	rect.m_left = atoi(left.c_str());
	rect.m_bottom = atoi(bottom.c_str());
	rect.m_right = atoi(right.c_str());
}

void RudeControl::ParseOffset(std::string &str, int &offx, int &offy)
{
	char offsetstr[256];
	snprintf(offsetstr, 256, "%s", str.c_str());

	// Split rect string into tokens
	std::list<std::string> tokens;

	const char *kDelimStr = "{, }";
	const char *token = strtok(offsetstr, kDelimStr);

	while(token)
	{
		tokens.push_back(std::string(token));
		token = strtok(0, kDelimStr);
	}

	std::string offxstr = PopToken(tokens, str, "x (x,y)");
	std::string offystr = PopToken(tokens, str, "y (x,y)");

	offx = atoi(offxstr.c_str());
	offy = atoi(offystr.c_str());
}

void RudeControl::ParseColor(std::string &str, unsigned int &color)
{
	int result = sscanf(str.c_str(), "0x%x", &color);

	RUDE_ASSERT(result == 1, "Failed to parse color (0xAARRGGBB), got %s\n", str.c_str());
}

/**
 * RudeControl factory assistant for RudeControl.  This is called by RudeControl::Load()
 * Sometimes all you need is a Control.
 */
RudeControl * ConstructControl(std::list<std::string> &tokens, const std::string &originalDesc)
{
	RudeControl *c = new RudeControl();
	RUDE_ASSERT(c, "Failed to construct control");

	// Rect {t,l,b,r}
	std::string rectstr = RudeControl::PopToken(tokens, originalDesc, "rect");

	RudeRect rect;
	RudeControl::ParseRect(rectstr, rect);
	c->SetRect(rect);

	return c;
}

RudeControlRegistration controlRegistration("RudeControl", ConstructControl);

<|endoftext|>


<commit_before>/*
Copyright 2014, Jernej Kovacic

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * @file
 * @author Jernej Kovacic
 *
 * Implementation of functions within the namespace NormalDist
 * that perform various normal distribution related operations,
 * such as calculation of upper and lower tail probabilities and
 * quantiles, calculation of z statistics, probability
 * distribution function, etc.
 */

/*
 * More details about the normal distribution:
 * https://en.wikipedia.org/wiki/Normal_distribution
 */

// No #include "NormalDistGeneric.hpp" !!!
#include <cmath>
#include <algorithm>

#include "../settings/stat_settings.h"

#include "util/math_constant.h"
#include "util/NumericUtil.hpp"
#include "specfun/SpecFunGeneric.hpp"
#include "exception/SpecFunException.hpp"
#include "exception/StatisticsException.hpp"

namespace math {  namespace NormalDist {  namespace __private
{

/*
 * Checks the validity of the given standard deviation.
 * It must be strictly greater than zero.
 *
 * @param sigma - standard deviation to check
 *
 * @throw StatisticsException if 'sigma' is not valid.
 */
template <class T>
void __checkSigma(const T& sigma) throw (math::StatisticsException)
{
    if ( sigma < NumericUtil::getEPS<T>() )
    {
        throw math::StatisticsException(math::StatisticsException::INVALID_STDEV);
    }
}

}}}  // namespace math::NormalDist::__private

/**
 * Obtains the z-statistics (a.k.a. standard score) of 'x', i.e.
 * the distance of 'x' from the mean, expressed in number of
 * standard deviations.
 *
 * @param x - value to be calculated its z-statistics
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 *
 * @return z statistics of 'x' for the given normal distribution parameters
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::getZ(
          const T& x,
          const T& mu,
          const T& sigma
        ) throw (math::StatisticsException)
{
    /*
     *
     *         x - mu
     *   z = -----------
     *         sigma
     */

    // sanity check:
    math::NormalDist::__private::__checkSigma<T>(sigma);

    return (x - mu) / sigma;
}

/**
 * Converts z-statistics (a.k.a standard score) back to the
 * original value for the normal distribution with specified
 * parameters.
 *
 * @param z - z-statistics to be converted
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 *
 * @return x value within the normal distribution
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::getX(
          const T& z,
          const T& mu,
          const T& sigma
        ) throw (math::StatisticsException)
{
    /*
     * x = mu + z * sigma
     */

    // sanity check:
	math::NormalDist::__private::__checkSigma<T>(sigma);

    return mu + z * sigma;
}

/**
 * Value of the normal distribution's probability distribution
 * function (pdf) for the given 'x'.
 *
 * @param x - value to be calculated its probability distribution function
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 *
 * @return pdf(x, mu, sigma)
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::pdf(
      const T& x,
      const T& mu,
      const T& sigma
    ) throw (math::StatisticsException)
{
    /*
     * Probability density function of the normal distribution:
     *
     *                            2
     *                    (x - mu)
     *                - --------------
     *                             2
     *                    2 * sigma
     *              e
     *   pdf =   -----------------------
     *                        ------+
     *              sigma * \/ 2*pi
     *
     */

    // sanity check:
    math::NormalDist::__private::__checkSigma<T>(sigma);

    const T z = (x - mu) / sigma;
    return static_cast<T>(MATH_CONST_SQRT_INV_2_PI) *
           std::exp( -z*z / static_cast<T>(2) ) / sigma;
}

/**
 * Probability in the normal distribution with specified
 * parameters  that 'x' is greater than 'a' and less  than 'b'
 * (or vice versa if b<a).
 *
 * @note 'a' and 'b' are interchangeable, the result's sign will
 *       not change in this case.
 *
 * @param a - lower limit of the interval
 * @param b - upper limit of the interval
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 *
 * @return P(a<x<b) or P(b<x<a)
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::probInt(
      const T& a,
      const T& b,
      const T& mu,
      const T& sigma
    ) throw (math::StatisticsException)
{
    /*
     *              b
     *              /
     *   P(a<x<b) = | pdf(t) dt  =  cdf(b) - cdf(a)
     *              /
     *              a
     */

    // sanity check:
    math::NormalDist::__private::__checkSigma<T>(sigma);

    const T from = std::min(a, b);
    const T to = std::max(a, b);

    return math::NormalDist::prob<T>(to, mu, sigma, true) -
           math::NormalDist::prob<T>(from, mu, sigma, true);
}

/**
 * Probability that a value is greater or smaller (depending on 'lowerTail')
 * than the given value 'x' for the specified normal distribution.
 *
 * @param x - value
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 * @param lowerTail - if true, returns P(t<x), otherwise P(t>x) (default: true)
 *
 * @return P(t<x) if 'lowerTail' equals true, P(t>x) if 'lowerTail' equals false
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::prob(
      const T& x,
      const T& mu,
      const T& sigma,
      bool lowerTail
    ) throw (math::StatisticsException)
{
    /*
     * The cdf represents probability that a value from the normal
     * distribution is smaller than a specified value 'x' and can be
     * expressed as:
     *
     *                     x                   x
     *                     /              1    /
     *   cdf(x) = P(t<x) = | pdf(t) dt = --- + | pdf(t) dt
     *                     /              2    /
     *                   -inf                 mu
     *
     * One approach to calculate this would be numerical integration,
     * however there are more efficient methods available.
     *
     * As evident from:
     * https://en.wikipedia.org/wiki/Normal_distribution
     * cdf can be further expressed as:
     *
     *                +-                             -+
     *             1  |         /      x - mu       \ |
     *   cdf(x) = --- | 1 + erf | ----------------- | | =
     *             2  |         \  sigma * sqrt(2)  / |
     *                +-                             -+
     *
     *             1         /        x - mu       \
     *          = --- * erfc | - ----------------- |
     *             2         \    sigma * sqrt(2)  /
     *
     * where 'erf' is the so called error function, implemented
     * in the namespace math::SpecFun.
     *
     * For the upper tail probability ( P(t>x) ) just return the complement
     * of the lower tail probability: 1 - cdf(x)
     */

    // sanity check
    math::NormalDist::__private::__checkSigma<T>(sigma);

    // Tolerance for the last Taylor series term
    const T TOL = static_cast<T>(STAT_DIST_PROB_TOL_NUM) /
                  static_cast<T>(STAT_DIST_PROB_TOL_DEN);

    /*
     *            x - mu            sqrt(2) * (x - mu)
     *   z = -----------------  =  --------------------
     *        sigma * sqrt(2)            2 * sigma
     */

    const T z = static_cast<T>(MATH_CONST_SQRT_INV_2) * ( x - mu ) / sigma;

    /*
     * Calculate the return value:
     *
     *   cdf = 0.5 * (1 + erf(z)) = 0.5 * erfc(-z)
     */

    const T cdf = math::SpecFun::erfc<T>(-z, TOL) / static_cast<T>(2);

    // the return value depends on 'lowerTail':
    return ( true==lowerTail ? cdf : static_cast<T>(1)-cdf );
}

/**
 * Quantile function for the specified normal distribution.
 *
 * If 'lowerTail' equals true, it returns such 'x' that P(t<x) = p
 * If 'lowerTail' equals false, it returns such 'x' that P(t>x) = p
 *
 * @param p - probability (must be greater than 0 and less than 1)
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 * @param lowerTail - if true, returns q(t<x), otherwise q(t>x) (default: true)
 *
 * @return x: P(t<x) if 'lowerTail' equals true, x: P(t>x) if 'lowerTail' equals false
 *
 * @throw StatisticsException if either 'sigma' or 'p' is invalid
 */
template <class T>
T math::NormalDist::quant(
      const T& p,
      const T& mu,
      const T& sigma,
      bool lowerTail
    ) throw (math::StatisticsException)
{
    // sanity check
    math::NormalDist::__private::__checkSigma<T>(sigma);
    if ( p<=static_cast<T>(0) || p>=static_cast<T>(1) )
    {
        throw math::StatisticsException(math::StatisticsException::INVALID_PROBABILTY);
    }

    /*
     * Quantile is a value of 'x' that solves the nonlinear equation:
     *
     *   cdf(x) = p
     *
     * If the cumulative density function is expressed as:
     *
     *                          1         /        x - mu       \
     *   cdf(x,mu,sigma) = p = --- * erfc | - ----------------- |
     *                          2         \    sigma * sqrt(2)  /
     *
     * the following expression for 'x' can be derived quickly:
     *
     *   x = mu - sqrt(2) * sigma * erfcInv(2 * p)
     */

    try
    {
        // The actual probability in the expressions above depends on 'lowerTail':
        const T P = (true==lowerTail ? p : static_cast<T>(1)-p);

        // Tolerance for the algorithm that evaluates erfcInv():)
        const T TOL = static_cast<T>(STAT_DIST_PROB_TOL_NUM) /
                      static_cast<T>(STAT_DIST_PROB_TOL_DEN);

        return mu - math::SpecFun::erfcInv<T>(static_cast<T>(2) * P, TOL) *
                    sigma * static_cast<T>(MATH_CONST_SQRT_2);
    }
    catch ( math::SpecFunException& spex )
    {
        /*
         * The validity of 'p' is checked beforehand.
         * Although very unlikely, it is theoretically possible that
         * the algorithm to evaluate erfcInv will not converge.
         */
        throw math::StatisticsException(math::StatisticsException::OPERATION_FAILED);
    }
}
<commit_msg>cosmetic correction<commit_after>/*
Copyright 2014, Jernej Kovacic

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

   http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

/**
 * @file
 * @author Jernej Kovacic
 *
 * Implementation of functions within the namespace NormalDist
 * that perform various normal distribution related operations,
 * such as calculation of upper and lower tail probabilities and
 * quantiles, calculation of z statistics, probability
 * distribution function, etc.
 */

/*
 * More details about the normal distribution:
 * https://en.wikipedia.org/wiki/Normal_distribution
 */

// No #include "NormalDistGeneric.hpp" !!!
#include <cmath>
#include <algorithm>

#include "../settings/stat_settings.h"

#include "util/math_constant.h"
#include "util/NumericUtil.hpp"
#include "specfun/SpecFunGeneric.hpp"
#include "exception/SpecFunException.hpp"
#include "exception/StatisticsException.hpp"

namespace math {  namespace NormalDist {  namespace __private
{

/*
 * Checks the validity of the given standard deviation.
 * It must be strictly greater than zero.
 *
 * @param sigma - standard deviation to check
 *
 * @throw StatisticsException if 'sigma' is not valid.
 */
template <class T>
void __checkSigma(const T& sigma) throw (math::StatisticsException)
{
    if ( sigma < math::NumericUtil::getEPS<T>() )
    {
        throw math::StatisticsException(math::StatisticsException::INVALID_STDEV);
    }
}

}}}  // namespace math::NormalDist::__private

/**
 * Obtains the z-statistics (a.k.a. standard score) of 'x', i.e.
 * the distance of 'x' from the mean, expressed in number of
 * standard deviations.
 *
 * @param x - value to be calculated its z-statistics
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 *
 * @return z statistics of 'x' for the given normal distribution parameters
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::getZ(
          const T& x,
          const T& mu,
          const T& sigma
        ) throw (math::StatisticsException)
{
    /*
     *
     *         x - mu
     *   z = -----------
     *         sigma
     */

    // sanity check:
    math::NormalDist::__private::__checkSigma<T>(sigma);

    return (x - mu) / sigma;
}

/**
 * Converts z-statistics (a.k.a standard score) back to the
 * original value for the normal distribution with specified
 * parameters.
 *
 * @param z - z-statistics to be converted
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 *
 * @return x value within the normal distribution
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::getX(
          const T& z,
          const T& mu,
          const T& sigma
        ) throw (math::StatisticsException)
{
    /*
     * x = mu + z * sigma
     */

    // sanity check:
	math::NormalDist::__private::__checkSigma<T>(sigma);

    return mu + z * sigma;
}

/**
 * Value of the normal distribution's probability distribution
 * function (pdf) for the given 'x'.
 *
 * @param x - value to be calculated its probability distribution function
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 *
 * @return pdf(x, mu, sigma)
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::pdf(
      const T& x,
      const T& mu,
      const T& sigma
    ) throw (math::StatisticsException)
{
    /*
     * Probability density function of the normal distribution:
     *
     *                            2
     *                    (x - mu)
     *                - --------------
     *                             2
     *                    2 * sigma
     *              e
     *   pdf =   -----------------------
     *                        ------+
     *              sigma * \/ 2*pi
     *
     */

    // sanity check:
    math::NormalDist::__private::__checkSigma<T>(sigma);

    const T z = (x - mu) / sigma;
    return static_cast<T>(MATH_CONST_SQRT_INV_2_PI) *
           std::exp( -z*z / static_cast<T>(2) ) / sigma;
}

/**
 * Probability in the normal distribution with specified
 * parameters  that 'x' is greater than 'a' and less  than 'b'
 * (or vice versa if b<a).
 *
 * @note 'a' and 'b' are interchangeable, the result's sign will
 *       not change in this case.
 *
 * @param a - lower limit of the interval
 * @param b - upper limit of the interval
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 *
 * @return P(a<x<b) or P(b<x<a)
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::probInt(
      const T& a,
      const T& b,
      const T& mu,
      const T& sigma
    ) throw (math::StatisticsException)
{
    /*
     *              b
     *              /
     *   P(a<x<b) = | pdf(t) dt  =  cdf(b) - cdf(a)
     *              /
     *              a
     */

    // sanity check:
    math::NormalDist::__private::__checkSigma<T>(sigma);

    const T from = std::min(a, b);
    const T to = std::max(a, b);

    return math::NormalDist::prob<T>(to, mu, sigma, true) -
           math::NormalDist::prob<T>(from, mu, sigma, true);
}

/**
 * Probability that a value is greater or smaller (depending on 'lowerTail')
 * than the given value 'x' for the specified normal distribution.
 *
 * @param x - value
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 * @param lowerTail - if true, returns P(t<x), otherwise P(t>x) (default: true)
 *
 * @return P(t<x) if 'lowerTail' equals true, P(t>x) if 'lowerTail' equals false
 *
 * @throw StatisticsException if the standard deviation is invalid
 */
template <class T>
T math::NormalDist::prob(
      const T& x,
      const T& mu,
      const T& sigma,
      bool lowerTail
    ) throw (math::StatisticsException)
{
    /*
     * The cdf represents probability that a value from the normal
     * distribution is smaller than a specified value 'x' and can be
     * expressed as:
     *
     *                     x                   x
     *                     /              1    /
     *   cdf(x) = P(t<x) = | pdf(t) dt = --- + | pdf(t) dt
     *                     /              2    /
     *                   -inf                 mu
     *
     * One approach to calculate this would be numerical integration,
     * however there are more efficient methods available.
     *
     * As evident from:
     * https://en.wikipedia.org/wiki/Normal_distribution
     * cdf can be further expressed as:
     *
     *                +-                             -+
     *             1  |         /      x - mu       \ |
     *   cdf(x) = --- | 1 + erf | ----------------- | | =
     *             2  |         \  sigma * sqrt(2)  / |
     *                +-                             -+
     *
     *             1         /        x - mu       \
     *          = --- * erfc | - ----------------- |
     *             2         \    sigma * sqrt(2)  /
     *
     * where 'erf' is the so called error function, implemented
     * in the namespace math::SpecFun.
     *
     * For the upper tail probability ( P(t>x) ) just return the complement
     * of the lower tail probability: 1 - cdf(x)
     */

    // sanity check
    math::NormalDist::__private::__checkSigma<T>(sigma);

    // Tolerance for the last Taylor series term
    const T TOL = static_cast<T>(STAT_DIST_PROB_TOL_NUM) /
                  static_cast<T>(STAT_DIST_PROB_TOL_DEN);

    /*
     *            x - mu            sqrt(2) * (x - mu)
     *   z = -----------------  =  --------------------
     *        sigma * sqrt(2)            2 * sigma
     */

    const T z = static_cast<T>(MATH_CONST_SQRT_INV_2) * ( x - mu ) / sigma;

    /*
     * Calculate the return value:
     *
     *   cdf = 0.5 * (1 + erf(z)) = 0.5 * erfc(-z)
     */

    const T cdf = math::SpecFun::erfc<T>(-z, TOL) / static_cast<T>(2);

    // the return value depends on 'lowerTail':
    return ( true==lowerTail ? cdf : static_cast<T>(1)-cdf );
}

/**
 * Quantile function for the specified normal distribution.
 *
 * If 'lowerTail' equals true, it returns such 'x' that P(t<x) = p
 * If 'lowerTail' equals false, it returns such 'x' that P(t>x) = p
 *
 * @param p - probability (must be greater than 0 and less than 1)
 * @param mu - normal distribution's mean value (default: 0)
 * @param sigma - normal distribution's standard deviation (default: 1)
 * @param lowerTail - if true, returns q(t<x), otherwise q(t>x) (default: true)
 *
 * @return x: P(t<x) if 'lowerTail' equals true, x: P(t>x) if 'lowerTail' equals false
 *
 * @throw StatisticsException if either 'sigma' or 'p' is invalid
 */
template <class T>
T math::NormalDist::quant(
      const T& p,
      const T& mu,
      const T& sigma,
      bool lowerTail
    ) throw (math::StatisticsException)
{
    // sanity check
    math::NormalDist::__private::__checkSigma<T>(sigma);
    if ( p<=static_cast<T>(0) || p>=static_cast<T>(1) )
    {
        throw math::StatisticsException(math::StatisticsException::INVALID_PROBABILTY);
    }

    /*
     * Quantile is a value of 'x' that solves the nonlinear equation:
     *
     *   cdf(x) = p
     *
     * If the cumulative density function is expressed as:
     *
     *                          1         /        x - mu       \
     *   cdf(x,mu,sigma) = p = --- * erfc | - ----------------- |
     *                          2         \    sigma * sqrt(2)  /
     *
     * the following expression for 'x' can be derived quickly:
     *
     *   x = mu - sqrt(2) * sigma * erfcInv(2 * p)
     */

    try
    {
        // The actual probability in the expressions above depends on 'lowerTail':
        const T P = (true==lowerTail ? p : static_cast<T>(1)-p);

        // Tolerance for the algorithm that evaluates erfcInv():)
        const T TOL = static_cast<T>(STAT_DIST_PROB_TOL_NUM) /
                      static_cast<T>(STAT_DIST_PROB_TOL_DEN);

        return mu - math::SpecFun::erfcInv<T>(static_cast<T>(2) * P, TOL) *
                    sigma * static_cast<T>(MATH_CONST_SQRT_2);
    }
    catch ( math::SpecFunException& spex )
    {
        /*
         * The validity of 'p' is checked beforehand.
         * Although very unlikely, it is theoretically possible that
         * the algorithm to evaluate erfcInv will not converge.
         */
        throw math::StatisticsException(math::StatisticsException::OPERATION_FAILED);
    }
}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <stan/math/fwd/core/fvar.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/prim/scal/meta/broadcast_array.hpp>
#include <vector>

TEST(foo, bar) {
  using stan::math::fvar;
  using stan::math::internal::broadcast_array;
  using stan::math::var;

  fvar<var> fv(1.0, 2.1);
  broadcast_array<fvar<var> > ba(fv);
  EXPECT_EQ(1.0, ba[0].val_.vi_->val_);
  EXPECT_EQ(1.0, ba[2].val_.vi_->val_);

  double two = 2.0;
  broadcast_array<double> ba2(two);
  std::vector<double> vd = {{1.0, 2.0}};
  ba2 = vd;
  EXPECT_EQ(1.0, ba2[0]);
}
<commit_msg>add init of AD stack include<commit_after>#include <gtest/gtest.h>
#include <stan/math/fwd/core/fvar.hpp>
#include <stan/math/rev/core/var.hpp>
#include <stan/math/rev/core/init_chainablestack.hpp>
#include <stan/math/prim/scal/meta/broadcast_array.hpp>
#include <vector>

TEST(foo, bar) {
  using stan::math::fvar;
  using stan::math::internal::broadcast_array;
  using stan::math::var;

  fvar<var> fv(1.0, 2.1);
  broadcast_array<fvar<var> > ba(fv);
  EXPECT_EQ(1.0, ba[0].val_.vi_->val_);
  EXPECT_EQ(1.0, ba[2].val_.vi_->val_);

  double two = 2.0;
  broadcast_array<double> ba2(two);
  std::vector<double> vd = {{1.0, 2.0}};
  ba2 = vd;
  EXPECT_EQ(1.0, ba2[0]);
}
<|endoftext|>


<commit_before>#include "output.hpp"

#include "config.hpp"

#include <boost/assert.hpp>
#include <boost/filesystem.hpp>

#include <climits>
#include <utility>

using namespace synth;

bool Markup::empty() const
{
    return beginOffset == endOffset
        || (attrs == TokenAttributes::none && !isRef());
}

fs::path HighlightedFile::dstPath() const
{
    fs::path r = inOutDir->second / fname;
    r += ".html";
    return r;
}

static char const* getTokenKindCssClass(TokenAttributes attrs)
{
    // These CSS classes are the ones Pygments uses.
    using Tk = TokenAttributes;
    SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
    switch(attrs & Tk::maskKind) {
        case Tk::attr: return "nd"; // Name.Decorator
        case Tk::cmmt: return "c"; // Comment
        case Tk::constant: return "no"; // Name.Constant
        case Tk::func: return "nf"; // Name.Function
        case Tk::kw: return "k"; // Keyword
        case Tk::kwDecl: return "kd"; // Keyword.Declaration
        case Tk::lbl: return "nl"; // Name.Label
        case Tk::lit: return "l"; // Literal
        case Tk::litChr: return "sc"; // String.Char
        case Tk::litKw: return "kc"; // Keyword.Constant
        case Tk::litNum: return "m"; // Number
        case Tk::litNumFlt: return "mf"; // Number.Float
        case Tk::litNumIntBin: return "mb"; // Number.Binary
        case Tk::litNumIntDecLong: return "ml"; // Number.Integer.Long
        case Tk::litNumIntHex: return "mh"; // Number.Hex
        case Tk::litNumIntOct: return "mo"; // Number.Oct
        case Tk::litStr: return "s"; // String
        case Tk::namesp: return "nn"; // Name.Namespace
        case Tk::op: return "o"; // Operator
        case Tk::opWord: return "ow"; // Operator.Word
        case Tk::pre: return "cp"; // Comment.Preproc
        case Tk::preIncludeFile: return "cpf"; // Comment.PreprocFile
        case Tk::punct: return "p"; // Punctuation
        case Tk::ty: return "nc"; // Name.Class
        case Tk::tyBuiltin: return "kt"; // Keyword.Type
        case Tk::varGlobal: return "vg"; // Name.Variable.Global
        case Tk::varLocal: return "nv"; // Name.Variable
        case Tk::varNonstaticMember: return "vi"; // Name.Variable.Instance
        case Tk::varStaticMember: return "vc"; // Name.Variable.Class
        case Tk::none: return "";

        default:
            assert(false && "Unexpected token kind!");
            return "";
    }
    SYNTH_DISCLANGWARN_END
}

static void writeCssClasses(TokenAttributes attrs, std::ostream& out)
{
    if ((attrs & TokenAttributes::flagDef) != TokenAttributes::none)
        out << "def ";
    if ((attrs & TokenAttributes::flagDecl) != TokenAttributes::none)
        out << "decl ";
    out << getTokenKindCssClass(attrs);
}

// return: The written tag was a reference.
static bool writeBeginTag(
    Markup const& m,
    fs::path const& outPath,
    MultiTuProcessor& multiTuProcessor,
    std::ostream& out)
{
    std::string href = m.isRef()
        ? m.refd(outPath, multiTuProcessor) : std::string();

    if (href.empty() && m.attrs == TokenAttributes::none)
        return false;

    out << '<';

    if (href.empty()) {
        out << "span";
    } else {
        out << "a href=\"" << href << "\" ";
    }

    if (m.attrs != TokenAttributes::none) {
        out << "class=\"";
        writeCssClasses(m.attrs, out);
        out << "\" ";
    }
    out << '>';

    return !href.empty();
}

namespace {

struct MarkupInfo {
    Markup const* markup;
    bool wasRef;
};

struct OutputState {
    std::istream& in;
    std::ostream& out;
    unsigned lineno;
    std::vector<MarkupInfo> const& activeTags;
    fs::path const& outPath;
    MultiTuProcessor& multiTuProcessor;
};

} // anonymous namespace

static void writeEndTag(MarkupInfo const& mi, std::ostream& out)
{
    if (mi.wasRef)
        out << "";
    else if (mi.markup->attrs != TokenAttributes::none)
        out << "";
}

static void writeAllEnds(
    std::ostream& out, std::vector<MarkupInfo> const& activeTags)
{

    auto rit = activeTags.rbegin();
    auto rend = activeTags.rend();
    for (; rit != rend; ++rit)
        writeEndTag(*rit, out);
}

static bool copyWithLinenosUntil(OutputState& state, unsigned offset)
{
    if (state.lineno == 0) {
        ++state.lineno;
        state.out << "";
    }

    while (state.in && state.in.tellg() < offset) {
        int ch = state.in.get();
        if (ch == std::istream::traits_type::eof()) {
            state.out << "\n"; // end tag for lineno.
            return false;
        } else {
            switch (ch) {
                case '\n': {
                    writeAllEnds(state.out, state.activeTags);
                    ++state.lineno;
                    state.out
                        << "\n<span id=\"L"
                        << state.lineno
                        << "\" class=\"Ln\">";

                    for (auto const& mi : state.activeTags) {
                        writeBeginTag(
                            *mi.markup,
                            state.outPath,
                            state.multiTuProcessor,
                            state.out);
                    }
                } break;

                case '<':
                    state.out << "<";
                    break;
                case '>':
                    state.out << ">";
                    break;
                case '&':
                    state.out << "&";
                    break;
                case '\r':
                    // Discard.
                    break;
                default:
                    state.out.put(static_cast<char>(ch));
                    break;
            }
        }
    }
    return true;
}

static void copyWithLinenosUntilNoEof(OutputState& state, unsigned offset)
{
    bool eof = !copyWithLinenosUntil(state, offset);
    if (eof) {
        throw std::runtime_error(
            "unexpected EOF in input source " + state.outPath.string()
            + " at line " + std::to_string(state.lineno));
    }
}

void HighlightedFile::writeTo(
    std::ostream& out, MultiTuProcessor& multiTuProcessor)
{
    // ORDER BY beginOffset ASC, endOffset DESC
    std::sort(
        markups.begin(), markups.end(),
        [] (Markup const& lhs, Markup const& rhs) {
            return lhs.beginOffset != rhs.beginOffset
                ? lhs.beginOffset < rhs.beginOffset
                : lhs.endOffset > rhs.endOffset;
        });

    fs::path outPath = dstPath();
    fs::ifstream in(srcPath(), std::ios::binary);
    if (!in) {
        throw std::runtime_error(
            "Could not reopen source " + srcPath().string());
    }
    std::vector<MarkupInfo> activeTags;
    OutputState state {in, out, 0, activeTags, outPath, multiTuProcessor};
    for (auto const& m : markups) {
        while (!activeTags.empty()
            && m.beginOffset >= activeTags.back().markup->endOffset
        ) {
            MarkupInfo const& miEnd = activeTags.back();
            copyWithLinenosUntilNoEof(state, miEnd.markup->endOffset);
            writeEndTag(miEnd, out);
            activeTags.pop_back();
        }

        copyWithLinenosUntilNoEof(state, m.beginOffset);
        bool wasRef = writeBeginTag(
            m, state.outPath, state.multiTuProcessor, out);
        activeTags.push_back({ &m, wasRef });
    }
    BOOST_VERIFY(!copyWithLinenosUntil(state, UINT_MAX));
    writeAllEnds(out, activeTags);
}
<commit_msg>output: Fix writing of final end tags.<commit_after>#include "output.hpp"

#include "config.hpp"

#include <boost/assert.hpp>
#include <boost/filesystem.hpp>

#include <climits>
#include <utility>

using namespace synth;

bool Markup::empty() const
{
    return beginOffset == endOffset
        || (attrs == TokenAttributes::none && !isRef());
}

fs::path HighlightedFile::dstPath() const
{
    fs::path r = inOutDir->second / fname;
    r += ".html";
    return r;
}

static char const* getTokenKindCssClass(TokenAttributes attrs)
{
    // These CSS classes are the ones Pygments uses.
    using Tk = TokenAttributes;
    SYNTH_DISCLANGWARN_BEGIN("-Wswitch-enum")
    switch(attrs & Tk::maskKind) {
        case Tk::attr: return "nd"; // Name.Decorator
        case Tk::cmmt: return "c"; // Comment
        case Tk::constant: return "no"; // Name.Constant
        case Tk::func: return "nf"; // Name.Function
        case Tk::kw: return "k"; // Keyword
        case Tk::kwDecl: return "kd"; // Keyword.Declaration
        case Tk::lbl: return "nl"; // Name.Label
        case Tk::lit: return "l"; // Literal
        case Tk::litChr: return "sc"; // String.Char
        case Tk::litKw: return "kc"; // Keyword.Constant
        case Tk::litNum: return "m"; // Number
        case Tk::litNumFlt: return "mf"; // Number.Float
        case Tk::litNumIntBin: return "mb"; // Number.Binary
        case Tk::litNumIntDecLong: return "ml"; // Number.Integer.Long
        case Tk::litNumIntHex: return "mh"; // Number.Hex
        case Tk::litNumIntOct: return "mo"; // Number.Oct
        case Tk::litStr: return "s"; // String
        case Tk::namesp: return "nn"; // Name.Namespace
        case Tk::op: return "o"; // Operator
        case Tk::opWord: return "ow"; // Operator.Word
        case Tk::pre: return "cp"; // Comment.Preproc
        case Tk::preIncludeFile: return "cpf"; // Comment.PreprocFile
        case Tk::punct: return "p"; // Punctuation
        case Tk::ty: return "nc"; // Name.Class
        case Tk::tyBuiltin: return "kt"; // Keyword.Type
        case Tk::varGlobal: return "vg"; // Name.Variable.Global
        case Tk::varLocal: return "nv"; // Name.Variable
        case Tk::varNonstaticMember: return "vi"; // Name.Variable.Instance
        case Tk::varStaticMember: return "vc"; // Name.Variable.Class
        case Tk::none: return "";

        default:
            assert(false && "Unexpected token kind!");
            return "";
    }
    SYNTH_DISCLANGWARN_END
}

static void writeCssClasses(TokenAttributes attrs, std::ostream& out)
{
    if ((attrs & TokenAttributes::flagDef) != TokenAttributes::none)
        out << "def ";
    if ((attrs & TokenAttributes::flagDecl) != TokenAttributes::none)
        out << "decl ";
    out << getTokenKindCssClass(attrs);
}

// return: The written tag was a reference.
static bool writeBeginTag(
    Markup const& m,
    fs::path const& outPath,
    MultiTuProcessor& multiTuProcessor,
    std::ostream& out)
{
    std::string href = m.isRef()
        ? m.refd(outPath, multiTuProcessor) : std::string();

    if (href.empty() && m.attrs == TokenAttributes::none)
        return false;

    out << '<';

    if (href.empty()) {
        out << "span";
    } else {
        out << "a href=\"" << href << "\" ";
    }

    if (m.attrs != TokenAttributes::none) {
        out << "class=\"";
        writeCssClasses(m.attrs, out);
        out << "\" ";
    }
    out << '>';

    return !href.empty();
}

namespace {

struct MarkupInfo {
    Markup const* markup;
    bool wasRef;
};

struct OutputState {
    std::istream& in;
    std::ostream& out;
    unsigned lineno;
    std::vector<MarkupInfo> const& activeTags;
    fs::path const& outPath;
    MultiTuProcessor& multiTuProcessor;
};

} // anonymous namespace

static void writeEndTag(MarkupInfo const& mi, std::ostream& out)
{
    if (mi.wasRef)
        out << "";
    else if (mi.markup->attrs != TokenAttributes::none)
        out << "";
}

static void writeAllEnds(
    std::ostream& out, std::vector<MarkupInfo> const& activeTags)
{

    auto rit = activeTags.rbegin();
    auto rend = activeTags.rend();
    for (; rit != rend; ++rit)
        writeEndTag(*rit, out);
}

static bool copyWithLinenosUntil(OutputState& state, unsigned offset)
{
    if (state.lineno == 0) {
        ++state.lineno;
        state.out << "";
    }

    while (state.in && state.in.tellg() < offset) {
        int ch = state.in.get();
        if (ch == std::istream::traits_type::eof()) {
            state.out << "\n"; // end tag for lineno.
            return false;
        } else {
            switch (ch) {
                case '\n': {
                    writeAllEnds(state.out, state.activeTags);
                    ++state.lineno;
                    state.out
                        << "\n<span id=\"L"
                        << state.lineno
                        << "\" class=\"Ln\">";

                    for (auto const& mi : state.activeTags) {
                        writeBeginTag(
                            *mi.markup,
                            state.outPath,
                            state.multiTuProcessor,
                            state.out);
                    }
                } break;

                case '<':
                    state.out << "<";
                    break;
                case '>':
                    state.out << ">";
                    break;
                case '&':
                    state.out << "&";
                    break;
                case '\r':
                    // Discard.
                    break;
                default:
                    state.out.put(static_cast<char>(ch));
                    break;
            }
        }
    }
    return true;
}

static void copyWithLinenosUntilNoEof(OutputState& state, unsigned offset)
{
    bool eof = !copyWithLinenosUntil(state, offset);
    if (eof) {
        throw std::runtime_error(
            "unexpected EOF in input source " + state.outPath.string()
            + " at line " + std::to_string(state.lineno));
    }
}

void HighlightedFile::writeTo(
    std::ostream& out, MultiTuProcessor& multiTuProcessor)
{
    // ORDER BY beginOffset ASC, endOffset DESC
    std::sort(
        markups.begin(), markups.end(),
        [] (Markup const& lhs, Markup const& rhs) {
            return lhs.beginOffset != rhs.beginOffset
                ? lhs.beginOffset < rhs.beginOffset
                : lhs.endOffset > rhs.endOffset;
        });

    fs::path outPath = dstPath();
    fs::ifstream in(srcPath(), std::ios::binary);
    if (!in) {
        throw std::runtime_error(
            "Could not reopen source " + srcPath().string());
    }
    std::vector<MarkupInfo> activeTags;
    OutputState state {in, out, 0, activeTags, outPath, multiTuProcessor};
    for (auto const& m : markups) {
        while (!activeTags.empty()
            && m.beginOffset >= activeTags.back().markup->endOffset
        ) {
            MarkupInfo const& miEnd = activeTags.back();
            copyWithLinenosUntilNoEof(state, miEnd.markup->endOffset);
            writeEndTag(miEnd, out);
            activeTags.pop_back();
        }

        copyWithLinenosUntilNoEof(state, m.beginOffset);
        bool wasRef = writeBeginTag(
            m, state.outPath, state.multiTuProcessor, out);
        activeTags.push_back({ &m, wasRef });
    }
    while (!activeTags.empty()) {
        copyWithLinenosUntilNoEof(state, activeTags.back().markup->endOffset);
        writeEndTag(activeTags.back(), out);
        activeTags.pop_back();
    }
    BOOST_VERIFY(!copyWithLinenosUntil(state, UINT_MAX));
}
<|endoftext|>


<commit_before>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2015                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_POLICY_WORK_STEALING_HPP
#define CAF_POLICY_WORK_STEALING_HPP

#include <deque>
#include <chrono>
#include <thread>
#include <random>
#include <cstddef>

#include "caf/resumable.hpp"

#include "caf/detail/double_ended_queue.hpp"

namespace caf {
namespace policy {

/// Implements scheduling of actors via work stealing. This implementation uses
/// two queues: a synchronized queue accessible by other threads and an internal
/// queue. Access to the synchronized queue is minimized.
/// The reasoning behind this design decision is that it
/// has been shown that stealing actually is very rare for most workloads [1].
/// Hence, implementations should focus on the performance in
/// the non-stealing case. For this reason, each worker has an exposed
/// job queue that can be accessed by the central scheduler instance as
/// well as other workers, but it also has a private job list it is
/// currently working on. To account for the load balancing aspect, each
/// worker makes sure that at least one job is left in its exposed queue
/// to allow other workers to steal it.
///
/// [1] http://dl.acm.org/citation.cfm?doid=2398857.2384639
///
/// @extends scheduler_policy
class work_stealing {
public:
  // A thead-safe queue implementation.
  using queue_type = detail::double_ended_queue<resumable>;

  // The coordinator has only a counter for round-robin enqueue to its workers.
  struct coordinator_data {
    std::atomic<size_t> next_worker;
    inline coordinator_data() : next_worker(0) {
      // nop
    }
  };

  // Holds job job queue of a worker and a random number generator.
  struct worker_data {
    // This queue is exposed to other workers that may attempt to steal jobs
    // from it and the central scheduling unit can push new jobs to the queue.
    queue_type queue;
    // needed by our engine
    std::random_device rdevice;
    // needed to generate pseudo random numbers
    std::default_random_engine rengine;
    // initialize random engine
    inline worker_data() : rdevice(), rengine(rdevice()) {
      // nop
    }
  };

  // Convenience function to access the data field.
  template <class WorkerOrCoordinator>
  static auto d(WorkerOrCoordinator* self) -> decltype(self->data()) {
    return self->data();
  }

  // Goes on a raid in quest for a shiny new job.
  template <class Worker>
  resumable* try_steal(Worker* self) {
    auto p = self->parent();
    if (p->num_workers() < 2) {
      // you can't steal from yourself, can you?
      return nullptr;
    }
    size_t victim;
    do {
      // roll the dice to pick a victim other than ourselves
      victim = d(self).rengine() % p->num_workers();
    }
    while (victim == self->id());
    // steal oldest element from the victim's queue
    return d(p->worker_by_id(victim)).queue.take_tail();
  }

  template <class Coordinator>
  void central_enqueue(Coordinator* self, resumable* job) {
    auto w = self->worker_by_id(d(self).next_worker++ % self->num_workers());
    w->external_enqueue(job);
  }

  template <class Worker>
  void external_enqueue(Worker* self, resumable* job) {
    d(self).queue.append(job);
  }

  template <class Worker>
  void internal_enqueue(Worker* self, resumable* job) {
    d(self).queue.prepend(job);
  }

  template <class Worker>
  void resume_job_later(Worker* self, resumable* job) {
    // job has voluntarily released the CPU to let others run instead
    // this means we are going to put this job to the very end of our queue
    d(self).queue.append(job);
  }

  template <class Worker>
  resumable* dequeue(Worker* self) {
    // we wait for new jobs by polling our external queue: first, we
    // assume an active work load on the machine and perform aggresive
    // polling, then we relax our polling a bit and wait 50 us between
    // dequeue attempts, finally we assume pretty much nothing is going
    // on and poll every 10 ms; this strategy strives to minimize the
    // downside of "busy waiting", which still performs much better than a
    // "signalizing" implementation based on mutexes and conition variables
    struct poll_strategy {
      size_t attempts;
      size_t step_size;
      size_t steal_interval;
      std::chrono::microseconds sleep_duration;
    };
    poll_strategy strategies[3] = {
      // aggressive polling  (100x) without sleep interval
      {100, 1, 10, std::chrono::microseconds{0}},
      // moderate polling (500x) with 50 us sleep interval
      {500, 1, 5,  std::chrono::microseconds{50}},
      // relaxed polling (infinite attempts) with 10 ms sleep interval
      {101, 0, 1,  std::chrono::microseconds{10000}}
    };
    resumable* job = nullptr;
    for (auto& strat : strategies) {
      for (size_t i = 0; i < strat.attempts; i += strat.step_size) {
        job = d(self).queue.take_head();
        if (job) {
          return job;
        }
        // try to steal every X poll attempts
        if ((i % strat.steal_interval) == 0) {
          job = try_steal(self);
          if (job) {
            return job;
          }
        }
        std::this_thread::sleep_for(strat.sleep_duration);
      }
    }
    // unreachable, because the last strategy loops
    // until a job has been dequeued
    return nullptr;
  }

  template <class Worker>
  void before_shutdown(Worker*) {
    // nop
  }

  template <class Worker>
  void before_resume(Worker*, resumable*) {
    // nop
  }

  template <class Worker>
  void after_resume(Worker*, resumable*) {
    // nop
  }

  template <class Worker>
  void after_completion(Worker*, resumable*) {
    // nop
  }

  template <class Worker, class UnaryFunction>
  void foreach_resumable(Worker* self, UnaryFunction f) {
    auto next = [&] { return d(self).queue.take_head(); };
    for (auto job = next(); job != nullptr; job = next()) {
      f(job);
    }
  }

  template <class Coordinator, class UnaryFunction>
  void foreach_central_resumable(Coordinator*, UnaryFunction) {
    // nop
  }
};

} // namespace policy
} // namespace caf

#endif // CAF_POLICY_WORK_STEALING_HPP
<commit_msg>Improve `policy::work_stealing::try_steal()`<commit_after>/******************************************************************************
 *                       ____    _    _____                                   *
 *                      / ___|  / \  |  ___|    C++                           *
 *                     | |     / _ \ | |_       Actor                         *
 *                     | |___ / ___ \|  _|      Framework                     *
 *                      \____/_/   \_|_|                                      *
 *                                                                            *
 * Copyright (C) 2011 - 2015                                                  *
 * Dominik Charousset <dominik.charousset (at) haw-hamburg.de>                *
 *                                                                            *
 * Distributed under the terms and conditions of the BSD 3-Clause License or  *
 * (at your option) under the terms and conditions of the Boost Software      *
 * License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE.       *
 *                                                                            *
 * If you did not receive a copy of the license files, see                    *
 * http://opensource.org/licenses/BSD-3-Clause and                            *
 * http://www.boost.org/LICENSE_1_0.txt.                                      *
 ******************************************************************************/

#ifndef CAF_POLICY_WORK_STEALING_HPP
#define CAF_POLICY_WORK_STEALING_HPP

#include <deque>
#include <chrono>
#include <thread>
#include <random>
#include <cstddef>

#include "caf/resumable.hpp"

#include "caf/detail/double_ended_queue.hpp"

namespace caf {
namespace policy {

/// Implements scheduling of actors via work stealing. This implementation uses
/// two queues: a synchronized queue accessible by other threads and an internal
/// queue. Access to the synchronized queue is minimized.
/// The reasoning behind this design decision is that it
/// has been shown that stealing actually is very rare for most workloads [1].
/// Hence, implementations should focus on the performance in
/// the non-stealing case. For this reason, each worker has an exposed
/// job queue that can be accessed by the central scheduler instance as
/// well as other workers, but it also has a private job list it is
/// currently working on. To account for the load balancing aspect, each
/// worker makes sure that at least one job is left in its exposed queue
/// to allow other workers to steal it.
///
/// [1] http://dl.acm.org/citation.cfm?doid=2398857.2384639
///
/// @extends scheduler_policy
class work_stealing {
public:
  // A thead-safe queue implementation.
  using queue_type = detail::double_ended_queue<resumable>;

  // The coordinator has only a counter for round-robin enqueue to its workers.
  struct coordinator_data {
    std::atomic<size_t> next_worker;
    inline coordinator_data() : next_worker(0) {
      // nop
    }
  };

  // Holds job job queue of a worker and a random number generator.
  struct worker_data {
    // This queue is exposed to other workers that may attempt to steal jobs
    // from it and the central scheduling unit can push new jobs to the queue.
    queue_type queue;
    // needed by our engine
    std::random_device rdevice;
    // needed to generate pseudo random numbers
    std::default_random_engine rengine;
    // initialize random engine
    inline worker_data() : rdevice(), rengine(rdevice()) {
      // nop
    }
  };

  // Convenience function to access the data field.
  template <class WorkerOrCoordinator>
  static auto d(WorkerOrCoordinator* self) -> decltype(self->data()) {
    return self->data();
  }

  // Goes on a raid in quest for a shiny new job.
  template <class Worker>
  resumable* try_steal(Worker* self) {
    auto p = self->parent();
    if (p->num_workers() < 2) {
      // you can't steal from yourself, can you?
      return nullptr;
    }
    // roll the dice to pick a victim other than ourselves
    size_t victim = d(self).rengine() % (p->num_workers() - 1);
    if (victim == self->id())
      victim = p->num_workers() - 1;
    // steal oldest element from the victim's queue
    return d(p->worker_by_id(victim)).queue.take_tail();
  }

  template <class Coordinator>
  void central_enqueue(Coordinator* self, resumable* job) {
    auto w = self->worker_by_id(d(self).next_worker++ % self->num_workers());
    w->external_enqueue(job);
  }

  template <class Worker>
  void external_enqueue(Worker* self, resumable* job) {
    d(self).queue.append(job);
  }

  template <class Worker>
  void internal_enqueue(Worker* self, resumable* job) {
    d(self).queue.prepend(job);
  }

  template <class Worker>
  void resume_job_later(Worker* self, resumable* job) {
    // job has voluntarily released the CPU to let others run instead
    // this means we are going to put this job to the very end of our queue
    d(self).queue.append(job);
  }

  template <class Worker>
  resumable* dequeue(Worker* self) {
    // we wait for new jobs by polling our external queue: first, we
    // assume an active work load on the machine and perform aggresive
    // polling, then we relax our polling a bit and wait 50 us between
    // dequeue attempts, finally we assume pretty much nothing is going
    // on and poll every 10 ms; this strategy strives to minimize the
    // downside of "busy waiting", which still performs much better than a
    // "signalizing" implementation based on mutexes and conition variables
    struct poll_strategy {
      size_t attempts;
      size_t step_size;
      size_t steal_interval;
      std::chrono::microseconds sleep_duration;
    };
    poll_strategy strategies[3] = {
      // aggressive polling  (100x) without sleep interval
      {100, 1, 10, std::chrono::microseconds{0}},
      // moderate polling (500x) with 50 us sleep interval
      {500, 1, 5,  std::chrono::microseconds{50}},
      // relaxed polling (infinite attempts) with 10 ms sleep interval
      {101, 0, 1,  std::chrono::microseconds{10000}}
    };
    resumable* job = nullptr;
    for (auto& strat : strategies) {
      for (size_t i = 0; i < strat.attempts; i += strat.step_size) {
        job = d(self).queue.take_head();
        if (job) {
          return job;
        }
        // try to steal every X poll attempts
        if ((i % strat.steal_interval) == 0) {
          job = try_steal(self);
          if (job) {
            return job;
          }
        }
        std::this_thread::sleep_for(strat.sleep_duration);
      }
    }
    // unreachable, because the last strategy loops
    // until a job has been dequeued
    return nullptr;
  }

  template <class Worker>
  void before_shutdown(Worker*) {
    // nop
  }

  template <class Worker>
  void before_resume(Worker*, resumable*) {
    // nop
  }

  template <class Worker>
  void after_resume(Worker*, resumable*) {
    // nop
  }

  template <class Worker>
  void after_completion(Worker*, resumable*) {
    // nop
  }

  template <class Worker, class UnaryFunction>
  void foreach_resumable(Worker* self, UnaryFunction f) {
    auto next = [&] { return d(self).queue.take_head(); };
    for (auto job = next(); job != nullptr; job = next()) {
      f(job);
    }
  }

  template <class Coordinator, class UnaryFunction>
  void foreach_central_resumable(Coordinator*, UnaryFunction) {
    // nop
  }
};

} // namespace policy
} // namespace caf

#endif // CAF_POLICY_WORK_STEALING_HPP
<|endoftext|>


<commit_before>#include "parser.h"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <streambuf>

using namespace std;

namespace gpr {

  template<typename T>
  struct parse_stream {
    size_t i;
    vector<T> s;

    template<typename R>
    parse_stream<T>(R v) : s(v.begin(), v.end()) {
      i = 0;
    }

    T next() {
      return s[i];
    }

    int chars_left() const {
      return i < s.size();
    }

    parse_stream<T>& operator++(int) {
      i++;
      return *this;
    }

    parse_stream<T>& operator--(int) {
      i--;
      return *this;
    }

    typename vector<T>::iterator end() {
      return s.end();
    }

    typename vector<T>::iterator begin() {
      return s.begin();
    }

    typename vector<T>::iterator remaining() {
      return s.begin() + i;
    }

  };

  typedef parse_stream<char> parse_state;

  void ignore_whitespace(parse_state& s) {
    while (s.chars_left() && (isspace(s.next()) || s.next() == '\r')) { s++; }
  }

  string string_remaining(parse_state& ps) {
    return string(ps.remaining(), ps.end());
  }

  void parse_char(char c, parse_state& s) {
    if (s.next() == c) {
      s++;
      return;
    }
    cout << "Cannot parse char " << c << " from string " << string_remaining(s) << endl;
    assert(false);
  }

  double parse_double(parse_state& s) {
    size_t j = s.i;
    double v = stod(string_remaining(s), &j);
    s.i += j;
    return v;
  }

  double parse_double(parse_stream<string>& s) {
    double v = stod(s.next());
    s++;
    return v;
  }

  int parse_int(parse_stream<string>& s) {
    int i = stoi(s.next());
    s++;
    return i;
  }

  int parse_int(parse_state& s) {
    size_t j = s.i;

    //cout << "Remaining = " << string_remaining(s) << endl;
    int v = stoi(string_remaining(s), &j);

    s.i += j;
    return v;
  }

  addr parse_address(char c, parse_stream<string>& s) {
    switch(c) {
    case 'X':
    case 'Y':
    case 'Z':
    case 'I':
    case 'J':
    case 'K':
    case 'F':
    case 'R':
    case 'Q':
    case 'S':
    case 'x':
    case 'y':
    case 'z':
    case 'i':
    case 'j':
    case 'k':
    case 'f':
    case 'r':
    case 's':
    case 'q':
    case 'E':
      return make_double_address(parse_double(s));
    case 'G':
    case 'H':
    case 'M':
    case 'N':
    case 'O':
    case 'T':
    case 'P':
    case 'D':
    case 'L':
    case 'g':
    case 'h':
    case 'm':
    case 'n':
    case 'o':
    case 't':
    case 'p':
    case 'd':
    case 'l':
      return make_int_address(parse_int(s));
    default:
      cout << "Invalid c = " << c << endl;
      cout << "Inavlid c as int = " << ((int) c) << endl;
      cout << "Is EOF? " << (((int) c) == EOF) << endl;
      assert(false);
    }
  }

  string parse_line_comment_with_delimiter(char sc, parse_state& s) {
    string text = "";
    while (s.chars_left() && s.next() != '\n') {
      text += s.next();
      s++;
    }

    return text;
  }

  string parse_comment_with_delimiters(char sc, char ec, parse_state& s) {
    int depth = 0;
    string text = "";
    do {
      if (s.next() == sc) { depth++; }
      else if (s.next() == ec) { depth--; }
      else {
	text += s.next();
      }
      s++;
    } while (s.chars_left() && depth > 0);

    return text;
  }

  string parse_comment_with_delimiters(string sc,
				       string ec,
				       parse_stream<string>& s) {
    int depth = 0;
    string text = "";
    do {
      if (s.next() == sc) { depth++; }
      else if (s.next() == ec) { depth--; }
      else {
	text += s.next();
      }
      s++;
    } while (s.chars_left() && depth > 0);

    return text;
  }

  chunk parse_word_address(parse_stream<string>& s) {
    assert(s.chars_left());
    assert(s.next().size() == 1);

    char c = s.next()[0];
    s++;

    cout << "value to be parsed in parse address = " << s.next() << endl;

    addr a = parse_address(c, s);
    return chunk(c, a);
  }

  chunk parse_chunk(parse_stream<string>& s) {
    assert(s.chars_left());

    if (s.next() == "[") {
      string cs = parse_comment_with_delimiters("[", "]", s);
      return chunk('[', ']', cs);
    } else if (s.next() == "(") {
      string cs = parse_comment_with_delimiters("(", ")", s);

      cout << "Parsed comment = " << cs << endl;
      cout << "Chars left ? " << s.chars_left() << endl;
      cout << "Next s = " << s.next() << endl;

      return chunk('(', ')', cs);

    } else if (s.next() == ";") {
      // s++;
      // string cs = parse_line_comment_with_delimiter(';', s);
      // return chunk(';', ';', cs);
      assert(false);
    } else {
      return parse_word_address(s);
    }

  }

  bool parse_slash(parse_state& s) {
    if (s.next() == '/') {
      s++;
      return true;
    }

    return false;
  }

  bool is_slash(const string& s) {
    if (s.size() != 1) { return false; }

    return s[0] == '/';
  }

  bool parse_slash(parse_stream<string>& s) {
    if (is_slash(s.next())) {
      s++;
      return true;
    }

    return false;
  }

  std::pair<bool, int> parse_line_number(parse_state& s) {
    if (s.next() == 'N') {
      s++;

      int ln = parse_int(s);

      return std::make_pair(true, ln);
    }
    return std::make_pair(false, -1);
  }

  std::pair<bool, int> parse_line_number(parse_stream<string>& s) {
    if (s.next() == "N") {
      s++;

      int ln = parse_int(s);

      return std::make_pair(true, ln);
    }
    return std::make_pair(false, -1);
  }

  block parse_tokens(const std::vector<string>& tokens) {
    cout << "Parsing tokens: ";
    for (auto& t : tokens) {
      cout << t << " ";
    }
    cout << endl;

    parse_stream<string> s(tokens);
    vector<chunk> chunks;
    bool is_slashed = parse_slash(s);

    std::pair<bool, int> line_no =
      parse_line_number(s);

    while (s.chars_left()) {
      chunk ch = parse_chunk(s);
      chunks.push_back(ch);
    }

    if (line_no.first) {
      return block(line_no.second, is_slashed, chunks);
    } else {
      return block(is_slashed, chunks);
    }

  }

  // block lex_gprog_line(const string& str) {
  //   parse_state s(str);

  //   vector<chunk> chunks;

  //   ignore_whitespace(s);

  //   bool is_slashed = parse_slash(s);

  //   ignore_whitespace(s);

  //   std::pair<bool, int> line_no =
  //     parse_line_number(s);

  //   while (s.chars_left()) {
  //     ignore_whitespace(s);
  //     if (!s.chars_left()) { break; }

  //     chunk ch = parse_chunk(s);
  //     chunks.push_back(ch);

  //   }

  //   if (line_no.first) {
  //     return block(line_no.second, is_slashed, chunks);
  //   } else {
  //     return block(is_slashed, chunks);
  //   }
  // }

  // vector<block> lex_gprog(const string& str) {
  //   vector<block> blocks;
  //   string::const_iterator line_start = str.begin();
  //   string::const_iterator line_end;

  //   while (line_start < str.end()) {
  //     line_end = find(line_start, str.end(), '\n');
  //     string line(line_start, line_end);
  //     if (line.size() > 0) {
  // 	block b = lex_gprog_line(line);
  // 	//if (b.size() > 0) {
  // 	  blocks.push_back(b);
  // 	  //}
  //     }
  //     line_start += line.size() + 1;
  //   }
  //   return blocks;
  // }

  vector<block> lex_gprog(const string& str) {
    vector<block> blocks;
    string::const_iterator line_start = str.begin();
    string::const_iterator line_end;

    while (line_start < str.end()) {
      line_end = find(line_start, str.end(), '\n');
      string line(line_start, line_end);
      cout << "Line to parse = " << line << endl;

      if (line.size() > 0) {
	vector<string> line_tokens = lex_block(line);
	block b = parse_tokens(line_tokens);
	blocks.push_back(b);
      }

      line_start += line.size() + 1;
    }
    return blocks;
  }

  gcode_program parse_gcode(const std::string& program_text) {
    auto blocks = lex_gprog(program_text);
    return gcode_program(blocks);
  }

  gcode_program parse_gcode_saving_block_text(const std::string& program_text) {
    auto blocks = lex_gprog(program_text);
    for (auto& b : blocks) {
      b.set_debug_text();
    }
    return gcode_program(blocks);
  }

  bool is_num_char(const char c) {
    return (isdigit(c) ||
	    (c == '.') ||
	    (c == '-'));
  }

  std::string digit_string(parse_state& s) {
    string num_str = "";

    while (s.chars_left() && is_num_char(s.next())) {
      num_str += s.next();
      s++;
    }

    return num_str;
  }

  std::string lex_token(parse_state& s) {
    assert(s.chars_left());

    char c = s.next();
    string next_token = "";

    if (is_num_char(c)) {
      return digit_string(s);
    }

    switch(c) {
    case '%':
      s++;
      return "%";
    case '/':
      s++;
      return "/";

    case '(':
      s++;
      return "(";

    case ')':
      s++;
      return ")";

    case '[':
      s++;
      return "[";

    case ']':
      s++;
      return "]";

    // case 'X':
    // case 'Y':
    // case 'Z':
    // case 'I':
    // case 'J':
    // case 'K':
    // case 'F':
    // case 'R':
    // case 'Q':
    // case 'S':
    // case 'x':
    // case 'y':
    // case 'z':
    // case 'i':
    // case 'j':
    // case 'k':
    // case 'f':
    // case 'r':
    // case 's':
    // case 'q':
    // case 'E':
    // case 'G':
    // case 'H':
    // case 'M':
    // case 'N':
    // case 'O':
    // case 'T':
    // case 'P':
    // case 'D':
    // case 'L':
    // case 'g':
    // case 'h':
    // case 'm':
    // case 'n':
    // case 'o':
    // case 't':
    // case 'p':
    // case 'd':
    // case 'l':
    default:
      next_token += c;
      s++;
      return next_token;
      //    default:
      // cout << "Invalid c = " << c << endl;
      // cout << "Inavlid c as int = " << ((int) c) << endl;
      // cout << "Is EOF? " << (((int) c) == EOF) << endl;
      // assert(false);
    }

  }

  std::vector<std::string> lex_block(const std::string& block_text) {
    cout << "Lexing: " << block_text << endl;
    parse_state s(block_text);

    vector<string> tokens;

    ignore_whitespace(s);

    while (s.chars_left()) {
      cout << "Remaining string = " << string_remaining(s) << endl;
      ignore_whitespace(s);

      if (s.chars_left()) {
	string token = lex_token(s);
	cout << "Pushing back token = " << token << endl;
	tokens.push_back(token);
      }
    }

    return tokens;
  }

}
<commit_msg>Need to lex comments all at once<commit_after>#include "parser.h"

#include <algorithm>
#include <fstream>
#include <iostream>
#include <sstream>
#include <streambuf>

using namespace std;

namespace gpr {

  template<typename T>
  struct parse_stream {
    size_t i;
    vector<T> s;

    template<typename R>
    parse_stream<T>(R v) : s(v.begin(), v.end()) {
      i = 0;
    }

    T next() {
      return s[i];
    }

    int chars_left() const {
      return i < s.size();
    }

    parse_stream<T>& operator++(int) {
      i++;
      return *this;
    }

    parse_stream<T>& operator--(int) {
      i--;
      return *this;
    }

    typename vector<T>::iterator end() {
      return s.end();
    }

    typename vector<T>::iterator begin() {
      return s.begin();
    }

    typename vector<T>::iterator remaining() {
      return s.begin() + i;
    }

  };

  typedef parse_stream<char> parse_state;

  void ignore_whitespace(parse_state& s) {
    while (s.chars_left() && (isspace(s.next()) || s.next() == '\r')) { s++; }
  }

  string string_remaining(parse_state& ps) {
    return string(ps.remaining(), ps.end());
  }

  void parse_char(char c, parse_state& s) {
    if (s.next() == c) {
      s++;
      return;
    }
    cout << "Cannot parse char " << c << " from string " << string_remaining(s) << endl;
    assert(false);
  }

  double parse_double(parse_state& s) {
    size_t j = s.i;
    double v = stod(string_remaining(s), &j);
    s.i += j;
    return v;
  }

  double parse_double(parse_stream<string>& s) {
    double v = stod(s.next());
    s++;
    return v;
  }

  int parse_int(parse_stream<string>& s) {
    int i = stoi(s.next());
    s++;
    return i;
  }

  int parse_int(parse_state& s) {
    size_t j = s.i;

    //cout << "Remaining = " << string_remaining(s) << endl;
    int v = stoi(string_remaining(s), &j);

    s.i += j;
    return v;
  }

  addr parse_address(char c, parse_stream<string>& s) {
    switch(c) {
    case 'X':
    case 'Y':
    case 'Z':
    case 'I':
    case 'J':
    case 'K':
    case 'F':
    case 'R':
    case 'Q':
    case 'S':
    case 'x':
    case 'y':
    case 'z':
    case 'i':
    case 'j':
    case 'k':
    case 'f':
    case 'r':
    case 's':
    case 'q':
    case 'E':
      return make_double_address(parse_double(s));
    case 'G':
    case 'H':
    case 'M':
    case 'N':
    case 'O':
    case 'T':
    case 'P':
    case 'D':
    case 'L':
    case 'g':
    case 'h':
    case 'm':
    case 'n':
    case 'o':
    case 't':
    case 'p':
    case 'd':
    case 'l':
      return make_int_address(parse_int(s));
    default:
      cout << "Invalid c = " << c << endl;
      cout << "Inavlid c as int = " << ((int) c) << endl;
      cout << "Is EOF? " << (((int) c) == EOF) << endl;
      assert(false);
    }
  }

  string parse_line_comment_with_delimiter(string sc, parse_stream<string>& s) {
    string text = "";
    while (s.chars_left()) {
      text += s.next();
      s++;
    }

    return text;
  }

  string parse_comment_with_delimiters(char sc, char ec, parse_state& s) {
    int depth = 0;
    string text = "";
    do {
      if (s.next() == sc) { depth++; }
      else if (s.next() == ec) { depth--; }
      else {
	text += s.next();
      }
      s++;
    } while (s.chars_left() && depth > 0);

    return text;
  }

  string parse_comment_with_delimiters(string sc,
				       string ec,
				       parse_stream<string>& s) {
    int depth = 0;
    string text = "";
    do {
      if (s.next() == sc) { depth++; }
      else if (s.next() == ec) { depth--; }
      else {
	text += s.next();
      }
      s++;
    } while (s.chars_left() && depth > 0);

    return text;
  }

  chunk parse_word_address(parse_stream<string>& s) {
    assert(s.chars_left());
    assert(s.next().size() == 1);

    char c = s.next()[0];
    s++;

    addr a = parse_address(c, s);
    return chunk(c, a);
  }

  chunk parse_chunk(parse_stream<string>& s) {
    assert(s.chars_left());

    if (s.next() == "[") {
      string cs = parse_comment_with_delimiters("[", "]", s);
      return chunk('[', ']', cs);
    } else if (s.next() == "(") {
      string cs = parse_comment_with_delimiters("(", ")", s);

      return chunk('(', ')', cs);

    } else if (s.next() == ";") {
      s++;
      string cs = parse_line_comment_with_delimiter(";", s);
      return chunk(';', ';', cs);
    } else {
      return parse_word_address(s);
    }

  }

  bool parse_slash(parse_state& s) {
    if (s.next() == '/') {
      s++;
      return true;
    }

    return false;
  }

  bool is_slash(const string& s) {
    if (s.size() != 1) { return false; }

    return s[0] == '/';
  }

  bool parse_slash(parse_stream<string>& s) {
    if (is_slash(s.next())) {
      s++;
      return true;
    }

    return false;
  }

  std::pair<bool, int> parse_line_number(parse_state& s) {
    if (s.next() == 'N') {
      s++;

      int ln = parse_int(s);

      return std::make_pair(true, ln);
    }
    return std::make_pair(false, -1);
  }

  std::pair<bool, int> parse_line_number(parse_stream<string>& s) {
    if (s.next() == "N") {
      s++;

      int ln = parse_int(s);

      return std::make_pair(true, ln);
    }
    return std::make_pair(false, -1);
  }

  block parse_tokens(const std::vector<string>& tokens) {

    parse_stream<string> s(tokens);
    vector<chunk> chunks;
    bool is_slashed = parse_slash(s);

    std::pair<bool, int> line_no =
      parse_line_number(s);

    while (s.chars_left()) {
      chunk ch = parse_chunk(s);
      chunks.push_back(ch);
    }

    if (line_no.first) {
      return block(line_no.second, is_slashed, chunks);
    } else {
      return block(is_slashed, chunks);
    }

  }

  // block lex_gprog_line(const string& str) {
  //   parse_state s(str);

  //   vector<chunk> chunks;

  //   ignore_whitespace(s);

  //   bool is_slashed = parse_slash(s);

  //   ignore_whitespace(s);

  //   std::pair<bool, int> line_no =
  //     parse_line_number(s);

  //   while (s.chars_left()) {
  //     ignore_whitespace(s);
  //     if (!s.chars_left()) { break; }

  //     chunk ch = parse_chunk(s);
  //     chunks.push_back(ch);

  //   }

  //   if (line_no.first) {
  //     return block(line_no.second, is_slashed, chunks);
  //   } else {
  //     return block(is_slashed, chunks);
  //   }
  // }

  // vector<block> lex_gprog(const string& str) {
  //   vector<block> blocks;
  //   string::const_iterator line_start = str.begin();
  //   string::const_iterator line_end;

  //   while (line_start < str.end()) {
  //     line_end = find(line_start, str.end(), '\n');
  //     string line(line_start, line_end);
  //     if (line.size() > 0) {
  // 	block b = lex_gprog_line(line);
  // 	//if (b.size() > 0) {
  // 	  blocks.push_back(b);
  // 	  //}
  //     }
  //     line_start += line.size() + 1;
  //   }
  //   return blocks;
  // }

  vector<block> lex_gprog(const string& str) {
    vector<block> blocks;
    string::const_iterator line_start = str.begin();
    string::const_iterator line_end;

    while (line_start < str.end()) {
      line_end = find(line_start, str.end(), '\n');
      string line(line_start, line_end);

      if (line.size() > 0) {
	vector<string> line_tokens = lex_block(line);
	block b = parse_tokens(line_tokens);
	blocks.push_back(b);
      }

      line_start += line.size() + 1;
    }
    return blocks;
  }

  gcode_program parse_gcode(const std::string& program_text) {
    auto blocks = lex_gprog(program_text);
    return gcode_program(blocks);
  }

  gcode_program parse_gcode_saving_block_text(const std::string& program_text) {
    auto blocks = lex_gprog(program_text);
    for (auto& b : blocks) {
      b.set_debug_text();
    }
    return gcode_program(blocks);
  }

  bool is_num_char(const char c) {
    return (isdigit(c) ||
	    (c == '.') ||
	    (c == '-'));
  }

  std::string digit_string(parse_state& s) {
    string num_str = "";

    while (s.chars_left() && is_num_char(s.next())) {
      num_str += s.next();
      s++;
    }

    return num_str;
  }

  std::string lex_token(parse_state& s) {
    assert(s.chars_left());

    char c = s.next();
    string next_token = "";

    if (is_num_char(c)) {
      return digit_string(s);
    }

    switch(c) {
    case '%':
      s++;
      return "%";
    case '/':
      s++;
      return "/";

    case '(':
      s++;
      return "(";

    case ')':
      s++;
      return ")";

    case '[':
      s++;
      return "[";

    case ']':
      s++;
      return "]";

    // case 'X':
    // case 'Y':
    // case 'Z':
    // case 'I':
    // case 'J':
    // case 'K':
    // case 'F':
    // case 'R':
    // case 'Q':
    // case 'S':
    // case 'x':
    // case 'y':
    // case 'z':
    // case 'i':
    // case 'j':
    // case 'k':
    // case 'f':
    // case 'r':
    // case 's':
    // case 'q':
    // case 'E':
    // case 'G':
    // case 'H':
    // case 'M':
    // case 'N':
    // case 'O':
    // case 'T':
    // case 'P':
    // case 'D':
    // case 'L':
    // case 'g':
    // case 'h':
    // case 'm':
    // case 'n':
    // case 'o':
    // case 't':
    // case 'p':
    // case 'd':
    // case 'l':
    default:
      next_token += c;
      s++;
      return next_token;
      //    default:
      // cout << "Invalid c = " << c << endl;
      // cout << "Inavlid c as int = " << ((int) c) << endl;
      // cout << "Is EOF? " << (((int) c) == EOF) << endl;
      // assert(false);
    }

  }

  std::vector<std::string> lex_block(const std::string& block_text) {
    parse_state s(block_text);

    vector<string> tokens;

    ignore_whitespace(s);

    while (s.chars_left()) {
      ignore_whitespace(s);

      if (s.chars_left()) {
	string token = lex_token(s);
	tokens.push_back(token);
      }
    }

    return tokens;
  }

}
<|endoftext|>