<commit_before>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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 "condor_common.h"
#include "ManagedDatabase.h"
#include "dbms_utils.h"
#include "condor_config.h"
#include "pgsqldatabase.h"
#include "condor_email.h"

ManagedDatabase::ManagedDatabase() {
	char *tmp;
	QuillErrCode ret_st;

	if (param_boolean("QUILL_ENABLED", false) == false) {
		EXCEPT("Quill++ is currently disabled. Please set QUILL_ENABLED to "
			   "TRUE if you want this functionality and read the manual "
			   "about this feature since it requires other attributes to be "
			   "set properly.");
	}

		//bail out if no SPOOL variable is defined since its used to
		//figure out the location of the quillWriter password file
	char *spool = param("SPOOL");
	if(!spool) {
		EXCEPT("No SPOOL variable found in config file\n");
	}

		/*
		  Here we try to read the database parameters in config
		  the db ip address format is <ipaddress:port>
		*/
	dt = getConfigDBType();
	dbIpAddress = param("QUILL_DB_IP_ADDR");
	dbName = param("QUILL_DB_NAME");
	dbUser = param("QUILL_DB_USER");

	dbConnStr = getDBConnStr(dbIpAddress,
							 dbName,
							 dbUser,
							 spool);

	dprintf(D_ALWAYS, "Using Database Type = Postgres\n");
	dprintf(D_ALWAYS, "Using Database IpAddress = %s\n",
			dbIpAddress?dbIpAddress:"");
	dprintf(D_ALWAYS, "Using Database Name = %s\n",
			dbName?dbName:"");
	dprintf(D_ALWAYS, "Using Database User = %s\n",
			dbUser?dbUser:"");

	if (spool) {
		free(spool);
	}

	switch (dt) {
	case T_PGSQL:
		DBObj = new PGSQLDatabase(dbConnStr);
		break;
	default:
		break;
	}

			/* default to a week of resource history info */
	resourceHistoryDuration = param_integer("QUILL_RESOURCE_HISTORY_DURATION", 7);

			/* default to a week of job run information */
	runHistoryDuration = param_integer("QUILL_RUN_HISTORY_DURATION", 7);

	tmp = param("QUILL_JOB_HISTORY_DURATION");
	if (tmp) {
		jobHistoryDuration= atoi(tmp);
		free(tmp);
	} else {
			/* default to 10 years of job history */
		jobHistoryDuration = 3650;
	}

	tmp = param("QUILL_DBSIZE_LIMIT");
	if (tmp) {
		dbSizeLimit= atoi(tmp);
		free(tmp);
	} else {
			/* default to 20 GB */
		dbSizeLimit = 20;
	}

		/* check if schema version is ok */
	ret_st = DBObj->connectDB();
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "config: unable to connect to DB--- ERROR");
		EXCEPT("config: unable to connect to DB\n");
	}

		/* the following will also throw an exception of the schema
		   version is not correct */
	DBObj->assertSchemaVersion();

	DBObj->disconnectDB();
}

ManagedDatabase::~ManagedDatabase() {
	if (dbIpAddress) {
		free(dbIpAddress);
		dbIpAddress = NULL;
	}

	if (dbName) {
		free(dbName);
		dbName = NULL;
	}

	if (dbUser) {
		free(dbUser);
		dbUser = NULL;
	}

	if (dbConnStr) {
		free(dbConnStr);
		dbConnStr = NULL;
	}

	if (DBObj) {
		delete DBObj;
	}
}

void ManagedDatabase::PurgeDatabase() {
	QuillErrCode ret_st;
	int dbsize;
	int num_result;
	MyString sql_str;

	ret_st = DBObj->connectDB();

		/* call the puging routine */
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "ManagedDatabase::PurgeDatabase: unable to connect to DB--- ERROR\n");
		return;
	}

	switch (dt) {
	case T_PGSQL:
		sql_str.sprintf("select quill_purgeHistory(%d, %d, %d)",
						resourceHistoryDuration,
						runHistoryDuration,
						jobHistoryDuration);
		break;
	default:
			// can't have this case
		dprintf(D_ALWAYS, "database type is %d, unexpected! exiting!\n", dt);
		ASSERT(0);
		break;
	}

	ret_st = DBObj->execCommand(sql_str.Value());
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "ManagedDatabase::PurgeDatabase --- ERROR [SQL] %s\n",
				sql_str.Value());
	}

	ret_st = DBObj->commitTransaction();
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "ManagedDatabase::PurgeDatabase --- ERROR [COMMIT] \n");
	}

		/* query the space usage and if it is above some threshold, send
		  a warning to the administrator
		*/

	sql_str.sprintf("SELECT dbsize FROM quillDBMonitor");
	ret_st = DBObj->execQuery(sql_str.Value(), num_result);

	if ((ret_st == QUILL_SUCCESS) &&
		(num_result == 1)) {
		dbsize = atoi(DBObj->getValue(0, 0));

			/* if dbsize is bigger than 75% the dbSizeLimit, send a
			   warning to the administrator with information about
			   the situation and suggestion for looking at the table
			   sizes using the following sql statement and tune down
			   the *HistoryDuration parameters accordingly.

			   This is an oracle version of sql for examining the
			   table sizes in descending order, sql for other
			   databases can be similarly constructed:
			   SELECT NUM_ROWS*AVG_ROW_LEN, table_name
			   FROM USER_TABLES
			   ORDER BY  NUM_ROWS*AVG_ROW_LEN DESC;
			*/
		if (dbsize/1024 > dbSizeLimit) {
			FILE *email;
			char msg_body[4000];

			snprintf(msg_body, 4000, "Current database size (> %d MB) is "
					 "bigger than 75 percent of the limit (%d GB). Please "
					 "decrease the values of these parameters: "
					 "QUILL_RESOURCE_HISTORY_DURATION, "
					 "QUILL_RUN_HISTORY_DURATION, "
					 "QUILL_JOB_HISTORY_DURATION or QUILL_DBSIZE_LIMIT\n",
					 dbsize, dbSizeLimit);

				/* notice that dbsize is stored in unit of MB, but
				   dbSizeLimit is stored in unit of GB */
			dprintf(D_ALWAYS, "%s", msg_body);

			email = email_admin_open(msg_body);

			if (email) {
				email_close ( email );
			} else {
				dprintf( D_ALWAYS, "ERROR: Can't send email to the Condor "
						 "Administrator\n" );
			}
		}

	} else {
		dprintf(D_ALWAYS, "Reading quillDBMonitor --- ERROR or returned # of rows is not exactly one [SQL] %s\n",
				sql_str.Value());
	}

	DBObj->releaseQueryResult();

	ret_st = DBObj->disconnectDB();
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "ManagedDatabase::disconnectDB: unable to disconnect --- ERROR\n");
		return;
	}
}

void ManagedDatabase::ReindexDatabase() {
	QuillErrCode ret_st;
	MyString sql_str;

	switch (dt) {
	case T_PGSQL:
		ret_st = DBObj->connectDB();

			/* call the reindex routine */
		if (ret_st == QUILL_FAILURE) {
			dprintf(D_ALWAYS, "ManagedDatabase::ReindexDatabase: unable to connect to DB--- ERROR\n");
			return;
		}

		sql_str.sprintf("select quill_reindexTables()");

		ret_st = DBObj->execCommand(sql_str.Value());
		if (ret_st == QUILL_FAILURE) {
			dprintf(D_ALWAYS, "ManagedDatabase::ReindexDatabase --- ERROR [SQL] %s\n",
					sql_str.Value());
		}

		ret_st = DBObj->disconnectDB();
		if (ret_st == QUILL_FAILURE) {
			dprintf(D_ALWAYS, "ManagedDatabase::disconnectDB: unable to disconnect --- ERROR\n");
			return;
		}

		break;
	default:
			// can't have this case
		dprintf(D_ALWAYS, "database type is %d, unexpected! exiting!\n", dt);
		ASSERT(0);
		break;
	}

}
<commit_msg>param+atoi -> param_integer for QUILL_JOB_HISTORY_DURATION<commit_after>/***************************************************************
 *
 * Copyright (C) 1990-2007, Condor Team, Computer Sciences Department,
 * University of Wisconsin-Madison, WI.
 *
 * 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 "condor_common.h"
#include "ManagedDatabase.h"
#include "dbms_utils.h"
#include "condor_config.h"
#include "pgsqldatabase.h"
#include "condor_email.h"

ManagedDatabase::ManagedDatabase() {
	char *tmp;
	QuillErrCode ret_st;

	if (param_boolean("QUILL_ENABLED", false) == false) {
		EXCEPT("Quill++ is currently disabled. Please set QUILL_ENABLED to "
			   "TRUE if you want this functionality and read the manual "
			   "about this feature since it requires other attributes to be "
			   "set properly.");
	}

		//bail out if no SPOOL variable is defined since its used to
		//figure out the location of the quillWriter password file
	char *spool = param("SPOOL");
	if(!spool) {
		EXCEPT("No SPOOL variable found in config file\n");
	}

		/*
		  Here we try to read the database parameters in config
		  the db ip address format is <ipaddress:port>
		*/
	dt = getConfigDBType();
	dbIpAddress = param("QUILL_DB_IP_ADDR");
	dbName = param("QUILL_DB_NAME");
	dbUser = param("QUILL_DB_USER");

	dbConnStr = getDBConnStr(dbIpAddress,
							 dbName,
							 dbUser,
							 spool);

	dprintf(D_ALWAYS, "Using Database Type = Postgres\n");
	dprintf(D_ALWAYS, "Using Database IpAddress = %s\n",
			dbIpAddress?dbIpAddress:"");
	dprintf(D_ALWAYS, "Using Database Name = %s\n",
			dbName?dbName:"");
	dprintf(D_ALWAYS, "Using Database User = %s\n",
			dbUser?dbUser:"");

	if (spool) {
		free(spool);
	}

	switch (dt) {
	case T_PGSQL:
		DBObj = new PGSQLDatabase(dbConnStr);
		break;
	default:
		break;
	}

			/* default to a week of resource history info */
	resourceHistoryDuration = param_integer("QUILL_RESOURCE_HISTORY_DURATION", 7);

			/* default to a week of job run information */
	runHistoryDuration = param_integer("QUILL_RUN_HISTORY_DURATION", 7);

			/* default to 10 years of job history */
	jobHistoryDuration = param_integer("QUILL_JOB_HISTORY_DURATION", 3650);

	tmp = param("QUILL_DBSIZE_LIMIT");
	if (tmp) {
		dbSizeLimit= atoi(tmp);
		free(tmp);
	} else {
			/* default to 20 GB */
		dbSizeLimit = 20;
	}

		/* check if schema version is ok */
	ret_st = DBObj->connectDB();
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "config: unable to connect to DB--- ERROR");
		EXCEPT("config: unable to connect to DB\n");
	}

		/* the following will also throw an exception of the schema
		   version is not correct */
	DBObj->assertSchemaVersion();

	DBObj->disconnectDB();
}

ManagedDatabase::~ManagedDatabase() {
	if (dbIpAddress) {
		free(dbIpAddress);
		dbIpAddress = NULL;
	}

	if (dbName) {
		free(dbName);
		dbName = NULL;
	}

	if (dbUser) {
		free(dbUser);
		dbUser = NULL;
	}

	if (dbConnStr) {
		free(dbConnStr);
		dbConnStr = NULL;
	}

	if (DBObj) {
		delete DBObj;
	}
}

void ManagedDatabase::PurgeDatabase() {
	QuillErrCode ret_st;
	int dbsize;
	int num_result;
	MyString sql_str;

	ret_st = DBObj->connectDB();

		/* call the puging routine */
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "ManagedDatabase::PurgeDatabase: unable to connect to DB--- ERROR\n");
		return;
	}

	switch (dt) {
	case T_PGSQL:
		sql_str.sprintf("select quill_purgeHistory(%d, %d, %d)",
						resourceHistoryDuration,
						runHistoryDuration,
						jobHistoryDuration);
		break;
	default:
			// can't have this case
		dprintf(D_ALWAYS, "database type is %d, unexpected! exiting!\n", dt);
		ASSERT(0);
		break;
	}

	ret_st = DBObj->execCommand(sql_str.Value());
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "ManagedDatabase::PurgeDatabase --- ERROR [SQL] %s\n",
				sql_str.Value());
	}

	ret_st = DBObj->commitTransaction();
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "ManagedDatabase::PurgeDatabase --- ERROR [COMMIT] \n");
	}

		/* query the space usage and if it is above some threshold, send
		  a warning to the administrator
		*/

	sql_str.sprintf("SELECT dbsize FROM quillDBMonitor");
	ret_st = DBObj->execQuery(sql_str.Value(), num_result);

	if ((ret_st == QUILL_SUCCESS) &&
		(num_result == 1)) {
		dbsize = atoi(DBObj->getValue(0, 0));

			/* if dbsize is bigger than 75% the dbSizeLimit, send a
			   warning to the administrator with information about
			   the situation and suggestion for looking at the table
			   sizes using the following sql statement and tune down
			   the *HistoryDuration parameters accordingly.

			   This is an oracle version of sql for examining the
			   table sizes in descending order, sql for other
			   databases can be similarly constructed:
			   SELECT NUM_ROWS*AVG_ROW_LEN, table_name
			   FROM USER_TABLES
			   ORDER BY  NUM_ROWS*AVG_ROW_LEN DESC;
			*/
		if (dbsize/1024 > dbSizeLimit) {
			FILE *email;
			char msg_body[4000];

			snprintf(msg_body, 4000, "Current database size (> %d MB) is "
					 "bigger than 75 percent of the limit (%d GB). Please "
					 "decrease the values of these parameters: "
					 "QUILL_RESOURCE_HISTORY_DURATION, "
					 "QUILL_RUN_HISTORY_DURATION, "
					 "QUILL_JOB_HISTORY_DURATION or QUILL_DBSIZE_LIMIT\n",
					 dbsize, dbSizeLimit);

				/* notice that dbsize is stored in unit of MB, but
				   dbSizeLimit is stored in unit of GB */
			dprintf(D_ALWAYS, "%s", msg_body);

			email = email_admin_open(msg_body);

			if (email) {
				email_close ( email );
			} else {
				dprintf( D_ALWAYS, "ERROR: Can't send email to the Condor "
						 "Administrator\n" );
			}
		}

	} else {
		dprintf(D_ALWAYS, "Reading quillDBMonitor --- ERROR or returned # of rows is not exactly one [SQL] %s\n",
				sql_str.Value());
	}

	DBObj->releaseQueryResult();

	ret_st = DBObj->disconnectDB();
	if (ret_st == QUILL_FAILURE) {
		dprintf(D_ALWAYS, "ManagedDatabase::disconnectDB: unable to disconnect --- ERROR\n");
		return;
	}
}

void ManagedDatabase::ReindexDatabase() {
	QuillErrCode ret_st;
	MyString sql_str;

	switch (dt) {
	case T_PGSQL:
		ret_st = DBObj->connectDB();

			/* call the reindex routine */
		if (ret_st == QUILL_FAILURE) {
			dprintf(D_ALWAYS, "ManagedDatabase::ReindexDatabase: unable to connect to DB--- ERROR\n");
			return;
		}

		sql_str.sprintf("select quill_reindexTables()");

		ret_st = DBObj->execCommand(sql_str.Value());
		if (ret_st == QUILL_FAILURE) {
			dprintf(D_ALWAYS, "ManagedDatabase::ReindexDatabase --- ERROR [SQL] %s\n",
					sql_str.Value());
		}

		ret_st = DBObj->disconnectDB();
		if (ret_st == QUILL_FAILURE) {
			dprintf(D_ALWAYS, "ManagedDatabase::disconnectDB: unable to disconnect --- ERROR\n");
			return;
		}

		break;
	default:
			// can't have this case
		dprintf(D_ALWAYS, "database type is %d, unexpected! exiting!\n", dt);
		ASSERT(0);
		break;
	}

}
<|endoftext|>


<commit_before>#include <vector>
using std::vector;

#include "cinder/app/AppBasic.h"
#include "cinder/Path2d.h"
#include "cinder/cairo/Cairo.h"
#include "cinder/ip/Fill.h"
#include "cinder/Rand.h"
#include "cinder/Utilities.h"

using namespace ci;
using namespace ci::app;

class Flower {
  public:
	Flower( Vec2f loc, float radius, float petalOutsideRadius, float petalInsideRadius, int numPetals, ColorA color )
		: mLoc( loc ), mRadius( radius ), mPetalOutsideRadius( petalOutsideRadius ), mPetalInsideRadius( petalInsideRadius ), mNumPetals( numPetals ), mColor( color )
	{}

	void makePath( cairo::Context &ctx ) const
	{
		for( int petal = 0; petal < mNumPetals; ++petal ) {
			ctx.newSubPath();
			float petalAngle = ( petal / (float)mNumPetals ) * 2 * M_PI;
			Vec2f outsideCircleCenter = mLoc + Vec2f::xAxis() * cos( petalAngle ) * mRadius + Vec2f::yAxis() * sin( petalAngle ) * mRadius;
			Vec2f insideCircleCenter = mLoc + Vec2f::xAxis() * cos( petalAngle ) * mPetalInsideRadius + Vec2f::yAxis() * sin( petalAngle ) * mPetalInsideRadius;
			ctx.arc( outsideCircleCenter, mPetalOutsideRadius, petalAngle + M_PI / 2 + M_PI, petalAngle + M_PI / 2 );
			ctx.arc( insideCircleCenter, mPetalInsideRadius, petalAngle + M_PI / 2, petalAngle + M_PI / 2 + M_PI );
			ctx.closePath();
		}
	}

	void draw( cairo::Context &ctx ) const
	{
		// draw the solid petals
		ctx.setSource( mColor );
		makePath( ctx );
		ctx.fill();

		// draw the petal outlines
		ctx.setSource( mColor * 0.8f );
		makePath( ctx );
		ctx.stroke();
	};

  private:
	Vec2f		mLoc;
	float		mRadius, mPetalOutsideRadius, mPetalInsideRadius;
	int			mNumPetals;
	ColorA		mColor;
};

class CairoBasicApp : public AppBasic {
  public:
	void mouseDown( MouseEvent event );
	void keyDown( KeyEvent event );
	void renderScene( cairo::Context &ctx );
	void draw();

	vector<Flower>		mFlowers;
};

void CairoBasicApp::mouseDown( MouseEvent event )
{
	// create a new flower
	float radius = randFloat( 60, 90 );
	int numPetals = randInt( 6, 50 );
	float outerRadius = ( 2 * M_PI * radius ) / numPetals / 2 * randFloat( 0.9f, 1.0f );
	float innerRadius = outerRadius * randFloat( 0.2f, 0.4f );
	mFlowers.push_back( Flower( event.getPos(), radius, outerRadius, innerRadius, numPetals, ColorA( CM_HSV, randFloat(), 1, 1, 0.65f ) ) );
}

void CairoBasicApp::keyDown( KeyEvent event )
{
	if( event.getCode() == KeyEvent::KEY_f ) {
		setFullScreen( ! isFullScreen() );
	}
	else if( event.getChar() == 'x' ) {
		mFlowers.clear();
	}
	else if( event.getChar() == 's' ) {
		cairo::Context ctx( cairo::SurfaceSvg( getHomeDirectory() / "CairoBasicShot.svg", getWindowWidth(), getWindowHeight() ) );
		renderScene( ctx );
	}
	else if( event.getChar() == 'e' ) {
		cairo::Context ctx( cairo::SurfaceEps( getHomeDirectory() / "CairoBasicShot.eps", getWindowWidth(), getWindowHeight() ) );
		renderScene( ctx );
	}
	else if( event.getChar() == 'p' ) {
		cairo::Context ctx( cairo::SurfacePs( getHomeDirectory() / "CairoBasicShot.ps", getWindowWidth(), getWindowHeight() ) );
		renderScene( ctx );
	}
	else if( event.getChar() == 'd' ) {
		cairo::Context ctx( cairo::SurfacePdf( getHomeDirectory() / "CairoBasicShot.pdf", getWindowWidth(), getWindowHeight() ) );
		renderScene( ctx );
	}
}

void CairoBasicApp::renderScene( cairo::Context &ctx )
{
	// clear the context with our radial gradient
	cairo::GradientRadial radialGrad( getWindowCenter(), 0, getWindowCenter(), getWindowWidth() );
	radialGrad.addColorStop( 0, Color( 1, 1, 1 ) );
	radialGrad.addColorStop( 1, Color( 0.6, 0.6, 0.6 ) );
	ctx.setSource( radialGrad );
	ctx.paint();

	for( vector<Flower>::const_iterator flIt = mFlowers.begin(); flIt != mFlowers.end(); ++flIt )
		flIt->draw( ctx );
}

void CairoBasicApp::draw()
{
	// render the scene straight to the window
	cairo::Context ctx( cairo::createWindowSurface() );
	renderScene( ctx );
}

CINDER_APP_BASIC( CairoBasicApp, Renderer2d )
<commit_msg>Update CairoBasic sample.<commit_after>#include <vector>
using std::vector;

#include "cinder/app/AppBasic.h"
#include "cinder/Path2d.h"
#include "cinder/cairo/Cairo.h"
#include "cinder/ip/Fill.h"
#include "cinder/Rand.h"
#include "cinder/Utilities.h"

using namespace ci;
using namespace ci::app;

class Flower {
  public:
	Flower( Vec2f loc, float radius, float petalOutsideRadius, float petalInsideRadius, int numPetals, ColorA color )
		: mLoc( loc ), mRadius( radius ), mPetalOutsideRadius( petalOutsideRadius ), mPetalInsideRadius( petalInsideRadius ), mNumPetals( numPetals ), mColor( color )
	{}

	void makePath( cairo::Context &ctx ) const
	{
		for( int petal = 0; petal < mNumPetals; ++petal ) {
			ctx.newSubPath();
			float petalAngle = ( petal / (float)mNumPetals ) * 2 * M_PI;
			Vec2f outsideCircleCenter = mLoc + vec2( 1, 0 ) * cos( petalAngle ) * mRadius + vec2( 0, 1 ) * sin( petalAngle ) * mRadius;
			Vec2f insideCircleCenter = mLoc + vec2( 1, 0 ) * cos( petalAngle ) * mPetalInsideRadius + vec2( 0, 1 ) * sin( petalAngle ) * mPetalInsideRadius;
			ctx.arc( outsideCircleCenter, mPetalOutsideRadius, petalAngle + M_PI / 2 + M_PI, petalAngle + M_PI / 2 );
			ctx.arc( insideCircleCenter, mPetalInsideRadius, petalAngle + M_PI / 2, petalAngle + M_PI / 2 + M_PI );
			ctx.closePath();
		}
	}

	void draw( cairo::Context &ctx ) const
	{
		// draw the solid petals
		ctx.setSource( mColor );
		makePath( ctx );
		ctx.fill();

		// draw the petal outlines
		ctx.setSource( mColor * 0.8f );
		makePath( ctx );
		ctx.stroke();
	};

  private:
	Vec2f		mLoc;
	float		mRadius, mPetalOutsideRadius, mPetalInsideRadius;
	int			mNumPetals;
	ColorA		mColor;
};

class CairoBasicApp : public AppBasic {
  public:
	void mouseDown( MouseEvent event );
	void keyDown( KeyEvent event );
	void renderScene( cairo::Context &ctx );
	void draw();

	vector<Flower>		mFlowers;
};

void CairoBasicApp::mouseDown( MouseEvent event )
{
	// create a new flower
	float radius = randFloat( 60, 90 );
	int numPetals = randInt( 6, 50 );
	float outerRadius = ( 2 * M_PI * radius ) / numPetals / 2 * randFloat( 0.9f, 1.0f );
	float innerRadius = outerRadius * randFloat( 0.2f, 0.4f );
	mFlowers.push_back( Flower( event.getPos(), radius, outerRadius, innerRadius, numPetals, ColorA( CM_HSV, randFloat(), 1, 1, 0.65f ) ) );
}

void CairoBasicApp::keyDown( KeyEvent event )
{
	if( event.getCode() == KeyEvent::KEY_f ) {
		setFullScreen( ! isFullScreen() );
	}
	else if( event.getChar() == 'x' ) {
		mFlowers.clear();
	}
	else if( event.getChar() == 's' ) {
		cairo::Context ctx( cairo::SurfaceSvg( getHomeDirectory() / "CairoBasicShot.svg", getWindowWidth(), getWindowHeight() ) );
		renderScene( ctx );
	}
	else if( event.getChar() == 'e' ) {
		cairo::Context ctx( cairo::SurfaceEps( getHomeDirectory() / "CairoBasicShot.eps", getWindowWidth(), getWindowHeight() ) );
		renderScene( ctx );
	}
	else if( event.getChar() == 'p' ) {
		cairo::Context ctx( cairo::SurfacePs( getHomeDirectory() / "CairoBasicShot.ps", getWindowWidth(), getWindowHeight() ) );
		renderScene( ctx );
	}
	else if( event.getChar() == 'd' ) {
		cairo::Context ctx( cairo::SurfacePdf( getHomeDirectory() / "CairoBasicShot.pdf", getWindowWidth(), getWindowHeight() ) );
		renderScene( ctx );
	}
}

void CairoBasicApp::renderScene( cairo::Context &ctx )
{
	// clear the context with our radial gradient
	cairo::GradientRadial radialGrad( getWindowCenter(), 0, getWindowCenter(), getWindowWidth() );
	radialGrad.addColorStop( 0, Color( 1, 1, 1 ) );
	radialGrad.addColorStop( 1, Color( 0.6, 0.6, 0.6 ) );
	ctx.setSource( radialGrad );
	ctx.paint();

	for( vector<Flower>::const_iterator flIt = mFlowers.begin(); flIt != mFlowers.end(); ++flIt )
		flIt->draw( ctx );
}

void CairoBasicApp::draw()
{
	// render the scene straight to the window
	cairo::Context ctx( cairo::createWindowSurface() );
	renderScene( ctx );
}

CINDER_APP_BASIC( CairoBasicApp, Renderer2d )
<|endoftext|>


<commit_before>/// \file ROOT/RColumnElement.hxx
/// \ingroup NTuple ROOT7
/// \author Jakob Blomer <jblomer@cern.ch>
/// \date 2018-10-09
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_RColumnElement
#define ROOT7_RColumnElement

#include <ROOT/RColumnModel.hxx>
#include <ROOT/RNTupleUtil.hxx>

#include <cstring> // for memcpy
#include <type_traits>

namespace ROOT {
namespace Experimental {

namespace Detail {

// clang-format off
/**
\class ROOT::Experimental::Detail::RColumnElement
\ingroup NTuple
\brief A column element points either to the content of an RFieldValue or into a memory mapped page.

The content pointed to by fRawContent can be a single element or the first element of an array.
Usually the on-disk element should map bitwise to the in-memory element. Sometimes that's not the case
though, for instance on big endian platforms and for exotic physical columns like 8 bit float.

This class does not provide protection around the raw pointer, fRawContent has to be managed correctly
by the user of this class.
*/
// clang-format on
class RColumnElementBase {
protected:
   /// Points to valid C++ data, either a single value or an array of values
   void* fRawContent;
   /// Size of the C++ value pointed to by fRawContent (not necessarily equal to the on-disk element size)
   const unsigned int fSize;

   /// Indicates that *fRawContent is bitwise identical to the physical column element
   const bool fIsMappable;

   virtual void DoSerialize(void* /* destination */, std::size_t /*count*/) const { }
   virtual void DoDeserialize(void* /* source */, std::size_t /*count*/) const { }

public:
   RColumnElementBase()
     : fRawContent(nullptr)
     , fSize(0)
     , fIsMappable(false)
   {}
   RColumnElementBase(void* rawContent, unsigned int size, bool isMappable)
     : fRawContent(rawContent)
     , fSize(size)
     , fIsMappable(isMappable)
   {}
   RColumnElementBase(const RColumnElementBase &elemArray, std::size_t at)
     : fRawContent(static_cast<unsigned char *>(elemArray.fRawContent) + elemArray.fSize * at)
     , fSize(elemArray.fSize)
     , fIsMappable(elemArray.fIsMappable)
   {}
   RColumnElementBase(const RColumnElementBase& other) = default;
   RColumnElementBase(RColumnElementBase&& other) = default;
   RColumnElementBase& operator =(const RColumnElementBase& other) = delete;
   RColumnElementBase& operator =(RColumnElementBase&& other) = default;
   virtual ~RColumnElementBase() = default;

   void Serialize(void *destination, std::size_t count) const {
     if (!fIsMappable) {
       DoSerialize(destination, count);
       return;
     }
     std::memcpy(destination, fRawContent, fSize * count);
   }

   void Deserialize(void *source, std::size_t count) {
     if (!fIsMappable) {
       DoDeserialize(source, count);
       return;
     }
     std::memcpy(fRawContent, source, fSize * count);
   }

   void* GetRawContent() const { return fRawContent; }
   unsigned int GetSize() const { return fSize; }
};

/**
 * Pairs of C++ type and column type, like float and EColumnType::kReal32
 */
template <typename CppT, EColumnType ColumnT>
class RColumnElement : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = false;
   explicit RColumnElement(CppT* value) : RColumnElementBase(value, sizeof(CppT), kIsMappable)
   {
      static_assert(sizeof(CppT) != sizeof(CppT), "No column mapping for this C++ type");
   }
};

template <>
class RColumnElement<float, EColumnType::kReal32> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(float);
   explicit RColumnElement(float* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<double, EColumnType::kReal64> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(double);
   explicit RColumnElement(double* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<std::int32_t, EColumnType::kInt32> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(std::int32_t);
   explicit RColumnElement(std::int32_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<std::uint32_t, EColumnType::kInt32> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(std::uint32_t);
   explicit RColumnElement(std::uint32_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<std::int64_t, EColumnType::kInt64> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(std::int64_t);
   explicit RColumnElement(std::int64_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<std::uint64_t, EColumnType::kInt64> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(std::uint64_t);
   explicit RColumnElement(std::uint64_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<ClusterSize_t, EColumnType::kIndex> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(ROOT::Experimental::ClusterSize_t);
   explicit RColumnElement(ClusterSize_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<char, EColumnType::kByte> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(char);
   explicit RColumnElement(char* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

} // namespace Detail
} // namespace Experimental
} // namespace ROOT

#endif
<commit_msg>[ntuple] fix silently removed move assignment in RColumnElement<commit_after>/// \file ROOT/RColumnElement.hxx
/// \ingroup NTuple ROOT7
/// \author Jakob Blomer <jblomer@cern.ch>
/// \date 2018-10-09
/// \warning This is part of the ROOT 7 prototype! It will change without notice. It might trigger earthquakes. Feedback
/// is welcome!

/*************************************************************************
 * Copyright (C) 1995-2019, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

#ifndef ROOT7_RColumnElement
#define ROOT7_RColumnElement

#include <ROOT/RColumnModel.hxx>
#include <ROOT/RNTupleUtil.hxx>

#include <cstring> // for memcpy
#include <type_traits>

namespace ROOT {
namespace Experimental {

namespace Detail {

// clang-format off
/**
\class ROOT::Experimental::Detail::RColumnElement
\ingroup NTuple
\brief A column element points either to the content of an RFieldValue or into a memory mapped page.

The content pointed to by fRawContent can be a single element or the first element of an array.
Usually the on-disk element should map bitwise to the in-memory element. Sometimes that's not the case
though, for instance on big endian platforms and for exotic physical columns like 8 bit float.

This class does not provide protection around the raw pointer, fRawContent has to be managed correctly
by the user of this class.
*/
// clang-format on
class RColumnElementBase {
protected:
   /// Points to valid C++ data, either a single value or an array of values
   void* fRawContent;
   /// Size of the C++ value pointed to by fRawContent (not necessarily equal to the on-disk element size)
   unsigned int fSize;

   /// Indicates that *fRawContent is bitwise identical to the physical column element
   bool fIsMappable;

   virtual void DoSerialize(void* /* destination */, std::size_t /*count*/) const { }
   virtual void DoDeserialize(void* /* source */, std::size_t /*count*/) const { }

public:
   RColumnElementBase()
     : fRawContent(nullptr)
     , fSize(0)
     , fIsMappable(false)
   {}
   RColumnElementBase(void* rawContent, unsigned int size, bool isMappable)
     : fRawContent(rawContent)
     , fSize(size)
     , fIsMappable(isMappable)
   {}
   RColumnElementBase(const RColumnElementBase &elemArray, std::size_t at)
     : fRawContent(static_cast<unsigned char *>(elemArray.fRawContent) + elemArray.fSize * at)
     , fSize(elemArray.fSize)
     , fIsMappable(elemArray.fIsMappable)
   {}
   RColumnElementBase(const RColumnElementBase& other) = default;
   RColumnElementBase(RColumnElementBase&& other) = default;
   RColumnElementBase& operator =(const RColumnElementBase& other) = delete;
   RColumnElementBase& operator =(RColumnElementBase&& other) = default;
   virtual ~RColumnElementBase() = default;

   void Serialize(void *destination, std::size_t count) const {
     if (!fIsMappable) {
       DoSerialize(destination, count);
       return;
     }
     std::memcpy(destination, fRawContent, fSize * count);
   }

   void Deserialize(void *source, std::size_t count) {
     if (!fIsMappable) {
       DoDeserialize(source, count);
       return;
     }
     std::memcpy(fRawContent, source, fSize * count);
   }

   void* GetRawContent() const { return fRawContent; }
   unsigned int GetSize() const { return fSize; }
};

/**
 * Pairs of C++ type and column type, like float and EColumnType::kReal32
 */
template <typename CppT, EColumnType ColumnT>
class RColumnElement : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = false;
   explicit RColumnElement(CppT* value) : RColumnElementBase(value, sizeof(CppT), kIsMappable)
   {
      static_assert(sizeof(CppT) != sizeof(CppT), "No column mapping for this C++ type");
   }
};

template <>
class RColumnElement<float, EColumnType::kReal32> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(float);
   explicit RColumnElement(float* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<double, EColumnType::kReal64> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(double);
   explicit RColumnElement(double* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<std::int32_t, EColumnType::kInt32> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(std::int32_t);
   explicit RColumnElement(std::int32_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<std::uint32_t, EColumnType::kInt32> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(std::uint32_t);
   explicit RColumnElement(std::uint32_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<std::int64_t, EColumnType::kInt64> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(std::int64_t);
   explicit RColumnElement(std::int64_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<std::uint64_t, EColumnType::kInt64> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(std::uint64_t);
   explicit RColumnElement(std::uint64_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<ClusterSize_t, EColumnType::kIndex> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(ROOT::Experimental::ClusterSize_t);
   explicit RColumnElement(ClusterSize_t* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

template <>
class RColumnElement<char, EColumnType::kByte> : public RColumnElementBase {
public:
   static constexpr bool kIsMappable = true;
   static constexpr size_t kSize = sizeof(char);
   explicit RColumnElement(char* value) : RColumnElementBase(value, kSize, kIsMappable) {}
};

} // namespace Detail
} // namespace Experimental
} // namespace ROOT

#endif
<|endoftext|>


<commit_before>#include "layers/weight.h"

namespace marian {

Ptr<WeightingBase> WeightingFactory(Ptr<Options> options) {
  if(options->has("data-weighting"))
    return New<DataWeighting>(options->get<std::string>("data-weighting-type"));
}

Expr DataWeighting::getWeights(Ptr<ExpressionGraph> graph,
                               Ptr<data::CorpusBatch> batch) {
  ABORT_IF(batch->getDataWeights().empty(),
           "Vector of weights is unexpectedly empty!");
  bool sentenceWeighting = weightingType_ == "sentence";
  int dimBatch = batch->size();
  int dimWords = sentenceWeighting ? 1 : batch->back()->batchWidth();
  auto weights = graph->constant({1, dimWords, dimBatch, 1},
                                 inits::from_vector(batch->getDataWeights()));
  return weights;
}
}
<commit_msg>fix compiler warning for unreturned value<commit_after>#include "layers/weight.h"

namespace marian {

Ptr<WeightingBase> WeightingFactory(Ptr<Options> options) {
  ABORT_IF(!options->has("data-weighting"), "No data-weigting specified in options");
  return New<DataWeighting>(options->get<std::string>("data-weighting-type"));
}

Expr DataWeighting::getWeights(Ptr<ExpressionGraph> graph,
                               Ptr<data::CorpusBatch> batch) {
  ABORT_IF(batch->getDataWeights().empty(),
           "Vector of weights is unexpectedly empty!");
  bool sentenceWeighting = weightingType_ == "sentence";
  int dimBatch = batch->size();
  int dimWords = sentenceWeighting ? 1 : batch->back()->batchWidth();
  auto weights = graph->constant({1, dimWords, dimBatch, 1},
                                 inits::from_vector(batch->getDataWeights()));
  return weights;
}
}
<|endoftext|>


<commit_before>//file: NisaBuzzer.h
//Author: Malte "mkalte" Kieling
//note: Header Holding the class that communicates with the Buzzers of the NiSaCon Buzzer Sytem

#pragma once

//if you want to use another version of the asio lib or just use the one distributed with your system, define NISABUZZER_DIFFERENT_ASIO_LOCATION
//example: #define NISABUZZER_DIFFERENT_ASIO_LOCATION <asio/asio.hpp>
#define ASIO_STANDALONE
#ifdef NISABUZZER_DIFFERENT_ASIO_LOCATION
#include NISABUZZER_DIFFERENT_ASIO_LOCATION
#else
#include "./asio-1.10.6/include/asio.hpp"
#endif

//includes
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <functional>

//namespace: NiseBuzzer
//note: Holds all classes, functions, ... for the NisaBuzzer lib
namespace NisaBuzzer
{
	//const var: BUZZER_BAUD_RATE
	//note: the baud rate of the buzzer system is fixed with the hardware
	const unsigned int BUZZER_BAUD_RATE = 38400;

	//class: BuzzerException
	//note: Exception thrown on critical errors with the Buzzer System
	class BuzzerException
	{
	public:
		BuzzerException() {}
		BuzzerException(const char* whatStringText) : whatString(whatStringText) { }
		~BuzzerException() throw() {};

		void SetWhat(const char* newWhatString) { whatString = newWhatString; }
		virtual const char* what(void) const throw() {
			return whatString;
		};

	private:
		const char* whatString;
	};

	//class: BuzzerEventHandler
	//note: Events caused by BuzzerManager can be handled with this class
	class BuzzerEventHandler
	{
	public:
		//typedef: EventHandlerFunction
		//note: Parameter 1 is the type of the event, parameter 2 the events parameter.
		typedef std::function<void(int,int)> EventHandlerFunction;

		//constructor: BuzzerEventHandler
		//note: Creates an empty BuzzerEventHandler. HandlerFunc still must be set with SetHandlerFunction
		BuzzerEventHandler()
			: handler()
		{
			id = maxId()++;
		}

		//constructor: BuzzerEventHandler
		//note: Creates an BuzzerEventHandler with a handlerFunc
		BuzzerEventHandler(EventHandlerFunction f)
			: handler(f)
		{
			id = maxId()++;
		}

		//copy constructor: BuzzerEventHandler
		//note: Copy Constructor
		BuzzerEventHandler(const BuzzerEventHandler& h)
		{
			if(&h!=this) {
				this->handler=h.handler;
				this->id=h.id;
			}
		}

		//destructor: ~BuzzerEventHandler
		//note: does nothing cause nothing needs to be done
		~BuzzerEventHandler()
		{
		}

		//function: SetHandlerFunction
		//note: Sets the handlers function - called when the () operator is called by BuzzerManager
		//param: 	f: function to set
		void SetHandlerFunction(EventHandlerFunction f)
		{
			handler=f;
		}

		//operator: ()
		//note: calles the hander-func of this handler if availble
		void operator()(int type, int arg) const
		{
			if(handler) {
				handler(type,arg);
			}
		}
		//operatpr: ==
		//note: compares the handler-funcs (ids cause you cant compare std::function)
		bool operator==(const BuzzerEventHandler&h) const
		{
			return (this->id==h.id);
		}
		bool operator!=(const BuzzerEventHandler&h) const { return !((*this)==h); }

	private:
		//var: handler. The Handlerfunc for this handler
		EventHandlerFunction handler;
		//var: id. Id of this handler. Used to assignt the handler-functions to handlers since std::function cannot be compared.
		unsigned int 		id;

		static int& maxId ()
		{ static int id= 0; return id; }

	};

	//class: BuzzerManager
	//note: Manages the communication with the buzzers and also fires events
	class BuzzerManager
	{
	public:
		//subclass: Event
		//note: class that holds the type and the param of an event. is basically a container
		class Event {
		public:
			//enum: Event
			//note: Events that can be caused
			enum EventType {
				EVENT_ARM = 0,	//param is 0
				EVENT_FULL_RESET,	//param is 0
				EVENT_PARTIAL_RESET, //param is 0
				EVENT_TRIGGER,  //param is id of the button triggerd
				EVENT_TILT,		//param is id of the button that should not have been pressed
				NUM_EVENTS		//not an event
			};

			int type;
			int param;
		};

		//constructor: BuzzerManager
		//note: Creates a BuzzzerManager, searching for the buzzer hardware at the givn port
		//param:	portname: the serial port with the hardware
		BuzzerManager(std::string portname)
			: isRunning(false), ioService(), port(ioService), enableThreadedEvents(false), hwVersion(0),swVersionMayor(0), swVersionMinor(0)
		{
			port.open(portname);
			port.set_option(asio::serial_port::baud_rate(BUZZER_BAUD_RATE));
			port.set_option(asio::serial_port::stop_bits(asio::serial_port::stop_bits::one));
			port.set_option(asio::serial_port::parity(asio::serial_port::parity::none));
			port.set_option(asio::serial_port::character_size(asio::serial_port::character_size(8)));
			if(!port.is_open()) {
				throw BuzzerException("Cannot open port!");
			}
			isRunning = true;
			try {
				sendThread = std::thread(&BuzzerManager::SendThread, this);
				recvThread = std::thread(&BuzzerManager::RecvThread, this);
				eventThread = std::thread(&BuzzerManager::EventThread, this);
			}
			catch (...) {
				throw BuzzerException("Cannot start worker threads!");
			}
			InitBuzzers();
		}

		//destructor: BuzzerManager
		//note: destroys the buzzer manager
		~BuzzerManager()
		{
			PutByte('I');
			isRunning = false;

			sendThread.join();
			recvThread.join();
		}

		//function: InitBuzzers
		//note: Sends the Init signal to the buzzer. Can be called anytime for a full reset
		void InitBuzzers()
		{
			PutByte('I');
		}

		//function: SetEnableThreadedEvents
		//note: if set to true, there is no need to call Update anymore sine that is handled from the EventThread.
		//		usefull if the events can be called anytime. If, at the time this is enabled, there are events left in the eventqueue, they are fired!
		//param:	b: if true, enables the mutlithreded events
		void SetEnableThreadedEvents(bool b)
		{
			eventMutex.lock();
			enableThreadedEvents = b;
			if(enableThreadedEvents) {
				while(!eventQueue.empty()) {
					auto e = eventQueue.front();
					for(auto h : eventHandlers) {
						h(e.type, e.param);
					}
					eventQueue.pop();
				}
			}
			eventMutex.unlock();
		}

		//function: Update
		//note: Updates the Manager, calling event handlers. Not needed if SetEnableThreadedEvents is true
		void Update()
		{
			if(!enableThreadedEvents) {
				eventMutex.lock();
				while(!eventQueue.empty()) {
					auto e = eventQueue.front();
					for(auto h : eventHandlers) {
						h(e.type, e.param);
					}
					eventQueue.pop();
					}
				eventMutex.unlock();
			}
		}

		//function: Arm
		//note: "Arms"(=activates) the buzzers so they can fire a trigger event
		void Arm()
		{
			PutByte('A');
			FireEvent(Event::EventType::EVENT_ARM, 0);
		}

		//function: Reset
		//note: Resets the buzzers blocking the buzzer that was pressed recently
		void Reset()
		{
			PutByte('r');
			FireEvent(Event::EventType::EVENT_PARTIAL_RESET, 0);
		}

		//function: FullReset
		//note: resets all buzzers
		void FullReset()
		{
			PutByte('R');
			FireEvent(Event::EventType::EVENT_FULL_RESET, 0);
		}

		//function: AddEventHandler
		//note: 	adds a BuzzerEventHandler
		//param:	h: the handler to add
		void AddEventHandler(BuzzerEventHandler h)
		{
			eventMutex.lock();
			//see if we already know this handler, if yes, just update it
			for(auto i = eventHandlers.begin();i<eventHandlers.end();i++) {
				if ((*i)==h) {
					(*i)=h;
					eventMutex.unlock();
					return;
				}
			}
			eventHandlers.push_back(h);
			eventMutex.unlock();
		}

		//function: RemoveEventHandler
		//note: removes a handler from the manager
		//param: h: the handler to remove
		void RemoveEventHandler(BuzzerEventHandler h)
		{
			for(auto i = eventHandlers.begin();i<eventHandlers.end();i++) {
				if ((*i)==h) {
					eventMutex.lock();
					eventHandlers.erase(i);
					eventMutex.unlock();
					return;
				}
			}
		}

	//this protected-block holds all functions to communicate with the serial port and the event-protocol-foo
	protected:
		//function: PutBytes
		//note: sends bytes to the ports send-queue
		//param:	bytes: std::vecor with the bytes to send
		void PutBytes(std::vector<unsigned char> bytes)
		{
			sendMutex.lock();
			for(auto b : bytes) {
				toSend.push(b);
			}
			sendMutex.unlock();
		}
		//function: PutByte
		//note: sends a single byte to the ports send-queue
		//param		byte: data to send
		void PutByte(unsigned char byte)
		{
			sendMutex.lock();
			toSend.push(byte);
			sendMutex.unlock();
		}

		//function: SendThread
		//note: Worker that puts data on the serial port
		void SendThread()
		{
			while(isRunning) {
				if(!toSend.empty()) {
					sendMutex.lock();
					while(!toSend.empty()) {
						unsigned char c = toSend.front();
						port.write_some(asio::buffer(&c,1));
						toSend.pop();
					}
					sendMutex.unlock();
				}
			}
		}

		//function: RecvThread
		//note: Worker that reads data from the serial port
		void RecvThread()
		{
			while(isRunning) {
				unsigned char c;
				port.read_some(asio::buffer(&c,1));
				recvMutex.lock();
				toRead.push(c);
				recvMutex.unlock();
			}
		}

		//function: FireEvent
		//note: Fires an event
		//param:	event: Should be one of BuzzerManager::Event
		//			param: see BuzzerManager::Event what param is for each event
		void FireEvent(int event, int param)
		{
			eventMutex.lock();
			if(enableThreadedEvents) {
				for(auto h : eventHandlers) {
					h(event,param);
				}
			}
			else {
				Event e;
				e.type = event;
				e.param = param;
				eventQueue.push(e);
			}
			eventMutex.unlock();
		}

		//function: EventThread
		//note: manages the events.
		void EventThread()
		{
			while(isRunning) {
				if(!toRead.empty()) {
					recvMutex.lock();
					unsigned char c = toRead.front();
					recvMutex.unlock();
					//is this the init-message?
					if(c=='H') {
						//we expect toRead to be size 6 or bigger, otherwise the init message isnt complete
						if(toRead.size()>=6) {
							recvMutex.lock();
							char hwChar, swMinorChar, swMayorChar;
							toRead.pop();
							hwChar = toRead.front();
							toRead.pop();toRead.pop();
							swMayorChar = toRead.front();
							toRead.pop();toRead.pop();
							swMinorChar = toRead.front();
							toRead.pop();
							recvMutex.unlock();
							hwVersion = hwChar - '0';
							swVersionMayor = swMayorChar - '0';
							swVersionMinor = swMinorChar - '0';
						}
					}
					//if c is a number, that means a buzzer is triggerd
					else if(c>='0' && c<= '9') {
						FireEvent(Event::EventType::EVENT_TRIGGER, c-'0');
						recvMutex.lock();
						toRead.pop();
						recvMutex.unlock();
					}
					//if its tilt, expect size to be >=2 since next byte is the id of the error-triggerd buzzer
					else if(c=='T') {
						if(toRead.size()>=2) {
							recvMutex.lock();
							toRead.pop();
							unsigned char param = toRead.front();
							toRead.pop();
							recvMutex.unlock();
							FireEvent(Event::EventType::EVENT_TILT,param);
						}
					}
					//otherwise this byte is incorrect, just drop it
					else {
						recvMutex.lock();
						toRead.pop();
						recvMutex.unlock();
					}
				}
			}
		}

	private:
		//var: isRunning. true if the Manager is running, false if not
		bool isRunning;

		//var: io_service. needed for port
		asio::io_service 	ioService;
		//var: port. Port for the serial communication
		asio::serial_port 	port;

		//var: toSend. The send Queue. Every byte here will be put on the serial port
		std::queue<unsigned char> 	toSend;
		//var: toRead. The read Queue. Ever byte from the serial port ends up here
		std::queue<unsigned char>	toRead;

		//var: sendThread. the Thread that writes to  the serial port
		std::thread					sendThread;
		//var: sendMutex. the mutex loced so toSend dosn't explode
		std::recursive_mutex		sendMutex;
		//var: recvThread. the thread that reads from the serial port
		std::thread					recvThread;
		//var: recvMutex. the Mutex loced so toRead dosn't explode
		std::recursive_mutex		recvMutex;
		//var: eventThread. the thread that handlers the events
		std::thread					eventThread;
		//var: evntMutex. the mutex that maks shure eventHandlers dosnt explode
		std::recursive_mutex		eventMutex;

		//var: enableThreadedEvents. enables threaded events
		bool						enableThreadedEvents;
		//var: eventHandlers. EventHandlers
		std::vector<BuzzerEventHandler> 	eventHandlers;
		//var: eventQueue. the queue of the events to fire
		std::queue<Event>					eventQueue;

		//var: hwVersion. version of the hardware
		unsigned int hwVersion;
		//var: swVersionMayor. mayor version of the software on the device
		unsigned int swVersionMayor;
		//var: swVersionMinor. minor version of the software on the device
		unsigned int swVersionMinor;
	};

}; //namespace NisaBuzzer

<commit_msg>fixed error with chrono and clang<commit_after>//file: NisaBuzzer.h
//Author: Malte "mkalte" Kieling
//note: Header Holding the class that communicates with the Buzzers of the NiSaCon Buzzer Sytem

#pragma once

//if you want to use another version of the asio lib or just use the one distributed with your system, define NISABUZZER_DIFFERENT_ASIO_LOCATION
//example: #define NISABUZZER_DIFFERENT_ASIO_LOCATION <asio/asio.hpp>
#define ASIO_STANDALONE
#define ASIO_HAS_STD_CHRONO
#ifdef NISABUZZER_DIFFERENT_ASIO_LOCATION
#include NISABUZZER_DIFFERENT_ASIO_LOCATION
#else
#include "./asio-1.10.6/include/asio.hpp"
#endif

//includes
#include <iostream>
#include <string>
#include <vector>
#include <queue>
#include <thread>
#include <mutex>
#include <functional>

//namespace: NiseBuzzer
//note: Holds all classes, functions, ... for the NisaBuzzer lib
namespace NisaBuzzer
{
	//const var: BUZZER_BAUD_RATE
	//note: the baud rate of the buzzer system is fixed with the hardware
	const unsigned int BUZZER_BAUD_RATE = 38400;

	//class: BuzzerException
	//note: Exception thrown on critical errors with the Buzzer System
	class BuzzerException
	{
	public:
		BuzzerException() {}
		BuzzerException(const char* whatStringText) : whatString(whatStringText) { }
		~BuzzerException() throw() {};

		void SetWhat(const char* newWhatString) { whatString = newWhatString; }
		virtual const char* what(void) const throw() {
			return whatString;
		};

	private:
		const char* whatString;
	};

	//class: BuzzerEventHandler
	//note: Events caused by BuzzerManager can be handled with this class
	class BuzzerEventHandler
	{
	public:
		//typedef: EventHandlerFunction
		//note: Parameter 1 is the type of the event, parameter 2 the events parameter.
		typedef std::function<void(int,int)> EventHandlerFunction;

		//constructor: BuzzerEventHandler
		//note: Creates an empty BuzzerEventHandler. HandlerFunc still must be set with SetHandlerFunction
		BuzzerEventHandler()
			: handler()
		{
			id = maxId()++;
		}

		//constructor: BuzzerEventHandler
		//note: Creates an BuzzerEventHandler with a handlerFunc
		BuzzerEventHandler(EventHandlerFunction f)
			: handler(f)
		{
			id = maxId()++;
		}

		//copy constructor: BuzzerEventHandler
		//note: Copy Constructor
		BuzzerEventHandler(const BuzzerEventHandler& h)
		{
			if(&h!=this) {
				this->handler=h.handler;
				this->id=h.id;
			}
		}

		//destructor: ~BuzzerEventHandler
		//note: does nothing cause nothing needs to be done
		~BuzzerEventHandler()
		{
		}

		//function: SetHandlerFunction
		//note: Sets the handlers function - called when the () operator is called by BuzzerManager
		//param: 	f: function to set
		void SetHandlerFunction(EventHandlerFunction f)
		{
			handler=f;
		}

		//operator: ()
		//note: calles the hander-func of this handler if availble
		void operator()(int type, int arg) const
		{
			if(handler) {
				handler(type,arg);
			}
		}
		//operatpr: ==
		//note: compares the handler-funcs (ids cause you cant compare std::function)
		bool operator==(const BuzzerEventHandler&h) const
		{
			return (this->id==h.id);
		}
		bool operator!=(const BuzzerEventHandler&h) const { return !((*this)==h); }

	private:
		//var: handler. The Handlerfunc for this handler
		EventHandlerFunction handler;
		//var: id. Id of this handler. Used to assignt the handler-functions to handlers since std::function cannot be compared.
		unsigned int 		id;

		static int& maxId ()
		{ static int id= 0; return id; }

	};

	//class: BuzzerManager
	//note: Manages the communication with the buzzers and also fires events
	class BuzzerManager
	{
	public:
		//subclass: Event
		//note: class that holds the type and the param of an event. is basically a container
		class Event {
		public:
			//enum: Event
			//note: Events that can be caused
			enum EventType {
				EVENT_ARM = 0,	//param is 0
				EVENT_FULL_RESET,	//param is 0
				EVENT_PARTIAL_RESET, //param is 0
				EVENT_TRIGGER,  //param is id of the button triggerd
				EVENT_TILT,		//param is id of the button that should not have been pressed
				NUM_EVENTS		//not an event
			};

			int type;
			int param;
		};

		//constructor: BuzzerManager
		//note: Creates a BuzzzerManager, searching for the buzzer hardware at the givn port
		//param:	portname: the serial port with the hardware
		BuzzerManager(std::string portname)
			: isRunning(false), ioService(), port(ioService), enableThreadedEvents(false), hwVersion(0),swVersionMayor(0), swVersionMinor(0)
		{
			port.open(portname);
			port.set_option(asio::serial_port::baud_rate(BUZZER_BAUD_RATE));
			port.set_option(asio::serial_port::stop_bits(asio::serial_port::stop_bits::one));
			port.set_option(asio::serial_port::parity(asio::serial_port::parity::none));
			port.set_option(asio::serial_port::character_size(asio::serial_port::character_size(8)));
			if(!port.is_open()) {
				throw BuzzerException("Cannot open port!");
			}
			isRunning = true;
			try {
				sendThread = std::thread(&BuzzerManager::SendThread, this);
				recvThread = std::thread(&BuzzerManager::RecvThread, this);
				eventThread = std::thread(&BuzzerManager::EventThread, this);
			}
			catch (...) {
				throw BuzzerException("Cannot start worker threads!");
			}
			InitBuzzers();
		}

		//destructor: BuzzerManager
		//note: destroys the buzzer manager
		~BuzzerManager()
		{
			PutByte('I');
			isRunning = false;

			sendThread.join();
			recvThread.join();
		}

		//function: InitBuzzers
		//note: Sends the Init signal to the buzzer. Can be called anytime for a full reset
		void InitBuzzers()
		{
			PutByte('I');
		}

		//function: SetEnableThreadedEvents
		//note: if set to true, there is no need to call Update anymore sine that is handled from the EventThread.
		//		usefull if the events can be called anytime. If, at the time this is enabled, there are events left in the eventqueue, they are fired!
		//param:	b: if true, enables the mutlithreded events
		void SetEnableThreadedEvents(bool b)
		{
			eventMutex.lock();
			enableThreadedEvents = b;
			if(enableThreadedEvents) {
				while(!eventQueue.empty()) {
					auto e = eventQueue.front();
					for(auto h : eventHandlers) {
						h(e.type, e.param);
					}
					eventQueue.pop();
				}
			}
			eventMutex.unlock();
		}

		//function: Update
		//note: Updates the Manager, calling event handlers. Not needed if SetEnableThreadedEvents is true
		void Update()
		{
			if(!enableThreadedEvents) {
				eventMutex.lock();
				while(!eventQueue.empty()) {
					auto e = eventQueue.front();
					for(auto h : eventHandlers) {
						h(e.type, e.param);
					}
					eventQueue.pop();
					}
				eventMutex.unlock();
			}
		}

		//function: Arm
		//note: "Arms"(=activates) the buzzers so they can fire a trigger event
		void Arm()
		{
			PutByte('A');
			FireEvent(Event::EventType::EVENT_ARM, 0);
		}

		//function: Reset
		//note: Resets the buzzers blocking the buzzer that was pressed recently
		void Reset()
		{
			PutByte('r');
			FireEvent(Event::EventType::EVENT_PARTIAL_RESET, 0);
		}

		//function: FullReset
		//note: resets all buzzers
		void FullReset()
		{
			PutByte('R');
			FireEvent(Event::EventType::EVENT_FULL_RESET, 0);
		}

		//function: AddEventHandler
		//note: 	adds a BuzzerEventHandler
		//param:	h: the handler to add
		void AddEventHandler(BuzzerEventHandler h)
		{
			eventMutex.lock();
			//see if we already know this handler, if yes, just update it
			for(auto i = eventHandlers.begin();i<eventHandlers.end();i++) {
				if ((*i)==h) {
					(*i)=h;
					eventMutex.unlock();
					return;
				}
			}
			eventHandlers.push_back(h);
			eventMutex.unlock();
		}

		//function: RemoveEventHandler
		//note: removes a handler from the manager
		//param: h: the handler to remove
		void RemoveEventHandler(BuzzerEventHandler h)
		{
			for(auto i = eventHandlers.begin();i<eventHandlers.end();i++) {
				if ((*i)==h) {
					eventMutex.lock();
					eventHandlers.erase(i);
					eventMutex.unlock();
					return;
				}
			}
		}

	//this protected-block holds all functions to communicate with the serial port and the event-protocol-foo
	protected:
		//function: PutBytes
		//note: sends bytes to the ports send-queue
		//param:	bytes: std::vecor with the bytes to send
		void PutBytes(std::vector<unsigned char> bytes)
		{
			sendMutex.lock();
			for(auto b : bytes) {
				toSend.push(b);
			}
			sendMutex.unlock();
		}
		//function: PutByte
		//note: sends a single byte to the ports send-queue
		//param		byte: data to send
		void PutByte(unsigned char byte)
		{
			sendMutex.lock();
			toSend.push(byte);
			sendMutex.unlock();
		}

		//function: SendThread
		//note: Worker that puts data on the serial port
		void SendThread()
		{
			while(isRunning) {
				if(!toSend.empty()) {
					sendMutex.lock();
					while(!toSend.empty()) {
						unsigned char c = toSend.front();
						port.write_some(asio::buffer(&c,1));
						toSend.pop();
					}
					sendMutex.unlock();
				}
			}
		}

		//function: RecvThread
		//note: Worker that reads data from the serial port
		void RecvThread()
		{
			while(isRunning) {
				unsigned char c;
				port.read_some(asio::buffer(&c,1));
				recvMutex.lock();
				toRead.push(c);
				recvMutex.unlock();
			}
		}

		//function: FireEvent
		//note: Fires an event
		//param:	event: Should be one of BuzzerManager::Event
		//			param: see BuzzerManager::Event what param is for each event
		void FireEvent(int event, int param)
		{
			eventMutex.lock();
			if(enableThreadedEvents) {
				for(auto h : eventHandlers) {
					h(event,param);
				}
			}
			else {
				Event e;
				e.type = event;
				e.param = param;
				eventQueue.push(e);
			}
			eventMutex.unlock();
		}

		//function: EventThread
		//note: manages the events.
		void EventThread()
		{
			while(isRunning) {
				if(!toRead.empty()) {
					recvMutex.lock();
					unsigned char c = toRead.front();
					recvMutex.unlock();
					//is this the init-message?
					if(c=='H') {
						//we expect toRead to be size 6 or bigger, otherwise the init message isnt complete
						if(toRead.size()>=6) {
							recvMutex.lock();
							char hwChar, swMinorChar, swMayorChar;
							toRead.pop();
							hwChar = toRead.front();
							toRead.pop();toRead.pop();
							swMayorChar = toRead.front();
							toRead.pop();toRead.pop();
							swMinorChar = toRead.front();
							toRead.pop();
							recvMutex.unlock();
							hwVersion = hwChar - '0';
							swVersionMayor = swMayorChar - '0';
							swVersionMinor = swMinorChar - '0';
						}
					}
					//if c is a number, that means a buzzer is triggerd
					else if(c>='0' && c<= '9') {
						FireEvent(Event::EventType::EVENT_TRIGGER, c-'0');
						recvMutex.lock();
						toRead.pop();
						recvMutex.unlock();
					}
					//if its tilt, expect size to be >=2 since next byte is the id of the error-triggerd buzzer
					else if(c=='T') {
						if(toRead.size()>=2) {
							recvMutex.lock();
							toRead.pop();
							unsigned char param = toRead.front();
							toRead.pop();
							recvMutex.unlock();
							FireEvent(Event::EventType::EVENT_TILT,param);
						}
					}
					//otherwise this byte is incorrect, just drop it
					else {
						recvMutex.lock();
						toRead.pop();
						recvMutex.unlock();
					}
				}
			}
		}

	private:
		//var: isRunning. true if the Manager is running, false if not
		bool isRunning;

		//var: io_service. needed for port
		asio::io_service 	ioService;
		//var: port. Port for the serial communication
		asio::serial_port 	port;

		//var: toSend. The send Queue. Every byte here will be put on the serial port
		std::queue<unsigned char> 	toSend;
		//var: toRead. The read Queue. Ever byte from the serial port ends up here
		std::queue<unsigned char>	toRead;

		//var: sendThread. the Thread that writes to  the serial port
		std::thread					sendThread;
		//var: sendMutex. the mutex loced so toSend dosn't explode
		std::recursive_mutex		sendMutex;
		//var: recvThread. the thread that reads from the serial port
		std::thread					recvThread;
		//var: recvMutex. the Mutex loced so toRead dosn't explode
		std::recursive_mutex		recvMutex;
		//var: eventThread. the thread that handlers the events
		std::thread					eventThread;
		//var: evntMutex. the mutex that maks shure eventHandlers dosnt explode
		std::recursive_mutex		eventMutex;

		//var: enableThreadedEvents. enables threaded events
		bool						enableThreadedEvents;
		//var: eventHandlers. EventHandlers
		std::vector<BuzzerEventHandler> 	eventHandlers;
		//var: eventQueue. the queue of the events to fire
		std::queue<Event>					eventQueue;

		//var: hwVersion. version of the hardware
		unsigned int hwVersion;
		//var: swVersionMayor. mayor version of the software on the device
		unsigned int swVersionMayor;
		//var: swVersionMinor. minor version of the software on the device
		unsigned int swVersionMinor;
	};

}; //namespace NisaBuzzer

<|endoftext|>


<commit_before>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
#include "Options.h"
#include "utils/ScopeGuard.h"

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <thread>
#include <util.h>
#include <vector>

#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) ||     \
    defined(__CYGWIN__)
#include <io.h> /* _isatty */
#define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
#else
#if defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) ||                      \
    defined(_POSIX_SOURCE) ||                                                  \
    (defined(__APPLE__) &&                                                     \
     defined(                                                                  \
         __MACH__)) /* https://sourceforge.net/p/predef/wiki/OperatingSystems/ \
                       */
#include <unistd.h> /* isatty */
#define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
#else
#define IS_CONSOLE(stdStream) 0
#endif
#endif

namespace pzstd {

namespace {
unsigned defaultNumThreads() {
#ifdef PZSTD_NUM_THREADS
  return PZSTD_NUM_THREADS;
#else
  return std::thread::hardware_concurrency();
#endif
}

unsigned parseUnsigned(const char **arg) {
  unsigned result = 0;
  while (**arg >= '0' && **arg <= '9') {
    result *= 10;
    result += **arg - '0';
    ++(*arg);
  }
  return result;
}

const char *getArgument(const char *options, const char **argv, int &i,
                        int argc) {
  if (options[1] != 0) {
    return options + 1;
  }
  ++i;
  if (i == argc) {
    std::fprintf(stderr, "Option -%c requires an argument, but none provided\n",
                 *options);
    return nullptr;
  }
  return argv[i];
}

const std::string kZstdExtension = ".zst";
constexpr char kStdIn[] = "-";
constexpr char kStdOut[] = "-";
constexpr unsigned kDefaultCompressionLevel = 3;
constexpr unsigned kMaxNonUltraCompressionLevel = 19;

#ifdef _WIN32
const char nullOutput[] = "nul";
#else
const char nullOutput[] = "/dev/null";
#endif

void notSupported(const char *option) {
  std::fprintf(stderr, "Operation not supported: %s\n", option);
}

void usage() {
  std::fprintf(stderr, "Usage:\n");
  std::fprintf(stderr, "  pzstd [args] [FILE(s)]\n");
  std::fprintf(stderr, "Parallel ZSTD options:\n");
  std::fprintf(stderr, "  -p, --processes   #    : number of threads to use for (de)compression (default:%d)\n", defaultNumThreads());

  std::fprintf(stderr, "ZSTD options:\n");
  std::fprintf(stderr, "  -#                     : # compression level (1-%d, default:%d)\n", kMaxNonUltraCompressionLevel, kDefaultCompressionLevel);
  std::fprintf(stderr, "  -d, --decompress       : decompression\n");
  std::fprintf(stderr, "  -o                file : result stored into `file` (only if 1 input file)\n");
  std::fprintf(stderr, "  -f, --force            : overwrite output without prompting\n");
  std::fprintf(stderr, "      --rm               : remove source file(s) after successful (de)compression\n");
  std::fprintf(stderr, "  -k, --keep             : preserve source file(s) (default)\n");
  std::fprintf(stderr, "  -h, --help             : display help and exit\n");
  std::fprintf(stderr, "  -V, --version          : display version number and exit\n");
  std::fprintf(stderr, "  -v, --verbose          : verbose mode; specify multiple times to increase log level (default:2)\n");
  std::fprintf(stderr, "  -q, --quiet            : suppress warnings; specify twice to suppress errors too\n");
  std::fprintf(stderr, "  -c, --stdout           : force wrtie to standard output, even if it is the console\n");
#ifdef UTIL_HAS_CREATEFILELIST
  std::fprintf(stderr, "  -r                     : operate recursively on directories\n");
#endif
  std::fprintf(stderr, "      --ultra            : enable levels beyond %i, up to %i (requires more memory)\n", kMaxNonUltraCompressionLevel, ZSTD_maxCLevel());
  std::fprintf(stderr, "  -C, --check            : integrity check (default)\n");
  std::fprintf(stderr, "      --no-check         : no integrity check\n");
  std::fprintf(stderr, "  -t, --test             : test compressed file integrity\n");
  std::fprintf(stderr, "  --                     : all arguments after \"--\" are treated as files\n");
}
} // anonymous namespace

Options::Options()
    : numThreads(defaultNumThreads()), maxWindowLog(23),
      compressionLevel(kDefaultCompressionLevel), decompress(false),
      overwrite(false), keepSource(true), writeMode(WriteMode::Auto),
      checksum(true), verbosity(2) {}

Options::Status Options::parse(int argc, const char **argv) {
  bool test = false;
  bool recursive = false;
  bool ultra = false;
  bool forceStdout = false;
  // Local copy of input files, which are pointers into argv.
  std::vector<const char *> localInputFiles;
  for (int i = 1; i < argc; ++i) {
    const char *arg = argv[i];
    // Protect against empty arguments
    if (arg[0] == 0) {
      continue;
    }
    // Everything after "--" is an input file
    if (!std::strcmp(arg, "--")) {
      ++i;
      std::copy(argv + i, argv + argc, std::back_inserter(localInputFiles));
      break;
    }
    // Long arguments that don't have a short option
    {
      bool isLongOption = true;
      if (!std::strcmp(arg, "--rm")) {
        keepSource = false;
      } else if (!std::strcmp(arg, "--ultra")) {
        ultra = true;
        maxWindowLog = 0;
      } else if (!std::strcmp(arg, "--no-check")) {
        checksum = false;
      } else if (!std::strcmp(arg, "--sparse")) {
        writeMode = WriteMode::Sparse;
        notSupported("Sparse mode");
        return Status::Failure;
      } else if (!std::strcmp(arg, "--no-sparse")) {
        writeMode = WriteMode::Regular;
        notSupported("Sparse mode");
        return Status::Failure;
      } else if (!std::strcmp(arg, "--dictID")) {
        notSupported(arg);
        return Status::Failure;
      } else if (!std::strcmp(arg, "--no-dictID")) {
        notSupported(arg);
        return Status::Failure;
      } else {
        isLongOption = false;
      }
      if (isLongOption) {
        continue;
      }
    }
    // Arguments with a short option simply set their short option.
    const char *options = nullptr;
    if (!std::strcmp(arg, "--processes")) {
      options = "p";
    } else if (!std::strcmp(arg, "--version")) {
      options = "V";
    } else if (!std::strcmp(arg, "--help")) {
      options = "h";
    } else if (!std::strcmp(arg, "--decompress")) {
      options = "d";
    } else if (!std::strcmp(arg, "--force")) {
      options = "f";
    } else if (!std::strcmp(arg, "--stdout")) {
      options = "c";
    } else if (!std::strcmp(arg, "--keep")) {
      options = "k";
    } else if (!std::strcmp(arg, "--verbose")) {
      options = "v";
    } else if (!std::strcmp(arg, "--quiet")) {
      options = "q";
    } else if (!std::strcmp(arg, "--check")) {
      options = "C";
    } else if (!std::strcmp(arg, "--test")) {
      options = "t";
    } else if (arg[0] == '-' && arg[1] != 0) {
      options = arg + 1;
    } else {
      localInputFiles.emplace_back(arg);
      continue;
    }
    assert(options != nullptr);

    bool finished = false;
    while (!finished && *options != 0) {
      // Parse the compression level
      if (*options >= '0' && *options <= '9') {
        compressionLevel = parseUnsigned(&options);
        continue;
      }

      switch (*options) {
      case 'h':
      case 'H':
        usage();
        return Status::Message;
      case 'V':
        std::fprintf(stderr, "PZSTD version: %s.\n", ZSTD_VERSION_STRING);
        return Status::Message;
      case 'p': {
        finished = true;
        const char *optionArgument = getArgument(options, argv, i, argc);
        if (optionArgument == nullptr) {
          return Status::Failure;
        }
        if (*optionArgument < '0' || *optionArgument > '9') {
          std::fprintf(stderr, "Option -p expects a number, but %s provided\n",
                       optionArgument);
          return Status::Failure;
        }
        numThreads = parseUnsigned(&optionArgument);
        if (*optionArgument != 0) {
          std::fprintf(stderr,
                       "Option -p expects a number, but %u%s provided\n",
                       numThreads, optionArgument);
          return Status::Failure;
        }
        break;
      }
      case 'o': {
        finished = true;
        const char *optionArgument = getArgument(options, argv, i, argc);
        if (optionArgument == nullptr) {
          return Status::Failure;
        }
        outputFile = optionArgument;
        break;
      }
      case 'C':
        checksum = true;
        break;
      case 'k':
        keepSource = true;
        break;
      case 'd':
        decompress = true;
        break;
      case 'f':
        overwrite = true;
        forceStdout = true;
        break;
      case 't':
        test = true;
        decompress = true;
        break;
#ifdef UTIL_HAS_CREATEFILELIST
      case 'r':
        recursive = true;
        break;
#endif
      case 'c':
        outputFile = kStdOut;
        forceStdout = true;
        break;
      case 'v':
        ++verbosity;
        break;
      case 'q':
        --verbosity;
        // Ignore them for now
        break;
      // Unsupported options from Zstd
      case 'D':
      case 's':
        notSupported("Zstd dictionaries.");
        return Status::Failure;
      case 'b':
      case 'e':
      case 'i':
      case 'B':
        notSupported("Zstd benchmarking options.");
        return Status::Failure;
      default:
        std::fprintf(stderr, "Invalid argument: -%c\n", *options);
        return Status::Failure;
      }
      if (!finished) {
        ++options;
      }
    } // while (*options != 0);
  }   // for (int i = 1; i < argc; ++i);

  // Input file defaults to standard input if not provided.
  if (localInputFiles.empty()) {
    localInputFiles.emplace_back(kStdIn);
  }

  // Check validity of input files
  if (localInputFiles.size() > 1) {
    const auto it = std::find(localInputFiles.begin(), localInputFiles.end(),
                              std::string{kStdIn});
    if (it != localInputFiles.end()) {
      std::fprintf(
          stderr,
          "Cannot specify standard input when handling multiple files\n");
      return Status::Failure;
    }
  }
  if (localInputFiles.size() > 1 || recursive) {
    if (!outputFile.empty() && outputFile != nullOutput) {
      std::fprintf(
          stderr,
          "Cannot specify an output file when handling multiple inputs\n");
      return Status::Failure;
    }
  }

  // Translate input files/directories into files to (de)compress
  if (recursive) {
    char *scratchBuffer = nullptr;
    unsigned numFiles = 0;
    const char **files =
        UTIL_createFileList(localInputFiles.data(), localInputFiles.size(),
                            &scratchBuffer, &numFiles);
    if (files == nullptr) {
      std::fprintf(stderr, "Error traversing directories\n");
      return Status::Failure;
    }
    auto guard =
        makeScopeGuard([&] { UTIL_freeFileList(files, scratchBuffer); });
    if (numFiles == 0) {
      std::fprintf(stderr, "No files found\n");
      return Status::Failure;
    }
    inputFiles.resize(numFiles);
    std::copy(files, files + numFiles, inputFiles.begin());
  } else {
    inputFiles.resize(localInputFiles.size());
    std::copy(localInputFiles.begin(), localInputFiles.end(),
              inputFiles.begin());
  }
  localInputFiles.clear();
  assert(!inputFiles.empty());

  // If reading from standard input, default to standard output
  if (inputFiles[0] == kStdIn && outputFile.empty()) {
    assert(inputFiles.size() == 1);
    outputFile = "-";
  }

  if (inputFiles[0] == kStdIn && IS_CONSOLE(stdin)) {
    assert(inputFiles.size() == 1);
    std::fprintf(stderr, "Cannot read input from interactive console\n");
    return Status::Failure;
  }
  if (outputFile == "-" && IS_CONSOLE(stdout) && !(forceStdout && decompress)) {
    std::fprintf(stderr, "Will not write to console stdout unless -c or -f is "
                         "specified and decompressing\n");
    return Status::Failure;
  }

  // Check compression level
  {
    unsigned maxCLevel =
        ultra ? ZSTD_maxCLevel() : kMaxNonUltraCompressionLevel;
    if (compressionLevel > maxCLevel || compressionLevel == 0) {
      std::fprintf(stderr, "Invalid compression level %u.\n", compressionLevel);
      return Status::Failure;
    }
  }

  // Check that numThreads is set
  if (numThreads == 0) {
    std::fprintf(stderr, "Invalid arguments: # of threads not specified "
                         "and unable to determine hardware concurrency.\n");
    return Status::Failure;
  }

  // Modify verbosity
  // If we are piping input and output, turn off interaction
  if (inputFiles[0] == kStdIn && outputFile == kStdOut && verbosity == 2) {
    verbosity = 1;
  }
  // If we are in multi-file mode, turn off interaction
  if (inputFiles.size() > 1 && verbosity == 2) {
    verbosity = 1;
  }

  // Set options for test mode
  if (test) {
    outputFile = nullOutput;
    keepSource = true;
  }
  return Status::Success;
}

std::string Options::getOutputFile(const std::string &inputFile) const {
  if (!outputFile.empty()) {
    return outputFile;
  }
  // Attempt to add/remove zstd extension from the input file
  if (decompress) {
    int stemSize = inputFile.size() - kZstdExtension.size();
    if (stemSize > 0 && inputFile.substr(stemSize) == kZstdExtension) {
      return inputFile.substr(0, stemSize);
    } else {
      return "";
    }
  } else {
    return inputFile + kZstdExtension;
  }
}
}
<commit_msg>[pzstd] Fix invalid argument message<commit_after>/**
 * Copyright (c) 2016-present, Facebook, Inc.
 * All rights reserved.
 *
 * This source code is licensed under the BSD-style license found in the
 * LICENSE file in the root directory of this source tree. An additional grant
 * of patent rights can be found in the PATENTS file in the same directory.
 */
#include "Options.h"
#include "utils/ScopeGuard.h"

#include <algorithm>
#include <cassert>
#include <cstdio>
#include <cstring>
#include <thread>
#include <util.h>
#include <vector>

#if defined(MSDOS) || defined(OS2) || defined(WIN32) || defined(_WIN32) ||     \
    defined(__CYGWIN__)
#include <io.h> /* _isatty */
#define IS_CONSOLE(stdStream) _isatty(_fileno(stdStream))
#else
#if defined(_POSIX_C_SOURCE) || defined(_XOPEN_SOURCE) ||                      \
    defined(_POSIX_SOURCE) ||                                                  \
    (defined(__APPLE__) &&                                                     \
     defined(                                                                  \
         __MACH__)) /* https://sourceforge.net/p/predef/wiki/OperatingSystems/ \
                       */
#include <unistd.h> /* isatty */
#define IS_CONSOLE(stdStream) isatty(fileno(stdStream))
#else
#define IS_CONSOLE(stdStream) 0
#endif
#endif

namespace pzstd {

namespace {
unsigned defaultNumThreads() {
#ifdef PZSTD_NUM_THREADS
  return PZSTD_NUM_THREADS;
#else
  return std::thread::hardware_concurrency();
#endif
}

unsigned parseUnsigned(const char **arg) {
  unsigned result = 0;
  while (**arg >= '0' && **arg <= '9') {
    result *= 10;
    result += **arg - '0';
    ++(*arg);
  }
  return result;
}

const char *getArgument(const char *options, const char **argv, int &i,
                        int argc) {
  if (options[1] != 0) {
    return options + 1;
  }
  ++i;
  if (i == argc) {
    std::fprintf(stderr, "Option -%c requires an argument, but none provided\n",
                 *options);
    return nullptr;
  }
  return argv[i];
}

const std::string kZstdExtension = ".zst";
constexpr char kStdIn[] = "-";
constexpr char kStdOut[] = "-";
constexpr unsigned kDefaultCompressionLevel = 3;
constexpr unsigned kMaxNonUltraCompressionLevel = 19;

#ifdef _WIN32
const char nullOutput[] = "nul";
#else
const char nullOutput[] = "/dev/null";
#endif

void notSupported(const char *option) {
  std::fprintf(stderr, "Operation not supported: %s\n", option);
}

void usage() {
  std::fprintf(stderr, "Usage:\n");
  std::fprintf(stderr, "  pzstd [args] [FILE(s)]\n");
  std::fprintf(stderr, "Parallel ZSTD options:\n");
  std::fprintf(stderr, "  -p, --processes   #    : number of threads to use for (de)compression (default:%d)\n", defaultNumThreads());

  std::fprintf(stderr, "ZSTD options:\n");
  std::fprintf(stderr, "  -#                     : # compression level (1-%d, default:%d)\n", kMaxNonUltraCompressionLevel, kDefaultCompressionLevel);
  std::fprintf(stderr, "  -d, --decompress       : decompression\n");
  std::fprintf(stderr, "  -o                file : result stored into `file` (only if 1 input file)\n");
  std::fprintf(stderr, "  -f, --force            : overwrite output without prompting\n");
  std::fprintf(stderr, "      --rm               : remove source file(s) after successful (de)compression\n");
  std::fprintf(stderr, "  -k, --keep             : preserve source file(s) (default)\n");
  std::fprintf(stderr, "  -h, --help             : display help and exit\n");
  std::fprintf(stderr, "  -V, --version          : display version number and exit\n");
  std::fprintf(stderr, "  -v, --verbose          : verbose mode; specify multiple times to increase log level (default:2)\n");
  std::fprintf(stderr, "  -q, --quiet            : suppress warnings; specify twice to suppress errors too\n");
  std::fprintf(stderr, "  -c, --stdout           : force wrtie to standard output, even if it is the console\n");
#ifdef UTIL_HAS_CREATEFILELIST
  std::fprintf(stderr, "  -r                     : operate recursively on directories\n");
#endif
  std::fprintf(stderr, "      --ultra            : enable levels beyond %i, up to %i (requires more memory)\n", kMaxNonUltraCompressionLevel, ZSTD_maxCLevel());
  std::fprintf(stderr, "  -C, --check            : integrity check (default)\n");
  std::fprintf(stderr, "      --no-check         : no integrity check\n");
  std::fprintf(stderr, "  -t, --test             : test compressed file integrity\n");
  std::fprintf(stderr, "  --                     : all arguments after \"--\" are treated as files\n");
}
} // anonymous namespace

Options::Options()
    : numThreads(defaultNumThreads()), maxWindowLog(23),
      compressionLevel(kDefaultCompressionLevel), decompress(false),
      overwrite(false), keepSource(true), writeMode(WriteMode::Auto),
      checksum(true), verbosity(2) {}

Options::Status Options::parse(int argc, const char **argv) {
  bool test = false;
  bool recursive = false;
  bool ultra = false;
  bool forceStdout = false;
  // Local copy of input files, which are pointers into argv.
  std::vector<const char *> localInputFiles;
  for (int i = 1; i < argc; ++i) {
    const char *arg = argv[i];
    // Protect against empty arguments
    if (arg[0] == 0) {
      continue;
    }
    // Everything after "--" is an input file
    if (!std::strcmp(arg, "--")) {
      ++i;
      std::copy(argv + i, argv + argc, std::back_inserter(localInputFiles));
      break;
    }
    // Long arguments that don't have a short option
    {
      bool isLongOption = true;
      if (!std::strcmp(arg, "--rm")) {
        keepSource = false;
      } else if (!std::strcmp(arg, "--ultra")) {
        ultra = true;
        maxWindowLog = 0;
      } else if (!std::strcmp(arg, "--no-check")) {
        checksum = false;
      } else if (!std::strcmp(arg, "--sparse")) {
        writeMode = WriteMode::Sparse;
        notSupported("Sparse mode");
        return Status::Failure;
      } else if (!std::strcmp(arg, "--no-sparse")) {
        writeMode = WriteMode::Regular;
        notSupported("Sparse mode");
        return Status::Failure;
      } else if (!std::strcmp(arg, "--dictID")) {
        notSupported(arg);
        return Status::Failure;
      } else if (!std::strcmp(arg, "--no-dictID")) {
        notSupported(arg);
        return Status::Failure;
      } else {
        isLongOption = false;
      }
      if (isLongOption) {
        continue;
      }
    }
    // Arguments with a short option simply set their short option.
    const char *options = nullptr;
    if (!std::strcmp(arg, "--processes")) {
      options = "p";
    } else if (!std::strcmp(arg, "--version")) {
      options = "V";
    } else if (!std::strcmp(arg, "--help")) {
      options = "h";
    } else if (!std::strcmp(arg, "--decompress")) {
      options = "d";
    } else if (!std::strcmp(arg, "--force")) {
      options = "f";
    } else if (!std::strcmp(arg, "--stdout")) {
      options = "c";
    } else if (!std::strcmp(arg, "--keep")) {
      options = "k";
    } else if (!std::strcmp(arg, "--verbose")) {
      options = "v";
    } else if (!std::strcmp(arg, "--quiet")) {
      options = "q";
    } else if (!std::strcmp(arg, "--check")) {
      options = "C";
    } else if (!std::strcmp(arg, "--test")) {
      options = "t";
    } else if (arg[0] == '-' && arg[1] != 0) {
      options = arg + 1;
    } else {
      localInputFiles.emplace_back(arg);
      continue;
    }
    assert(options != nullptr);

    bool finished = false;
    while (!finished && *options != 0) {
      // Parse the compression level
      if (*options >= '0' && *options <= '9') {
        compressionLevel = parseUnsigned(&options);
        continue;
      }

      switch (*options) {
      case 'h':
      case 'H':
        usage();
        return Status::Message;
      case 'V':
        std::fprintf(stderr, "PZSTD version: %s.\n", ZSTD_VERSION_STRING);
        return Status::Message;
      case 'p': {
        finished = true;
        const char *optionArgument = getArgument(options, argv, i, argc);
        if (optionArgument == nullptr) {
          return Status::Failure;
        }
        if (*optionArgument < '0' || *optionArgument > '9') {
          std::fprintf(stderr, "Option -p expects a number, but %s provided\n",
                       optionArgument);
          return Status::Failure;
        }
        numThreads = parseUnsigned(&optionArgument);
        if (*optionArgument != 0) {
          std::fprintf(stderr,
                       "Option -p expects a number, but %u%s provided\n",
                       numThreads, optionArgument);
          return Status::Failure;
        }
        break;
      }
      case 'o': {
        finished = true;
        const char *optionArgument = getArgument(options, argv, i, argc);
        if (optionArgument == nullptr) {
          return Status::Failure;
        }
        outputFile = optionArgument;
        break;
      }
      case 'C':
        checksum = true;
        break;
      case 'k':
        keepSource = true;
        break;
      case 'd':
        decompress = true;
        break;
      case 'f':
        overwrite = true;
        forceStdout = true;
        break;
      case 't':
        test = true;
        decompress = true;
        break;
#ifdef UTIL_HAS_CREATEFILELIST
      case 'r':
        recursive = true;
        break;
#endif
      case 'c':
        outputFile = kStdOut;
        forceStdout = true;
        break;
      case 'v':
        ++verbosity;
        break;
      case 'q':
        --verbosity;
        // Ignore them for now
        break;
      // Unsupported options from Zstd
      case 'D':
      case 's':
        notSupported("Zstd dictionaries.");
        return Status::Failure;
      case 'b':
      case 'e':
      case 'i':
      case 'B':
        notSupported("Zstd benchmarking options.");
        return Status::Failure;
      default:
        std::fprintf(stderr, "Invalid argument: %s\n", arg);
        return Status::Failure;
      }
      if (!finished) {
        ++options;
      }
    } // while (*options != 0);
  }   // for (int i = 1; i < argc; ++i);

  // Input file defaults to standard input if not provided.
  if (localInputFiles.empty()) {
    localInputFiles.emplace_back(kStdIn);
  }

  // Check validity of input files
  if (localInputFiles.size() > 1) {
    const auto it = std::find(localInputFiles.begin(), localInputFiles.end(),
                              std::string{kStdIn});
    if (it != localInputFiles.end()) {
      std::fprintf(
          stderr,
          "Cannot specify standard input when handling multiple files\n");
      return Status::Failure;
    }
  }
  if (localInputFiles.size() > 1 || recursive) {
    if (!outputFile.empty() && outputFile != nullOutput) {
      std::fprintf(
          stderr,
          "Cannot specify an output file when handling multiple inputs\n");
      return Status::Failure;
    }
  }

  // Translate input files/directories into files to (de)compress
  if (recursive) {
    char *scratchBuffer = nullptr;
    unsigned numFiles = 0;
    const char **files =
        UTIL_createFileList(localInputFiles.data(), localInputFiles.size(),
                            &scratchBuffer, &numFiles);
    if (files == nullptr) {
      std::fprintf(stderr, "Error traversing directories\n");
      return Status::Failure;
    }
    auto guard =
        makeScopeGuard([&] { UTIL_freeFileList(files, scratchBuffer); });
    if (numFiles == 0) {
      std::fprintf(stderr, "No files found\n");
      return Status::Failure;
    }
    inputFiles.resize(numFiles);
    std::copy(files, files + numFiles, inputFiles.begin());
  } else {
    inputFiles.resize(localInputFiles.size());
    std::copy(localInputFiles.begin(), localInputFiles.end(),
              inputFiles.begin());
  }
  localInputFiles.clear();
  assert(!inputFiles.empty());

  // If reading from standard input, default to standard output
  if (inputFiles[0] == kStdIn && outputFile.empty()) {
    assert(inputFiles.size() == 1);
    outputFile = "-";
  }

  if (inputFiles[0] == kStdIn && IS_CONSOLE(stdin)) {
    assert(inputFiles.size() == 1);
    std::fprintf(stderr, "Cannot read input from interactive console\n");
    return Status::Failure;
  }
  if (outputFile == "-" && IS_CONSOLE(stdout) && !(forceStdout && decompress)) {
    std::fprintf(stderr, "Will not write to console stdout unless -c or -f is "
                         "specified and decompressing\n");
    return Status::Failure;
  }

  // Check compression level
  {
    unsigned maxCLevel =
        ultra ? ZSTD_maxCLevel() : kMaxNonUltraCompressionLevel;
    if (compressionLevel > maxCLevel || compressionLevel == 0) {
      std::fprintf(stderr, "Invalid compression level %u.\n", compressionLevel);
      return Status::Failure;
    }
  }

  // Check that numThreads is set
  if (numThreads == 0) {
    std::fprintf(stderr, "Invalid arguments: # of threads not specified "
                         "and unable to determine hardware concurrency.\n");
    return Status::Failure;
  }

  // Modify verbosity
  // If we are piping input and output, turn off interaction
  if (inputFiles[0] == kStdIn && outputFile == kStdOut && verbosity == 2) {
    verbosity = 1;
  }
  // If we are in multi-file mode, turn off interaction
  if (inputFiles.size() > 1 && verbosity == 2) {
    verbosity = 1;
  }

  // Set options for test mode
  if (test) {
    outputFile = nullOutput;
    keepSource = true;
  }
  return Status::Success;
}

std::string Options::getOutputFile(const std::string &inputFile) const {
  if (!outputFile.empty()) {
    return outputFile;
  }
  // Attempt to add/remove zstd extension from the input file
  if (decompress) {
    int stemSize = inputFile.size() - kZstdExtension.size();
    if (stemSize > 0 && inputFile.substr(stemSize) == kZstdExtension) {
      return inputFile.substr(0, stemSize);
    } else {
      return "";
    }
  } else {
    return inputFile + kZstdExtension;
  }
}
}
<|endoftext|>