text:
//Copyright (c) 2006-2013 Emil Dotchevski and Reverge Studios, Inc.

//Distributed under the Boost Software License, Version 1.0. (See accompanying
//file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

//This file tests the N3757 syntax for adding error info to std::exception, which is
//different from the syntax used by Boost Exception.

#include <boost/exception/N3757.hpp>
#include <boost/exception/diagnostic_information.hpp>
#include <boost/detail/lightweight_test.hpp>
#include <ostream>

struct tag1 { typedef int type; };
struct tag2 { typedef std::string type; };
struct tag3 { typedef int type; };

struct my_error_code { int ec; my_error_code(int ec):ec(ec){ } };
struct tag_error_code { typedef my_error_code type; };

bool my_error_code_to_string_called=false;

std::ostream &
operator<<( std::ostream & s, my_error_code const & x )
{
    my_error_code_to_string_called=true;
    return s << "my_error_code(" << x.ec << ')';
}

struct my_exception: virtual std::exception, virtual boost::exception { };

int
main()
    {
    try
        {
        throw my_exception();
        }
    catch(
	boost::exception & e )
        {
        e.set<tag1>(42);
        e.set<tag2>("42");
        e.set<tag_error_code>(42); //Implicit conversion
        try
            {
            throw;
            }
        catch(
        my_exception & e )
            {
            BOOST_TEST(e.get<tag1>() && *e.get<tag1>()==42);
            BOOST_TEST(e.get<tag2>() && *e.get<tag2>()=="42");
            BOOST_TEST(!e.get<tag3>());
            BOOST_TEST(e.get<tag_error_code>() && e.get<tag_error_code>()->ec==42);

            //Below we're verifying that an error code wrapped in a user-defined type
            //invokes the correct op<< to convert the error code to string.
            //Note that N3757 diagnostic_information uses different syntax, it is a
            //member of of std::exception.
            std::string di=boost::diagnostic_information(e);
            BOOST_TEST(!di.empty());
            BOOST_TEST(my_error_code_to_string_called);
            }
        }
    return boost::report_errors();
    }

max_stars_repo_name: Abce/boost


text:
//------------------------------------------------------------------------------
// Copyright (c) 2018 Hsienchi Kuo (Allen Institute, Hanchuan Peng's team)
// All rights reserved.
//------------------------------------------------------------------------------

/*******************************************************************************
*
*  Most of NeuronStructUtil class methods intend to operate on the whole neuron struct level.
*  As 'utility' it is called, the functionalities provided in this class include:
*    a. [Basic neuron struct operations]                   -- cropping SWC, scaling SWC, swc registration, etc.
*    b. [Tree - subtree operations]                        -- extracting upstream or downstream of a given tree.
*    c. [Neuron struct profiling methods]                  -- node-tile mapping, node-location mapping, etc.
*    d. [SWC - ImgAnalyzer::connectedComponent operations] -- Methods of this category convert SWC into vector<ImgAnalyzer::connectedComponent>
*
*  Most of NeuronStructUtil class methods are implemented as static functions. The input NeuronTree is always set to be const so that it will not be modified.
*  A typical function call would need at least three input arguments:
*
*		NeuronStructUtil::func(const NeuronTree& inputTree, NeuronTree& outputTree, other input arguments);
*
********************************************************************************/

#include <iostream>
#include <iterator>
#include <set>
#include <cmath>

#include <boost/filesystem.hpp>

#include "basic_4dimage.h"

#include "NeuronStructUtilities.h"
#include "ImgProcessor.h"

using namespace boost;

/* ======================================== Segment Operations ========================================= */
segUnit NeuronStructUtil::segUnitConnect_executer(const segUnit& segUnit1, const segUnit& segUnit2, connectOrientation connOrt)
{
	if (segUnit1.tails.size() > 1 || segUnit2.tails.size() > 1)
		throw invalid_argument("Currently forked segment connection is not supported. Do nothing and return");

	segUnit newSeg;
	QList<NeuronSWC> newSegNodes;
	QList<NeuronSWC> endEditedNodes;

	switch (connOrt)
	{
	case head_tail:
	{
		int connTailID = *segUnit2.tails.cbegin();
		endEditedNodes = segUnit1.nodes;
		endEditedNodes.begin()->parent = connTailID; // In current implementation, the 1st element of a seg must be a root.
		newSegNodes.append(segUnit2.nodes);
		newSegNodes.append(endEditedNodes);
		newSeg.nodes = newSegNodes;
		break;
	}
	case tail_head:
	{
		int connTailID = *segUnit1.tails.cbegin();
		endEditedNodes = segUnit2.nodes;
		endEditedNodes.begin()->parent = connTailID; // In current implementation, the 1st element of a seg must be a root.
		newSegNodes.append(segUnit1.nodes);
		newSegNodes.append(endEditedNodes);
		newSeg.nodes = newSegNodes;
		break;
	}
	case head_head:
	{
		int connTailID = segUnit2.head;
		for (map<int, vector<size_t>>::const_iterator it = segUnit2.seg_childLocMap.cbegin(); it != segUnit2.seg_childLocMap.cend(); ++it)
		{
			size_t nodeLoc = segUnit2.seg_nodeLocMap.at(it->first);
			NeuronSWC newNode = segUnit2.nodes.at(nodeLoc);
			if (it->second.empty())
			{
				//cout << newNode.x << " " << newNode.y << " " << newNode.z << endl;
				newNode.parent = -1;
			}
			else newNode.parent = segUnit2.nodes.at(*(it->second.cbegin())).n;
			endEditedNodes.push_back(newNode);
		}
		newSegNodes.append(segUnit1.nodes);
		newSegNodes.begin()->parent = connTailID;
		newSegNodes.append(endEditedNodes);
		newSeg.nodes = newSegNodes;
		break;
	}
	case tail_tail:
	{
		int connTailID = *segUnit2.tails.cbegin();
		for (map<int, vector<size_t>>::const_iterator it = segUnit1.seg_childLocMap.cbegin(); it != segUnit1.seg_childLocMap.cend(); ++it)
		{
			size_t nodeLoc = segUnit1.seg_nodeLocMap.at(it->first);
			NeuronSWC newNode = segUnit1.nodes.at(nodeLoc);
			if (it->second.empty()) newNode.parent = connTailID;
			else newNode.parent = segUnit1.nodes.at(*(it->second.cbegin())).n;
			endEditedNodes.push_back(newNode);
		}
		newSegNodes.append(segUnit2.nodes);
		newSegNodes.append(endEditedNodes);
		newSeg.nodes = newSegNodes;
		break;
	}
	default:
		break;
	}

	return newSeg;
}
/* ===================================================================================================== */

/* ===================================== Neuron Struct Processing ====================================== */
NeuronTree NeuronStructUtil::swcRegister(NeuronTree& inputTree, const NeuronTree& refTree)
{
	double xShift, yShift, zShift;
	double xScale, yScale, zScale;

	double xmin = 10000, ymin = 10000, zmin = 10000;
	double xmax = 0, ymax = 0, zmax = 0;
	for (QList<NeuronSWC>::iterator it = inputTree.listNeuron.begin(); it != inputTree.listNeuron.end(); ++it)
	{
		if (it->x < xmin) xmin = it->x;
		if (it->x > xmax) xmax = it->x;
		if (it->y < ymin) ymin = it->y;
		if (it->y > ymax) ymax = it->y;
		if (it->z < zmin) zmin = it->z;
		if (it->z > zmax) zmax = it->z;
	}
	double refXmin = 10000, refYmin = 10000, refZmin = 10000;
	double refXmax = 0, refYmax = 0, refZmax = 0;
	for (QList<NeuronSWC>::const_iterator refIt = refTree.listNeuron.begin(); refIt != refTree.listNeuron.end(); ++refIt)
	{
		if (refIt->x < refXmin) refXmin = refIt->x;
		if (refIt->x > refXmax) refXmax = refIt->x;
		if (refIt->y < refYmin) refYmin = refIt->y;
		if (refIt->y > refYmax) refYmax = refIt->y;
		if (refIt->z < refZmin) refZmin = refIt->z;
		if (refIt->z > refZmax) refZmax = refIt->z;
	}

	xScale = (refXmax - refXmin) / (xmax - xmin);
	yScale = (refYmax - refYmin) / (ymax - ymin);
	zScale = (refZmax - refZmin) / (zmax - zmin);
	xShift = refXmin - xmin * xScale;
	yShift = refYmin - ymin * yScale;
	zShift = refZmin - zmin * zScale;

	NeuronTree outputTree;
	for (int i = 0; i < inputTree.listNeuron.size(); ++i)
	{
		NeuronSWC newNode = inputTree.listNeuron.at(i);
		newNode.x = newNode.x * xScale + xShift;
		newNode.y = newNode.y * yScale + yShift;
		newNode.z = newNode.z * zScale + zShift;
		outputTree.listNeuron.push_back(newNode);
	}

	return outputTree;
}

NeuronTree NeuronStructUtil::swcCombine(const vector<NeuronTree>& inputTrees)
{
	NeuronTree outputTree;
	ptrdiff_t listSize = 0;
	int nodeIDmax = 0;
	for (vector<NeuronTree>::const_iterator it = inputTrees.begin(); it != inputTrees.end(); ++it)
	{
		for (QList<NeuronSWC>::iterator outputNodeIt = outputTree.listNeuron.begin(); outputNodeIt != outputTree.listNeuron.end(); ++outputNodeIt)
			if (outputNodeIt->n > nodeIDmax) nodeIDmax = outputNodeIt->n;

		outputTree.listNeuron.append(it->listNeuron);
		for (QList<NeuronSWC>::iterator nodeIt = outputTree.listNeuron.begin() + listSize; nodeIt != outputTree.listNeuron.end(); ++nodeIt)
		{
			nodeIt->n = nodeIt->n + nodeIDmax;
			if (nodeIt->parent == -1) continue;
			else nodeIt->parent = nodeIt->parent + nodeIDmax;
		}

		listSize = ptrdiff_t(outputTree.listNeuron.size());
	}

	return outputTree;
}

void NeuronStructUtil::swcSlicer(const NeuronTree& inputTree, vector<NeuronTree>& outputTrees, int thickness)
{
	QList<NeuronSWC> inputList = inputTree.listNeuron;
	int zMax = 0;
	ptrdiff_t thicknessPtrDiff = ptrdiff_t(thickness); // Determining largest number of z in inputTree.
	for (QList<NeuronSWC>::const_iterator it = inputTree.listNeuron.begin(); it != inputTree.listNeuron.end(); ++it)
	{
		int z = round(it->z);
		if (z >= zMax) zMax = z;
	}

	int treeNum = zMax / thickness + 1;
	vector<ptrdiff_t> delLocs;
	for (int i = 0; i < treeNum; ++i)
	{
		NeuronTree outputTree;
		outputTrees.push_back(outputTree);
		for (QList<NeuronSWC>::iterator it = inputList.begin(); it != inputList.end(); ++it)
		{
			if (it->z <= thickness * (i + 1))
			{
				outputTrees.at(i).listNeuron.push_back(*it);
				delLocs.push_back(it - inputList.begin());
			}
		}

		sort(delLocs.rbegin(), delLocs.rend());
		for (vector<ptrdiff_t>::iterator delIt = delLocs.begin(); delIt != delLocs.end(); ++delIt) inputList.erase(inputList.begin() + *delIt);
		delLocs.clear();
	}
}

map<int, QList<NeuronSWC>> NeuronStructUtil::swcSplitByType(const NeuronTree& inputTree)
{
	map<int, QList<NeuronSWC>> outputNodeTypeMap;
	map<int, boost::container::flat_set<int>> nodeIDsetMap;
	for (QList<NeuronSWC>::const_iterator it = inputTree.listNeuron.begin(); it != inputTree.listNeuron.end(); ++it)
	{
		outputNodeTypeMap[it->type].append(*it);
		nodeIDsetMap[it->type].insert(it->n);
	}
	for (map<int, QList<NeuronSWC>>::iterator mapIt = outputNodeTypeMap.begin(); mapIt != outputNodeTypeMap.end(); ++mapIt)
	{
		for (QList<NeuronSWC>::iterator nodeIt = mapIt->second.begin(); nodeIt != mapIt->second.end(); ++nodeIt)
		{
			if (nodeIt->parent == -1) continue;
			else if (nodeIDsetMap.at(nodeIt->type).find(nodeIt->parent) == nodeIDsetMap.at(nodeIt->type).end()) nodeIt->parent = -1;
		}
	}

	return outputNodeTypeMap;
}

NeuronTree NeuronStructUtil::swcSubtraction(const NeuronTree& targetTree, const NeuronTree& refTree, int type)
{
	boost::container::flat_map<string, QList<NeuronSWC>> targetNodeTileMap;
	boost::container::flat_map<string, QList<NeuronSWC>> refNodeTileMap;
	NeuronStructUtil::nodeTileMapGen(targetTree, targetNodeTileMap);
	NeuronStructUtil::nodeTileMapGen(refTree, refNodeTileMap);

	if (type == 0)
	{
		vector<ptrdiff_t> delLocs;
		for (boost::container::flat_map<string, QList<NeuronSWC>>::iterator targetTileIt = targetNodeTileMap.begin(); targetTileIt != targetNodeTileMap.end(); ++targetTileIt)
		{
			if (refNodeTileMap.find(targetTileIt->first) != refNodeTileMap.end())
			{
				for (QList<NeuronSWC>::iterator checkIt1 = targetTileIt->second.begin(); checkIt1 != targetTileIt->second.end(); ++checkIt1)
				{
					for (QList<NeuronSWC>::iterator checkIt2 = refNodeTileMap.at(targetTileIt->first).begin(); checkIt2 != refNodeTileMap.at(targetTileIt->first).end(); ++checkIt2)
					{
						if (checkIt1->x == checkIt2->x && checkIt1->y == checkIt2->y && checkIt1->z == checkIt2->z)
							delLocs.push_back(ptrdiff_t(checkIt1 - targetTileIt->second.begin()));
					}
				}
			}
			else continue;

			sort(delLocs.rbegin(), delLocs.rend());
			for (vector<ptrdiff_t>::iterator delIt = delLocs.begin(); delIt != delLocs.end(); ++delIt) targetTileIt->second.erase(targetTileIt->second.begin() + *delIt);
			delLocs.clear();
		}
	}
	else
	{
		vector<ptrdiff_t> delLocs;
		for (boost::container::flat_map<string, QList<NeuronSWC>>::iterator targetTileIt = targetNodeTileMap.begin(); targetTileIt != targetNodeTileMap.end(); ++targetTileIt)
		{
			if (refNodeTileMap.find(targetTileIt->first) != refNodeTileMap.end())
			{
				for (QList<NeuronSWC>::iterator checkIt1 = targetTileIt->second.begin(); checkIt1 != targetTileIt->second.end(); ++checkIt1)
				{
					for (QList<NeuronSWC>::iterator checkIt2 = refNodeTileMap.at(targetTileIt->first).begin(); checkIt2 != refNodeTileMap.at(targetTileIt->first).end(); ++checkIt2)
					{
						if (checkIt1->x == checkIt2->x && checkIt1->y == checkIt2->y && checkIt1->z == checkIt2->z && checkIt2->type == type)
							delLocs.push_back(ptrdiff_t(checkIt1 - targetTileIt->second.begin()));
					}
				}
			}
			else continue;

			sort(delLocs.rbegin(), delLocs.rend());
			for (vector<ptrdiff_t>::iterator delIt = delLocs.begin(); delIt != delLocs.end(); ++delIt)
			{
				if (targetTileIt->second.begin() + *delIt >= targetTileIt->second.end()) continue;
				else targetTileIt->second.erase(targetTileIt->second.begin() + *delIt);
			}
			delLocs.clear();
		}
	}

	NeuronTree outputTree;
	boost::container::flat_set<int> nodeIDs;
	for (boost::container::flat_map<string, QList<NeuronSWC>>::iterator mapIt = targetNodeTileMap.begin(); mapIt != targetNodeTileMap.end(); ++mapIt)
	{
		outputTree.listNeuron.append(mapIt->second);
		for (QList<NeuronSWC>::iterator nodeIt = mapIt->second.begin(); nodeIt != mapIt->second.end(); ++nodeIt)
			nodeIDs.insert(nodeIt->n);
	}

	for (QList<NeuronSWC>::iterator nodeIt = outputTree.listNeuron.begin(); nodeIt != outputTree.listNeuron.end(); ++nodeIt)
	{
		if (nodeIt->parent == -1) continue;
		else
			if (nodeIDs.find(nodeIt->parent) == nodeIDs.end()) nodeIt->parent = -1;
	}

	return outputTree;
}

void NeuronStructUtil::treeUpSample(const profiledTree& inputProfiledTree, profiledTree& outputProfiledTree, float intervalLength)
{
	size_t maxNodeID = 0;
	for (QList<NeuronSWC>::const_iterator it = inputProfiledTree.tree.listNeuron.begin(); it != inputProfiledTree.tree.listNeuron.end(); ++it)
		if (it->n > maxNodeID) maxNodeID = it->n;

	for (map<int, segUnit>::const_iterator segIt = inputProfiledTree.segs.begin(); segIt != inputProfiledTree.segs.end(); ++segIt)
	{
		QList<NeuronSWC> newSegNodes;
		map<int, vector<QList<NeuronSWC>>> interpolatedNodeMap;
		for (QList<NeuronSWC>::const_iterator nodeIt = segIt->second.nodes.begin(); nodeIt != segIt->second.nodes.end() - 1; ++nodeIt)
		{
			vector<size_t> childLocs = segIt->second.seg_childLocMap.at(nodeIt->n);
			for (vector<size_t>::iterator childLocIt = childLocs.begin(); childLocIt != childLocs.end(); ++childLocIt)
			{
				float dist = sqrt((segIt->second.nodes.at(*childLocIt).x - nodeIt->x) * (segIt->second.nodes.at(*childLocIt).x - nodeIt->x) +
					(segIt->second.nodes.at(*childLocIt).y - nodeIt->y) * (segIt->second.nodes.at(*childLocIt).y - nodeIt->y) +
					(segIt->second.nodes.at(*childLocIt).z - nodeIt->z) * (segIt->second.nodes.at(*childLocIt).z - nodeIt->z));
				int intervals = int(dist / intervalLength);
				float intervalX = (segIt->second.nodes.at(*childLocIt).x - nodeIt->x) / float(intervals);
				float intervalY = (segIt->second.nodes.at(*childLocIt).y - nodeIt->y) / float(intervals);
				float intervalZ = (segIt->second.nodes.at(*childLocIt).z - nodeIt->z) / float(intervals);

				QList<NeuronSWC> interpolatedNodes;
				for (int i = 1; i < intervals; ++i)
				{
					NeuronSWC newNode;
					newNode.x = nodeIt->x + intervalX * float(i);
					newNode.y = nodeIt->y + intervalY * float(i);
					newNode.z = nodeIt->z + intervalZ * float(i);
					newNode.type = nodeIt->type;
					++maxNodeID;
					newNode.n = maxNodeID;
					newNode.parent = maxNodeID - 1;
					interpolatedNodes.push_back(newNode);
				}
				interpolatedNodes.push_back(segIt->second.nodes.at(*childLocIt));
				if (interpolatedNodes.size() >= 2)
				{
					interpolatedNodes.back().parent = (interpolatedNodes.end() - 2)->n;
					interpolatedNodes.begin()->parent = nodeIt->n;
				}

				interpolatedNodeMap[nodeIt->n].push_back(interpolatedNodes);
			}
		}
		for (map<int, vector<QList<NeuronSWC>>>::iterator mapIt = interpolatedNodeMap.begin(); mapIt != interpolatedNodeMap.end(); ++mapIt)
			for (vector<QList<NeuronSWC>>::iterator qlistIt = mapIt->second.begin(); qlistIt != mapIt->second.end(); ++qlistIt) newSegNodes.append(*qlistIt);
		newSegNodes.push_front(segIt->second.nodes.at(segIt->second.seg_nodeLocMap.at(segIt->second.head)));

		segUnit newSegUnit;
		newSegUnit.nodes = newSegNodes;
		outputProfiledTree.segs.insert(pair<int, segUnit>(segIt->first, newSegUnit));
		outputProfiledTree.tree.listNeuron.append(newSegNodes);
	}
}

profiledTree NeuronStructUtil::treeDownSample(const profiledTree& inputProfiledTree, int nodeInterval)
{
	// -- This method "down samples" the input tree segment by segment.
	// -- A recursive down sampling method [NeuronStructExplorer::rc_segDownSample] is called in this function to deal with all possible braching points in each segment.
	// -- NOTE, this method is essentially used for straightening / smoothing segments when there are too many zigzagging.

	NeuronTree outputTree;
	QList<NeuronSWC> currSegOutputList;
	for (map<int, segUnit>::const_iterator it = inputProfiledTree.segs.begin(); it != inputProfiledTree.segs.end(); ++it)
	{
		//if (it->second.seg_childLocMap.empty()) continue; => Using this line is not safe. Can occasionally result in program crash.
		// The safety of seg_childLocMap needs to be investigated later.
		if (it->second.nodes.size() <= 3) continue;

		currSegOutputList.clear();
		currSegOutputList.push_back(*(it->second.nodes.begin()));
		NeuronStructUtil::rc_segDownSample(it->second, currSegOutputList, it->second.head, nodeInterval);
		outputTree.listNeuron.append(currSegOutputList);
	}

	vector<size_t> delLocs;
	for (QList<NeuronSWC>::iterator nodeIt = outputTree.listNeuron.begin(); nodeIt != outputTree.listNeuron.end(); ++nodeIt)
		if (nodeIt->n == nodeIt->parent) delLocs.push_back(size_t(nodeIt - outputTree.listNeuron.begin()));
	sort(delLocs.rbegin(), delLocs.rend());
	for (vector<size_t>::iterator delIt = delLocs.begin(); delIt != delLocs.end(); ++delIt) outputTree.listNeuron.erase(outputTree.listNeuron.begin() + ptrdiff_t(*delIt));
	profiledTree outputProfiledTree(outputTree);

	return outputProfiledTree;
}

void NeuronStructUtil::rc_segDownSample(const segUnit& inputSeg, QList<NeuronSWC>& outputNodeList, int branchigNodeID, int interval)
{
	int currNodeID = 0, count = 0;
	for (vector<size_t>::const_iterator childIt = inputSeg.seg_childLocMap.at(branchigNodeID).begin(); childIt != inputSeg.seg_childLocMap.at(branchigNodeID).end(); ++childIt)
	{
		outputNodeList.push_back(inputSeg.nodes.at(*childIt));
		outputNodeList.last().parent = branchigNodeID;
		currNodeID = inputSeg.nodes.at(*childIt).n;
		count = 0;
		while (inputSeg.seg_childLocMap.at(currNodeID).size() > 0)
		{
			if (inputSeg.seg_childLocMap.at(currNodeID).size() >= 2) // branching point found, function recursively called
			{
				outputNodeList.push_back(inputSeg.nodes.at(inputSeg.seg_nodeLocMap.at(currNodeID)));
				outputNodeList.last().parent = (outputNodeList.end() - 2)->n;
				NeuronStructUtil::rc_segDownSample(inputSeg, outputNodeList, currNodeID, interval);
				break;
			}

			++count;
			currNodeID = inputSeg.nodes.at(*(inputSeg.seg_childLocMap.at(currNodeID).begin())).n;
			if (count % interval == 0 || inputSeg.seg_childLocMap.at(currNodeID).size() == 0) // The tail(s) of the segment needs to stay.
			{
				outputNodeList.push_back(inputSeg.nodes.at(inputSeg.seg_nodeLocMap.at(currNodeID)));
				outputNodeList.last().parent = (outputNodeList.end() - 2)->n;
			}
		}
	}
}
/* ===================================== END of [Neuron Struct Processing] ===================================== */

/* ================================== SWC <-> ImgAnalyzer::connectedComponents ================================== */
vector<connectedComponent> NeuronStructUtil::swc2signal2DBlobs(const NeuronTree& inputTree)
{
	// -- Finds signal blobs "slice by slice" from input NeuronTree. Each slice is independent to one another.
	// -- Therefore, the same real blobs in 3D are consists of certain amount of 2D "blob slices" produced by this method.
	// -- Each 2D blob slice accounts for 1 ImgAnalyzer::connectedComponent.

	vector<NeuronSWC> allNodes;
	for (QList<NeuronSWC>::const_iterator it = inputTree.listNeuron.begin(); it != inputTree.listNeuron.end(); ++it) allNodes.push_back(*it);
	bool longList = false;

	vector<connectedComponent> connComps2D;
	int islandCount = 0;
	if (allNodes.size() >= 100000)
	{
		longList = true;
		cout << "number of SWC nodes processed: ";
	}
	for (vector<NeuronSWC>::iterator nodeIt = allNodes.begin(); nodeIt != allNodes.end(); ++nodeIt)
	{
		if (longList)
		{
			if (int(nodeIt - allNodes.begin()) % 10000 == 0) cout << int(nodeIt - allNodes.begin()) << " ";
		}

		for (vector<connectedComponent>::iterator connIt = connComps2D.begin(); connIt != connComps2D.end(); ++connIt)
		{
			if (connIt->coordSets.empty()) continue;
			else if (int(nodeIt->z) == connIt->coordSets.begin()->first)
			{
				for (set<vector<int>>::iterator dotIt = connIt->coordSets[int(nodeIt->z)].begin(); dotIt != connIt->coordSets[int(nodeIt->z)].end(); ++dotIt)
				{
					if (int(nodeIt->x) <= dotIt->at(0) + 1 && int(nodeIt->x) >= dotIt->at(0) - 1 &&
						int(nodeIt->y) <= dotIt->at(1) + 1 && int(nodeIt->y) >= dotIt->at(1) - 1)
					{
						vector<int> newCoord(3);
						newCoord[0] = int(nodeIt->x);
						newCoord[1] = int(nodeIt->y);
						newCoord[2] = int(nodeIt->z);
						connIt->coordSets[newCoord[2]].insert(newCoord);
						connIt->size = connIt->size + 1;

						if (newCoord[0] < connIt->xMin) connIt->xMin = newCoord[0];
						else if (newCoord[0] > connIt->xMax) connIt->xMax = newCoord[0];

						if (newCoord[1] < connIt->yMin) connIt->yMin = newCoord[1];
						else if (newCoord[1] > connIt->yMax) connIt->yMax = newCoord[1];

						goto NODE_INSERTED;
					}
				}
			}
		}

		{
			++islandCount;
			connectedComponent newIsland;
			newIsland.islandNum = islandCount;
			vector<int> newCoord(3);
			newCoord[0] = int(nodeIt->x);
			newCoord[1] = int(nodeIt->y);
			newCoord[2] = int(nodeIt->z);
			set<vector<int>> coordSet;
			coordSet.insert(newCoord);
			newIsland.coordSets.insert(pair<int, set<vector<int>>>(newCoord[2], coordSet));
			newIsland.xMax = newCoord[0];
			newIsland.xMin = newCoord[0];
			newIsland.yMax = newCoord[1];
			newIsland.yMin = newCoord[1];
			newIsland.zMin = newCoord[2];
			newIsland.zMax = newCoord[2];
			newIsland.size = 1;
			connComps2D.push_back(newIsland);
		}

	NODE_INSERTED:
		continue;
	}
	//cout << endl << endl;

	vector<float> center(3);
	for (vector<connectedComponent>::iterator it = connComps2D.begin(); it != connComps2D.end(); ++it)
		ChebyshevCenter_connComp(*it);

	return connComps2D;
}

vector<connectedComponent> NeuronStructUtil::swc2signal3DBlobs(const NeuronTree& inputTree)
{
	// -- This method is a wrapper of NeuronStructUtil::swc2signal2DBlobs and NeuronStructUtil::merge2DConnComponent.
	// -- It produces 3D signal blobs by calling the two swc2signal2DBlobs and merge2DConnComponent sequentially.

	vector<connectedComponent> inputConnCompList = NeuronStructUtil::swc2signal2DBlobs(inputTree);
	vector<connectedComponent> outputConnCompList = NeuronStructUtil::merge2DConnComponent(inputConnCompList);

	return outputConnCompList;
}

vector<connectedComponent> NeuronStructUtil::merge2DConnComponent(const vector<connectedComponent>& inputConnCompList)
{
	// -- This method finds 3D signal blobs by grouping 2D signal blobs together, which are generated by NeuronStructUtil::swc2signal2DBlobs.
	// -- This method is typically called by NeuronStructUtil::swc2signal2DBlobs when identifying 3D blobs from 2D ones.
	// -- The approach is consists of 2 stages:
	//		1. Identifying the same 3D blobs slice by slice.
	//		2. Merging 3D blobs that contain the same 2D blobs.

	cout << "Merging 2D signal blobs.." << endl;
	cout << "-- processing slice ";

	vector<connectedComponent> outputConnCompList;

	int zMax = 0;

	// -- I notice that boost's container templates are able to lift up the performace by ~30%.
	boost::container::flat_map<int, boost::container::flat_set<int>> b2Dtob3Dmap;
	b2Dtob3Dmap.clear();
	boost::container::flat_map<int, boost::container::flat_set<int>> b3Dcomps;  // a map from 3D connected components to all of its associated 2D connected components
	b3Dcomps.clear();
	// ---------------------------------------------------------------------------------------

	// --------- First slice, container initialization --------------
	int sliceBlobCount = 0;
	for (vector<connectedComponent>::const_iterator it = inputConnCompList.begin(); it != inputConnCompList.end(); ++it)
	{
		if (it->coordSets.begin()->first > zMax) zMax = it->coordSets.begin()->first;

		if (it->coordSets.begin()->first == 0) // 1st slice connected components profile initialization
		{
			++sliceBlobCount;
			boost::container::flat_set<int> blob3D;
			blob3D.insert(sliceBlobCount);
			b2Dtob3Dmap.insert(pair<int, boost::container::flat_set<int>>(it->islandNum, blob3D));
			boost::container::flat_set<int> comps;
			comps.insert(it->islandNum);
			b3Dcomps[sliceBlobCount] = comps;
		}
	}
	// -----------------------------------------------------------

	// ------------------------------------------- Merge 2D blobs from 2 adjacent slices -------------------------------------------
	vector<connectedComponent> currSliceConnComps;
	vector<connectedComponent> preSliceConnComps;
	size_t increasedSize;
	for (int i = 1; i <= zMax; ++i)
	{
		currSliceConnComps.clear();
		preSliceConnComps.clear();

		increasedSize = 0;
		for (vector<connectedComponent>::const_iterator it = inputConnCompList.begin(); it != inputConnCompList.end(); ++it)
			if (it->coordSets.begin()->first == i) currSliceConnComps.push_back(*it); // collect all connected components from the current slice
		if (currSliceConnComps.empty())
		{
			//cout << i << "->0 ";
			continue;
		}

		cout << i << "->";
		for (vector<connectedComponent>::const_iterator it = inputConnCompList.begin(); it != inputConnCompList.end(); ++it)
			if (it->coordSets.begin()->first == i - 1) preSliceConnComps.push_back(*it);  // collect all connected components from the previous slice
		if (preSliceConnComps.empty())
		{
			// If the previous slice is empty, all 2D components found in the current slice will be part of new 3D components.
			for (vector<connectedComponent>::iterator newCompsIt = currSliceConnComps.begin(); newCompsIt != currSliceConnComps.end(); ++newCompsIt)
			{
				++sliceBlobCount;
				boost::container::flat_set<int> blob3D;
				blob3D.insert(sliceBlobCount);
				b2Dtob3Dmap.insert(pair<int, boost::container::flat_set<int>>(newCompsIt->islandNum, blob3D));
				boost::container::flat_set<int> comps;
				comps.insert(newCompsIt->islandNum);
				b3Dcomps[sliceBlobCount] = comps;
				increasedSize = increasedSize + comps.size();
			}
			continue;
		}

		for (vector<connectedComponent>::iterator currIt = currSliceConnComps.begin(); currIt != currSliceConnComps.end(); ++currIt)
		{
			bool merged = false;
			for (vector<connectedComponent>::iterator preIt = preSliceConnComps.begin(); preIt != preSliceConnComps.end(); ++preIt)
			{
				// First, use component boundaries to quickly exclude those pixels that can't be connected to any existing components.
				// And then create new components for these pixels.
				if (currIt->xMin > preIt->xMax + 2 || currIt->xMax < preIt->xMin - 2 ||
					currIt->yMin > preIt->yMax + 2 || currIt->yMax < preIt->yMin - 2) continue;

				for (set<vector<int>>::iterator currDotIt = currIt->coordSets.begin()->second.begin(); currDotIt != currIt->coordSets.begin()->second.end(); ++currDotIt)
				{
					for (set<vector<int>>::iterator preDotIt = preIt->coordSets.begin()->second.begin(); preDotIt != preIt->coordSets.begin()->second.end(); ++preDotIt)
					{
						if (currDotIt->at(0) >= preDotIt->at(0) - 1 && currDotIt->at(0) <= preDotIt->at(0) + 1 &&
							currDotIt->at(1) >= preDotIt->at(1) - 1 && currDotIt->at(1) <= preDotIt->at(1) + 1)
						{
							merged = true;
							// Find out to which 3D component the 2D component connected to the pixel belong.
							boost::container::flat_set<int> asso3Dblob = b2Dtob3Dmap[preIt->islandNum];

							// Register the component of the pixel in the current slice to b2Dtob3Dmap.
							b2Dtob3Dmap.insert(pair<int, boost::container::flat_set<int>>(currIt->islandNum, asso3Dblob));

							// Add a new entry of newly identified 2D component that is connected to the existing 3D component to b3Dcomps.
							for (boost::container::flat_set<int>::iterator blob3DIt = asso3Dblob.begin(); blob3DIt != asso3Dblob.end(); ++blob3DIt)
								b3Dcomps[*blob3DIt].insert(currIt->islandNum);

							goto BLOB_MERGED;
						}
					}
				}

				if (!merged) continue;

			BLOB_MERGED:
				merged = true;
			}

			if (!merged) // All 2D blobs in the current slice fail to find its associated 3D blobs. Create new 3D blobs for them here.
			{
				++sliceBlobCount;
				boost::container::flat_set<int> newBlob3D;
				newBlob3D.insert(sliceBlobCount);
				b2Dtob3Dmap.insert(pair<int, boost::container::flat_set<int>>(currIt->islandNum, newBlob3D));
				boost::container::flat_set<int> comps;
				comps.insert(currIt->islandNum);
				b3Dcomps[sliceBlobCount] = comps;
				increasedSize = increasedSize + comps.size();
			}
		}
		cout << increasedSize << ", ";
	}
	cout << endl;
	cout << "Done merging 2D blobs from every 2 slices." << endl;
	// ---------------------------------------- END of [Merge 2D blobs from 2 adjacent slices] -------------------------------------------

	// ------------------------------------------ Merge 3D blobs --------------------------------------------
	// Merge any 3D blobs if any of them share the same 2D blob members.
	cout << "Now merging 3D blobs.." << endl;
	cout << " -- original 3D blobs number: " << b3Dcomps.size() << endl;
	bool mergeFinish = false;
	int currBaseBlob = 1;
	while (!mergeFinish)
	{
		for (boost::container::flat_map<int, boost::container::flat_set<int>>::iterator checkIt1 = b3Dcomps.begin(); checkIt1 != b3Dcomps.end(); ++checkIt1)
		{
			if (checkIt1->first < currBaseBlob) continue;
			for (boost::container::flat_map<int, boost::container::flat_set<int>>::iterator checkIt2 = checkIt1 + 1; checkIt2 != b3Dcomps.end(); ++checkIt2)
			{
				//if (checkIt2 == checkIt1) continue;
				for (boost::container::flat_set<int>::iterator member1 = checkIt1->second.begin(); member1 != checkIt1->second.end(); ++member1)
				{
					for (boost::container::flat_set<int>::iterator member2 = checkIt2->second.begin(); member2 != checkIt2->second.end(); ++member2)
					{
						if (*member2 == *member1)
						{
							checkIt1->second.insert(checkIt2->second.begin(), checkIt2->second.end());
							b3Dcomps.erase(checkIt2);
							currBaseBlob = checkIt1->first;
							cout << "  merging blob " << checkIt1->first << " and blob " << checkIt2->first << endl;
							goto MERGED;
						}
					}
				}
			}
		}
		mergeFinish = true;

	MERGED:
		continue;
	}
	cout << " -- new 3D blobs number: " << b3Dcomps.size() << endl;
	cout << "    ------------------------------" << endl << endl;
	// --------------------------------------- END of [Merge 3D blobs] --------------------------------------

	// ------------------------------------- Create 3D connected component data -------------------------------------
	map<int, connectedComponent> compsMap;
	for (vector<connectedComponent>::const_iterator inputIt = inputConnCompList.begin(); inputIt != inputConnCompList.end(); ++inputIt)
		compsMap.insert(pair<int, connectedComponent>(inputIt->islandNum, *inputIt));
	int newLabel = 0;
	for (boost::container::flat_map<int, boost::container::flat_set<int>>::iterator it = b3Dcomps.begin(); it != b3Dcomps.end(); ++it)
	{
		++newLabel;
		connectedComponent newComp;
		newComp.islandNum = newLabel;
		newComp.size = 0;
		newComp.xMax = 0; newComp.xMin = 1000000;
		newComp.yMax = 0; newComp.yMin = 1000000;
		newComp.zMax = 0; newComp.zMin = 1000000;
		for (boost::container::flat_set<int>::iterator it2 = it->second.begin(); it2 != it->second.end(); ++it2) // *it2 = 2D connected component's [islandNum]
		{
			// A 3D connected component may contain different 2D components from the same slice.
			if (newComp.coordSets.find(compsMap.at(*it2).coordSets.begin()->first) != newComp.coordSets.end())
			{
				for (set<vector<int>>::iterator it3 = compsMap.at(*it2).coordSets.begin()->second.begin(); it3 != compsMap.at(*it2).coordSets.begin()->second.end(); ++it3)
					newComp.coordSets.at(compsMap.at(*it2).coordSets.begin()->first).insert(*it3);

				newComp.xMax = getMax(newComp.xMax, compsMap.at(*it2).xMax);
				newComp.xMin = getMin(newComp.xMin, compsMap.at(*it2).xMin);
				newComp.yMax = getMax(newComp.yMax, compsMap.at(*it2).yMax);
				newComp.yMin = getMin(newComp.yMin, compsMap.at(*it2).yMin);
				newComp.zMax = getMax(newComp.zMax, compsMap.at(*it2).zMax);
				newComp.zMin = getMin(newComp.zMin, compsMap.at(*it2).zMin);
				newComp.size = newComp.size + compsMap.at(*it2).size;
			}
			else
			{
				newComp.coordSets.insert(pair<int, set<vector<int>>>(compsMap.at(*it2).coordSets.begin()->first, compsMap.at(*it2).coordSets.begin()->second));
				newComp.xMax = getMax(newComp.xMax, compsMap.at(*it2).xMax);
				newComp.xMin = getMin(newComp.xMin, compsMap.at(*it2).xMin);
				newComp.yMax = getMax(newComp.yMax, compsMap.at(*it2).yMax);
				newComp.yMin = getMin(newComp.yMin, compsMap.at(*it2).yMin);
				newComp.zMax = getMax(newComp.zMax, compsMap.at(*it2).zMax);
				newComp.zMin = getMin(newComp.zMin, compsMap.at(*it2).zMin);
				newComp.size = newComp.size + compsMap.at(*it2).size;
			}
		}

		outputConnCompList.push_back(newComp);
	}
	// --------------------------------- END of [Create 3D connected component data] ---------------------------------

	return outputConnCompList;
}

NeuronTree NeuronStructUtil::blobs2tree(const vector<connectedComponent>& inputconnComp, bool usingRadius2compNum)
{
	// -- This method produces a NeuronTree that is used to store connected component information. The radius column is ususally used for component label.

	NeuronTree outputTree;
	for (vector<connectedComponent>::const_iterator it = inputconnComp.begin(); it != inputconnComp.end(); ++it)
	{
		for (map<int, set<vector<int>>>::const_iterator sliceIt = it->coordSets.begin(); sliceIt != it->coordSets.end(); ++sliceIt)
		{
			for (set<vector<int>>::const_iterator pointIt = sliceIt->second.begin(); pointIt != sliceIt->second.end(); ++pointIt)
			{
				NeuronSWC newNode;
				newNode.x = pointIt->at(0);
				newNode.y = pointIt->at(1);
				newNode.z = pointIt->at(2);
				newNode.type = it->islandNum % 500;
				newNode.parent = -1;

				if (usingRadius2compNum) newNode.radius = it->islandNum; // Use SWC's radius column to keep component label information.

				outputTree.listNeuron.push_back(newNode);
			}
		}
	}

	return outputTree;
}
/* =============================== END of [SWC <-> ImgAnalyzer::connectedComponents] =============================== */

/* =========================================== Miscellaneous =========================================== */
NeuronTree NeuronStructUtil::nodeSpheresGen(float sphereRadius, float density, float stepX, float stepY, float stepZ, float xRange, float yRange, float zRange)
{
	NeuronTree outputTree;
	for (float x = 0; x <= xRange; x += stepX)
	{
		for (float y = 0; y <= yRange; y += stepY)
		{
			for (float z = 0; z <= zRange; z += stepZ)
			{
				NeuronTree currSphereTree = NeuronStructUtil::sphereRandNodes(sphereRadius, x, y, z, density);
				size_t existingNodeNum = outputTree.listNeuron.size();
				for (QList<NeuronSWC>::iterator it = currSphereTree.listNeuron.begin(); it != currSphereTree.listNeuron.end(); ++it) it->n = it->n + existingNodeNum;
				outputTree.listNeuron.append(currSphereTree.listNeuron);
			}
		}
	}

	return outputTree;
}
/* ===================================================================================================== */

/* =================================== Volumetric SWC sampling methods =================================== */
void NeuronStructUtil::sigNode_Gen(const NeuronTree& inputTree, NeuronTree& outputTree, float ratio, float distance)
{
	// -- Randomly generate signal patches within given distance range
	//      ratio:    the ratio of targeted number of upsampling nodes to the number of maunal nodes in the inputTree
	//      distance: the radius allowed with SWC node centered

	cout << "target signal patch number: " << int(inputTree.listNeuron.size() * ratio) << endl;
	int nodeCount = 0;
	for (QList<NeuronSWC>::const_iterator it = inputTree.listNeuron.begin(); it != inputTree.listNeuron.end(); ++it)
	{
		outputTree.listNeuron.push_back(*it);
		(outputTree.listNeuron.end() - 1)->parent = -1;
		(outputTree.listNeuron.end() - 1)->type = 2;
		int foldCount = 2;
		while (foldCount <= ratio)
		{
			int randNumX = rand() % int(distance * 2) + int(it->x - distance);
			int randNumY = rand() % int(distance * 2) + int(it->y - distance);
			int randNumZ = rand() % int(distance * 2) + int(it->z - distance);

			++nodeCount;
			if (nodeCount % 10000 == 0) cout << nodeCount << " signal nodes generated." << endl;

			NeuronSWC newNode;
			newNode.x = randNumX;
			newNode.y = randNumY;
			newNode.z = randNumZ;
			newNode.type = 2;
			newNode.radius = 1;
			newNode.parent = -1;
			outputTree.listNeuron.push_back(newNode);

			++foldCount;
		}
	}
}

void NeuronStructUtil::bkgNode_Gen(const NeuronTree& inputTree, NeuronTree& outputTree, int dims[], float ratio, float distance)
{
	// -- Randomly generate background patches away from the forbidden distance
	//      dims:     image stack dimension
	//      ratio:    the ratio of targeted number of background nodes to the number of manual nodes in the inputTree
	//      distance: the forbidden distance from each SWC node

	QList<NeuronSWC> neuronList = inputTree.listNeuron;
	int targetBkgNodeNum = int(neuronList.size() * ratio);
	cout << targetBkgNodeNum << " targeted bkg nodes to ge generated." << endl;
	int bkgNodeCount = 0;
	while (bkgNodeCount <= targetBkgNodeNum)
	{
		int randNumX = rand() % (dims[0] - 20) + 10;
		int randNumY = rand() % (dims[1] - 20) + 10;
		int randNumZ = rand() % dims[2];

		bool flag = false;
		for (QList<NeuronSWC>::iterator it = neuronList.begin(); it != neuronList.end(); ++it)
		{
			float distSqr;
			float diffx = float(randNumX) - it->x;
			float diffy = float(randNumY) - it->y;
			float diffz = float(randNumZ) - it->z;
			distSqr = diffx * diffx + diffy * diffy + diffz * diffz;

			if (distSqr <= distance * distance)
			{
				flag = true;
				break;
			}
		}

		if (flag == false)
		{
			++bkgNodeCount;
			if (bkgNodeCount % 10000 == 0) cout << bkgNodeCount << " bkg nodes generated." << endl;

			NeuronSWC newBkgNode;
			newBkgNode.x = randNumX;
			newBkgNode.y = randNumY;
			newBkgNode.z = randNumZ;
			newBkgNode.type = 3;
			newBkgNode.radius = 1;
			newBkgNode.parent = -1;
			outputTree.listNeuron.push_back(newBkgNode);
		}
	}
}

void NeuronStructUtil::bkgNode_Gen_somaArea(const NeuronTree& intputTree, NeuronTree& outputTree, int xLength, int yLength, int zLength, float ratio, float distance)
{
	// -- Randomly generate background patches away from the forbidden distance. This method aims to reinforce the background recognition near soma area.
	//      xLength, yLength, zLength: decide the range to apply with soma centered
	//      ratio:    the ratio of targeted number of soma background nodes to the number of manual nodes in the inputTree
	//      distance: the forbidden distance from each SWC node

	NeuronSWC somaNode;
	for (QList<NeuronSWC>::const_iterator it = intputTree.listNeuron.begin(); it != intputTree.listNeuron.end(); ++it)
	{
		if (it->parent == -1)
		{
			somaNode = *it;
			break;
		}
	}
	float xlb = somaNode.x - float(xLength);
	float xhb = somaNode.x + float(xLength);
	float ylb = somaNode.y - float(yLength);
	float yhb = somaNode.y + float(yLength);
	float zlb = somaNode.z - float(zLength);
	float zhb = somaNode.z + float(zLength);

	list<NeuronSWC> confinedNodes;
	for (QList<NeuronSWC>::const_iterator it = intputTree.listNeuron.begin(); it != intputTree.listNeuron.end(); ++it)
		if (xlb <= it->x && xhb >= it->x && ylb <= it->y && yhb >= it->y && zlb <= it->z && zhb >= it->z) confinedNodes.push_back(*it);

	int targetBkgNodeNum = int(float(xLength) * float(yLength) * float(zLength) * ratio);
	cout << targetBkgNodeNum << " targeted bkg nodes to ge generated." << endl;
	int bkgNodeCount = 0;
	while (bkgNodeCount <= targetBkgNodeNum)
	{
		int randNumX = rand() % int(xhb - xlb + 1) + int(xlb);
		int randNumY = rand() % int(yhb - ylb + 1) + int(ylb);
		int randNumZ = rand() % int(zhb - zlb + 1) + int(zlb);

		bool flag = false;
		for (list<NeuronSWC>::iterator it = confinedNodes.begin(); it != confinedNodes.end(); ++it)
		{
			float distSqr;
			float diffx = float(randNumX) - it->x;
			float diffy = float(randNumY) - it->y;
			float diffz = float(randNumZ) - it->z;
			distSqr = diffx * diffx + diffy * diffy + diffz * diffz;

			if (distSqr <= distance * distance)
			{
				flag = true;
				break;
			}
		}

		if (flag == false)
		{
			++bkgNodeCount;
			if (bkgNodeCount % 10000 == 0) cout << bkgNodeCount << " bkg nodes generated within the soma area." << endl;

			NeuronSWC newBkgNode;
			newBkgNode.x = randNumX;
			newBkgNode.y = randNumY;
			newBkgNode.z = randNumZ;
			newBkgNode.type = 3;
			newBkgNode.radius = 1;
			newBkgNode.parent = -1;
			outputTree.listNeuron.push_back(newBkgNode);
		}
	}
}

void NeuronStructUtil::swcSlicer_DL(const NeuronTree& inputTree, vector<NeuronTree>& outputTrees, int thickness)
{
	// -- Dissemble SWC files into "slices." Each outputSWC file represents only 1 z slice.
	// thickness * 2 + 1 = the number of consecutive z slices for one SWC node to appear. This is for the purpose producing continous masks.

	QList<NeuronSWC> inputList = inputTree.listNeuron;
	int zMax = 0;
	ptrdiff_t thicknessPtrDiff = ptrdiff_t(thickness); // Determining how many z sections to be included in 1 single slice.
	for (QList<NeuronSWC>::iterator it = inputList.begin(); it != inputList.end(); ++it)
	{
		it->z = round(it->z);
		if (it->z >= zMax) zMax = it->z;
	}

	QList<NeuronTree> slicedTrees; // Determining number of sliced trees in the list.
	for (int i = 0; i < zMax; ++i)
	{
		NeuronTree nt;
		slicedTrees.push_back(nt);
	}

	for (QList<NeuronSWC>::iterator it = inputList.begin(); it != inputList.end(); ++it)
	{
		NeuronSWC currNode = *it;
		ptrdiff_t sliceNo = ptrdiff_t(it->z);
		(slicedTrees.begin() + sliceNo - 1)->listNeuron.push_back(currNode); // SWC starts with 1.
		float currZ = currNode.z;

		// -- Project +/- thickness slices onto the same plane, making sure the tube can be connected accross planes. -- //
		vector<ptrdiff_t> sectionNums;
		for (ptrdiff_t ptri = 1; ptri <= thicknessPtrDiff; ++ptri)
		{
			ptrdiff_t minusDiff = sliceNo - ptri;
			ptrdiff_t plusDiff = sliceNo + ptri;

			if (minusDiff < 0) continue;
			else sectionNums.push_back(minusDiff);

			if (plusDiff > ptrdiff_t(zMax)) continue;
			else sectionNums.push_back(plusDiff);
		}
		for (vector<ptrdiff_t>::iterator ptrIt = sectionNums.begin(); ptrIt != sectionNums.end(); ++ptrIt)
		{
			//cout << "current node z:" << currNode.z << " " << *ptrIt << "| ";
			NeuronSWC newNode = currNode;
			newNode.z = float(*ptrIt);
			(slicedTrees.begin() + *ptrIt - 1)->listNeuron.push_back(newNode);
		}
		//cout << endl;

		sectionNums.clear();
		// ------------------------------------------------------------------------------------------------------------- //
	}

	for (QList<NeuronTree>::iterator it = slicedTrees.begin(); it != slicedTrees.end(); ++it)
		outputTrees.push_back(*it);
}
/* =================================== Volumetric SWC sampling methods =================================== */

ext: cpp


text:
#include <asio_cares/done.hpp>

#include <asio_cares/channel.hpp>
#include <asio_cares/error.hpp>
#include <asio_cares/library.hpp>
#include <asio_cares/string.hpp>
#include <boost/asio/io_service.hpp>
#include "setup.hpp"
#include <catch.hpp>

#ifdef _WIN32
#include <nameser.h>
#else
#include <arpa/nameser.h>
#endif

namespace asio_cares {
namespace tests {
namespace {

SCENARIO("asio_cares::done correctly determines whether there are outstanding queries on an ares_channel", "[asio_cares][done]") {
	GIVEN("An ares_channel") {
		library l;
		boost::asio::io_service ios;
		channel c(ios);
		setup(c);
		THEN("asio_cares::done reports there are no outstanding queries") {
			CHECK(done(c));
		}
		WHEN("A query is sent thereupon") {
			unsigned char * ptr;
			int buflen;
			int result = ares_create_query("google.com",
				                           ns_c_any,
				                           ns_t_a,
				                           0,
				                           1,
				                           &ptr,
				                           &buflen,
				                           0);
			raise(result);
			string s(ptr);
			bool invoked = false;
			auto f = [] (void * data, int, int, unsigned char *, int) noexcept {
				*static_cast<bool *>(data) = true;
			};
			ares_send(c, ptr, buflen, f, &invoked);
			REQUIRE_FALSE(invoked);
			THEN("asio_cares::done reports that there are outstanding queries") {
				CHECK_FALSE(done(c));
			}
		}
	}
}

}
}
}

max_stars_repo_name: RobertLeahy/ASIO-C-ARES

max_issues_repo_name: RobertLeahy/ASIO-C-ARES

max_forks_repo_name: RobertLeahy/ASIO-C-ARES


text:
//==============================================================================
//         Copyright 2003 - 2011   LASMEA UMR 6602 CNRS/Univ. Clermont II
//         Copyright 2009 - 2011   LRI    UMR 8623 CNRS/Univ Paris Sud XI
//         Copyright 2012 - 2013   MetaScale
//
//          Distributed under the Boost Software License, Version 1.0.
//                 See accompanying file LICENSE.txt or copy at
//                     http://www.boost.org/LICENSE_1_0.txt
//==============================================================================
#ifndef NT2_CORE_UTILITY_ASSIGN_SWAP_HPP_INCLUDED
#define NT2_CORE_UTILITY_ASSIGN_SWAP_HPP_INCLUDED

#include <nt2/include/functions/swap.hpp>
#include <nt2/include/functions/copy.hpp>
#include <nt2/core/settings/locality.hpp>
#include <nt2/sdk/memory/forward/container.hpp>
#include <nt2/sdk/meta/is_container.hpp>
#include <boost/mpl/and.hpp>
#include <boost/mpl/or.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/utility/enable_if.hpp>

namespace nt2 { namespace container
{
  template<class A0, class A1>
  typename boost::enable_if<
    boost::mpl::and_< meta::is_container_terminal<A0>
                    , meta::is_container_terminal<A1>
                    , boost::is_same<typename A0::value_type, typename A1::value_type>
                    >
  >::type
  assign_swap(A0& a0, A1& a1)
  {
    nt2::swap(a0,a1);
  }

  template<class A0, class A1>
  typename boost::disable_if<
  boost::mpl::or_<
    boost::mpl::and_< meta::is_container_terminal<A0>
                    , meta::is_container_terminal<A1>
                    , boost::is_same<typename A0::value_type, typename A1::value_type>
                    >
                  , meta::is_on_device<A0> , meta::is_on_device<A1>
                  >
  >::type
  assign_swap(A0& a0, A1& a1)
  {
    a0 = a1;
  }
} }

#endif

ext: hpp


text:
/* page_table_allocator.cc
   Jeremy Barnes, 28 September 2011
   Copyright (c) 2011 Datacratic Inc.  All rights reserved.

*/

#include "page_table_allocator.h"
#include "page_table_allocator_itl.h"
#include "jml/arch/exception.h"
#include "jml/utils/exc_assert.h"
#include <iostream>
#include <boost/static_assert.hpp>
#include <boost/tuple/tuple.hpp>
#include <boost/thread.hpp>

using namespace std;
using namespace ML;

namespace Datacratic {
namespace MMap {

/* Both of these need to be able to fit within one page. */
BOOST_STATIC_ASSERT(sizeof(PageTableAllocator::Metadata) <= page_size);

/*****************************************************************************/
/* PAGE TABLE ALLOCATOR                                                      */
/*****************************************************************************/

PageTableAllocator::
PageTableAllocator(MemoryRegion & region, size_t offset, bool initTable)
    : region_(&region)
{
    if (initTable)
        init(offset);
}

PageTableAllocator::
~PageTableAllocator()
{
}

/** Set up the first mapping. */
void
PageTableAllocator::
init(size_t offset)
{
    // We need at least 6 pages to start off with...
    //
    // +---------------+----------------+----+----+----+----+
    // | file metadata | alloc metadata | l4 | l3 | l2 | l1 |
    // +---------------+----------------+----+----+----+----+

    if (region_->length() < 6 * page_size)
        region_->grow(6 * page_size);

    ExcAssert(region_->isPinned());

    // Page 1 is the metadata... make sure it's valid
    auto md = getMetadata();
    md->init();
    ExcAssert(md->valid());

    // Allocate a level 5 page
    allocatePageAndSplit(5, false /* allocate */);
}

//static boost::recursive_mutex mutex;

Page
PageTableAllocator::
splitPage(Page page, bool allocate)
{
    //cerr << "splitPage(" << page << ", " << allocate << ")" << endl;

    // Impossible to split smaller than 4k with the page allocator
    ExcAssert(page.order > 1);

    // First thing: make sure that the first 6 pages of this page are
    // within the region so that we know we can write to the page
    // tables.

    uint64_t minOffset = page.offset + 6 * page_size;

    if (region_->length() < minOffset)
        region_->grow(minOffset);

    // Find the page table, which will be within the page we're splitting
    auto pt = getUninitializedPageTableForPage(page.subpage(0));

    // Initialize the page table
    pt->init(page.order - 1);

    int numFreePages;
    Page result;

    if (page.order == 2) {
        // We're in a 4M page that we want to split up into 4k subpages.

        // The first 6 subpages may be reserved for the different levels of
        // page tables depending upon whether or not we're the first page
        // of a higher order.

        bool hasMetadata = page.offset == 0;
        bool hasL4PT = page.l4PageNumber() == 0;
        bool hasL3PT = page.l3PageNumber() == 0;
        bool hasL2PT = page.l2PageNumber() == 0;
        bool hasL1PT = page.l1PageNumber() == 0;

#if 0
        cerr << "split: page " << page << " hasL4 = " << hasL4PT
             << " hasL3 = " << hasL3PT << " hasL2 = " << hasL2PT
             << " hasL1 = " << hasL1PT << endl;
        cerr << "page.offset = " << ML::format("%llx", page.offset)
             << endl;
        cerr << "(page.offset & ~((1ULL << 22) - 1))"
             << ML::format("%llx", (page.offset & ~((1ULL << 22) - 1)))
             << endl;
        cerr << ML::format("((1ULL << 22) - 1) = %llx", ((1ULL << 22) - 1))
             << endl;
#endif

        if (!hasL1PT) {
            cerr << "page = " << page << endl;
        }

        // Must be true, since we're accessing it above (as the pt variable)
        ExcAssert(hasL1PT);

        int numReserved = 0;

        if (hasMetadata) {   // two pages at start
            pt->reserve(0);
            pt->reserve(1);
            pt->setType(0, PT_METADATA);
            pt->setType(1, PT_PAGE_ALLOCATOR);
            numReserved += 2;
        }
        else {
            if (allocate) {
                result = page.subpage(0);
                pt->reserve(0);
            }
        }

        if (hasL4PT) {      // One every 4PB = 2^52 bytes... so one!
            pt->reserve(2);
            pt->setType(2, PT_L4_PTE);
            ++numReserved;
        } else {
            if (!result && allocate) {
                result = page.subpage(2);
                pt->reserve(2);
            }
        }

        if (hasL3PT) {      // One every 4TB = 2^42 bytes
            pt->reserve(3);
            pt->setType(3, PT_L3_PTE);
            ++numReserved;
        } else {
            if (!result && allocate) {
                result = page.subpage(3);
                pt->reserve(3);
            }
        }

        if (hasL2PT) {      // One every 4GB = 2^32 bytes
            pt->reserve(4);
            pt->setType(4, PT_L2_PTE);
            ++numReserved;
        } else {
            if (!result && allocate) {
                result = page.subpage(4);
                pt->reserve(4);
            }
        }

        if (hasL1PT) {      // One every 4MB = 2^22 bytes
            pt->reserve(5);
            pt->setType(5, PT_L1_PTE);
            ++numReserved;
        } else {
            if (!result && allocate) {
                result = page.subpage(5);
                pt->reserve(5);
            }
        }

        if (!result && allocate) {
            result = page.subpage(6);
            pt->reserve(6);
        }

        numFreePages = 1024 - numReserved - allocate;
    }
    else {
        // The first page has to be split all the way down so that there
        // is room for the page tables

        pt->reserve(0);
        splitPage(page.subpage(0), false /* allocate */);
        pt->setType(0, PageType(PT_4M_SPLIT + 3 - page.order));

        // The rest of them are free
        numFreePages = 1023 - allocate;

        if (allocate) {
            pt->reserve(1);
            result = page.subpage(1);
        }
    }

    // Notify that this page contains free pages of the given order.
    notifyPageContainsFreeSubpages(page, page.order - 1, numFreePages);

    //cerr << "splitPage returned " << result << endl;

    //cerr << "after split" << endl;
    //dumpPageTableInfo(page.subpage(0));

    return result;
}

Page
PageTableAllocator::
allocatePage(int order)
{
    //boost::lock_guard<boost::recursive_mutex> guard(mutex);
    ExcAssert(region_->isPinned());
    return doAllocatePage(order, false);
}

Page
PageTableAllocator::
allocatePageOfType(int order, uint8_t pageType)
{
    ExcAssert(region_->isPinned());

    // TODO: as part of allocating it
    Page allocated = allocatePage(order);

    // TODO: on exception...

    if (!allocated)
        throw ML::Exception("couldn't allocate page");

    auto pt = getPageTableForPage(allocated);
    int index = getPageTableIndex(allocated);

    //cerr << "index = " << index << endl;

    pt->setType(index, (PageType)pageType);

    return allocated;
}

Page
PageTableAllocator::
allocatePageAndSplit(int order, bool allocate)
{
    // TODO: don't allow for more than one 4G page to be allocated at once

    Page bigPage = doAllocatePage(order, true /* to_split */);
    try {
        return splitPage(bigPage, allocate);
    }
    catch(RegionResizeException& ex) {
        // If this exception is raised then the split page wasn't initialized
        // so deallocate it. Note that this should be a fairly rare event.
        deallocatePage(bigPage);
        throw;
    }
}

Page
PageTableAllocator::
doAllocatePage(int order, bool toSplit)
{
    //cerr << "doAllocatePage(" << order << ")" << endl;
    if (order < 0 || order > 5)
        throw ML::Exception("attempt to allocate page of invalid order");

    if (order == 5) {
        ExcAssert(toSplit);

        // There should only be one of these...
        auto md = getMetadata();

        ExcAssert(md->valid());

        if (md->allocatedOrder5)
            throw ML::Exception("Order 5 page already allocated");

        // TODO: make sure it's atomic(?) (shouldn't really be necessary...)

        md->allocatedOrder5 = true;

        return Page(0, 5);
    }

    if (order == 1 && toSplit)
        throw ML::Exception("can't split a level 1 page");

    // 1.  Look in the freelist for a page to find a higher level
    //     page that has at least one free entry.

    PageType type;
    if (toSplit) type = PageType(PT_4M_SPLIT + 2 - order);
    else type = PageType(PT_4K_PAGE + 1 - order);

    Page result = allocateFreePage(order);
    bool gotFree = result;
    if (!result) result = allocatePageAndSplit(order + 1, true /* allocate */);
    if (!result)
        throw ML::Exception("couldn't allocate any pages");

    {
        // Update the page's type
        auto pt = getPageTableForPage(result);
        int index = getPageTableIndex(result);

        if (pt->getType(index) != PT_EMPTY) {
            cerr << "gotFree = " << gotFree << endl;
            cerr << "result = " << result << endl;
            cerr << "index = " << index << endl;
            cerr << "pt = " << endl;
            dumpPageTableInfo(result);
        }

        ExcAssertEqual(pt->getType(index), PT_EMPTY);
        pt->setType(index, type);
    }

    // If we're not splitting, make sure that the page is present and
    // backed
    if (!toSplit && result.endOffset() > region_->length()) {
        try {
            region_->grow(result.endOffset());
        }
        catch (RegionResizeException& ex) {
            // If the resize failed, deallocate the page so it doesn't leak.
            deallocatePage(result);
            throw;
        }
    }

    return result;
}

void
PageTableAllocator::
deallocatePage(Page page)
{
    //boost::lock_guard<boost::recursive_mutex> guard2(mutex);

    ExcAssert(region_->isPinned());

    //cerr << "deallocatePage(" << page << ")" << endl;

    if (page.order < 1 || page.order > 5)
        throw ML::Exception("attempt to deallocate page of invalid order");

    if (page.order == 5)
        throw ML::Exception("the level 5 page should never be deallocated");

    // Set the page type and allocated flag to false

    bool needUpdate = true;

    for (int order = page.order;  needUpdate && order < 5;  ++order) {
        // The page table was full before but now it's not.  We need to recurse
        // down marking each stage non-full.

        //cerr << "marking order " << order << " deallocated" << endl;

        auto pt = getPageTableForPage(page, order);

        //dumpPageTableInfo(Page(page.offset, order));

        needUpdate = pt->markDeallocated(getPageTableIndex(page, order),
                                        page.order);
    }
}

uint64_t
PageTableAllocator::
getPageTableOffset(Page page, int order)
{
    if (order == -1) order = page.order;
    if (order == 5) return page_size;
    Page super = page.superpage(order + 1);
    return super.offset + (6 - order) * page_size;
}

RegionPtr<PageTable>
PageTableAllocator::
getUninitializedPageTableForPage(Page page, int order)
{
    if (order == -1) order = page.order;

    uint64_t offset = getPageTableOffset(page, order);

    // We can't make it grow since that may need a write lock and we
    // already have the read lock... that needs to be handled somewhere
    // else.

    return RegionPtr<PageTable>(*region_, offset);
}

RegionPtr<PageTable>
PageTableAllocator::
getPageTableForPage(Page page, int order)
{
    if (order == -1) order = page.order;
    auto result = getUninitializedPageTableForPage(page, order);
    ExcAssert(result->valid());
    ExcAssertEqual(result->order, order);
    return result;
}

RegionPtr<PageTableAllocator::Metadata>
PageTableAllocator::
getMetadata()
{
    return RegionPtr<Metadata>(*region_, page_size);
}

Page
PageTableAllocator::
allocateFreePage(int order)
{
    ExcAssertGreaterEqual(order, 1);

    // The one L5 page is always split and so can't be allocated
    ExcAssertLessEqual(order, 4);

    // Try up to 3 times
    int NUM_ATTEMPTS = 3;

    Page result;

    //int threadNum = random();

    //cerr << "allocateFreePage(order=" << order << ")" << endl;

    for (int attempt = 0;  !result && attempt < NUM_ATTEMPTS;  ++attempt) {

        Page page(0, 5);

        // Go from bigger to smaller pages, narrowing down at each
        // step...
        for (int currentOrder = 5;  currentOrder > order;  --currentOrder) {

            //cerr << "attempt " << attempt << " page " << page
            //     << " currentOrder " << currentOrder
            //     << " order " << order << endl;

            // Find the page table
            auto pt = getPageTableForPage(page.subpage(0));

            ExcAssert(pt->valid());
            ExcAssertEqual(pt->order, page.order - 1);

            //dumpPageTableInfo(page.subpage(0));

            int startAt = 0;//(currentOrder > 3 ? 0 : random());

            if (currentOrder == order + 1) {
                // Finally, we allocate a page
                int pageNum;
                bool full;

                boost::tie(pageNum, full) = pt->allocate(startAt);

                //cerr << "pageNum = " << pageNum << " full = "
                //     << full << endl;

                if (pageNum == -1)
                    break;  // full; backtrack and try again

                result = page.subpage(pageNum);

                //cerr << "result = " << result << endl;

                while (pageNum != -1 && full && page.order < 5) {
                    // we moved from not full to full... we need to pass
                    // this information down
                    int index = getPageTableIndex(page);
                    //cerr << "page = " << page << " index = " << index
                    //     << endl;

                    auto pt = getPageTableForPage(page);

                    //dumpPageTableInfo(page);

                    try {
                        full = pt->markAllocated(index, result.order);
                    } catch (...) {
                        cerr << "marking allocated: index = " << index
                             << " order = " << order << " page = "
                             << page << " result = " << result << endl;
                        throw;
                    }

                    //cerr << "after markAllocated: full = " << full << endl;

                    //dumpPageTableInfo(page);
                    page = page.superpage();
                }
            }
            else {
                // We're not yet down to the last order.  Look in the
                // bitmap for our order.
                FullBitmap<1024> & bitmap = pt->fullLevels[order - 1];

                int subPage = bitmap.getNonFullEntry(startAt);

                //cerr << "subPage = " << subPage << endl;

                if (subPage == -1)
                    break;  // full; backtrack and try again

                ExcAssert(pt->subpageIsSplit(subPage));

                page = page.subpage(subPage);
            }
        }
    }

    return result;
}

void
PageTableAllocator::
notifyPageContainsFreeSubpages(Page page, int order, uint64_t numFree)
{
    // TODO: contains the same logic as deallocatePage... unify them

    //cerr << "notifyPageContainsFreeSubpages(" << page << ", " << order
    //     << ", " << numFree << ")" << endl;

    // We assume that the l5 page contains free subpages of all kinds
    if (page.order == 5)
        return;

    ExcAssertGreaterEqual(order, 1);
    ExcAssertLessEqual(order, page.order);

    int subpage = getPageTableIndex(page);

    //cerr << "  subpage = " << subpage << endl;

    auto pt = getPageTableForPage(page);
    ExcAssertEqual(pt->order, page.order);

    bool needPropagation;

    if (order == page.order)
        needPropagation = pt->allocated.markDeallocated(subpage);
    else
        needPropagation = pt->fullLevels[order - 1].markDeallocated(subpage);

    if (needPropagation)
        notifyPageContainsFreeSubpages(page.superpage(), order, numFree);
}

int
PageTableAllocator::
getPageTableIndex(Page page, int order)
{
    if (order == -1) order = page.order;
    if (order == 5) return 0;  // only one order 5 page

    //cerr << "getPageTableIndex: page " << page << " order " << order
    //     << endl;

    Page super = page.superpage(order + 1);
    int result = (page.offset - super.offset) / getPageSizeForOrder(order);
    ExcAssertGreaterEqual(result, 0);
    ExcAssertLess(result, 1024);
    return result;
}

void
PageTableAllocator::
dumpPageTableInfo(Page page)
{
    ExcAssert(region_->isPinned());
    // Dump page table info for the given page.
    auto pt = getPageTableForPage(page);

    pt->dump();
}

} // namespace MMap
} // namespace Datacratic

ext: cc

max_stars_repo_name: datacratic/DasDB

max_issues_repo_name: datacratic/DasDB

max_forks_repo_name: datacratic/DasDB


text:
/**
 * Copyright (C) 2019 Xilinx, Inc
 *
 * Licensed under the Apache License, Version 2.0 (the "License"). You may
 * not use this file except in compliance with the License. A copy of the
 * License is located at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations
 * under the License.
 */

// ------ I N C L U D E   F I L E S -------------------------------------------
// Local - Include Files
#include "SubCmdFlash.h"
#include "tools/common/XBUtilities.h"
namespace XBU = XBUtilities;

#include "core/common/device.h"
#include "core/common/system.h"
#include "core/pcie/common/device_pcie.h"
#include "core/common/error.h"
#include "flash/flasher.h"

// 3rd Party Library - Include Files
#include <boost/program_options.hpp>
namespace po = boost::program_options;

// System - Include Files
#include <iostream>

// ======= R E G I S T E R   T H E   S U B C O M M A N D ======================
#include "tools/common/SubCmd.h"
static const unsigned int registerResult =
                    register_subcommand("flash",
                                        "Update SC firmware or shell on the device",
                                        subCmdFlash);
// =============================================================================

// ------ L O C A L   F U N C T I O N S ---------------------------------------

namespace {

static void
scan_devices(bool verbose, bool json)
{
  json = json;
  auto total = xrt_core::get_total_devices().first;

  if (total == 0) {
    std::string errMsg = "No card found!";
    throw xrt_core::error(errMsg);
  }

  for(uint16_t i = 0; i < total; i++) {
    Flasher f(i);
    if (!f.isValid())
        return;

    DSAInfo board = f.getOnBoardDSA();
    std::vector<DSAInfo> installedDSA = f.getInstalledDSA();

    BoardInfo info;
    f.getBoardInfo(info);
    std::cout << "Card [" << f.sGetDBDF() << "]:\n";
    std::cout << "\tCard type:\t\t" << board.board << "\n";
    std::cout << "\tFlash type:\t\t" << f.sGetFlashType() << "\n";
    std::cout << "\tFlashable partition running on FPGA:" << "\n";
    std::cout << "\t\t" << board << "\n";
    std::cout << "\tFlashable partitions installed in system:\n";
    if (!installedDSA.empty())
	    std::cout << "\t\t" << installedDSA.front() << "\n";
    else
	    std::cout << "\t\tNone\n";

    if (verbose) {
	  std::cout << "\tCard name\t\t\t" << info.mName << "\n";
	  std::cout << "\tCard S/N: \t\t\t" << info.mSerialNum << "\n";
	  std::cout << "\tConfig mode: \t\t" << info.mConfigMode << "\n";
	  std::cout << "\tFan presence:\t\t" << info.mFanPresence << "\n";
	  std::cout << "\tMax power level:\t\t" << info.mMaxPower << "\n";
	  std::cout << "\tMAC address0:\t\t" << info.mMacAddr0 << "\n";
	  std::cout << "\tMAC address1:\t\t" << info.mMacAddr1 << "\n";
	  std::cout << "\tMAC address2:\t\t" << info.mMacAddr2 << "\n";
	  std::cout << "\tMAC address3:\t\t" << info.mMacAddr3 << "\n";
    }
  }
}

// Update shell on the board.
static void
update_shell(uint16_t index, const std::string& flashType,
    const std::string& primary, const std::string& secondary)
{
    std::shared_ptr<firmwareImage> pri;
    std::shared_ptr<firmwareImage> sec;

    if (!flashType.empty()) {
        std::cout << "CAUTION: Overriding flash mode is not recommended. " <<
            "You may damage your card with this option." << std::endl;
    }

    Flasher flasher(index);
    if(!flasher.isValid())
        return;

    if (primary.empty())
        return;

    pri = std::make_shared<firmwareImage>(primary.c_str(), MCS_FIRMWARE_PRIMARY);
    if (pri->fail())
        return;
    if (!secondary.empty()) {
        sec = std::make_shared<firmwareImage>(secondary.c_str(),
            MCS_FIRMWARE_SECONDARY);
        if (sec->fail())
            sec = nullptr;
    }

    flasher.upgradeFirmware(flashType, pri.get(), sec.get());
    std::cout << "Shell is updated succesfully\n";
    std::cout << "Cold reboot machine to load new shell on card" << std::endl;
}

static void
update_SC(uint16_t index, const std::string& file)
{
    Flasher flasher(index);
    if(!flasher.isValid())
        return;

    std::shared_ptr<firmwareImage> bmc =
        std::make_shared<firmwareImage>(file.c_str(), BMC_FIRMWARE);
    if (bmc->fail())
        return;

    flasher.upgradeBMCFirmware(bmc.get());
}

static void
auto_flash(uint16_t index, std::string& name,
    std::string& id, bool force)
{
  //to-do
  index = index;
  name = name;
  id = id;
  force = force;
}

static void
reset_shell(uint16_t index)
{
  index = index;
}

} // unnamed namespace

// ------ F U N C T I O N S ---------------------------------------------------

int subCmdFlash(const std::vector<std::string> &_options)
// Reference Command:   'flash' sub-command usage:
//                      --scan [--verbose|--json]
//                      --update [--shell name [--id id]] [--card bdf] [--force]
//                      --factory_reset [--card bdf]
//
//                      Experts only:
//                      --shell --path file --card bdf [--type flash_type]
//                      --sc_firmware --path file --card bdf

{
  XBU::verbose("SubCommand: flash");
  // -- Retrieve and parse the subcommand options -----------------------------
  bool help = false;
  bool scan = false;
  bool reset = false;
  bool update = false;
  bool shell = false;
  bool sc_firmware = false;

  po::options_description flashDesc("flash options");
  flashDesc.add_options()
    ("help", boost::program_options::bool_switch(&help), "Help to use this sub-command")
    ("scan", boost::program_options::bool_switch(&scan), "Information about the card")
    ("shell", boost::program_options::bool_switch(&shell), "Flash platform from source")
    ("sc_firmware", boost::program_options::bool_switch(&sc_firmware), "Flash sc firmware from source")
    //("factory_reset", boost::program_options::bool_switch(&reset), "Reset to golden image")
    //("update", boost::program_options::bool_switch(&update), "Update the card with the installed shell")
  ;

  // po::options_description expertsOnlyDesc("experts only");
  // expertsOnlyDesc.add_options()
  //   ("shell", boost::program_options::bool_switch(&shell), "Flash platform from source")
  //   ("sc_firmware", boost::program_options::bool_switch(&sc_firmware), "Flash sc firmware from source")
  // ;

  po::options_description allOptions("");
  allOptions.add(flashDesc);//.add(expertsOnlyDesc);

  // Parse the command line
  po::parsed_options parsed = po::command_line_parser(_options).
    options(allOptions).         // Global options
    allow_unregistered().           // Allow for unregistered options (needed for options)
    run();                          // Parse the options

  // Parse sub-command ...
  po::variables_map vm;
  try {
    po::store(parsed, vm); //Can throw
    po::notify(vm); // Can throw
  } catch (po::error& e) {
    xrt_core::send_exception_message(e.what(), "XBMGMT");
    std::cerr << allOptions << std::endl;

    // Re-throw exception
    throw;
  }
  // Check to see if help was requested or no command was found
  if (help == true)  {
    std::cout << allOptions << std::endl;
    return 0;
  }

  //prep data
  std::vector<std::string> opts = po::collect_unrecognized(parsed.options, po::include_positional);

  // -- Now process the subcommand --------------------------------------------
  XBU::verbose(XBU::format("  Scan: %ld", scan));
  XBU::verbose(XBU::format("  Shell: %ld", shell));
  // XBU::verbose(XBU::format("  sc_firmware: %ld", sc_firmware));
  // XBU::verbose(XBU::format("  Reset: %ld", reset));
  // XBU::verbose(XBU::format("  Update: %ld", update));

  if (scan) {
    bool verbose;
    bool json = false;
    XBU::verbose("Sub command: --scan");

    po::options_description scanDesc("scan options");
    scanDesc.add_options()
      (",v", boost::program_options::bool_switch(&verbose), "verbose")
      //("json", boost::program_options::bool_switch(&json), "json")
    ;
    // -- Now process the subcommand options ----------------------------------
    po::variables_map option_vm;
    try {
      po::store(po::command_line_parser(opts).options(scanDesc).run(), option_vm);
      po::notify(option_vm); // Can throw
    } catch (po::error& e) {
      xrt_core::send_exception_message(e.what(), "XBMGMT");
      std::cerr << scanDesc << std::endl;
    // Re-throw exception
    throw;
    }

    // -- Now process the subcommand option-------------------------------
    XBU::verbose(XBU::format("  Verbose: %ld", verbose));
    //XBU::verbose(XBU::format("  Json: %ld", json));

    if (verbose && json) {
      XBU::error("Please specify only one option");
      return 1;
    }

    scan_devices(verbose, json);
    return registerResult;
  }

  if (update) {
    //--update [--shell name [--id id]] [--card bdf] [--force]
    bool force;
    std::string bdf;
    std::string name;
    std::string id;

    XBU::verbose("Sub command: --update");

    po::options_description updateDesc("update options");
    updateDesc.add_options()
      ("force", boost::program_options::bool_switch(&force), "force")
      ("card", boost::program_options::value<std::string>(&bdf), "bdf of the card")
      ("shell_name", boost::program_options::value<std::string>(&name), "name of shell")
      ("id", boost::program_options::value<std::string>(&id), "id of the card")
    ;

    // -- Now process the subcommand options ----------------------------------
    po::variables_map option_vm;
    try {
      po::store(po::command_line_parser(opts).options(updateDesc).run(), option_vm);
      po::notify(option_vm); // Can throw
    } catch (po::error& e) {
      xrt_core::send_exception_message(e.what(), "XBMGMT");
      std::cerr << updateDesc << std::endl;
    // Re-throw exception
    throw;
    }

    // -- Now process the subcommand option-------------------------------
    XBU::verbose(XBU::format("  Force: %ld", force));
    XBU::verbose(XBU::format("  Card: %s", bdf.c_str()));
    XBU::verbose(XBU::format("  Shell_name: %s", name.c_str()));
    XBU::verbose(XBU::format("  Card id: %s", id.c_str()));

    if (name.empty() && !id.empty()){
      XBU::error("Please specify the shell");
      return 1;
    }

    uint16_t idx = xrt_core::bdf2index(bdf);
    auto_flash(idx, name, id, force);
    return registerResult;
  }

  if (reset) {
    // --factory_reset [--card bdf]
    std::string bdf;

    XBU::verbose("Sub command: --factory_reset");

    po::options_description resetDesc("factory_reset options");
    resetDesc.add_options()
      ("card", boost::program_options::value<std::string>(&bdf), "bdf of the card");

    po::variables_map option_vm;
    try {
      po::store(po::command_line_parser(opts).options(resetDesc).run(), option_vm);
      po::notify(option_vm); // Can throw
    } catch (po::error& e) {
      xrt_core::send_exception_message(e.what(), "XBMGMT");
      std::cerr << resetDesc << std::endl;
    // Re-throw exception
    throw;
    }

    // -- Now process the subcommand option-------------------------------
    XBU::verbose(XBU::format("  Card: %s", bdf.c_str()));

    uint16_t idx = xrt_core::bdf2index(bdf);
    reset_shell(idx);
    return registerResult;
  }

  if (shell) {
    // --shell --path file --card bdf [--type flash_type]
    std::string bdf;
    std::string file;
    std::string flash_type;
    std::string secondary;

    XBU::verbose("Sub command: --shell");

    po::options_description shellDesc("shell options");
    shellDesc.add_options()
      ("path", boost::program_options::value<std::string>(&file), "path of shell file")
      ("card", boost::program_options::value<std::string>(&bdf), "index of the card") //change this to bdf later
      // ("type", boost::program_options::value<std::string>(&flash_type), "flash_type")
    ;

    po::variables_map option_vm;
    try {
      po::store(po::command_line_parser(opts).options(shellDesc).run(), option_vm);
      po::notify(option_vm); // Can throw
    } catch (po::error& e) {
      xrt_core::send_exception_message(e.what(), "XBMGMT");
      std::cerr << shellDesc << "\n";
      std::cerr << "Example: xbmgmt.exe flash --shell --path='path\\to\\dsabin\\file'\n" << std::endl;
    // Re-throw exception
    throw;
    }

    // -- Now process the subcommand option-------------------------------
    XBU::verbose(XBU::format("  Card: %s", bdf.c_str()));
    XBU::verbose(XBU::format("  File: %s", file.c_str()));
    // XBU::verbose(XBU::format("  Flash_type: %s", flash_type.c_str()));

    if (file.empty() || bdf.empty()) {
      XBU::error("Please specify the shell file path and the device bdf");
      std::cerr << shellDesc << "\n";
      std::cerr << "Example: xbmgmt.exe flash --shell --path='path\\to\\dsabin\\file' --card=0000:04:00.0" << std::endl;
      return 1;
    }
	  uint16_t idx = xrt_core::bdf2index(bdf);
    update_shell(idx, flash_type, file, secondary);
    return registerResult;
  }

  if (sc_firmware) {
    //--sc_firmware --path file --card bdf
    std::string bdf;
    std::string file;

    XBU::verbose("Sub command: --sc_firmware");

    po::options_description scDesc("sc_firmware options");
    scDesc.add_options()
      ("path", boost::program_options::value<std::string>(&file), "path of sc firmware file")
      ("card", boost::program_options::value<std::string>(&bdf), "bdf of the card")
    ;

    po::variables_map option_vm;
    try {
      po::store(po::command_line_parser(opts).options(scDesc).run(), option_vm);
      po::notify(option_vm); // Can throw
    } catch (po::error& e) {
      xrt_core::send_exception_message(e.what(), "XBMGMT");
      std::cerr << scDesc << std::endl;
    // Re-throw exception
    throw;
    }

    // -- Now process the subcommand option-------------------------------
    XBU::verbose(XBU::format("  Card: %s", bdf.c_str()));
    XBU::verbose(XBU::format("  Sc_file: %s", file.c_str()));
    if (file.empty() || bdf.empty()) {
      XBU::error("Please specify the sc file path and the device bdf");
      std::cerr << scDesc <<  "\n";
      std::cerr << "Example: xbmgmt.exe flash --sc_firmware --path='path\\to\\dsabin\\file' --card=0000:04:00.0" << std::endl;
      return 1;
    }

    uint16_t idx = xrt_core::bdf2index(bdf);
    update_SC(idx, file);
    return registerResult;
  }

  return registerResult;
}

max_stars_repo_name: giunatale/XRT

max_issues_repo_name: giunatale/XRT

max_forks_repo_name: giunatale/XRT


text:
//  (C) Copyright Gennadiy Rozental 2001-2015.
//  (C) Copyright Beman Dawes 2001.
//  Distributed under the Boost Software License, Version 1.0.
//  (See accompanying file LICENSE_1_0.txt or copy at
//  http://www.boost.org/LICENSE_1_0.txt)

//  See http://www.boost.org/libs/test for the library home page.
//
//  File        : $RCSfile$
//
//  Version     : $Revision$
//
//  Description : tests an ability of Program Execution Monitor to catch
//  uncatched exceptions. Should fail during run.
// ***************************************************************************

#ifdef __MWERKS__
//  Metrowerks doesn't build knowledge of what runtime libraries to link with
//  into their compiler. Instead they depend on pragmas in their standard
//  library headers. That creates the odd situation that certain programs
//  won't link unless at least one standard header is included. Note that
//  this problem is highly dependent on enviroment variables and command
//  line options, so just because the problem doesn't show up on one
//  system doesn't mean it has been fixed. Remove this workaround only
//  when told by Metrowerks that it is safe to do so.
#include <cstddef> //Metrowerks linker needs at least one standard library
#endif

#include <boost/test/included/prg_exec_monitor.hpp>

int
cpp_main( int argc, char *[] )  // note the name
{
    if( argc > 0 ) // to prevent the unreachable return warning
        throw "Test error by throwing C-style string exception";

    return 0;
}

//____________________________________________________________________________//

// EOF