<commit_before>/*
 * spatial_displacement_leafless.cpp
 *
 *  Created on: Aug 12, 2010
 *      Author: Mark Christensen
 */

#include "spatial_displacement_leafless.h"
#include "../system/discursive_system.h"

using namespace std;

SpatialDisplacementLeafless::SpatialDisplacementLeafless(int width, int height):width(width), height(height), growthUnit(5.0)
{
}

void SpatialDisplacementLeafless::decorate(SurrogateTreeNode* tree)
{
	// Iterate over each node with children
	// First, "count".  Calculates child center of mass and subtree depth
	this->count(tree);
	// Second, float weighted surrogate nodes into position
	//this->expand(tree,(3.14159/2),0,0);
	// Max tree depth
	double maxDepth = tree->findMax(TreeNodeKey::DEPTH);
	this->expand(tree,(3.14159/2),0,0,(this->height)/maxDepth);
	// Third, transform coordinates
	this->transform(tree);
}

// Scale point values to fit within width and height give
// with root at (width/2, height)
// Transformation flips y values and shifts x values
// after scaling
void SpatialDisplacementLeafless::transform(SurrogateTreeNode* tree)
{
	// Calculate resize scaling factors
	double allowedWidth = this->width*0.95;
	double allowedHeight = this->height*0.95;
	double xMax = tree->findMax(TreeNodeKey::X);
	double xMin = tree->findMin(TreeNodeKey::X);
	double yMax = tree->findMax(TreeNodeKey::Y);
	double yMin = tree->findMin(TreeNodeKey::Y);
	DiscursiveDebugPrint("Mins: (%f,%f), Maxs: (%f,%f)\n",xMin,yMin,xMax,yMax);
	//double currWidth = xMax - xMin;
	double maxXDim = max(fabs(xMax),fabs(xMin));
	double currWidth = xMax - xMin;
	double currHeight = yMax - yMin;

	double minDim = min(allowedHeight, allowedWidth);

	double scalingFactorW = minDim/(2*maxXDim);
	double scalingFactorH = minDim/currHeight;

	// Transform points to look more "naturally tree-like"
	tree->scale(TreeNodeKey::Y, scalingFactorH * 0.98);
	PropertyInverter inverter(this->height * 0.98);
	tree->transform(TreeNodeKey::Y,&inverter);

//	PropertyShifter shifter(-1*((xMax + xMin) / 2));
	PropertyShifter shifter(-xMin);
	tree->transform(TreeNodeKey::X,&shifter);
	// Scale tree values
	tree->scale(TreeNodeKey::X, scalingFactorW);
//	PropertyShifter shifter2(minDim * 1 / 2);
	PropertyShifter shifter2(maxXDim * scalingFactorW);
	tree->transform(TreeNodeKey::X,&shifter2);
}

// Sorted in increasing order
void SpatialDisplacementLeafless::insertOrderedBy(vector<SurrogateTreeNode*>* list, SurrogateTreeNode* tree, string property)
{
	//printf("Inserting '%s' from %s.  Current size: %d\n",property.c_str(),tree->data[TreeNodeKey::NAME].c_str(), list->size());
	SurrogateTreeNode* node;
	bool inserted = false;
	long comp = atol(tree->data[property].c_str());
	long curr = 0;
	for(vector<SurrogateTreeNode*>::iterator iter = list->begin(); iter != list->end(); ++iter)
	{
		node = *iter;
		curr = atol(node->data[property].c_str());
		//printf("%ld < %ld?\n",atol(tree->data[property].c_str()),atol(node->data[property].c_str()));
		if(comp < curr)
		{
			list->insert(iter,tree);
			inserted = true;
			break;
		}
	}
	if(!inserted)
	{
		//printf("Inserting at end\n");
		list->push_back(tree);
	}
}

void SpatialDisplacementLeafless::expand(SurrogateTreeNode* tree, double rootAngle, double rootX, double rootY, double allowedHeight)
{
	if(tree->children->size() > 0)
	{
		// Determine initial layout based on creation time of child nodes.
		// Files are split into different list than directories.
		vector<SurrogateTreeNode*> files;
		vector<SurrogateTreeNode*> dirs;
		SurrogateTreeNode* node = NULL;
		int maxChild = 1;
		int childSize;
		int mass = 0;
		int children = 0;
		double minChildMass = DBL_MAX;
		for(vector<SurrogateTreeNode*>::iterator iter = tree->children->begin(); iter != tree->children->end(); ++iter)
		{
			children++;
			node = *iter;
			// Directory
			if(node->children->size() > 0)
			{
				//printf("Inserting into dirs...\n");
				this->insertOrderedBy(&dirs,node,TreeNodeKey::SIZE);
				childSize = atoi(node->data[TreeNodeKey::SIZE].c_str());
				mass += childSize;
				if(childSize > maxChild )
				{
					maxChild = childSize;
				}
				if(childSize < minChildMass)
				{
					minChildMass = childSize;
				}
			}
			// File
			else
			{
				//printf("Inserting into files...\n");
				this->insertOrderedBy(&files,node,TreeNodeKey::CREATION_TIME);
				mass++;
				if(minChildMass > 1)
				{
					minChildMass = 1;
				}
			}
		}

		// Map for retrieving resutls
		unordered_map<SurrogateTreeNode*,int> pairs;
		double masses[children];
		double positions[children];
		memset(positions,0,children*sizeof(double));
		// Layout directories first
		// Start left if even number of items.
		bool left = children % 2 != 0;
		int center = children / 2;
		int dist = 0;
		//TreeDisplacementNode* treeNode;
		int i = 0;
		int location;
		int nodeMass;
		for(; i < (int)dirs.size(); i++)
		{
			dist = (i+1)/2;
			nodeMass = atoi(dirs[i]->data[TreeNodeKey::SIZE].c_str());
			if(left)
			{
				location = center - dist;
			}
			else
			{
				location = center + dist;
			}
			masses[location] = nodeMass;
			pairs[dirs[i]] = location;
			for(int k = location; k < children; k++)
			{
				positions[k] += nodeMass;
			}
			left = !left;
		}
		// Now layout files
//		for(int j = 0; j < (int)files.size(); j++)
//		{
//			dist = ((i + j + 1)/2);
//			nodeMass = 1;
//			if(left)
//			{
//				location = center - dist;
//			}
//			else
//			{
//				location = center + dist;
//			}
//			masses[location] = nodeMass;
//			pairs[files[j]] = location;
//			for(int k = location; k < children; k++)
//			{
//				positions[k] += nodeMass;
//			}
//			left = !left;
//		}

		// Calculate spacing to range [0,splay]
		double deltaSplay = 0;
		double splay = 3.14159 / 2;
		double com;
		double max = 0;
		if(mass > minChildMass)
		{
			deltaSplay = splay / (mass - minChildMass);
		}

		DiscursiveDebugPrint("Subtree mass effects [");
		for(i = 0; i < children; i++)
		{
			DiscursiveDebugPrint("%f,",positions[i]);
		}
		DiscursiveDebugPrint("] @ %f\n", deltaSplay);

		// Convert masses to initial locations
		// Record bounds
		positions[0] = 0;
		com = 0;
		for(i = 1; i < children; i++)
		{
			positions[i] = (positions[i] - minChildMass)*deltaSplay;
			com += (positions[i] * masses[i]);

			if(positions[i] > max)
			{
				max = positions[i];
			}
		}
		// Final part of CoM calculation
		com /= mass;

		// Balance tree
		double balancedCom = com;
		double divergence = balancedCom - (max/2);
		double scale;
		bool shortenLeft;
		printf("CoM: %f, Max: %f, Divergence: %f\n", balancedCom, max, divergence);
		while(fabs(divergence) > 3.14159 / 50)
		{
			// Shorten left half
			if(divergence > 0)
			{
				shortenLeft = true;
				scale = (max - balancedCom)/balancedCom;
			}
			// Shorten right half
			else
			{
				shortenLeft = false;
				scale = balancedCom/(max - balancedCom);
			}
			com = 0;
			for(i = 1; i < children; i++)
			{
				// Adjust position
				if(shortenLeft && positions[i] < balancedCom)
				{
					positions[i] = (positions[i] - divergence) * scale;
				}
				else if(!shortenLeft && positions[i] > balancedCom)
				{
					positions[i] = ((positions[i] - balancedCom) * scale) + balancedCom;
				}
				else if(shortenLeft && positions[i] > balancedCom)
				{
					positions[i] -= (2 * balancedCom - max);
				}
//				else
//				{
//					positions[i] = ;
//				}

				// Aggregate new position to calc new CoM
				com += (positions[i] * masses[i]);
			}
			max = 2*(max - balancedCom);
			balancedCom = com/mass;
			divergence = balancedCom - (max/2);
//			printf("CoM: %f, Max: %f, Divergence: %f\n", balancedCom, max, divergence);
		}

		// Transform positions to arc
		//double arcRadius = 10.0;
//		double deltaAngle = splay / children;
		int maxDepth = (int)tree->findMax(TreeNodeKey::DEPTH);
		int depth;
		double arcRadius = allowedHeight/maxDepth;
		double ratio;
		double angle;

		// Controls width of fan-out.  > 1 : Wide tree
		//							   < 1 : Narrow tree
		double widthHeightScaleFactor = 1.0;
		// Transform positions to arc and Update new positions
		// Dirs first
		for(i = 0; i < (int)dirs.size(); i++)
		{
			node = dirs[i];
			depth = atoi(node->data[TreeNodeKey::DEPTH].c_str());
			ratio = depth / (double)maxDepth;
			angle = rootAngle - (positions[pairs[node]] - com);
			double newX = rootX + (ratio * arcRadius * cos(angle));
			double newY = rootY + (ratio * arcRadius * widthHeightScaleFactor * sin(angle));
			node->set(TreeNodeKey::X, boost::lexical_cast<string>(newX));
			node->set(TreeNodeKey::Y, boost::lexical_cast<string>(newY));
			// Run expand on child
			double childRot = (3.14159/2);//angle;// + ((3.14159/2)-angle)/2;
			this->expand(node,childRot,newX,newY,allowedHeight - arcRadius);
		}
		// Then files
		for(int j = 0; j < (int)files.size(); j++)
		{
			node = files[j];
			depth = atoi(node->data[TreeNodeKey::DEPTH].c_str());
			ratio = depth / (double)maxDepth;
			angle = rootAngle - (positions[pairs[node]] - com);
			double newX = rootX + (ratio * arcRadius * cos(angle));
			double newY = rootY + (ratio * arcRadius * widthHeightScaleFactor * sin(angle));
			node->set(TreeNodeKey::X, boost::lexical_cast<string>(newX));
			node->set(TreeNodeKey::Y, boost::lexical_cast<string>(newY));
		}
	}
}

int SpatialDisplacementLeafless::count(SurrogateTreeNode* tree)
{
	// Count all children plus ourselves (initial 1)
	int sum = 1;
	int maxDepth = 0;
	int childDepth = 0;
	for(vector<SurrogateTreeNode*>::iterator iter = tree->children->begin(); iter != tree->children->end(); ++iter)
	{
		sum += this->count(*iter);
		//childDepth = atoi((*iter)->data["count"].c_str());
		childDepth = atoi((*iter)->data[TreeNodeKey::DEPTH].c_str());
		if(childDepth > maxDepth)
		{
			maxDepth = childDepth;
		}
	}
	// Assign count to data
	tree->set(TreeNodeKey::SIZE, boost::lexical_cast<string>(sum));
	DiscursiveDebugPrint("Size of tree %s is %s in this and %d sublevels\n",tree->data[TreeNodeKey::NAME].c_str(),tree->data[TreeNodeKey::SIZE].c_str(),maxDepth);
	tree->set(TreeNodeKey::DEPTH, boost::lexical_cast<string>(maxDepth + 1));
	return sum;
}
<commit_msg>Fixed infinite loop and rescale problems in spatial_displacement_leafless.cpp.<commit_after>/*
 * spatial_displacement_leafless.cpp
 *
 *  Created on: Aug 12, 2010
 *      Author: Mark Christensen
 */

#include "spatial_displacement_leafless.h"
#include "../system/discursive_system.h"

using namespace std;

SpatialDisplacementLeafless::SpatialDisplacementLeafless(int width, int height):width(width), height(height), growthUnit(5.0)
{
}

void SpatialDisplacementLeafless::decorate(SurrogateTreeNode* tree)
{
	// Iterate over each node with children
	// First, "count".  Calculates child center of mass and subtree depth
	this->count(tree);
	// Second, float weighted surrogate nodes into position
	//this->expand(tree,(3.14159/2),0,0);
	// Max tree depth
	double maxDepth = tree->findMax(TreeNodeKey::DEPTH);
	this->expand(tree,(3.14159/2),0,0,(this->height)/maxDepth);
	// Third, transform coordinates
	this->transform(tree);
}

// Scale point values to fit within width and height give
// with root at (width/2, height)
// Transformation flips y values and shifts x values
// after scaling
void SpatialDisplacementLeafless::transform(SurrogateTreeNode* tree)
{
	// Calculate resize scaling factors
	double allowedWidth = this->width*0.95;
	double allowedHeight = this->height*0.95;
	double xMax = tree->findMax(TreeNodeKey::X);
	double xMin = tree->findMin(TreeNodeKey::X);
	double yMax = tree->findMax(TreeNodeKey::Y);
	double yMin = tree->findMin(TreeNodeKey::Y);
	DiscursiveDebugPrint("Mins: (%f,%f), Maxs: (%f,%f)\n",xMin,yMin,xMax,yMax);
	//double currWidth = xMax - xMin;
	double maxXDim = max(fabs(xMax),fabs(xMin));
	double currWidth = xMax - xMin;
	double currHeight = yMax - yMin;

	double minDim = min(allowedHeight, allowedWidth);

	double scalingFactorW = minDim/(2*maxXDim);
	double scalingFactorH = minDim/currHeight;

	// Transform points to look more "naturally tree-like"
	tree->scale(TreeNodeKey::Y, scalingFactorH * 0.98);
	PropertyInverter inverter(this->height * 0.98);
	tree->transform(TreeNodeKey::Y,&inverter);

//	PropertyShifter shifter(-1*((xMax + xMin) / 2));
//	PropertyShifter shifter(-xMin);
	// Center on 0
	PropertyShifter shifter(-(xMax+xMin)/2.0);
	tree->transform(TreeNodeKey::X,&shifter);
	// Scale tree values
	tree->scale(TreeNodeKey::X, scalingFactorW);
//	PropertyShifter shifter2(minDim * 1 / 2);
	PropertyShifter shifter2(maxXDim * scalingFactorW);
	tree->transform(TreeNodeKey::X,&shifter2);
}

// Sorted in increasing order
void SpatialDisplacementLeafless::insertOrderedBy(vector<SurrogateTreeNode*>* list, SurrogateTreeNode* tree, string property)
{
	//printf("Inserting '%s' from %s.  Current size: %d\n",property.c_str(),tree->data[TreeNodeKey::NAME].c_str(), list->size());
	SurrogateTreeNode* node;
	bool inserted = false;
	long comp = atol(tree->data[property].c_str());
	long curr = 0;
	for(vector<SurrogateTreeNode*>::iterator iter = list->begin(); iter != list->end(); ++iter)
	{
		node = *iter;
		curr = atol(node->data[property].c_str());
		//printf("%ld < %ld?\n",atol(tree->data[property].c_str()),atol(node->data[property].c_str()));
		if(comp < curr)
		{
			list->insert(iter,tree);
			inserted = true;
			break;
		}
	}
	if(!inserted)
	{
		//printf("Inserting at end\n");
		list->push_back(tree);
	}
}

void SpatialDisplacementLeafless::expand(SurrogateTreeNode* tree, double rootAngle, double rootX, double rootY, double allowedHeight)
{
	if(tree->children->size() > 0)
	{
		// Determine initial layout based on creation time of child nodes.
		// Files are split into different list than directories.
		vector<SurrogateTreeNode*> files;
		vector<SurrogateTreeNode*> dirs;
		SurrogateTreeNode* node = NULL;
		int maxChild = 1;
		int childSize;
		int mass = 0;
		int children = 0;
		double minChildMass = DBL_MAX;
		for(vector<SurrogateTreeNode*>::iterator iter = tree->children->begin(); iter != tree->children->end(); ++iter)
		{
			children++;
			node = *iter;
			// Directory
			if(node->children->size() > 0)
			{
				//printf("Inserting into dirs...\n");
				this->insertOrderedBy(&dirs,node,TreeNodeKey::SIZE);
				childSize = atoi(node->data[TreeNodeKey::SIZE].c_str());
				mass += childSize;
				if(childSize > maxChild )
				{
					maxChild = childSize;
				}
				if(childSize < minChildMass)
				{
					minChildMass = childSize;
				}
			}
			// File
			else
			{
				//printf("Inserting into files...\n");
				this->insertOrderedBy(&files,node,TreeNodeKey::CREATION_TIME);
				mass++;
				if(minChildMass > 1)
				{
					minChildMass = 1;
				}
			}
		}

		// Map for retrieving resutls
		unordered_map<SurrogateTreeNode*,int> pairs;
		double masses[children];
		double positions[children];
		memset(positions,0,children*sizeof(double));
		// Layout directories first
		// Start left if even number of items.
		bool left = children % 2 != 0;
		int center = children / 2;
		int dist = 0;
		//TreeDisplacementNode* treeNode;
		int i = 0;
		int location;
		int nodeMass;
		for(; i < (int)dirs.size(); i++)
		{
			dist = (i+1)/2;
			nodeMass = atoi(dirs[i]->data[TreeNodeKey::SIZE].c_str());
			if(left)
			{
				location = center - dist;
			}
			else
			{
				location = center + dist;
			}
			masses[location] = nodeMass;
			pairs[dirs[i]] = location;
			for(int k = location; k < children; k++)
			{
				positions[k] += nodeMass;
			}
			left = !left;
		}
		// Now layout files
//		for(int j = 0; j < (int)files.size(); j++)
//		{
//			dist = ((i + j + 1)/2);
//			nodeMass = 1;
//			if(left)
//			{
//				location = center - dist;
//			}
//			else
//			{
//				location = center + dist;
//			}
//			masses[location] = nodeMass;
//			pairs[files[j]] = location;
//			for(int k = location; k < children; k++)
//			{
//				positions[k] += nodeMass;
//			}
//			left = !left;
//		}

		// Calculate spacing to range [0,splay]
		double deltaSplay = 0;
		double splay = 3.14159 / 2;
		double com;
		double max = 0;
		if(mass > minChildMass)
		{
			deltaSplay = splay / (mass - minChildMass);
		}

		DiscursiveDebugPrint("Subtree mass effects [");
		for(i = 0; i < children; i++)
		{
			DiscursiveDebugPrint("%f,",positions[i]);
		}
		DiscursiveDebugPrint("] @ %f\n", deltaSplay);

		// Convert masses to initial locations
		// Record bounds
		positions[0] = 0;
		com = 0;
		for(i = 1; i < children; i++)
		{
			positions[i] = (positions[i] - minChildMass)*deltaSplay;
			com += (positions[i] * masses[i]);

			if(positions[i] > max)
			{
				max = positions[i];
			}
		}
		// Final part of CoM calculation
		com /= mass;

		// Balance tree
//		double balancedCom = com;
//		double divergence = balancedCom - (max/2);
//		double scale;
//		bool shortenLeft;
//		printf("CoM: %f, Max: %f, Divergence: %f\n", balancedCom, max, divergence);
//		int step = 0;
//		while(fabs(divergence) > 3.14159 / (50-step))
//		{
//			// Shorten left half
//			if(divergence > 0)
//			{
//				shortenLeft = true;
//				scale = (max - balancedCom)/balancedCom;
//			}
//			// Shorten right half
//			else
//			{
//				shortenLeft = false;
//				scale = balancedCom/(max - balancedCom);
//			}
//			com = 0;
//			for(i = 1; i < children; i++)
//			{
//				// Adjust position
//				if(shortenLeft && positions[i] < balancedCom)
//				{
//					positions[i] = (positions[i] - divergence) * scale;
//				}
//				else if(!shortenLeft && positions[i] > balancedCom)
//				{
//					positions[i] = ((positions[i] - balancedCom) * scale) + balancedCom;
//				}
//				else if(shortenLeft && positions[i] > balancedCom)
//				{
//					positions[i] -= (2 * balancedCom - max);
//				}
////				else
////				{
////					positions[i] = ;
////				}
//
//				// Aggregate new position to calc new CoM
//				com += (positions[i] * masses[i]);
//			}
//			max = 2*(max - balancedCom);
//			balancedCom = com/mass;
//			divergence = balancedCom - (max/2);
//			step++;
////			printf("CoM: %f, Max: %f, Divergence: %f\n", balancedCom, max, divergence);
//		}

		// Transform positions to arc
		//double arcRadius = 10.0;
//		double deltaAngle = splay / children;
		int maxDepth = (int)tree->findMax(TreeNodeKey::DEPTH);
		int depth;
		double arcRadius = allowedHeight/maxDepth;
		double ratio;
		double angle;

		// Controls width of fan-out.  > 1 : Wide tree
		//							   < 1 : Narrow tree
		double widthHeightScaleFactor = 1.0;
		// Transform positions to arc and Update new positions
		// Dirs first
		for(i = 0; i < (int)dirs.size(); i++)
		{
			node = dirs[i];
			depth = atoi(node->data[TreeNodeKey::DEPTH].c_str());
			ratio = depth / (double)maxDepth;
			angle = rootAngle - (positions[pairs[node]] - com);
			double newX = rootX + (ratio * arcRadius * cos(angle));
			double newY = rootY + (ratio * arcRadius * widthHeightScaleFactor * sin(angle));
			node->set(TreeNodeKey::X, boost::lexical_cast<string>(newX));
			node->set(TreeNodeKey::Y, boost::lexical_cast<string>(newY));
			// Run expand on child
			double childRot = (3.14159/2);//angle;// + ((3.14159/2)-angle)/2;
			this->expand(node,childRot,newX,newY,allowedHeight - arcRadius);
		}
		// Then files
		for(int j = 0; j < (int)files.size(); j++)
		{
			node = files[j];
			depth = atoi(node->data[TreeNodeKey::DEPTH].c_str());
			ratio = depth / (double)maxDepth;
			angle = rootAngle - (positions[pairs[node]] - com);
			double newX = rootX + (ratio * arcRadius * cos(angle));
			double newY = rootY + (ratio * arcRadius * widthHeightScaleFactor * sin(angle));
			node->set(TreeNodeKey::X, boost::lexical_cast<string>(newX));
			node->set(TreeNodeKey::Y, boost::lexical_cast<string>(newY));
		}
	}
}

int SpatialDisplacementLeafless::count(SurrogateTreeNode* tree)
{
	// Count all children plus ourselves (initial 1)
	int sum = 1;
	int maxDepth = 0;
	int childDepth = 0;
	for(vector<SurrogateTreeNode*>::iterator iter = tree->children->begin(); iter != tree->children->end(); ++iter)
	{
		sum += this->count(*iter);
		//childDepth = atoi((*iter)->data["count"].c_str());
		childDepth = atoi((*iter)->data[TreeNodeKey::DEPTH].c_str());
		if(childDepth > maxDepth)
		{
			maxDepth = childDepth;
		}
	}
	// Assign count to data
	tree->set(TreeNodeKey::SIZE, boost::lexical_cast<string>(sum));
	DiscursiveDebugPrint("Size of tree %s is %s in this and %d sublevels\n",tree->data[TreeNodeKey::NAME].c_str(),tree->data[TreeNodeKey::SIZE].c_str(),maxDepth);
	tree->set(TreeNodeKey::DEPTH, boost::lexical_cast<string>(maxDepth + 1));
	return sum;
}
<|endoftext|>


<commit_before>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>

#include "qtcontacts.h"

//TESTED_CLASS=
//TESTED_FILES=

class tst_QContactGroup: public QObject
{
Q_OBJECT

public:
    tst_QContactGroup();
    virtual ~tst_QContactGroup();

public slots:
    void init();
    void cleanup();
private slots:
    void ctors();
    void name();
    void members();
    void id();
    void empty();
};

tst_QContactGroup::tst_QContactGroup()
{
}

tst_QContactGroup::~tst_QContactGroup()
{
}

void tst_QContactGroup::init()
{
}

void tst_QContactGroup::cleanup()
{
}

void tst_QContactGroup::ctors()
{
    QContactGroup g;
    QVERIFY(g.addMember(QUniqueId(1)));
    QCOMPARE(g.members().count(), 1);

    QContactGroup g2 = g;
    QCOMPARE(g2.members().count(), 1);

    QContactGroup g3(g2);
    QCOMPARE(g3.members().count(), 1);
}

void tst_QContactGroup::name()
{
    QContactGroup g;
    QVERIFY(g.name().isEmpty());
    g.setName("test");
    QCOMPARE(g.name(), QString("test"));

    QContactGroup g2;
    g2 = g;
    QCOMPARE(g2.name(), g.name());
    g2.setName("test2");
    QCOMPARE(g.name(), QString("test"));
    QCOMPARE(g2.name(), QString("test2"));
}

void tst_QContactGroup::members()
{
    QContact c;
    c.setId(QUniqueId(224));
    QContactName n;
    n.setFirst("John");
    n.setLast("Citizen");
    c.saveDetail(&n);

    // create a new group
    QContactGroup g;
    QVERIFY(g.members().isEmpty());

    // test add
    QVERIFY(g.addMember(c.id()));
    QCOMPARE(g.members().size(), 1);
    QVERIFY(g.hasMember(c.id()));

    // test remove
    QVERIFY(g.removeMember(c.id()));
    QVERIFY(g.members().isEmpty());
    QVERIFY(!g.hasMember(c.id()));

    // test multiple adds
    int currentCount = 0;
    for (int i = 1; i < 50; i++) {
        QCOMPARE(g.hasMember(QUniqueId(i)), false);
        QVERIFY(g.addMember(QUniqueId(i)));
        currentCount += 1;
        QCOMPARE(g.hasMember(QUniqueId(i)), true);
        QCOMPARE(g.members().count(), currentCount);
        QCOMPARE(g.error(), QContactGroup::NoError);
    }

    while (currentCount > 0) {
        QVERIFY(g.removeMember(QUniqueId(currentCount)));
        currentCount -= 1;
        QCOMPARE(g.members().count(), currentCount);
        QCOMPARE(g.error(), QContactGroup::NoError);
    }

    // test that adding the same contact twice fails properly
    QVERIFY(g.addMember(QUniqueId(1)));
    QVERIFY(!g.addMember(QUniqueId(1)));
    QCOMPARE(g.error(), QContactGroup::ContactAlreadyInGroupError);
    QCOMPARE(g.members().count(), 1);

    // test removing a non-existent contact fails properly
    QVERIFY(!g.removeMember(QUniqueId(2)));
    QCOMPARE(g.error(), QContactGroup::ContactNotInGroupError);
    QCOMPARE(g.members().count(), 1);
}

void tst_QContactGroup::id()
{
    QContactGroup g;
    g.setId(QUniqueId(1));
    QCOMPARE(g.id(), QUniqueId(1));
    g.setId(QUniqueId(2));
    QCOMPARE(g.id(), QUniqueId(2));
}

void tst_QContactGroup::empty()
{
    QContactGroup g;
    QVERIFY(g.isEmpty());

    g.setName("Name");
    QVERIFY(!g.isEmpty());

    g.setName(QString());
    QVERIFY(g.isEmpty());

    g.setId(243234);
    QVERIFY(!g.isEmpty());

    g.setId(0);
    QVERIFY(g.isEmpty());

    g.addMember(123);
    QVERIFY(!g.isEmpty());

    g.removeMember(123);
    QVERIFY(g.isEmpty());

    g.setId(1123);
    g.addMember(123);
    QVERIFY(!g.isEmpty());

    g.removeMember(123);
    QVERIFY(!g.isEmpty());

    g.setId(0);
    QVERIFY(g.isEmpty());
}

QTEST_MAIN(tst_QContactGroup)
#include "tst_qcontactgroup.moc"
<commit_msg>Expand group auto test to test QContactGroup::setMembers()<commit_after>/****************************************************************************
**
** Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** This file is part of the Qt Mobility Components.
**
** $QT_BEGIN_LICENSE:LGPL$
** No Commercial Usage
** This file contains pre-release code and may not be distributed.
** You may use this file in accordance with the terms and conditions
** contained in the Technology Preview License Agreement accompanying
** this package.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain
** additional rights. These rights are described in the Nokia Qt LGPL
** Exception version 1.0, included in the file LGPL_EXCEPTION.txt in this
** package.
**
** If you have questions regarding the use of this file, please
** contact Nokia at http://www.qtsoftware.com/contact.
** $QT_END_LICENSE$
**
****************************************************************************/

#include <QtTest/QtTest>

#include "qtcontacts.h"

//TESTED_CLASS=
//TESTED_FILES=

class tst_QContactGroup: public QObject
{
Q_OBJECT

public:
    tst_QContactGroup();
    virtual ~tst_QContactGroup();

public slots:
    void init();
    void cleanup();
private slots:
    void ctors();
    void name();
    void members();
    void id();
    void empty();
};

tst_QContactGroup::tst_QContactGroup()
{
}

tst_QContactGroup::~tst_QContactGroup()
{
}

void tst_QContactGroup::init()
{
}

void tst_QContactGroup::cleanup()
{
}

void tst_QContactGroup::ctors()
{
    QContactGroup g;
    QVERIFY(g.addMember(QUniqueId(1)));
    QCOMPARE(g.members().count(), 1);

    QContactGroup g2 = g;
    QCOMPARE(g2.members().count(), 1);

    QContactGroup g3(g2);
    QCOMPARE(g3.members().count(), 1);
}

void tst_QContactGroup::name()
{
    QContactGroup g;
    QVERIFY(g.name().isEmpty());
    g.setName("test");
    QCOMPARE(g.name(), QString("test"));

    QContactGroup g2;
    g2 = g;
    QCOMPARE(g2.name(), g.name());
    g2.setName("test2");
    QCOMPARE(g.name(), QString("test"));
    QCOMPARE(g2.name(), QString("test2"));
}

void tst_QContactGroup::members()
{
    QContact c;
    c.setId(QUniqueId(224));
    QContactName n;
    n.setFirst("John");
    n.setLast("Citizen");
    c.saveDetail(&n);

    // create a new group
    QContactGroup g;
    QVERIFY(g.members().isEmpty());

    // test add
    QVERIFY(g.addMember(c.id()));
    QCOMPARE(g.members().size(), 1);
    QVERIFY(g.hasMember(c.id()));

    // test remove
    QVERIFY(g.removeMember(c.id()));
    QVERIFY(g.members().isEmpty());
    QVERIFY(!g.hasMember(c.id()));

    // test multiple adds
    int currentCount = 0;
    for (int i = 1; i < 50; i++) {
        QCOMPARE(g.hasMember(QUniqueId(i)), false);
        QVERIFY(g.addMember(QUniqueId(i)));
        currentCount += 1;
        QCOMPARE(g.hasMember(QUniqueId(i)), true);
        QCOMPARE(g.members().count(), currentCount);
        QCOMPARE(g.error(), QContactGroup::NoError);
    }

    while (currentCount > 0) {
        QVERIFY(g.removeMember(QUniqueId(currentCount)));
        currentCount -= 1;
        QCOMPARE(g.members().count(), currentCount);
        QCOMPARE(g.error(), QContactGroup::NoError);
    }

    // test that adding the same contact twice fails properly
    QVERIFY(g.addMember(QUniqueId(1)));
    QVERIFY(!g.addMember(QUniqueId(1)));
    QCOMPARE(g.error(), QContactGroup::ContactAlreadyInGroupError);
    QCOMPARE(g.members().count(), 1);

    // test removing a non-existent contact fails properly
    QVERIFY(!g.removeMember(QUniqueId(2)));
    QCOMPARE(g.error(), QContactGroup::ContactNotInGroupError);
    QCOMPARE(g.members().count(), 1);

    // clear the list
    QList<QUniqueId> members = g.members();
    currentCount = members.size();
    while (currentCount > 0) {
        QVERIFY(g.removeMember(members.at(0)));
        currentCount -= 1;
        QCOMPARE(g.error(), QContactGroup::NoError);
    }
    QCOMPARE(g.members(), QList<QUniqueId>());

    // set the member list manually.
    members.append(QUniqueId(3));
    members.append(QUniqueId(8));
    members.append(QUniqueId(33));
    QVERIFY(g.setMembers(members));
    QCOMPARE(g.members(), members);
}

void tst_QContactGroup::id()
{
    QContactGroup g;
    g.setId(QUniqueId(1));
    QCOMPARE(g.id(), QUniqueId(1));
    g.setId(QUniqueId(2));
    QCOMPARE(g.id(), QUniqueId(2));
}

void tst_QContactGroup::empty()
{
    QContactGroup g;
    QVERIFY(g.isEmpty());

    g.setName("Name");
    QVERIFY(!g.isEmpty());

    g.setName(QString());
    QVERIFY(g.isEmpty());

    g.setId(243234);
    QVERIFY(!g.isEmpty());

    g.setId(0);
    QVERIFY(g.isEmpty());

    g.addMember(123);
    QVERIFY(!g.isEmpty());

    g.removeMember(123);
    QVERIFY(g.isEmpty());

    g.setId(1123);
    g.addMember(123);
    QVERIFY(!g.isEmpty());

    g.removeMember(123);
    QVERIFY(!g.isEmpty());

    g.setId(0);
    QVERIFY(g.isEmpty());
}

QTEST_MAIN(tst_QContactGroup)
#include "tst_qcontactgroup.moc"
<|endoftext|>


<commit_before>#include <age/graphics/TileMapComponent.h>

#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <iostream>

using namespace age::graphics;

TileMapComponent::TileMapComponent()
{
}

TileMapComponent::~TileMapComponent()
{
}

void TileMapComponent::loadTileMap(const age::terrain::TileMap&)
{
	// for(const auto& layer : x.getLayers())
	//{
	//	// const auto filename = x.getTileSet()[0].getSource().getFileName().string();

	//	// if(this->texture.loadFromFile(filename) == true)
	//	{
	//		sf::VertexArray& m_vertices = vertices;
	//		const auto& indices = layer.getIndices();
	//		m_vertices.resize(indices.size() * 4);
	//		m_vertices.setPrimitiveType(sf::Quads);

	//		// Render order right-down
	//		for(auto i = 0; i < layer.getHeight(); i++)
	//		{
	//			for(auto j = 0; j < layer.getWidth(); j++)
	//			{
	//				// Two dimensional index into one dimensional array.
	//				const auto index = j + (i * layer.getWidth());

	//				// https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php
	//				sf::Vector2u tileSize{static_cast<unsigned int>(x.getTileWidth()), static_cast<unsigned int>(x.getTileHeight())};

	//				const auto quad = &m_vertices[index * 4];

	//				// Define the size and shape on screen to draw the texture at.
	//				quad[0].position = sf::Vector2f(static_cast<float>(j * tileSize.x), static_cast<float>(i * tileSize.y));
	//				quad[1].position = sf::Vector2f(static_cast<float>((j + 1) * tileSize.x), static_cast<float>(i * tileSize.y));
	//				quad[2].position = sf::Vector2f(static_cast<float>((j + 1) * tileSize.x), static_cast<float>((i + 1) * tileSize.y));
	//				quad[3].position = sf::Vector2f(static_cast<float>(j * tileSize.x), static_cast<float>((i + 1) * tileSize.y));

	//				// Define the location of the tile within the texture.
	//				// We must account for the spacing between tiles that may appear within the tileset texture.
	//				const auto& tileset = x.getTileSet()[0];
	//				const auto tile = indices[index] - tileset.getTileOffset();
	//				const auto tu = tile % tileset.getColumns();
	//				const auto tv = tile / tileset.getColumns();
	//				const auto su = tu * tileset.getSpacing();
	//				const auto sv = tv * tileset.getSpacing();
	//				quad[0].texCoords = sf::Vector2f(static_cast<float>(su + tu * tileSize.x), static_cast<float>(sv + tv * tileSize.y));
	//				quad[1].texCoords = sf::Vector2f(static_cast<float>(su + (tu + 1) * tileSize.x), static_cast<float>(sv + tv * tileSize.y));
	//				quad[2].texCoords = sf::Vector2f(static_cast<float>(su + (tu + 1) * tileSize.x), static_cast<float>(sv + (tv + 1) * tileSize.y));
	//				quad[3].texCoords = sf::Vector2f(static_cast<float>(su + tu * tileSize.x), static_cast<float>(sv + (tv + 1) * tileSize.y));
	//			}
	//		}
	//	}
	//}
}

void TileMapComponent::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
	states.texture = &texture;
	target.draw(vertices, states);
}
<commit_msg>Uncomment render code for tile maps.<commit_after>#include <age/graphics/TileMapComponent.h>

#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <iostream>

using namespace age::graphics;

TileMapComponent::TileMapComponent()
{
}

TileMapComponent::~TileMapComponent()
{
}

void TileMapComponent::loadTileMap(const age::terrain::TileMap& x)
{
	for(const auto& layer : x.getLayers())
	{
		const auto filename = x.getTileSet()[0].getSource().getFileName().string();

		if(this->texture.loadFromFile(filename) == true)
		{
			sf::VertexArray& m_vertices = vertices;
			const auto& indices = layer.getIndices();
			m_vertices.resize(indices.size() * 4);
			m_vertices.setPrimitiveType(sf::Quads);

			// Render order right-down
			for(auto i = 0; i < layer.getHeight(); i++)
			{
				for(auto j = 0; j < layer.getWidth(); j++)
				{
					// Two dimensional index into one dimensional array.
					const auto index = j + (i * layer.getWidth());

					// https://www.sfml-dev.org/tutorials/2.5/graphics-vertex-array.php
					sf::Vector2u tileSize{static_cast<unsigned int>(x.getTileWidth()), static_cast<unsigned int>(x.getTileHeight())};

					const auto quad = &m_vertices[index * 4];

					// Define the size and shape on screen to draw the texture at.
					quad[0].position = sf::Vector2f(static_cast<float>(j * tileSize.x), static_cast<float>(i * tileSize.y));
					quad[1].position = sf::Vector2f(static_cast<float>((j + 1) * tileSize.x), static_cast<float>(i * tileSize.y));
					quad[2].position = sf::Vector2f(static_cast<float>((j + 1) * tileSize.x), static_cast<float>((i + 1) * tileSize.y));
					quad[3].position = sf::Vector2f(static_cast<float>(j * tileSize.x), static_cast<float>((i + 1) * tileSize.y));

					// Define the location of the tile within the texture.
					// We must account for the spacing between tiles that may appear within the tileset texture.
					const auto& tileset = x.getTileSet()[0];
					const auto tile = indices[index] - tileset.getTileOffset();
					const auto tu = tile % tileset.getColumns();
					const auto tv = tile / tileset.getColumns();
					const auto su = tu * tileset.getSpacing();
					const auto sv = tv * tileset.getSpacing();
					quad[0].texCoords = sf::Vector2f(static_cast<float>(su + tu * tileSize.x), static_cast<float>(sv + tv * tileSize.y));
					quad[1].texCoords = sf::Vector2f(static_cast<float>(su + (tu + 1) * tileSize.x), static_cast<float>(sv + tv * tileSize.y));
					quad[2].texCoords = sf::Vector2f(static_cast<float>(su + (tu + 1) * tileSize.x), static_cast<float>(sv + (tv + 1) * tileSize.y));
					quad[3].texCoords = sf::Vector2f(static_cast<float>(su + tu * tileSize.x), static_cast<float>(sv + (tv + 1) * tileSize.y));
				}
			}
		}
	}
}

void TileMapComponent::draw(sf::RenderTarget& target, sf::RenderStates states) const
{
	states.texture = &texture;
	target.draw(vertices, states);
}
<|endoftext|>


<commit_before>/**
 * File        : ParDivide.cc
 * Description : Parallel divide search implementation. Makes rough
 *               guess of where certain equidistant points in the final
 *               path will be and "commits" them and searches out from
 *               each point (and start and end) in parallel. After
 *               connections have been made it does a final smoothing
 *               stage in case the original guesses are in highly
 *               non-optimal spots
 */

#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <limits>
#include <cmath>
#include <chrono>
#include <thread>
#include <mutex>

#include <boost/lexical_cast.hpp>

#include "tbb/concurrent_unordered_map.h"
#include "tbb/concurrent_vector.h"

#include "algorithms/tools/PathTile.h"
#include "algorithms/tools/PriorityQueue.h"
#include "common/Results.h"

using namespace pathFind;

const std::string WORLD_DIR = "worlds";
const std::string WORLD_EXT = ".world";

const std::string ALG_NAME = "parDivide";

const uint numThreads = 4;

Point findStart (const World& world, uint numThreadsLeft, const Point& start, const Point& end);

void search (uint id, const Point& start, const Point& predEnd, const Point& succEnd,
             tbb::concurrent_unordered_map<uint, uint>& tileIdsFound,
             std::unordered_map<uint, PathTile>& expandedTiles,
             std::vector<Point>& meetingTiles, tbb::concurrent_vector<std::pair<bool, uint>>& meetingTilesFound,
             const pathFind::World& world, std::mutex& m);

void searchNeighbor (const Point& adjPoint, const World& world, const PathTile& tile,
    PriorityQueue& openTiles, const std::unordered_map<uint, PathTile>& expandedTiles);

int main (int args, char* argv[])
{
    // Program should be started with 5 command line parameter
    // that specifies the name of the world file to read from,
    // the start x, start y, end x, and end y
    if (args != 6 )
    {
        std::cout << "Incorrect inputs. Usage: <filename> <start x> <start y> <end x> <end y>" << std::endl;
        return EXIT_FAILURE;
    }

    // Parse the world file
    std::stringstream filename;
    filename << WORLD_DIR << "/" << argv[1] << WORLD_EXT;

    std::ifstream worldFile (filename.str (),
            std::ifstream::in | std::ifstream::binary);

    if (!worldFile)
    {
        std::cout << "World file doesn't exist." << std::endl;
        return EXIT_FAILURE;
    }
    pathFind::World world;

    worldFile >> world;

    // Parse the start and end points
    uint startX, startY, endX, endY;
    try
    {
        startX = boost::lexical_cast<uint> (argv[2]);
        startY = boost::lexical_cast<uint> (argv[3]);
        endX = boost::lexical_cast<uint> (argv[4]);
        endY = boost::lexical_cast<uint> (argv[5]);
    } catch (boost::bad_lexical_cast &e)
    {
        std::cout << "Start and end points failed to convert to numeric types" << std::endl;
        return EXIT_FAILURE;
    }

    auto t1 = std::chrono::high_resolution_clock::now();

    std::vector<Point> startPoints (numThreads);
    startPoints[0] = Point {startX, startY};
    if (numThreads > 1)
    {
        startPoints.back() = Point {endX, endY};
        uint i = 1;
        uint j = numThreads - 2;
        while (i < j)
        {
            startPoints[i] = findStart (world, j - i + 1, startPoints[i - 1], startPoints[j + 1]);
            startPoints[j] = findStart (world, j - i, startPoints[j + 1], startPoints[i]);
            i++;
            j--;
        }
        if (i == j)
        {
            startPoints[i] = findStart (world, 1, startPoints[i -1], startPoints[i + 1]);
        }
    }

    pathFind::PathTile fTile, rTile;

    std::vector<std::unordered_map<uint, PathTile>> expandedTiles (numThreads);
    tbb::concurrent_unordered_map<uint, uint> idsFound;
    std::vector<Point> meetingTiles (numThreads + 1);
    tbb::concurrent_vector<std::pair<bool, uint>> meetingTilesFound (numThreads + 1);
    std::mutex m;

    std::vector<std::thread> threads (numThreads);
    for (uint i = 0; i < numThreads; ++i)
    {
        threads[i] = std::thread (search, i, std::cref(startPoints[i]), std::cref((i == 0) ? startPoints[0] : startPoints[i - 1]),
                std::cref((i == numThreads - 1) ? startPoints[i] : startPoints[i + 1]), std::ref (idsFound), std::ref(expandedTiles[i]),
                std::ref(meetingTiles), std::ref (meetingTilesFound),
                std::cref(world), std::ref(m));
    }

    for (auto& t : threads)
    {
        t.join ();
    }

    auto t2 = std::chrono::high_resolution_clock::now();

    // Parse reverse results
    uint totalCost = 0;
    std::vector<Point> finalPath;
    finalPath.emplace_back (endX, endY);
    uint j = expandedTiles.size () - 1, i = meetingTiles.size () - 1;
    while (i > 0)
    {
        PathTile fTile = expandedTiles[j][(meetingTiles[i].y * world.getWidth ()) + meetingTiles[i].x];
        while (fTile.xy ().x != startPoints[j].x || fTile.xy ().y != startPoints[j].y)
        {
            fTile = expandedTiles[j][(fTile.bestTile ().y * world.getWidth()) + fTile.bestTile ().x];
            if (finalPath.back().x != fTile.xy().x || finalPath.back().y != fTile.xy().y)
            {
                totalCost += fTile.getTile().cost;
                finalPath.emplace_back(fTile.xy());
            }
        }

        --i;
        std::vector <Point> reversePath;
        PathTile rTile = expandedTiles[j][(meetingTiles[i].y * world.getWidth ()) + meetingTiles[i].x];
        while (rTile.xy ().x != startPoints[j].x || rTile.xy ().y != startPoints[j].y)
        {
            totalCost += rTile.getTile().cost;
            reversePath.emplace_back (rTile.xy ());
            rTile = expandedTiles[j][(rTile.bestTile ().y * world.getWidth ()) + rTile.bestTile ().x];
        }
        finalPath.insert(finalPath.end (), reversePath.rbegin (), reversePath.rend ());

        --j;
    }
    totalCost -= fTile.getTile().cost;

    writeResults (finalPath, argv[1], ALG_NAME,
            std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count(), totalCost);

    return EXIT_SUCCESS;
}

Point findStart (const World& world, uint numThreadsLeft, const Point& start, const Point& end)
{
    if (start.x == end.x && start.y == end.y)
    {
        return start;
    }
    int diffX = static_cast<int> (end.x) - start.x;
    int diffY = static_cast<int> (end.y) - start.y;
    Point forward, backward;
    forward.x = static_cast<float> (diffX) / (numThreadsLeft + 1) + start.x;
    forward.y = static_cast<float> (diffY) / (numThreadsLeft + 1) + start.y;
    backward.x = forward.x;
    backward.y = forward.y;

    int slope;
    bool ySlope = true;
    if (abs (diffX) < abs (diffY))
    {
        slope = (diffY == 0) ? std::numeric_limits<int>::max () : -diffX / diffY;
    }
    else
    {
        slope = (diffX == 0) ? std::numeric_limits<int>::max () : -diffY / diffX;
        ySlope = false;
    }

    int distAlongSlope = 0;
    int slopeDirection = (slope >= 0) ? 1 : -1;
    while (world (forward.x, forward.y).cost == 0 && world (backward.x, backward.y).cost == 0)
    {
        if (distAlongSlope == slope)
        {
            distAlongSlope = 0;
            if (ySlope)
            {
                forward.x++;
                backward.x++;
            }
            else
            {
                forward.y++;
                backward.y++;
            }
        }
        else
        {
            distAlongSlope += slopeDirection;
            if (ySlope)
            {
                forward.y += slopeDirection;
                backward.y += slopeDirection;
            }
            else
            {
                forward.x += slopeDirection;
                backward.x += slopeDirection;
            }
        }
    }

    return (world (forward.x, forward.y).cost == 0) ? backward : forward;
}

void search (uint id, const Point& start, const Point& predEnd, const Point& succEnd,
             tbb::concurrent_unordered_map<uint, uint>& tileIdsFound,
             std::unordered_map<uint, PathTile>& expandedTiles,
             std::vector<Point>& meetingTiles, tbb::concurrent_vector<std::pair<bool, uint>>& meetingTilesFound,
             const pathFind::World& world, std::mutex& m)
{
    PriorityQueue openTiles (world.getWidth (), world.getHeight (), [predEnd, succEnd] (uint x, uint y)
    {
        return  std::min ((x < predEnd.x ? predEnd.x - x : x - predEnd.x) + (y < predEnd.y ? predEnd.y - y : y - predEnd.y),
            (x < succEnd.x ? succEnd.x - x : x - succEnd.x) + (y < succEnd.y ? succEnd.y - y : y - succEnd.y));
    });
    openTiles.push (world (start.x, start.y), {start.x, start.y}, 0);

    // Used to determine the "farthest" thread that we have met
    // uint predIdMet = id, succIdMet = id;
    while (!meetingTilesFound[id].first || !meetingTilesFound[id + 1].first)
    {
        PathTile tile = openTiles.top ();
        openTiles.pop ();
        if (tile.xy().x == predEnd.x && tile.xy().y == predEnd.y)
        {
            meetingTilesFound[id].first = true;
            meetingTilesFound[id].second = id;
            m.lock ();
            meetingTiles[id] = tile.xy ();
            m.unlock ();
        }
        if(tile.xy().x == succEnd.x && tile.xy().y == succEnd.y)
        {
            meetingTilesFound[id + 1].first = true;
            meetingTilesFound[id + 1].second = id;
            m.lock ();
            meetingTiles[id + 1] = tile.xy ();
            m.unlock ();
        }

        auto tileFound = tileIdsFound.find(tile.getTile().id);
        if (tileFound != tileIdsFound.end ())
        {
            if ((tileFound->second == id || tileFound->second == id - 1) && !meetingTilesFound[id].first)
            {
                m.lock ();
                meetingTiles[id] = tile.xy ();
                m.unlock ();
                meetingTilesFound[id].first = true;
                meetingTilesFound[id].second = id; // Set who the author was for this discovery
            }
            else if (tileFound->second == id + 1 && !meetingTilesFound[id + 1].first)
            {
                m.lock ();
                meetingTiles[id + 1] = tile.xy ();
                m.unlock ();
                meetingTilesFound[id + 1].first = true;
                meetingTilesFound[id + 1].second = id; // Set who the author was for this discovery
            }
        }
        else
        {
            tileIdsFound[tile.getTile().id] = id;
        }
        expandedTiles[tile.getTile ().id] = tile;

        // Check each neighbor
        Point adjPoint {tile.xy ().x + 1, tile.xy ().y}; // east
        searchNeighbor (adjPoint, world, tile, openTiles, expandedTiles);

        adjPoint = {tile.xy ().x, tile.xy ().y + 1}; // south
        searchNeighbor (adjPoint, world, tile, openTiles, expandedTiles);

        adjPoint = {tile.xy ().x - 1, tile.xy ().y}; // west
        searchNeighbor (adjPoint, world, tile, openTiles, expandedTiles);

        adjPoint = {tile.xy ().x, tile.xy ().y - 1}; // north
        searchNeighbor (adjPoint, world, tile, openTiles, expandedTiles);
    }
}

void searchNeighbor (const Point& adjPoint, const World& world, const PathTile& tile,
    PriorityQueue& openTiles, const std::unordered_map<uint, PathTile>& expandedTiles)
{
    if (adjPoint.x < world.getWidth() && adjPoint.y < world.getHeight ())
    {
        World::tile_t worldTile = world (adjPoint.x, adjPoint.y);
        if (worldTile.cost != 0 &&
            expandedTiles.find (worldTile.id) == expandedTiles.end ())
        {
            openTiles.tryUpdateBestCost (worldTile, adjPoint, tile);
        }
    }
}
<commit_msg>Corrected totalCost output.<commit_after>/**
 * File        : ParDivide.cc
 * Description : Parallel divide search implementation. Makes rough
 *               guess of where certain equidistant points in the final
 *               path will be and "commits" them and searches out from
 *               each point (and start and end) in parallel. After
 *               connections have been made it does a final smoothing
 *               stage in case the original guesses are in highly
 *               non-optimal spots
 */

#include <iostream>
#include <fstream>
#include <sstream>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include <limits>
#include <cmath>
#include <chrono>
#include <thread>
#include <mutex>

#include <boost/lexical_cast.hpp>

#include "tbb/concurrent_unordered_map.h"
#include "tbb/concurrent_vector.h"

#include "algorithms/tools/PathTile.h"
#include "algorithms/tools/PriorityQueue.h"
#include "common/Results.h"

using namespace pathFind;

const std::string WORLD_DIR = "worlds";
const std::string WORLD_EXT = ".world";

const std::string ALG_NAME = "parDivide";

const uint numThreads = 4;

Point findStart (const World& world, uint numThreadsLeft, const Point& start, const Point& end);

void search (uint id, const Point& start, const Point& predEnd, const Point& succEnd,
             tbb::concurrent_unordered_map<uint, uint>& tileIdsFound,
             std::unordered_map<uint, PathTile>& expandedTiles,
             std::vector<Point>& meetingTiles, tbb::concurrent_vector<std::pair<bool, uint>>& meetingTilesFound,
             const pathFind::World& world, std::mutex& m);

void searchNeighbor (const Point& adjPoint, const World& world, const PathTile& tile,
    PriorityQueue& openTiles, const std::unordered_map<uint, PathTile>& expandedTiles);

int main (int args, char* argv[])
{
    // Program should be started with 5 command line parameter
    // that specifies the name of the world file to read from,
    // the start x, start y, end x, and end y
    if (args != 6 )
    {
        std::cout << "Incorrect inputs. Usage: <filename> <start x> <start y> <end x> <end y>" << std::endl;
        return EXIT_FAILURE;
    }

    // Parse the world file
    std::stringstream filename;
    filename << WORLD_DIR << "/" << argv[1] << WORLD_EXT;

    std::ifstream worldFile (filename.str (),
            std::ifstream::in | std::ifstream::binary);

    if (!worldFile)
    {
        std::cout << "World file doesn't exist." << std::endl;
        return EXIT_FAILURE;
    }
    pathFind::World world;

    worldFile >> world;

    // Parse the start and end points
    uint startX, startY, endX, endY;
    try
    {
        startX = boost::lexical_cast<uint> (argv[2]);
        startY = boost::lexical_cast<uint> (argv[3]);
        endX = boost::lexical_cast<uint> (argv[4]);
        endY = boost::lexical_cast<uint> (argv[5]);
    } catch (boost::bad_lexical_cast &e)
    {
        std::cout << "Start and end points failed to convert to numeric types" << std::endl;
        return EXIT_FAILURE;
    }

    auto t1 = std::chrono::high_resolution_clock::now();

    std::vector<Point> startPoints (numThreads);
    startPoints[0] = Point {startX, startY};
    if (numThreads > 1)
    {
        startPoints.back() = Point {endX, endY};
        uint i = 1;
        uint j = numThreads - 2;
        while (i < j)
        {
            startPoints[i] = findStart (world, j - i + 1, startPoints[i - 1], startPoints[j + 1]);
            startPoints[j] = findStart (world, j - i, startPoints[j + 1], startPoints[i]);
            i++;
            j--;
        }
        if (i == j)
        {
            startPoints[i] = findStart (world, 1, startPoints[i -1], startPoints[i + 1]);
        }
    }

    pathFind::PathTile fTile, rTile;

    std::vector<std::unordered_map<uint, PathTile>> expandedTiles (numThreads);
    tbb::concurrent_unordered_map<uint, uint> idsFound;
    std::vector<Point> meetingTiles (numThreads + 1);
    tbb::concurrent_vector<std::pair<bool, uint>> meetingTilesFound (numThreads + 1);
    std::mutex m;

    std::vector<std::thread> threads (numThreads);
    for (uint i = 0; i < numThreads; ++i)
    {
        threads[i] = std::thread (search, i, std::cref(startPoints[i]), std::cref((i == 0) ? startPoints[0] : startPoints[i - 1]),
                std::cref((i == numThreads - 1) ? startPoints[i] : startPoints[i + 1]), std::ref (idsFound), std::ref(expandedTiles[i]),
                std::ref(meetingTiles), std::ref (meetingTilesFound),
                std::cref(world), std::ref(m));
    }

    for (auto& t : threads)
    {
        t.join ();
    }

    auto t2 = std::chrono::high_resolution_clock::now();

    // Parse reverse results
    uint totalCost = 0;
    std::vector<Point> finalPath;
    finalPath.emplace_back (endX, endY);
    uint j = expandedTiles.size () - 1, i = meetingTiles.size () - 1;
    while (i > 0)
    {
        PathTile fTile = expandedTiles[j][(meetingTiles[i].y * world.getWidth ()) + meetingTiles[i].x];
        while (fTile.xy ().x != startPoints[j].x || fTile.xy ().y != startPoints[j].y)
        {
            fTile = expandedTiles[j][(fTile.bestTile ().y * world.getWidth()) + fTile.bestTile ().x];
            if (finalPath.back().x != fTile.xy().x || finalPath.back().y != fTile.xy().y)
            {
                totalCost += fTile.getTile().cost;
                finalPath.emplace_back(fTile.xy());
            }
        }

        --i;
        std::vector <Point> reversePath;
        PathTile rTile = expandedTiles[j][(meetingTiles[i].y * world.getWidth ()) + meetingTiles[i].x];
        while (rTile.xy ().x != startPoints[j].x || rTile.xy ().y != startPoints[j].y)
        {
            totalCost += rTile.getTile().cost;
            reversePath.emplace_back (rTile.xy ());
            rTile = expandedTiles[j][(rTile.bestTile ().y * world.getWidth ()) + rTile.bestTile ().x];
        }
        finalPath.insert(finalPath.end (), reversePath.rbegin (), reversePath.rend ());

        --j;
    }
    totalCost -= world (startX, startY).cost;

    writeResults (finalPath, argv[1], ALG_NAME,
            std::chrono::duration_cast<std::chrono::milliseconds>(t2-t1).count(), totalCost);

    return EXIT_SUCCESS;
}

Point findStart (const World& world, uint numThreadsLeft, const Point& start, const Point& end)
{
    if (start.x == end.x && start.y == end.y)
    {
        return start;
    }
    int diffX = static_cast<int> (end.x) - start.x;
    int diffY = static_cast<int> (end.y) - start.y;
    Point forward, backward;
    forward.x = static_cast<float> (diffX) / (numThreadsLeft + 1) + start.x;
    forward.y = static_cast<float> (diffY) / (numThreadsLeft + 1) + start.y;
    backward.x = forward.x;
    backward.y = forward.y;

    int slope;
    bool ySlope = true;
    if (abs (diffX) < abs (diffY))
    {
        slope = (diffY == 0) ? std::numeric_limits<int>::max () : -diffX / diffY;
    }
    else
    {
        slope = (diffX == 0) ? std::numeric_limits<int>::max () : -diffY / diffX;
        ySlope = false;
    }

    int distAlongSlope = 0;
    int slopeDirection = (slope >= 0) ? 1 : -1;
    while (world (forward.x, forward.y).cost == 0 && world (backward.x, backward.y).cost == 0)
    {
        if (distAlongSlope == slope)
        {
            distAlongSlope = 0;
            if (ySlope)
            {
                forward.x++;
                backward.x++;
            }
            else
            {
                forward.y++;
                backward.y++;
            }
        }
        else
        {
            distAlongSlope += slopeDirection;
            if (ySlope)
            {
                forward.y += slopeDirection;
                backward.y += slopeDirection;
            }
            else
            {
                forward.x += slopeDirection;
                backward.x += slopeDirection;
            }
        }
    }

    return (world (forward.x, forward.y).cost == 0) ? backward : forward;
}

void search (uint id, const Point& start, const Point& predEnd, const Point& succEnd,
             tbb::concurrent_unordered_map<uint, uint>& tileIdsFound,
             std::unordered_map<uint, PathTile>& expandedTiles,
             std::vector<Point>& meetingTiles, tbb::concurrent_vector<std::pair<bool, uint>>& meetingTilesFound,
             const pathFind::World& world, std::mutex& m)
{
    PriorityQueue openTiles (world.getWidth (), world.getHeight (), [predEnd, succEnd] (uint x, uint y)
    {
        return  std::min ((x < predEnd.x ? predEnd.x - x : x - predEnd.x) + (y < predEnd.y ? predEnd.y - y : y - predEnd.y),
            (x < succEnd.x ? succEnd.x - x : x - succEnd.x) + (y < succEnd.y ? succEnd.y - y : y - succEnd.y));
    });
    openTiles.push (world (start.x, start.y), {start.x, start.y}, 0);

    // Used to determine the "farthest" thread that we have met
    // uint predIdMet = id, succIdMet = id;
    while (!meetingTilesFound[id].first || !meetingTilesFound[id + 1].first)
    {
        PathTile tile = openTiles.top ();
        openTiles.pop ();
        if (tile.xy().x == predEnd.x && tile.xy().y == predEnd.y)
        {
            meetingTilesFound[id].first = true;
            meetingTilesFound[id].second = id;
            m.lock ();
            meetingTiles[id] = tile.xy ();
            m.unlock ();
        }
        if(tile.xy().x == succEnd.x && tile.xy().y == succEnd.y)
        {
            meetingTilesFound[id + 1].first = true;
            meetingTilesFound[id + 1].second = id;
            m.lock ();
            meetingTiles[id + 1] = tile.xy ();
            m.unlock ();
        }

        auto tileFound = tileIdsFound.find(tile.getTile().id);
        if (tileFound != tileIdsFound.end ())
        {
            if ((tileFound->second == id || tileFound->second == id - 1) && !meetingTilesFound[id].first)
            {
                m.lock ();
                meetingTiles[id] = tile.xy ();
                m.unlock ();
                meetingTilesFound[id].first = true;
                meetingTilesFound[id].second = id; // Set who the author was for this discovery
            }
            else if (tileFound->second == id + 1 && !meetingTilesFound[id + 1].first)
            {
                m.lock ();
                meetingTiles[id + 1] = tile.xy ();
                m.unlock ();
                meetingTilesFound[id + 1].first = true;
                meetingTilesFound[id + 1].second = id; // Set who the author was for this discovery
            }
        }
        else
        {
            tileIdsFound[tile.getTile().id] = id;
        }
        expandedTiles[tile.getTile ().id] = tile;

        // Check each neighbor
        Point adjPoint {tile.xy ().x + 1, tile.xy ().y}; // east
        searchNeighbor (adjPoint, world, tile, openTiles, expandedTiles);

        adjPoint = {tile.xy ().x, tile.xy ().y + 1}; // south
        searchNeighbor (adjPoint, world, tile, openTiles, expandedTiles);

        adjPoint = {tile.xy ().x - 1, tile.xy ().y}; // west
        searchNeighbor (adjPoint, world, tile, openTiles, expandedTiles);

        adjPoint = {tile.xy ().x, tile.xy ().y - 1}; // north
        searchNeighbor (adjPoint, world, tile, openTiles, expandedTiles);
    }
}

void searchNeighbor (const Point& adjPoint, const World& world, const PathTile& tile,
    PriorityQueue& openTiles, const std::unordered_map<uint, PathTile>& expandedTiles)
{
    if (adjPoint.x < world.getWidth() && adjPoint.y < world.getHeight ())
    {
        World::tile_t worldTile = world (adjPoint.x, adjPoint.y);
        if (worldTile.cost != 0 &&
            expandedTiles.find (worldTile.id) == expandedTiles.end ())
        {
            openTiles.tryUpdateBestCost (worldTile, adjPoint, tile);
        }
    }
}
<|endoftext|>


<commit_before>#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <time.h>
#include <netdb.h>
#include <tclap/CmdLine.h>

#include "stinger_utils/stinger_sockets.h"
#include "stinger_utils/timer.h"
#include "stinger_net/send_rcv.h"
#include "stinger_utils/csv.h"
#include "explore_csv.h"

#define LOG_AT_I 1
#include "stinger_core/stinger_error.h"

using namespace gt::stinger;

int
main(int argc, char *argv[])
{
  /* global options */
  int port;
  int batch_size;
  struct hostent * server = NULL;
  bool use_directed;
  float timeout;
  const char * filename = NULL;

  try {
    /* parse command line configuration */
    TCLAP::CmdLine cmd("STINGER CSV Stream", ' ', "1.0");

    TCLAP::ValueArg<int> portArg ("p", "port", "STINGER Stream Port", false, 10102, "port");
    cmd.add (portArg);

    TCLAP::ValueArg<int> batchArg ("x", "batchsize", "Number of edges per batch", false, 1000, "edges");
    cmd.add (batchArg);

    TCLAP::ValueArg<std::string> hostnameArg ("a", "host", "STINGER Server hostname", false, "localhost", "hostname");
    cmd.add (hostnameArg);

    TCLAP::SwitchArg directedSwitch ("d", "directed", "Set if graph edges are directed.  Otherwise edges are assumed undirected.", cmd, false);

    TCLAP::ValueArg<float> timeoutArg ("t", "timeout", "Timeout", false, 0.0, "seconds");
    cmd.add (timeoutArg);

    TCLAP::UnlabeledValueArg<std::string> filenameArg ("template", "Path to CSV template file", true, "", "filename");
    cmd.add (filenameArg);

    cmd.parse (argc, argv);

    port = portArg.getValue();
    batch_size = batchArg.getValue();
    use_directed = directedSwitch.getValue();
    timeout = timeoutArg.getValue();
    filename = filenameArg.getValue().c_str();

    server = gethostbyname(hostnameArg.getValue().c_str());
    if(NULL == server) {
      LOG_E_A("Hostname %s could not be resolved.", hostnameArg.getValue().c_str());
      exit(-1);
    }

  } catch (TCLAP::ArgException &e)
  { std::cerr << "error: " << e.error() << " for arg " << e.argId() << std::endl; return 0; }

  /* start the connection */
  int sock_handle = connect_to_batch_server (server, port);

  LOG_V_A("Connected to %s on port %d\n", server->h_name, port);

  EdgeCollectionSet edge_finder;

  FILE * fp = fopen(filename, "r");
  if (fp == NULL) {
    LOG_E_A ("Unable to open file: %s", filename);
    exit(-1);
  }

  char * buf = NULL, ** fields = NULL;
  uint64_t bufSize = 0, * lengths = NULL, fieldsSize = 0, count = 0;

  while (!feof(fp)) {
    readCSVLineDynamic(',', fp, &buf, &bufSize, &fields, &lengths, &fieldsSize, &count);
    if (count <= 1)
      continue;
    edge_finder.learn(fields, (int64_t *)lengths, count);
  }

  LOG_V("Printing learn");
  edge_finder.print();

  StingerBatch batch;
  if(use_directed) {
    batch.set_make_undirected(false);
  } else {
    batch.set_make_undirected(true);
  }
  batch.set_type(MIXED);
  batch.set_keep_alive(true);

  tic();
  double timesince = 0;
  while (!feof(stdin)) {
    int64_t count_read = readCSVLineDynamic(',', stdin, &buf, &bufSize, &fields, &lengths, &fieldsSize, &count);
    if (count > 1) {
      if(edge_finder.apply(batch, fields, (int64_t *)lengths, count, batch.metadata_size())) {
	batch.add_metadata(buf, count_read);
      }
    }
    timesince += toc();
    int64_t total_actions = batch.insertions_size() + batch.deletions_size();
    if(total_actions >= batch_size || (timeout > 0 && timesince >= timeout)) {
      LOG_I_A("Sending a batch of %ld actions", total_actions);
      send_message(sock_handle, batch);
      timesince = 0;
      batch.Clear();
      if(use_directed) {
	batch.set_make_undirected(false);
      } else {
	batch.set_make_undirected(true);
      }
      batch.set_type(MIXED);
      batch.set_keep_alive(true);
    }
  }

  int64_t total_actions = batch.insertions_size() + batch.deletions_size();
  if(total_actions) {
    LOG_I_A("Sending a batch of %ld actions", total_actions);
    send_message(sock_handle, batch);
  }

  free(buf); free(fields); free(lengths);
  return 0;
}
<commit_msg>Revert "Using TCLAP with the CSV stream"<commit_after>#include <cstdlib>
#include <cstring>
#include <sys/types.h>
#include <time.h>
#include <netdb.h>

#include "stinger_utils/stinger_sockets.h"
#include "stinger_utils/timer.h"
#include "stinger_net/send_rcv.h"
#include "stinger_utils/csv.h"
#include "explore_csv.h"

using namespace gt::stinger;

#define E_A(X,...) fprintf(stderr, "%s %s %d:\n\t" #X "\n", __FILE__, __func__, __LINE__, __VA_ARGS__);
#define E(X) E_A(X,NULL)
#define V_A(X,...) fprintf(stdout, "%s %s %d:\n\t" #X "\n", __FILE__, __func__, __LINE__, __VA_ARGS__);
#define V(X) V_A(X,NULL)

#define LOG_AT_I 1
#include "stinger_core/stinger_error.h"

int
main(int argc, char *argv[])
{
  /* global options */
  int port = 10102;
  int batch_size = 1000;
  double timeout = 0;
  struct hostent * server = NULL;
  char * filename = NULL;
  int use_directed = 0;

  int opt = 0;
  while(-1 != (opt = getopt(argc, argv, "p:a:x:t:d"))) {
    switch(opt) {
      case 'p': {
		  port = atoi(optarg);
		} break;

      case 'x': {
		  batch_size = atol(optarg);
		  LOG_I_A("Batch size changed to %d", batch_size);
		} break;

      case 'a': {
		  server = gethostbyname(optarg);
		  if(NULL == server) {
		    LOG_E_A("ERROR: server %s could not be resolved.", optarg);
		    exit(-1);
		  }
		} break;
      case 'd': {
		  use_directed = 1;
		} break;
      case 't': {
	timeout = atof(optarg);
      } break;

      case '?':
      case 'h': {
		  printf("Usage:    %s [-p port] [-a server_addr] [-t timeout] [-x batch_size] filename\n", argv[0]);
		  printf("Defaults:\n\tport: %d\n\tserver: localhost\n\ttimeout:%lf\n\tbatch_size: %d", port, timeout, batch_size);
		  exit(0);
		} break;
    }
  }

  if (optind < argc && 0 != strcmp (argv[optind], "-")) {
    filename = argv[optind];
  } else {
    LOG_E("No filename given.");
    return -1;
  }

  LOG_V_A("Running with: port: %d\n", port);

  /* connect to localhost if server is unspecified */
  if(NULL == server) {
    server = gethostbyname("localhost");
    if(NULL == server) {
      LOG_E_A("ERROR: server %s could not be resolved.", "localhost");
      exit(-1);
    }
  }

  /* start the connection */
  int sock_handle = connect_to_batch_server (server, port);

  EdgeCollectionSet edge_finder;

  FILE * fp = fopen(filename, "r");
  char * buf = NULL, ** fields = NULL;
  uint64_t bufSize = 0, * lengths = NULL, fieldsSize = 0, count = 0;

  while (!feof(fp)) {
    readCSVLineDynamic(',', fp, &buf, &bufSize, &fields, &lengths, &fieldsSize, &count);
    if (count <= 1)
      continue;
    edge_finder.learn(fields, (int64_t *)lengths, count);
  }

  LOG_V("Printing learn");
  edge_finder.print();

  StingerBatch batch;
  if(use_directed) {
    batch.set_make_undirected(false);
  } else {
    batch.set_make_undirected(true);
  }
  batch.set_type(MIXED);
  batch.set_keep_alive(true);

  tic();
  double timesince = 0;
  while (!feof(stdin)) {
    int64_t count_read = readCSVLineDynamic(',', stdin, &buf, &bufSize, &fields, &lengths, &fieldsSize, &count);
    if (count > 1) {
      if(edge_finder.apply(batch, fields, (int64_t *)lengths, count, batch.metadata_size())) {
	batch.add_metadata(buf, count_read);
      }
    }
    timesince += toc();
    int64_t total_actions = batch.insertions_size() + batch.deletions_size();
    if(total_actions >= batch_size || (timeout > 0 && timesince >= timeout)) {
      LOG_I_A("Sending a batch of %ld actions", total_actions);
      send_message(sock_handle, batch);
      timesince = 0;
      batch.Clear();
      if(use_directed) {
	batch.set_make_undirected(false);
      } else {
	batch.set_make_undirected(true);
      }
      batch.set_type(MIXED);
      batch.set_keep_alive(true);
    }
  }

  int64_t total_actions = batch.insertions_size() + batch.deletions_size();
  if(total_actions) {
    LOG_I_A("Sending a batch of %ld actions", total_actions);
    send_message(sock_handle, batch);
  }

  free(buf); free(fields); free(lengths);
  return 0;
}
<|endoftext|>


<commit_before>/*
 * Problem Statement:
 * http://www.topcoder.com/stat?c=problem_statement&pm=10152&rd=13952&rm=&cr=22684375
 * */

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

using namespace std;

class Xosceles{

	public:
		vector <string> draw(int xCount)
		{
			vector <string> ans;
			string st;
			int n = sqrt(xCount);
			int lastval=0;
			int i,j;
			if (pow(n, 2) == xCount)
				lastval = 2*n -1;
			else if ((n * (n+1)) == xCount)
					lastval = 2*n;
			for (i=0;i<n;i++)
			{
				st.assign(lastval, 'X');
				j = i;
				while (j)
				{
					st[j-1] = '.';
					st[lastval - j] =  '.';
					j--;
				}
				ans.push_back(st);
			}

			reverse(ans.begin(), ans.end());
			return ans;
		}
};

int main(int argc, char *argv[])
{
	Xosceles obj;
	vector<string> xosceles_tri;
	xosceles_tri = obj.draw(2550);
	for (int i=0; i <xosceles_tri.size(); i++)
		cout<<xosceles_tri[i]<<endl;
}
<commit_msg>Minor changes to Xosceles problem. Even this is solved.<commit_after>/*
 * Problem Statement:
 * http://www.topcoder.com/stat?c=problem_statement&pm=10152&rd=13952&rm=&cr=22684375
 * */

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

using namespace std;

class Xosceles{

	public:
		vector <string> draw(int xCount)
		{
			vector <string> ans;
			string st;
			int n = sqrt(xCount);
			int lastval=0;
			int i,j;
			if (pow(n, 2) == xCount)
				lastval = 2*n -1;
			else if ((n * (n+1)) == xCount)
					lastval = 2*n;
			else
				return ans;
			for (i=0;i<n;i++)
			{
				st.assign(lastval, 'X');
				j = i;
				while (j)
				{
					st[j-1] = '.';
					st[lastval - j] =  '.';
					j--;
				}
				ans.push_back(st);
			}

			reverse(ans.begin(), ans.end());
			return ans;
		}
};

int main(int argc, char *argv[])
{
	Xosceles obj;
	vector<string> xosceles_tri;
	xosceles_tri = obj.draw(2550);
	for (int i=0; i <xosceles_tri.size(); i++)
		cout<<xosceles_tri[i]<<endl;
}
<|endoftext|>


<commit_before>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit (ITK)
  Module:    itkImageToImageAffineNormalizedCorrelationGradientDescentRegistrationTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2000 National Library of Medicine
All rights reserved.

See COPYRIGHT.txt for copyright details.

=========================================================================*/
#include "itkPhysicalImage.h"
#include "itkSimpleImageRegionIterator.h"
#include "itkImageToImageAffineNormalizedCorrelationGradientDescentRegistration.h"

/**
 *  This test uses two 2D-Gaussians (standard deviation RegionSize/2)
 *  One is shifted by 7,3 pixels from the other.
 *  therefore the solution of the registration is |-7 -3|
 *  This test uses LevenbergMarquart Optimizer but
 *  conjugate gradient optimizer tolerances are also defined
 *  in the itkImageToImageAffineNormalizedCorrelationGradientDescentRegistration.txx file
 *  (you need to change the type of the optimizer in the header file
 *  ie itkImageToImageAffineNormalizedCorrelationGradientDescentRegistration.h)
 */

int main()
{

  /*Allocate Images*/
  typedef itk::PhysicalImage<unsigned char,2>           ReferenceType;
  typedef itk::PhysicalImage<unsigned char,2>           TargetType;

  typedef itk::ImageToImageAffineNormalizedCorrelationGradientDescentRegistration<ReferenceType,TargetType> RegistrationType;

  ReferenceType::SizeType size = {{100,100}};
  ReferenceType::IndexType index = {{0,0}};
  ReferenceType::RegionType region;
  region.SetSize( size );
  region.SetIndex( index );

  ReferenceType::Pointer imgReference = ReferenceType::New();
  imgReference->SetLargestPossibleRegion( region );
  imgReference->SetBufferedRegion( region );
  imgReference->SetRequestedRegion( region );
  imgReference->Allocate();

  TargetType::Pointer imgTarget = TargetType::New();
  imgTarget->SetLargestPossibleRegion( region );
  imgTarget->SetBufferedRegion( region );
  imgTarget->SetRequestedRegion( region );
  imgTarget->Allocate();

  /* Fill images with a 2D gaussian*/
  typedef  itk::SimpleImageRegionIterator<ReferenceType> ReferenceIteratorType;

  typedef  itk::SimpleImageRegionIterator<TargetType> TargetIteratorType;

  itk::Point<double,2> center;
  center[0] = (double)region.GetSize()[0]/2.0;
  center[1] = (double)region.GetSize()[1]/2.0;

  const double s = (double)region.GetSize()[0]/2.0;

  itk::Point<double,2>  p;
  itk::Vector<double,2> d;

  /* Set the displacement */
  itk::Vector<double,2> displacement;
  displacement[0] = 7;
  displacement[1] = 3;

  ReferenceIteratorType ri(imgReference,region);
  TargetIteratorType ti(imgTarget,region);
  ri.Begin();
  while(!ri.IsAtEnd())
  {
    p[0] = ri.GetIndex()[0];
    p[1] = ri.GetIndex()[1];
    d = p-center;
    d += displacement;
    const double x = d[0];
    const double y = d[1];
    ri.Set( 200.0 * exp( - ( x*x + y*y )/(s*s) ) );
    ++ri;
  }

  ti.Begin();
  while(!ti.IsAtEnd())
  {
    p[0] = ti.GetIndex()[0];
    p[1] = ti.GetIndex()[1];
    d = p-center;
    const double x = d[0];
    const double y = d[1];
    ti.Set( 200.0 * exp( - ( x*x + y*y )/(s*s) ) );
    ++ti;
  }

  RegistrationType::Pointer registrationMethod = RegistrationType::New();

  registrationMethod->SetReference(imgReference);
  registrationMethod->SetTarget(imgTarget);
  registrationMethod->SetTranslationScale( 1e4 );

  registrationMethod->GetOptimizer()->SetLearningRate(1e-6);
  registrationMethod->GetOptimizer()->SetNumberOfIterations(100);

  registrationMethod->StartRegistration();

  std::cout << "The correct answer should be : " << std::endl;
  std::cout << " 1.0    0.0    0.0    1.0  ";
  std::cout << -displacement << std::endl;

  return EXIT_SUCCESS;

}
<commit_msg>ENH: Quantitative test added<commit_after>/*=========================================================================

  Program:   Insight Segmentation & Registration Toolkit (ITK)
  Module:    itkImageToImageAffineNormalizedCorrelationGradientDescentRegistrationTest.cxx
  Language:  C++
  Date:      $Date$
  Version:   $Revision$

Copyright (c) 2000 National Library of Medicine
All rights reserved.

See COPYRIGHT.txt for copyright details.

=========================================================================*/
#include "itkPhysicalImage.h"
#include "itkSimpleImageRegionIterator.h"
#include "itkImageToImageAffineNormalizedCorrelationGradientDescentRegistration.h"

/**
 *  This test uses two 2D-Gaussians (standard deviation RegionSize/2)
 *  One is shifted by 7,3 pixels from the other.
 *  therefore the solution of the registration is |-7 -3|
 *  This test uses LevenbergMarquart Optimizer but
 *  conjugate gradient optimizer tolerances are also defined
 *  in the itkImageToImageAffineNormalizedCorrelationGradientDescentRegistration.txx file
 *  (you need to change the type of the optimizer in the header file
 *  ie itkImageToImageAffineNormalizedCorrelationGradientDescentRegistration.h)
 */

int main()
{

  /*Allocate Images*/
  typedef itk::PhysicalImage<unsigned char,2>           ReferenceType;
  typedef itk::PhysicalImage<unsigned char,2>           TargetType;

  typedef itk::ImageToImageAffineNormalizedCorrelationGradientDescentRegistration<ReferenceType,TargetType> RegistrationType;

  ReferenceType::SizeType size = {{100,100}};
  ReferenceType::IndexType index = {{0,0}};
  ReferenceType::RegionType region;
  region.SetSize( size );
  region.SetIndex( index );

  ReferenceType::Pointer imgReference = ReferenceType::New();
  imgReference->SetLargestPossibleRegion( region );
  imgReference->SetBufferedRegion( region );
  imgReference->SetRequestedRegion( region );
  imgReference->Allocate();

  TargetType::Pointer imgTarget = TargetType::New();
  imgTarget->SetLargestPossibleRegion( region );
  imgTarget->SetBufferedRegion( region );
  imgTarget->SetRequestedRegion( region );
  imgTarget->Allocate();

  /* Fill images with a 2D gaussian*/
  typedef  itk::SimpleImageRegionIterator<ReferenceType> ReferenceIteratorType;

  typedef  itk::SimpleImageRegionIterator<TargetType> TargetIteratorType;

  itk::Point<double,2> center;
  center[0] = (double)region.GetSize()[0]/2.0;
  center[1] = (double)region.GetSize()[1]/2.0;

  const double s = (double)region.GetSize()[0]/2.0;

  itk::Point<double,2>  p;
  itk::Vector<double,2> d;

  /* Set the displacement */
  itk::Vector<double,2> displacement;
  displacement[0] = 7;
  displacement[1] = 3;

  ReferenceIteratorType ri(imgReference,region);
  TargetIteratorType ti(imgTarget,region);
  ri.Begin();
  while(!ri.IsAtEnd())
  {
    p[0] = ri.GetIndex()[0];
    p[1] = ri.GetIndex()[1];
    d = p-center;
    d += displacement;
    const double x = d[0];
    const double y = d[1];
    ri.Set( 200.0 * exp( - ( x*x + y*y )/(s*s) ) );
    ++ri;
  }

  ti.Begin();
  while(!ti.IsAtEnd())
  {
    p[0] = ti.GetIndex()[0];
    p[1] = ti.GetIndex()[1];
    d = p-center;
    const double x = d[0];
    const double y = d[1];
    ti.Set( 200.0 * exp( - ( x*x + y*y )/(s*s) ) );
    ++ti;
  }

  RegistrationType::Pointer registrationMethod = RegistrationType::New();

  const double translationScale = 1e4;

  registrationMethod->SetReference(imgReference);
  registrationMethod->SetTarget(imgTarget);
  registrationMethod->SetTranslationScale( translationScale );

  registrationMethod->GetOptimizer()->SetLearningRate(1e-6);
  registrationMethod->GetOptimizer()->SetNumberOfIterations(100);

  registrationMethod->StartRegistration();

  // get the results
  RegistrationType::ParametersType solution =
    registrationMethod->GetOptimizer()->GetCurrentPosition();

  std::cout << "Solution is: " << solution << std::endl;

  //
  // check results to see if it is within range
  //
  bool pass = true;
  double trueParameters[6] = { 1, 0, 0, 1, -7, -3 };
  for( unsigned int j = 0; j < 4; j++ )
    {
    if( vnl_math_abs( solution[j] - trueParameters[j] ) > 0.02 )
      pass = false;
    }
  for( unsigned int j = 4; j < 6; j++ )
    {
    if( vnl_math_abs( solution[j] * translationScale - trueParameters[j] ) > 1.0 )
      pass = false;
    }

  if( !pass )
    {
    std::cout << "Test failed." << std::endl;
    return EXIT_FAILURE;
    }

  std::cout << "Test passed." << std::endl;
  return EXIT_SUCCESS;

}
<|endoftext|>


<commit_before>#include <gtest/gtest.h>
#include <string>
#include <iostream>
#include <memory>
#include <vector>
#include <fstream>
#include <thread>
#include <mutex>
#include "../src/InotifyFileWatcher.hpp"
#include "common/RC2Utils.hpp"

using namespace std;

namespace RC2 {
namespace testing {

	void
	writeDummyFile(string fname)
	{
		ofstream file;
		file.open(fname);
		file << "data here" << endl;
		file.close();
	}

	void
	modifyDummyFile(string fname)
	{
		ofstream file;
		file.open(fname, ofstream::out | ofstream::app);
		file << "data here" << endl;
		file.close();
	}

	TEST(InotifyWatcherTest, simpleAddTest)
	{
		event_base *eb = event_base_new();
		InotifyFileWatcher watcher(eb);
		vector<string> added, modified, deleted;
		TemporaryDirectory tmpDir;
		mutex mx;

		watcher.initializeWatcher(tmpDir.getPath());
		watcher.startWatch();

		//add a foo object
		string tfilename = tmpDir.getPath() + "/foo";
		mx.lock();
		thread t([&] () {
			unique_lock<mutex> ulock(mx);
			writeDummyFile(tfilename);
			event_base_loopbreak(eb);
		});
		mx.unlock();

		event_base_loop(eb, EVLOOP_ONCE);
		watcher.stopWatch(added, modified, deleted);

		ASSERT_TRUE(added.size() == 1);
		ASSERT_TRUE(modified.size() == 0);
		ASSERT_TRUE(deleted.size() == 0);
		//wait for bg threads to continue
		t.join();

		event_base_free(eb);
	}

	TEST(InotifyWatcherTest, simpleModifyTest)
	{
		TemporaryDirectory tmpDir;
		string tfilename = tmpDir.getPath() + "/foo";
		writeDummyFile(tfilename);

		event_base *eb = event_base_new();
		InotifyFileWatcher watcher(eb);
		vector<string> added, modified, deleted;

		watcher.initializeWatcher(tmpDir.getPath());
		watcher.startWatch();

		//modify a foo object
		mutex mx;
		mx.lock();
		thread t([&] () {
			unique_lock<mutex> ulock(mx);
			modifyDummyFile(tfilename);
			event_base_loopbreak(eb);
		});
		mx.unlock();

		event_base_loop(eb, EVLOOP_ONCE); //modified
		event_base_loop(eb, EVLOOP_ONCE); //closed w/write
		watcher.stopWatch(added, modified, deleted);

		ASSERT_TRUE(added.size() == 0);
		ASSERT_TRUE(modified.size() == 1);
		ASSERT_TRUE(deleted.size() == 0);
		//wait for bg threads to continue
		t.join();

		event_base_free(eb);
	}

};
};
<commit_msg>sets boost log level across all tests in test case<commit_after>#include <gtest/gtest.h>
#include <string>
#include <iostream>
#include <memory>
#include <vector>
#include <fstream>
#include <thread>
#include <mutex>
#include <boost/filesystem.hpp>
#include <boost/log/trivial.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include "../src/InotifyFileWatcher.hpp"
#include "common/RC2Utils.hpp"

using namespace std;

namespace RC2 {
namespace testing {

	void
	writeDummyFile(string fname)
	{
		ofstream file;
		file.open(fname);
		file << "data here" << endl;
		file.close();
	}

	void
	modifyDummyFile(string fname)
	{
		ofstream file;
		file.open(fname, ofstream::out | ofstream::app);
		file << "data here" << endl;
		file.close();
	}

	class InotifyWatcherTest : public ::testing::Test {
		protected:
			static void SetUpTestCase() {
				boost::log::core::get()->set_filter(
					boost::log::trivial::severity >= (boost::log::trivial::warning)
				);
			}
	};

	TEST_F(InotifyWatcherTest, simpleAddTest)
	{
		event_base *eb = event_base_new();
		InotifyFileWatcher watcher(eb);
		vector<string> added, modified, deleted;
		TemporaryDirectory tmpDir;
		mutex mx;

		watcher.initializeWatcher(tmpDir.getPath());
		watcher.startWatch();

		//add a foo object
		string tfilename = tmpDir.getPath() + "/foo";
		mx.lock();
		thread t([&] () {
			unique_lock<mutex> ulock(mx);
			writeDummyFile(tfilename);
			event_base_loopbreak(eb);
		});
		mx.unlock();

		event_base_loop(eb, EVLOOP_ONCE);
		watcher.stopWatch(added, modified, deleted);

		ASSERT_TRUE(added.size() == 1);
		ASSERT_TRUE(modified.size() == 0);
		ASSERT_TRUE(deleted.size() == 0);
		//wait for bg threads to continue
		t.join();

		event_base_free(eb);
	}

	TEST_F(InotifyWatcherTest, simpleModifyTest)
	{
		TemporaryDirectory tmpDir;
		string tfilename = tmpDir.getPath() + "/foo";
		writeDummyFile(tfilename);

		event_base *eb = event_base_new();
		InotifyFileWatcher watcher(eb);
		vector<string> added, modified, deleted;

		watcher.initializeWatcher(tmpDir.getPath());
		watcher.startWatch();

		//modify a foo object
		mutex mx;
		mx.lock();
		thread t([&] () {
			unique_lock<mutex> ulock(mx);
			modifyDummyFile(tfilename);
			event_base_loopbreak(eb);
		});
		mx.unlock();

		event_base_loop(eb, EVLOOP_ONCE); //modified
		event_base_loop(eb, EVLOOP_ONCE); //closed w/write
		watcher.stopWatch(added, modified, deleted);

		ASSERT_TRUE(added.size() == 0);
		ASSERT_TRUE(modified.size() == 1);
		ASSERT_TRUE(deleted.size() == 0);
		//wait for bg threads to continue
		t.join();

		event_base_free(eb);
	}

};
};
<|endoftext|>


<commit_before><commit_msg>-Werror,-Wnon-literal-null-conversion (Clang towards 3.2)<commit_after><|endoftext|>


<commit_before><commit_msg>Align transparency cut-off with application defaults<commit_after><|endoftext|>


<commit_before><commit_msg>Generalize the check for a recode table<commit_after><|endoftext|>


<commit_before><commit_msg>Resolves: fdo#68192 always recode from trad symbol to apple symbol<commit_after><|endoftext|>


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

// ---
// Author: Rebecca Shapiro <bxx@google.com>
//
// This file contains functions that implement doubly linked and
// singly linked lists.  The singly linked lists are null terminated,
// use raw pointers to link neighboring elements, and these pointers
// are stored at the start of each element, independently of the
// elements's size.  Because pointers are stored within each element,
// each element must be large enough to store two raw pointers if
// doubly linked lists are employed, or one raw pointer if singly
// linked lists are employed.  On machines with 64 bit pointers, this
// means elements must be at least 16 bytes in size for doubly linked
// list support, and 8 bytes for singly linked list support.  No
// attempts are made to preserve the data in elements stored in the
// list.
//
// Given a machine with pointers of size N (on a 64bit machine N=8, on
// a 32bit machine, N=4), the list pointers are stored in the
// following manner:
// -In doubly linked lists, the |next| pointer is stored in the first N
// bytes of the node and the |previous| pointer is writtend into the
// second N bytes.
// -In singly linked lists, the |next| pointer is stored in the first N
// bytes of the node.
//
// For both types of lists: when a pop operation is performed on a non
// empty list, the new list head becomes that which is pointed to by
// the former head's |next| pointer.  If the list is doubly linked, the
// new head |previous| pointer gets changed from pointing to the former
// head to NULL.

#include <stddef.h>
#include "free_list.h"

#if defined(TCMALLOC_USE_DOUBLYLINKED_FREELIST)

using tcmalloc::kCrash;

// TODO(jar): We should use C++ rather than a macro here.
#define MEMORY_CHECK(v1, v2) \
  if (v1 != v2) Log(kCrash, __FILE__, __LINE__, "Memory corruption detected.")

namespace {
void EnsureNonLoop(void* node, void* next) {
  // We only have time to do minimal checking.  We don't traverse the list, but
  // only look for an immediate loop (cycle back to ourself).
  if (node != next) return;
  Log(kCrash, __FILE__, __LINE__, "Circular loop in list detected: ", next);
}

// Returns value of the |previous| pointer w/out running a sanity
// check.
inline void *FL_Previous_No_Check(void *t) {
  return reinterpret_cast<void**>(t)[1];
}

// Returns value of the |next| pointer w/out running a sanity check.
inline void *FL_Next_No_Check(void *t) {
  return reinterpret_cast<void**>(t)[0];
}

void *FL_Previous(void *t) {
  void *previous = FL_Previous_No_Check(t);
  if (previous) {
    MEMORY_CHECK(FL_Next_No_Check(previous), t);
  }
  return previous;
}

inline void FL_SetPrevious(void *t, void *n) {
  EnsureNonLoop(t, n);
  reinterpret_cast<void**>(t)[1] = n;
}

inline void FL_SetNext(void *t, void *n) {
  EnsureNonLoop(t, n);
  reinterpret_cast<void**>(t)[0] = n;
}

} // namespace

namespace tcmalloc {

void *FL_Next(void *t) {
  void *next = FL_Next_No_Check(t);
  if (next) {
    MEMORY_CHECK(FL_Previous_No_Check(next), t);
  }
  return next;
}

// Makes the element at |t| a singleton doubly linked list.
void FL_Init(void *t) {
  FL_SetPrevious(t, NULL);
  FL_SetNext(t, NULL);
}

// Pushes element to a linked list whose first element is at
// |*list|. When this call returns, |list| will point to the new head
// of the linked list.
void FL_Push(void **list, void *element) {
  void *old = *list;
  if (old == NULL) { // Builds singleton list.
    FL_Init(element);
  } else {
    ASSERT(FL_Previous_No_Check(old) == NULL);
    FL_SetNext(element, old);
    FL_SetPrevious(old, element);
    FL_SetPrevious(element, NULL);
  }
  *list = element;
}

// Pops the top element off the linked list whose first element is at
// |*list|, and updates |*list| to point to the next element in the
// list.  Returns the address of the element that was removed from the
// linked list.  |list| must not be NULL.
void *FL_Pop(void **list) {
  void *result = *list;
  ASSERT(FL_Previous_No_Check(result) == NULL);
  *list = FL_Next(result);
  if (*list != NULL) {
    FL_SetPrevious(*list, NULL);
  }
  return result;
}

// Remove |n| elements from linked list at whose first element is at
// |*head|.  |head| will be modified to point to the new head.
// |start| will point to the first node of the range, |end| will point
// to the last node in the range. |n| must be <= FL_Size(|*head|)
// If |n| > 0, |head| must not be NULL.
void FL_PopRange(void **head, int n, void **start, void **end) {
  if (n == 0) {
    *start = NULL;
    *end = NULL;
    return;
  }

  *start = *head; // Remember the first node in the range.
  void *tmp = *head;
  for (int i = 1; i < n; ++i) { // Find end of range.
    tmp = FL_Next(tmp);
  }
  *end = tmp; // |end| now set to point to last node in range.
  *head = FL_Next(*end);
  FL_SetNext(*end, NULL); // Unlink range from list.

  if (*head ) { // Fixup popped list.
    FL_SetPrevious(*head, NULL);
  }
}

// Pushes the nodes in the list begginning at |start| whose last node
// is |end| into the linked list at |*head|. |*head| is updated to
// point be the new head of the list.  |head| must not be NULL.
void FL_PushRange(void **head, void *start, void *end) {
  if (!start) return;

  // Sanity checking of ends of list to push is done by calling
  // FL_Next and FL_Previous.
  FL_Next(start);
  FL_Previous(end);
  ASSERT(FL_Previous_No_Check(start) == NULL);
  ASSERT(FL_Next_No_Check(end) == NULL);

  if (*head) {
    MEMORY_CHECK(FL_Previous_No_Check(*head), NULL);
    FL_SetNext(end, *head);
    FL_SetPrevious(*head, end);
  }
  *head = start;
}

// Calculates the size of the list that begins at |head|.
size_t FL_Size(void *head){
  int count = 0;
  if (head) {
    MEMORY_CHECK(FL_Previous_No_Check(head), NULL);
  }
  while (head) {
    count++;
    head = FL_Next(head);
  }
  return count;
}

} // namespace tcmalloc

#else
#include "linked_list.h" // for SLL_SetNext

namespace {

inline void FL_SetNext(void *t, void *n) {
  tcmalloc::SLL_SetNext(t,n);
}

}

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

// ---
// Author: Rebecca Shapiro <bxx@google.com>
//
// This file contains functions that implement doubly linked and
// singly linked lists.  The singly linked lists are null terminated,
// use raw pointers to link neighboring elements, and these pointers
// are stored at the start of each element, independently of the
// elements's size.  Because pointers are stored within each element,
// each element must be large enough to store two raw pointers if
// doubly linked lists are employed, or one raw pointer if singly
// linked lists are employed.  On machines with 64 bit pointers, this
// means elements must be at least 16 bytes in size for doubly linked
// list support, and 8 bytes for singly linked list support.  No
// attempts are made to preserve the data in elements stored in the
// list.
//
// Given a machine with pointers of size N (on a 64bit machine N=8, on
// a 32bit machine, N=4), the list pointers are stored in the
// following manner:
// -In doubly linked lists, the |next| pointer is stored in the first N
// bytes of the node and the |previous| pointer is writtend into the
// second N bytes.
// -In singly linked lists, the |next| pointer is stored in the first N
// bytes of the node.
//
// For both types of lists: when a pop operation is performed on a non
// empty list, the new list head becomes that which is pointed to by
// the former head's |next| pointer.  If the list is doubly linked, the
// new head |previous| pointer gets changed from pointing to the former
// head to NULL.

#include <limits>
#include <stddef.h>
#include "free_list.h"
#include "system-alloc.h"

#if defined(TCMALLOC_USE_DOUBLYLINKED_FREELIST)

using tcmalloc::kCrash;

// TODO(jar): We should use C++ rather than a macro here.
#define MEMORY_CHECK(v1, v2) \
  if (v1 != v2) Log(kCrash, __FILE__, __LINE__, "Memory corruption detected.")

namespace {
void EnsureNonLoop(void* node, void* next) {
  // We only have time to do minimal checking.  We don't traverse the list, but
  // only look for an immediate loop (cycle back to ourself).
  if (node != next) return;
  Log(kCrash, __FILE__, __LINE__, "Circular loop in list detected: ", next);
}

inline void* MaskPtr(void* p) {
  // Maximize ASLR entropy and guarantee the result is an invalid address.
  const uintptr_t q = ~(reinterpret_cast<intptr_t>(TCMalloc_SystemAlloc) >> 13);
  // Do not mask NULL pointers, otherwise we could leak address state.
  if (p)
    return reinterpret_cast<void*>(reinterpret_cast<uintptr_t>(p) ^ q);
  return p;
}

inline void* UnmaskPtr(void* p) {
  return MaskPtr(p);
}

// Returns value of the |previous| pointer w/out running a sanity
// check.
inline void *FL_Previous_No_Check(void *t) {
  return UnmaskPtr(reinterpret_cast<void**>(t)[1]);
}

// Returns value of the |next| pointer w/out running a sanity check.
inline void *FL_Next_No_Check(void *t) {
  return UnmaskPtr(reinterpret_cast<void**>(t)[0]);
}

void *FL_Previous(void *t) {
  void *previous = FL_Previous_No_Check(t);
  if (previous) {
    MEMORY_CHECK(FL_Next_No_Check(previous), t);
  }
  return previous;
}

inline void FL_SetPrevious(void *t, void *n) {
  EnsureNonLoop(t, n);
  reinterpret_cast<void**>(t)[1] = MaskPtr(n);
}

inline void FL_SetNext(void *t, void *n) {
  EnsureNonLoop(t, n);
  reinterpret_cast<void**>(t)[0] = MaskPtr(n);
}

} // namespace

namespace tcmalloc {

void *FL_Next(void *t) {
  void *next = FL_Next_No_Check(t);
  if (next) {
    MEMORY_CHECK(FL_Previous_No_Check(next), t);
  }
  return next;
}

// Makes the element at |t| a singleton doubly linked list.
void FL_Init(void *t) {
  FL_SetPrevious(t, NULL);
  FL_SetNext(t, NULL);
}

// Pushes element to a linked list whose first element is at
// |*list|. When this call returns, |list| will point to the new head
// of the linked list.
void FL_Push(void **list, void *element) {
  void *old = *list;
  if (old == NULL) { // Builds singleton list.
    FL_Init(element);
  } else {
    ASSERT(FL_Previous_No_Check(old) == NULL);
    FL_SetNext(element, old);
    FL_SetPrevious(old, element);
    FL_SetPrevious(element, NULL);
  }
  *list = element;
}

// Pops the top element off the linked list whose first element is at
// |*list|, and updates |*list| to point to the next element in the
// list.  Returns the address of the element that was removed from the
// linked list.  |list| must not be NULL.
void *FL_Pop(void **list) {
  void *result = *list;
  ASSERT(FL_Previous_No_Check(result) == NULL);
  *list = FL_Next(result);
  if (*list != NULL) {
    FL_SetPrevious(*list, NULL);
  }
  return result;
}

// Remove |n| elements from linked list at whose first element is at
// |*head|.  |head| will be modified to point to the new head.
// |start| will point to the first node of the range, |end| will point
// to the last node in the range. |n| must be <= FL_Size(|*head|)
// If |n| > 0, |head| must not be NULL.
void FL_PopRange(void **head, int n, void **start, void **end) {
  if (n == 0) {
    *start = NULL;
    *end = NULL;
    return;
  }

  *start = *head; // Remember the first node in the range.
  void *tmp = *head;
  for (int i = 1; i < n; ++i) { // Find end of range.
    tmp = FL_Next(tmp);
  }
  *end = tmp; // |end| now set to point to last node in range.
  *head = FL_Next(*end);
  FL_SetNext(*end, NULL); // Unlink range from list.

  if (*head ) { // Fixup popped list.
    FL_SetPrevious(*head, NULL);
  }
}

// Pushes the nodes in the list begginning at |start| whose last node
// is |end| into the linked list at |*head|. |*head| is updated to
// point be the new head of the list.  |head| must not be NULL.
void FL_PushRange(void **head, void *start, void *end) {
  if (!start) return;

  // Sanity checking of ends of list to push is done by calling
  // FL_Next and FL_Previous.
  FL_Next(start);
  FL_Previous(end);
  ASSERT(FL_Previous_No_Check(start) == NULL);
  ASSERT(FL_Next_No_Check(end) == NULL);

  if (*head) {
    MEMORY_CHECK(FL_Previous_No_Check(*head), NULL);
    FL_SetNext(end, *head);
    FL_SetPrevious(*head, end);
  }
  *head = start;
}

// Calculates the size of the list that begins at |head|.
size_t FL_Size(void *head){
  int count = 0;
  if (head) {
    MEMORY_CHECK(FL_Previous_No_Check(head), NULL);
  }
  while (head) {
    count++;
    head = FL_Next(head);
  }
  return count;
}

} // namespace tcmalloc

#else
#include "linked_list.h" // for SLL_SetNext

namespace {

inline void FL_SetNext(void *t, void *n) {
  tcmalloc::SLL_SetNext(t,n);
}

}

#endif // TCMALLOC_USE_DOUBLYLINKED_FREELIST
<|endoftext|>