<commit_before>#ifndef __elxResamplerBase_hxx
#define __elxResamplerBase_hxx

#include "elxResamplerBase.h"

#include "elxTimer.h"

namespace elastix
{
	using namespace itk;

	/*
	 * ********************* Constructor ****************************
	 */

	template <class TElastix>
		ResamplerBase<TElastix>::ResamplerBase()
	{

	} // end Constructor

	/*
	 * ******************* BeforeRegistrationBase *******************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::BeforeRegistrationBase(void)
	{
		/** Connect the components. */
		this->SetComponents();

		/** Set the size of the image to be produced by the resampler. */

		/** Get a pointer to the fixedImage. */
		OutputImageType * fixedImage = dynamic_cast<OutputImageType *>(
			this->m_Elastix->GetFixedImage() );

		/** Set the region info to the same values as in the fixedImage. */
		this->GetAsITKBaseType()->SetSize( fixedImage->GetLargestPossibleRegion().GetSize() );
		this->GetAsITKBaseType()->SetOutputStartIndex( fixedImage->GetLargestPossibleRegion().GetIndex() );
		this->GetAsITKBaseType()->SetOutputOrigin( fixedImage->GetOrigin() );
		this->GetAsITKBaseType()->SetOutputSpacing( fixedImage->GetSpacing() );

		/** Set the DefaultPixelValue (for pixels in the resampled image
		 * that come from outside the original (moving) image.
		 */
		OutputPixelType defaultPixelValue = NumericTraits<OutputPixelType>::Zero;
		this->m_Configuration->ReadParameter( defaultPixelValue, "DefaultPixelValue", 0 );

		/** Set the defaultPixelValue. */
		this->GetAsITKBaseType()->SetDefaultPixelValue( defaultPixelValue );

	} // end BeforeRegistrationBase

	/*
	 * ******************* AfterEachResolutionBase ********************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::AfterEachResolutionBase(void)
	{
		/** Set the final transform parameters. */
		this->GetElastix()->GetElxTransformBase()->SetFinalParameters();

		/** What is the current resolution level? */
		unsigned int level = this->m_Registration->GetAsITKBaseType()->GetCurrentLevel();

		/** Decide whether or not to write the result image this resolution. */
		std::string writeResultImageThisResolution = "false";
		this->m_Configuration->ReadParameter(
			writeResultImageThisResolution, "WriteResultImageAfterEachResolution", level, true );

		/** Create a name for the final result. */
		std::string resultImageFormat = "mhd";
		this->m_Configuration->ReadParameter(	resultImageFormat, "ResultImageFormat", 0, true );
		std::ostringstream makeFileName( "" );
		makeFileName << this->m_Configuration->GetCommandLineArgument( "-out" )
			<< "result." << this->m_Configuration->GetElastixLevel()
			<< ".R" << level
			<< "." << resultImageFormat;

		/** Writing result image. */
		if ( writeResultImageThisResolution == "true" )
		{
			/** Time the resampling. */
			typedef tmr::Timer TimerType;
			TimerType::Pointer timer = TimerType::New();
			timer->StartTimer();
			/** Apply the final transform, and save the result. */
			elxout << "Applying transform this resolution";
			/** Call WriteResultImage. */
			try
			{
				this->WriteResultImage( makeFileName.str().c_str() );
			}
			catch( itk::ExceptionObject & excp )
			{
				xl::xout["error"] << "Exception caught: " << std::endl;
				xl::xout["error"] << excp
					<< "Resuming elastix." << std::endl;
			}
			/** Print the elapsed time for the resampling. */
			timer->StopTimer();
			elxout << ", which took: "
				<< static_cast<long>( timer->GetElapsedClockSec() )
				<< " s." << std::endl;
		} // end if

	} // end AfterEachResolutionBase

	/*
	 * ******************* AfterRegistrationBase ********************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::AfterRegistrationBase(void)
	{
		/** Set the final transform parameters. */
		this->GetElastix()->GetElxTransformBase()->SetFinalParameters();

		/** Decide whether or not to write the result image. */
		std::string writeResultImage = "true";
		this->m_Configuration->ReadParameter(	writeResultImage, "WriteResultImage", 0, true );

		/** Create a name for the final result. */
		std::string resultImageFormat = "mhd";
		this->m_Configuration->ReadParameter(	resultImageFormat, "ResultImageFormat", 0, true );
		std::ostringstream makeFileName( "" );
		makeFileName << this->m_Configuration->GetCommandLineArgument( "-out" )
			<< "result." << this->m_Configuration->GetElastixLevel()
			<< "." << resultImageFormat;

		/** Writing result image. */
		if ( writeResultImage == "true" )
		{
			/** Time the resampling. */
			typedef tmr::Timer TimerType;
			TimerType::Pointer timer = TimerType::New();
			timer->StartTimer();
			/** Apply the final transform, and save the result. */
			elxout << std::endl << "Applying final transform";
			/** Call WriteResultImage. */
			try
			{
				this->WriteResultImage( makeFileName.str().c_str() );
			}
			catch( itk::ExceptionObject & excp )
			{
				xl::xout["error"] << "Exception caught: " << std::endl;
				xl::xout["error"] << excp
					<< "Resuming elastix." << std::endl;
			}
			/** Print the elapsed time for the resampling. */
			timer->StopTimer();
			elxout << ", which took: "
				<< static_cast<long>( timer->GetElapsedClockSec() )
				<< " s." << std::endl;
		}
		else
		{
			/** Do not apply the final transform. */
			elxout << std::endl
				<< "Skipping applying final transform, no resulting output image generated."
				<< std::endl;
		} // end if

	} // end AfterRegistrationBase

	/*
	 * *********************** SetComponents ************************
	 */

	template <class TElastix>
		void ResamplerBase<TElastix>
		::SetComponents(void)
	{
		/** Set the transform, the interpolator and the inputImage
		 * (which is the moving image).
		 */
		this->GetAsITKBaseType()->SetTransform( dynamic_cast<TransformType *>(
			this->m_Elastix->GetTransform() ) );

		this->GetAsITKBaseType()->SetInterpolator( dynamic_cast<InterpolatorType *>(
			this->m_Elastix->GetResampleInterpolator() ) );

		this->GetAsITKBaseType()->SetInput( dynamic_cast<InputImageType *>(
			this->m_Elastix->GetMovingImage() ) );

	} // end SetComponents

	/*
	 * ******************* WriteResultImage ********************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::WriteResultImage( const char * filename )
	{
		/** Make sure the resampler is updated. */
		this->GetAsITKBaseType()->Modified();

		/** Create writer. */
		WriterPointer writer = WriterType::New();

		/** Setup the pipeline. */
		writer->SetInput( this->GetAsITKBaseType()->GetOutput() );

		/** Set the filename. */
		writer->SetFileName( filename );

		/** Do the writing. */
		try
		{
			writer->Update();
		}
		catch( itk::ExceptionObject & excp )
		{
			/** Add information to the exception. */
			excp.SetLocation( "ResamplerBase - AfterRegistrationBase()" );
			std::string err_str = excp.GetDescription();
			err_str += "\nError occured while writing resampled image.\n";
			excp.SetDescription( err_str );
			/** Pass the exception to an higher level. */
			throw excp;
		}

	} // WriteResultImage

	/*
	 * ************************* ReadFromFile ***********************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::ReadFromFile(void)
	{
		/** Connect the components. */
		this->SetComponents();

		/** Get spacing, origin and size of the image to be produced by the resampler. */
		SpacingType			spacing;
		IndexType				index;
		OriginPointType	origin;
		SizeType				size;
		for ( unsigned int i = 0; i < ImageDimension; i++ )
		{
			/** No default size. Read size from the parameter file. */
			this->m_Configuration->ReadParameter(	size[ i ], "Size", i );

			/** Default index. Read index from the parameter file. */
			index[ i ] = 0;
			this->m_Configuration->ReadParameter(	index[ i ], "Index", i );

			/** Default spacing. Read spacing from the parameter file. */
			spacing[ i ] = 1.0;
			this->m_Configuration->ReadParameter(	spacing[ i ], "Spacing", i );

			/** Default origin. Read origin from the parameter file. */
			origin[ i ] = 0.0;
			this->m_Configuration->ReadParameter(	origin[ i ], "Origin", i );
		}

		/** Check for image size. */
		unsigned int sum = 0;
		for ( unsigned int i = 0; i < ImageDimension; i++ )
		{
			if ( size[ i ] == 0 ) sum++;
		}
		if ( sum > 0 )
		{
			xl::xout["error"] << "ERROR: One or more image sizes are 0!" << std::endl;
			/** \todo quit program nicely. */
		}

		/** Set the region info to the same values as in the fixedImage. */
		this->GetAsITKBaseType()->SetSize( size );
		this->GetAsITKBaseType()->SetOutputStartIndex( index );
		this->GetAsITKBaseType()->SetOutputOrigin( origin );
		this->GetAsITKBaseType()->SetOutputSpacing( spacing );

		/** Set the DefaultPixelValue (for pixels in the resampled image
		 * that come from outside the original (moving) image.
		 */
		int defaultPixelValue = 0;
		this->m_Configuration->ReadParameter( defaultPixelValue, "DefaultPixelValue", 0 );

		/** Set the defaultPixelValue in the Superclass. */
		this->GetAsITKBaseType()->SetDefaultPixelValue( defaultPixelValue );

	} // end ReadFromFile

	/**
	 * ******************* WriteToFile ******************************
	 */

	template <class TElastix>
		void ResamplerBase<TElastix>
		::WriteToFile(void)
	{
		/** Write Resampler specific things. */
		xl::xout["transpar"] << std::endl << "// Resampler specific" << std::endl;

		/** Write the name of the Resampler. */
		xl::xout["transpar"] << "(Resampler \""
			<< this->elxGetClassName() << "\")" << std::endl;

		/** Write the DefaultPixelValue. */
		xl::xout["transpar"] << "(DefaultPixelValue "
			<< this->GetAsITKBaseType()->GetDefaultPixelValue() << ")" << std::endl;

		/** Write the output image format. */
		std::string resultImageFormat = "mhd";
		this->m_Configuration->ReadParameter(	resultImageFormat, "ResultImageFormat", 0, true );
		xl::xout["transpar"] << "(ResultImageFormat \""
			<< resultImageFormat << "\")" << std::endl;

	} // end WriteToFile

} // end namespace elastix

#endif // end #ifndef __elxResamplerBase_hxx

<commit_msg>SK:<commit_after>#ifndef __elxResamplerBase_hxx
#define __elxResamplerBase_hxx

#include "elxResamplerBase.h"

#include "elxTimer.h"

namespace elastix
{
	using namespace itk;

	/*
	 * ********************* Constructor ****************************
	 */

	template <class TElastix>
		ResamplerBase<TElastix>::ResamplerBase()
	{

	} // end Constructor

	/*
	 * ******************* BeforeRegistrationBase *******************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::BeforeRegistrationBase(void)
	{
		/** Connect the components. */
		this->SetComponents();

		/** Set the size of the image to be produced by the resampler. */

		/** Get a pointer to the fixedImage. */
		OutputImageType * fixedImage = dynamic_cast<OutputImageType *>(
			this->m_Elastix->GetFixedImage() );

		/** Set the region info to the same values as in the fixedImage. */
		this->GetAsITKBaseType()->SetSize( fixedImage->GetLargestPossibleRegion().GetSize() );
		this->GetAsITKBaseType()->SetOutputStartIndex( fixedImage->GetLargestPossibleRegion().GetIndex() );
		this->GetAsITKBaseType()->SetOutputOrigin( fixedImage->GetOrigin() );
		this->GetAsITKBaseType()->SetOutputSpacing( fixedImage->GetSpacing() );

		/** Set the DefaultPixelValue (for pixels in the resampled image
		 * that come from outside the original (moving) image.
		 */
		OutputPixelType defaultPixelValue = NumericTraits<OutputPixelType>::Zero;
		this->m_Configuration->ReadParameter( defaultPixelValue, "DefaultPixelValue", 0 );

		/** Set the defaultPixelValue. */
		this->GetAsITKBaseType()->SetDefaultPixelValue( defaultPixelValue );

	} // end BeforeRegistrationBase

	/*
	 * ******************* AfterEachResolutionBase ********************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::AfterEachResolutionBase(void)
	{
		/** Set the final transform parameters. */
		this->GetElastix()->GetElxTransformBase()->SetFinalParameters();

		/** What is the current resolution level? */
		unsigned int level = this->m_Registration->GetAsITKBaseType()->GetCurrentLevel();

		/** Decide whether or not to write the result image this resolution. */
		std::string writeResultImageThisResolution = "false";
		this->m_Configuration->ReadParameter(
			writeResultImageThisResolution, "WriteResultImageAfterEachResolution", 0, true );
		this->m_Configuration->ReadParameter(
			writeResultImageThisResolution, "WriteResultImageAfterEachResolution", level, true );

		/** Create a name for the final result. */
		std::string resultImageFormat = "mhd";
		this->m_Configuration->ReadParameter(	resultImageFormat, "ResultImageFormat", 0, true );
		std::ostringstream makeFileName( "" );
		makeFileName << this->m_Configuration->GetCommandLineArgument( "-out" )
			<< "result." << this->m_Configuration->GetElastixLevel()
			<< ".R" << level
			<< "." << resultImageFormat;

		/** Writing result image. */
		if ( writeResultImageThisResolution == "true" )
		{
			/** Time the resampling. */
			typedef tmr::Timer TimerType;
			TimerType::Pointer timer = TimerType::New();
			timer->StartTimer();
			/** Apply the final transform, and save the result. */
			elxout << "Applying transform this resolution";
			/** Call WriteResultImage. */
			try
			{
				this->WriteResultImage( makeFileName.str().c_str() );
			}
			catch( itk::ExceptionObject & excp )
			{
				xl::xout["error"] << "Exception caught: " << std::endl;
				xl::xout["error"] << excp
					<< "Resuming elastix." << std::endl;
			}
			/** Print the elapsed time for the resampling. */
			timer->StopTimer();
			elxout << ", which took: "
				<< static_cast<long>( timer->GetElapsedClockSec() )
				<< " s." << std::endl;
		} // end if

	} // end AfterEachResolutionBase

	/*
	 * ******************* AfterRegistrationBase ********************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::AfterRegistrationBase(void)
	{
		/** Set the final transform parameters. */
		this->GetElastix()->GetElxTransformBase()->SetFinalParameters();

		/** Decide whether or not to write the result image. */
		std::string writeResultImage = "true";
		this->m_Configuration->ReadParameter(	writeResultImage, "WriteResultImage", 0, true );

		/** Create a name for the final result. */
		std::string resultImageFormat = "mhd";
		this->m_Configuration->ReadParameter(	resultImageFormat, "ResultImageFormat", 0, true );
		std::ostringstream makeFileName( "" );
		makeFileName << this->m_Configuration->GetCommandLineArgument( "-out" )
			<< "result." << this->m_Configuration->GetElastixLevel()
			<< "." << resultImageFormat;

		/** Writing result image. */
		if ( writeResultImage == "true" )
		{
			/** Time the resampling. */
			typedef tmr::Timer TimerType;
			TimerType::Pointer timer = TimerType::New();
			timer->StartTimer();
			/** Apply the final transform, and save the result. */
			elxout << std::endl << "Applying final transform";
			/** Call WriteResultImage. */
			try
			{
				this->WriteResultImage( makeFileName.str().c_str() );
			}
			catch( itk::ExceptionObject & excp )
			{
				xl::xout["error"] << "Exception caught: " << std::endl;
				xl::xout["error"] << excp
					<< "Resuming elastix." << std::endl;
			}
			/** Print the elapsed time for the resampling. */
			timer->StopTimer();
			elxout << ", which took: "
				<< static_cast<long>( timer->GetElapsedClockSec() )
				<< " s." << std::endl;
		}
		else
		{
			/** Do not apply the final transform. */
			elxout << std::endl
				<< "Skipping applying final transform, no resulting output image generated."
				<< std::endl;
		} // end if

	} // end AfterRegistrationBase

	/*
	 * *********************** SetComponents ************************
	 */

	template <class TElastix>
		void ResamplerBase<TElastix>
		::SetComponents(void)
	{
		/** Set the transform, the interpolator and the inputImage
		 * (which is the moving image).
		 */
		this->GetAsITKBaseType()->SetTransform( dynamic_cast<TransformType *>(
			this->m_Elastix->GetTransform() ) );

		this->GetAsITKBaseType()->SetInterpolator( dynamic_cast<InterpolatorType *>(
			this->m_Elastix->GetResampleInterpolator() ) );

		this->GetAsITKBaseType()->SetInput( dynamic_cast<InputImageType *>(
			this->m_Elastix->GetMovingImage() ) );

	} // end SetComponents

	/*
	 * ******************* WriteResultImage ********************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::WriteResultImage( const char * filename )
	{
		/** Make sure the resampler is updated. */
		this->GetAsITKBaseType()->Modified();

		/** Create writer. */
		WriterPointer writer = WriterType::New();

		/** Setup the pipeline. */
		writer->SetInput( this->GetAsITKBaseType()->GetOutput() );

		/** Set the filename. */
		writer->SetFileName( filename );

		/** Do the writing. */
		try
		{
			writer->Update();
		}
		catch( itk::ExceptionObject & excp )
		{
			/** Add information to the exception. */
			excp.SetLocation( "ResamplerBase - AfterRegistrationBase()" );
			std::string err_str = excp.GetDescription();
			err_str += "\nError occured while writing resampled image.\n";
			excp.SetDescription( err_str );
			/** Pass the exception to an higher level. */
			throw excp;
		}

	} // WriteResultImage

	/*
	 * ************************* ReadFromFile ***********************
	 */

	template<class TElastix>
		void ResamplerBase<TElastix>
		::ReadFromFile(void)
	{
		/** Connect the components. */
		this->SetComponents();

		/** Get spacing, origin and size of the image to be produced by the resampler. */
		SpacingType			spacing;
		IndexType				index;
		OriginPointType	origin;
		SizeType				size;
		for ( unsigned int i = 0; i < ImageDimension; i++ )
		{
			/** No default size. Read size from the parameter file. */
			this->m_Configuration->ReadParameter(	size[ i ], "Size", i );

			/** Default index. Read index from the parameter file. */
			index[ i ] = 0;
			this->m_Configuration->ReadParameter(	index[ i ], "Index", i );

			/** Default spacing. Read spacing from the parameter file. */
			spacing[ i ] = 1.0;
			this->m_Configuration->ReadParameter(	spacing[ i ], "Spacing", i );

			/** Default origin. Read origin from the parameter file. */
			origin[ i ] = 0.0;
			this->m_Configuration->ReadParameter(	origin[ i ], "Origin", i );
		}

		/** Check for image size. */
		unsigned int sum = 0;
		for ( unsigned int i = 0; i < ImageDimension; i++ )
		{
			if ( size[ i ] == 0 ) sum++;
		}
		if ( sum > 0 )
		{
			xl::xout["error"] << "ERROR: One or more image sizes are 0!" << std::endl;
			/** \todo quit program nicely. */
		}

		/** Set the region info to the same values as in the fixedImage. */
		this->GetAsITKBaseType()->SetSize( size );
		this->GetAsITKBaseType()->SetOutputStartIndex( index );
		this->GetAsITKBaseType()->SetOutputOrigin( origin );
		this->GetAsITKBaseType()->SetOutputSpacing( spacing );

		/** Set the DefaultPixelValue (for pixels in the resampled image
		 * that come from outside the original (moving) image.
		 */
		int defaultPixelValue = 0;
		this->m_Configuration->ReadParameter( defaultPixelValue, "DefaultPixelValue", 0 );

		/** Set the defaultPixelValue in the Superclass. */
		this->GetAsITKBaseType()->SetDefaultPixelValue( defaultPixelValue );

	} // end ReadFromFile

	/**
	 * ******************* WriteToFile ******************************
	 */

	template <class TElastix>
		void ResamplerBase<TElastix>
		::WriteToFile(void)
	{
		/** Write Resampler specific things. */
		xl::xout["transpar"] << std::endl << "// Resampler specific" << std::endl;

		/** Write the name of the Resampler. */
		xl::xout["transpar"] << "(Resampler \""
			<< this->elxGetClassName() << "\")" << std::endl;

		/** Write the DefaultPixelValue. */
		xl::xout["transpar"] << "(DefaultPixelValue "
			<< this->GetAsITKBaseType()->GetDefaultPixelValue() << ")" << std::endl;

		/** Write the output image format. */
		std::string resultImageFormat = "mhd";
		this->m_Configuration->ReadParameter(	resultImageFormat, "ResultImageFormat", 0, true );
		xl::xout["transpar"] << "(ResultImageFormat \""
			<< resultImageFormat << "\")" << std::endl;

	} // end WriteToFile

} // end namespace elastix

#endif // end #ifndef __elxResamplerBase_hxx

<|endoftext|>


<commit_before>//
// Copyright 2013 Jeff Bush
//
// 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 "assert.h"
#include "Barrier.h"
#include "Debug.h"
#include "Matrix.h"
#include "ParameterInterpolator.h"
#include "PixelShader.h"
#include "Rasterizer.h"
#include "RenderTarget.h"
#include "TextureSampler.h"
#include "utils.h"
#include "VertexShader.h"

class TextureVertexShader : public VertexShader
{
public:
	TextureVertexShader()
		:	VertexShader(5, 6)
	{
		const float kAspectRatio = 640.0f / 480.0f;
		const float kProjCoeff[] = {
			1.0f / kAspectRatio, 0.0f, 0.0f, 0.0f,
			0.0f, kAspectRatio, 0.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
		};

		fProjectionMatrix = Matrix(kProjCoeff);
		fMVPMatrix = fProjectionMatrix;
	}

	void applyTransform(const Matrix &mat)
	{
		fModelViewMatrix = fModelViewMatrix * mat;
		fMVPMatrix = fProjectionMatrix * fModelViewMatrix;
	}

	void shadeVertices(vecf16 outParams[kMaxVertexAttribs],
		const vecf16 inAttribs[kMaxVertexAttribs], int mask)
	{
		// Multiply by mvp matrix
		vecf16 coord[4];
		for (int i = 0; i < 3; i++)
			coord[i] = inAttribs[i];

		coord[3] = splatf(1.0f);
		fMVPMatrix.mulVec(outParams, coord);

		// Copy remaining parameters
		outParams[4] = inAttribs[3];
		outParams[5] = inAttribs[4];
	}

private:
	Matrix fMVPMatrix;
	Matrix fProjectionMatrix;
	Matrix fModelViewMatrix;
};

class TexturePixelShader : public PixelShader
{
public:
	TexturePixelShader(ParameterInterpolator *interp, RenderTarget *target)
		:	PixelShader(interp, target)
	{}

	void bindTexture(Surface *surface)
	{
		fSampler.bind(surface);
		fSampler.setEnableBilinearFiltering(true);
	}

	virtual void shadePixels(const vecf16 inParams[16], vecf16 outColor[4],
		unsigned short mask)
	{
		fSampler.readPixels(inParams[0], inParams[1], mask, outColor);
	}

private:
	TextureSampler fSampler;
};

const int kMaxTileIndex = (640 / 64) * ((480 / 64) + 1);
int nextTileIndex = 0;
extern char *kImage;
const int kFbWidth = 640;
const int kFbHeight = 480;
Barrier<4> gGeometryBarrier;
Barrier<4> gPixelBarrier;
const int gNumVertices = 36;
float gVertexParams[512];

const float kCube[] = {
	// Front face
	0.5, 0.5, -0.5, 1.0, 0.0,
	-0.5, 0.5, -0.5, 1.0, 1.0,
	-0.5, -0.5, -0.5, 0.0, 1.0,

	-0.5, -0.5, -0.5, 0.0, 1.0,
	0.5, -0.5, -0.5, 0.0, 0.0,
	0.5, 0.5, -0.5, 1.0, 0.0,

	// Right side
	0.5, -0.5, -0.5, 1.0, 0.0,
	0.5, -0.5, 0.5, 1.0, 1.0,
	0.5, 0.5, 0.5, 0.0, 1.0,

	0.5, 0.5, 0.5, 0.0, 1.0,
	0.5, 0.5, -0.5, 0.0, 0.0,
	0.5, -0.5, -0.5, 1.0, 0.0,

	// Left side
	-0.5, -0.5, -0.5, 0.0, 0.0,
	-0.5, 0.5, -0.5, 1.0, 0.0,
	-0.5, 0.5, 0.5, 1.0, 1.0,

	-0.5, 0.5, 0.5, 0.0, 0.0,
	-0.5, -0.5, 0.5, 1.0, 0.0,
	-0.5, -0.5, -0.5, 1.0, 1.0,

	// Back
	0.5, -0.5, 0.5, 0.0, 0.0,
	-0.5, -0.5, 0.5, 1.0, 0.0,
	-0.5, 0.5, 0.5, 1.0, 1.0,

	-0.5, 0.5, 0.5, 0.0, 0.0,
	0.5, 0.5, 0.5, 1.0, 0.0,
	0.5, -0.5, 0.5, 1.0, 1.0,

	// Top
	-0.5, -0.5, -0.5, 0.0, 0.0,
	-0.5, -0.5, 0.5, 1.0, 0.0,
	0.5, -0.5, 0.5, 1.0, 1.0,

	0.5, -0.5, 0.5, 0.0, 0.0,
	0.5, -0.5, -0.5, 1.0, 0.0,
	-0.5, -0.5, -0.5, 1.0, 1.0,

	// Bottom
	0.5, 0.5, -0.5, 0.0, 0.0,
	0.5, 0.5, 0.5, 1.0, 0.0,
	-0.5, 0.5, 0.5, 1.0, 1.0,

	-0.5, 0.5, 0.5, 0.0, 0.0,
	-0.5, 0.5, -0.5, 1.0, 0.0,
	0.5, 0.5, -0.5, 1.0, 1.0
};

Matrix translate(float x, float y, float z)
{
	float kValues[] = {
		1.0f, 0.0f, 0.0f, x,
		0.0f, 1.0f, 0.0f, y,
		0.0f, 0.0f, 1.0f, z,
		0.0f, 0.0f, 0.0f, 1.0f,
	};

	return Matrix(kValues);
}

Matrix rotateX()
{
	float sin = 0.19509032201f;	// sin(pi / 16)
	float cos = 0.9807852804f;	// cos(pi / 16)

	float kMat1[] = {
		1, 0, 0, 0,
		0, cos, sin, 0,
		0, -sin, cos, 0,
		0, 0, 0, 1
	};

	return Matrix(kMat1);
}

Matrix rotateY()
{
	float sin = 0.19509032201f;	// sin(pi / 16)
	float cos = 0.9807852804f;	// cos(pi / 16)

	float kMat1[] = {
		cos, 0, sin, 0,
		0, 1, 0, 0,
		-sin, 0, cos, 0,
		0, 0, 0, 1
	};

	return Matrix(kMat1);
}

Matrix rotateZ()
{
	float sin = 0.19509032201f;	// sin(pi / 16)
	float cos = 0.9807852804f;	// cos(pi / 16)

	float kMat1[] = {
		cos, -sin, 0, 0,
		sin, cos, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1
	};

	return Matrix(kMat1);
}

//
// All threads start execution here
//
int main()
{
	Rasterizer rasterizer;
	RenderTarget renderTarget;
	Surface colorBuffer(0x100000, kFbWidth, kFbHeight);
	Surface zBuffer(0x240000, kFbWidth, kFbHeight);
	renderTarget.setColorBuffer(&colorBuffer);
	renderTarget.setZBuffer(&zBuffer);
	ParameterInterpolator interp(kFbWidth, kFbHeight);
	Surface texture((unsigned int) kImage, 128, 128);
	TexturePixelShader pixelShader(&interp, &renderTarget);
	pixelShader.bindTexture(&texture);
	TextureVertexShader vertexShader;

	vertexShader.applyTransform(translate(0.0f, 0.0f, 1.5f));
	vertexShader.applyTransform(rotateX());
	Matrix rotateStepMatrix = rotateY();
	vertexShader.applyTransform(rotateZ());

//	pixelShader.enableZBuffer(true);
//	pixelShader.enableBlend(true);

	int numVertexParams = vertexShader.getNumParams();

	for (int frame = 0; frame < 1; frame++)
	{
		//
		// Geometry phase
		//
		if (__builtin_vp_get_current_strand() == 0)
		{
			vertexShader.applyTransform(rotateStepMatrix);
			vertexShader.processVertexBuffer(gVertexParams, kCube, gNumVertices);
		}

		gGeometryBarrier.wait();

		//
		// Pixel phase
		//
		nextTileIndex = 0;
		while (nextTileIndex < kMaxTileIndex)
		{
			// Grab the next available tile to begin working on.
			int myTileIndex = __sync_fetch_and_add(&nextTileIndex, 1);
			if (myTileIndex >= kMaxTileIndex)
				break;

			unsigned int tileXI, tileYI;
			udiv(myTileIndex, 10, tileYI, tileXI);
			int tileX = tileXI * 64;
			int tileY = tileYI * 64;

			renderTarget.getColorBuffer()->clearTile(tileX, tileY, 0);
			if (pixelShader.isZBufferEnabled())
				renderTarget.getZBuffer()->clearTile(tileX, tileY, 0x7f800000);	// Infinity

			// Cycle through all triangles and attempt to render into this
			// 64x64 tile.
			float *params = gVertexParams;
			for (int vidx = 0; vidx < gNumVertices; vidx += 3)
			{
				// XXX could do some trivial rejections here for triangles that
				// obviously aren't in this tile.
				float x0 = params[kParamX];
				float y0 = params[kParamY];
				float z0 = params[kParamZ];
				float x1 = params[numVertexParams + kParamX];
				float y1 = params[numVertexParams + kParamY];
				float z1 = params[numVertexParams + kParamZ];
				float x2 = params[numVertexParams * 2 + kParamX];
				float y2 = params[numVertexParams * 2 + kParamY];
				float z2 = params[numVertexParams * 2 + kParamZ];

				interp.setUpTriangle(x0, y0, z0, x1, y1, z1, x2, y2, z2);
				for (int paramI = 0; paramI < numVertexParams; paramI++)
				{
					interp.setUpParam(paramI,
						params[paramI + 4],
						params[numVertexParams + paramI + 4],
						params[numVertexParams * 2 + paramI + 4]);
				}

				rasterizer.rasterizeTriangle(&pixelShader, tileX, tileY,
					(int)(x0 * kFbWidth / 2 + kFbWidth / 2),
					(int)(y0 * kFbHeight / 2 + kFbHeight / 2),
					(int)(x1 * kFbWidth / 2 + kFbWidth / 2),
					(int)(y1 * kFbHeight / 2 + kFbHeight / 2),
					(int)(x2 * kFbWidth / 2 + kFbWidth / 2),
					(int)(y2 * kFbHeight / 2 + kFbHeight / 2));

				params += numVertexParams * 3;
			}

			renderTarget.getColorBuffer()->flushTile(tileX, tileY);
		}

		gPixelBarrier.wait();
	}

	return 0;
}

Debug Debug::debug;
<commit_msg>Reset tile index in a thread safe way.<commit_after>//
// Copyright 2013 Jeff Bush
//
// 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 "assert.h"
#include "Barrier.h"
#include "Debug.h"
#include "Matrix.h"
#include "ParameterInterpolator.h"
#include "PixelShader.h"
#include "Rasterizer.h"
#include "RenderTarget.h"
#include "TextureSampler.h"
#include "utils.h"
#include "VertexShader.h"

class TextureVertexShader : public VertexShader
{
public:
	TextureVertexShader()
		:	VertexShader(5, 6)
	{
		const float kAspectRatio = 640.0f / 480.0f;
		const float kProjCoeff[] = {
			1.0f / kAspectRatio, 0.0f, 0.0f, 0.0f,
			0.0f, kAspectRatio, 0.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
			0.0f, 0.0f, 1.0f, 0.0f,
		};

		fProjectionMatrix = Matrix(kProjCoeff);
		fMVPMatrix = fProjectionMatrix;
	}

	void applyTransform(const Matrix &mat)
	{
		fModelViewMatrix = fModelViewMatrix * mat;
		fMVPMatrix = fProjectionMatrix * fModelViewMatrix;
	}

	void shadeVertices(vecf16 outParams[kMaxVertexAttribs],
		const vecf16 inAttribs[kMaxVertexAttribs], int mask)
	{
		// Multiply by mvp matrix
		vecf16 coord[4];
		for (int i = 0; i < 3; i++)
			coord[i] = inAttribs[i];

		coord[3] = splatf(1.0f);
		fMVPMatrix.mulVec(outParams, coord);

		// Copy remaining parameters
		outParams[4] = inAttribs[3];
		outParams[5] = inAttribs[4];
	}

private:
	Matrix fMVPMatrix;
	Matrix fProjectionMatrix;
	Matrix fModelViewMatrix;
};

class TexturePixelShader : public PixelShader
{
public:
	TexturePixelShader(ParameterInterpolator *interp, RenderTarget *target)
		:	PixelShader(interp, target)
	{}

	void bindTexture(Surface *surface)
	{
		fSampler.bind(surface);
		fSampler.setEnableBilinearFiltering(true);
	}

	virtual void shadePixels(const vecf16 inParams[16], vecf16 outColor[4],
		unsigned short mask)
	{
		fSampler.readPixels(inParams[0], inParams[1], mask, outColor);
	}

private:
	TextureSampler fSampler;
};

const int kMaxTileIndex = (640 / 64) * ((480 / 64) + 1);
int nextTileIndex = 0;
extern char *kImage;
const int kFbWidth = 640;
const int kFbHeight = 480;
Barrier<4> gGeometryBarrier;
Barrier<4> gPixelBarrier;
const int gNumVertices = 36;
float gVertexParams[512];

const float kCube[] = {
	// Front face
	0.5, 0.5, -0.5, 1.0, 0.0,
	-0.5, 0.5, -0.5, 1.0, 1.0,
	-0.5, -0.5, -0.5, 0.0, 1.0,

	-0.5, -0.5, -0.5, 0.0, 1.0,
	0.5, -0.5, -0.5, 0.0, 0.0,
	0.5, 0.5, -0.5, 1.0, 0.0,

	// Right side
	0.5, -0.5, -0.5, 1.0, 0.0,
	0.5, -0.5, 0.5, 1.0, 1.0,
	0.5, 0.5, 0.5, 0.0, 1.0,

	0.5, 0.5, 0.5, 0.0, 1.0,
	0.5, 0.5, -0.5, 0.0, 0.0,
	0.5, -0.5, -0.5, 1.0, 0.0,

	// Left side
	-0.5, -0.5, -0.5, 0.0, 0.0,
	-0.5, 0.5, -0.5, 1.0, 0.0,
	-0.5, 0.5, 0.5, 1.0, 1.0,

	-0.5, 0.5, 0.5, 0.0, 0.0,
	-0.5, -0.5, 0.5, 1.0, 0.0,
	-0.5, -0.5, -0.5, 1.0, 1.0,

	// Back
	0.5, -0.5, 0.5, 0.0, 0.0,
	-0.5, -0.5, 0.5, 1.0, 0.0,
	-0.5, 0.5, 0.5, 1.0, 1.0,

	-0.5, 0.5, 0.5, 0.0, 0.0,
	0.5, 0.5, 0.5, 1.0, 0.0,
	0.5, -0.5, 0.5, 1.0, 1.0,

	// Top
	-0.5, -0.5, -0.5, 0.0, 0.0,
	-0.5, -0.5, 0.5, 1.0, 0.0,
	0.5, -0.5, 0.5, 1.0, 1.0,

	0.5, -0.5, 0.5, 0.0, 0.0,
	0.5, -0.5, -0.5, 1.0, 0.0,
	-0.5, -0.5, -0.5, 1.0, 1.0,

	// Bottom
	0.5, 0.5, -0.5, 0.0, 0.0,
	0.5, 0.5, 0.5, 1.0, 0.0,
	-0.5, 0.5, 0.5, 1.0, 1.0,

	-0.5, 0.5, 0.5, 0.0, 0.0,
	-0.5, 0.5, -0.5, 1.0, 0.0,
	0.5, 0.5, -0.5, 1.0, 1.0
};

Matrix translate(float x, float y, float z)
{
	float kValues[] = {
		1.0f, 0.0f, 0.0f, x,
		0.0f, 1.0f, 0.0f, y,
		0.0f, 0.0f, 1.0f, z,
		0.0f, 0.0f, 0.0f, 1.0f,
	};

	return Matrix(kValues);
}

Matrix rotateX()
{
	float sin = 0.19509032201f;	// sin(pi / 16)
	float cos = 0.9807852804f;	// cos(pi / 16)

	float kMat1[] = {
		1, 0, 0, 0,
		0, cos, sin, 0,
		0, -sin, cos, 0,
		0, 0, 0, 1
	};

	return Matrix(kMat1);
}

Matrix rotateY()
{
	float sin = 0.19509032201f;	// sin(pi / 16)
	float cos = 0.9807852804f;	// cos(pi / 16)

	float kMat1[] = {
		cos, 0, sin, 0,
		0, 1, 0, 0,
		-sin, 0, cos, 0,
		0, 0, 0, 1
	};

	return Matrix(kMat1);
}

Matrix rotateZ()
{
	float sin = 0.19509032201f;	// sin(pi / 16)
	float cos = 0.9807852804f;	// cos(pi / 16)

	float kMat1[] = {
		cos, -sin, 0, 0,
		sin, cos, 0, 0,
		0, 0, 1, 0,
		0, 0, 0, 1
	};

	return Matrix(kMat1);
}

//
// All threads start execution here
//
int main()
{
	Rasterizer rasterizer;
	RenderTarget renderTarget;
	Surface colorBuffer(0x100000, kFbWidth, kFbHeight);
	Surface zBuffer(0x240000, kFbWidth, kFbHeight);
	renderTarget.setColorBuffer(&colorBuffer);
	renderTarget.setZBuffer(&zBuffer);
	ParameterInterpolator interp(kFbWidth, kFbHeight);
	Surface texture((unsigned int) kImage, 128, 128);
	TexturePixelShader pixelShader(&interp, &renderTarget);
	pixelShader.bindTexture(&texture);
	TextureVertexShader vertexShader;

	vertexShader.applyTransform(translate(0.0f, 0.0f, 1.5f));
	vertexShader.applyTransform(rotateX());
	Matrix rotateStepMatrix = rotateY();
	vertexShader.applyTransform(rotateZ());

//	pixelShader.enableZBuffer(true);
//	pixelShader.enableBlend(true);

	int numVertexParams = vertexShader.getNumParams();

	for (int frame = 0; frame < 1; frame++)
	{
		//
		// Geometry phase
		//
		if (__builtin_vp_get_current_strand() == 0)
		{
			vertexShader.applyTransform(rotateStepMatrix);
			vertexShader.processVertexBuffer(gVertexParams, kCube, gNumVertices);
			nextTileIndex = 0;
		}

		gGeometryBarrier.wait();

		//
		// Pixel phase
		//
		while (nextTileIndex < kMaxTileIndex)
		{
			// Grab the next available tile to begin working on.
			int myTileIndex = __sync_fetch_and_add(&nextTileIndex, 1);
			if (myTileIndex >= kMaxTileIndex)
				break;

			unsigned int tileXI, tileYI;
			udiv(myTileIndex, 10, tileYI, tileXI);
			int tileX = tileXI * 64;
			int tileY = tileYI * 64;

			renderTarget.getColorBuffer()->clearTile(tileX, tileY, 0);
			if (pixelShader.isZBufferEnabled())
				renderTarget.getZBuffer()->clearTile(tileX, tileY, 0x7f800000);	// Infinity

			// Cycle through all triangles and attempt to render into this
			// 64x64 tile.
			float *params = gVertexParams;
			for (int vidx = 0; vidx < gNumVertices; vidx += 3)
			{
				// XXX could do some trivial rejections here for triangles that
				// obviously aren't in this tile.
				float x0 = params[kParamX];
				float y0 = params[kParamY];
				float z0 = params[kParamZ];
				float x1 = params[numVertexParams + kParamX];
				float y1 = params[numVertexParams + kParamY];
				float z1 = params[numVertexParams + kParamZ];
				float x2 = params[numVertexParams * 2 + kParamX];
				float y2 = params[numVertexParams * 2 + kParamY];
				float z2 = params[numVertexParams * 2 + kParamZ];

				interp.setUpTriangle(x0, y0, z0, x1, y1, z1, x2, y2, z2);
				for (int paramI = 0; paramI < numVertexParams; paramI++)
				{
					interp.setUpParam(paramI,
						params[paramI + 4],
						params[numVertexParams + paramI + 4],
						params[numVertexParams * 2 + paramI + 4]);
				}

				rasterizer.rasterizeTriangle(&pixelShader, tileX, tileY,
					(int)(x0 * kFbWidth / 2 + kFbWidth / 2),
					(int)(y0 * kFbHeight / 2 + kFbHeight / 2),
					(int)(x1 * kFbWidth / 2 + kFbWidth / 2),
					(int)(y1 * kFbHeight / 2 + kFbHeight / 2),
					(int)(x2 * kFbWidth / 2 + kFbWidth / 2),
					(int)(y2 * kFbHeight / 2 + kFbHeight / 2));

				params += numVertexParams * 3;
			}

			renderTarget.getColorBuffer()->flushTile(tileX, tileY);
		}

		gPixelBarrier.wait();
	}

	return 0;
}

Debug Debug::debug;
<|endoftext|>


<commit_before>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2015 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Dataflow/Engine/Scheduler/ExecutionStrategy.h>

using namespace SCIRun::Dataflow::Engine;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Core::Thread;

ExecutionBounds ExecutionContext::executionBounds_;

boost::signals2::connection ExecutionContext::connectNetworkExecutionStarts(const ExecuteAllStartsSignalType::slot_type& subscriber)
{
  return executionBounds_.executeStarts_.connect(subscriber);
}
boost::signals2::connection ExecutionContext::connectNetworkExecutionFinished(const ExecuteAllFinishesSignalType::slot_type& subscriber)
{
  return executionBounds_.executeFinishes_.connect(subscriber);
}

ModuleFilter ExecutionContext::addAdditionalFilter(ModuleFilter filter) const
{
  if (!filter)
    return additionalFilter;
  if (!additionalFilter)
    return filter;

  return boost::bind(filter, _1) && boost::bind(additionalFilter, _1);
}

ExecutionQueueManager::ExecutionQueueManager() :
  contexts_(10),
  executionMutex_("executionQueue"),
  somethingToExecute_("executionQueue"),
  contextCount_(0)
{
}

void ExecutionQueueManager::setExecutionStrategy(ExecutionStrategyHandle exec)
{
  Guard g(executionMutex_.get());
  currentExecutor_ = exec;
}

void ExecutionQueueManager::initExecutor(ExecutionStrategyFactoryHandle factory)
{
  if (!currentExecutor_ && factory)
    currentExecutor_ = factory->createDefault();
}

void ExecutionQueueManager::start()
{
  executionLaunchThread_.reset(new boost::thread([this]() { executeTopContext(); }));
}

boost::shared_ptr<boost::thread> ExecutionQueueManager::enqueueContext(ExecutionContextHandle context)
{
  bool contextReady;
  {
    Guard g(executionMutex_.get());
    contextReady = contexts_.push(context);
    if (contextReady)
      contextCount_.fetch_add(1);
  }
  if (contextReady)
  {
    if (!executionLaunchThread_)
      start();
    somethingToExecute_.conditionBroadcast();
  }
  return executionLaunchThread_;
}

void ExecutionQueueManager::executeTopContext()
{
  while (true)
  {
    UniqueLock lock(executionMutex_.get());
    while (0 == contextCount_)
    {
      somethingToExecute_.wait(lock);
    }
    if (contexts_.consume_one([&](ExecutionContextHandle ctx) { executeImpl(ctx); }))
    {
      contextCount_.fetch_sub(1);
    }
  }
}

void ExecutionQueueManager::executeImpl(ExecutionContextHandle ctx)
{
  if (currentExecutor_ && ctx)
  {
    ctx->preexecute();
    currentExecutor_->execute(*ctx, executionMutex_);
  }
}

void ExecutionQueueManager::stop()
{
  executionLaunchThread_->interrupt();
  executionLaunchThread_.reset();
}<commit_msg>Don't dereference thread pointer if it doesn't exist<commit_after>/*
   For more information, please see: http://software.sci.utah.edu

   The MIT License

   Copyright (c) 2015 Scientific Computing and Imaging Institute,
   University of Utah.

   License for the specific language governing rights and limitations under
   Permission is hereby granted, free of charge, to any person obtaining a
   copy of this software and associated documentation files (the "Software"),
   to deal in the Software without restriction, including without limitation
   the rights to use, copy, modify, merge, publish, distribute, sublicense,
   and/or sell copies of the Software, and to permit persons to whom the
   Software is furnished to do so, subject to the following conditions:

   The above copyright notice and this permission notice shall be included
   in all copies or substantial portions of the Software.

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
   OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
   THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
   DEALINGS IN THE SOFTWARE.
*/

#include <Dataflow/Engine/Scheduler/ExecutionStrategy.h>

using namespace SCIRun::Dataflow::Engine;
using namespace SCIRun::Dataflow::Networks;
using namespace SCIRun::Core::Thread;

ExecutionBounds ExecutionContext::executionBounds_;

boost::signals2::connection ExecutionContext::connectNetworkExecutionStarts(const ExecuteAllStartsSignalType::slot_type& subscriber)
{
  return executionBounds_.executeStarts_.connect(subscriber);
}
boost::signals2::connection ExecutionContext::connectNetworkExecutionFinished(const ExecuteAllFinishesSignalType::slot_type& subscriber)
{
  return executionBounds_.executeFinishes_.connect(subscriber);
}

ModuleFilter ExecutionContext::addAdditionalFilter(ModuleFilter filter) const
{
  if (!filter)
    return additionalFilter;
  if (!additionalFilter)
    return filter;

  return boost::bind(filter, _1) && boost::bind(additionalFilter, _1);
}

ExecutionQueueManager::ExecutionQueueManager() :
  contexts_(10),
  executionMutex_("executionQueue"),
  somethingToExecute_("executionQueue"),
  contextCount_(0)
{
}

void ExecutionQueueManager::setExecutionStrategy(ExecutionStrategyHandle exec)
{
  Guard g(executionMutex_.get());
  currentExecutor_ = exec;
}

void ExecutionQueueManager::initExecutor(ExecutionStrategyFactoryHandle factory)
{
  if (!currentExecutor_ && factory)
    currentExecutor_ = factory->createDefault();
}

void ExecutionQueueManager::start()
{
  executionLaunchThread_.reset(new boost::thread([this]() { executeTopContext(); }));
}

boost::shared_ptr<boost::thread> ExecutionQueueManager::enqueueContext(ExecutionContextHandle context)
{
  bool contextReady;
  {
    Guard g(executionMutex_.get());
    contextReady = contexts_.push(context);
    if (contextReady)
      contextCount_.fetch_add(1);
  }
  if (contextReady)
  {
    if (!executionLaunchThread_)
      start();
    somethingToExecute_.conditionBroadcast();
  }
  return executionLaunchThread_;
}

void ExecutionQueueManager::executeTopContext()
{
  while (true)
  {
    UniqueLock lock(executionMutex_.get());
    while (0 == contextCount_)
    {
      somethingToExecute_.wait(lock);
    }
    if (contexts_.consume_one([&](ExecutionContextHandle ctx) { executeImpl(ctx); }))
    {
      contextCount_.fetch_sub(1);
    }
  }
}

void ExecutionQueueManager::executeImpl(ExecutionContextHandle ctx)
{
  if (currentExecutor_ && ctx)
  {
    ctx->preexecute();
    currentExecutor_->execute(*ctx, executionMutex_);
  }
}

void ExecutionQueueManager::stop()
{
  if (executionLaunchThread_)
  {
    executionLaunchThread_->interrupt();
    executionLaunchThread_.reset();
  }
}
<|endoftext|>


<commit_before>#include <errno.h>
#include <node_buffer.h>

#include "serverInterface.h"
#include "btio.h"
#include "util.h"

using namespace v8;
using namespace node;

// Constructor definition
Persistent<Function>
ServerInterface::constructor;

ServerInterface::ServerInterface()
: server(new Server())
{
}

ServerInterface::~ServerInterface()
{
  delete server;
}

void
ServerInterface::Init(Handle<Object> exports)
{
  Local<FunctionTemplate> t = FunctionTemplate::New(ServerInterface::New);
  t->InstanceTemplate()->SetInternalFieldCount(2);
  t->SetClassName(String::New("ServerInterface"));
  NODE_SET_PROTOTYPE_METHOD(t, "listen", ServerInterface::Listen);
  NODE_SET_PROTOTYPE_METHOD(t, "write", ServerInterface::Write);

  exports->Set(String::NewSymbol("Server"), t->GetFunction());
}

Handle<Value>
ServerInterface::New(const Arguments& args)
{
  HandleScope scope;

  assert(args.IsConstructCall());

  ServerInterface* server = new ServerInterface();
  server->self = Persistent<Object>::New(args.This());
  server->Wrap(args.This());

  return scope.Close(args.This());
}

Handle<Value>
ServerInterface::Listen(const Arguments& args)
{
  HandleScope scope;

  if (args.Length() < 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!args[0]->IsObject()) {
    ThrowException(Exception::TypeError(String::New("First argument must be either listen options or a callback")));
    return scope.Close(Undefined());
  }

  Local<Object> options;
  ServerInterface* serverInterface = ObjectWrap::Unwrap<ServerInterface>(args.This());

  if (args[0]->IsFunction()) {
    serverInterface->connectionCallback = Persistent<Function>::New(Local<Function>::Cast(args[0]));
    options = Object::New();
  } else {
    if (args.Length() < 2) {
      ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
      return scope.Close(Undefined());
    }
    if (!args[1]->IsFunction()) {
      ThrowException(Exception::TypeError(String::New("Second argument must be a callback")));
      return scope.Close(Undefined());
    }
    options = args[0]->ToObject();
    serverInterface->connectionCallback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
  }

  struct set_opts opts;
  if (!setOpts(opts, options)) {
    return scope.Close(Undefined());
  }

  serverInterface->server->listen(opts, onConnect, (void*)serverInterface);

  return scope.Close(Undefined());
}

void
ServerInterface::onConnect(void* data, int status, int events)
{
  ServerInterface* serverInterface = static_cast<ServerInterface*>(data);
  if (status == 0) {
    serverInterface->server->setReadCallback(onRead, (void*) serverInterface);
    serverInterface->server->setErrorCallback(onError, (void*) serverInterface);
    serverInterface->server->setCloseCallback(onClose, (void*) serverInterface);
    // Call the provided callback
    const int argc = 1;
    Local<Value> argv[argc] = { Local<Value>::New(Null()), Local<Value>::New(serverInterface->self) };
    serverInterface->connectionCallback->Call(serverInterface->self, argc, argv);
  } else {
    // Call the provided callback with the error
    uv_err_t err = uv_last_error(uv_default_loop());
    const int argc = 2;
    Local<Value> error = ErrnoException(errno, "connect", uv_strerror(err));
    Local<Value> argv[argc] = { error, Local<Value>::New(serverInterface->self) };
    serverInterface->connectionCallback->Call(serverInterface->self, argc, argv);
  }
}

void
ServerInterface::onRead(void* data, uint8_t* buf, int len, const char* error)
{
  // Emit 'data' event with Buffer containing data
  ServerInterface* serverInterface = static_cast<ServerInterface*>(data);
  Buffer* buffer = Buffer::New(len);
  memcpy(Buffer::Data(buffer), buf, len);
  const int argc = 2;
  Local<Value> argv[argc] = { String::New("data"), Local<Value>::New(buffer->handle_) };
  MakeCallback(serverInterface->self, "emit", argc, argv);
}

void
ServerInterface::onClose(void* data)
{
  ServerInterface* serverInterface = static_cast<ServerInterface*>(data);
  const int argc = 1;
  Local<Value> argv[argc] = { String::New("close") };
  MakeCallback(serverInterface->self, "emit", argc, argv);
}

void
ServerInterface::onError(void* data, const char* error)
{
  ServerInterface* serverInterface = static_cast<ServerInterface*>(data);
  const int argc = 2;
  Local<Value> argv[argc] = { String::New("error"), String::New(error) };
  MakeCallback(serverInterface->self, "emit", argc, argv);
}

struct WriteData {
  WriteData() : serverInterface(NULL) {}
  ServerInterface* serverInterface;
  Persistent<Function> callback;
};

Handle<Value>
ServerInterface::Write(const Arguments& args)
{
  HandleScope scope;

  if (args.Length() < 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!Buffer::HasInstance(args[0])) {
    ThrowException(Exception::TypeError(String::New("First argument must be a Buffer")));
    return scope.Close(Undefined());
  }

  ServerInterface* serverInterface = ObjectWrap::Unwrap<ServerInterface>(args.This());

  struct WriteData* wd = new struct WriteData();
  wd->serverInterface = serverInterface;

  if (args.Length() > 1) {
    if (!args[1]->IsFunction()) {
      ThrowException(Exception::TypeError(String::New("Second argument must be a callback")));
      return scope.Close(Undefined());
    }
    wd->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
  }

  serverInterface->server->write((char*) Buffer::Data(args[0]), Buffer::Length(args[0]),
      onWrite, (void*) wd);

  return scope.Close(Undefined());
}

void
ServerInterface::onWrite(void* data, const char* error)
{
  struct WriteData* wd = static_cast<struct WriteData*>(data);
  if (error) {
    if (wd->callback.IsEmpty()) {
      // Emit an 'error' event
      const int argc = 2;
      Local<Value> argv[argc] = { String::New("error"), String::New(error) };
      MakeCallback(wd->serverInterface->self, "emit", argc, argv);
    } else {
      const int argc = 1;
      Local<Value> argv[argc] = { String::New(error) };
      wd->callback->Call(wd->serverInterface->self, argc, argv);
    }
  } else {
    if (!wd->callback.IsEmpty()) {
      const int argc = 1;
      Local<Value> argv[argc] = { Local<Value>::New(Null()) };
      wd->callback->Call(wd->serverInterface->self, argc, argv);
    }
  }
}
<commit_msg>Fixed compile problem<commit_after>#include <errno.h>
#include <node_buffer.h>

#include "serverInterface.h"
#include "btio.h"
#include "util.h"

using namespace v8;
using namespace node;

// Constructor definition
Persistent<Function>
ServerInterface::constructor;

ServerInterface::ServerInterface()
: server(new Server())
{
}

ServerInterface::~ServerInterface()
{
  delete server;
}

void
ServerInterface::Init(Handle<Object> exports)
{
  Local<FunctionTemplate> t = FunctionTemplate::New(ServerInterface::New);
  t->InstanceTemplate()->SetInternalFieldCount(2);
  t->SetClassName(String::New("ServerInterface"));
  NODE_SET_PROTOTYPE_METHOD(t, "listen", ServerInterface::Listen);
  NODE_SET_PROTOTYPE_METHOD(t, "write", ServerInterface::Write);

  exports->Set(String::NewSymbol("Server"), t->GetFunction());
}

Handle<Value>
ServerInterface::New(const Arguments& args)
{
  HandleScope scope;

  assert(args.IsConstructCall());

  ServerInterface* server = new ServerInterface();
  server->self = Persistent<Object>::New(args.This());
  server->Wrap(args.This());

  return scope.Close(args.This());
}

Handle<Value>
ServerInterface::Listen(const Arguments& args)
{
  HandleScope scope;

  if (args.Length() < 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!args[0]->IsObject()) {
    ThrowException(Exception::TypeError(String::New("First argument must be either listen options or a callback")));
    return scope.Close(Undefined());
  }

  Local<Object> options;
  ServerInterface* serverInterface = ObjectWrap::Unwrap<ServerInterface>(args.This());

  if (args[0]->IsFunction()) {
    serverInterface->connectionCallback = Persistent<Function>::New(Local<Function>::Cast(args[0]));
    options = Object::New();
  } else {
    if (args.Length() < 2) {
      ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
      return scope.Close(Undefined());
    }
    if (!args[1]->IsFunction()) {
      ThrowException(Exception::TypeError(String::New("Second argument must be a callback")));
      return scope.Close(Undefined());
    }
    options = args[0]->ToObject();
    serverInterface->connectionCallback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
  }

  struct set_opts opts;
  if (!setOpts(opts, options)) {
    return scope.Close(Undefined());
  }

  serverInterface->server->listen(opts, onConnect, (void*)serverInterface);

  return scope.Close(Undefined());
}

void
ServerInterface::onConnect(void* data, int status, int events)
{
  ServerInterface* serverInterface = static_cast<ServerInterface*>(data);
  if (status == 0) {
    serverInterface->server->setReadCallback(onRead, (void*) serverInterface);
    serverInterface->server->setErrorCallback(onError, (void*) serverInterface);
    serverInterface->server->setCloseCallback(onClose, (void*) serverInterface);
    // Call the provided callback
    const int argc = 2;
    Local<Value> argv[argc] = { Local<Value>::New(Null()), Local<Value>::New(serverInterface->self) };
    serverInterface->connectionCallback->Call(serverInterface->self, argc, argv);
  } else {
    // Call the provided callback with the error
    uv_err_t err = uv_last_error(uv_default_loop());
    const int argc = 2;
    Local<Value> error = ErrnoException(errno, "connect", uv_strerror(err));
    Local<Value> argv[argc] = { error, Local<Value>::New(serverInterface->self) };
    serverInterface->connectionCallback->Call(serverInterface->self, argc, argv);
  }
}

void
ServerInterface::onRead(void* data, uint8_t* buf, int len, const char* error)
{
  // Emit 'data' event with Buffer containing data
  ServerInterface* serverInterface = static_cast<ServerInterface*>(data);
  Buffer* buffer = Buffer::New(len);
  memcpy(Buffer::Data(buffer), buf, len);
  const int argc = 2;
  Local<Value> argv[argc] = { String::New("data"), Local<Value>::New(buffer->handle_) };
  MakeCallback(serverInterface->self, "emit", argc, argv);
}

void
ServerInterface::onClose(void* data)
{
  ServerInterface* serverInterface = static_cast<ServerInterface*>(data);
  const int argc = 1;
  Local<Value> argv[argc] = { String::New("close") };
  MakeCallback(serverInterface->self, "emit", argc, argv);
}

void
ServerInterface::onError(void* data, const char* error)
{
  ServerInterface* serverInterface = static_cast<ServerInterface*>(data);
  const int argc = 2;
  Local<Value> argv[argc] = { String::New("error"), String::New(error) };
  MakeCallback(serverInterface->self, "emit", argc, argv);
}

struct WriteData {
  WriteData() : serverInterface(NULL) {}
  ServerInterface* serverInterface;
  Persistent<Function> callback;
};

Handle<Value>
ServerInterface::Write(const Arguments& args)
{
  HandleScope scope;

  if (args.Length() < 1) {
    ThrowException(Exception::TypeError(String::New("Wrong number of arguments")));
    return scope.Close(Undefined());
  }

  if (!Buffer::HasInstance(args[0])) {
    ThrowException(Exception::TypeError(String::New("First argument must be a Buffer")));
    return scope.Close(Undefined());
  }

  ServerInterface* serverInterface = ObjectWrap::Unwrap<ServerInterface>(args.This());

  struct WriteData* wd = new struct WriteData();
  wd->serverInterface = serverInterface;

  if (args.Length() > 1) {
    if (!args[1]->IsFunction()) {
      ThrowException(Exception::TypeError(String::New("Second argument must be a callback")));
      return scope.Close(Undefined());
    }
    wd->callback = Persistent<Function>::New(Local<Function>::Cast(args[1]));
  }

  serverInterface->server->write((char*) Buffer::Data(args[0]), Buffer::Length(args[0]),
      onWrite, (void*) wd);

  return scope.Close(Undefined());
}

void
ServerInterface::onWrite(void* data, const char* error)
{
  struct WriteData* wd = static_cast<struct WriteData*>(data);
  if (error) {
    if (wd->callback.IsEmpty()) {
      // Emit an 'error' event
      const int argc = 2;
      Local<Value> argv[argc] = { String::New("error"), String::New(error) };
      MakeCallback(wd->serverInterface->self, "emit", argc, argv);
    } else {
      const int argc = 1;
      Local<Value> argv[argc] = { String::New(error) };
      wd->callback->Call(wd->serverInterface->self, argc, argv);
    }
  } else {
    if (!wd->callback.IsEmpty()) {
      const int argc = 1;
      Local<Value> argv[argc] = { Local<Value>::New(Null()) };
      wd->callback->Call(wd->serverInterface->self, argc, argv);
    }
  }
}
<|endoftext|>


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

#include <memory>
#include <sstream>
#include <string>

#include <grpc/support/log.h>

#include "src/core/lib/support/env.h"
#include "test/core/util/port.h"
#include "test/cpp/util/subprocess.h"

using grpc::SubProcess;

template <class T>
std::string as_string(const T& val) {
  std::ostringstream out;
  out << val;
  return out.str();
}

int main(int argc, char** argv) {
  typedef std::unique_ptr<SubProcess> SubProcessPtr;
  std::vector<SubProcessPtr> jobs;

  std::string my_bin = argv[0];
  std::string bin_dir = my_bin.substr(0, my_bin.rfind('/'));

  std::ostringstream env;
  bool first = true;

  for (int i = 0; i < 2; i++) {
    auto port = grpc_pick_unused_port_or_die();
    std::vector<std::string> args = {bin_dir + "/qps_worker", "-driver_port",
                                     as_string(port)};
    jobs.emplace_back(new SubProcess(args));
    if (!first) env << ",";
    env << "localhost:" << port;
    first = false;
  }

  gpr_setenv("QPS_WORKERS", env.str().c_str());
  std::vector<std::string> args = {bin_dir + "/qps_json_driver"};
  for (int i = 1; i < argc; i++) {
    args.push_back(argv[i]);
  }
  GPR_ASSERT(SubProcess(args).Join() == 0);

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

#include <memory>
#include <sstream>
#include <string>

#include <grpc/support/log.h>

#include "src/core/lib/support/env.h"
#include "test/core/util/port.h"
#include "test/cpp/util/subprocess.h"

using grpc::SubProcess;

template <class T>
std::string as_string(const T& val) {
  std::ostringstream out;
  out << val;
  return out.str();
}

static void LogStatus(int status) {
  if (WIFEXITED(status)) {
    gpr_log(GPR_INFO, "subprocess exited with status %d",
            WEXITSTATUS(status));
  } else if (WIFSIGNALED(status)) {
    gpr_log(GPR_INFO, "subprocess terminated with signal %d",
            WTERMSIG(status));
  } else {
    gpr_log(GPR_INFO, "unknown subprocess status: %d", status);
  }
}

int main(int argc, char** argv) {
  typedef std::unique_ptr<SubProcess> SubProcessPtr;
  std::vector<SubProcessPtr> jobs;

  std::string my_bin = argv[0];
  std::string bin_dir = my_bin.substr(0, my_bin.rfind('/'));

  std::ostringstream env;
  bool first = true;

  for (int i = 0; i < 2; i++) {
    auto port = grpc_pick_unused_port_or_die();
    std::vector<std::string> args = {bin_dir + "/qps_worker", "-driver_port",
                                     as_string(port)};
    jobs.emplace_back(new SubProcess(args));
    if (!first) env << ",";
    env << "localhost:" << port;
    first = false;
  }

  gpr_setenv("QPS_WORKERS", env.str().c_str());
  std::vector<std::string> args = {bin_dir + "/qps_json_driver"};
  for (int i = 1; i < argc; i++) {
    args.push_back(argv[i]);
  }
gpr_log(GPR_INFO, "calling Join() on driver");
  int status = SubProcess(args).Join();
  if (status != 0) {
    LogStatus(status);
    GPR_ASSERT(status == 0);
  }

  for (auto it = jobs.begin(); it != jobs.end(); ++it) {
    (*it)->Interrupt();
  }
  for (auto it = jobs.begin(); it != jobs.end(); ++it) {
gpr_log(GPR_INFO, "calling Join() on job");
    status = (*it)->Join();
    if (status != 0) {
      LogStatus(status);
    }
  }
}
<|endoftext|>


<commit_before>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011, 2012                                                   *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa 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 3 of the License                  *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa 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 libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
#define CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP

#include "cppa/anything.hpp"

#include "cppa/util/rm_ref.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/is_iterable.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_forward_iterator.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp"

#include "cppa/detail/map_member.hpp"
#include "cppa/detail/list_member.hpp"
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/detail/primitive_member.hpp"

namespace cppa { namespace detail {

template<typename T>
class is_stl_compliant_list {

    template<class C>
    static bool cmp_help_fun (
        // mutable pointer
        C* mc,
        // check if there's a 'void push_back()' that takes C::value_type
        decltype(mc->push_back(typename C::value_type()))* = nullptr
    ) {
        return true;
    }

    // SFNINAE default
    static void cmp_help_fun(void*) { }

    typedef decltype(cmp_help_fun(static_cast<T*>(nullptr))) result_type;

 public:

    static constexpr bool value =    util::is_iterable<T>::value
                              && std::is_same<bool, result_type>::value;

};

template<typename T>
class is_stl_compliant_map {

    template<class C>
    static bool cmp_help_fun (
        // mutable pointer
        C* mc,
        // check if there's an 'insert()' that takes C::value_type
        decltype(mc->insert(typename C::value_type()))* = nullptr
    ) {
        return true;
    }

    static void cmp_help_fun(void*) { }

    typedef decltype(cmp_help_fun(static_cast<T*>(nullptr))) result_type;

 public:

    static constexpr bool value =    util::is_iterable<T>::value
                              && std::is_same<bool, result_type>::value;

};

template<typename T>
class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T> {

    template<typename X>
    struct is_invalid {
        static constexpr bool value =    !util::is_primitive<X>::value
                                  && !is_stl_compliant_map<X>::value
                                  && !is_stl_compliant_list<X>::value;
    };

    class member {

        uniform_type_info* m_meta;

        std::function<void (const uniform_type_info*,
                            const void*,
                            serializer*              )> m_serialize;

        std::function<void (const uniform_type_info*,
                            void*,
                            deserializer*            )> m_deserialize;

        member(const member&) = delete;
        member& operator=(const member&) = delete;

        void swap(member& other) {
            std::swap(m_meta, other.m_meta);
            std::swap(m_serialize, other.m_serialize);
            std::swap(m_deserialize, other.m_deserialize);
        }

        template<typename S, class D>
        member(uniform_type_info* mtptr, S&& s, D&& d)
            : m_meta(mtptr)
            , m_serialize(std::forward<S>(s))
            , m_deserialize(std::forward<D>(d)) {
        }

     public:

        template<typename R, class C>
        member(uniform_type_info* mtptr, R C::*mem_ptr) : m_meta(mtptr) {
            m_serialize = [mem_ptr] (const uniform_type_info* mt,
                                     const void* obj,
                                     serializer* s) {
                mt->serialize(&(*reinterpret_cast<const C*>(obj).*mem_ptr), s);
            };
            m_deserialize = [mem_ptr] (const uniform_type_info* mt,
                                       void* obj,
                                       deserializer* d) {
                mt->deserialize(&(*reinterpret_cast<C*>(obj).*mem_ptr), d);
            };
        }

        template<typename GRes, typename SRes, typename SArg, class C>
        member(uniform_type_info* mtptr,
               GRes (C::*getter)() const,
               SRes (C::*setter)(SArg)) : m_meta(mtptr) {
            typedef typename util::rm_ref<GRes>::type getter_result;
            typedef typename util::rm_ref<SArg>::type setter_arg;
            static_assert(std::is_same<getter_result, setter_arg>::value,
                          "getter result doesn't match setter argument");
            m_serialize = [getter] (const uniform_type_info* mt,
                                    const void* obj,
                                    serializer* s) {
                GRes v = (*reinterpret_cast<const C*>(obj).*getter)();
                mt->serialize(&v, s);
            };
            m_deserialize = [setter] (const uniform_type_info* mt,
                                      void* obj,
                                      deserializer* d) {
                setter_arg value;
                mt->deserialize(&value, d); (*reinterpret_cast<C*>(obj).*setter)(value);
            };
        }

        member(member&& other) : m_meta(nullptr) {
            swap(other);
        }

        // a member that's not a member at all, but "forwards"
        // the 'self' pointer to make use of *_member implementations
        static member fake_member(uniform_type_info* mtptr) {
            return {
                mtptr,
                [] (const uniform_type_info* mt, const void* obj, serializer* s) {
                    mt->serialize(obj, s);
                },
                [] (const uniform_type_info* mt, void* obj, deserializer* d) {
                    mt->deserialize(obj, d);
                }
            };
        }

        ~member() {
            delete m_meta;
        }

        member& operator=(member&& other) {
            swap(other);
            return *this;
        }

        inline void serialize(const void* parent, serializer* s) const {
            m_serialize(m_meta, parent, s);
        }

        inline void deserialize(void* parent, deserializer* d) const {
            m_deserialize(m_meta, parent, d);
        }

    };

    std::vector<member> m_members;

    // terminates recursion
    inline void push_back() { }

    // pr.first = member pointer
    // pr.second = meta object to handle pr.first
    template<typename R, class C, typename... Args>
    void push_back(std::pair<R C::*, util::abstract_uniform_type_info<R>*> pr,
                   Args&&... args) {
        m_members.push_back({ pr.second, pr.first });
        push_back(std::forward<Args>(args)...);
    }

    // pr.first = getter / setter pair
    // pr.second = meta object to handle pr.first
    template<typename GRes, typename SRes, typename SArg, typename C, typename... Args>
    void push_back(const std::pair<std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>, util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>& pr,
                   Args&&... args) {
        m_members.push_back({ pr.second, pr.first.first, pr.first.second });
        push_back(std::forward<Args>(args)...);
    }

    // pr.first = getter member const function pointer
    // pr.second = setter member function pointer
    template<typename GRes, typename SRes, typename SArg, class C, typename... Args>
    typename std::enable_if<util::is_primitive<typename util::rm_ref<GRes>::type>::value>::type
    push_back(const std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>& pr,
              Args&&... args) {
        typedef typename util::rm_ref<GRes>::type memtype;
        m_members.push_back({ new primitive_member<memtype>(), pr.first, pr.second });
        push_back(std::forward<Args>(args)...);
    }

    template<typename R, class C, typename... Args>
    typename std::enable_if<util::is_primitive<R>::value>::type
    push_back(R C::*mem_ptr, Args&&... args) {
        m_members.push_back({ new primitive_member<R>(), mem_ptr });
        push_back(std::forward<Args>(args)...);
    }

    template< typename R, class C,typename... Args>
    typename std::enable_if<is_stl_compliant_list<R>::value>::type
    push_back(R C::*mem_ptr, Args&&... args) {
        m_members.push_back({ new list_member<R>(), mem_ptr });
        push_back(std::forward<Args>(args)...);
    }

    template<typename R, class C, typename... Args>
    typename std::enable_if<is_stl_compliant_map<R>::value>::type
    push_back(R C::*mem_ptr, Args&&... args) {
        m_members.push_back({ new map_member<R>(), mem_ptr });
        push_back(std::forward<Args>(args)...);
    }

    template<typename R, class C, typename... Args>
    typename std::enable_if<is_invalid<R>::value>::type
    push_back(R C::*, Args&&...) {
        static_assert(util::is_primitive<R>::value,
                      "T is neither a primitive type nor a "
                      "stl-compliant list/map");
    }

    template<typename P>
    void init_(typename std::enable_if<util::is_primitive<P>::value>::type* = 0) {
        m_members.push_back(member::fake_member(new primitive_member<P>()));
    }

    template<typename Map>
    void init_(typename std::enable_if<is_stl_compliant_map<Map>::value>::type* = 0) {
        m_members.push_back(member::fake_member(new map_member<Map>));
    }

    template<typename List>
    void init_(typename std::enable_if<is_stl_compliant_list<List>::value>::type* = 0) {
        m_members.push_back(member::fake_member(new list_member<List>));
    }

    template<typename X>
    void init_(typename std::enable_if<is_invalid<X>::value>::type* = 0) {
        // T is neither primitive nor a STL compliant list/map,
        // so it has to be an announced type
        static_assert(util::is_primitive<X>::value,
                      "T is neither a primitive type nor a "
                      "stl-compliant list/map");
    }

 public:

    template<typename... Args>
    default_uniform_type_info_impl(Args&&... args) {
        push_back(std::forward<Args>(args)...);
    }

    default_uniform_type_info_impl() {
        init_<T>();
        if (m_members.size() != 1) {
            throw std::logic_error("no fake member added");
        }
    }

    void serialize(const void* obj, serializer* s) const {
        s->begin_object(this->name());
        for (auto& m : m_members) {
            m.serialize(obj, s);
        }
        s->end_object();
    }

    void deserialize(void* obj, deserializer* d) const {
        this->assert_type_name(d);
        d->begin_object(this->name());
        for (auto& m : m_members) {
            m.deserialize(obj, d);
        }
        d->end_object();
    }

};

} } // namespace detail

#endif // CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
<commit_msg>enable announced types to have members of any builtin type<commit_after>/******************************************************************************\
 *           ___        __                                                    *
 *          /\_ \    __/\ \                                                   *
 *          \//\ \  /\_\ \ \____    ___   _____   _____      __               *
 *            \ \ \ \/\ \ \ '__`\  /'___\/\ '__`\/\ '__`\  /'__`\             *
 *             \_\ \_\ \ \ \ \L\ \/\ \__/\ \ \L\ \ \ \L\ \/\ \L\.\_           *
 *             /\____\\ \_\ \_,__/\ \____\\ \ ,__/\ \ ,__/\ \__/.\_\          *
 *             \/____/ \/_/\/___/  \/____/ \ \ \/  \ \ \/  \/__/\/_/          *
 *                                          \ \_\   \ \_\                     *
 *                                           \/_/    \/_/                     *
 *                                                                            *
 * Copyright (C) 2011, 2012                                                   *
 * Dominik Charousset <dominik.charousset@haw-hamburg.de>                     *
 *                                                                            *
 * This file is part of libcppa.                                              *
 * libcppa 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 3 of the License                  *
 * or (at your option) any later version.                                     *
 *                                                                            *
 * libcppa 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 libcppa. If not, see <http://www.gnu.org/licenses/>.            *
\******************************************************************************/

#ifndef CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
#define CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP

#include "cppa/anything.hpp"

#include "cppa/util/rm_ref.hpp"
#include "cppa/util/void_type.hpp"
#include "cppa/util/is_builtin.hpp"
#include "cppa/util/is_iterable.hpp"
#include "cppa/util/is_primitive.hpp"
#include "cppa/util/is_forward_iterator.hpp"
#include "cppa/util/abstract_uniform_type_info.hpp"

#include "cppa/detail/map_member.hpp"
#include "cppa/detail/list_member.hpp"
#include "cppa/detail/type_to_ptype.hpp"
#include "cppa/detail/primitive_member.hpp"

namespace cppa { namespace detail {

template<typename T>
class is_stl_compliant_list {

    template<class C>
    static bool cmp_help_fun (
        // mutable pointer
        C* mc,
        // check if there's a 'void push_back()' that takes C::value_type
        decltype(mc->push_back(typename C::value_type()))* = nullptr
    ) {
        return true;
    }

    // SFNINAE default
    static void cmp_help_fun(void*) { }

    typedef decltype(cmp_help_fun(static_cast<T*>(nullptr))) result_type;

 public:

    static constexpr bool value =    util::is_iterable<T>::value
                              && std::is_same<bool, result_type>::value;

};

template<typename T>
class is_stl_compliant_map {

    template<class C>
    static bool cmp_help_fun (
        // mutable pointer
        C* mc,
        // check if there's an 'insert()' that takes C::value_type
        decltype(mc->insert(typename C::value_type()))* = nullptr
    ) {
        return true;
    }

    static void cmp_help_fun(void*) { }

    typedef decltype(cmp_help_fun(static_cast<T*>(nullptr))) result_type;

 public:

    static constexpr bool value =    util::is_iterable<T>::value
                              && std::is_same<bool, result_type>::value;

};

template<typename T>
class builtin_member : public util::abstract_uniform_type_info<T> {

 public:

    builtin_member() : m_decorated(uniform_typeid<T>()) { }

    void serialize(const void* obj, serializer* s) const {
        m_decorated->serialize(obj, s);
    }

    void deserialize(void* obj, deserializer* d) const {
        m_decorated->deserialize(obj, d);
    }

 private:

    const uniform_type_info* m_decorated;

};

template<typename T>
class default_uniform_type_info_impl : public util::abstract_uniform_type_info<T> {

    template<typename X>
    struct is_invalid {
        static constexpr bool value =    !util::is_primitive<X>::value
                                      && !is_stl_compliant_map<X>::value
                                      && !is_stl_compliant_list<X>::value;
    };

    class member {

        uniform_type_info* m_meta;

        std::function<void (const uniform_type_info*,
                            const void*,
                            serializer*              )> m_serialize;

        std::function<void (const uniform_type_info*,
                            void*,
                            deserializer*            )> m_deserialize;

        member(const member&) = delete;
        member& operator=(const member&) = delete;

        void swap(member& other) {
            std::swap(m_meta, other.m_meta);
            std::swap(m_serialize, other.m_serialize);
            std::swap(m_deserialize, other.m_deserialize);
        }

        template<typename S, class D>
        member(uniform_type_info* mtptr, S&& s, D&& d)
            : m_meta(mtptr)
            , m_serialize(std::forward<S>(s))
            , m_deserialize(std::forward<D>(d)) {
        }

     public:

        template<typename R, class C>
        member(uniform_type_info* mtptr, R C::*mem_ptr) : m_meta(mtptr) {
            m_serialize = [mem_ptr] (const uniform_type_info* mt,
                                     const void* obj,
                                     serializer* s) {
                mt->serialize(&(*reinterpret_cast<const C*>(obj).*mem_ptr), s);
            };
            m_deserialize = [mem_ptr] (const uniform_type_info* mt,
                                       void* obj,
                                       deserializer* d) {
                mt->deserialize(&(*reinterpret_cast<C*>(obj).*mem_ptr), d);
            };
        }

        template<typename GRes, typename SRes, typename SArg, class C>
        member(uniform_type_info* mtptr,
               GRes (C::*getter)() const,
               SRes (C::*setter)(SArg)) : m_meta(mtptr) {
            typedef typename util::rm_ref<GRes>::type getter_result;
            typedef typename util::rm_ref<SArg>::type setter_arg;
            static_assert(std::is_same<getter_result, setter_arg>::value,
                          "getter result doesn't match setter argument");
            m_serialize = [getter] (const uniform_type_info* mt,
                                    const void* obj,
                                    serializer* s) {
                GRes v = (*reinterpret_cast<const C*>(obj).*getter)();
                mt->serialize(&v, s);
            };
            m_deserialize = [setter] (const uniform_type_info* mt,
                                      void* obj,
                                      deserializer* d) {
                setter_arg value;
                mt->deserialize(&value, d); (*reinterpret_cast<C*>(obj).*setter)(value);
            };
        }

        member(member&& other) : m_meta(nullptr) {
            swap(other);
        }

        // a member that's not a member at all, but "forwards"
        // the 'self' pointer to make use of *_member implementations
        static member fake_member(uniform_type_info* mtptr) {
            return {
                mtptr,
                [] (const uniform_type_info* mt, const void* obj, serializer* s) {
                    mt->serialize(obj, s);
                },
                [] (const uniform_type_info* mt, void* obj, deserializer* d) {
                    mt->deserialize(obj, d);
                }
            };
        }

        ~member() {
            delete m_meta;
        }

        member& operator=(member&& other) {
            swap(other);
            return *this;
        }

        inline void serialize(const void* parent, serializer* s) const {
            m_serialize(m_meta, parent, s);
        }

        inline void deserialize(void* parent, deserializer* d) const {
            m_deserialize(m_meta, parent, d);
        }

    };

    std::vector<member> m_members;

    // terminates recursion
    inline void push_back() { }

    // pr.first = member pointer
    // pr.second = meta object to handle pr.first
    template<typename R, class C, typename... Args>
    void push_back(std::pair<R C::*, util::abstract_uniform_type_info<R>*> pr,
                   Args&&... args) {
        m_members.push_back({ pr.second, pr.first });
        push_back(std::forward<Args>(args)...);
    }

    // pr.first = getter / setter pair
    // pr.second = meta object to handle pr.first
    template<typename GRes, typename SRes, typename SArg, typename C, typename... Args>
    void push_back(const std::pair<std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>, util::abstract_uniform_type_info<typename util::rm_ref<GRes>::type>*>& pr,
                   Args&&... args) {
        m_members.push_back({ pr.second, pr.first.first, pr.first.second });
        push_back(std::forward<Args>(args)...);
    }

    // pr.first = getter member const function pointer
    // pr.second = setter member function pointer
    template<typename GRes, typename SRes, typename SArg, class C, typename... Args>
    typename std::enable_if<util::is_primitive<typename util::rm_ref<GRes>::type>::value>::type
    push_back(const std::pair<GRes (C::*)() const, SRes (C::*)(SArg)>& pr,
              Args&&... args) {
        typedef typename util::rm_ref<GRes>::type memtype;
        m_members.push_back({ new primitive_member<memtype>(), pr.first, pr.second });
        push_back(std::forward<Args>(args)...);
    }

    template<typename R, class C, typename... Args>
    typename std::enable_if<util::is_primitive<R>::value>::type
    push_back(R C::*mem_ptr, Args&&... args) {
        m_members.push_back({ new primitive_member<R>(), mem_ptr });
        push_back(std::forward<Args>(args)...);
    }

    template< typename R, class C,typename... Args>
    typename std::enable_if<is_stl_compliant_list<R>::value>::type
    push_back(R C::*mem_ptr, Args&&... args) {
        m_members.push_back({ new list_member<R>(), mem_ptr });
        push_back(std::forward<Args>(args)...);
    }

    template<typename R, class C, typename... Args>
    typename std::enable_if<is_stl_compliant_map<R>::value>::type
    push_back(R C::*mem_ptr, Args&&... args) {
        m_members.push_back({ new map_member<R>(), mem_ptr });
        push_back(std::forward<Args>(args)...);
    }

    template<typename R, class C, typename... Args>
    typename std::enable_if<is_invalid<R>::value && util::is_builtin<R>::value>::type
    push_back(R C::* mem_ptr, Args&&... args) {
        m_members.push_back({new builtin_member<R>(), mem_ptr});
        push_back(std::forward<Args>(args)...);
    }

    template<typename R, class C, typename... Args>
    typename std::enable_if<is_invalid<R>::value && !util::is_builtin<R>::value>::type
    push_back(R C::*, Args&&...) {
        static_assert(util::is_primitive<R>::value,
                      "T is neither a primitive type nor a "
                      "stl-compliant list/map");
    }

    template<typename P>
    void init_(typename std::enable_if<util::is_primitive<P>::value>::type* = 0) {
        m_members.push_back(member::fake_member(new primitive_member<P>()));
    }

    template<typename Map>
    void init_(typename std::enable_if<is_stl_compliant_map<Map>::value>::type* = 0) {
        m_members.push_back(member::fake_member(new map_member<Map>));
    }

    template<typename List>
    void init_(typename std::enable_if<is_stl_compliant_list<List>::value>::type* = 0) {
        m_members.push_back(member::fake_member(new list_member<List>));
    }

    template<typename X>
    void init_(typename std::enable_if<is_invalid<X>::value>::type* = 0) {
        // T is neither primitive nor a STL compliant list/map,
        // so it has to be an announced type
        static_assert(util::is_primitive<X>::value,
                      "T is neither a primitive type nor a "
                      "stl-compliant list/map");
    }

 public:

    template<typename... Args>
    default_uniform_type_info_impl(Args&&... args) {
        push_back(std::forward<Args>(args)...);
    }

    default_uniform_type_info_impl() {
        init_<T>();
        if (m_members.size() != 1) {
            throw std::logic_error("no fake member added");
        }
    }

    void serialize(const void* obj, serializer* s) const {
        s->begin_object(this->name());
        for (auto& m : m_members) {
            m.serialize(obj, s);
        }
        s->end_object();
    }

    void deserialize(void* obj, deserializer* d) const {
        this->assert_type_name(d);
        d->begin_object(this->name());
        for (auto& m : m_members) {
            m.deserialize(obj, d);
        }
        d->end_object();
    }

};

} } // namespace detail

#endif // CPPA_DEFAULT_UNIFORM_TYPE_INFO_IMPL_HPP
<|endoftext|>


<commit_before>#include "Halide.h"

// Include the machine-generated .stub.h header file.
#include "example.stub.h"

using Halide::Buffer;

const int kSize = 32;

void verify(const Buffer<int32_t> &img, float compiletime_factor, float runtime_factor, int channels) {
    for (int i = 0; i < kSize; i++) {
        for (int j = 0; j < kSize; j++) {
            for (int c = 0; c < channels; c++) {
                if (img(i, j, c) !=
                    (int32_t)(compiletime_factor * runtime_factor * c * (i > j ? i : j))) {
                    printf("img[%d, %d, %d] = %d\n", i, j, c, img(i, j, c));
                    exit(-1);
                }
            }
        }
    }
}

int main(int argc, char **argv) {
    Halide::JITGeneratorContext context(Halide::get_target_from_environment());

    {
        // Create a Generator and set its Inputs and GeneratorParams.
        // We could just use initializer-list syntax, but we'll explicitly
        // set the fields by name for clarity.
        example::Inputs inputs;
        inputs.runtime_factor = 1.f;

        // The fields of the GeneratorParams struct are initialized to the
        // default values specified in the Generator, so we can just omit
        // any we don't want to change
        example::GeneratorParams gp;
        gp.compiletime_factor = 2.392f;
        gp.enummy = Enum_enummy::foo;
        // gp.channels = 3;  -- this is the default; no need to set

        auto gen = example(context, inputs, gp);

        // We must call schedule() before calling realize()
        gen.schedule();

        Image<int32_t> img = gen.realize(kSize, kSize, 3);
        verify(img, 2.392f, 1, 3);
    }

    {
        // Here, we'll use an initializer list for inputs, and omit
        // the GeneratorParams entirely to use their default values.
        auto gen = example(context, /* inputs: */ { 1.f });

        // We'll set "vectorize=false" in the ScheduleParams, just to
        // show that we can:
        example::ScheduleParams sp;
        sp.vectorize = false;
        gen.schedule(sp);

        Image<int32_t> img = gen.realize(kSize, kSize, 3);
        verify(img, 1, 1, 3);
    }

    printf("Success!\n");
    return 0;
}
<commit_msg>Image -> Buffer in example_jittest<commit_after>#include "Halide.h"

// Include the machine-generated .stub.h header file.
#include "example.stub.h"

using Halide::Buffer;

const int kSize = 32;

void verify(const Buffer<int32_t> &img, float compiletime_factor, float runtime_factor, int channels) {
    for (int i = 0; i < kSize; i++) {
        for (int j = 0; j < kSize; j++) {
            for (int c = 0; c < channels; c++) {
                if (img(i, j, c) !=
                    (int32_t)(compiletime_factor * runtime_factor * c * (i > j ? i : j))) {
                    printf("img[%d, %d, %d] = %d\n", i, j, c, img(i, j, c));
                    exit(-1);
                }
            }
        }
    }
}

int main(int argc, char **argv) {
    Halide::JITGeneratorContext context(Halide::get_target_from_environment());

    {
        // Create a Generator and set its Inputs and GeneratorParams.
        // We could just use initializer-list syntax, but we'll explicitly
        // set the fields by name for clarity.
        example::Inputs inputs;
        inputs.runtime_factor = 1.f;

        // The fields of the GeneratorParams struct are initialized to the
        // default values specified in the Generator, so we can just omit
        // any we don't want to change
        example::GeneratorParams gp;
        gp.compiletime_factor = 2.392f;
        gp.enummy = Enum_enummy::foo;
        // gp.channels = 3;  -- this is the default; no need to set

        auto gen = example(context, inputs, gp);

        // We must call schedule() before calling realize()
        gen.schedule();

        Halide::Buffer<int32_t> img = gen.realize(kSize, kSize, 3);
        verify(img, 2.392f, 1, 3);
    }

    {
        // Here, we'll use an initializer list for inputs, and omit
        // the GeneratorParams entirely to use their default values.
        auto gen = example(context, /* inputs: */ { 1.f });

        // We'll set "vectorize=false" in the ScheduleParams, just to
        // show that we can:
        example::ScheduleParams sp;
        sp.vectorize = false;
        gen.schedule(sp);

        Halide::Buffer<int32_t> img = gen.realize(kSize, kSize, 3);
        verify(img, 1, 1, 3);
    }

    printf("Success!\n");
    return 0;
}
<|endoftext|>