<commit_before>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: chainBuilder.C,v 1.4.10.2 2007/04/03 13:29:37 bertsch Exp $
//
// Author:
//   Holger Franken
//

#include <BALL/KERNEL/bond.h>
#include <BALL/KERNEL/system.h>

#include <BALL/STRUCTURE/sdGenerator.h>
#include <BALL/STRUCTURE/chainBuilder.h>

#ifdef BALL_DEBUG_CHAINBUILDER
#define DEBUG(a) Log.info() << a << std::endl;
#else
# define DEBUG(a)
#endif

namespace BALL
{

	ChainBuilder::ChainBuilder()
	{}

	ChainBuilder::~ChainBuilder()
	{}

	vector<vector<Size> > ChainBuilder::calcAdjMatrix(vector<Atom*>& core_chain_atoms)
	{
		//      build a matrix, holding a "1" if two atoms are bound to each other and "0" if they are not

		DEBUG("\t-*-[ChainHandler]:\tcalcAdjMatrix started." << endl)

		int nodes = core_chain_atoms.size() -1;

		if (nodes < 0)
		{
			nodes = 0;
		}

		vector<vector<Size> > adj_matrix;

		DEBUG("nodes = " << nodes)

		int x(0);
		int y(0);

		for (x = 0; x <= nodes; x++)
		{
			vector<Size> row;

			for (y = 0; y <= nodes; y++)
			{
				row.push_back(0);
			}
			adj_matrix.push_back(row);
		}

		for (x = 0; x <= nodes; x++)
		{
			for (y = 0; y <= nodes; y++)
			{
				if (core_chain_atoms[x] -> isBoundTo(*(core_chain_atoms[y])))
				{
					adj_matrix[x][y] = 1;
				}
			}
		}

		for (x = 0; x <= nodes; x++)
		{
			adj_matrix[x][x] = 1;
		}

		DEBUG("\t-*-[ChainHandler]:\tcalcAdjMatrix done." << endl)

		return adj_matrix;
	}

	void ChainBuilder::visit_c_areas(Size& k, vector<vector<Size> >& adj_matrix, vector<int>& val, Size& nodes, Size& id, vector<Atom*>& core_chain_atoms, vector<Atom*>& chain_area)
	{
		//      recursive visit-procedure used in the depth-first-search for chain-areas
		Size t(0);
		val[k] = ++id;

		for (t = 0; t <= nodes; t++)
		{
			if (adj_matrix[k][t] != 0)
			{
				if (val[t] == 0)
				{
					visit_c_areas(t, adj_matrix, val, nodes, id,  core_chain_atoms, chain_area);
				}
			}
		}
		chain_area.push_back(core_chain_atoms[k]);
	}

	void ChainBuilder::findChainAreas(Size& nodes, vector<vector<Size> >& adj_matrix, vector<Atom*>& core_chain_atoms, vector<vector<Atom*> >& chain_areas)
	{
		//      depth-first-search for the chain-areas

		vector<int> val;        //      vector to hold the order, in which the atoms were visited
		Size id(0);
		Size k(0);

		for (Size i = 0; i <= nodes; i++)
		{
			val.push_back(0);
		}

		for (k = 0; k <= nodes; k++)
		{

			if (val[k] == 0)
			{
				vector<Atom*> chain_area;
				//      the recursive visit-function finds one connected chain-area each time it is called
				visit_c_areas(k, adj_matrix, val, nodes, id, core_chain_atoms, chain_area);
				chain_areas.push_back(chain_area);
			}
		}

	}

	void ChainBuilder::findEdges(vector<Atom*>& chain_area)
	{
		//      find atoms that have only one adjacent core-chain-atom and therefore must be an edge of the chain-area
		for (vector<Atom*>::size_type i = 0; i != chain_area.size(); i++)
		{
			Size adjacent_core_chain_atoms = 0;

			for (Atom::BondIterator bond_it = chain_area[i] -> beginBond(); bond_it != chain_area[i] -> endBond(); bond_it++)
			{
				if (bond_it -> getPartner(*chain_area[i]) -> hasProperty(SDGenerator::CORE_CHAIN))
				{
					adjacent_core_chain_atoms ++;
				}
			}

			if (adjacent_core_chain_atoms < 2)
			{
				chain_area[i] -> setProperty(SDGenerator::EDGE);
			}
		}
	}

	void ChainBuilder::visit_chains(Size& k,  vector<vector<Size> >& adj_matrix, vector<int>& val, Size& id, vector<Atom*>& chain_area, Size& end, bool& breaker, Size& t, vector<Atom*>& prev_nodes)
	{
		list<Size> queue;

		//queue.enQueue(k);     //      put the starting atom Sizeo the queue
		queue.push_back(k);

		//while ((!queue.isEmpty()) && (!(breaker)))
		while ((!queue.empty()) && (!(breaker)))
		{
			//k = queue.deQueue();  //      get the next atom from the queue
			k = *queue.begin();
			queue.erase(queue.begin());

			val[k] = ++id;

			//      enqueue every atom that is bound to the current one and has not been seen yet, and set its previous atom to the current one
			for (t = 0; t != adj_matrix.size(); t++)
			{
				if ((adj_matrix[k][t] == 1) && (k != t))
				{
					//      if the end atom is reached, stop the search and return
					if (chain_area[t] == chain_area[end])
					{
						prev_nodes[t] = chain_area[k];
						breaker = 1;
						break;
					}

					if (val[t] == INT_MAX)
					{
						prev_nodes[t] = chain_area[k];
						queue.push_back(t);
						val[t] = -1;
					}
				}
			}
		}
	}

	// get the index of an Atom-poSizeer in a certain vector<Atom*>
	Size ChainBuilder::getIndex(Atom*& atom, vector<Atom*>& container)
	{
		for (Size i = 0; i != container.size(); i++)
		{
			if (container[i] == atom)
			{
				return i;
			}
		}

		DEBUG("!!! getIndex failed !!! ")
		return INT_MAX;
	}

	vector<Atom*> ChainBuilder::findPath(Atom*& first_edge, Atom*& second_edge,vector<Atom*>& chain_area, vector<vector<Size> >& adj_matrix)
	{
		//breadth first search with traceback to find the path between every two edges in chain-area
		vector<Atom*> path;

		vector<int> val;                                                        //      vector to hold the order, in which the atoms were visited
		vector<Atom*> prev_nodes;                       //      vector to hold the previously visited atom for each atom
		Size id = 0;

		Size t(0); //      starting position for the traceback after the end atom has been found

		//      get the indices of the two edges between which the path shall be found
		Size start = getIndex(first_edge, chain_area);
		Size end = getIndex(second_edge, chain_area);

		//      initialize the vectors val and prev_nodes
		for (Size i = 0; i != chain_area.size(); i++)
		{
			val.push_back(INT_MAX);
			prev_nodes.push_back(0);
		}

		Size k = start;

		//      flag to indicate when the end is found and finish the search
		bool breaker = 0;

		while (!breaker)
		{
			if (val[k] == INT_MAX)
			{
				visit_chains(k, adj_matrix, val, id, chain_area, end, breaker, t, prev_nodes);
			}
		}

		//      traceback from the end of the path along the previously found atoms to the beginning of the path
		Atom* traceback = chain_area[t];

		while (traceback != chain_area[start])
		{
			path.push_back(traceback);

			traceback = prev_nodes[getIndex(traceback, chain_area)];
		}
		path.push_back(chain_area[start]);

		return path;
	}

  // comparator, used to sort the chains by their length

	bool ChainBuilder::compareChains(const vector<Atom*>& x, const vector<Atom*>& y)
	{
		return x.size() > y.size();
	}

	vector<vector<Atom*> > ChainBuilder::findChains(vector<Atom*>& chain_area, vector<vector<Size> >& adj_matrix)
	{
		DEBUG("\t-*-[buildChains]:\t findChains called.")

		vector<vector<Atom*> > chains;

		//      for every two edges of the chain-area, find the path beween them
		for (vector<Atom*>::size_type i = 0; i != chain_area.size(); i++)
		{
			for (vector<Atom*>::size_type j = 0; j != chain_area.size(); j++)
			{
				if (i != j)
				{

					if (chain_area[i] -> hasProperty(SDGenerator::EDGE)  && chain_area[j] -> hasProperty(SDGenerator::EDGE))
					{
						vector<Atom*> chain = findPath(chain_area[i], chain_area[j], chain_area, adj_matrix);
						chains.push_back(chain);
					}

				}
			}
		}
		//      sort the found chains by their length

		// 		ChainBuilder cb;
		sort(chains.begin(), chains.end(), ChainBuilder::compareChains);

		vector<vector<Atom*> > new_chains;

		Size max_adj_rings = 0;
		Size keep_i = 0;
		for (Size i = 0; i != chains.size(); i++)
		{
			Size adj_rings = 0;
			if (chains[i].size() == chains[0].size())
			{

				for (Atom::BondIterator bond_it = chains[i][0] -> beginBond(); bond_it != chains[i][0] -> endBond(); ++bond_it)
				{
					if (bond_it -> getPartner(*chains[i][0]) -> hasProperty(SDGenerator::IN_RING))
					{
						adj_rings++;
					}
				}

				// if there is more than one chain of maximum length, chose the one with the most adjacent rings as the main chain
				for (Atom::BondIterator bond_it = chains[i][chains[i].size() -1] -> beginBond(); bond_it != chains[i][chains[i].size() -1] -> endBond(); ++bond_it)
				{
					if (bond_it -> getPartner(*chains[i][chains[i].size() -1]) -> hasProperty(SDGenerator::IN_RING))
					{
						adj_rings++;
					}
				}
				if (adj_rings > max_adj_rings)
				{
					max_adj_rings = adj_rings;
					keep_i = i;
				}
			}
		}

		// arrange all the other chains around the the main chain

		for (Size i = 0; i != chains[keep_i].size(); i++)
		{
			chains[keep_i][i] -> setProperty(SDGenerator::BUILT_IN_CHAIN);
		}

		new_chains.push_back(chains[keep_i]);

		bool pushbacked = 0;
		bool increment_i = 0;
		Size j = 0;
		for (Size i = 1; i != chains.size();)
		{
			pushbacked = 0;
			increment_i = 0;

			vector<Atom*> new_chain;

			while (!(increment_i))
			{
				if (!(chains[i][j] -> hasProperty(SDGenerator::BUILT_IN_CHAIN)))
				{
					chains[i][j] -> setProperty(SDGenerator::BUILT_IN_CHAIN);
					new_chain.push_back(chains[i][j]);
				}
				else
				{
					if (new_chain.size() > 0)
					{
						new_chains.push_back(new_chain);
						pushbacked = 1;

						break;
					}
				}

				j++;

				if (j == chains[i].size())
				{
					j = 0;
					increment_i = 1;
				}
			}

			if (new_chain.size() > 0 && !pushbacked)
			{
				new_chains.push_back(new_chain);
			}

			if (increment_i)
			{
				i++;
			}
		}

		return new_chains;

	}

	vector<vector<Atom*> > ChainBuilder::buildChains(System& molecule_sys)
	{
		//      declare return-vector
		vector<vector<Atom*> > all_chains;

		//      build a vector holding all core-chain-atoms
		vector<Atom*> core_chain_atoms;

		vector<Size> visited;

		AtomIterator atom_it;

		for (atom_it = molecule_sys.beginAtom(); atom_it != molecule_sys.endAtom(); ++atom_it)
		{
			if (atom_it -> hasProperty(SDGenerator::CORE_CHAIN))
			{
				core_chain_atoms.push_back(&(*atom_it));
			}

		}

		//      calculate an adjacence-matrix for the core-chain-atoms

		if (core_chain_atoms.size() > 0)
		{
			vector<vector<Size> > adj_matrix = calcAdjMatrix(core_chain_atoms);

			static Size nodes = core_chain_atoms.size() -1;

			vector<vector<Atom*> > chain_areas;

			//      depth-first-search for areas, consisting of chains
			findChainAreas(nodes, adj_matrix, core_chain_atoms, chain_areas);

			DEBUG("\t-*-[buildChains]:\t" << chain_areas.size() << " chain areas found." << endl)

			for (vector<vector<Atom*> >::size_type i = 0; i != chain_areas.size(); i++)
			{
				//      find all ending core chain atoms in a chain-area
				findEdges(chain_areas[i]);

				//      calculate an adjacence-matrix for the chain-area
				adj_matrix = calcAdjMatrix(chain_areas[i]);

				//      breadth first search for all chains in the chain-area
				vector<vector<Atom*> > chains = findChains(chain_areas[i], adj_matrix);

				for (Size i = 0; i != chains.size(); i++)
				{
					all_chains.push_back(chains[i]);
				}

			}
// 			ChainBuilder cb;
			sort(all_chains.begin(), all_chains.end(), ChainBuilder::compareChains);
		}

		return all_chains;

	}

} // namespace BALL

<commit_msg>*** empty log message ***<commit_after>// -*- Mode: C++; tab-width: 2; -*-
// vi: set ts=2:
//
// $Id: chainBuilder.C,v 1.4.10.3 2007/08/08 10:25:04 oliver Exp $
//
// Author:
//   Holger Franken
//

#include <BALL/KERNEL/bond.h>
#include <BALL/KERNEL/system.h>

#include <BALL/STRUCTURE/sdGenerator.h>
#include <BALL/STRUCTURE/chainBuilder.h>

#ifdef BALL_DEBUG_CHAINBUILDER
#define DEBUG(a) Log.info() << a << std::endl;
#else
# define DEBUG(a)
#endif

namespace BALL
{

	ChainBuilder::ChainBuilder()
	{}

	ChainBuilder::~ChainBuilder()
	{}

	vector<vector<Size> > ChainBuilder::calcAdjMatrix(vector<Atom*>& core_chain_atoms)
	{
		//      build a matrix, holding a "1" if two atoms are bound to each other and "0" if they are not

		DEBUG("\t-*-[ChainHandler]:\tcalcAdjMatrix started." << endl)

		int nodes = core_chain_atoms.size() -1;

		if (nodes < 0)
		{
			nodes = 0;
		}

		vector<vector<Size> > adj_matrix;

		DEBUG("nodes = " << nodes)

		int x(0);
		int y(0);

		for (x = 0; x <= nodes; x++)
		{
			adj_matrix.push_back(vector<Size>(nodes + 1, 0));
		}

		for (x = 0; x <= nodes; x++)
		{
			for (y = 0; y <= nodes; y++)
			{
				if (core_chain_atoms[x] -> isBoundTo(*(core_chain_atoms[y])))
				{
					adj_matrix[x][y] = 1;
				}
			}
		}

		for (x = 0; x <= nodes; x++)
		{
			adj_matrix[x][x] = 1;
		}

		DEBUG("\t-*-[ChainHandler]:\tcalcAdjMatrix done." << endl)

		return adj_matrix;
	}

	void ChainBuilder::visit_c_areas(Size& k, vector<vector<Size> >& adj_matrix, vector<int>& val, Size& nodes, Size& id, vector<Atom*>& core_chain_atoms, vector<Atom*>& chain_area)
	{
		//      recursive visit-procedure used in the depth-first-search for chain-areas
		Size t(0);
		val[k] = ++id;

		for (t = 0; t <= nodes; t++)
		{
			if (adj_matrix[k][t] != 0)
			{
				if (val[t] == 0)
				{
					visit_c_areas(t, adj_matrix, val, nodes, id,  core_chain_atoms, chain_area);
				}
			}
		}
		chain_area.push_back(core_chain_atoms[k]);
	}

	void ChainBuilder::findChainAreas(Size& nodes, vector<vector<Size> >& adj_matrix,
																		vector<Atom*>& core_chain_atoms, vector<vector<Atom*> >& chain_areas)
	{
		//      depth-first-search for the chain-areas
		vector<int> val(nodes + 1, 0);        //      vector to hold the order, in which the atoms were visited
		Size id(0);
		Size k(0);

		for (k = 0; k <= nodes; k++)
		{
			if (val[k] == 0)
			{
				vector<Atom*> chain_area;
				//      the recursive visit-function finds one connected chain-area each time it is called
				visit_c_areas(k, adj_matrix, val, nodes, id, core_chain_atoms, chain_area);
				chain_areas.push_back(chain_area);
			}
		}
	}

	void ChainBuilder::findEdges(vector<Atom*>& chain_area)
	{
		//      find atoms that have only one adjacent core-chain-atom and therefore must be an edge of the chain-area
		for (vector<Atom*>::size_type i = 0; i < chain_area.size(); i++)
		{
			Size adjacent_core_chain_atoms = 0;

			for (Atom::BondIterator bond_it = chain_area[i] -> beginBond(); bond_it != chain_area[i] -> endBond(); bond_it++)
			{
				if (bond_it -> getPartner(*chain_area[i]) -> hasProperty(SDGenerator::CORE_CHAIN))
				{
					adjacent_core_chain_atoms ++;
				}
			}

			if (adjacent_core_chain_atoms < 2)
			{
				chain_area[i] -> setProperty(SDGenerator::EDGE);
			}
		}
	}

	void ChainBuilder::visit_chains(Size& k,  vector<vector<Size> >& adj_matrix, vector<int>& val, Size& id, vector<Atom*>& chain_area, Size& end, bool& breaker, Size& t, vector<Atom*>& prev_nodes)
	{
		list<Size> queue;

		//queue.enQueue(k);     //      put the starting atom Sizeo the queue
		queue.push_back(k);

		//while ((!queue.isEmpty()) && (!(breaker)))
		while ((!queue.empty()) && (!(breaker)))
		{
			//k = queue.deQueue();  //      get the next atom from the queue
			k = *queue.begin();
			queue.erase(queue.begin());

			val[k] = ++id;

			//      enqueue every atom that is bound to the current one and has not been seen yet, and set its previous atom to the current one
			for (t = 0; t != adj_matrix.size(); t++)
			{
				if ((adj_matrix[k][t] == 1) && (k != t))
				{
					//      if the end atom is reached, stop the search and return
					if (chain_area[t] == chain_area[end])
					{
						prev_nodes[t] = chain_area[k];
						breaker = 1;
						break;
					}

					if (val[t] == INT_MAX)
					{
						prev_nodes[t] = chain_area[k];
						queue.push_back(t);
						val[t] = -1;
					}
				}
			}
		}
	}

	// get the index of an Atom-poSizeer in a certain vector<Atom*>
	Size ChainBuilder::getIndex(Atom*& atom, vector<Atom*>& container)
	{
		for (Size i = 0; i != container.size(); i++)
		{
			if (container[i] == atom)
			{
				return i;
			}
		}

		DEBUG("!!! getIndex failed !!! ")
		return INT_MAX;
	}

	vector<Atom*> ChainBuilder::findPath(Atom*& first_edge, Atom*& second_edge,vector<Atom*>& chain_area, vector<vector<Size> >& adj_matrix)
	{
		//breadth first search with traceback to find the path between every two edges in chain-area
		vector<Atom*> path;

		vector<int> val;                                                        //      vector to hold the order, in which the atoms were visited
		vector<Atom*> prev_nodes;                       //      vector to hold the previously visited atom for each atom
		Size id = 0;

		Size t(0); //      starting position for the traceback after the end atom has been found

		//      get the indices of the two edges between which the path shall be found
		Size start = getIndex(first_edge, chain_area);
		Size end = getIndex(second_edge, chain_area);

		//      initialize the vectors val and prev_nodes
		for (Size i = 0; i != chain_area.size(); i++)
		{
			val.push_back(INT_MAX);
			prev_nodes.push_back(0);
		}

		Size k = start;

		//      flag to indicate when the end is found and finish the search
		bool breaker = 0;

		while (!breaker)
		{
			if (val[k] == INT_MAX)
			{
				visit_chains(k, adj_matrix, val, id, chain_area, end, breaker, t, prev_nodes);
			}
		}

		//      traceback from the end of the path along the previously found atoms to the beginning of the path
		Atom* traceback = chain_area[t];

		while (traceback != chain_area[start])
		{
			path.push_back(traceback);

			traceback = prev_nodes[getIndex(traceback, chain_area)];
		}
		path.push_back(chain_area[start]);

		return path;
	}

  // comparator, used to sort the chains by their length

	bool ChainBuilder::compareChains(const vector<Atom*>& x, const vector<Atom*>& y)
	{
		return x.size() > y.size();
	}

	vector<vector<Atom*> > ChainBuilder::findChains(vector<Atom*>& chain_area, vector<vector<Size> >& adj_matrix)
	{
		DEBUG("\t-*-[buildChains]:\t findChains called.")

		vector<vector<Atom*> > chains;

		//      for every two edges of the chain-area, find the path beween them
		for (vector<Atom*>::size_type i = 0; i != chain_area.size(); i++)
		{
			for (vector<Atom*>::size_type j = 0; j != chain_area.size(); j++)
			{
				if (i != j)
				{

					if (chain_area[i] -> hasProperty(SDGenerator::EDGE)  && chain_area[j] -> hasProperty(SDGenerator::EDGE))
					{
						vector<Atom*> chain = findPath(chain_area[i], chain_area[j], chain_area, adj_matrix);
						chains.push_back(chain);
					}

				}
			}
		}
		//      sort the found chains by their length

		// 		ChainBuilder cb;
		sort(chains.begin(), chains.end(), ChainBuilder::compareChains);

		vector<vector<Atom*> > new_chains;

		Size max_adj_rings = 0;
		Size keep_i = 0;
		for (Size i = 0; i != chains.size(); i++)
		{
			Size adj_rings = 0;
			if (chains[i].size() == chains[0].size())
			{

				for (Atom::BondIterator bond_it = chains[i][0] -> beginBond(); bond_it != chains[i][0] -> endBond(); ++bond_it)
				{
					if (bond_it -> getPartner(*chains[i][0]) -> hasProperty(SDGenerator::IN_RING))
					{
						adj_rings++;
					}
				}

				// if there is more than one chain of maximum length, chose the one with the most adjacent rings as the main chain
				for (Atom::BondIterator bond_it = chains[i][chains[i].size() -1] -> beginBond(); bond_it != chains[i][chains[i].size() -1] -> endBond(); ++bond_it)
				{
					if (bond_it -> getPartner(*chains[i][chains[i].size() -1]) -> hasProperty(SDGenerator::IN_RING))
					{
						adj_rings++;
					}
				}
				if (adj_rings > max_adj_rings)
				{
					max_adj_rings = adj_rings;
					keep_i = i;
				}
			}
		}

		// arrange all the other chains around the the main chain

		for (Size i = 0; i != chains[keep_i].size(); i++)
		{
			chains[keep_i][i] -> setProperty(SDGenerator::BUILT_IN_CHAIN);
		}

		new_chains.push_back(chains[keep_i]);

		bool pushbacked = 0;
		bool increment_i = 0;
		Size j = 0;
		for (Size i = 1; i != chains.size();)
		{
			pushbacked = 0;
			increment_i = 0;

			vector<Atom*> new_chain;

			while (!(increment_i))
			{
				if (!(chains[i][j] -> hasProperty(SDGenerator::BUILT_IN_CHAIN)))
				{
					chains[i][j] -> setProperty(SDGenerator::BUILT_IN_CHAIN);
					new_chain.push_back(chains[i][j]);
				}
				else
				{
					if (new_chain.size() > 0)
					{
						new_chains.push_back(new_chain);
						pushbacked = 1;

						break;
					}
				}

				j++;

				if (j == chains[i].size())
				{
					j = 0;
					increment_i = 1;
				}
			}

			if (new_chain.size() > 0 && !pushbacked)
			{
				new_chains.push_back(new_chain);
			}

			if (increment_i)
			{
				i++;
			}
		}

		return new_chains;

	}

	vector<vector<Atom*> > ChainBuilder::buildChains(System& molecule_sys)
	{
		//      declare return-vector
		vector<vector<Atom*> > all_chains;

		//      build a vector holding all core-chain-atoms
		vector<Atom*> core_chain_atoms;

		vector<Size> visited;

		AtomIterator atom_it;

		for (atom_it = molecule_sys.beginAtom(); atom_it != molecule_sys.endAtom(); ++atom_it)
		{
			if (atom_it -> hasProperty(SDGenerator::CORE_CHAIN))
			{
				core_chain_atoms.push_back(&(*atom_it));
			}

		}

		//      calculate an adjacence-matrix for the core-chain-atoms

		if (core_chain_atoms.size() > 0)
		{
			vector<vector<Size> > adj_matrix = calcAdjMatrix(core_chain_atoms);

			Size nodes = core_chain_atoms.size() - 1;

			vector<vector<Atom*> > chain_areas;

			//      depth-first-search for areas, consisting of chains
			findChainAreas(nodes, adj_matrix, core_chain_atoms, chain_areas);

			DEBUG("\t-*-[buildChains]:\t" << chain_areas.size() << " chain areas found." << endl)

			for (vector<vector<Atom*> >::size_type i = 0; i < chain_areas.size(); i++)
			{
				//      find all ending core chain atoms in a chain-area
				findEdges(chain_areas[i]);

				//      calculate the adjacency matrix for the chain-area
				adj_matrix = calcAdjMatrix(chain_areas[i]);

				//      breadth-first search for all chains in the chain-area
				vector<vector<Atom*> > chains = findChains(chain_areas[i], adj_matrix);

				for (Size i = 0; i < chains.size(); i++)
				{
					all_chains.push_back(chains[i]);
				}

			}
			// ChainBuilder cb;
			sort(all_chains.begin(), all_chains.end(), ChainBuilder::compareChains);
		}

		return all_chains;

	}

} // namespace BALL

<|endoftext|>


<commit_before>/*
 *   CrissCross
 *   A multi-purpose cross-platform library.
 *
 *   A product of Uplink Laboratories.
 *
 *   (c) 2006-2009 Steven Noonan.
 *   Licensed under the New BSD License.
 *
 */

#ifndef __included_cc_hashtable_h
#error "This file shouldn't be compiled directly."
#endif

#include <crisscross/compare.h>
#include <crisscross/hash.h>
#include <crisscross/internal_mem.h>

namespace CrissCross
{
	namespace Data
	{
		template <class Data>
		HashTable<Data>::HashTable(size_t _initialSize)
		: m_keys(NULL), m_size(32)
		{
			m_mask = m_size - 1;
			m_slotsFree = m_size;
			m_keys = new char *[m_size];
			m_data = new Data[m_size];

			memset(m_keys, 0, sizeof(char *) * m_size);
			memset(m_data, 0, sizeof(Data) * m_size);
		}

		template <class Data>
		HashTable<Data>::~HashTable()
		{
			empty();

			delete [] m_keys;
			delete [] m_data;
		}

		template <class Data>
		void HashTable<Data>::grow()
		{
			unsigned int oldSize = m_size;
			m_size *= 2;
			m_mask = m_size - 1;
			char **oldKeys = m_keys;
			m_keys = new char *[m_size];
			Data *oldData = m_data;
			m_data = new Data[m_size];

			memset(m_keys, 0, sizeof(char *) * m_size);
			memset(m_data, 0, sizeof(Data) * m_size);

			for (unsigned int i = 0; i < oldSize; ++i) {
				if (oldKeys[i] != NULL) {
					unsigned int newIndex = findInsertIndex(oldKeys[i]);
					m_keys[newIndex] = oldKeys[i];
					m_data[newIndex] = oldData[i];
				}
			}

			m_slotsFree += m_size - oldSize;

			delete [] oldKeys;
			delete [] oldData;
		}

		template <class Data>
		int HashTable<Data>::findInsertIndex(const char *_key) const
		{
			unsigned int index = Hash<const char *>(_key) & m_mask;

			while (m_keys[index] != NULL &&
			       m_keys[index] != (char *)-1)
			{
				CoreAssert(Compare<const char *>((const char *)m_keys[index], _key) != 0);
				index++;
				index &= m_mask;
			}

			return index;
		}

		template <class Data>
		int HashTable<Data>::findIndex(const char *_key) const
		{
			int index = Hash<const char *>(_key) & m_mask;

			if (m_keys[index] == NULL &&
			    m_keys[index] != (char*)-1) {
				return -1;
			}

			while (true)
			{
				if (m_keys[index] != NULL && m_keys[index] != (char*)-1) {
					if (Compare<const char *>((const char *)m_keys[index], _key) == 0)
						break;
				}

				index++;
				index &= m_mask;

				if (m_keys[index] == NULL &&
				    m_keys[index] != (char*)-1 ) {
					return -1;
				}
			}

			return index;
		}

		template <class Data>
		Data HashTable<Data>::find(const char * _key, Data const &_default) const
		{
			int index = findIndex(_key);
			if (index != -1) {
				return m_data[index];
			}
			return _default;
		}

		template <class Data>
		bool HashTable<Data>::exists(const char * _key) const
		{
			return findIndex(_key) != -1;
		}

		template <class Data>
		bool HashTable<Data>::erase(const char *_key)
		{
			int index = findIndex(_key);
			if (index != -1) {
				Dealloc(m_keys[index]);
				m_keys[index] = (char*)-1;
				m_slotsFree++;
				return true;
			}
			return false;
		}

		template <class Data>
		void HashTable<Data>::empty()
		{
			for (size_t i = 0; i < m_size; ++i) {
				if (m_keys[i] == (char*)-1) m_keys[i] = NULL;
				Dealloc(m_keys[i]);
			}

			memset(m_keys, 0, sizeof(char *) * m_size);
			memset(m_data, 0, sizeof(Data) * m_size);
		}

		template <class Data>
		int HashTable<Data>::insert(const char *_key, Data const &_data)
		{
			if (m_slotsFree * 2 <= m_size) {
				grow();
			}

			unsigned int index = findInsertIndex(_key);
			CoreAssert(m_keys[index] == NULL || m_keys[index] == (char*)-1);
			m_keys[index] = cc_strdup(_key);
			m_data[index] = _data;
			m_slotsFree--;

			return index;
		}

		template <class T>
		void SortingHashTable<T>::grow()
		{
			unsigned int oldSize = this->m_size;
			this->m_size *= 2;
			this->m_mask = (this->m_mask << 1) + 1;

			/* Copy pointers to existing data */
			char      * *oldKeys = this->m_keys;
			T           *oldData = this->m_data;
			short       *oldOrderedIndices = m_orderedIndices;

			/* Make new data */
			this->m_keys = new char *[this->m_size];
			this->m_data = new T [this->m_size];
			m_orderedIndices = new short [this->m_size];

			/* Set all new data to zero */
			memset(this->m_keys, 0, sizeof(char *) * this->m_size);
			memset(this->m_data, 0, sizeof(T) * this->m_size);
			for (size_t i = 0; i < this->m_size; i++)
				m_orderedIndices[i] = (short)-1;

			/* */
			/* Go through the existing ordered index list, inserting elements into the */
			/* new table as we go */

			short oldI = m_firstOrderedIndex;
			short newI = this->findInsertIndex(oldKeys[oldI]);
			m_firstOrderedIndex = newI;
			while (oldI != -1)
			{
				short nextOldI = oldOrderedIndices[oldI];

				this->m_keys[newI] = oldKeys[oldI];
				this->m_data[newI] = oldData[oldI];

				short nextNewI = (nextOldI != -1) ? this->findInsertIndex(oldKeys[nextOldI]) : -1;

				m_orderedIndices[newI] = nextNewI;

				oldI = nextOldI;
				newI = nextNewI;
			}

			this->m_slotsFree += this->m_size - oldSize;

			delete [] oldKeys;
			delete [] oldData;
			delete [] oldOrderedIndices;
		}

		/* See header for description */
		template <class T>
		short SortingHashTable<T>::findPrevKey(char const *_key) const
		{
			short prevI = -1;
			short i = m_firstOrderedIndex;

			while (1)
			{
				if (i == -1) return prevI;

				if (Compare((const char *)this->m_keys[i], _key) >= 0)
					return prevI;

				prevI = i;
				i = m_orderedIndices[i];
			}
		}

		template <class T>
		SortingHashTable<T>::SortingHashTable() :
			HashTable<T>(),
			m_firstOrderedIndex(-1)
		{
			m_orderedIndices = new short [this->m_size];
			memset(m_orderedIndices, 0, sizeof(short) * this->m_size);
		}

		template <class T>
		SortingHashTable<T>::~SortingHashTable()
		{
			delete [] m_orderedIndices;
		}

		template <class T>
		int SortingHashTable<T>::insert(char const *_key, T const &_data)
		{
			/* */
			/* Make sure the table is big enough */

			if (this->m_slotsFree * 2 <= this->m_size) {
				grow();
			}

			/* */
			/* Do the main insert */

			unsigned int index = HashTable<T>::findInsertIndex(_key);
			CoreAssert(this->m_keys[index] == NULL || this->m_keys[index] == (char*)-1);
			this->m_keys[index] = cc_strdup(_key);
			this->m_data[index] = _data;
			this->m_slotsFree--;

			/* */
			/* Insert us into the alphabetically order index list */

			short        i = findPrevKey(_key);
			if (i == -1) {
				/* Handle the case when the table is empty, or the new element is going */
				/* to be the new first alphabetical element */
				m_orderedIndices[index] = m_firstOrderedIndex;
				m_firstOrderedIndex = index;
			} else	{
				m_orderedIndices[index] = m_orderedIndices[i];
				m_orderedIndices[i] = index;
			}

			return index;
		}

		template <class T>
		bool SortingHashTable<T>::erase(char const *_key)
		{
			int index = this->GetIndex(_key);
			if (index >= 0)	{
				return erase(index);
			}
			return false;
		}

		template <class T>
		bool SortingHashTable<T>::erase(size_t _index)
		{
			bool retval = false;
			/* */
			/* Remove data */

			if (this->m_keys[_index] != (char *)-1) {
				retval = true;
				delete [] this->m_keys[_index];
			}
			this->m_keys[_index] = (char *)-1;
			this->m_slotsFree++;

			/* */
			/* Remove from ordered list */

			short prevIndex = -1;
			short index = m_firstOrderedIndex;
			while (m_orderedIndices[index] != _index)
			{
				CoreAssert(index != -1);
				prevIndex = index;
				index = m_orderedIndices[index];
			}

			if (prevIndex == -1) {
				m_firstOrderedIndex = -1;
			} else	{
				m_orderedIndices[prevIndex] = m_orderedIndices[index];
			}
			return retval;
		}

		template <class T>
		short SortingHashTable<T>::beginOrderedWalk()
		{
			m_nextOrderedIndex = m_orderedIndices[m_firstOrderedIndex];
			return m_firstOrderedIndex;
		}

		template <class T>
		short SortingHashTable<T>::nextOrderedIndex()
		{
			short rv = m_nextOrderedIndex;
			if (rv != -1)
				m_nextOrderedIndex = m_orderedIndices[m_nextOrderedIndex];
			return rv;
		}
	}
}
<commit_msg>HashTable: remove superfluous comparison<commit_after>/*
 *   CrissCross
 *   A multi-purpose cross-platform library.
 *
 *   A product of Uplink Laboratories.
 *
 *   (c) 2006-2009 Steven Noonan.
 *   Licensed under the New BSD License.
 *
 */

#ifndef __included_cc_hashtable_h
#error "This file shouldn't be compiled directly."
#endif

#include <crisscross/compare.h>
#include <crisscross/hash.h>
#include <crisscross/internal_mem.h>

namespace CrissCross
{
	namespace Data
	{
		template <class Data>
		HashTable<Data>::HashTable(size_t _initialSize)
		: m_keys(NULL), m_size(32)
		{
			m_mask = m_size - 1;
			m_slotsFree = m_size;
			m_keys = new char *[m_size];
			m_data = new Data[m_size];

			memset(m_keys, 0, sizeof(char *) * m_size);
			memset(m_data, 0, sizeof(Data) * m_size);
		}

		template <class Data>
		HashTable<Data>::~HashTable()
		{
			empty();

			delete [] m_keys;
			delete [] m_data;
		}

		template <class Data>
		void HashTable<Data>::grow()
		{
			unsigned int oldSize = m_size;
			m_size *= 2;
			m_mask = m_size - 1;
			char **oldKeys = m_keys;
			m_keys = new char *[m_size];
			Data *oldData = m_data;
			m_data = new Data[m_size];

			memset(m_keys, 0, sizeof(char *) * m_size);
			memset(m_data, 0, sizeof(Data) * m_size);

			for (unsigned int i = 0; i < oldSize; ++i) {
				if (oldKeys[i] != NULL) {
					unsigned int newIndex = findInsertIndex(oldKeys[i]);
					m_keys[newIndex] = oldKeys[i];
					m_data[newIndex] = oldData[i];
				}
			}

			m_slotsFree += m_size - oldSize;

			delete [] oldKeys;
			delete [] oldData;
		}

		template <class Data>
		int HashTable<Data>::findInsertIndex(const char *_key) const
		{
			unsigned int index = Hash<const char *>(_key) & m_mask;

			while (m_keys[index] != NULL &&
			       m_keys[index] != (char *)-1)
			{
				CoreAssert(Compare<const char *>((const char *)m_keys[index], _key) != 0);
				index++;
				index &= m_mask;
			}

			return index;
		}

		template <class Data>
		int HashTable<Data>::findIndex(const char *_key) const
		{
			int index = Hash<const char *>(_key) & m_mask;

			if (m_keys[index] == NULL) {
				return -1;
			}

			while (true)
			{
				if (m_keys[index] != NULL && m_keys[index] != (char*)-1) {
					if (Compare<const char *>((const char *)m_keys[index], _key) == 0)
						break;
				}

				index++;
				index &= m_mask;

				if (m_keys[index] == NULL) {
					return -1;
				}
			}

			return index;
		}

		template <class Data>
		Data HashTable<Data>::find(const char * _key, Data const &_default) const
		{
			int index = findIndex(_key);
			if (index != -1) {
				return m_data[index];
			}
			return _default;
		}

		template <class Data>
		bool HashTable<Data>::exists(const char * _key) const
		{
			return findIndex(_key) != -1;
		}

		template <class Data>
		bool HashTable<Data>::erase(const char *_key)
		{
			int index = findIndex(_key);
			if (index != -1) {
				Dealloc(m_keys[index]);
				m_keys[index] = (char*)-1;
				m_slotsFree++;
				return true;
			}
			return false;
		}

		template <class Data>
		void HashTable<Data>::empty()
		{
			for (size_t i = 0; i < m_size; ++i) {
				if (m_keys[i] == (char*)-1) m_keys[i] = NULL;
				Dealloc(m_keys[i]);
			}

			memset(m_keys, 0, sizeof(char *) * m_size);
			memset(m_data, 0, sizeof(Data) * m_size);
		}

		template <class Data>
		int HashTable<Data>::insert(const char *_key, Data const &_data)
		{
			if (m_slotsFree * 2 <= m_size) {
				grow();
			}

			unsigned int index = findInsertIndex(_key);
			CoreAssert(m_keys[index] == NULL || m_keys[index] == (char*)-1);
			m_keys[index] = cc_strdup(_key);
			m_data[index] = _data;
			m_slotsFree--;

			return index;
		}

		template <class T>
		void SortingHashTable<T>::grow()
		{
			unsigned int oldSize = this->m_size;
			this->m_size *= 2;
			this->m_mask = (this->m_mask << 1) + 1;

			/* Copy pointers to existing data */
			char      * *oldKeys = this->m_keys;
			T           *oldData = this->m_data;
			short       *oldOrderedIndices = m_orderedIndices;

			/* Make new data */
			this->m_keys = new char *[this->m_size];
			this->m_data = new T [this->m_size];
			m_orderedIndices = new short [this->m_size];

			/* Set all new data to zero */
			memset(this->m_keys, 0, sizeof(char *) * this->m_size);
			memset(this->m_data, 0, sizeof(T) * this->m_size);
			for (size_t i = 0; i < this->m_size; i++)
				m_orderedIndices[i] = (short)-1;

			/* */
			/* Go through the existing ordered index list, inserting elements into the */
			/* new table as we go */

			short oldI = m_firstOrderedIndex;
			short newI = this->findInsertIndex(oldKeys[oldI]);
			m_firstOrderedIndex = newI;
			while (oldI != -1)
			{
				short nextOldI = oldOrderedIndices[oldI];

				this->m_keys[newI] = oldKeys[oldI];
				this->m_data[newI] = oldData[oldI];

				short nextNewI = (nextOldI != -1) ? this->findInsertIndex(oldKeys[nextOldI]) : -1;

				m_orderedIndices[newI] = nextNewI;

				oldI = nextOldI;
				newI = nextNewI;
			}

			this->m_slotsFree += this->m_size - oldSize;

			delete [] oldKeys;
			delete [] oldData;
			delete [] oldOrderedIndices;
		}

		/* See header for description */
		template <class T>
		short SortingHashTable<T>::findPrevKey(char const *_key) const
		{
			short prevI = -1;
			short i = m_firstOrderedIndex;

			while (1)
			{
				if (i == -1) return prevI;

				if (Compare((const char *)this->m_keys[i], _key) >= 0)
					return prevI;

				prevI = i;
				i = m_orderedIndices[i];
			}
		}

		template <class T>
		SortingHashTable<T>::SortingHashTable() :
			HashTable<T>(),
			m_firstOrderedIndex(-1)
		{
			m_orderedIndices = new short [this->m_size];
			memset(m_orderedIndices, 0, sizeof(short) * this->m_size);
		}

		template <class T>
		SortingHashTable<T>::~SortingHashTable()
		{
			delete [] m_orderedIndices;
		}

		template <class T>
		int SortingHashTable<T>::insert(char const *_key, T const &_data)
		{
			/* */
			/* Make sure the table is big enough */

			if (this->m_slotsFree * 2 <= this->m_size) {
				grow();
			}

			/* */
			/* Do the main insert */

			unsigned int index = HashTable<T>::findInsertIndex(_key);
			CoreAssert(this->m_keys[index] == NULL || this->m_keys[index] == (char*)-1);
			this->m_keys[index] = cc_strdup(_key);
			this->m_data[index] = _data;
			this->m_slotsFree--;

			/* */
			/* Insert us into the alphabetically order index list */

			short        i = findPrevKey(_key);
			if (i == -1) {
				/* Handle the case when the table is empty, or the new element is going */
				/* to be the new first alphabetical element */
				m_orderedIndices[index] = m_firstOrderedIndex;
				m_firstOrderedIndex = index;
			} else	{
				m_orderedIndices[index] = m_orderedIndices[i];
				m_orderedIndices[i] = index;
			}

			return index;
		}

		template <class T>
		bool SortingHashTable<T>::erase(char const *_key)
		{
			int index = this->GetIndex(_key);
			if (index >= 0)	{
				return erase(index);
			}
			return false;
		}

		template <class T>
		bool SortingHashTable<T>::erase(size_t _index)
		{
			bool retval = false;
			/* */
			/* Remove data */

			if (this->m_keys[_index] != (char *)-1) {
				retval = true;
				delete [] this->m_keys[_index];
			}
			this->m_keys[_index] = (char *)-1;
			this->m_slotsFree++;

			/* */
			/* Remove from ordered list */

			short prevIndex = -1;
			short index = m_firstOrderedIndex;
			while (m_orderedIndices[index] != _index)
			{
				CoreAssert(index != -1);
				prevIndex = index;
				index = m_orderedIndices[index];
			}

			if (prevIndex == -1) {
				m_firstOrderedIndex = -1;
			} else	{
				m_orderedIndices[prevIndex] = m_orderedIndices[index];
			}
			return retval;
		}

		template <class T>
		short SortingHashTable<T>::beginOrderedWalk()
		{
			m_nextOrderedIndex = m_orderedIndices[m_firstOrderedIndex];
			return m_firstOrderedIndex;
		}

		template <class T>
		short SortingHashTable<T>::nextOrderedIndex()
		{
			short rv = m_nextOrderedIndex;
			if (rv != -1)
				m_nextOrderedIndex = m_orderedIndices[m_nextOrderedIndex];
			return rv;
		}
	}
}
<|endoftext|>


<commit_before>#include <pcl/point_cloud.h>
#include <pcl/kdtree/kdtree_flann.h>

#include <iostream>
#include <vector>
#include <ctime>

using namespace pcl;

int
main (int argc, char** argv)
{

  srand (time (NULL));

  PointCloud<PointXYZ>::Ptr cloud (new PointCloud<PointXYZ>);

  // Generate pointcloud data
  cloud->width = 1000;
  cloud->height = 1;
  cloud->points.resize (cloud->width * cloud->height);

  for (size_t i = 0; i < cloud->points.size (); ++i)
  {
    cloud->points[i].x = 1024.0f * rand () / (RAND_MAX + 1.0);
    cloud->points[i].y = 1024.0f * rand () / (RAND_MAX + 1.0);
    cloud->points[i].z = 1024.0f * rand () / (RAND_MAX + 1.0);
  }

  float resolution = 128.0f;

  KdTreeFLANN<PointXYZ> kdtree;

  kdtree.setInputCloud (cloud);

  PointXYZ searchPoint;

  searchPoint.x = 1024.0f * rand () / (RAND_MAX + 1.0);
  searchPoint.y = 1024.0f * rand () / (RAND_MAX + 1.0);
  searchPoint.z = 1024.0f * rand () / (RAND_MAX + 1.0);

  // K nearest neighbor search

  int K = 10;

  std::vector<int> pointIdxNKNSearch(K);
  std::vector<float> pointNKNSquaredDistance(K);

  std::cerr << "K nearest neighbor search at (" << searchPoint.x
      << " " << searchPoint.y
      << " " << searchPoint.z
      << ") with K=" << K << std::endl;

  if ( kdtree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0 )
  {
    for (size_t i = 0; i < pointIdxNKNSearch.size (); ++i)
   std::cerr << "    "  <<   cloud->points[ pointIdxNKNSearch[i] ].x
       << " " << cloud->points[ pointIdxNKNSearch[i] ].y
       << " " << cloud->points[ pointIdxNKNSearch[i] ].z
       << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;
  }

  // Neighbors within radius search

  std::vector<int> pointIdxRadiusSearch;
  std::vector<float> pointRadiusSquaredDistance;

  float radius = 256.0f * rand () / (RAND_MAX + 1.0);

  std::cerr << "Neighbors within radius search at (" << searchPoint.x
      << " " << searchPoint.y
      << " " << searchPoint.z
      << ") with radius=" << radius << std::endl;

  if ( kdtree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0 )
  {
    for (size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)
   std::cerr << "    "  <<   cloud->points[ pointIdxRadiusSearch[i] ].x
       << " " << cloud->points[ pointIdxRadiusSearch[i] ].y
       << " " << cloud->points[ pointIdxRadiusSearch[i] ].z
       << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
  }

  return 0;
}
<commit_msg>Removed unused variable<commit_after>#include <pcl/point_cloud.h>
#include <pcl/kdtree/kdtree_flann.h>

#include <iostream>
#include <vector>
#include <ctime>

using namespace pcl;

int
main (int argc, char** argv)
{

  srand (time (NULL));

  PointCloud<PointXYZ>::Ptr cloud (new PointCloud<PointXYZ>);

  // Generate pointcloud data
  cloud->width = 1000;
  cloud->height = 1;
  cloud->points.resize (cloud->width * cloud->height);

  for (size_t i = 0; i < cloud->points.size (); ++i)
  {
    cloud->points[i].x = 1024.0f * rand () / (RAND_MAX + 1.0);
    cloud->points[i].y = 1024.0f * rand () / (RAND_MAX + 1.0);
    cloud->points[i].z = 1024.0f * rand () / (RAND_MAX + 1.0);
  }

  KdTreeFLANN<PointXYZ> kdtree;

  kdtree.setInputCloud (cloud);

  PointXYZ searchPoint;

  searchPoint.x = 1024.0f * rand () / (RAND_MAX + 1.0);
  searchPoint.y = 1024.0f * rand () / (RAND_MAX + 1.0);
  searchPoint.z = 1024.0f * rand () / (RAND_MAX + 1.0);

  // K nearest neighbor search

  int K = 10;

  std::vector<int> pointIdxNKNSearch(K);
  std::vector<float> pointNKNSquaredDistance(K);

  std::cerr << "K nearest neighbor search at (" << searchPoint.x
      << " " << searchPoint.y
      << " " << searchPoint.z
      << ") with K=" << K << std::endl;

  if ( kdtree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0 )
  {
    for (size_t i = 0; i < pointIdxNKNSearch.size (); ++i)
   std::cerr << "    "  <<   cloud->points[ pointIdxNKNSearch[i] ].x
       << " " << cloud->points[ pointIdxNKNSearch[i] ].y
       << " " << cloud->points[ pointIdxNKNSearch[i] ].z
       << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;
  }

  // Neighbors within radius search

  std::vector<int> pointIdxRadiusSearch;
  std::vector<float> pointRadiusSquaredDistance;

  float radius = 256.0f * rand () / (RAND_MAX + 1.0);

  std::cerr << "Neighbors within radius search at (" << searchPoint.x
      << " " << searchPoint.y
      << " " << searchPoint.z
      << ") with radius=" << radius << std::endl;

  if ( kdtree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0 )
  {
    for (size_t i = 0; i < pointIdxRadiusSearch.size (); ++i)
   std::cerr << "    "  <<   cloud->points[ pointIdxRadiusSearch[i] ].x
       << " " << cloud->points[ pointIdxRadiusSearch[i] ].y
       << " " << cloud->points[ pointIdxRadiusSearch[i] ].z
       << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
  }

  return 0;
}
<|endoftext|>


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

#ifndef __STOUT_UUID_HPP__
#define __STOUT_UUID_HPP__

#include <assert.h>

#include <sstream>
#include <string>

#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <stout/error.hpp>
#include <stout/thread_local.hpp>
#include <stout/try.hpp>

#ifdef __WINDOWS__
#include <stout/windows.hpp>
#endif // __WINDOWS__

// NOTE: This namespace is necessary because the standard Windows headers
// define a UUID struct in the global namespace for the DCE RPC API. We put
// this in the `id::` namespace to avoid collisions. Note also that we include
// a line below, `using id::UUID`, which allows us to avoid being forced to
// change most of the callsites that use `UUID` to use `id::UUID` instead.
namespace id {

struct UUID : boost::uuids::uuid
{
public:
  static UUID random()
  {
    static THREAD_LOCAL boost::uuids::random_generator* generator = nullptr;

    if (generator == nullptr) {
      generator = new boost::uuids::random_generator();
    }

    return UUID((*generator)());
  }

  static Try<UUID> fromBytes(const std::string& s)
  {
    const std::string error = "Not a valid UUID";

    if (s.size() != UUID::static_size()) {
      return Error(error);
    }

    boost::uuids::uuid uuid;
    memcpy(&uuid, s.data(), s.size());

    if (uuid.version() == UUID::version_unknown) {
      return Error(error);
    }

    return UUID(uuid);
  }

  static UUID fromString(const std::string& s)
  {
    boost::uuids::uuid uuid;
    std::istringstream in(s);
    in >> uuid;
    return UUID(uuid);
  }

  std::string toBytes() const
  {
    assert(sizeof(data) == size());
    return std::string(reinterpret_cast<const char*>(data), sizeof(data));
  }

  std::string toString() const
  {
    std::ostringstream out;
    out << *this;
    return out.str();
  }

private:
  explicit UUID(const boost::uuids::uuid& uuid)
    : boost::uuids::uuid(uuid) {}
};

} // namespace id {

// NOTE: see comment for the line `namespace id {`, near the top of the file.
using id::UUID;

namespace std {

template <>
struct hash<UUID>
{
  typedef size_t result_type;

  typedef UUID argument_type;

  result_type operator()(const argument_type& uuid) const
  {
    return boost::uuids::hash_value(uuid);
  }
};

} // namespace std {

#endif // __STOUT_UUID_HPP__
<commit_msg>Optimized `UUID::fromString()` and `UUID::toString()` in stout.<commit_after>// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//  http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#ifndef __STOUT_UUID_HPP__
#define __STOUT_UUID_HPP__

#include <assert.h>

#include <string>

#include <boost/uuid/random_generator.hpp>
#include <boost/uuid/string_generator.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_io.hpp>

#include <stout/error.hpp>
#include <stout/thread_local.hpp>
#include <stout/try.hpp>

#ifdef __WINDOWS__
#include <stout/windows.hpp>
#endif // __WINDOWS__

// NOTE: This namespace is necessary because the standard Windows headers
// define a UUID struct in the global namespace for the DCE RPC API. We put
// this in the `id::` namespace to avoid collisions. Note also that we include
// a line below, `using id::UUID`, which allows us to avoid being forced to
// change most of the callsites that use `UUID` to use `id::UUID` instead.
namespace id {

struct UUID : boost::uuids::uuid
{
public:
  static UUID random()
  {
    static THREAD_LOCAL boost::uuids::random_generator* generator = nullptr;

    if (generator == nullptr) {
      generator = new boost::uuids::random_generator();
    }

    return UUID((*generator)());
  }

  static Try<UUID> fromBytes(const std::string& s)
  {
    const std::string error = "Not a valid UUID";

    if (s.size() != UUID::static_size()) {
      return Error(error);
    }

    boost::uuids::uuid uuid;
    memcpy(&uuid, s.data(), s.size());

    if (uuid.version() == UUID::version_unknown) {
      return Error(error);
    }

    return UUID(uuid);
  }

  static UUID fromString(const std::string& s)
  {
    // NOTE: We don't use THREAD_LOCAL for the `string_generator`
    // (unlike for the `random_generator` above), because it is cheap
    // to construct one each time.
    boost::uuids::string_generator gen;
    boost::uuids::uuid uuid = gen(s);
    return UUID(uuid);
  }

  std::string toBytes() const
  {
    assert(sizeof(data) == size());
    return std::string(reinterpret_cast<const char*>(data), sizeof(data));
  }

  std::string toString() const
  {
    return to_string(*this);
  }

private:
  explicit UUID(const boost::uuids::uuid& uuid)
    : boost::uuids::uuid(uuid) {}
};

} // namespace id {

// NOTE: see comment for the line `namespace id {`, near the top of the file.
using id::UUID;

namespace std {

template <>
struct hash<UUID>
{
  typedef size_t result_type;

  typedef UUID argument_type;

  result_type operator()(const argument_type& uuid) const
  {
    return boost::uuids::hash_value(uuid);
  }
};

} // namespace std {

#endif // __STOUT_UUID_HPP__
<|endoftext|>


<commit_before>/**
 * \file
 * \brief __cxa_pure_virtual() system call implementation
 *
 * \author Copyright (C) 2014 Kamil Szczygiel https://distortec.com https://freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include <cstdlib>

extern "C"
{

/*---------------------------------------------------------------------------------------------------------------------+
| global functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Replacement of original __cxa_pure_virtual().
 *
 * This function is called on pure virtual function call. It does not return.
 *
 * It just calls abort().
 */

__attribute__ ((noreturn))
void __cxa_pure_virtual()
{
	abort();
}

}	// extern "C"
<commit_msg>Use FATAL_ERROR() instead of abort() in __cxa_pure_virtual()<commit_after>/**
 * \file
 * \brief __cxa_pure_virtual() system call implementation
 *
 * \author Copyright (C) 2014-2022 Kamil Szczygiel https://distortec.com https://freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
 */

#include "distortos/FATAL_ERROR.h"

#include <cstdlib>

extern "C"
{

/*---------------------------------------------------------------------------------------------------------------------+
| global functions
+---------------------------------------------------------------------------------------------------------------------*/

/**
 * \brief Replacement of original __cxa_pure_virtual().
 *
 * This function is called on pure virtual function call. It does not return.
 *
 * It just calls FATAL_ERROR().
 */

__attribute__ ((noreturn))
void __cxa_pure_virtual()
{
	FATAL_ERROR("Pure virtual function called!");
}

}	// extern "C"
<|endoftext|>


<commit_before>// -------------------------------------------------------------------
//
// perf_count.cc:  performance counters LevelDB (http://code.google.com/p/leveldb/)
//
// Copyright (c) 2012 Basho Technologies, Inc. All Rights Reserved.
//
// This file is provided to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file
// except in compliance with the License.  You may obtain
// a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
// -------------------------------------------------------------------

#include <limits.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <errno.h>

#ifndef STORAGE_LEVELDB_INCLUDE_PERF_COUNT_H_
#include "leveldb/perf_count.h"
#endif

#include "util/coding.h"
//#include "util/crc32c.h"

namespace leveldb
{

// always have something active in gPerfCounters, eliminates
//  need to test for "is shared object attached yet"
static PerformanceCounters LocalStartupCounters;
PerformanceCounters * gPerfCounters(&LocalStartupCounters);

    SstCounters::SstCounters()
        : m_IsReadOnly(false),
          m_Version(eSstCountVersion),
          m_CounterSize(eSstCountEnumSize)
    {
        memset(m_Counter, 0, sizeof(m_Counter));

        m_Counter[eSstCountKeySmallest]=ULLONG_MAX;
        m_Counter[eSstCountValueSmallest]=ULLONG_MAX;

        return;

    };  // SstCounters::SstCounters

    void
    SstCounters::EncodeTo(
        std::string & Dst) const
    {
        unsigned loop;

        PutVarint32(&Dst, m_Version);
        PutVarint32(&Dst, m_CounterSize);

        for(loop=0; loop<eSstCountEnumSize; ++loop)
            PutVarint64(&Dst, m_Counter[loop]);
    }   // SstCounters::EncodeTo

    Status
    SstCounters::DecodeFrom(
        const Slice& src)
    {
        Status ret_status;
        Slice cursor;
        bool good;
        int loop;

        cursor=src;
        m_IsReadOnly=true;
        good=GetVarint32(&cursor, &m_Version);
        good=good && (m_Version<=eSstCountVersion);

        // all lesser number of stats to be read
        good=good && GetVarint32(&cursor, &m_CounterSize);
        if (good && eSstCountEnumSize < m_CounterSize)
            m_CounterSize=eSstCountEnumSize;

        for (loop=0; good && loop<eSstCountEnumSize; ++loop)
        {
            good=GetVarint64(&cursor, &m_Counter[loop]);
        }   // for

        // if (!good) change ret_status to bad

        return(ret_status);

    }   // SstCounters::DecodeFrom

    uint64_t
    SstCounters::Inc(
        unsigned Index)
    {
        uint64_t ret_val;

        ret_val=0;
        if (!m_IsReadOnly && Index<m_CounterSize)
        {
            ++m_Counter[Index];
            ret_val=m_Counter[Index];
        }   // if

        return(ret_val);
    }   // SstCounters::Inc

    uint64_t
    SstCounters::Add(
        unsigned Index,
        uint64_t Amount)
    {
        uint64_t ret_val;

        ret_val=0;
        if (!m_IsReadOnly && Index<m_CounterSize)
        {
            m_Counter[Index]+=Amount;
            ret_val=m_Counter[Index];
        }   // if

        return(ret_val);
    }   // SstCounters::Add

    uint64_t
    SstCounters::Value(
        unsigned Index) const
    {
        uint64_t ret_val;

        ret_val=0;
        if (Index<m_CounterSize)
        {
            ret_val=m_Counter[Index];
        }   // if

        return(ret_val);
    }   // SstCounters::Value

    void
    SstCounters::Set(
        unsigned Index,
        uint64_t Value)
    {
        if (Index<m_CounterSize)
        {
            m_Counter[Index]=Value;
        }   // if

        return;
    }   // SstCounters::Set

    void
    SstCounters::Dump() const
    {
        unsigned loop;

        printf("SstCounters:\n");
        printf("   m_IsReadOnly: %u\n", m_IsReadOnly);
        printf("      m_Version: %u\n", m_Version);
        printf("  m_CounterSize: %u\n", m_CounterSize);
        for (loop=0; loop<m_CounterSize; ++loop)
            printf("    Counter[%2u]: %llu\n", loop, m_Counter[loop]);

        return;

    }   // SstCounters::Dump

    // only used for local static objects, not shared memory objects
    PerformanceCounters::PerformanceCounters()
    {
        m_Version=ePerfVersion;
        m_CounterSize=ePerfCountEnumSize;
        // cast away "volatile"
        memset((void*)m_Counter, 0, sizeof(m_Counter));

        return;

    }   // PerformanceCounters::PerformanceCounters

    PerformanceCounters *
    PerformanceCounters::Init(
        bool IsReadOnly)
    {
        int ret_val;
        PerformanceCounters * ret_ptr;

        ret_ptr=NULL;

        // attempt to attach/create to shared memory instance
        m_PerfSharedId=shmget(ePerfKey, sizeof(PerformanceCounters), IPC_CREAT);
        if (-1!=m_PerfSharedId)
        {
            ret_ptr=(PerformanceCounters *)shmat(m_PerfSharedId, NULL, (IsReadOnly ? SHM_RDONLY : 0));
            if ((void*)-1 != ret_ptr)
            {
                // initialize?
                if (0==ret_ptr->m_Version || ePerfCountEnumSize!=ret_ptr->m_CounterSize)
                {
                    if (!IsReadOnly)
                    {
                        memset(ret_ptr, 0, sizeof(PerformanceCounters));
                        ret_ptr->m_Version=ePerfVersion;
                        ret_ptr->m_CounterSize=ePerfCountEnumSize;
                    }   // if

                    // bad version match to existing segment
                    else
                    {
                        ret_ptr=(PerformanceCounters *)-1;
                        errno=EINVAL;
                    }   // else
                }   // if
            }   // if

            if ((void*)-1 != ret_ptr)
            {
                // make this available process wide
                gPerfCounters=ret_ptr;
            }   // if
            else
            {
                ret_ptr=NULL;
                m_LastError=errno;
            }   // else
        }   // if
        else
        {
            m_LastError=errno;
            ret_ptr=NULL;
        }   // else

        return(ret_ptr);

    };  // PerformanceCounters::Init

    uint64_t
    PerformanceCounters::Inc(
        unsigned Index)
    {
        uint64_t ret_val;

        ret_val=0;
        if (Index<m_CounterSize)
        {
            volatile uint64_t * val_ptr;

            val_ptr=&m_Counter[Index];

#ifdef OS_SOLARIS
            atomic_add_int(val_ptr, 1);
#else
            __sync_add_and_fetch(val_ptr, 1);
#endif
            ret_val=*val_ptr;
        }   // if

        return(ret_val);
    }   // PerformanceCounters::Inc

    int PerformanceCounters::m_PerfSharedId=-1;
    int PerformanceCounters::m_LastError=0;
    const char * PerformanceCounters::m_PerfCounterNames[]=
    {
        "ROFileOpen",
        "ROFileClose",
        "ROFileUnmap",
        "RWFileOpen",
        "RWFileClose",
        "RWFileUnmap",
        "ApiOpen",
        "ApiGet",
        "ApiWrite",
        "WriteSleep",
        "WriteWaitImm",
        "WriteWaitLevel0",
        "WriteNewMem",
        "WriteError",
        "WriteNoWait",
        "GetMem",
        "GetImm",
        "GetVersion",
        "SearchLevel[0]",
        "SearchLevel[1]",
        "SearchLevel[2]",
        "SearchLevel[3]",
        "SearchLevel[4]",
        "SearchLevel[5]",
        "SearchLevel[6]",
        "TableCached",
        "TableOpened",
        "TableGet",
        "BGCloseUnmap",
        "BGCompactImm",
        "BGNormal",
        "BGCompactLevel0",
        "BlockFiltered",
        "BlockFilterFalse",
        "BlockCached",
        "BlockRead",
        "BlockFilterRead",
        "BlockValidGet",
        "Debug[0]",
        "Debug[1]",
        "Debug[2]",
        "Debug[3]",
        "Debug[4]"
    };

    void
    PerformanceCounters::Dump()
    {
        int loop;

        printf(" m_Version: %u\n", m_Version);
        printf(" m_CounterSize: %u\n", m_CounterSize);

        for (loop=0; loop<ePerfCountEnumSize; ++loop)
        {
            printf("  %s: %llu\n", m_PerfCounterNames[loop], m_Counter[loop]);
        }   // loop
    };  // Dump

}  // namespace leveldb
<commit_msg>Forgot to assign owner permissions to shared memory.<commit_after>// -------------------------------------------------------------------
//
// perf_count.cc:  performance counters LevelDB (http://code.google.com/p/leveldb/)
//
// Copyright (c) 2012 Basho Technologies, Inc. All Rights Reserved.
//
// This file is provided to you under the Apache License,
// Version 2.0 (the "License"); you may not use this file
// except in compliance with the License.  You may obtain
// a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied.  See the License for the
// specific language governing permissions and limitations
// under the License.
//
// -------------------------------------------------------------------

#include <limits.h>
#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>

#ifndef STORAGE_LEVELDB_INCLUDE_PERF_COUNT_H_
#include "leveldb/perf_count.h"
#endif

#include "util/coding.h"
//#include "util/crc32c.h"

namespace leveldb
{

// always have something active in gPerfCounters, eliminates
//  need to test for "is shared object attached yet"
static PerformanceCounters LocalStartupCounters;
PerformanceCounters * gPerfCounters(&LocalStartupCounters);

    SstCounters::SstCounters()
        : m_IsReadOnly(false),
          m_Version(eSstCountVersion),
          m_CounterSize(eSstCountEnumSize)
    {
        memset(m_Counter, 0, sizeof(m_Counter));

        m_Counter[eSstCountKeySmallest]=ULLONG_MAX;
        m_Counter[eSstCountValueSmallest]=ULLONG_MAX;

        return;

    };  // SstCounters::SstCounters

    void
    SstCounters::EncodeTo(
        std::string & Dst) const
    {
        unsigned loop;

        PutVarint32(&Dst, m_Version);
        PutVarint32(&Dst, m_CounterSize);

        for(loop=0; loop<eSstCountEnumSize; ++loop)
            PutVarint64(&Dst, m_Counter[loop]);
    }   // SstCounters::EncodeTo

    Status
    SstCounters::DecodeFrom(
        const Slice& src)
    {
        Status ret_status;
        Slice cursor;
        bool good;
        int loop;

        cursor=src;
        m_IsReadOnly=true;
        good=GetVarint32(&cursor, &m_Version);
        good=good && (m_Version<=eSstCountVersion);

        // all lesser number of stats to be read
        good=good && GetVarint32(&cursor, &m_CounterSize);
        if (good && eSstCountEnumSize < m_CounterSize)
            m_CounterSize=eSstCountEnumSize;

        for (loop=0; good && loop<eSstCountEnumSize; ++loop)
        {
            good=GetVarint64(&cursor, &m_Counter[loop]);
        }   // for

        // if (!good) change ret_status to bad

        return(ret_status);

    }   // SstCounters::DecodeFrom

    uint64_t
    SstCounters::Inc(
        unsigned Index)
    {
        uint64_t ret_val;

        ret_val=0;
        if (!m_IsReadOnly && Index<m_CounterSize)
        {
            ++m_Counter[Index];
            ret_val=m_Counter[Index];
        }   // if

        return(ret_val);
    }   // SstCounters::Inc

    uint64_t
    SstCounters::Add(
        unsigned Index,
        uint64_t Amount)
    {
        uint64_t ret_val;

        ret_val=0;
        if (!m_IsReadOnly && Index<m_CounterSize)
        {
            m_Counter[Index]+=Amount;
            ret_val=m_Counter[Index];
        }   // if

        return(ret_val);
    }   // SstCounters::Add

    uint64_t
    SstCounters::Value(
        unsigned Index) const
    {
        uint64_t ret_val;

        ret_val=0;
        if (Index<m_CounterSize)
        {
            ret_val=m_Counter[Index];
        }   // if

        return(ret_val);
    }   // SstCounters::Value

    void
    SstCounters::Set(
        unsigned Index,
        uint64_t Value)
    {
        if (Index<m_CounterSize)
        {
            m_Counter[Index]=Value;
        }   // if

        return;
    }   // SstCounters::Set

    void
    SstCounters::Dump() const
    {
        unsigned loop;

        printf("SstCounters:\n");
        printf("   m_IsReadOnly: %u\n", m_IsReadOnly);
        printf("      m_Version: %u\n", m_Version);
        printf("  m_CounterSize: %u\n", m_CounterSize);
        for (loop=0; loop<m_CounterSize; ++loop)
            printf("    Counter[%2u]: %llu\n", loop, m_Counter[loop]);

        return;

    }   // SstCounters::Dump

    // only used for local static objects, not shared memory objects
    PerformanceCounters::PerformanceCounters()
    {
        m_Version=ePerfVersion;
        m_CounterSize=ePerfCountEnumSize;
        // cast away "volatile"
        memset((void*)m_Counter, 0, sizeof(m_Counter));

        return;

    }   // PerformanceCounters::PerformanceCounters

    PerformanceCounters *
    PerformanceCounters::Init(
        bool IsReadOnly)
    {
        int ret_val;
        PerformanceCounters * ret_ptr;

        ret_ptr=NULL;

        // attempt to attach/create to shared memory instance
        m_PerfSharedId=shmget(ePerfKey, sizeof(PerformanceCounters), IPC_CREAT | S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        if (-1!=m_PerfSharedId)
        {
            ret_ptr=(PerformanceCounters *)shmat(m_PerfSharedId, NULL, (IsReadOnly ? SHM_RDONLY : 0));
            if ((void*)-1 != ret_ptr)
            {
                // initialize?
                if (0==ret_ptr->m_Version || ePerfCountEnumSize!=ret_ptr->m_CounterSize)
                {
                    if (!IsReadOnly)
                    {
                        memset(ret_ptr, 0, sizeof(PerformanceCounters));
                        ret_ptr->m_Version=ePerfVersion;
                        ret_ptr->m_CounterSize=ePerfCountEnumSize;
                    }   // if

                    // bad version match to existing segment
                    else
                    {
                        ret_ptr=(PerformanceCounters *)-1;
                        errno=EINVAL;
                    }   // else
                }   // if
            }   // if

            if ((void*)-1 != ret_ptr)
            {
                // make this available process wide
                gPerfCounters=ret_ptr;
            }   // if
            else
            {
                ret_ptr=NULL;
                m_LastError=errno;
            }   // else
        }   // if
        else
        {
            m_LastError=errno;
            ret_ptr=NULL;
        }   // else

        return(ret_ptr);

    };  // PerformanceCounters::Init

    uint64_t
    PerformanceCounters::Inc(
        unsigned Index)
    {
        uint64_t ret_val;

        ret_val=0;
        if (Index<m_CounterSize)
        {
            volatile uint64_t * val_ptr;

            val_ptr=&m_Counter[Index];

#ifdef OS_SOLARIS
            atomic_add_int(val_ptr, 1);
#else
            __sync_add_and_fetch(val_ptr, 1);
#endif
            ret_val=*val_ptr;
        }   // if

        return(ret_val);
    }   // PerformanceCounters::Inc

    int PerformanceCounters::m_PerfSharedId=-1;
    int PerformanceCounters::m_LastError=0;
    const char * PerformanceCounters::m_PerfCounterNames[]=
    {
        "ROFileOpen",
        "ROFileClose",
        "ROFileUnmap",
        "RWFileOpen",
        "RWFileClose",
        "RWFileUnmap",
        "ApiOpen",
        "ApiGet",
        "ApiWrite",
        "WriteSleep",
        "WriteWaitImm",
        "WriteWaitLevel0",
        "WriteNewMem",
        "WriteError",
        "WriteNoWait",
        "GetMem",
        "GetImm",
        "GetVersion",
        "SearchLevel[0]",
        "SearchLevel[1]",
        "SearchLevel[2]",
        "SearchLevel[3]",
        "SearchLevel[4]",
        "SearchLevel[5]",
        "SearchLevel[6]",
        "TableCached",
        "TableOpened",
        "TableGet",
        "BGCloseUnmap",
        "BGCompactImm",
        "BGNormal",
        "BGCompactLevel0",
        "BlockFiltered",
        "BlockFilterFalse",
        "BlockCached",
        "BlockRead",
        "BlockFilterRead",
        "BlockValidGet",
        "Debug[0]",
        "Debug[1]",
        "Debug[2]",
        "Debug[3]",
        "Debug[4]"
    };

    void
    PerformanceCounters::Dump()
    {
        int loop;

        printf(" m_Version: %u\n", m_Version);
        printf(" m_CounterSize: %u\n", m_CounterSize);

        for (loop=0; loop<ePerfCountEnumSize; ++loop)
        {
            printf("  %s: %llu\n", m_PerfCounterNames[loop], m_Counter[loop]);
        }   // loop
    };  // Dump

}  // namespace leveldb
<|endoftext|>


<commit_before>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "relay/session_manager.h"

#include "base/logging.h"
#include "base/task_runner.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_pump_asio.h"
#include "base/crypto/message_decryptor_openssl.h"
#include "base/peer/host_id.h"
#include "base/strings/unicode.h"

namespace relay {

namespace {

// Decrypts an encrypted pair of peer identifiers using key |session_key|.
base::ByteArray decryptSecret(const proto::PeerToRelay& message, const SessionKey& session_key)
{
    std::unique_ptr<base::MessageDecryptor> decryptor =
        base::MessageDecryptorOpenssl::createForChaCha20Poly1305(
            session_key.sessionKey(message.public_key()), session_key.iv());
    if (!decryptor)
        return base::ByteArray();

    const std::string& source = message.data();
    if (source.empty())
        return base::ByteArray();

    base::ByteArray target;
    target.resize(decryptor->decryptedDataSize(source.size()));

    if (!decryptor->decrypt(source.data(), source.size(), target.data()))
        return base::ByteArray();

    return target;
}

// Removes a session from the list and returns a pointer to it.
template<class T>
std::unique_ptr<T> removeSessionT(std::vector<std::unique_ptr<T>>* session_list, T* session)
{
    session->stop();

    auto it = session_list->begin();
    while (it != session_list->end())
    {
        if (it->get() == session)
            break;

        ++it;
    }

    if (it != session_list->end())
    {
        std::unique_ptr<T> result = std::move(*it);
        session_list->erase(it);
        return result;
    }

    return nullptr;
}

} // namespace

SessionManager::SessionManager(std::shared_ptr<base::TaskRunner> task_runner, uint16_t port)
    : task_runner_(std::move(task_runner)),
      acceptor_(base::MessageLoop::current()->pumpAsio()->ioContext(),
                asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port))
{
    DCHECK(task_runner_);
}

SessionManager::~SessionManager()
{
    std::error_code ignored_code;
    acceptor_.cancel(ignored_code);
    acceptor_.close(ignored_code);
}

void SessionManager::start(std::unique_ptr<SharedPool> shared_pool, Delegate* delegate)
{
    shared_pool_ = std::move(shared_pool);
    delegate_ = delegate;

    SessionManager::doAccept(this);
}

void SessionManager::onPendingSessionReady(
    PendingSession* session, const proto::PeerToRelay& message)
{
    // Looking for a key with the specified identifier.
    const SessionKey& session_key = shared_pool_->key(message.key_id());
    if (session_key.isValid())
    {
        // Decrypt the identifiers of peers.
        base::ByteArray secret = decryptSecret(message, session_key);
        if (!secret.empty())
        {
            // Save the identifiers of peers and the identifier of their shared key.
            session->setIdentify(message.key_id(), secret);

            // Trying to find a peer that wants to be connected.
            for (auto& other_session : pending_sessions_)
            {
                if (session->isPeerFor(*other_session))
                {
                    // Delete the key from the pool. It can no longer be used.
                    shared_pool_->removeKey(message.key_id());

                    // Now the opposite peer is found, start the data transfer between them.
                    active_sessions_.emplace_back(std::make_unique<Session>(
                        std::make_pair(session->takeSocket(), other_session->takeSocket())));
                    active_sessions_.back()->start(this);

                    // Pending sessions are no longer needed, remove them.
                    removePendingSession(other_session.get());
                    removePendingSession(session);
                    return;
                }
            }

            return;
        }
    }

    // The key was not found in the pool.
    removePendingSession(session);
}

void SessionManager::onPendingSessionFailed(PendingSession* session)
{
    removePendingSession(session);
}

void SessionManager::onSessionFinished(Session* session)
{
    removeSession(session);
}

// static
void SessionManager::doAccept(SessionManager* session_manager)
{
    session_manager->acceptor_.async_accept(
        [session_manager](const std::error_code& error_code, asio::ip::tcp::socket socket)
    {
        if (!error_code)
        {
            LOG(LS_INFO) << "New accepted connection: " << base::utf16FromLocal8Bit(
                socket.remote_endpoint().address().to_string());

            // A new peer is connected. Create and start the pending session.
            session_manager->pending_sessions_.emplace_back(std::make_unique<PendingSession>(
                session_manager->task_runner_, std::move(socket), session_manager));
            session_manager->pending_sessions_.back()->start();
        }
        else
        {
            LOG(LS_ERROR) << "Error while accepting connection: "
                          << base::utf16FromLocal8Bit(error_code.message());
        }

        // Waiting for the next connection.
        SessionManager::doAccept(session_manager);
    });
}

void SessionManager::removePendingSession(PendingSession* session)
{
    task_runner_->deleteSoon(removeSessionT(&pending_sessions_, session));
}

void SessionManager::removeSession(Session* session)
{
    task_runner_->deleteSoon(removeSessionT(&active_sessions_, session));

    if (delegate_)
        delegate_->onSessionFinished();
}

} // namespace relay
<commit_msg>Added debug messages.<commit_after>//
// Aspia Project
// Copyright (C) 2020 Dmitry Chapyshev <dmitry@aspia.ru>
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
//

#include "relay/session_manager.h"

#include "base/logging.h"
#include "base/task_runner.h"
#include "base/message_loop/message_loop.h"
#include "base/message_loop/message_pump_asio.h"
#include "base/crypto/message_decryptor_openssl.h"
#include "base/peer/host_id.h"
#include "base/strings/unicode.h"

namespace relay {

namespace {

// Decrypts an encrypted pair of peer identifiers using key |session_key|.
base::ByteArray decryptSecret(const proto::PeerToRelay& message, const SessionKey& session_key)
{
    std::unique_ptr<base::MessageDecryptor> decryptor =
        base::MessageDecryptorOpenssl::createForChaCha20Poly1305(
            session_key.sessionKey(message.public_key()), session_key.iv());
    if (!decryptor)
        return base::ByteArray();

    const std::string& source = message.data();
    if (source.empty())
        return base::ByteArray();

    base::ByteArray target;
    target.resize(decryptor->decryptedDataSize(source.size()));

    if (!decryptor->decrypt(source.data(), source.size(), target.data()))
        return base::ByteArray();

    return target;
}

// Removes a session from the list and returns a pointer to it.
template<class T>
std::unique_ptr<T> removeSessionT(std::vector<std::unique_ptr<T>>* session_list, T* session)
{
    session->stop();

    auto it = session_list->begin();
    while (it != session_list->end())
    {
        if (it->get() == session)
            break;

        ++it;
    }

    if (it != session_list->end())
    {
        std::unique_ptr<T> result = std::move(*it);
        session_list->erase(it);
        return result;
    }

    return nullptr;
}

} // namespace

SessionManager::SessionManager(std::shared_ptr<base::TaskRunner> task_runner, uint16_t port)
    : task_runner_(std::move(task_runner)),
      acceptor_(base::MessageLoop::current()->pumpAsio()->ioContext(),
                asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port))
{
    DCHECK(task_runner_);

    LOG(LS_INFO) << "Session manager port: " << port;
}

SessionManager::~SessionManager()
{
    std::error_code ignored_code;
    acceptor_.cancel(ignored_code);
    acceptor_.close(ignored_code);
}

void SessionManager::start(std::unique_ptr<SharedPool> shared_pool, Delegate* delegate)
{
    LOG(LS_INFO) << "Starting session manager";

    shared_pool_ = std::move(shared_pool);
    delegate_ = delegate;

    DCHECK(delegate_ && shared_pool_);

    SessionManager::doAccept(this);
}

void SessionManager::onPendingSessionReady(
    PendingSession* session, const proto::PeerToRelay& message)
{
    LOG(LS_INFO) << "Pending session ready";

    // Looking for a key with the specified identifier.
    const SessionKey& session_key = shared_pool_->key(message.key_id());
    if (session_key.isValid())
    {
        // Decrypt the identifiers of peers.
        base::ByteArray secret = decryptSecret(message, session_key);
        if (!secret.empty())
        {
            // Save the identifiers of peers and the identifier of their shared key.
            session->setIdentify(message.key_id(), secret);

            // Trying to find a peer that wants to be connected.
            for (auto& other_session : pending_sessions_)
            {
                if (session->isPeerFor(*other_session))
                {
                    // Delete the key from the pool. It can no longer be used.
                    shared_pool_->removeKey(message.key_id());

                    // Now the opposite peer is found, start the data transfer between them.
                    active_sessions_.emplace_back(std::make_unique<Session>(
                        std::make_pair(session->takeSocket(), other_session->takeSocket())));
                    active_sessions_.back()->start(this);

                    // Pending sessions are no longer needed, remove them.
                    removePendingSession(other_session.get());
                    removePendingSession(session);
                    return;
                }
            }

            return;
        }
    }

    // The key was not found in the pool.
    removePendingSession(session);
}

void SessionManager::onPendingSessionFailed(PendingSession* session)
{
    removePendingSession(session);
}

void SessionManager::onSessionFinished(Session* session)
{
    removeSession(session);
}

// static
void SessionManager::doAccept(SessionManager* session_manager)
{
    session_manager->acceptor_.async_accept(
        [session_manager](const std::error_code& error_code, asio::ip::tcp::socket socket)
    {
        if (!error_code)
        {
            LOG(LS_INFO) << "New accepted connection: " << base::utf16FromLocal8Bit(
                socket.remote_endpoint().address().to_string());

            // A new peer is connected. Create and start the pending session.
            session_manager->pending_sessions_.emplace_back(std::make_unique<PendingSession>(
                session_manager->task_runner_, std::move(socket), session_manager));
            session_manager->pending_sessions_.back()->start();
        }
        else
        {
            LOG(LS_ERROR) << "Error while accepting connection: "
                          << base::utf16FromLocal8Bit(error_code.message());
        }

        // Waiting for the next connection.
        SessionManager::doAccept(session_manager);
    });
}

void SessionManager::removePendingSession(PendingSession* session)
{
    task_runner_->deleteSoon(removeSessionT(&pending_sessions_, session));
}

void SessionManager::removeSession(Session* session)
{
    task_runner_->deleteSoon(removeSessionT(&active_sessions_, session));

    if (delegate_)
        delegate_->onSessionFinished();
}

} // namespace relay
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "spline_renderer.h"

#include <glm/gtx/spline.hpp>
#include <glm/gtx/compatibility.hpp> //for lerp

#include "asdf_multiplat/utilities/utilities.h"

namespace asdf {
namespace hexmap
{
    using namespace data;

namespace ui
{
    namespace
    {
        constexpr size_t default_subdivs_per_spline_segment = 10;
    }

    /// vertex spec allocation / definition
    gl_vertex_spec_<vertex_attrib::position3_t, vertex_attrib::color_t> spline_vertex_t::vertex_spec;

    /// Helper Func Declarations
    line_node_t interpolated_node(spline_t const& spline, size_t spline_node_ind, float t);
    std::vector<line_node_t> line_from_interpolated_spline(spline_t const& spline, size_t subdivisions_per_segment);
    line_node_t interpolate_linear(line_node_t const& start, line_node_t const& end, float t);
    line_node_t interpolate_bezier(line_node_t const& start, control_node_t const& cn_start, control_node_t const& cn_end, line_node_t const& end, float t);

    /// Member Func Definitions
    void spline_renderer_t::begin()
    {
        ASSERT(shader, "cannot render splines without a shader");

        spline_batch.clear();
    }

    void spline_renderer_t::batch(spline_t const& spline)
    {
        spline_batch.push_back(&spline);
    }

    void spline_renderer_t::batch(std::vector<spline_t> const& splines)
    {
        spline_batch.reserve(spline_batch.size() + splines.size());

        for(size_t i = 0; i < splines.size(); ++i)
        {
            spline_batch.push_back(&(splines[i]));
        }
    }

    void spline_renderer_t::end()
    {
        if(spline_batch.empty())
        {
            return;
        }

        ASSERT(shader, "cannot render splines without a shader");

        polygon_<spline_vertex_t> verts;

        std::vector<std::vector<line_node_t>> constructed_lines;
        constructed_lines.reserve(spline_batch.size());

        //reticulate splines
        for(auto const* spline : spline_batch)
        {
            ASSERT(spline, "null spline in batch");
            constructed_lines.push_back( line_from_interpolated_spline(*spline, default_subdivs_per_spline_segment) );
        }

        //pre-loop to get size info
        size_t num_verts = 0;
        for(auto const& polyline : constructed_lines)
        {
            //not doing thickness yet, so only one vertex per polyline node
            num_verts += polyline.size();
        }
        verts.resize(num_verts);

        size_t vert_ind = 0;
        for(auto const& polyline : constructed_lines)
        {
            for(auto const& line_vert : polyline)
            {
                verts[vert_ind].position = glm::vec3(line_vert.position, 0.0f);
                verts[vert_ind].color    = line_vert.color;

                ++vert_ind;
            }
        }

        ASSERT(vert_ind + 1 == num_verts, "Unexpected unset vertices in polyline");
        spline_polygon.set_data(verts, shader);
        spline_polygon.render(GL_LINE_LOOP); //will change this to GL_TRIANGLES later when I implement thickness
    }

    /// Helper Func Definitions
    line_node_t interpolated_node(spline_t const& spline, size_t spline_node_ind, float t)
    {
        ASSERT(spline.nodes.size() > spline_node_ind, "out of bounds");

        switch(spline.spline_type)
        {
            case spline_t::linear:
            {
                return interpolate_linear(spline.nodes[spline_node_ind], spline.nodes[spline_node_ind+1], t);
            }
            case spline_t::bezier:
            {
                auto cn_ind = spline_node_ind * 2;

                ASSERT(spline.control_nodes.size() > cn_ind, "out of bounds");

                auto const& p0 = spline.nodes[spline_node_ind];
                auto const& p1 = spline.control_nodes[cn_ind];
                auto const& p2 = spline.control_nodes[cn_ind + 1];
                auto const& p3 = spline.nodes[spline_node_ind+1];

                return interpolate_bezier(p0, p1, p2, p3, t);
            }
        };

        return spline.nodes[spline_node_ind];
    }

    std::vector<line_node_t> line_from_interpolated_spline(spline_t const& spline, size_t subdivisions_per_segment)
    {
        std::vector<line_node_t> constructed_line;

        if(spline.size() == 0 || spline.spline_type == spline_t::linear)
            return constructed_line;

        //space for the original nodes plus subdivisions
        constructed_line.reserve(spline.size() + subdivisions_per_segment * spline.size() - 1);

        for(size_t spline_node_ind = 0; spline_node_ind < spline.size() - 1; ++spline_node_ind)
        {
            //start node
            constructed_line.push_back(spline.nodes[spline_node_ind]);

            for(size_t i = 0; i < subdivisions_per_segment; ++i)
            {
                auto t = static_cast<float>( (i+1) / (subdivisions_per_segment+2) ); //i+1 becuase the 0th node is the spline's start node, not this one
                                                                                //subdivisions_per_segment+2 because
                constructed_line.push_back(interpolated_node(spline, spline_node_ind, t));
            }

            //end node
            constructed_line.push_back(spline.nodes[spline_node_ind+1]);
        }

        //todo: simpilfy spline by removing nodes that are relatively coplanar

        return constructed_line;
    }

    line_node_t interpolate_linear(line_node_t const& start, line_node_t const& end, float t)
    {
        line_node_t node;
        node.position  = glm::lerp(start.position,  end.position,  t);
        node.thickness = glm::lerp(start.thickness, end.thickness, t);
        node.color     = glm::lerp(start.color,     end.color,     t);

        return node;
    }

    line_node_t interpolate_bezier(line_node_t const& start, control_node_t const& cn_start, control_node_t const& cn_end, line_node_t const& end, float t)
    {
        line_node_t node;
        node.position = bezier(start.position, cn_start, cn_end, end.position, t);

        //TODO: do something non-linear for interpolating non-position attributes?
        node.thickness = glm::lerp(start.thickness, end.thickness, t);
        node.color = glm::lerp(start.color, end.color, t);

        return node;
    }
}
}
}<commit_msg>minor fixes and optimizations to spline_renderer<commit_after>#include "stdafx.h"
#include "spline_renderer.h"

#include <glm/gtx/spline.hpp>
#include <glm/gtx/compatibility.hpp> //for lerp

#include "asdf_multiplat/utilities/utilities.h"
#include "asdf_multiplat/data/gl_state.h"

namespace asdf {
namespace hexmap
{
    using namespace data;

namespace ui
{
    namespace
    {
        constexpr size_t default_subdivs_per_spline_segment = 10;
    }

    /// vertex spec allocation / definition
    gl_vertex_spec_<vertex_attrib::position3_t, vertex_attrib::color_t> spline_vertex_t::vertex_spec;

    /// Helper Func Declarations
    line_node_t interpolated_node(spline_t const& spline, size_t spline_node_ind, float t);
    std::vector<line_node_t> line_from_interpolated_spline(spline_t const& spline, size_t subdivisions_per_segment);
    line_node_t interpolate_linear(line_node_t const& start, line_node_t const& end, float t);
    line_node_t interpolate_bezier(line_node_t const& start, control_node_t const& cn_start, control_node_t const& cn_end, line_node_t const& end, float t);

    /// Member Func Definitions
    void spline_renderer_t::begin()
    {
        ASSERT(shader, "cannot render splines without a shader");

        spline_batch.clear();
    }

    void spline_renderer_t::batch(spline_t const& spline)
    {
        spline_batch.push_back(&spline);
    }

    void spline_renderer_t::batch(std::vector<spline_t> const& splines)
    {
        spline_batch.reserve(spline_batch.size() + splines.size());

        for(size_t i = 0; i < splines.size(); ++i)
        {
            spline_batch.push_back(&(splines[i]));
        }
    }

    void spline_renderer_t::end()
    {
        if(spline_batch.empty())
        {
            return;
        }

        ASSERT(shader, "cannot render splines without a shader");

        polygon_<spline_vertex_t> verts;

        std::vector<std::vector<line_node_t>> constructed_lines;
        constructed_lines.reserve(spline_batch.size());

        //reticulate splines
        for(auto const* spline : spline_batch)
        {
            ASSERT(spline, "null spline in batch");
            if(spline->size() > 1)
            {
                constructed_lines.push_back( line_from_interpolated_spline(*spline, default_subdivs_per_spline_segment) );
            }

        }

        constructed_lines.shrink_to_fit();

        if(constructed_lines.empty())
        {
            return;
        }

        //pre-loop to get size info
        size_t num_verts = 0;
        for(auto const& polyline : constructed_lines)
        {
            //not doing thickness yet, so only one vertex per polyline node
            num_verts += polyline.size();
        }
        verts.resize(num_verts);

        size_t vert_ind = 0;
        for(auto const& polyline : constructed_lines)
        {
            for(auto const& line_vert : polyline)
            {
                verts[vert_ind].position = glm::vec3(line_vert.position, 0.0f);
                verts[vert_ind].color    = line_vert.color;

                ++vert_ind;
            }
        }

        ASSERT(vert_ind == num_verts, "Unexpected unset vertices in polyline");

        LOG("binding shader %s", shader->name.c_str());
        GL_State->bind(shader);
        spline_polygon.set_data(verts, shader);
        spline_polygon.render(GL_LINE_LOOP); //will change this to GL_TRIANGLES later when I implement thickness
    }

    /// Helper Func Definitions
    line_node_t interpolated_node(spline_t const& spline, size_t spline_node_ind, float t)
    {
        ASSERT(spline.nodes.size() > spline_node_ind, "out of bounds");

        switch(spline.spline_type)
        {
            case spline_t::linear:
            {
                return interpolate_linear(spline.nodes[spline_node_ind], spline.nodes[spline_node_ind+1], t);
            }
            case spline_t::bezier:
            {
                auto cn_ind = spline_node_ind * 2;

                ASSERT(spline.control_nodes.size() > cn_ind, "out of bounds");

                auto const& p0 = spline.nodes[spline_node_ind];
                auto const& p1 = spline.control_nodes[cn_ind];
                auto const& p2 = spline.control_nodes[cn_ind + 1];
                auto const& p3 = spline.nodes[spline_node_ind+1];

                return interpolate_bezier(p0, p1, p2, p3, t);
            }
        };

        return spline.nodes[spline_node_ind];
    }

    std::vector<line_node_t> line_from_interpolated_spline(spline_t const& spline, size_t subdivisions_per_segment)
    {
        std::vector<line_node_t> constructed_line;

        if(spline.size() == 0 || spline.spline_type == spline_t::linear)
            return spline.nodes;

        //space for the original nodes plus subdivisions
        constructed_line.reserve(spline.size() + subdivisions_per_segment * spline.size() - 1);

        for(size_t spline_node_ind = 0; spline_node_ind < spline.size() - 1; ++spline_node_ind)
        {
            //start node
            constructed_line.push_back(spline.nodes[spline_node_ind]);

            for(size_t i = 0; i < subdivisions_per_segment; ++i)
            {
                auto t = static_cast<float>( (i+1) / (subdivisions_per_segment+2) ); //i+1 becuase the 0th node is the spline's start node, not this one
                                                                                //subdivisions_per_segment+2 because
                constructed_line.push_back(interpolated_node(spline, spline_node_ind, t));
            }

            //end node
            constructed_line.push_back(spline.nodes[spline_node_ind+1]);
        }

        //todo: simpilfy spline by removing nodes that are relatively coplanar

        return constructed_line;
    }

    line_node_t interpolate_linear(line_node_t const& start, line_node_t const& end, float t)
    {
        line_node_t node;
        node.position  = glm::lerp(start.position,  end.position,  t);
        node.thickness = glm::lerp(start.thickness, end.thickness, t);
        node.color     = glm::lerp(start.color,     end.color,     t);

        return node;
    }

    line_node_t interpolate_bezier(line_node_t const& start, control_node_t const& cn_start, control_node_t const& cn_end, line_node_t const& end, float t)
    {
        line_node_t node;
        node.position = bezier(start.position, cn_start, cn_end, end.position, t);

        //TODO: do something non-linear for interpolating non-position attributes?
        node.thickness = glm::lerp(start.thickness, end.thickness, t);
        node.color = glm::lerp(start.color, end.color, t);

        return node;
    }
}
}
}<|endoftext|>