<commit_before>//////////////////////////////////////////////////////////////////////
//
//                             Pixie
//
// Copyright  1999 - 2003, Okan Arikan
//
// Contact: okan@cs.utexas.edu
//
//	This library is free software; you can redistribute it and/or
//	modify it under the terms of the GNU Lesser General Public
//	License as published by the Free Software Foundation; either
//	version 2.1 of the License, or (at your option) any later version.
//
//	This library 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
//	Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//
//  File				:	bsplinePatchgrid.cpp
//  Classes				:
//  Description			:	Patchgrid implementation
//
////////////////////////////////////////////////////////////////////////
#include <math.h>

#include "bsplinePatchgrid.h"
#include "object.h"
#include "shading.h"
#include "memory.h"
#include "stats.h"
#include "patchUtils.h"

///////////////////////////////////////////////////////////////////////
// Class				:	CBSplinePatchGrid
// Method				:	CBSplinePatchGrid
// Description			:	Ctor
// Return Value			:	-
// Comments				:
CBSplinePatchGrid::CBSplinePatchGrid(CAttributes *a,CXform *x,CVertexData *var,CParameter *p,int nu,int nv,float uOrg,float vOrg,float uMult,float vMult,float *ve) : CSurface(a,x) {
	atomicIncrement(&stats.numGprims);

	variables			=	var;
	variables->attach();

	parameters			=	p;

	uVertices			=	nu;
	vVertices			=	nv;
	this->uOrg			=	uOrg;
	this->vOrg			=	vOrg;
	this->uMult			=	uMult;
	this->vMult			=	vMult;

	const int		numVertices		=	(nu*nv);
	int				i,j,k;
	matrix			ut;
	matrix			bsplinebasis;
	matrix			geometryU,geometryV;
	matrix			tmp;
	const int 		upatches		=	uVertices - 3;
	const int	 	vpatches		=	vVertices - 3;

	initv(bmin,C_INFINITY,C_INFINITY,C_INFINITY);
	initv(bmax,-C_INFINITY,-C_INFINITY,-C_INFINITY);

	// Note that u basis and v basis are swapped to take the transpose into account done during the precomputation
	// Note also that we could use the B-spline basis to bound the curve, but Bezier bound is tighter
	for (i=0;i<4;i++)
		for (j=0;j<4;j++)
			bsplinebasis[element(i,j)]	=	RiBSplineBasis[j][i];
	transposem(ut,bsplinebasis);
	mulmm(geometryV,invBezier,ut);
	mulmm(geometryU,bsplinebasis,invBezier);

	// alloc off upatches*vpatches*16*vertexSize worth of data
	const int	vertexSize	=	var->vertexSize;
	const int	vs			=	(variables->moving ? vertexSize*2 : vertexSize);
	vertex					=	new float[vs*16*upatches*vpatches];

	for (i=0;i<vpatches;i++) {
		for (j=0;j<upatches;j++) {
			int		r,c;
			float	*patchData = vertex + (i*upatches + j)*16*vertexSize;

			// Fill in the geometry matrices
			for (r=0;r<4;r++) {
				int					y	=	(r + i) % vVertices;
				for (c=0;c<4;c++) {
					int			x	=	(c + j) % uVertices;
					const float	*d	=	ve + (y*uVertices+x)*vs;

					for	(k=0;k<vertexSize;k++) {
						patchData[16*k + element(r,c)]		=	*d++;
					}
				}
			}

			// add to bounds
			makeCubicBound(bmin,bmax,patchData+0*16,patchData+1*16,patchData+2*16);

			// precompute B*G*B' and stash it
			for	(k=0;k<vertexSize;k++) {
				mulmm(tmp,ut,patchData);
				mulmm(patchData,tmp,bsplinebasis);
				patchData += 16;
			}

			// do the same for moving points
			if (variables->moving) {
				patchData = vertex + (upatches*vpatches + i*upatches + j)*16*vertexSize;

				for (r=0;r<4;r++) {
					int					y	=	(r + i) % vVertices;
					for (c=0;c<4;c++) {
						int			x	=	(c + j) % uVertices;
						const float	*d	=	ve + vertexSize + (y*uVertices+x)*vs;

						for	(k=0;k<vertexSize;k++) {
							patchData[16*k + element(r,c)]		=	*d++;
						}
					}
				}

				// add to bounds
				makeCubicBound(bmin,bmax,patchData+0*16,patchData+1*16,patchData+2*16);

				// precompute B*G*B' and stash it
				for	(k=0;k<vertexSize;k++) {
					mulmm(tmp,ut,patchData);
					mulmm(patchData,tmp,bsplinebasis);
					patchData += 16;
				}
			}
		}
	}

	makeBound(bmin,bmax);
}

///////////////////////////////////////////////////////////////////////
// Class				:	CBSplinePatchGrid
// Method				:	~CBSplinePatchGrid
// Description			:	Dtor
// Return Value			:	-
// Comments				:
CBSplinePatchGrid::~CBSplinePatchGrid() {
	delete [] vertex;

	variables->detach();

	if (parameters != NULL)	delete parameters;

	atomicDecrement(&stats.numGprims);
}

///////////////////////////////////////////////////////////////////////
// Class				:	CBSplinePatchGrid
// Method				:	sample
// Description			:	See object.h
// Return Value			:	-
// Comments				:
void		CBSplinePatchGrid::sample(int start,int numVertices,float **varying,float ***locals,unsigned int &up) const {
	int					i,j,k;
	const float			*u						=	varying[VARIABLE_U]+start;
	const float			*v						=	varying[VARIABLE_V]+start;
	const int			vertexSize				=	variables->vertexSize;
	float				*vertexData;
	int					vertexDataStep;
	int					vertexSampleStride;

	const int 	upatches	=	uVertices - 3;
	const int 	vpatches	=	vVertices - 3;

	if (variables->moving == FALSE) {
		vertexData			=	vertex;								// No need for interpolation
		vertexDataStep		=	0;
		vertexSampleStride	=	vertexSize*16;
	} else {
		if (up & PARAMETER_BEGIN_SAMPLE) {
			vertexData			=	vertex;							// No need for interpolation
			vertexDataStep		=	0;
			vertexSampleStride	=	vertexSize*16;
		} else if (up & PARAMETER_END_SAMPLE) {
			vertexData			=	vertex + vertexSize*16*upatches*vpatches;	// No need for interpolation
			vertexDataStep		=	0;
			vertexSampleStride	=	vertexSize*16;
		} else {
														// Interpolate the vertex data in advance
														// Note: this is potentially hugely expensive
			float			*interpolate;
			const float		*time	=	varying[VARIABLE_TIME] + start;

			vertexData				=	(float *) alloca(numVertices*vertexSize*16*sizeof(float));
			vertexDataStep			=	vertexSize*16;
			vertexSampleStride		=	0;

			interpolate				=	vertexData;

			for (i=0;i<numVertices;i++) {
				const	int		x			=	(int) floor(min(u[i]*upatches,(uVertices-4)));
				const	int		y			=	(int) floor(min(v[i]*vpatches,(vVertices-4)));
				const 	float	*vertex0	=	vertex + (y*upatches + x)*vertexSize*16;
				const 	float	*vertex1	=	vertex0 + vertexSize*16*upatches*vpatches;
				const	float	ctime		=	*time++;

				for (j=0;j<vertexDataStep;j++) {
					*interpolate++	=	vertex0[j]*(1-ctime) + vertex1[j]*ctime;
				}
			}
		}
	}

	{	// Do the vertices
		float	*intr		=	(float *) alloca(numVertices*vertexSize*sizeof(float));
		float	*dPdu		=	varying[VARIABLE_DPDU] + start*3;
		float	*dPdv		=	varying[VARIABLE_DPDV] + start*3;
		float	*N			=	varying[VARIABLE_NG] + start*3;
		float	*intrStart	=	intr;
		const float um		=	(float) upatches;
		const float vm		=	(float) vpatches;

		// Interpolate the vertices
		for (i=0,k=0;i<numVertices;i++) {
			double			tmp1[4],tmp2[4];
			const	int		x			=	(int) floor(min(u[i]*upatches,(uVertices-4)));
			const	int		y			=	(int) floor(min(v[i]*vpatches,(vVertices-4)));
			const	float	cu			=	(u[i]*upatches - x);
			const	float	cv			=	(v[i]*vpatches - y);

			const	float	*data		=	vertexData + (y*upatches + x)*vertexSampleStride;
			const	double	usquared	=	cu*cu;
			const	double	ucubed		=	cu*usquared;
			const	double	vsquared	=	cv*cv;
			const	double	vcubed		=	cv*vsquared;
			int				j;

			for (j=0;j<3;j++) {
				for (int t=0;t<4;t++) {
					tmp2[t]	=	3*vsquared*data[element(0,t)] + 2*cv*data[element(1,t)]     + data[element(2,t)];
					tmp1[t]	=	  vcubed*  data[element(0,t)] + vsquared*data[element(1,t)] + cv*data[element(2,t)] + data[element(3,t)];
				}

				dPdv[j]			=	(float) (tmp2[0]*ucubed + tmp2[1]*usquared + tmp2[2]*cu + tmp2[3])*vm;
				dPdu[j]			=	(float) (tmp1[0]*3*usquared + tmp1[1]*2*cu + tmp1[2])*um;
				intr[k++]		=	(float) (tmp1[0]*ucubed + tmp1[1]*usquared + tmp1[2]*cu + tmp1[3]);
				data			+=	16;
			}

			for (;j<vertexSize;j++) {
				for (int t=0;t<4;t++) {
					tmp1[t]	=	  vcubed*  data[element(0,t)] + vsquared*data[element(1,t)] + cv*data[element(2,t)] + data[element(3,t)];
				}

				intr[k++]		=	(float) (tmp1[0]*ucubed + tmp1[1]*usquared + tmp1[2]*cu + tmp1[3]);
				data			+=	16;
			}

			crossvv(N,dPdu,dPdv);

			vertexData		+=	vertexDataStep;
			dPdu			+=	3;
			dPdv			+=	3;
			N				+=	3;
		}

		// Note: make the common case fast: We're computing NG,DPDU and DPDV even if it's not required.
		// Most of the time though, surface normal is required

		// Dispatch the vertex data
		variables->dispatch(intrStart,start,numVertices,varying,locals);
	}

	normalFix();

	up	&=	~(PARAMETER_P | PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_NG | variables->parameters);
}

///////////////////////////////////////////////////////////////////////
// Class				:	CBSplinePatchGrid
// Method				:	interpolate
// Description			:	See object.h
// Return Value			:	-
// Comments				:
void		CBSplinePatchGrid::interpolate(int numVertices,float **varying,float ***locals) const {
	// perform u,v rescale first to interpolate from larger patch
	if ((uMult != 1) || (vMult != 1)) {
		float	*u,*v,*du,*dv,*dPdu,*dPdv;
		int		i;

		u		=	varying[VARIABLE_U];
		v		=	varying[VARIABLE_V];
		du		=	varying[VARIABLE_DU];
		dv		=	varying[VARIABLE_DV];
		dPdu	=	varying[VARIABLE_DPDU];
		dPdv	=	varying[VARIABLE_DPDV];

		for (i=numVertices;i>0;i--) {
			*u++	=	(*u) * uMult + uOrg;
			*v++	=	(*v) * vMult + vOrg;
			*du++	*=	uMult;
			*dv++	*=	vMult;
			mulvf(dPdu,uMult);	dPdu	+=	3;
			mulvf(dPdv,vMult);	dPdv	+=	3;
		}
	}

	if (parameters != NULL)	parameters->dispatch(numVertices,varying,locals);
}

<commit_msg>math precision improvements<commit_after>//////////////////////////////////////////////////////////////////////
//
//                             Pixie
//
// Copyright  1999 - 2003, Okan Arikan
//
// Contact: okan@cs.utexas.edu
//
//	This library is free software; you can redistribute it and/or
//	modify it under the terms of the GNU Lesser General Public
//	License as published by the Free Software Foundation; either
//	version 2.1 of the License, or (at your option) any later version.
//
//	This library 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
//	Lesser General Public License for more details.
//
//	You should have received a copy of the GNU Lesser General Public
//	License along with this library; if not, write to the Free Software
//	Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//
///////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////
//
//  File				:	bsplinePatchgrid.cpp
//  Classes				:
//  Description			:	Patchgrid implementation
//
////////////////////////////////////////////////////////////////////////
#include <math.h>

#include "bsplinePatchgrid.h"
#include "object.h"
#include "shading.h"
#include "memory.h"
#include "stats.h"
#include "patchUtils.h"

///////////////////////////////////////////////////////////////////////
// Class				:	CBSplinePatchGrid
// Method				:	CBSplinePatchGrid
// Description			:	Ctor
// Return Value			:	-
// Comments				:
CBSplinePatchGrid::CBSplinePatchGrid(CAttributes *a,CXform *x,CVertexData *var,CParameter *p,int nu,int nv,float uOrg,float vOrg,float uMult,float vMult,float *ve) : CSurface(a,x) {
	atomicIncrement(&stats.numGprims);

	variables			=	var;
	variables->attach();

	parameters			=	p;

	uVertices			=	nu;
	vVertices			=	nv;
	this->uOrg			=	uOrg;
	this->vOrg			=	vOrg;
	this->uMult			=	uMult;
	this->vMult			=	vMult;

	const int		numVertices		=	(nu*nv);
	int				i,j,k;
	matrix			ut;
	matrix			bsplinebasis;
	matrix			geometryU,geometryV;
	matrix			tmp;
	const int 		upatches		=	uVertices - 3;
	const int	 	vpatches		=	vVertices - 3;

	initv(bmin,C_INFINITY,C_INFINITY,C_INFINITY);
	initv(bmax,-C_INFINITY,-C_INFINITY,-C_INFINITY);

	// Note that u basis and v basis are swapped to take the transpose into account done during the precomputation
	// Note also that we could use the B-spline basis to bound the curve, but Bezier bound is tighter
	for (i=0;i<4;i++)
		for (j=0;j<4;j++)
			bsplinebasis[element(i,j)]	=	RiBSplineBasis[j][i];
	transposem(ut,bsplinebasis);
	mulmm(geometryV,invBezier,ut);
	mulmm(geometryU,bsplinebasis,invBezier);

	// alloc off upatches*vpatches*16*vertexSize worth of data
	const int	vertexSize	=	var->vertexSize;
	const int	vs			=	(variables->moving ? vertexSize*2 : vertexSize);
	vertex					=	new float[vs*16*upatches*vpatches];

	for (i=0;i<vpatches;i++) {
		for (j=0;j<upatches;j++) {
			int		r,c;
			float	*patchData = vertex + (i*upatches + j)*16*vertexSize;

			// Fill in the geometry matrices
			for (r=0;r<4;r++) {
				int					y	=	(r + i) % vVertices;
				for (c=0;c<4;c++) {
					int			x	=	(c + j) % uVertices;
					const float	*d	=	ve + (y*uVertices+x)*vs;

					for	(k=0;k<vertexSize;k++) {
						patchData[16*k + element(r,c)]		=	*d++;
					}
				}
			}

			// add to bounds
			makeCubicBound(bmin,bmax,patchData+0*16,patchData+1*16,patchData+2*16);

			// precompute B*G*B' and stash it
			for	(k=0;k<vertexSize;k++) {
				mulmm(tmp,ut,patchData);
				mulmm(patchData,tmp,bsplinebasis);
				patchData += 16;
			}

			// do the same for moving points
			if (variables->moving) {
				patchData = vertex + (upatches*vpatches + i*upatches + j)*16*vertexSize;

				for (r=0;r<4;r++) {
					int					y	=	(r + i) % vVertices;
					for (c=0;c<4;c++) {
						int			x	=	(c + j) % uVertices;
						const float	*d	=	ve + vertexSize + (y*uVertices+x)*vs;

						for	(k=0;k<vertexSize;k++) {
							patchData[16*k + element(r,c)]		=	*d++;
						}
					}
				}

				// add to bounds
				makeCubicBound(bmin,bmax,patchData+0*16,patchData+1*16,patchData+2*16);

				// precompute B*G*B' and stash it
				for	(k=0;k<vertexSize;k++) {
					mulmm(tmp,ut,patchData);
					mulmm(patchData,tmp,bsplinebasis);
					patchData += 16;
				}
			}
		}
	}

	makeBound(bmin,bmax);
}

///////////////////////////////////////////////////////////////////////
// Class				:	CBSplinePatchGrid
// Method				:	~CBSplinePatchGrid
// Description			:	Dtor
// Return Value			:	-
// Comments				:
CBSplinePatchGrid::~CBSplinePatchGrid() {
	delete [] vertex;

	variables->detach();

	if (parameters != NULL)	delete parameters;

	atomicDecrement(&stats.numGprims);
}

///////////////////////////////////////////////////////////////////////
// Class				:	CBSplinePatchGrid
// Method				:	sample
// Description			:	See object.h
// Return Value			:	-
// Comments				:
void		CBSplinePatchGrid::sample(int start,int numVertices,float **varying,float ***locals,unsigned int &up) const {
	int					i,j,k;
	const float			*u						=	varying[VARIABLE_U]+start;
	const float			*v						=	varying[VARIABLE_V]+start;
	const int			vertexSize				=	variables->vertexSize;
	float				*vertexData;
	int					vertexDataStep;
	int					vertexSampleStride;

	const int 	upatches	=	uVertices - 3;
	const int 	vpatches	=	vVertices - 3;

	if (variables->moving == FALSE) {
		vertexData			=	vertex;								// No need for interpolation
		vertexDataStep		=	0;
		vertexSampleStride	=	vertexSize*16;
	} else {
		if (up & PARAMETER_BEGIN_SAMPLE) {
			vertexData			=	vertex;							// No need for interpolation
			vertexDataStep		=	0;
			vertexSampleStride	=	vertexSize*16;
		} else if (up & PARAMETER_END_SAMPLE) {
			vertexData			=	vertex + vertexSize*16*upatches*vpatches;	// No need for interpolation
			vertexDataStep		=	0;
			vertexSampleStride	=	vertexSize*16;
		} else {
														// Interpolate the vertex data in advance
														// Note: this is potentially hugely expensive
			float			*interpolate;
			const float		*time	=	varying[VARIABLE_TIME] + start;

			vertexData				=	(float *) alloca(numVertices*vertexSize*16*sizeof(float));
			vertexDataStep			=	vertexSize*16;
			vertexSampleStride		=	0;

			interpolate				=	vertexData;

			for (i=0;i<numVertices;i++) {
				const	int		x			=	(int) floor(min(u[i]*upatches,(uVertices-4)));
				const	int		y			=	(int) floor(min(v[i]*vpatches,(vVertices-4)));
				const 	float	*vertex0	=	vertex + (y*upatches + x)*vertexSize*16;
				const 	float	*vertex1	=	vertex0 + vertexSize*16*upatches*vpatches;
				const	float	ctime		=	*time++;

				for (j=0;j<vertexDataStep;j++) {
					*interpolate++	=	(float) (vertex0[j]*(1.0-ctime) + vertex1[j]*ctime);
				}
			}
		}
	}

	{	// Do the vertices
		float	*intr		=	(float *) alloca(numVertices*vertexSize*sizeof(float));
		float	*dPdu		=	varying[VARIABLE_DPDU] + start*3;
		float	*dPdv		=	varying[VARIABLE_DPDV] + start*3;
		float	*N			=	varying[VARIABLE_NG] + start*3;
		float	*intrStart	=	intr;
		const float um		=	(float) upatches;
		const float vm		=	(float) vpatches;

		// Interpolate the vertices
		for (i=0,k=0;i<numVertices;i++) {
			double			tmp1[4],tmp2[4];
			const	int		x			=	(int) floor(min(u[i]*upatches,(uVertices-4)));
			const	int		y			=	(int) floor(min(v[i]*vpatches,(vVertices-4)));
			const	double	cu			=	(u[i]*upatches - x);
			const	double	cv			=	(v[i]*vpatches - y);

			const	float	*data		=	vertexData + (y*upatches + x)*vertexSampleStride;
			const	double	usquared	=	cu*cu;
			const	double	ucubed		=	cu*usquared;
			const	double	vsquared	=	cv*cv;
			const	double	vcubed		=	cv*vsquared;
			int				j;

			for (j=0;j<3;j++) {
				for (int t=0;t<4;t++) {
					tmp2[t]	=	3*vsquared*data[element(0,t)] + 2*cv*data[element(1,t)]     + data[element(2,t)];
					tmp1[t]	=	  vcubed*  data[element(0,t)] + vsquared*data[element(1,t)] + cv*data[element(2,t)] + data[element(3,t)];
				}

				dPdv[j]			=	(float) (tmp2[0]*ucubed + tmp2[1]*usquared + tmp2[2]*cu + tmp2[3])*vm;
				dPdu[j]			=	(float) (tmp1[0]*3*usquared + tmp1[1]*2*cu + tmp1[2])*um;
				intr[k++]		=	(float) (tmp1[0]*ucubed + tmp1[1]*usquared + tmp1[2]*cu + tmp1[3]);
				data			+=	16;
			}

			for (;j<vertexSize;j++) {
				for (int t=0;t<4;t++) {
					tmp1[t]	=	  vcubed*  data[element(0,t)] + vsquared*data[element(1,t)] + cv*data[element(2,t)] + data[element(3,t)];
				}

				intr[k++]		=	(float) (tmp1[0]*ucubed + tmp1[1]*usquared + tmp1[2]*cu + tmp1[3]);
				data			+=	16;
			}

			crossvv(N,dPdu,dPdv);

			vertexData		+=	vertexDataStep;
			dPdu			+=	3;
			dPdv			+=	3;
			N				+=	3;
		}

		// Note: make the common case fast: We're computing NG,DPDU and DPDV even if it's not required.
		// Most of the time though, surface normal is required

		// Dispatch the vertex data
		variables->dispatch(intrStart,start,numVertices,varying,locals);
	}

	normalFix();

	up	&=	~(PARAMETER_P | PARAMETER_DPDU | PARAMETER_DPDV | PARAMETER_NG | variables->parameters);
}

///////////////////////////////////////////////////////////////////////
// Class				:	CBSplinePatchGrid
// Method				:	interpolate
// Description			:	See object.h
// Return Value			:	-
// Comments				:
void		CBSplinePatchGrid::interpolate(int numVertices,float **varying,float ***locals) const {
	// perform u,v rescale first to interpolate from larger patch
	if ((uMult != 1) || (vMult != 1)) {
		float	*u,*v,*du,*dv,*dPdu,*dPdv;
		int		i;

		u		=	varying[VARIABLE_U];
		v		=	varying[VARIABLE_V];
		du		=	varying[VARIABLE_DU];
		dv		=	varying[VARIABLE_DV];
		dPdu	=	varying[VARIABLE_DPDU];
		dPdv	=	varying[VARIABLE_DPDV];

		for (i=numVertices;i>0;i--) {
			*u++	=	(*u) * uMult + uOrg;
			*v++	=	(*v) * vMult + vOrg;
			*du++	*=	uMult;
			*dv++	*=	vMult;
			mulvf(dPdu,uMult);	dPdu	+=	3;
			mulvf(dPdv,vMult);	dPdv	+=	3;
		}
	}

	if (parameters != NULL)	parameters->dispatch(numVertices,varying,locals);
}

<|endoftext|>


<commit_before>#include "net/connection.h"

#include "util/logger.h"

#ifdef WIN32
#pragma comment(lib,"libevent.lib")
#pragma comment(lib,"wsock32.lib")
#pragma comment(lib,"Ws2_32.lib")
#endif	// WIN32

using namespace khorost::Network;

Connection::Connection(ConnectionController* pThis_, int ID_, evutil_socket_t fd_, struct sockaddr* sa_, int socklen_){
    m_pController = pThis_;
    m_ID = ID_;
    m_fd = fd_;
    memcpy(&m_sa, sa_, sizeof(m_sa));
    m_bev = NULL;

    m_nReceiveBytes = m_nSendBytes = 0;
}

Connection::~Connection(){
    if (m_bev!=NULL) {
        bufferevent_free(m_bev);
    }
}

bool Connection::SendData(const boost::uint8_t* pBuffer_, size_t nBufferSize_) {
    m_nSendBytes += nBufferSize_;
    bufferevent_write(m_bev, pBuffer_, nBufferSize_);
    return true;
}

bool Connection::SendString(const std::string& rString_) {
    return SendData(reinterpret_cast<const boost::uint8_t*>(rString_.c_str()), rString_.size());
}

bool Connection::SendString(const char* pString_, size_t nLength_) {
    if (nLength_==-1) {
        nLength_ = strlen(pString_);
    }
    return SendData(reinterpret_cast<const boost::uint8_t*>(pString_), nLength_);
}

bool Connection::SendNumber(unsigned int nNumber_) {
    char    st[25];
    sprintf(st, "%d", nNumber_);
    return SendString(st);
}

bool Connection::CompileBufferData() {
    size_t		s, nProcessedBytes = 0;

    for( s = 0; m_abSocketBuffer.GetFillSize() > s; s += nProcessedBytes ) {
        nProcessedBytes = DataProcessing(m_abSocketBuffer.GetPosition(s), m_abSocketBuffer.GetFillSize() - s);
        if (nProcessedBytes==0)
            break;
    }
    m_abSocketBuffer.CutFromHead(s);
    return true;
}

void Connection::stubConnWrite(bufferevent* bev_, void* ctx_) {
    Connection* pThis = static_cast<Connection*>(ctx_);
	struct evbuffer *output = bufferevent_get_output(bev_);

    if (evbuffer_get_length(output) == 0) {
		bufferevent_free(bev_);
        pThis->m_bev = NULL;

        ConnectionController* cc = pThis->GetController();
        if (cc!=NULL){
            cc->RemoveConnection(pThis);
        }

        delete pThis;
	}
}

void Connection::stubConnRead(bufferevent* bev_, void* ctx_){
    Connection* pThis = static_cast<Connection*>(ctx_);
    /* This callback is invoked when there is data to read on bev. */
    struct evbuffer* input = bufferevent_get_input(bev_);

    size_t len = evbuffer_get_length(input);
    if (len!=0) {
        pThis->m_abSocketBuffer.CheckSize(len);
        len = bufferevent_read(bev_, static_cast<void*>(pThis->m_abSocketBuffer.GetFreePosition()), len);
        pThis->m_abSocketBuffer.DecrementFreeSize(len);
        pThis->m_nReceiveBytes += len;
        pThis->CompileBufferData();
    }
}

void Connection::stubConnEvent(bufferevent* bev_, short events_, void* ctx_){
    Connection* pThis = static_cast<Connection*>(ctx_);
	if (events_ & BEV_EVENT_EOF) {
		printf("Connection closed.\n");
	} else if (events_ & BEV_EVENT_ERROR) {
		printf("Got an error on the connection: %s\n",
		    strerror(errno));/*XXX win32*/
	}

    ConnectionController* cc = pThis->GetController();
    if (cc!=NULL){
        cc->RemoveConnection(pThis);
    }

    delete pThis;
}

bool Connection::OpenConnection(){
    event_base* base = m_pController->GetBaseListen();

    m_bev = bufferevent_socket_new(base, m_fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE );
    bufferevent_setcb(m_bev, stubConnRead, NULL, stubConnEvent, this);
    bufferevent_enable(m_bev, EV_READ|EV_WRITE);

    return true;
}

bool Connection::CloseConnection() {
    struct evbuffer *output = bufferevent_get_output(m_bev);

    bufferevent_setwatermark(m_bev, EV_WRITE,  evbuffer_get_length(output), 0);
	if (evbuffer_get_length(output)) {
        LOG_CONTEXT(LOG_CTX_NETWORK, LOG_LEVEL_DEBUG, "Flush & Close connection");
        /* We still have to flush data from the other
		 * side, but when that's done, close the other
		 * side. */
        bufferevent_setcb(m_bev, NULL, Connection::stubConnWrite, Connection::stubConnEvent, this);
	    bufferevent_disable(m_bev, EV_READ);
    } else {
        LOG_CONTEXT(LOG_CTX_NETWORK, LOG_LEVEL_DEBUG, "Close connection");
	    /* We have nothing left to say to the other
	    * side; close it. */
		bufferevent_free(m_bev);
        m_bev = NULL;

        // TODO необходима разрегистрация соединения
    }

    return true;
}

ConnectionController::ConnectionController(void* pContext_){
    m_nUniqID = 0;
    m_pContext = pContext_;
    m_ptListen = NULL;
    m_ptgWorkers = NULL;
}

ConnectionController::~ConnectionController(){
    delete m_ptListen;
    delete m_ptgWorkers;
}

Connection* ConnectionController::CreateConnection(ConnectionController* pThis_, int ID_, evutil_socket_t fd_, struct sockaddr* sa_, int socklen_){
    return new Connection(pThis_, ID_, fd_, sa_, socklen_);
}

bool ConnectionController::Shutdown(){
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Shutdown listner");
    event_base_loopexit(m_pebBaseListen, NULL);

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Shutdown workers");
    for (std::deque<event_base*>::const_iterator cit=m_vWorkersBase.begin();cit!=m_vWorkersBase.end();++cit) {
        event_base_loopbreak(*cit);
    }
    m_vWorkersBase.clear();

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Shutdown complete");
    return true;
}

bool ConnectionController::WaitListen() {
    m_ptListen->join();
    m_ptgWorkers->join_all();

    return true;
}

bool ConnectionController::RemoveConnection(Connection* pConnection_){
    boost::mutex::scoped_lock lock(m_mutex);

    LOG_CONTEXT(LOG_CTX_NETWORK, LOG_LEVEL_INFO
        , "Close connect #%d. Receive %d bytes, send %d bytes"
        , pConnection_->GetID(), pConnection_->GetReceiveBytes(), pConnection_->GetSendBytes());

    return true;
}
// Так делать опасно, осуществляется вызов функции из libevent\util-internal.h
extern "C" const char * evutil_format_sockaddr_port(const struct sockaddr *sa, char *out, size_t outlen);

Connection* ConnectionController::AddConnection(evutil_socket_t fd_, struct sockaddr* sa_, int socklen_){
    boost::mutex::scoped_lock lock(m_mutex);

    Connection* pConnection = CreateConnection(this, GetUniqID(), fd_, sa_, socklen_);

    char    buf[1024];
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_INFO
        ,"Detect incoming connect #%d from %s. Accepted on socket #%X"
        ,pConnection->GetID(),evutil_format_sockaddr_port(sa_, buf, sizeof(buf)), fd_);

    pConnection->OpenConnection();

    return pConnection;
}

void Connection::GetClientIP(char* pBuffer_, size_t nBufferSize_) {
    evutil_format_sockaddr_port(&m_sa, pBuffer_, nBufferSize_);
}

#ifndef WIN32
static void stubSignal(
                      evutil_socket_t sig
                      , short events
                      , void *user_data)
{
    ConnectionController* pThis = static_cast<ConnectionController*>(user_data);

    printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
    pThis->Shutdown();
}
#endif

void ConnectionController::stubAccept(
                        struct evconnlistener *listener
                        , evutil_socket_t fd
                        , struct sockaddr *sa
                        , int socklen
                        , void *user_data)
{
    ConnectionController* pThis = static_cast<ConnectionController*>(user_data);
    pThis->AddConnection(fd,sa,socklen);
}

static void stubAcceptError(struct evconnlistener *listener, void *ctx) {
    ConnectionController* pThis = static_cast<ConnectionController*>(ctx);
    struct event_base *base = evconnlistener_get_base(listener);
    int err = EVUTIL_SOCKET_ERROR();
    fprintf(stderr, "Got an error %d (%s) on the listener. "
        "Shutting down.\n", err, evutil_socket_error_to_string(err));

    pThis->Shutdown();
}

void ConnectionController::stubListenRun(ConnectionController* pThis_, int iListenPort_){
    event_config*           cfg = event_config_new();
    evconnlistener*         pelListener;
    sockaddr_in             sin;

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Start listen");

#ifdef WIN32
    evthread_use_windows_threads();
// включать этот режим для использования с сокетами закрывающимися со стороны сервера нельзя. теряется информация
//    event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP);
    event_config_set_num_cpus_hint(cfg,4);
#else
    evthread_use_pthreads();
#endif

    pThis_->m_pebBaseListen = event_base_new_with_config(cfg);
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"LibEvent Method %s",event_base_get_method(pThis_->m_pebBaseListen));

    if (!pThis_->m_pebBaseListen) {
        // fprintf(stderr, "Could not initialize libevent!\n");
        return;
    }

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    /* Listen on 0.0.0.0 */
    sin.sin_addr.s_addr = htonl(0);
    sin.sin_port = htons(iListenPort_);

    pelListener = evconnlistener_new_bind(
        pThis_->m_pebBaseListen
        , stubAccept
        , (void*)pThis_
        , LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE
        , -1
        , (struct sockaddr*)&sin
        , sizeof(sin));

    if (!pelListener) {
        // fprintf(stderr, "Could not create a listener!\n");
        return;
    }

    evconnlistener_set_error_cb(pelListener, stubAcceptError);

#ifndef WIN32
    event*                  peSignalEvent = evsignal_new(
        pThis_->m_pebBaseListen
        , SIGINT
        , stubSignal
        , (void *)pThis_);

    if (!peSignalEvent || event_add(peSignalEvent, NULL)<0) {
        // fprintf(stderr, "Could not create/add a signal event!\n");
        return;
    }
#endif
    // цикл ожидания и обработки событий
    event_base_dispatch(pThis_->m_pebBaseListen);

    evconnlistener_free(pelListener);
#ifndef WIN32
    event_free(peSignalEvent);
#endif
    event_base_free(pThis_->m_pebBaseListen);
    event_config_free(cfg);

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Listen stoped");
}

void ConnectionController::stubWorker(ConnectionController* pThis_){
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Start worker");
    event_base* base = event_base_new();
    pThis_->m_vWorkersBase.push_back(base);

    // цикл ожидания и обработки событий
    event_base_dispatch(base);

    event_base_free(base);
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Stop worker");
}

bool ConnectionController::StartListen(int iListenPort_, int iPollSize_){
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Start listen on port %d", iListenPort_);
    m_ptgWorkers = new boost::thread_group();
    for (int k=0; k<iPollSize_; ++k) {
//        m_ptgWorkers->create_thread(boost::bind(&stubWorker,this));
    }

    m_ptListen = new boost::thread(boost::bind(&stubListenRun,this, iListenPort_));

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Starting listen");
    return true;
}

<commit_msg>корректирока по вычислению IP адреса в случае localhost<commit_after>#include "net/connection.h"

#include "util/logger.h"

#ifdef WIN32
#pragma comment(lib,"libevent.lib")
#pragma comment(lib,"wsock32.lib")
#pragma comment(lib,"Ws2_32.lib")
#endif	// WIN32

using namespace khorost::Network;

Connection::Connection(ConnectionController* pThis_, int ID_, evutil_socket_t fd_, struct sockaddr* sa_, int socklen_){
    m_pController = pThis_;
    m_ID = ID_;
    m_fd = fd_;
    memcpy(&m_sa, sa_, sizeof(m_sa));
    m_bev = NULL;

    m_nReceiveBytes = m_nSendBytes = 0;
}

Connection::~Connection(){
    if (m_bev!=NULL) {
        bufferevent_free(m_bev);
    }
}

bool Connection::SendData(const boost::uint8_t* pBuffer_, size_t nBufferSize_) {
    m_nSendBytes += nBufferSize_;
    bufferevent_write(m_bev, pBuffer_, nBufferSize_);
    return true;
}

bool Connection::SendString(const std::string& rString_) {
    return SendData(reinterpret_cast<const boost::uint8_t*>(rString_.c_str()), rString_.size());
}

bool Connection::SendString(const char* pString_, size_t nLength_) {
    if (nLength_==-1) {
        nLength_ = strlen(pString_);
    }
    return SendData(reinterpret_cast<const boost::uint8_t*>(pString_), nLength_);
}

bool Connection::SendNumber(unsigned int nNumber_) {
    char    st[25];
    sprintf(st, "%d", nNumber_);
    return SendString(st);
}

bool Connection::CompileBufferData() {
    size_t		s, nProcessedBytes = 0;

    for( s = 0; m_abSocketBuffer.GetFillSize() > s; s += nProcessedBytes ) {
        nProcessedBytes = DataProcessing(m_abSocketBuffer.GetPosition(s), m_abSocketBuffer.GetFillSize() - s);
        if (nProcessedBytes==0)
            break;
    }
    m_abSocketBuffer.CutFromHead(s);
    return true;
}

void Connection::stubConnWrite(bufferevent* bev_, void* ctx_) {
    Connection* pThis = static_cast<Connection*>(ctx_);
	struct evbuffer *output = bufferevent_get_output(bev_);

    if (evbuffer_get_length(output) == 0) {
		bufferevent_free(bev_);
        pThis->m_bev = NULL;

        ConnectionController* cc = pThis->GetController();
        if (cc!=NULL){
            cc->RemoveConnection(pThis);
        }

        delete pThis;
	}
}

void Connection::stubConnRead(bufferevent* bev_, void* ctx_){
    Connection* pThis = static_cast<Connection*>(ctx_);
    /* This callback is invoked when there is data to read on bev. */
    struct evbuffer* input = bufferevent_get_input(bev_);

    size_t len = evbuffer_get_length(input);
    if (len!=0) {
        pThis->m_abSocketBuffer.CheckSize(len);
        len = bufferevent_read(bev_, static_cast<void*>(pThis->m_abSocketBuffer.GetFreePosition()), len);
        pThis->m_abSocketBuffer.DecrementFreeSize(len);
        pThis->m_nReceiveBytes += len;
        pThis->CompileBufferData();
    }
}

void Connection::stubConnEvent(bufferevent* bev_, short events_, void* ctx_){
    Connection* pThis = static_cast<Connection*>(ctx_);
	if (events_ & BEV_EVENT_EOF) {
		printf("Connection closed.\n");
	} else if (events_ & BEV_EVENT_ERROR) {
		printf("Got an error on the connection: %s\n",
		    strerror(errno));/*XXX win32*/
	}

    ConnectionController* cc = pThis->GetController();
    if (cc!=NULL){
        cc->RemoveConnection(pThis);
    }

    delete pThis;
}

bool Connection::OpenConnection(){
    event_base* base = m_pController->GetBaseListen();

    m_bev = bufferevent_socket_new(base, m_fd, BEV_OPT_CLOSE_ON_FREE | BEV_OPT_THREADSAFE );
    bufferevent_setcb(m_bev, stubConnRead, NULL, stubConnEvent, this);
    bufferevent_enable(m_bev, EV_READ|EV_WRITE);

    return true;
}

bool Connection::CloseConnection() {
    struct evbuffer *output = bufferevent_get_output(m_bev);

    bufferevent_setwatermark(m_bev, EV_WRITE,  evbuffer_get_length(output), 0);
	if (evbuffer_get_length(output)) {
        LOG_CONTEXT(LOG_CTX_NETWORK, LOG_LEVEL_DEBUG, "Flush & Close connection");
        /* We still have to flush data from the other
		 * side, but when that's done, close the other
		 * side. */
        bufferevent_setcb(m_bev, NULL, Connection::stubConnWrite, Connection::stubConnEvent, this);
	    bufferevent_disable(m_bev, EV_READ);
    } else {
        LOG_CONTEXT(LOG_CTX_NETWORK, LOG_LEVEL_DEBUG, "Close connection");
	    /* We have nothing left to say to the other
	    * side; close it. */
		bufferevent_free(m_bev);
        m_bev = NULL;

        // TODO необходима разрегистрация соединения
    }

    return true;
}

ConnectionController::ConnectionController(void* pContext_){
    m_nUniqID = 0;
    m_pContext = pContext_;
    m_ptListen = NULL;
    m_ptgWorkers = NULL;
}

ConnectionController::~ConnectionController(){
    delete m_ptListen;
    delete m_ptgWorkers;
}

Connection* ConnectionController::CreateConnection(ConnectionController* pThis_, int ID_, evutil_socket_t fd_, struct sockaddr* sa_, int socklen_){
    return new Connection(pThis_, ID_, fd_, sa_, socklen_);
}

bool ConnectionController::Shutdown(){
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Shutdown listner");
    event_base_loopexit(m_pebBaseListen, NULL);

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Shutdown workers");
    for (std::deque<event_base*>::const_iterator cit=m_vWorkersBase.begin();cit!=m_vWorkersBase.end();++cit) {
        event_base_loopbreak(*cit);
    }
    m_vWorkersBase.clear();

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Shutdown complete");
    return true;
}

bool ConnectionController::WaitListen() {
    m_ptListen->join();
    m_ptgWorkers->join_all();

    return true;
}

bool ConnectionController::RemoveConnection(Connection* pConnection_){
    boost::mutex::scoped_lock lock(m_mutex);

    LOG_CONTEXT(LOG_CTX_NETWORK, LOG_LEVEL_INFO
        , "Close connect #%d. Receive %d bytes, send %d bytes"
        , pConnection_->GetID(), pConnection_->GetReceiveBytes(), pConnection_->GetSendBytes());

    return true;
}
// Так делать опасно, осуществляется вызов функции из libevent\util-internal.h
extern "C" const char * evutil_format_sockaddr_port(const struct sockaddr *sa, char *out, size_t outlen);

Connection* ConnectionController::AddConnection(evutil_socket_t fd_, struct sockaddr* sa_, int socklen_){
    boost::mutex::scoped_lock lock(m_mutex);

    Connection* pConnection = CreateConnection(this, GetUniqID(), fd_, sa_, socklen_);

    char    buf[1024];
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_INFO
        ,"Detect incoming connect #%d from %s. Accepted on socket #%X"
        ,pConnection->GetID(),evutil_format_sockaddr_port(sa_, buf, sizeof(buf)), fd_);

    pConnection->OpenConnection();

    return pConnection;
}

void Connection::GetClientIP(char* pBuffer_, size_t nBufferSize_) {
    evutil_format_sockaddr_port(&m_sa, pBuffer_, nBufferSize_);
    for (size_t k = 0; k < nBufferSize_ && pBuffer_[k] != '\0'; ++k) {
        if (pBuffer_[k] == ':') {
            pBuffer_[k] = '\0';
            break;
        }
    }
}

void Connection::GetClientIP(char* pBuffer_, size_t nBufferSize_) {
    evutil_format_sockaddr_port(&m_sa, pBuffer_, nBufferSize_);
}

#ifndef WIN32
static void stubSignal(
                      evutil_socket_t sig
                      , short events
                      , void *user_data)
{
    ConnectionController* pThis = static_cast<ConnectionController*>(user_data);

    printf("Caught an interrupt signal; exiting cleanly in two seconds.\n");
    pThis->Shutdown();
}
#endif

void ConnectionController::stubAccept(
                        struct evconnlistener *listener
                        , evutil_socket_t fd
                        , struct sockaddr *sa
                        , int socklen
                        , void *user_data)
{
    ConnectionController* pThis = static_cast<ConnectionController*>(user_data);
    pThis->AddConnection(fd,sa,socklen);
}

static void stubAcceptError(struct evconnlistener *listener, void *ctx) {
    ConnectionController* pThis = static_cast<ConnectionController*>(ctx);
    struct event_base *base = evconnlistener_get_base(listener);
    int err = EVUTIL_SOCKET_ERROR();
    fprintf(stderr, "Got an error %d (%s) on the listener. "
        "Shutting down.\n", err, evutil_socket_error_to_string(err));

    pThis->Shutdown();
}

void ConnectionController::stubListenRun(ConnectionController* pThis_, int iListenPort_){
    event_config*           cfg = event_config_new();
    evconnlistener*         pelListener;
    sockaddr_in             sin;

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Start listen");

#ifdef WIN32
    evthread_use_windows_threads();
// включать этот режим для использования с сокетами закрывающимися со стороны сервера нельзя. теряется информация
//    event_config_set_flag(cfg,EVENT_BASE_FLAG_STARTUP_IOCP);
    event_config_set_num_cpus_hint(cfg,4);
#else
    evthread_use_pthreads();
#endif

    pThis_->m_pebBaseListen = event_base_new_with_config(cfg);
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"LibEvent Method %s",event_base_get_method(pThis_->m_pebBaseListen));

    if (!pThis_->m_pebBaseListen) {
        // fprintf(stderr, "Could not initialize libevent!\n");
        return;
    }

    memset(&sin, 0, sizeof(sin));
    sin.sin_family = AF_INET;
    /* Listen on 0.0.0.0 */
    sin.sin_addr.s_addr = htonl(0);
    sin.sin_port = htons(iListenPort_);

    pelListener = evconnlistener_new_bind(
        pThis_->m_pebBaseListen
        , stubAccept
        , (void*)pThis_
        , LEV_OPT_REUSEABLE|LEV_OPT_CLOSE_ON_FREE
        , -1
        , (struct sockaddr*)&sin
        , sizeof(sin));

    if (!pelListener) {
        // fprintf(stderr, "Could not create a listener!\n");
        return;
    }

    evconnlistener_set_error_cb(pelListener, stubAcceptError);

#ifndef WIN32
    event*                  peSignalEvent = evsignal_new(
        pThis_->m_pebBaseListen
        , SIGINT
        , stubSignal
        , (void *)pThis_);

    if (!peSignalEvent || event_add(peSignalEvent, NULL)<0) {
        // fprintf(stderr, "Could not create/add a signal event!\n");
        return;
    }
#endif
    // цикл ожидания и обработки событий
    event_base_dispatch(pThis_->m_pebBaseListen);

    evconnlistener_free(pelListener);
#ifndef WIN32
    event_free(peSignalEvent);
#endif
    event_base_free(pThis_->m_pebBaseListen);
    event_config_free(cfg);

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Listen stoped");
}

void ConnectionController::stubWorker(ConnectionController* pThis_){
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Start worker");
    event_base* base = event_base_new();
    pThis_->m_vWorkersBase.push_back(base);

    // цикл ожидания и обработки событий
    event_base_dispatch(base);

    event_base_free(base);
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Stop worker");
}

bool ConnectionController::StartListen(int iListenPort_, int iPollSize_){
    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Start listen on port %d", iListenPort_);
    m_ptgWorkers = new boost::thread_group();
    for (int k=0; k<iPollSize_; ++k) {
//        m_ptgWorkers->create_thread(boost::bind(&stubWorker,this));
    }

    m_ptListen = new boost::thread(boost::bind(&stubListenRun,this, iListenPort_));

    LOG_CONTEXT(LOG_CTX_NETWORK,LOG_LEVEL_DEBUG,"Starting listen");
    return true;
}

<|endoftext|>


<commit_before>/* Copyright 2014 - 2015 CyberTech Labs Ltd.
 *
 * 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. */

#include "trikPyRunnerTest.h"

#include <QtCore/QEventLoop>
#include <QtCore/QFile>

#include <trikControl/brickFactory.h>
#include <trikKernel/fileUtils.h>
#include <testUtils/wait.h>
#include <QTimer>

using namespace tests;
constexpr auto EXIT_TIMEOUT = -93;
constexpr auto EXIT_SCRIPT_ERROR = 113;
constexpr auto EXIT_SCRIPT_SUCCESS = EXIT_SUCCESS;

void TrikPyRunnerTest::SetUp()
{
	mBrick.reset(trikControl::BrickFactory::create("./test-system-config.xml"
				   , "./test-model-config.xml", "./media/"));
	mScriptRunner.reset(new trikScriptRunner::TrikScriptRunner(*mBrick, nullptr));
	mScriptRunner->setDefaultRunner(trikScriptRunner::ScriptType::PYTHON);
	QObject::connect(&*mScriptRunner, &trikScriptRunner::TrikScriptRunnerInterface::textInStdOut,
					 &*mScriptRunner, [this](const QString &m) { mStdOut += m; });
// TODO:	mScriptRunner->registerUserFunction("assert", scriptAssert);
}

void TrikPyRunnerTest::TearDown()
{
}

int TrikPyRunnerTest::run(const QString &script)
{
	QEventLoop l;
	QTimer::singleShot(5000, &l, std::bind(&QEventLoop::exit, &l, EXIT_TIMEOUT));
	QObject::connect(&*mScriptRunner, &trikScriptRunner::TrikScriptRunnerInterface::completed
					 , &l, [&l](const QString &e) { l.exit(e.isEmpty() ? EXIT_SCRIPT_SUCCESS : EXIT_SCRIPT_ERROR); } );
	mStdOut.clear();
	mScriptRunner->run(script, "_.py");
	return l.exec();
}

int TrikPyRunnerTest::runDirectCommandAndWaitForQuit(const QString &script)
{
	QEventLoop l;
	QObject::connect(&*mScriptRunner, &trikScriptRunner::TrikScriptRunnerInterface::completed, &l, &QEventLoop::quit);
	mStdOut.clear();
	mScriptRunner->runDirectCommand(script);
	l.exec();
	return mScriptRunner->wasError()? EXIT_SCRIPT_ERROR : EXIT_SCRIPT_SUCCESS;
}

int TrikPyRunnerTest::runFromFile(const QString &fileName)
{
	auto fileContents = trikKernel::FileUtils::readFromFile("data/" + fileName);

#ifdef Q_OS_WIN
	fileContents = fileContents.replace("&&", ";");
#endif

	return run(fileContents);
}

trikScriptRunner::TrikScriptRunner &TrikPyRunnerTest::scriptRunner()
{
	return *mScriptRunner;
}

TEST_F(TrikPyRunnerTest, abortBeforeRun)
{
	scriptRunner().abortAll();
}

TEST_F(TrikPyRunnerTest, syntaxErrorReport)
{
	auto err = run("]");
	ASSERT_EQ(err, EXIT_SCRIPT_ERROR);
}

TEST_F(TrikPyRunnerTest, sanityCheck)
{
	auto err = run("1 + 1");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
	const auto &knownMethodNames = scriptRunner().knownMethodNames();
	ASSERT_TRUE(knownMethodNames.contains("brick"));
	ASSERT_TRUE(knownMethodNames.contains("setPower"));
	err = run("brick.motor('M2').setPower(10)");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, print)
{
	const QString text = "Hello";
	auto err = runDirectCommandAndWaitForQuit("print('" + text + "', end='')");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
	ASSERT_TRUE(text == mStdOut);
}

TEST_F(TrikPyRunnerTest, abortWhileTrue)
{
	QTimer t;
	t.setInterval(200);
	t.setSingleShot(true);
	using trikScriptRunner::TrikScriptRunnerInterface;
	QObject::connect(&scriptRunner(), &TrikScriptRunnerInterface::startedScript
					 , &t, QOverload<>::of(&QTimer::start));
	QObject::connect(&t, &QTimer::timeout, &scriptRunner(), &TrikScriptRunnerInterface::abort);
	auto err = run("print('before')\nwhile True: pass\nprint('after')");
	ASSERT_NE(err, EXIT_TIMEOUT);
	t.stop();
}

TEST_F(TrikPyRunnerTest, scriptWait)
{
	scriptRunner().run("script.wait(500)");
	tests::utils::Wait::wait(600);
}

TEST_F(TrikPyRunnerTest, directCommandContextWithTimersAndQtCore)
{
	auto err = runDirectCommandAndWaitForQuit("from PythonQt import QtCore");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
	err = runDirectCommandAndWaitForQuit("QtCore.QTimer.singleShot(100, lambda _ : None)");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
	err = runDirectCommandAndWaitForQuit("t=QtCore.QTimer()");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, propertyAndMethodWithSimpleType)
{
	auto exitCode = run("brick.gyroscope().read()");
	ASSERT_EQ(exitCode, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, brickMethodWithNonTrivialReturnTypeConversion)
{
	auto exitCode = run("brick.getStillImage()");
	ASSERT_EQ(exitCode, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, brickPropertyAndVectorArgument)
{
	auto exitCode = run("brick.display().show([0], 1, 1, 'grayscale8')");
	ASSERT_EQ(exitCode, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, DISABLED_fileTestPy)
{
	auto err = runFromFile("file-test.py");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, scriptExecutionControl)
{
	auto exitCode = run("a = script.timer(1000)");
	ASSERT_EQ(exitCode, EXIT_SCRIPT_SUCCESS);
}
<commit_msg>Increase delay to give enough time to start<commit_after>/* Copyright 2014 - 2015 CyberTech Labs Ltd.
 *
 * 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. */

#include "trikPyRunnerTest.h"

#include <QtCore/QEventLoop>
#include <QtCore/QFile>

#include <trikControl/brickFactory.h>
#include <trikKernel/fileUtils.h>
#include <testUtils/wait.h>
#include <QTimer>

using namespace tests;
constexpr auto EXIT_TIMEOUT = -93;
constexpr auto EXIT_SCRIPT_ERROR = 113;
constexpr auto EXIT_SCRIPT_SUCCESS = EXIT_SUCCESS;

void TrikPyRunnerTest::SetUp()
{
	mBrick.reset(trikControl::BrickFactory::create("./test-system-config.xml"
				   , "./test-model-config.xml", "./media/"));
	mScriptRunner.reset(new trikScriptRunner::TrikScriptRunner(*mBrick, nullptr));
	mScriptRunner->setDefaultRunner(trikScriptRunner::ScriptType::PYTHON);
	QObject::connect(&*mScriptRunner, &trikScriptRunner::TrikScriptRunnerInterface::textInStdOut,
					 &*mScriptRunner, [this](const QString &m) { mStdOut += m; });
// TODO:	mScriptRunner->registerUserFunction("assert", scriptAssert);
}

void TrikPyRunnerTest::TearDown()
{
}

int TrikPyRunnerTest::run(const QString &script)
{
	QEventLoop l;
	QTimer::singleShot(5000, &l, std::bind(&QEventLoop::exit, &l, EXIT_TIMEOUT));
	QObject::connect(&*mScriptRunner, &trikScriptRunner::TrikScriptRunnerInterface::completed
					 , &l, [&l](const QString &e) { l.exit(e.isEmpty() ? EXIT_SCRIPT_SUCCESS : EXIT_SCRIPT_ERROR); } );
	mStdOut.clear();
	mScriptRunner->run(script, "_.py");
	return l.exec();
}

int TrikPyRunnerTest::runDirectCommandAndWaitForQuit(const QString &script)
{
	QEventLoop l;
	QObject::connect(&*mScriptRunner, &trikScriptRunner::TrikScriptRunnerInterface::completed, &l, &QEventLoop::quit);
	mStdOut.clear();
	mScriptRunner->runDirectCommand(script);
	l.exec();
	return mScriptRunner->wasError()? EXIT_SCRIPT_ERROR : EXIT_SCRIPT_SUCCESS;
}

int TrikPyRunnerTest::runFromFile(const QString &fileName)
{
	auto fileContents = trikKernel::FileUtils::readFromFile("data/" + fileName);

#ifdef Q_OS_WIN
	fileContents = fileContents.replace("&&", ";");
#endif

	return run(fileContents);
}

trikScriptRunner::TrikScriptRunner &TrikPyRunnerTest::scriptRunner()
{
	return *mScriptRunner;
}

TEST_F(TrikPyRunnerTest, abortBeforeRun)
{
	scriptRunner().abortAll();
}

TEST_F(TrikPyRunnerTest, syntaxErrorReport)
{
	auto err = run("]");
	ASSERT_EQ(err, EXIT_SCRIPT_ERROR);
}

TEST_F(TrikPyRunnerTest, sanityCheck)
{
	auto err = run("1 + 1");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
	const auto &knownMethodNames = scriptRunner().knownMethodNames();
	ASSERT_TRUE(knownMethodNames.contains("brick"));
	ASSERT_TRUE(knownMethodNames.contains("setPower"));
	err = run("brick.motor('M2').setPower(10)");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, print)
{
	auto text = "Hello";
	auto err = runDirectCommandAndWaitForQuit(QString("print('") + text + "', end='')");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
	ASSERT_EQ(text, mStdOut.toStdString());
}

TEST_F(TrikPyRunnerTest, abortWhileTrue)
{
	QTimer t;
	t.setInterval(1000);
	t.setSingleShot(true);
	using trikScriptRunner::TrikScriptRunnerInterface;
	QObject::connect(&scriptRunner(), &TrikScriptRunnerInterface::startedScript
					 , &t, QOverload<>::of(&QTimer::start));
	QObject::connect(&t, &QTimer::timeout, &scriptRunner(), &TrikScriptRunnerInterface::abort);
	auto err = run("print('before')\nwhile True: pass\nprint('after')");
	ASSERT_EQ(mStdOut.toStdString(), "before\n");
	ASSERT_NE(err, EXIT_TIMEOUT);
	t.stop();
}

TEST_F(TrikPyRunnerTest, scriptWait)
{
	scriptRunner().run("script.wait(500)");
	tests::utils::Wait::wait(600);
}

TEST_F(TrikPyRunnerTest, directCommandContextWithTimersAndQtCore)
{
	auto err = runDirectCommandAndWaitForQuit("from PythonQt import QtCore");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
	err = runDirectCommandAndWaitForQuit("QtCore.QTimer.singleShot(100, lambda _ : None)");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
	err = runDirectCommandAndWaitForQuit("t=QtCore.QTimer()");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, propertyAndMethodWithSimpleType)
{
	auto exitCode = run("brick.gyroscope().read()");
	ASSERT_EQ(exitCode, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, brickMethodWithNonTrivialReturnTypeConversion)
{
	auto exitCode = run("brick.getStillImage()");
	ASSERT_EQ(exitCode, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, brickPropertyAndVectorArgument)
{
	auto exitCode = run("brick.display().show([0], 1, 1, 'grayscale8')");
	ASSERT_EQ(exitCode, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, DISABLED_fileTestPy)
{
	auto err = runFromFile("file-test.py");
	ASSERT_EQ(err, EXIT_SCRIPT_SUCCESS);
}

TEST_F(TrikPyRunnerTest, scriptExecutionControl)
{
	auto exitCode = run("a = script.timer(1000)");
	ASSERT_EQ(exitCode, EXIT_SCRIPT_SUCCESS);
}
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "TransientContextMemberTest.h"
#include "TransientContextMember.h"
#include "TransientPool.h"

class TransientEventA:
  public virtual EventReceiver
{
public:
  virtual void ZeroArgsA(void) = 0;
};

class TransientEventB:
  public virtual EventReceiver
{
public:
  virtual void ZeroArgsB(void) = 0;
};

class TransientClassA:
  public TransientContextMember,
  public TransientEventA,
  public EventSender<TransientEventB>
{
public:
  TransientClassA(void):
    m_received(false)
  {}

  virtual void ZeroArgsA(void) override {
    m_received = true;
  }

  bool m_received;

  using EventSender::Fire;
};

class DurableClassA:
  public EventSender<TransientEventA>,
  public TransientEventB
{
public:
  DurableClassA(void):
    m_received(false)
  {}

  virtual void ZeroArgsB(void) override {
    m_received = true;
  }

  bool m_received;

  using EventSender::Fire;
};

class MyTransientPool:
  public TransientPool<TransientClassA>
{
};

TEST_F(TransientContextMemberTest, VerifyTransience) {
  std::weak_ptr<TransientClassA> transWeak;

  AutoRequired<DurableClassA> durable;
  {
    AutoRequired<MyTransientPool> pool;

    AutoTransient<TransientClassA> trans;
    transWeak = trans;

    // Verify bidirectional event transmission:
    trans->Fire(&TransientEventB::ZeroArgsB)();
    durable->Fire(&TransientEventA::ZeroArgsA)();

    EXPECT_TRUE(trans->m_received) << "Transient class did not receive an event as expected";
    EXPECT_TRUE(durable->m_received) << "Durable instance did not receive a message from a transient instance";
  }

  EXPECT_TRUE(transWeak.expired()) << "Transient instance did not expire as expected";
}<commit_msg>Unit tests extended for transient members<commit_after>#include "stdafx.h"
#include "TransientContextMemberTest.h"
#include "TransientContextMember.h"
#include "TransientPool.h"

class TransientEventA:
  public virtual EventReceiver
{
public:
  virtual void ZeroArgsA(void) = 0;
};

class TransientEventB:
  public virtual EventReceiver
{
public:
  virtual void ZeroArgsB(void) = 0;
};

class TransientClassA:
  public TransientContextMember,
  public TransientEventA,
  public EventSender<TransientEventB>
{
public:
  TransientClassA(void):
    m_received(false)
  {}

  virtual void ZeroArgsA(void) override {
    m_received = true;
  }

  bool m_received;

  using EventSender::Fire;
};

class DurableClassA:
  public EventSender<TransientEventA>,
  public TransientEventB
{
public:
  DurableClassA(void):
    m_received(false)
  {}

  virtual void ZeroArgsB(void) override {
    m_received = true;
  }

  bool m_received;

  using EventSender::Fire;
};

class DurableClassB:
  public DurableClassA
{
};

class MyTransientPool:
  public TransientPool<TransientClassA>
{
};

TEST_F(TransientContextMemberTest, VerifyTransience) {
  std::weak_ptr<TransientClassA> transWeak;

  AutoRequired<DurableClassA> durable;
  {
    AutoRequired<DurableClassB> durableB;
    AutoRequired<MyTransientPool> pool;

    AutoTransient<TransientClassA> trans;
    transWeak = trans;

    // Verify bidirectional event transmission:
    trans->Fire(&TransientEventB::ZeroArgsB)();
    durable->Fire(&TransientEventA::ZeroArgsA)();
    durableB->Fire(&TransientEventA::ZeroArgsA)();

    EXPECT_TRUE(trans->m_received) << "Transient class did not receive an event as expected";
    EXPECT_TRUE(durable->m_received) << "Durable instance did not receive a message from a transient instance";
  }

  EXPECT_TRUE(transWeak.expired()) << "Transient instance did not expire as expected";
}<|endoftext|>


<commit_before>#include "runtime/runtime_spec_helper.h"
#include "runtime/helpers/spy_reader.h"

extern "C" const TSLanguage * ts_language_json();

START_TEST

describe("Document", [&]() {
  TSDocument *doc;

  before_each([&]() {
    doc = ts_document_make();
  });

  after_each([&]() {
    ts_document_free(doc);
  });

  describe("set_input", [&]() {
    SpyReader *reader;

    before_each([&]() {
      reader = new SpyReader("{ \"key\": [1, 2] }", 5);
    });

    after_each([&]() {
      delete reader;
    });

    describe("when the language is set", [&]() {
      before_each([&]() {
        ts_document_set_language(doc, ts_language_json());
      });

      it("parses the document", [&]() {
        SpyReader *reader = new SpyReader("{ \"key\": [1, 2] }", 5);
        ts_document_set_input(doc, reader->input);

        AssertThat(string(ts_node_string(ts_document_root_node(doc))), Equals(
            "(DOCUMENT (object (string) (array (number) (number))))"
        ));
      });

      it("reads the entire input", [&]() {
        SpyReader *reader = new SpyReader("{ \"key\": [1, 2] }", 5);
        ts_document_set_input(doc, reader->input);
        AssertThat(reader->strings_read, Equals(vector<string>({
            "{ \"key\": [1, 2] }"
        })));
      });
    });

    describe("when the language is not set", [&]() {
      it("does not try to parse the document", [&]() {
        ts_document_set_input(doc, reader->input);

        AssertThat(ts_document_root_node(doc), Equals<TSNode *>(nullptr));
      });
    });
  });

  describe("edit", [&]() {
    SpyReader *reader;

    before_each([&]() {
      reader = new SpyReader("{ \"key\": [1, 2] }", 5);
      ts_document_set_language(doc, ts_language_json());
      ts_document_set_input(doc, reader->input);
    });

    after_each([&]() {
      delete reader;
    });

    describe("modifying the end of the input", [&]() {
      before_each([&]() {
        size_t position(string("{ \"key\": [1, 2]").length());
        string inserted_text(", \"key2\": 4");

        reader->content.insert(position, inserted_text);
        ts_document_edit(doc, { position, 0, inserted_text.length() });
      });

      it("updates the parse tree", [&]() {
        AssertThat(string(ts_node_string(ts_document_root_node(doc))), Equals(
            "(DOCUMENT (object (string) (array (number) (number)) (string) (number)))"));
      });

      it("re-reads only the changed portion of the input", [&]() {
        AssertThat(reader->strings_read.size(), Equals<size_t>(2));
        AssertThat(reader->strings_read[1], Equals(", \"key2\": 4 }"));
      });
    });

    describe("modifying the beginning of the input", [&]() {
      before_each([&]() {
        size_t position(string("{ ").length());
        string inserted_text("\"key2\": 4, ");

        reader->content.insert(position, inserted_text);
        ts_document_edit(doc, { position, 0, inserted_text.length() });
      });

      it("updates the parse tree", [&]() {
        AssertThat(string(ts_node_string(ts_document_root_node(doc))), Equals(
            "(DOCUMENT (object (string) (number) (string) (array (number) (number))))"));
      });

      it_skip("re-reads only the changed portion of the input", [&]() {
        AssertThat(reader->strings_read.size(), Equals<size_t>(2));
        AssertThat(reader->strings_read[1], Equals("\"key2\": 4, "));
      });
    });
  });

  describe("parsing", [&]() {
    TSNode *root;

    describe("error handling", [&]() {
      before_each([&]() {
        ts_document_set_language(doc, ts_language_json());
      });

      describe("when the error occurs at the beginning of a token", [&]() {
        it("computes the error node's size and position correctly", [&]() {
          ts_document_set_input_string(doc, "  [123, @@@@@, true]");
          AssertThat(ts_node_string(ts_document_root_node(doc)), Equals(
              "(DOCUMENT (array (number) (ERROR '@') (true)))"));

          root = ts_document_root_node(doc);
          TSNode *array = ts_node_child(root, 0);
          TSNode *error = ts_node_child(array, 1);

          AssertThat(ts_node_name(error), Equals("error"));
          AssertThat(ts_node_pos(error), Equals(string("  [123,").length()))
          AssertThat(ts_node_size(error), Equals(string(" @@@@@").length()))

          ts_node_release(error);
          ts_node_release(array);
          ts_node_release(error);
        });
      });

      describe("when the error occurs in the middle of a token", [&]() {
        it("computes the error node's size and position correctly", [&]() {
          ts_document_set_input_string(doc, "  [123, total nonsense, true]");
          AssertThat(ts_node_string(ts_document_root_node(doc)), Equals(
              "(DOCUMENT (array (number) (ERROR 'o') (true)))"));

          root = ts_document_root_node(doc);
          TSNode *array = ts_node_child(root, 0);
          TSNode *error = ts_node_child(array, 1);

          AssertThat(ts_node_name(error), Equals("error"));
          AssertThat(ts_node_pos(error), Equals(string("  [123,").length()))
          AssertThat(ts_node_size(error), Equals(string(" total nonsense").length()))

          ts_node_release(error);
          ts_node_release(array);
          ts_node_release(error);
        });
      });

      describe("when the error occurs after one or more tokens", [&]() {
        it("computes the error node's size and position correctly", [&]() {
          ts_document_set_input_string(doc, "  [123, true false, true]");
          AssertThat(ts_node_string(ts_document_root_node(doc)), Equals(
              "(DOCUMENT (array (number) (ERROR 'f') (true)))"));

          root = ts_document_root_node(doc);
          TSNode *array = ts_node_child(root, 0);
          TSNode *error = ts_node_child(array, 1);

          AssertThat(ts_node_name(error), Equals("error"));
          AssertThat(ts_node_pos(error), Equals(string("  [123,").length()))
          AssertThat(ts_node_size(error), Equals(string(" true false").length()))

          ts_node_release(error);
          ts_node_release(array);
          ts_node_release(error);
        });
      });
    });
  });
});

END_TEST
<commit_msg>Fix double release calls in document spec<commit_after>#include "runtime/runtime_spec_helper.h"
#include "runtime/helpers/spy_reader.h"

extern "C" const TSLanguage * ts_language_json();

START_TEST

describe("Document", [&]() {
  TSDocument *doc;

  before_each([&]() {
    doc = ts_document_make();
  });

  after_each([&]() {
    ts_document_free(doc);
  });

  describe("set_input", [&]() {
    SpyReader *reader;

    before_each([&]() {
      reader = new SpyReader("{ \"key\": [1, 2] }", 5);
    });

    after_each([&]() {
      delete reader;
    });

    describe("when the language is set", [&]() {
      before_each([&]() {
        ts_document_set_language(doc, ts_language_json());
      });

      it("parses the document", [&]() {
        SpyReader *reader = new SpyReader("{ \"key\": [1, 2] }", 5);
        ts_document_set_input(doc, reader->input);

        AssertThat(string(ts_node_string(ts_document_root_node(doc))), Equals(
            "(DOCUMENT (object (string) (array (number) (number))))"
        ));
      });

      it("reads the entire input", [&]() {
        SpyReader *reader = new SpyReader("{ \"key\": [1, 2] }", 5);
        ts_document_set_input(doc, reader->input);
        AssertThat(reader->strings_read, Equals(vector<string>({
            "{ \"key\": [1, 2] }"
        })));
      });
    });

    describe("when the language is not set", [&]() {
      it("does not try to parse the document", [&]() {
        ts_document_set_input(doc, reader->input);

        AssertThat(ts_document_root_node(doc), Equals<TSNode *>(nullptr));
      });
    });
  });

  describe("edit", [&]() {
    SpyReader *reader;

    before_each([&]() {
      reader = new SpyReader("{ \"key\": [1, 2] }", 5);
      ts_document_set_language(doc, ts_language_json());
      ts_document_set_input(doc, reader->input);
    });

    after_each([&]() {
      delete reader;
    });

    describe("modifying the end of the input", [&]() {
      before_each([&]() {
        size_t position(string("{ \"key\": [1, 2]").length());
        string inserted_text(", \"key2\": 4");

        reader->content.insert(position, inserted_text);
        ts_document_edit(doc, { position, 0, inserted_text.length() });
      });

      it("updates the parse tree", [&]() {
        AssertThat(string(ts_node_string(ts_document_root_node(doc))), Equals(
            "(DOCUMENT (object (string) (array (number) (number)) (string) (number)))"));
      });

      it("re-reads only the changed portion of the input", [&]() {
        AssertThat(reader->strings_read.size(), Equals<size_t>(2));
        AssertThat(reader->strings_read[1], Equals(", \"key2\": 4 }"));
      });
    });

    describe("modifying the beginning of the input", [&]() {
      before_each([&]() {
        size_t position(string("{ ").length());
        string inserted_text("\"key2\": 4, ");

        reader->content.insert(position, inserted_text);
        ts_document_edit(doc, { position, 0, inserted_text.length() });
      });

      it("updates the parse tree", [&]() {
        AssertThat(string(ts_node_string(ts_document_root_node(doc))), Equals(
            "(DOCUMENT (object (string) (number) (string) (array (number) (number))))"));
      });

      it_skip("re-reads only the changed portion of the input", [&]() {
        AssertThat(reader->strings_read.size(), Equals<size_t>(2));
        AssertThat(reader->strings_read[1], Equals("\"key2\": 4, "));
      });
    });
  });

  describe("parsing", [&]() {
    TSNode *root;

    describe("error handling", [&]() {
      before_each([&]() {
        ts_document_set_language(doc, ts_language_json());
      });

      describe("when the error occurs at the beginning of a token", [&]() {
        it("computes the error node's size and position correctly 1", [&]() {
          ts_document_set_input_string(doc, "  [123, @@@@@, true]");
          AssertThat(ts_node_string(ts_document_root_node(doc)), Equals(
              "(DOCUMENT (array (number) (ERROR '@') (true)))"));

          root = ts_document_root_node(doc);
          TSNode *array = ts_node_child(root, 0);
          TSNode *error = ts_node_child(array, 1);

          AssertThat(ts_node_name(error), Equals("error"));
          AssertThat(ts_node_pos(error), Equals(string("  [123,").length()))
          AssertThat(ts_node_size(error), Equals(string(" @@@@@").length()))

          ts_node_release(error);
          ts_node_release(array);
        });
      });

      describe("when the error occurs in the middle of a token", [&]() {
        it("computes the error node's size and position correctly 2", [&]() {
          ts_document_set_input_string(doc, "  [123, total nonsense, true]");
          AssertThat(ts_node_string(ts_document_root_node(doc)), Equals(
              "(DOCUMENT (array (number) (ERROR 'o') (true)))"));

          root = ts_document_root_node(doc);
          TSNode *array = ts_node_child(root, 0);
          TSNode *error = ts_node_child(array, 1);

          AssertThat(ts_node_name(error), Equals("error"));
          AssertThat(ts_node_pos(error), Equals(string("  [123,").length()))
          AssertThat(ts_node_size(error), Equals(string(" total nonsense").length()))

          ts_node_release(error);
          ts_node_release(array);
        });
      });

      describe("when the error occurs after one or more tokens", [&]() {
        it("computes the error node's size and position correctly 3", [&]() {
          ts_document_set_input_string(doc, "  [123, true false, true]");
          AssertThat(ts_node_string(ts_document_root_node(doc)), Equals(
              "(DOCUMENT (array (number) (ERROR 'f') (true)))"));

          root = ts_document_root_node(doc);
          TSNode *array = ts_node_child(root, 0);
          TSNode *error = ts_node_child(array, 1);

          AssertThat(ts_node_name(error), Equals("error"));
          AssertThat(ts_node_pos(error), Equals(string("  [123,").length()))
          AssertThat(ts_node_size(error), Equals(string(" true false").length()))

          ts_node_release(error);
          ts_node_release(array);
        });
      });
    });
  });
});

END_TEST
<|endoftext|>


<commit_before>/***********************************************************************************
This file is part of Project for MaratonServant
For the latest info, see  https://github.com/Yhgenomics/MaratonServant.git

Copyright 2016 Yhgenomics

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.
***********************************************************************************/

/***********************************************************************************
* Description   : Serial pipes make a pipeline.
* Creator       : Ke Yang(keyang@yhgenomics.com)
* Date          : 2016/3/8
* Modifed       : When      | Who       | What
***********************************************************************************/

#include "Pipeline.h"
#include "WorkManager.h"
#include "ExitCodeHandlerSet.h"
#include <fstream>
#include <iostream>
#include <string>

using std::string;

NS_SERVANT_BEGIN

// Add one Pipe to pipeline
// @pipe    : one Pipe need to be added.
void Pipeline::AddPipe( uptr<Pipe> pipe )
{
    pipe_list_.push_back( std::move( pipe ) );
}

// Parse the pipeline informantion from a protobuf Message.
// @orignalMessage : message from the Maraton Master
void Pipeline::ParseFromMessage( uptr<MessageTaskDeliver> orignalMessage )
{
    // Refresh task info
    task_id_.clear();
    original_id_.clear();
    main_path_.clear();
    task_path_.clear();

    task_id_     = orignalMessage->id();
    original_id_ = orignalMessage->originalid();
    main_path_   = task_root_ + original_id_ + "/";
    task_path_   = task_root_ + original_id_ + "/" + task_id_ + "/";

    // Make the main task path and the subtask path
    system( ( mkdir_ + main_path_ ).c_str() );
    system( ( mkdir_ + task_path_ ).c_str() );

    // Append to subtask list
    std::ofstream subtaskFout( main_path_ + subtask_list_,std::ios::app);

    subtaskFout << task_id_ <<  std::endl;
    subtaskFout.close();

    // Make Input File
    std::ofstream fout( task_path_ + input_file_ );

    for ( auto file : orignalMessage->input() )
    {
        fout << file << std::endl;
    }

    fout.close();

    // Add others info to pipeline
    for ( auto item : orignalMessage->pipeline().pipes() )
    {
        auto pipe = make_uptr( Pipe );

        pipe->DockerDaemon( docker_daemon );

        pipe->DockerImage( item.executor() );

        pipe->AddPathBind( task_path_ , docker_work_ );
        pipe->AddPathBind( data_path_ , docker_data_ );

        pipe->SetPipeExit( NextPipe );

        for(auto param : item.parameters())
        {
            pipe->AddEnvironment( param );
        }

        AddPipe( std::move( pipe ) );
    } // end of for ( auto item : orignalMessage->pipeline().pipes() )
}

// Start the pipeline
void Pipeline::Run()
{
    RunNext( 0 );
}

// Run Next based on the exit Code from last pipe
// @lastExitCode : Exit code of the one pipe before current one.
// @note         : exit code is 0 before the first pipe run.
void Pipeline::RunNext( const int & lastExitCode )
{
    if ( lastExitCode != 0 )
        OnException( lastExitCode );

    if ( pipe_list_.size() == 0 )
        OnFinish();

    else
    {
        auto currentPipe = std::move( pipe_list_[ 0 ] );
        pipe_list_.erase( pipe_list_.begin() );
        currentPipe->Run();
    }
}

// Called when pipeline finish
void Pipeline::OnFinish()
{
    vector<string> outputs;
    GatherOutputInformation( outputs );
    Protocal::MessageHub::Instance()->SendTaskUpdate( TaskStatus::kFinished , outputs );
    Logger::Log( "Pipeline Finished " );

    WorkManager::Instance()->FinishWork();
}

// Called when exception happens
// @lastExitCode : Exit code of the one pipe before current one.
// @note         : any non-zero exit code is consider as exception
void Pipeline::OnException( const int & lastExitCode )
{
    Protocal::MessageHub::Instance()->SendTaskUpdate( TaskStatus::kError );

    Logger::Error("Exception happended code : %",lastExitCode);
}

// Constructor
Pipeline::Pipeline()
{
    Init();
}

// Initialization
void Pipeline::Init()
{
    mkdir_        = "mkdir ";
    task_root_    = "/data/mrttask/";
    data_path_    = "/data/ref/";
    task_id_      = "";
    original_id_  = "";
    task_path_    = "";
    input_file_   = "input.mrt";
    output_file_  = "output.mrt";
    subtask_list_ = "subtasklist.log";
    docker_work_  = "/work/";
    docker_data_  = "/data/";
    docker_daemon = "http://127.0.0.1:4243";
    main_log_     = "subtasklist.log";
    runtime_Log_  = "runtime.log";
    main_path_    = "";
}

// Check if a string contains valid content
// @oneLine : one line from the output file.
inline bool Pipeline::IsOutputLineValid( const string & oneLine )
{
    return (    oneLine != ""
             && oneLine != "\r"
             && oneLine != "\n"
             && oneLine != "\r\n"
             && oneLine != "\n\r" );
}

// Gathering all outputs informantion
// @outputs   : The contianer's outputs files informations.
bool Pipeline::GatherOutputInformation( vector<string>& outputs )
{
    bool result = false;
    std::ifstream fin;
    fin.open( task_path_ + output_file_ );

    if ( fin )
    {
        while ( !fin.eof() )
        {
            std::string oneLine;
            fin >> oneLine;

            if ( IsOutputLineValid( oneLine ) )
            {
                outputs.push_back( oneLine );
            }
        }

        fin.close();
        result = true;
    } //  end of  if ( fin )

    else
    {
        result = false;
    }

    return result;
}

NS_SERVANT_END
<commit_msg>check bugs in linux (may cause by the default value of class members)<commit_after>/***********************************************************************************
This file is part of Project for MaratonServant
For the latest info, see  https://github.com/Yhgenomics/MaratonServant.git

Copyright 2016 Yhgenomics

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.
***********************************************************************************/

/***********************************************************************************
* Description   : Serial pipes make a pipeline.
* Creator       : Ke Yang(keyang@yhgenomics.com)
* Date          : 2016/3/8
* Modifed       : When      | Who       | What
***********************************************************************************/

#include "Pipeline.h"
#include "WorkManager.h"
#include "ExitCodeHandlerSet.h"
#include <fstream>
#include <iostream>
#include <string>

using std::string;

NS_SERVANT_BEGIN

// Add one Pipe to pipeline
// @pipe    : one Pipe need to be added.
void Pipeline::AddPipe( uptr<Pipe> pipe )
{
    pipe_list_.push_back( std::move( pipe ) );
}

// Parse the pipeline informantion from a protobuf Message.
// @orignalMessage : message from the Maraton Master
void Pipeline::ParseFromMessage( uptr<MessageTaskDeliver> orignalMessage )
{
    pipe_list_.clear();
    // Refresh task info
    task_id_.clear();
    original_id_.clear();
    main_path_.clear();
    task_path_.clear();

    task_id_     = orignalMessage->id();
    original_id_ = orignalMessage->originalid();
    main_path_   = task_root_ + original_id_ + "/";
    task_path_   = task_root_ + original_id_ + "/" + task_id_ + "/";

    // Make the main task path and the subtask path
    system( ( mkdir_ + main_path_ ).c_str() );
    system( ( mkdir_ + task_path_ ).c_str() );

    // Append to subtask list
    std::ofstream subtaskFout( main_path_ + subtask_list_,std::ios::app);

    subtaskFout << task_id_ <<  std::endl;
    subtaskFout.close();

    // Make Input File
    std::ofstream fout( task_path_ + input_file_ );

    for ( auto file : orignalMessage->input() )
    {
        fout << file << std::endl;
    }

    fout.close();

    // Add others info to pipeline
    for ( auto item : orignalMessage->pipeline().pipes() )
    {
        auto pipe = make_uptr( Pipe );

        pipe->DockerDaemon( docker_daemon );

        pipe->DockerImage( item.executor() );

        pipe->AddPathBind( task_path_ , docker_work_ );
        pipe->AddPathBind( data_path_ , docker_data_ );

        pipe->SetPipeExit( NextPipe );

        for(auto param : item.parameters())
        {
            pipe->AddEnvironment( param );
        }

        AddPipe( std::move( pipe ) );
    } // end of for ( auto item : orignalMessage->pipeline().pipes() )
}

// Start the pipeline
void Pipeline::Run()
{
    RunNext( 0 );
}

// Run Next based on the exit Code from last pipe
// @lastExitCode : Exit code of the one pipe before current one.
// @note         : exit code is 0 before the first pipe run.
void Pipeline::RunNext( const int & lastExitCode )
{
    if ( lastExitCode != 0 )
        OnException( lastExitCode );

    if ( pipe_list_.size() == 0 )
        OnFinish();

    else
    {
        auto currentPipe = std::move( pipe_list_[ 0 ] );
        pipe_list_.erase( pipe_list_.begin() );
        currentPipe->Run();
    }
}

// Called when pipeline finish
void Pipeline::OnFinish()
{
    vector<string> outputs;
    GatherOutputInformation( outputs );
    Protocal::MessageHub::Instance()->SendTaskUpdate( TaskStatus::kFinished , outputs );
    Logger::Log( "Pipeline Finished " );

    WorkManager::Instance()->FinishWork();
}

// Called when exception happens
// @lastExitCode : Exit code of the one pipe before current one.
// @note         : any non-zero exit code is consider as exception
void Pipeline::OnException( const int & lastExitCode )
{
    Protocal::MessageHub::Instance()->SendTaskUpdate( TaskStatus::kError );

    Logger::Error("Exception happended code : %",lastExitCode);
}

// Constructor
Pipeline::Pipeline()
{
    Init();
}

// Initialization
void Pipeline::Init()
{
    mkdir_        = "mkdir ";
    task_root_    = "/data/mrttask/";
    data_path_    = "/data/ref/";
    task_id_      = "";
    original_id_  = "";
    task_path_    = "";
    input_file_   = "input.mrt";
    output_file_  = "output.mrt";
    subtask_list_ = "subtasklist.log";
    docker_work_  = "/work/";
    docker_data_  = "/data/";
    docker_daemon = "http://127.0.0.1:4243";
    main_log_     = "subtasklist.log";
    runtime_Log_  = "runtime.log";
    main_path_    = "";
}

// Check if a string contains valid content
// @oneLine : one line from the output file.
inline bool Pipeline::IsOutputLineValid( const string & oneLine )
{
    return (    oneLine != ""
             && oneLine != "\r"
             && oneLine != "\n"
             && oneLine != "\r\n"
             && oneLine != "\n\r" );
}

// Gathering all outputs informantion
// @outputs   : The contianer's outputs files informations.
bool Pipeline::GatherOutputInformation( vector<string>& outputs )
{
    bool result = false;
    std::ifstream fin;
    fin.open( task_path_ + output_file_ );

    if ( fin )
    {
        while ( !fin.eof() )
        {
            std::string oneLine;
            fin >> oneLine;

            if ( IsOutputLineValid( oneLine ) )
            {
                outputs.push_back( oneLine );
            }
        }

        fin.close();
        result = true;
    } //  end of  if ( fin )

    else
    {
        result = false;
    }

    return result;
}

NS_SERVANT_END
<|endoftext|>


<commit_before>/*
    Copyright 2014 Brain Research Institute, Melbourne, Australia

    Written by David Raffelt, 2014

    This file is part of MRtrix.

    MRtrix 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.

    MRtrix 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 MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "command.h"
#include "progressbar.h"
#include "image/buffer.h"
#include "image/buffer_sparse.h"
#include "image/loop.h"
#include "image/voxel.h"
#include "image/sparse/fixel_metric.h"
#include "image/sparse/voxel.h"

using namespace MR;
using namespace App;

using Image::Sparse::FixelMetric;

void usage ()
{
  AUTHOR = "David Raffelt (david.raffelt@florey.edu.au)";

  DESCRIPTION
  + "Divide two fixel images";

  ARGUMENTS
  + Argument ("input1", "the input fixel image.").type_image_in ()
  + Argument ("input2", "the input fixel image.").type_image_in ()
  + Argument ("output", "the output fixel image.").type_image_out ();
}

void run ()
{
  Image::Header input_header1 (argument[0]);
  Image::BufferSparse<FixelMetric> input_data1 (input_header1);
  auto input_vox1 = input_data1.voxel();

  Image::Header input_header2 (argument[1]);
  Image::BufferSparse<FixelMetric> input_data2 (input_header2);
  auto input_vox2 = input_data2.voxel();

  Image::check_dimensions(input_header1, input_header2);

  Image::BufferSparse<FixelMetric> output_data (argument[2], input_header1);
  auto output_vox = output_data.voxel();

  Image::LoopInOrder loop (input_data1, "multiplying fixel images...");
  for (auto i = loop (input_vox1, input_vox2, output_vox); i; ++i) {
    if (input_vox1.value().size() != input_vox2.value().size())
      throw Exception ("the fixel images do not have corresponding fixels in all voxels");
    output_vox.value().set_size (input_vox1.value().size());
    for (size_t fixel = 0; fixel != input_vox1.value().size(); ++fixel) {
      output_vox.value()[fixel] = input_vox1.value()[fixel];
      output_vox.value()[fixel].value = -input_vox1.value()[fixel].value / input_vox2.value()[fixel].value;
    }
  }
}

<commit_msg>fix fixeldivide negative output<commit_after>/*
    Copyright 2014 Brain Research Institute, Melbourne, Australia

    Written by David Raffelt, 2014

    This file is part of MRtrix.

    MRtrix 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.

    MRtrix 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 MRtrix.  If not, see <http://www.gnu.org/licenses/>.

*/

#include "command.h"
#include "progressbar.h"
#include "image/buffer.h"
#include "image/buffer_sparse.h"
#include "image/loop.h"
#include "image/voxel.h"
#include "image/sparse/fixel_metric.h"
#include "image/sparse/voxel.h"

using namespace MR;
using namespace App;

using Image::Sparse::FixelMetric;

void usage ()
{
  AUTHOR = "David Raffelt (david.raffelt@florey.edu.au)";

  DESCRIPTION
  + "Divide two fixel images";

  ARGUMENTS
  + Argument ("input1", "the input fixel image.").type_image_in ()
  + Argument ("input2", "the input fixel image.").type_image_in ()
  + Argument ("output", "the output fixel image.").type_image_out ();
}

void run ()
{
  Image::Header input_header1 (argument[0]);
  Image::BufferSparse<FixelMetric> input_data1 (input_header1);
  auto input_vox1 = input_data1.voxel();

  Image::Header input_header2 (argument[1]);
  Image::BufferSparse<FixelMetric> input_data2 (input_header2);
  auto input_vox2 = input_data2.voxel();

  Image::check_dimensions(input_header1, input_header2);

  Image::BufferSparse<FixelMetric> output_data (argument[2], input_header1);
  auto output_vox = output_data.voxel();

  Image::LoopInOrder loop (input_data1, "multiplying fixel images...");
  for (auto i = loop (input_vox1, input_vox2, output_vox); i; ++i) {
    if (input_vox1.value().size() != input_vox2.value().size())
      throw Exception ("the fixel images do not have corresponding fixels in all voxels");
    output_vox.value().set_size (input_vox1.value().size());
    for (size_t fixel = 0; fixel != input_vox1.value().size(); ++fixel) {
      output_vox.value()[fixel] = input_vox1.value()[fixel];
      output_vox.value()[fixel].value = input_vox1.value()[fixel].value / input_vox2.value()[fixel].value;
    }
  }
}

<|endoftext|>


<commit_before>#include "flatgltf/2.0/glTF_generated.h"
#include "flatgltf/2.0/glTFapi.hpp"

#include "glTFinternal.hpp"

#define KHUTILS_ASSERTION_INLINE

#include "khutils/assertion.hpp"
#include "khutils/runtime_exceptions.hpp"

namespace glTF_2_0
{
	//-------------------------------------------------------------------------

	BufferViewT* const createBufferView(Document* const doc, const char* name)
	{
		auto instance = BufferView_t{new BufferViewT};
		if (name)
		{
			instance->name = name;
		}
		doc->root->bufferViews.push_back(std::move(instance));
		return doc->root->bufferViews.back().get();
	}

	//---

	BufferViewT* const createBufferView(const uint8_t* const data, size_t length, Document* const doc, BufferT* const buf, const char* name)
	{
		KHUTILS_ASSERT_PTR(buf);

		auto view = createBufferView(doc);
		KHUTILS_ASSERT_PTR(view);

		view->buffer = getId(doc, buf);

		if (name)
		{
			view->name = name;
		}

		setBufferViewData(data, length, doc, view);

		return view;
	}

	//---

	BufferViewT* const createBufferView(const std::vector<uint8_t>& data, Document* const doc, BufferT* const buf, const char* name)
	{
		return createBufferView(data.data(), data.size(), doc, buf);
	}

	//---

	size_t setBufferViewData(const std::vector<uint8_t>& data, Document* const doc, BufferViewT* const view)
	{
		KHUTILS_ASSERT_CNTR_NOT_EMPTY(data);
		return setBufferViewData(data.data(), data.size(), doc, view);
	}

	//---

	size_t setBufferViewData(const uint8_t* const data, size_t length, Document* const doc, BufferViewT* const view)
	{
		KHUTILS_ASSERT_PTR(data);
		KHUTILS_ASSERT_PTR(doc);
		KHUTILS_ASSERT_PTR(view);
		KHUTILS_ASSERT_LESSEREQ(view->byteLength, 0);

		auto buf = getBuffer(doc, view->buffer);
		KHUTILS_ASSERT_PTR(buf);

		view->byteOffset = buf->byteLength;
		appendBufferData(data, length, doc, buf);

		view->byteLength = length;
		view->byteStride = 0;

		return view->byteLength;
	}

	//---

	std::vector<uint8_t> getBufferViewData(const Document* const doc, const BufferViewT* const view)
	{
		KHUTILS_ASSERT_PTR(doc);
		KHUTILS_ASSERT_PTR(view);

		auto buf = getBuffer(doc, view->buffer);
		KHUTILS_ASSERT_PTR(buf);

		auto bufdata = getBufferData(doc, buf);

		std::vector<uint8_t> viewdata;
		viewdata.reserve(view->byteLength);
		std::copy_n(bufdata.begin() + view->byteOffset, view->byteLength, std::back_inserter(viewdata));
		return viewdata;
	}

	//-------------------------------------------------------------------------
	//-------------------------------------------------------------------------

}	// namespace glTF_2_0
<commit_msg>removed duplicate code<commit_after>#include "flatgltf/2.0/glTF_generated.h"
#include "flatgltf/2.0/glTFapi.hpp"

#include "glTFinternal.hpp"

#define KHUTILS_ASSERTION_INLINE

#include "khutils/assertion.hpp"
#include "khutils/runtime_exceptions.hpp"

namespace glTF_2_0
{
	//-------------------------------------------------------------------------

	BufferViewT* const createBufferView(Document* const doc, const char* name)
	{
		auto instance = BufferView_t{new BufferViewT};
		if (name)
		{
			instance->name = name;
		}
		doc->root->bufferViews.push_back(std::move(instance));
		return doc->root->bufferViews.back().get();
	}

	//---

	BufferViewT* const createBufferView(const uint8_t* const data, size_t length, Document* const doc, BufferT* const buf, const char* name)
	{
		KHUTILS_ASSERT_PTR(buf);

		auto view = createBufferView(doc, name);
		KHUTILS_ASSERT_PTR(view);

		view->buffer = getId(doc, buf);

		setBufferViewData(data, length, doc, view);

		return view;
	}

	//---

	BufferViewT* const createBufferView(const std::vector<uint8_t>& data, Document* const doc, BufferT* const buf, const char* name)
	{
		return createBufferView(data.data(), data.size(), doc, buf);
	}

	//---

	size_t setBufferViewData(const std::vector<uint8_t>& data, Document* const doc, BufferViewT* const view)
	{
		KHUTILS_ASSERT_CNTR_NOT_EMPTY(data);
		return setBufferViewData(data.data(), data.size(), doc, view);
	}

	//---

	size_t setBufferViewData(const uint8_t* const data, size_t length, Document* const doc, BufferViewT* const view)
	{
		KHUTILS_ASSERT_PTR(data);
		KHUTILS_ASSERT_PTR(doc);
		KHUTILS_ASSERT_PTR(view);
		KHUTILS_ASSERT_LESSEREQ(view->byteLength, 0);

		auto buf = getBuffer(doc, view->buffer);
		KHUTILS_ASSERT_PTR(buf);

		view->byteOffset = buf->byteLength;
		appendBufferData(data, length, doc, buf);

		view->byteLength = length;
		view->byteStride = 0;

		return view->byteLength;
	}

	//---

	std::vector<uint8_t> getBufferViewData(const Document* const doc, const BufferViewT* const view)
	{
		KHUTILS_ASSERT_PTR(doc);
		KHUTILS_ASSERT_PTR(view);

		auto buf = getBuffer(doc, view->buffer);
		KHUTILS_ASSERT_PTR(buf);

		auto bufdata = getBufferData(doc, buf);

		std::vector<uint8_t> viewdata;
		viewdata.reserve(view->byteLength);
		std::copy_n(bufdata.begin() + view->byteOffset, view->byteLength, std::back_inserter(viewdata));
		return viewdata;
	}

	//-------------------------------------------------------------------------
	//-------------------------------------------------------------------------

}	// namespace glTF_2_0
<|endoftext|>


<commit_before>//===-- ClangIncludeFixer.cpp - Standalone include fixer ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "InMemoryXrefsDB.h"
#include "IncludeFixer.h"
#include "YamlXrefsDB.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"

using namespace clang;
using namespace llvm;

namespace {
cl::OptionCategory IncludeFixerCategory("Tool options");

enum DatabaseFormatTy {
  fixed, ///< Hard-coded mapping.
  yaml,  ///< Yaml database created by find-all-symbols.
};

cl::opt<DatabaseFormatTy> DatabaseFormat(
    "db", cl::desc("Specify input format"),
    cl::values(clEnumVal(fixed, "Hard-coded mapping"),
               clEnumVal(yaml, "Yaml database created by find-all-symbols"),
               clEnumValEnd),
    cl::init(fixed), cl::cat(IncludeFixerCategory));

cl::opt<std::string> Input("input",
                           cl::desc("String to initialize the database"),
                           cl::cat(IncludeFixerCategory));

cl::opt<bool>
    MinimizeIncludePaths("minimize-paths",
                         cl::desc("Whether to minimize added include paths"),
                         cl::init(true), cl::cat(IncludeFixerCategory));
} // namespace

int main(int argc, const char **argv) {
  tooling::CommonOptionsParser options(argc, argv, IncludeFixerCategory);
  tooling::ClangTool tool(options.getCompilations(),
                          options.getSourcePathList());

  // Set up the data source.
  std::unique_ptr<include_fixer::XrefsDB> XrefsDB;
  switch (DatabaseFormat) {
  case fixed: {
    // Parse input and fill the database with it.
    // <symbol>=<header><, header...>
    // Multiple symbols can be given, separated by semicolons.
    std::map<std::string, std::vector<std::string>> XrefsMap;
    SmallVector<StringRef, 4> SemicolonSplits;
    StringRef(Input).split(SemicolonSplits, ";");
    for (StringRef Pair : SemicolonSplits) {
      auto Split = Pair.split('=');
      std::vector<std::string> Headers;
      SmallVector<StringRef, 4> CommaSplits;
      Split.second.split(CommaSplits, ",");
      for (StringRef Header : CommaSplits)
        Headers.push_back(Header.trim());
      XrefsMap[Split.first.trim()] = std::move(Headers);
    }
    XrefsDB =
        llvm::make_unique<include_fixer::InMemoryXrefsDB>(std::move(XrefsMap));
    break;
  }
  case yaml: {
    XrefsDB = llvm::make_unique<include_fixer::YamlXrefsDB>(Input);
    break;
  }
  }

  // Now run our tool.
  std::vector<tooling::Replacement> Replacements;
  include_fixer::IncludeFixerActionFactory Factory(*XrefsDB, Replacements,
                                                   MinimizeIncludePaths);

  tool.run(&Factory); // Always succeeds.

  // Set up a new source manager for applying the resulting replacements.
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
  DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
  TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
  SourceManager SM(Diagnostics, tool.getFiles());
  Diagnostics.setClient(&DiagnosticPrinter, false);

  // Write replacements to disk.
  Rewriter Rewrites(SM, LangOptions());
  tooling::applyAllReplacements(Replacements, Rewrites);
  return Rewrites.overwriteChangedFiles();
}
<commit_msg>[include-fixer] Abstract includeFixerMain function.<commit_after>//===-- ClangIncludeFixer.cpp - Standalone include fixer ------------------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "InMemoryXrefsDB.h"
#include "IncludeFixer.h"
#include "YamlXrefsDB.h"
#include "clang/Frontend/TextDiagnosticPrinter.h"
#include "clang/Rewrite/Core/Rewriter.h"
#include "clang/Tooling/CommonOptionsParser.h"
#include "clang/Tooling/Tooling.h"
#include "llvm/Support/CommandLine.h"

using namespace clang;
using namespace llvm;

namespace {
cl::OptionCategory IncludeFixerCategory("Tool options");

enum DatabaseFormatTy {
  fixed, ///< Hard-coded mapping.
  yaml,  ///< Yaml database created by find-all-symbols.
};

cl::opt<DatabaseFormatTy> DatabaseFormat(
    "db", cl::desc("Specify input format"),
    cl::values(clEnumVal(fixed, "Hard-coded mapping"),
               clEnumVal(yaml, "Yaml database created by find-all-symbols"),
               clEnumValEnd),
    cl::init(fixed), cl::cat(IncludeFixerCategory));

cl::opt<std::string> Input("input",
                           cl::desc("String to initialize the database"),
                           cl::cat(IncludeFixerCategory));

cl::opt<bool>
    MinimizeIncludePaths("minimize-paths",
                         cl::desc("Whether to minimize added include paths"),
                         cl::init(true), cl::cat(IncludeFixerCategory));

int includeFixerMain(int argc, const char **argv) {
  tooling::CommonOptionsParser options(argc, argv, IncludeFixerCategory);
  tooling::ClangTool tool(options.getCompilations(),
                          options.getSourcePathList());

  // Set up the data source.
  std::unique_ptr<include_fixer::XrefsDB> XrefsDB;
  switch (DatabaseFormat) {
  case fixed: {
    // Parse input and fill the database with it.
    // <symbol>=<header><, header...>
    // Multiple symbols can be given, separated by semicolons.
    std::map<std::string, std::vector<std::string>> XrefsMap;
    SmallVector<StringRef, 4> SemicolonSplits;
    StringRef(Input).split(SemicolonSplits, ";");
    for (StringRef Pair : SemicolonSplits) {
      auto Split = Pair.split('=');
      std::vector<std::string> Headers;
      SmallVector<StringRef, 4> CommaSplits;
      Split.second.split(CommaSplits, ",");
      for (StringRef Header : CommaSplits)
        Headers.push_back(Header.trim());
      XrefsMap[Split.first.trim()] = std::move(Headers);
    }
    XrefsDB =
        llvm::make_unique<include_fixer::InMemoryXrefsDB>(std::move(XrefsMap));
    break;
  }
  case yaml: {
    XrefsDB = llvm::make_unique<include_fixer::YamlXrefsDB>(Input);
    break;
  }
  }

  // Now run our tool.
  std::vector<tooling::Replacement> Replacements;
  include_fixer::IncludeFixerActionFactory Factory(*XrefsDB, Replacements,
                                                   MinimizeIncludePaths);

  tool.run(&Factory); // Always succeeds.

  // Set up a new source manager for applying the resulting replacements.
  IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts(new DiagnosticOptions);
  DiagnosticsEngine Diagnostics(new DiagnosticIDs, &*DiagOpts);
  TextDiagnosticPrinter DiagnosticPrinter(outs(), &*DiagOpts);
  SourceManager SM(Diagnostics, tool.getFiles());
  Diagnostics.setClient(&DiagnosticPrinter, false);

  // Write replacements to disk.
  Rewriter Rewrites(SM, LangOptions());
  tooling::applyAllReplacements(Replacements, Rewrites);
  return Rewrites.overwriteChangedFiles();
}

} // namespace

int main(int argc, const char **argv) {
  return includeFixerMain(argc, argv);
}
<|endoftext|>