<commit_before>/*
 * TessuMod: Mod for integrating TeamSpeak into World of Tanks
 * Copyright (C) 2015  Janne Hakonen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "openalbackend.h"
#include "../entities/vector.h"
#include "../libs/openal.h"
#include "../utils/logging.h"

#include <AL/alext.h>

#include <QStandardPaths>
#include <QRegularExpression>
#include <QDir>

#include <iostream>

namespace
{
QMutex mutex;

const int AUDIO_FREQUENCY = 48000;

QString getAppdataPath()
{
	QString targetPath = QStandardPaths::standardLocations( QStandardPaths::GenericDataLocation )[0];
	return targetPath.replace( QRegularExpression( "Local$" ), "Roaming" );
}

QString getOALHRTFPath()
{
	QString targetPath = getAppdataPath() + "/openal/hrtf";
	QDir().mkpath( targetPath );
	return QDir::cleanPath( ( targetPath + "/default-%1.mhr" ).arg( AUDIO_FREQUENCY ) );
}

ALfloat tsVolumeModifierToOALGain( float tsVolumeModifier )
{
	return 1.0 / ( pow( 2.0, tsVolumeModifier / -6.0 ) );
}

}

namespace Driver
{

class OpenALBackendPrivate
{
public:
	OpenALBackendPrivate()
		: isEnabled( false ), playbackVolume( 0 ), device( NULL ), context( NULL )
	{
	}

	void enableAL()
	{
		Log::info() << "Enabling OpenALBackend";
		QString hrtfInstallPath = getOALHRTFPath();
		if( !QFile::exists( hrtfInstallPath ) )
		{
			if( !QFile::copy( QString(":/etc/default-%1.mhr").arg( AUDIO_FREQUENCY ), hrtfInstallPath ) )
			{
				Log::error() << "Failed to install default HRTF file to " << hrtfInstallPath;
			}
		}

		ALCint attrs[6] = { 0 };
		attrs[0] = ALC_FORMAT_TYPE_SOFT;
		attrs[1] = ALC_SHORT_SOFT;
		attrs[2] = ALC_FREQUENCY;
		attrs[3] = AUDIO_FREQUENCY;
		QByteArray deviceNameBytes = playbackDeviceName.toUtf8();

		Log::info() << "OpenALBackend opens device: " << playbackDeviceName;
		try
		{
			OpenAL::loadLib();
			device = OpenAL::alcOpenDevice( deviceNameBytes.data() );
			context = OpenAL::alcCreateContext( device, attrs );
			OpenAL::alcMakeContextCurrent( context );
		}
		catch( ... )
		{
			disableAL();
			throw;
		}

		OpenAL::alListener3f( AL_VELOCITY, 0, 0, 0 );
		OpenAL::alListenerf( AL_GAIN, tsVolumeModifierToOALGain( playbackVolume ) );
		updateCameraToAL();
		foreach( quint16 id, userPositions.keys() )
		{
			updateUserToAL( id );
		}
	}

	void disableAL()
	{
		Log::info() << "Disabling OpenALBackend";
		userSources.clear();
		if( context )
		{
			OpenAL::alcMakeContextCurrent( NULL );
			OpenAL::alcDestroyContext( context );
			context = NULL;
		}
		if( device )
		{
			OpenAL::alcCloseDevice( device );
			device = NULL;
		}
	}

	void updateUserToAL( quint16 id )
	{
		if( userPositions.contains( id ) )
		{
			Entity::Vector position = userPositions[id];
			if( !userSources.contains( id ) )
			{
				ALuint source = 0;
				OpenAL::alGenSources( 1, &source );
				userSources[id] = source;
				OpenAL::alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE );
				OpenAL::alSourcef( source, AL_ROLLOFF_FACTOR, 0 );
			}
			OpenAL::alSource3f( userSources[id], AL_POSITION, position.x, position.y, -position.z );
		}
		else if( userSources.contains( id ) )
		{
			Log::debug() << "alDeleteSources(): " << userSources[id];
			OpenAL::alDeleteSources( 1, &userSources[id] );
			userSources.remove( id );
		}
	}

	void updateCameraToAL()
	{
		ALfloat orientation[] = { cameraForward.x, cameraForward.y, -cameraForward.z, cameraUp.x, cameraUp.y, -cameraUp.z };
		OpenAL::alListener3f( AL_POSITION, cameraPosition.x, cameraPosition.y, -cameraPosition.z );
		OpenAL::alListenerfv( AL_ORIENTATION, orientation );
	}

	void changeALPlaybackDevice()
	{
		if( isEnabled )
		{
			try
			{
				disableAL();
			}
			catch( const OpenAL::Failure &error )
			{
				Log::warning() << "Failed to disable OpenAL, reason: " << error.what();
			}
			try
			{
				enableAL();
			}
			catch( const OpenAL::Failure &error )
			{
				Log::error() << "Failed to enable OpenAL, reason: " << error.what();
				isEnabled = false;
			}
		}
	}

	void changeALPlaybackVolume()
	{
		if( isEnabled )
		{
			OpenAL::alListenerf( AL_GAIN, tsVolumeModifierToOALGain( playbackVolume ) );
		}
	}

	bool feedUserAudioToAL( quint16 id, const short *samples, int sampleCount, int channels )
	{
		if( !isEnabled )
		{
			return false;
		}
		if( !userSources.contains( id ) )
		{
			return false;
		}
		if( channels != 1 )
		{
			// accept only mono source audio
			return false;
		}

		ALuint source = userSources[id];
		int sampleDataLength = sampleCount * channels * 2;
		ALint state;

		try
		{
			freeProcessedAudioData( source );
		}
		catch( const OpenAL::Failure &error )
		{
			Log::warning() << "Failed to free processed data, reason: " << error.what();
		}
		OpenAL::alGetSourcei( source, AL_SOURCE_STATE, &state );
		try
		{
			// delay start of playback a bit so that we don't starve the playback device
			if( state != AL_PLAYING )
			{
				short silence[AUDIO_FREQUENCY / 10] = {}; // 0.1 seconds worth of silence
				queueAudioData( source, silence, sizeof( silence ) );
			}
		}
		catch( const OpenAL::Failure &error )
		{
			Log::warning() << "Failed to queue audio delay, reason: " << error.what();
		}
		queueAudioData( source, samples, sampleDataLength );
		if( state != AL_PLAYING )
		{
			OpenAL::alSourcePlay( source );
		}
		return true;
	}

	void freeProcessedAudioData( ALuint source )
	{
		ALint processedCount = 0;
		OpenAL::alGetSourcei( source, AL_BUFFERS_PROCESSED, &processedCount );
		if( processedCount > 0 )
		{
			QScopedArrayPointer<ALuint> buffers( new ALuint[processedCount] );
			OpenAL::alSourceUnqueueBuffers( source, processedCount, buffers.data() );
			OpenAL::alDeleteBuffers( processedCount, buffers.data() );
		}
	}

	void queueAudioData( ALuint source, const short *data, int length )
	{
		ALuint buffer;
		OpenAL::alGenBuffers( 1, &buffer );
		OpenAL::alBufferData( buffer, AL_FORMAT_MONO16, data, length, AUDIO_FREQUENCY );
		OpenAL::alSourceQueueBuffers( source, 1, &buffer );
	}

	void writeSilence( short *samples, int sampleCount, int channels )
	{
		// write silence back to teamspeak
		int sampleDataLength = sampleCount * channels * 2;
		memset( samples, 0, sampleDataLength );
	}

	void changeALContext()
	{
		if( isEnabled && context )
		{
			OpenAL::alcMakeContextCurrent( context );
		}
	}

public:
	QMap<quint16, Entity::Vector> userPositions;
	QMap<quint16, ALuint> userSources;
	bool isEnabled;
	Entity::Vector cameraPosition;
	Entity::Vector cameraForward;
	Entity::Vector cameraUp;
	QString playbackDeviceName;
	float playbackVolume;
	ALCdevice *device;
	ALCcontext *context;
};

OpenALBackend::OpenALBackend( QObject *parent )
	: QObject( parent ), d_ptr( new OpenALBackendPrivate() )
{
}

OpenALBackend::~OpenALBackend()
{
	Q_D( OpenALBackend );
	delete d;
}

void OpenALBackend::setEnabled( bool enabled )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::setEnabled(" << enabled << "), state: " << d->isEnabled;
	try
	{
		if( enabled && !d->isEnabled )
		{
			d->enableAL();
		}
		else if( !enabled && d->isEnabled )
		{
			d->disableAL();
		}
		d->isEnabled = enabled;
	}
	catch( const OpenAL::Failure &error )
	{
		Log::error() << "Enabling/disabling OpenAL backend failed, reason: " << error.what();
	}
}

bool OpenALBackend::isEnabled() const
{
	Q_D( const OpenALBackend );
	QMutexLocker locker( &mutex );
	return d->isEnabled;
}

void OpenALBackend::removeUser( quint16 id )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::removeUser(" << id << ")";
	if( d->userPositions.contains( id ) )
	{
		d->userPositions.remove( id );
	}
	try
	{
		d->changeALContext();
		d->updateUserToAL( id );
	}
	catch( const OpenAL::Failure &error )
	{
		Log::error() << "Failed to remove user, reason: " << error.what();
	}
}

void OpenALBackend::removeAllUsers()
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	QList<quint16> existingUsers = d->userPositions.keys();
	d->userPositions.clear();
	try
	{
		d->changeALContext();
		foreach( quint16 id, existingUsers )
		{
			d->updateUserToAL( id );
		}
	}
	catch( const OpenAL::Failure &error )
	{
		std::cout << "Failed to remove users, reason: " << error.what().toStdString() << std::endl;
	}
}

void OpenALBackend::positionUser( quint16 id, const Entity::Vector &position )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	//Log::debug() << "OpenALBackend::positionUser(" << id << ", " << position << ")";
	d->userPositions[id] = position;
	try
	{
		d->changeALContext();
		d->updateUserToAL( id );
	}
	catch( const OpenAL::Failure &error )
	{
		Log::error() << "Failed to position user, reason: " << error.what();
	}
}

void OpenALBackend::positionCamera( const Entity::Vector &position, const Entity::Vector &forward, const Entity::Vector &up )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::positionCamera(" << position << ", " << forward << ", " << up << ")";
	d->cameraPosition = position;
	d->cameraForward = forward;
	d->cameraUp = up;
	if( d->isEnabled )
	{
		try
		{
			d->changeALContext();
			d->updateCameraToAL();
		}
		catch( const OpenAL::Failure &error )
		{
			Log::error() << "Failed to position camera, reason: " << error.what();
		}
	}
}

void OpenALBackend::setPlaybackDeviceName( const QString &name )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::setPlaybackDeviceName('" << name << "')";
	if( d->playbackDeviceName != name )
	{
		d->playbackDeviceName = name;
		try
		{
			d->changeALContext();
			d->changeALPlaybackDevice();
		}
		catch( const OpenAL::Failure &error )
		{
			Log::error() << "Failed to change playback device, reason: " << error.what();
		}
	}
}

void OpenALBackend::setPlaybackVolume( float volume )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::setPlaybackVolume(" << volume << ")";
	d->playbackVolume = volume;
	try
	{
		d->changeALContext();
		d->changeALPlaybackVolume();
	}
	catch( const OpenAL::Failure &error )
	{
		Log::error() << "Failed to change playback volume, reason: " << error.what();
	}
}

void OpenALBackend::onEditPlaybackVoiceDataEvent( quint16 id, short *samples, int sampleCount, int channels )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	if( d->userPositions.contains( id ) )
	{
		try
		{
			d->changeALContext();
			if( d->feedUserAudioToAL( id, samples, sampleCount, channels ) )
			{
				d->writeSilence( samples, sampleCount, channels );
			}
		}
		catch( const OpenAL::Failure &error )
		{
			Log::error() << "Failed to feed audio data to OpenAL, reason: " << error.what();
		}
	}
}

}
<commit_msg>Fixed OpenAL device left open at TeamSpeak exit.<commit_after>/*
 * TessuMod: Mod for integrating TeamSpeak into World of Tanks
 * Copyright (C) 2015  Janne Hakonen
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301
 * USA
 */

#include "openalbackend.h"
#include "../entities/vector.h"
#include "../libs/openal.h"
#include "../utils/logging.h"

#include <AL/alext.h>

#include <QStandardPaths>
#include <QRegularExpression>
#include <QDir>

#include <iostream>

namespace
{
QMutex mutex;

const int AUDIO_FREQUENCY = 48000;

QString getAppdataPath()
{
	QString targetPath = QStandardPaths::standardLocations( QStandardPaths::GenericDataLocation )[0];
	return targetPath.replace( QRegularExpression( "Local$" ), "Roaming" );
}

QString getOALHRTFPath()
{
	QString targetPath = getAppdataPath() + "/openal/hrtf";
	QDir().mkpath( targetPath );
	return QDir::cleanPath( ( targetPath + "/default-%1.mhr" ).arg( AUDIO_FREQUENCY ) );
}

ALfloat tsVolumeModifierToOALGain( float tsVolumeModifier )
{
	return 1.0 / ( pow( 2.0, tsVolumeModifier / -6.0 ) );
}

}

namespace Driver
{

class OpenALBackendPrivate
{
public:
	OpenALBackendPrivate()
		: isEnabled( false ), playbackVolume( 0 ), device( NULL ), context( NULL )
	{
	}

	void enableAL()
	{
		Log::info() << "Enabling OpenALBackend";
		QString hrtfInstallPath = getOALHRTFPath();
		if( !QFile::exists( hrtfInstallPath ) )
		{
			if( !QFile::copy( QString(":/etc/default-%1.mhr").arg( AUDIO_FREQUENCY ), hrtfInstallPath ) )
			{
				Log::error() << "Failed to install default HRTF file to " << hrtfInstallPath;
			}
		}

		ALCint attrs[6] = { 0 };
		attrs[0] = ALC_FORMAT_TYPE_SOFT;
		attrs[1] = ALC_SHORT_SOFT;
		attrs[2] = ALC_FREQUENCY;
		attrs[3] = AUDIO_FREQUENCY;
		QByteArray deviceNameBytes = playbackDeviceName.toUtf8();

		Log::info() << "OpenALBackend opens device: " << playbackDeviceName;
		try
		{
			OpenAL::loadLib();
			device = OpenAL::alcOpenDevice( deviceNameBytes.data() );
			context = OpenAL::alcCreateContext( device, attrs );
			OpenAL::alcMakeContextCurrent( context );
		}
		catch( ... )
		{
			disableAL();
			throw;
		}

		OpenAL::alListener3f( AL_VELOCITY, 0, 0, 0 );
		OpenAL::alListenerf( AL_GAIN, tsVolumeModifierToOALGain( playbackVolume ) );
		updateCameraToAL();
		foreach( quint16 id, userPositions.keys() )
		{
			updateUserToAL( id );
		}
	}

	void disableAL()
	{
		Log::info() << "Disabling OpenALBackend";
		userSources.clear();
		if( context )
		{
			OpenAL::alcMakeContextCurrent( NULL );
			OpenAL::alcDestroyContext( context );
			context = NULL;
		}
		if( device )
		{
			OpenAL::alcCloseDevice( device );
			device = NULL;
		}
	}

	void updateUserToAL( quint16 id )
	{
		if( userPositions.contains( id ) )
		{
			Entity::Vector position = userPositions[id];
			if( !userSources.contains( id ) )
			{
				ALuint source = 0;
				OpenAL::alGenSources( 1, &source );
				userSources[id] = source;
				OpenAL::alSourcei( source, AL_SOURCE_RELATIVE, AL_FALSE );
				OpenAL::alSourcef( source, AL_ROLLOFF_FACTOR, 0 );
			}
			OpenAL::alSource3f( userSources[id], AL_POSITION, position.x, position.y, -position.z );
		}
		else if( userSources.contains( id ) )
		{
			Log::debug() << "alDeleteSources(): " << userSources[id];
			OpenAL::alDeleteSources( 1, &userSources[id] );
			userSources.remove( id );
		}
	}

	void updateCameraToAL()
	{
		ALfloat orientation[] = { cameraForward.x, cameraForward.y, -cameraForward.z, cameraUp.x, cameraUp.y, -cameraUp.z };
		OpenAL::alListener3f( AL_POSITION, cameraPosition.x, cameraPosition.y, -cameraPosition.z );
		OpenAL::alListenerfv( AL_ORIENTATION, orientation );
	}

	void changeALPlaybackDevice()
	{
		if( isEnabled )
		{
			try
			{
				disableAL();
			}
			catch( const OpenAL::Failure &error )
			{
				Log::warning() << "Failed to disable OpenAL, reason: " << error.what();
			}
			try
			{
				enableAL();
			}
			catch( const OpenAL::Failure &error )
			{
				Log::error() << "Failed to enable OpenAL, reason: " << error.what();
				isEnabled = false;
			}
		}
	}

	void changeALPlaybackVolume()
	{
		if( isEnabled )
		{
			OpenAL::alListenerf( AL_GAIN, tsVolumeModifierToOALGain( playbackVolume ) );
		}
	}

	bool feedUserAudioToAL( quint16 id, const short *samples, int sampleCount, int channels )
	{
		if( !isEnabled )
		{
			return false;
		}
		if( !userSources.contains( id ) )
		{
			return false;
		}
		if( channels != 1 )
		{
			// accept only mono source audio
			return false;
		}

		ALuint source = userSources[id];
		int sampleDataLength = sampleCount * channels * 2;
		ALint state;

		try
		{
			freeProcessedAudioData( source );
		}
		catch( const OpenAL::Failure &error )
		{
			Log::warning() << "Failed to free processed data, reason: " << error.what();
		}
		OpenAL::alGetSourcei( source, AL_SOURCE_STATE, &state );
		try
		{
			// delay start of playback a bit so that we don't starve the playback device
			if( state != AL_PLAYING )
			{
				short silence[AUDIO_FREQUENCY / 10] = {}; // 0.1 seconds worth of silence
				queueAudioData( source, silence, sizeof( silence ) );
			}
		}
		catch( const OpenAL::Failure &error )
		{
			Log::warning() << "Failed to queue audio delay, reason: " << error.what();
		}
		queueAudioData( source, samples, sampleDataLength );
		if( state != AL_PLAYING )
		{
			OpenAL::alSourcePlay( source );
		}
		return true;
	}

	void freeProcessedAudioData( ALuint source )
	{
		ALint processedCount = 0;
		OpenAL::alGetSourcei( source, AL_BUFFERS_PROCESSED, &processedCount );
		if( processedCount > 0 )
		{
			QScopedArrayPointer<ALuint> buffers( new ALuint[processedCount] );
			OpenAL::alSourceUnqueueBuffers( source, processedCount, buffers.data() );
			OpenAL::alDeleteBuffers( processedCount, buffers.data() );
		}
	}

	void queueAudioData( ALuint source, const short *data, int length )
	{
		ALuint buffer;
		OpenAL::alGenBuffers( 1, &buffer );
		OpenAL::alBufferData( buffer, AL_FORMAT_MONO16, data, length, AUDIO_FREQUENCY );
		OpenAL::alSourceQueueBuffers( source, 1, &buffer );
	}

	void writeSilence( short *samples, int sampleCount, int channels )
	{
		// write silence back to teamspeak
		int sampleDataLength = sampleCount * channels * 2;
		memset( samples, 0, sampleDataLength );
	}

	void changeALContext()
	{
		if( isEnabled && context )
		{
			OpenAL::alcMakeContextCurrent( context );
		}
	}

public:
	QMap<quint16, Entity::Vector> userPositions;
	QMap<quint16, ALuint> userSources;
	bool isEnabled;
	Entity::Vector cameraPosition;
	Entity::Vector cameraForward;
	Entity::Vector cameraUp;
	QString playbackDeviceName;
	float playbackVolume;
	ALCdevice *device;
	ALCcontext *context;
};

OpenALBackend::OpenALBackend( QObject *parent )
	: QObject( parent ), d_ptr( new OpenALBackendPrivate() )
{
}

OpenALBackend::~OpenALBackend()
{
	Q_D( OpenALBackend );
	if( d->isEnabled )
	{
		d->disableAL();
	}
	delete d;
}

void OpenALBackend::setEnabled( bool enabled )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::setEnabled(" << enabled << "), state: " << d->isEnabled;
	try
	{
		if( enabled && !d->isEnabled )
		{
			d->enableAL();
		}
		else if( !enabled && d->isEnabled )
		{
			d->disableAL();
		}
		d->isEnabled = enabled;
	}
	catch( const OpenAL::Failure &error )
	{
		Log::error() << "Enabling/disabling OpenAL backend failed, reason: " << error.what();
	}
}

bool OpenALBackend::isEnabled() const
{
	Q_D( const OpenALBackend );
	QMutexLocker locker( &mutex );
	return d->isEnabled;
}

void OpenALBackend::removeUser( quint16 id )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::removeUser(" << id << ")";
	if( d->userPositions.contains( id ) )
	{
		d->userPositions.remove( id );
	}
	try
	{
		d->changeALContext();
		d->updateUserToAL( id );
	}
	catch( const OpenAL::Failure &error )
	{
		Log::error() << "Failed to remove user, reason: " << error.what();
	}
}

void OpenALBackend::removeAllUsers()
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	QList<quint16> existingUsers = d->userPositions.keys();
	d->userPositions.clear();
	try
	{
		d->changeALContext();
		foreach( quint16 id, existingUsers )
		{
			d->updateUserToAL( id );
		}
	}
	catch( const OpenAL::Failure &error )
	{
		std::cout << "Failed to remove users, reason: " << error.what().toStdString() << std::endl;
	}
}

void OpenALBackend::positionUser( quint16 id, const Entity::Vector &position )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	//Log::debug() << "OpenALBackend::positionUser(" << id << ", " << position << ")";
	d->userPositions[id] = position;
	try
	{
		d->changeALContext();
		d->updateUserToAL( id );
	}
	catch( const OpenAL::Failure &error )
	{
		Log::error() << "Failed to position user, reason: " << error.what();
	}
}

void OpenALBackend::positionCamera( const Entity::Vector &position, const Entity::Vector &forward, const Entity::Vector &up )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::positionCamera(" << position << ", " << forward << ", " << up << ")";
	d->cameraPosition = position;
	d->cameraForward = forward;
	d->cameraUp = up;
	if( d->isEnabled )
	{
		try
		{
			d->changeALContext();
			d->updateCameraToAL();
		}
		catch( const OpenAL::Failure &error )
		{
			Log::error() << "Failed to position camera, reason: " << error.what();
		}
	}
}

void OpenALBackend::setPlaybackDeviceName( const QString &name )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::setPlaybackDeviceName('" << name << "')";
	if( d->playbackDeviceName != name )
	{
		d->playbackDeviceName = name;
		try
		{
			d->changeALContext();
			d->changeALPlaybackDevice();
		}
		catch( const OpenAL::Failure &error )
		{
			Log::error() << "Failed to change playback device, reason: " << error.what();
		}
	}
}

void OpenALBackend::setPlaybackVolume( float volume )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	Log::debug() << "OpenALBackend::setPlaybackVolume(" << volume << ")";
	d->playbackVolume = volume;
	try
	{
		d->changeALContext();
		d->changeALPlaybackVolume();
	}
	catch( const OpenAL::Failure &error )
	{
		Log::error() << "Failed to change playback volume, reason: " << error.what();
	}
}

void OpenALBackend::onEditPlaybackVoiceDataEvent( quint16 id, short *samples, int sampleCount, int channels )
{
	Q_D( OpenALBackend );
	QMutexLocker locker( &mutex );
	if( d->userPositions.contains( id ) )
	{
		try
		{
			d->changeALContext();
			if( d->feedUserAudioToAL( id, samples, sampleCount, channels ) )
			{
				d->writeSilence( samples, sampleCount, channels );
			}
		}
		catch( const OpenAL::Failure &error )
		{
			Log::error() << "Failed to feed audio data to OpenAL, reason: " << error.what();
		}
	}
}

}
<|endoftext|>


<commit_before>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_ASSEMBLER_GRIDWALKER_HH
#define DUNE_GDT_ASSEMBLER_GRIDWALKER_HH

#include <vector>
#include <memory>
#include <type_traits>

#include <dune/stuff/grid/boundaryinfo.hh>

namespace Dune {
namespace GDT {
namespace Functor {

template <class GridViewImp>
class Codim0
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;

  virtual ~Codim0()
  {
  }

  virtual void prepare()
  {
  }

  virtual void apply_local(const EntityType& entity) = 0;

  virtual void finalize()
  {
  }
}; // class Codim0

template <class GridViewImp>
class Codim1
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;
  typedef typename GridViewType::Intersection IntersectionType;

  virtual ~Codim1()
  {
  }

  virtual void prepare()
  {
  }

  virtual void apply_local(const IntersectionType& intersection, const EntityType& inside_entity,
                           const EntityType& outside_entity) = 0;

  virtual void finalize()
  {
  }
}; // class Codim1

/**
 *  \brief Interface for functors to tell on which entity to apply.
 *
 *  The derived class has to provide a method with the following signature:
 *  \code
virtual bool apply_on(const GridViewType& grid_view, const EntityType& entity) const
{
  ...
}
\endcode
 */
template <class GridViewImp>
class ApplyOnWhichEntity
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::EntityType EntityType;

  virtual ~ApplyOnWhichEntity()
  {
  }

  virtual bool apply_on(const GridViewType& /*grid_view*/, const EntityType& /*entity*/) const = 0;
}; // class ApplyOnWhichEntity

/**
 *  \brief Selects all entities.
 */
template <class GridViewImp>
class ApplyOnAllEntities : public ApplyOnWhichEntity<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::EntityType EntityType;

  virtual bool apply_on(const GridViewType& /*grid_view*/, const EntityType& /*entity*/) const /*DS_OVERRIDE*/
  {
    return true;
  }
}; // class ApplyOnAllEntities

/**
 *  \brief Interface for functors to tell on which intersection to apply.
 *
 *  The derived class has to provide a method with the following signature:
 *  \code
virtual bool apply_on(const GridViewType& grid_view, const IntersectionType& intersection) const
{
  ...
}
\endcode
 */
template <class GridViewImp>
class ApplyOnWhichIntersection
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::IntersectionType IntersectionType;

  virtual ~ApplyOnWhichIntersection<GridViewImp>()
  {
  }

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& /*intersection*/) const = 0;
}; // class ApplyOnWhichIntersection< GridViewImp >

/**
 *  \brief Selects each inner intersection.
 *
 *  To decide if this in an inner intersection,
\code
intersection.neighbor() && !intersection.boundary()
\endcode
 *  is used.
 */
template <class GridViewImp>
class ApplyOnInnerIntersections : public ApplyOnWhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::IntersectionType IntersectionType;

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& intersection) const /*DS_OVERRIDE*/
  {
    return intersection.neighbor() && !intersection.boundary();
  }
}; // class ApplyOnInnerIntersections

/**
 *  \brief Selects each inner intersection only once.
 *
 *  To decide if this in an inner intersection,
\code
intersection.neighbor() && !intersection.boundary()
\endcode
 *  is used, and true is returned, if the index of the inside() entity is smaller than the index of the outside()
 *  entity.
 */
template <class GridViewImp>
class ApplyOnInnerIntersectionsPrimally : public ApplyOnWhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::IntersectionType IntersectionType;

  virtual bool apply_on(const GridViewType& grid_view, const IntersectionType& intersection) const /*DS_OVERRIDE*/
  {
    if (intersection.neighbor() && !intersection.boundary()) {
      const auto insideEntityPtr    = intersection.inside();
      const auto& insideEntity      = *insideEntityPtr;
      const auto outsideNeighborPtr = intersection.outside();
      const auto& outsideNeighbor = *outsideNeighborPtr;
      return grid_view.indexSet().index(insideEntity) < grid_view.indexSet().index(outsideNeighbor);
    } else
      return false;
  }
}; // class ApplyOnInnerIntersections

template <class GridViewImp>
class ApplyOnBoundaryIntersections : public ApplyOnWhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::IntersectionType IntersectionType;

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& intersection) const /*DS_OVERRIDE*/
  {
    return intersection.boundary();
  }
}; // class ApplyOnBoundaryIntersections

template <class GridViewImp>
class ApplyOnDirichletIntersections : public ApplyOnWhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::IntersectionType IntersectionType;
  typedef Stuff::GridboundaryInterface<IntersectionType> BoundaryInfoType;

  ApplyOnDirichletIntersections(const BoundaryInfoType& boundary_info)
    : boundary_info_(boundary_info)
  {
  }

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& intersection) const /*DS_OVERRIDE*/
  {
    return boundary_info_.dirichlet(intersection);
  }

private:
  const BoundaryInfoType& boundary_info_;
}; // class ApplyOnDirichletIntersections

template <class GridViewImp>
class ApplyOnNeumannIntersections : public ApplyOnWhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::IntersectionType IntersectionType;
  typedef Stuff::GridboundaryInterface<IntersectionType> BoundaryInfoType;

  ApplyOnNeumannIntersections(const BoundaryInfoType& boundary_info)
    : boundary_info_(boundary_info)
  {
  }

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& intersection) const /*DS_OVERRIDE*/
  {
    return boundary_info_.neumann(intersection);
  }

private:
  const BoundaryInfoType& boundary_info_;
}; // class ApplyOnNeumannIntersections

} // namespace Functor

template <class GridViewImp>
class GridWalker
{
  typedef GridWalker<GridViewImp> ThisType;

public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;
  typedef typename GridViewType::Intersection IntersectionType;

private:
  typedef Stuff::GridboundaryInterface<IntersectionType> BoundaryInfoType;
  typedef Functor::Codim0<GridViewType> Codim0FunctorType;
  typedef Functor::Codim1<GridViewType> Codim1FunctorType;

  class Codim0FunctorWrapper : public Functor::Codim0<GridViewType>
  {
  public:
    Codim0FunctorWrapper(Codim0FunctorType& wrapped_functor)
      : wrapped_functor_(wrapped_functor)
    {
    }

    virtual void prepare() DS_FINAL
    {
      wrapped_functor_.prepare();
    }

    virtual void apply_local(const EntityType& entity) DS_FINAL
    {
      wrapped_functor_.apply_local(entity);
    }

    virtual void finalize() DS_FINAL
    {
      wrapped_functor_.finalize();
    }

  private:
    Codim0FunctorType& wrapped_functor_;
  }; // class Codim0FunctorWrapper

  class Codim1FunctorWrapper : public Functor::Codim1<GridViewType>
  {
  public:
    Codim1FunctorWrapper(Codim1FunctorType& wrapped_functor)
      : wrapped_functor_(wrapped_functor)
    {
    }

    virtual void prepare() DS_FINAL
    {
      wrapped_functor_.prepare();
    }

    virtual void apply_local(const IntersectionType& intersection, const EntityType& inside_entity,
                             const EntityType& outside_entity) DS_FINAL
    {
      wrapped_functor_.apply_local(intersection, inside_entity, outside_entity);
    }

    virtual void finalize() DS_FINAL
    {
      wrapped_functor_.finalize();
    }

  private:
    Codim1FunctorType& wrapped_functor_;
  }; // class Codim1FunctorWrapper

public:
  GridWalker(const GridViewType& grid_view)
    : grid_view_(grid_view)
  {
  }

  void add(Functor::Codim0<GridViewType>& functor)
  {
    codim0_functors_.emplace_back(new Codim0FunctorWrapper(functor));
  }

  void add(Functor::Codim1<GridViewType>& functor)
  {
    codim1_functors_.emplace_back(new Codim1FunctorWrapper(functor));
  }

  void walk() const
  {
    // prepare functors
    for (auto& functor : codim0_functors_)
      functor->prepare();

    // only do something, if we have to
    if ((codim0_functors_.size() + codim1_functors_.size()) > 0) {
      // walk the grid
      const auto entity_it_end = grid_view_.template end<0>();
      for (auto entity_it = grid_view_.template begin<0>(); entity_it != entity_it_end; ++entity_it) {
        const EntityType& entity = *entity_it;

        // apply codim0 functors
        for (auto& functor : codim0_functors_)
          functor->apply_local(entity);

        // only walk the intersections, if there are codim1 functors present
        if (codim1_functors_.size()) {
          // walk the intersections
          const auto intersection_it_end = grid_view_.iend(entity);
          for (auto intersection_it = grid_view_.ibegin(entity); intersection_it != intersection_it_end;
               ++intersection_it) {
            const auto& intersection   = *intersection_it;
            const auto neighbor_ptr    = intersection.outside();
            const EntityType& neighbor = *neighbor_ptr;

            // apply codim1 functors
            for (auto& functor : codim1_functors_)
              functor->apply_local(intersection, entity, neighbor);

          } // walk the intersections
        } // only walk the intersections, if there are codim1 functors present
      } // walk the grid
    } // only do something, if we have to

    // finalize functors
    for (auto& functor : codim0_functors_)
      functor->finalize();
  } // ... walk()

private:
  const GridViewType& grid_view_;
  std::vector<std::unique_ptr<Codim0FunctorType>> codim0_functors_;
  std::vector<std::unique_ptr<Codim1FunctorType>> codim1_functors_;
}; // class GridWalker

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMBLER_GRIDWALKER_HH
<commit_msg>[assembler.gridwalker] update * moved Functor::ApplyOn... -> ApplyOn::... * add() now takes an optional ApplyOn tag<commit_after>// This file is part of the dune-gdt project:
//   http://users.dune-project.org/projects/dune-gdt
// Copyright holders: Felix Albrecht
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#ifndef DUNE_GDT_ASSEMBLER_GRIDWALKER_HH
#define DUNE_GDT_ASSEMBLER_GRIDWALKER_HH

#include <vector>
#include <memory>
#include <type_traits>

#include <dune/stuff/grid/boundaryinfo.hh>

namespace Dune {
namespace GDT {
namespace Functor {

template <class GridViewImp>
class Codim0
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;

  virtual ~Codim0()
  {
  }

  virtual void prepare()
  {
  }

  virtual void apply_local(const EntityType& entity) = 0;

  virtual void finalize()
  {
  }
}; // class Codim0

template <class GridViewImp>
class Codim1
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;
  typedef typename GridViewType::Intersection IntersectionType;

  virtual ~Codim1()
  {
  }

  virtual void prepare()
  {
  }

  virtual void apply_local(const IntersectionType& intersection) = 0;

  virtual void finalize()
  {
  }
}; // class Codim1

} // namespace Functor
namespace ApplyOn {

/**
 *  \brief Interface for functors to tell on which entity to apply.
 *
 *  The derived class has to provide a method with the following signature:
 *  \code
virtual bool apply_on(const GridViewType& grid_view, const EntityType& entity) const
{
  ...
}
\endcode
 */
template <class GridViewImp>
class WhichEntity
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;

  virtual ~WhichEntity()
  {
  }

  virtual bool apply_on(const GridViewType& /*grid_view*/, const EntityType& /*entity*/) const = 0;
}; // class WhichEntity

/**
 *  \brief Selects all entities.
 */
template <class GridViewImp>
class AllEntities : public WhichEntity<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;

  virtual bool apply_on(const GridViewType& /*grid_view*/, const EntityType& /*entity*/) const DS_FINAL
  {
    return true;
  }
}; // class AllEntities

/**
 *  \brief Selects entities which have a boundary intersection.
 */
template <class GridViewImp>
class BoundaryEntities : public WhichEntity<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;

  virtual bool apply_on(const GridViewType& /*grid_view*/, const EntityType& entity) const DS_FINAL
  {
    return entity.hasBoundaryIntersections();
  }
}; // class BoundaryEntities

/**
 *  \brief Interface for functors to tell on which intersection to apply.
 *
 *  The derived class has to provide a method with the following signature:
 *  \code
virtual bool apply_on(const GridViewType& grid_view, const IntersectionType& intersection) const
{
  ...
}
\endcode
 */
template <class GridViewImp>
class WhichIntersection
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::Intersection IntersectionType;

  virtual ~WhichIntersection<GridViewImp>()
  {
  }

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& /*intersection*/) const = 0;
}; // class WhichIntersection< GridViewImp >

/**
 *  \brief Selects all intersections.
 */
template <class GridViewImp>
class AllIntersections : public WhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::Intersection IntersectionType;

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& /*intersection*/) const DS_FINAL
  {
    return true;
  }
}; // class AllIntersections

/**
 *  \brief Selects each inner intersection.
 *
 *  To decide if this in an inner intersection,
\code
intersection.neighbor() && !intersection.boundary()
\endcode
 *  is used.
 */
template <class GridViewImp>
class InnerIntersections : public WhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::Intersection IntersectionType;

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& intersection) const DS_FINAL
  {
    return intersection.neighbor() && !intersection.boundary();
  }
}; // class InnerIntersections

/**
 *  \brief Selects each inner intersection only once.
 *
 *  To decide if this in an inner intersection,
\code
intersection.neighbor() && !intersection.boundary()
\endcode
 *  is used, and true is returned, if the index of the inside() entity is smaller than the index of the outside()
 *  entity.
 */
template <class GridViewImp>
class InnerIntersectionsPrimally : public WhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::Intersection IntersectionType;

  virtual bool apply_on(const GridViewType& grid_view, const IntersectionType& intersection) const DS_FINAL
  {
    if (intersection.neighbor() && !intersection.boundary()) {
      const auto insideEntityPtr    = intersection.inside();
      const auto& insideEntity      = *insideEntityPtr;
      const auto outsideNeighborPtr = intersection.outside();
      const auto& outsideNeighbor = *outsideNeighborPtr;
      return grid_view.indexSet().index(insideEntity) < grid_view.indexSet().index(outsideNeighbor);
    } else
      return false;
  }
}; // class InnerIntersections

template <class GridViewImp>
class BoundaryIntersections : public WhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::Intersection IntersectionType;

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& intersection) const DS_FINAL
  {
    return intersection.boundary();
  }
}; // class BoundaryIntersections

template <class GridViewImp>
class DirichletIntersections : public WhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::Intersection IntersectionType;
  typedef Stuff::GridboundaryInterface<IntersectionType> BoundaryInfoType;

  DirichletIntersections(const BoundaryInfoType& boundary_info)
    : boundary_info_(boundary_info)
  {
  }

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& intersection) const DS_FINAL
  {
    return boundary_info_.dirichlet(intersection);
  }

private:
  const BoundaryInfoType& boundary_info_;
}; // class DirichletIntersections

template <class GridViewImp>
class NeumannIntersections : public WhichIntersection<GridViewImp>
{
public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::Intersection IntersectionType;
  typedef Stuff::GridboundaryInterface<IntersectionType> BoundaryInfoType;

  NeumannIntersections(const BoundaryInfoType& boundary_info)
    : boundary_info_(boundary_info)
  {
  }

  virtual bool apply_on(const GridViewType& /*grid_view*/, const IntersectionType& intersection) const DS_FINAL
  {
    return boundary_info_.neumann(intersection);
  }

private:
  const BoundaryInfoType& boundary_info_;
}; // class NeumannIntersections

} // namespace ApplyOn

template <class GridViewImp>
class GridWalker
{
  typedef GridWalker<GridViewImp> ThisType;

public:
  typedef GridViewImp GridViewType;
  typedef typename GridViewType::template Codim<0>::Entity EntityType;
  typedef typename GridViewType::Intersection IntersectionType;

protected:
  typedef Stuff::GridboundaryInterface<IntersectionType> BoundaryInfoType;

  class Codim0Object : public Functor::Codim0<GridViewType>
  {
  public:
    ~Codim0Object()
    {
    }
    virtual bool apply_on(const GridViewType& grid_view, const EntityType& entity) const = 0;
  };

  template <class Codim0FunctorType>
  class Codim0FunctorWrapper : public Codim0Object
  {
  public:
    Codim0FunctorWrapper(Codim0FunctorType& wrapped_functor, const ApplyOn::WhichEntity<GridViewType>* where)
      : wrapped_functor_(wrapped_functor)
      , where_(where)
    {
    }

    virtual ~Codim0FunctorWrapper()
    {
    }

    virtual void prepare() DS_FINAL
    {
      wrapped_functor_.prepare();
    }

    virtual bool apply_on(const GridViewType& grid_view, const EntityType& entity) const DS_FINAL
    {
      return where_->apply_on(grid_view, entity);
    }

    virtual void apply_local(const EntityType& entity) DS_FINAL
    {
      wrapped_functor_.apply_local(entity);
    }

    virtual void finalize() DS_FINAL
    {
      wrapped_functor_.finalize();
    }

  private:
    Codim0FunctorType& wrapped_functor_;
    std::unique_ptr<const ApplyOn::WhichEntity<GridViewType>> where_;
  }; // class Codim0FunctorWrapper

  class Codim1Object : public Functor::Codim1<GridViewType>
  {
  public:
    ~Codim1Object()
    {
    }
    virtual bool apply_on(const GridViewType& grid_view, const IntersectionType& intersection) const = 0;
  };

  template <class Codim1FunctorType>
  class Codim1FunctorWrapper : public Codim1Object
  {
  public:
    Codim1FunctorWrapper(Codim1FunctorType& wrapped_functor, const ApplyOn::WhichIntersection<GridViewType>* where)
      : wrapped_functor_(wrapped_functor)
      , where_(where)
    {
    }

    virtual void prepare() DS_FINAL
    {
      wrapped_functor_.prepare();
    }

    virtual bool apply_on(const GridViewType& grid_view, const IntersectionType& intersection) const DS_FINAL
    {
      return where_->apply_on(grid_view, intersection);
    }

    virtual void apply_local(const IntersectionType& intersection) DS_FINAL
    {
      wrapped_functor_.apply_local(intersection);
    }

    virtual void finalize() DS_FINAL
    {
      wrapped_functor_.finalize();
    }

  private:
    Codim1FunctorType& wrapped_functor_;
    std::unique_ptr<const ApplyOn::WhichIntersection<GridViewType>> where_;
  }; // class Codim1FunctorWrapper

public:
  GridWalker(const GridViewType& grid_view)
    : grid_view_(grid_view)
  {
  }

  const GridViewType& grid_view() const
  {
    return grid_view_;
  }

  void add(Functor::Codim0<GridViewType>& functor,
           const ApplyOn::WhichEntity<GridViewType>* where = new ApplyOn::AllEntities<GridViewType>())
  {
    codim0_functors_.emplace_back(new Codim0FunctorWrapper<Functor::Codim0<GridViewType>>(functor, where));
  }

  void add(Functor::Codim1<GridViewType>& functor,
           const ApplyOn::WhichIntersection<GridViewType>* where = new ApplyOn::AllIntersections<GridViewType>())
  {
    codim1_functors_.emplace_back(new Codim1FunctorWrapper<Functor::Codim1<GridViewType>>(functor, where));
  }

  void walk() const
  {
    // prepare functors
    for (auto& functor : codim0_functors_)
      functor->prepare();
    for (auto& functor : codim1_functors_)
      functor->prepare();

    // only do something, if we have to
    if ((codim0_functors_.size() + codim1_functors_.size()) > 0) {
      // walk the grid
      const auto entity_it_end = grid_view_.template end<0>();
      for (auto entity_it = grid_view_.template begin<0>(); entity_it != entity_it_end; ++entity_it) {
        const EntityType& entity = *entity_it;

        // apply codim0 functors
        for (auto& functor : codim0_functors_)
          if (functor->apply_on(grid_view_, entity))
            functor->apply_local(entity);

        // only walk the intersections, if there are codim1 functors present
        if (codim1_functors_.size() > 0) {
          // walk the intersections
          const auto intersection_it_end = grid_view_.iend(entity);
          for (auto intersection_it = grid_view_.ibegin(entity); intersection_it != intersection_it_end;
               ++intersection_it) {
            const auto& intersection = *intersection_it;

            // apply codim1 functors
            for (auto& functor : codim1_functors_)
              if (functor->apply_on(grid_view_, intersection))
                functor->apply_local(intersection);

          } // walk the intersections
        } // only walk the intersections, if there are codim1 functors present
      } // walk the grid
    } // only do something, if we have to

    // finalize functors
    for (auto& functor : codim0_functors_)
      functor->finalize();
    for (auto& functor : codim1_functors_)
      functor->finalize();
  } // ... walk()

  void clear()
  {
    codim0_functors_ = std::vector<std::unique_ptr<Codim0Object>>();
    codim1_functors_ = std::vector<std::unique_ptr<Codim1Object>>();
  }

protected:
  const GridViewType& grid_view_;
  std::vector<std::unique_ptr<Codim0Object>> codim0_functors_;
  std::vector<std::unique_ptr<Codim1Object>> codim1_functors_;
}; // class GridWalker

} // namespace GDT
} // namespace Dune

#endif // DUNE_GDT_ASSEMBLER_GRIDWALKER_HH
<|endoftext|>


<commit_before>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include "main.hxx"

#if HAVE_DUNE_GRID
# if HAVE_ALUGRID
#   include <dune/grid/alugrid.hh>
# endif
# include <dune/grid/sgrid.hh>
# include <dune/grid/yaspgrid.hh>

# include <dune/stuff/common/type_utils.hh>
# include <dune/stuff/grid/provider/interface.hh>
# include <dune/stuff/grid/provider/cube.hh>

using namespace Dune;
using namespace Stuff;

# define SGRIDS \
    SGrid< 1, 1 > \
  , SGrid< 2, 2 > \
  , SGrid< 3, 3 > \
  , SGrid< 4, 4 > \
  , SGrid< 1, 2 > \
  , SGrid< 2, 3 > \
  , SGrid< 3, 4 > \
  , SGrid< 4, 5 >

# define YASPGRIDS \
    YaspGrid< 1 > \
  , YaspGrid< 2 > \
  , YaspGrid< 3 > \
  , YaspGrid< 4 >

# if HAVE_ALUGRID
#   define ALUGRIDS \
    ALUGrid< 2, 2, cube, nonconforming > \
  /*, ALUGrid< 2, 3, cube, nonconforming >     <- provider does not work */ \
  , ALUGrid< 3, 3, cube, nonconforming > \
  , ALUGrid< 2, 2, simplex, nonconforming > \
  /*, ALUGrid< 2, 3, simplex, nonconforming >  <- same here */ \
  , ALUGrid< 3, 3, simplex, nonconforming > \
  , ALUGrid< 2, 2, simplex, conforming > \
  /*, ALUGrid< 2, 3, simplex, conforming >     <- same here */ \
  , ALUGrid< 3, 3, simplex, conforming >
# endif // HAVE_ALUGRID

template< class GridProviderType >
class ConstGridProviderBase
  : public testing::Test
{
protected:
  typedef typename GridProviderType::GridType             GridType;
private:
  typedef Stuff::Grid::ConstProviderInterface< GridType > InterfaceType;

  static_assert(std::is_base_of< InterfaceType, GridProviderType >::value,
                "GridProviderType has to be derived from Stuff::Grid::ConstProviderInterface!");

protected:
  static std::unique_ptr< GridProviderType > create()
  {
     return GridProviderType::create();
  }

public:
  static void is_default_creatable()
  {
    std::unique_ptr< GridProviderType > DUNE_UNUSED(grd_prvdr) = create();
  }

  static void static_interface()
  {
    std::string static_id_s = GridProviderType::static_id();
    auto grid_provider_d = create();
    std::string static_id_d = grid_provider_d->static_id();
    std::unique_ptr< InterfaceType >& grid_provider_i = grid_provider_d;
    std::string static_id_i = grid_provider_i->static_id();
  } // ... static_interface(...)

private:
  template< class GPT >
  static void check_const_interface(const GPT& grid_provider)
  {
    using Stuff::Grid::ChooseLayer;
    using Stuff::Grid::ChoosePartView;
    const auto& grid_i = grid_provider.grid();
    auto DUNE_UNUSED(leaf_grid_view_1) = grid_provider.leaf_view();
    auto DUNE_UNUSED(leaf_grid_view_2) = grid_provider.template leaf< ChoosePartView::view >();
    //auto leaf_grid_part = grid_provider.template leaf< ChoosePartView::part >();                       // <does not work
    for (int level = 0; level <= grid_i.maxLevel(); ++level) {
      auto DUNE_UNUSED(level_grid_view_1) = grid_provider.level_view(level);
      auto DUNE_UNUSED(level_grid_view_2) = grid_provider.template level< ChoosePartView::view >(level);
      //auto DUNE_UNUSED(level_grid_part) = grid_provider.template level< ChoosePartView::part >(level); // <does not work
    }
  } // ... check_const_interface()

public:
  static void const_interface()
  {
    const auto grid_provider = create();
    check_const_interface< GridProviderType >(*grid_provider);
    check_const_interface< InterfaceType >(*grid_provider);
  } // ... const_interface()

private:
  template< class GPT >
  static void check_visualize(const GPT& grid_provider)
  {
    auto type_str = Stuff::Common::Typename< GPT >::value();
    grid_provider.visualize();
    grid_provider.visualize(type_str + "_a");
    grid_provider.visualize(Stuff::Grid::BoundaryInfoConfigs::AllDirichlet::default_config());
    grid_provider.visualize(Stuff::Grid::BoundaryInfoConfigs::AllDirichlet::default_config(), type_str + "_b");
  } // ... check_visualize(...)

public:
  static void visualize()
  {
    if (GridType::dimension <= 3) {
      const auto grid_provider = create();
      check_visualize< GridProviderType >(*grid_provider);
      check_visualize< InterfaceType >(*grid_provider);
    }
  } // ... visualize(...)

}; // class ConstGridProviderBase

template< class GridProviderType >
class GridProviderBase
  : public ConstGridProviderBase< GridProviderType >
{
  typedef ConstGridProviderBase< GridProviderType >  BaseType;
  typedef typename BaseType::GridType GridType;
  typedef Stuff::Grid::ProviderInterface< GridType > InterfaceType;

private:
  template< class GPT >
  static void check_non_const_interface(GPT& grid_provider)
  {
    using Stuff::Grid::ChooseLayer;
    using Stuff::Grid::ChoosePartView;
    auto& grid_i = grid_provider.grid();
    auto DUNE_UNUSED(leaf_grid_part_1) = grid_provider.template leaf< ChoosePartView::part >();
    auto DUNE_UNUSED(leaf_grid_part_2) = grid_provider.leaf_part();
    for (int level = 0; level <= grid_i.maxLevel(); ++level) {
      auto DUNE_UNUSED(level_grid_part_1) = grid_provider.template level< ChoosePartView::part >(level);
      auto DUNE_UNUSED(level_grid_part_2) = grid_provider.level_part(level);
    }
  } // ... check_non_const_interface()

public:
  static void non_const_interface()
  {
    auto grid_provider = BaseType::create();
    check_non_const_interface< GridProviderType >(*grid_provider);
    check_non_const_interface< InterfaceType >(*grid_provider);
  } // ... non_const_interface()

}; // class GridProviderBase

template< class GridType >
struct CubeGridProvider
  : public GridProviderBase< Stuff::Grid::Providers::Cube< GridType > >
{};

typedef testing::Types< SGRIDS
                      , YASPGRIDS
# if HAVE_ALUGRID
                      , ALUGRIDS
# endif
                      > GridTypes;

TYPED_TEST_CASE(CubeGridProvider, GridTypes);
TYPED_TEST(CubeGridProvider, is_default_creatable)
{
  this->is_default_creatable();
}
TYPED_TEST(CubeGridProvider, fulfills_const_interface)
{
  this->const_interface();
}
TYPED_TEST(CubeGridProvider, is_visualizable)
{
  this->visualize();
}

# if HAVE_DUNE_FEM

TYPED_TEST(CubeGridProvider, fulfills_non_const_interface)
{
  this->non_const_interface();
}

# else // HAVE_DUNE_FEM

TEST(DISABLED_CubeGridProvider, fulfills_non_const_interface) {}

# endif

#else // HAVE_DUNE_GRID

TEST(DISABLED_CubeGridProvider, is_default_creatable) {}
TEST(DISABLED_CubeGridProvider, fulfills_const_interface) {}
TEST(DISABLED_CubeGridProvider, is_visualizable) {}

#endif // HAVE_DUNE_GRID

<commit_msg>[tests] workaround for icc not compiling gridprovider test, refs #38<commit_after>// This file is part of the dune-stuff project:
//   https://github.com/wwu-numerik/dune-stuff
// Copyright holders: Rene Milk, Felix Schindler
// License: BSD 2-Clause License (http://opensource.org/licenses/BSD-2-Clause)

#include "main.hxx"

#if HAVE_DUNE_GRID
# if HAVE_ALUGRID
#   include <dune/grid/alugrid.hh>
# endif
# include <dune/grid/sgrid.hh>
# include <dune/grid/yaspgrid.hh>

# include <dune/stuff/common/type_utils.hh>
# include <dune/stuff/grid/provider/interface.hh>
# include <dune/stuff/grid/provider/cube.hh>

using namespace Dune;
using namespace Stuff;

# define SGRIDS \
    SGrid< 1, 1 > \
  , SGrid< 2, 2 > \
  , SGrid< 3, 3 > \
  , SGrid< 4, 4 > \
  , SGrid< 1, 2 > \
  , SGrid< 2, 3 > \
  , SGrid< 3, 4 > \
  , SGrid< 4, 5 >

# define YASPGRIDS \
    YaspGrid< 1 > \
  , YaspGrid< 2 > \
  , YaspGrid< 3 > \
  , YaspGrid< 4 >

# if HAVE_ALUGRID
#   define ALUGRIDS \
    ALUGrid< 2, 2, cube, nonconforming > \
  /*, ALUGrid< 2, 3, cube, nonconforming >     <- provider does not work */ \
  , ALUGrid< 3, 3, cube, nonconforming > \
  , ALUGrid< 2, 2, simplex, nonconforming > \
  /*, ALUGrid< 2, 3, simplex, nonconforming >  <- same here */ \
  , ALUGrid< 3, 3, simplex, nonconforming > \
  , ALUGrid< 2, 2, simplex, conforming > \
  /*, ALUGrid< 2, 3, simplex, conforming >     <- same here */ \
  , ALUGrid< 3, 3, simplex, conforming >
# endif // HAVE_ALUGRID

template< class GridProviderType >
class ConstGridProviderBase
  : public testing::Test
{
protected:
  typedef typename GridProviderType::GridType             GridType;
private:
  typedef Stuff::Grid::ConstProviderInterface< GridType > ConstInterfaceType;
  typedef Stuff::Grid::ProviderInterface< GridType > InterfaceType;

  static_assert(std::is_base_of< InterfaceType, GridProviderType >::value,
                "GridProviderType has to be derived from Stuff::Grid::ConstProviderInterface!");

protected:
  static std::unique_ptr< GridProviderType > create()
  {
     return GridProviderType::create();
  }

public:
  static void is_default_creatable()
  {
    std::unique_ptr< GridProviderType > DUNE_UNUSED(grd_prvdr) = create();
  }

  static void static_interface()
  {
    std::string static_id_s = GridProviderType::static_id();
    auto grid_provider_d = create();
    std::string static_id_d = grid_provider_d->static_id();
    std::unique_ptr< InterfaceType >& grid_provider_i = grid_provider_d;
    std::string static_id_i = grid_provider_i->static_id();
  } // ... static_interface(...)

private:
  template< class GPT >
  static void check_const_interface(const GPT& grid_provider)
  {
    using Stuff::Grid::ChooseLayer;
    using Stuff::Grid::ChoosePartView;
    const auto& grid_i = grid_provider.grid();
    auto DUNE_UNUSED(leaf_grid_view_1) = grid_provider.leaf_view();
    auto DUNE_UNUSED(leaf_grid_view_2) = grid_provider.template leaf< ChoosePartView::view >();
    //auto leaf_grid_part = grid_provider.template leaf< ChoosePartView::part >();                       // <does not work
    for (int level = 0; level <= grid_i.maxLevel(); ++level) {
      auto DUNE_UNUSED(level_grid_view_1) = grid_provider.level_view(level);
      auto DUNE_UNUSED(level_grid_view_2) = grid_provider.template level< ChoosePartView::view >(level);
      //auto DUNE_UNUSED(level_grid_part) = grid_provider.template level< ChoosePartView::part >(level); // <does not work
    }
  } // ... check_const_interface()

public:
  static void const_interface()
  {
    const auto grid_provider = create();
#if defined(__INTEL_COMPILER)
/**
 * ICC is actually correct and standard compliant in rejecting the #else branch here:
 * 7.3.3 The using declaration [namespace.udecl]
 * 14/ If a function declaration in namespace scope or block scope has the same name and
 * the same parameter types as a function introduced by a using-declaration, and the
 * declarations do not declare the same function, the program is ill-formed.
 *
 * This is just a temporary workaround to have tests build on all compilers again
 **/
    check_const_interface< ConstInterfaceType >(*grid_provider);
#else
    check_const_interface< GridProviderType >(*grid_provider);
    check_const_interface< InterfaceType >(*grid_provider);
#endif
  } // ... const_interface()

private:
  template< class GPT >
  static void check_visualize(const GPT& grid_provider)
  {
    auto type_str = Stuff::Common::Typename< GPT >::value();
    grid_provider.visualize();
    grid_provider.visualize(type_str + "_a");
    grid_provider.visualize(Stuff::Grid::BoundaryInfoConfigs::AllDirichlet::default_config());
    grid_provider.visualize(Stuff::Grid::BoundaryInfoConfigs::AllDirichlet::default_config(), type_str + "_b");
  } // ... check_visualize(...)

public:
  static void visualize()
  {
    if (GridType::dimension <= 3) {
      const auto grid_provider = create();
      check_visualize< GridProviderType >(*grid_provider);
      check_visualize< InterfaceType >(*grid_provider);
    }
  } // ... visualize(...)

}; // class ConstGridProviderBase

template< class GridProviderType >
class GridProviderBase
  : public ConstGridProviderBase< GridProviderType >
{
  typedef ConstGridProviderBase< GridProviderType >  BaseType;
  typedef typename BaseType::GridType GridType;
  typedef Stuff::Grid::ProviderInterface< GridType > InterfaceType;

private:
  template< class GPT >
  static void check_non_const_interface(GPT& grid_provider)
  {
    using Stuff::Grid::ChooseLayer;
    using Stuff::Grid::ChoosePartView;
    auto& grid_i = grid_provider.grid();
    auto DUNE_UNUSED(leaf_grid_part_1) = grid_provider.template leaf< ChoosePartView::part >();
    auto DUNE_UNUSED(leaf_grid_part_2) = grid_provider.leaf_part();
    for (int level = 0; level <= grid_i.maxLevel(); ++level) {
      auto DUNE_UNUSED(level_grid_part_1) = grid_provider.template level< ChoosePartView::part >(level);
      auto DUNE_UNUSED(level_grid_part_2) = grid_provider.level_part(level);
    }
  } // ... check_non_const_interface()

public:
  static void non_const_interface()
  {
    auto grid_provider = BaseType::create();
    check_non_const_interface< GridProviderType >(*grid_provider);
    check_non_const_interface< InterfaceType >(*grid_provider);
  } // ... non_const_interface()

}; // class GridProviderBase

template< class GridType >
struct CubeGridProvider
  : public GridProviderBase< Stuff::Grid::Providers::Cube< GridType > >
{};

typedef testing::Types< SGRIDS
                      , YASPGRIDS
# if HAVE_ALUGRID
                      , ALUGRIDS
# endif
                      > GridTypes;

TYPED_TEST_CASE(CubeGridProvider, GridTypes);
TYPED_TEST(CubeGridProvider, is_default_creatable)
{
  this->is_default_creatable();
}
TYPED_TEST(CubeGridProvider, fulfills_const_interface)
{
  this->const_interface();
}
TYPED_TEST(CubeGridProvider, is_visualizable)
{
  this->visualize();
}

# if HAVE_DUNE_FEM

TYPED_TEST(CubeGridProvider, fulfills_non_const_interface)
{
  this->non_const_interface();
}

# else // HAVE_DUNE_FEM

TEST(DISABLED_CubeGridProvider, fulfills_non_const_interface) {}

# endif

#else // HAVE_DUNE_GRID

TEST(DISABLED_CubeGridProvider, is_default_creatable) {}
TEST(DISABLED_CubeGridProvider, fulfills_const_interface) {}
TEST(DISABLED_CubeGridProvider, is_visualizable) {}

#endif // HAVE_DUNE_GRID

<|endoftext|>


<commit_before>// Copyright 2019 The TCMalloc Authors
//
// 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
//
//     https://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.
//
// This tests the memory accounting when releasing memory to the OS.  As this
// requires careful memory accounting, we avoid allocating at critical times and
// avoid Google Test/background threads.

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <cstdio>
#include <limits>
#include <vector>

#include "benchmark/benchmark.h"
#include "absl/random/random.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "tcmalloc/common.h"
#include "tcmalloc/internal/logging.h"
#include "tcmalloc/internal/memory_stats.h"
#include "tcmalloc/malloc_extension.h"

namespace {

int64_t GetRSS() {
  tcmalloc::tcmalloc_internal::MemoryStats stats;
  CHECK_CONDITION(tcmalloc::tcmalloc_internal::GetMemoryStats(&stats));
  return stats.rss;
}

int64_t UnmappedBytes() {
  absl::optional<size_t> value = tcmalloc::MallocExtension::GetNumericProperty(
      "tcmalloc.pageheap_unmapped_bytes");
  CHECK_CONDITION(value.has_value());
  return *value;
}

}  // namespace

int main() {
  int ret = mlockall(MCL_CURRENT | MCL_FUTURE);
  if (ret != 0) {
    const bool kSoftFail = true;

    if (kSoftFail) {
      // Determine if we should be able to mlock memory due to our limits.
      struct rlimit lock_limit;
      if (getrlimit(RLIMIT_MEMLOCK, &lock_limit) != 0) {
        tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                      "getrlimit failed: errno", errno);
      }

      if (lock_limit.rlim_cur != RLIM_INFINITY && errno == ENOMEM) {
        tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__,
                      "mlockall failed: errno", errno, " mlock limit ",
                      lock_limit.rlim_cur);
        return 0;
      }
    }
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                  "mlockall failed: errno", errno);
  }

  const int kSmallAllocations = 1000;
  const size_t kSmallSize = 256 * 1024;
  const int kLargeAllocations = 1000;
  const size_t kLargeSize = 4 * 1024 * 1024;

  std::vector<void*> ptrs;
  ptrs.reserve(kSmallAllocations + kLargeAllocations);

  absl::BitGen rng;
  for (int i = 0; i < kSmallAllocations; i++) {
    size_t size = absl::LogUniform<size_t>(rng, 0, kSmallSize);
    void* ptr = ::operator new(size);
    memset(ptr, 0xCD, size);
    ::benchmark::DoNotOptimize(ptr);
    ptrs.push_back(ptr);
  }

  for (int i = 0; i < kLargeAllocations; i++) {
    size_t size = absl::LogUniform<size_t>(rng, kLargeSize / 2, kLargeSize);
    void* ptr = ::operator new(size);
    memset(ptr, 0xCD, size);
    ::benchmark::DoNotOptimize(ptr);
    ptrs.push_back(ptr);
  }

  int64_t before, after, before_unmapped, after_unmapped;
  // Release all of the memory that we can.  Verify that RSS change corresponds
  // to what the release logic did.

  before = GetRSS();
  before_unmapped = UnmappedBytes();

  // Clean up.
  for (void* ptr : ptrs) {
    ::operator delete(ptr);
  }

  // Try to release memory TCMalloc thinks it does not need.
  tcmalloc::MallocExtension::ReleaseMemoryToSystem(0);
  after = GetRSS();
  after_unmapped = UnmappedBytes();

  int64_t unmapped_diff = after_unmapped - before_unmapped;
  int64_t memusage_diff = before - after;
  if (unmapped_diff < 0) {
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__, "Memory was mapped.");
  } else if (unmapped_diff % tcmalloc::kHugePageSize != 0) {
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                  "Non-hugepage size for unmapped memory: ", unmapped_diff);
  }

  // Try to release all unused memory.

  tcmalloc::MallocExtension::ReleaseMemoryToSystem(
      std::numeric_limits<size_t>::max());
  after = GetRSS();
  after_unmapped = UnmappedBytes();

  unmapped_diff = after_unmapped - before_unmapped;
  memusage_diff = before - after;
  const double kTolerance = 5e-4;

  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Unmapped Memory [Before]",
                before_unmapped);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Unmapped Memory [After ]",
                after_unmapped);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Unmapped Memory [Diff  ]",
                after_unmapped - before_unmapped);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Memory Usage [Before]",
                before);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Memory Usage [After ]",
                after);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Memory Usage [Diff  ]",
                before - after);

  if (unmapped_diff == 0) {
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                  "No memory was unmapped.");
  }

  if (unmapped_diff * (1. + kTolerance) < memusage_diff ||
      unmapped_diff * (1. - kTolerance) > memusage_diff) {
    tcmalloc::Log(tcmalloc::kCrash,
                  "(after_unmapped - before_unmapped) != (before - after)",
                  after_unmapped - before_unmapped, before - after);
  }

  printf("PASS\n");
  return 0;
}
<commit_msg>Internal change<commit_after>// Copyright 2019 The TCMalloc Authors
//
// 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
//
//     https://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.
//
// This tests the memory accounting when releasing memory to the OS.  As this
// requires careful memory accounting, we avoid allocating at critical times and
// avoid Google Test/background threads.

#include <fcntl.h>
#include <sys/mman.h>
#include <sys/resource.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>

#include <cstdio>
#include <limits>
#include <vector>

#include "benchmark/benchmark.h"
#include "absl/random/random.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "tcmalloc/common.h"
#include "tcmalloc/internal/logging.h"
#include "tcmalloc/internal/memory_stats.h"
#include "tcmalloc/malloc_extension.h"

namespace {

int64_t GetRSS() {
  tcmalloc::tcmalloc_internal::MemoryStats stats;
  CHECK_CONDITION(tcmalloc::tcmalloc_internal::GetMemoryStats(&stats));
  return stats.rss;
}

int64_t UnmappedBytes() {
  absl::optional<size_t> value = tcmalloc::MallocExtension::GetNumericProperty(
      "tcmalloc.pageheap_unmapped_bytes");
  CHECK_CONDITION(value.has_value());
  return *value;
}

}  // namespace

int main() {
  int ret = mlockall(MCL_CURRENT | MCL_FUTURE);
  if (ret != 0) {
    const bool kSoftFail = true;

    if (kSoftFail) {
      // Determine if we should be able to mlock memory due to our limits.
      struct rlimit lock_limit;
      if (getrlimit(RLIMIT_MEMLOCK, &lock_limit) != 0) {
        tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                      "getrlimit failed: errno", errno);
      }

      if (lock_limit.rlim_cur != RLIM_INFINITY && errno == ENOMEM) {
        tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__,
                      "mlockall failed: errno", errno, " mlock limit ",
                      lock_limit.rlim_cur);
        return 0;
      }
    }
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                  "mlockall failed: errno", errno);
  }

  const int kSmallAllocations = 1000;
  const size_t kSmallSize = 256 * 1024;
  const int kLargeAllocations = 1000;
  const size_t kLargeSize = 4 * 1024 * 1024;

  std::vector<void*> ptrs;
  ptrs.reserve(kSmallAllocations + kLargeAllocations);

  absl::BitGen rng;
  for (int i = 0; i < kSmallAllocations; i++) {
    size_t size = absl::LogUniform<size_t>(rng, 0, kSmallSize);
    void* ptr = ::operator new(size);
    memset(ptr, 0xCD, size);
    ::benchmark::DoNotOptimize(ptr);
    ptrs.push_back(ptr);
  }

  for (int i = 0; i < kLargeAllocations; i++) {
    size_t size = absl::LogUniform<size_t>(rng, kLargeSize / 2, kLargeSize);
    void* ptr = ::operator new(size);
    memset(ptr, 0xCD, size);
    ::benchmark::DoNotOptimize(ptr);
    ptrs.push_back(ptr);
  }

  int64_t before, after, before_unmapped, after_unmapped;
  // Release all of the memory that we can.  Verify that RSS change corresponds
  // to what the release logic did.

  before = GetRSS();
  before_unmapped = UnmappedBytes();

  // Clean up.
  for (void* ptr : ptrs) {
    ::operator delete(ptr);
  }

  // Try to release memory TCMalloc thinks it does not need.
  tcmalloc::MallocExtension::ReleaseMemoryToSystem(0);
  after = GetRSS();
  after_unmapped = UnmappedBytes();

  int64_t unmapped_diff = after_unmapped - before_unmapped;
  int64_t memusage_diff = before - after;
  if (unmapped_diff < 0) {
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__, "Memory was mapped.");
  } else if (unmapped_diff % tcmalloc::kHugePageSize != 0) {
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                  "Non-hugepage size for unmapped memory: ", unmapped_diff);
  }

  // Try to release all unused memory.

  tcmalloc::MallocExtension::ReleaseMemoryToSystem(
      std::numeric_limits<size_t>::max());
  after = GetRSS();
  after_unmapped = UnmappedBytes();

  unmapped_diff = after_unmapped - before_unmapped;
  memusage_diff = before - after;
  const double kTolerance = 5e-4;

  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Unmapped Memory [Before]",
                before_unmapped);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Unmapped Memory [After ]",
                after_unmapped);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Unmapped Memory [Diff  ]",
                after_unmapped - before_unmapped);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Memory Usage [Before]",
                before);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Memory Usage [After ]",
                after);
  tcmalloc::Log(tcmalloc::kLog, __FILE__, __LINE__, "Memory Usage [Diff  ]",
                before - after);

  if (unmapped_diff == 0) {
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                  "No memory was unmapped.");
  }

  if (unmapped_diff * (1. + kTolerance) < memusage_diff ||
      unmapped_diff * (1. - kTolerance) > memusage_diff) {
    tcmalloc::Log(tcmalloc::kCrash, __FILE__, __LINE__,
                  "(after_unmapped - before_unmapped) != (before - after)",
                  after_unmapped - before_unmapped, before - after);
  }

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


<commit_before>/***********************************************************************
 *                                                                   _
 *       _____  _                           ____  _                 |_|
 *      |  _  |/ \   ____  ____ __ ___     / ___\/ \   __   _  ____  _
 *      | |_| || |  / __ \/ __ \\ '_  \ _ / /    | |___\ \ | |/ __ \| |
 *      |  _  || |__. ___/. ___/| | | ||_|\ \___ |  _  | |_| |. ___/| |
 *      |_/ \_|\___/\____|\____||_| |_|    \____/|_| |_|_____|\____||_|
 *
 *      ================================================================
 *                 More than a coder, More than a designer
 *      ================================================================
 *
 *
 *      - Document: image.cpp
 *      - Author: aleen42
 *      - Description: image class for all the image obj
 *      - Create Time: Nov 29th, 2015
 *      - Update Time: Feb 18th, 2016
 *
 **********************************************************************/

#include "opencv_main.h"
#include "common.h"

class Image
{
protected:
	Mat img;											// the container of the image
	const char* path;									// the local path of the image

	/* calculate the angle according to 3 points */
	double angle(Point pt1, Point pt2, Point pt0) {
		double dx1 = pt1.x - pt0.x;
		double dy1 = pt1.y - pt0.y;
		double dx2 = pt2.x - pt0.x;
		double dy2 = pt2.y - pt0.y;
		return (dx1 * dx2 + dy1 * dy2) / sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10);
	}

	/* show the detection of squares */
	void debugSquares(vector<vector<Point> > points) {

		for (int i = 0; i < points[0].size(); i++) {
			printf("Point%d: (%d, %d)\n", i, points[0][i].x, points[0][i].y);
		}

		drawContours(img, points, 0, Scalar(255, 0, 0), 1, 8, vector<Vec4i>(), 0, Point());
		// for (int i = 0; i < points.size(); i++) {
		// 	/* draw contour */
		// 	drawContours(img, points, i, Scalar(255, 0, 0), 1, 8, vector<Vec4i>(), 0, Point());

		// 	/* draw bounding rect */
		// 	Rect rect = boundingRect(Mat(points[i]));
		// 	rectangle(img, rect.tl(), rect.br(), cv::Scalar(255, 0, 0), 2, 8, 0);

		// 	/* draw rotated rect */
		// 	RotatedRect minRect = minAreaRect(Mat(points[i]));
		// 	Point2f rect_points[4];
		// 	minRect.points(rect_points);
		// 	for (int j = 0; j < 4; j++) {
		// 		line(img, rect_points[j], rect_points[(j + 1) % 4], Scalar(0, 0, 255), 1, 8);
		// 	}
		// }
	}
public:
	/* constructors of the class */
	Image() {}
	Image(Mat img) : img(img){}

	/* read the image from a local path */
	void readImage(const char* path) {
		/* set the path */
		this->path = path;
		/* read the image according to the path */
		this->img = imread(path);
		/* check existence */
		if (this->img.empty()) {
			ostringstream os;
			os << "Cannot load image from" << path;
			Common::errorPrint(os.str().c_str());
			/* exit */
			exit(-1);
		}
	}

	/* threshold algorithm */
	void thresholdImage(THRESHOLD_TYPE type) {
		Mat gray;
		const double threshold_value = 0.0;
		const double max_binary_value = 255.0;

		/* convert gray */
		cvtColor(this->img, gray, CV_BGR2GRAY);

		threshold(gray, this->img, threshold_value, max_binary_value, type);
	}

	/* detect squares algorithm by karlphillip */
	vector<vector<Point> > detectSquare(bool debug = false) {
		/* blur will enhance edge detection */
		Mat blurred(this->img);

		medianBlur(this->img, blurred, 9);

		Mat gray0(blurred.size(), CV_8U), gray;

		/* reserved Points array */
		vector<vector<Point> > reserved;
		/* contours Points array*/
		vector<vector<Point> > contours;

		/* find squares in every color plane of the image */
		for (int c = 0; c < 3; c++) {
			int ch[] = { c, 0 };

			/* canny ratio which is recommended as 3 by Canny */
			int ratio = 2;
			int lowThreshold = 10;

			mixChannels(&blurred, 1, &gray0, 1, ch, 1);

			/* try several threshold level */
			const int threshold_level = 2;
			for (int l = 0; l < threshold_level; l++) {
				/* Use Canny instead of zero threshold level */
				/* Canny helps to catch squares with gradient shading */
				if (l == 0) {
					Canny(gray0, gray, lowThreshold, ratio * lowThreshold, 3);

					/* Dilage helps to remove potential holes between edge segments */
					dilate(gray, gray, Mat(), Point(-1, -1));
				} else {
					gray = gray0 >= (l + 1) * 255 / threshold_level;
				}

				vector<Vec4i> hierarchy;
				/* find contours and store them in a list */
				findContours(gray, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

				/* draw contours to improve accuracy */
				for (size_t i = 0; i < contours.size(); i++) {
					drawContours(this->img, contours, i, Scalar(0, 0, 0), 1, 8, hierarchy, 0, Point());
				}

				/* test contours */
				vector<Point> approx;
				for (size_t i = 0; i < contours.size(); i++) {
					/* approximate contour with accuracy proportional to the contour perimeter */
					approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.02, true);

					/*
					 * Note: absolute value of an area is used becuase
					 *       area may be positive or negative, in accordance
					 *		 with the contour orientation
					 */
					// cout << "size: " << approx.size() << endl;
					// cout << "area: " << fabs(contourArea(Mat(approx))) << endl;
					if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx))) {
						double maxCosine = 0;

						for (int j = 2; j < 5; j++) {
							double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
							maxCosine = MAX(maxCosine, cosine);
						}

						reserved.push_back(approx);

						//if (maxCosine < 0.3) {
						//	reserved.push_back(approx);
						//}
					}
				}
			}
		}

		/* check debug option */
 		if (debug && reserved.size() > 0) {
			debugSquares(reserved);
		}

		return reserved;
	}

	/* detect corner */
	vector<Point2f> detectCorner(const char* quantity, bool debug = false, const char* path = "data.json") {
		/* clock */
		time_t start = clock();

		vector<Point2f> Corners;

		/* parameters */
		const int maxCorners = atoi(quantity);
		const double qualityLevels = 0.001;
		const double minDistance = 10;
		const int blockSize = 10;
		const bool useHarrisDetector = false;
		const int r = 5;

		Mat gray;
		cvtColor(this->img, gray, COLOR_BGR2GRAY);

		goodFeaturesToTrack(gray, Corners, maxCorners, qualityLevels, minDistance, Mat(), blockSize, useHarrisDetector);

		cJSON* pointsArray = cJSON_CreateArray();

		for (size_t i = 0; i < Corners.size(); i++) {
			if (debug) {
				ostringstream os;
				os << " (" << Corners[i].x << ", " << Corners[i].y << ")";
				circle(this->img, Corners[i], r, Scalar(255, 255, 255), 2, 8);
				putText(this->img, os.str(), Corners[i], FONT_HERSHEY_SCRIPT_SIMPLEX, 0.6, Scalar(0, 0, 255), 1, 8);
			}

			/* create json */
			cJSON* item = cJSON_CreateObject();
			cJSON_AddNumberToObject(item, "xPrecent", (double)Corners[i].x / this->img.cols);
			cJSON_AddNumberToObject(item, "yPrecent", (double)Corners[i].y / this->img.rows);
			cJSON_AddNumberToObject(item, "x", Corners[i].x);
			cJSON_AddNumberToObject(item, "y", Corners[i].y);

			cJSON_AddItemToArray(pointsArray, item);
		}

		time_t end = clock();
		cJSON* data = cJSON_CreateObject();
		const char* duration = (Common::doubleToStr(double(end - start) / CLOCKS_PER_SEC) + "s").c_str();
		cJSON_AddStringToObject(data, "time", duration);

		cJSON_AddNumberToObject(data, "width", this->img.cols);
		cJSON_AddNumberToObject(data, "height", this->img.rows);

		/* write the data.json */
		ofstream file;
		file.open(path, ios::out);

		if (file.is_open()) {
			file << cJSON_Print(pointsArray);
			cJSON_AddItemToObject(data, "data", pointsArray);
			file.close();
		}

		Common::successPrint(data);

		return Corners;
	}

	void fastDetectCorner(bool debug = false) {
		vector<KeyPoint> keyPoints;

		FAST(this->img, keyPoints, 10, true, FastFeatureDetector::TYPE_7_12);

		if (debug) {
			drawKeypoints(this->img, keyPoints, this->img, Scalar(255, 255, 255), DrawMatchesFlags::DRAW_OVER_OUTIMG);
		}
	}

	/* write the image to the local path */
	void writeImage(const char* path) {
		/* save the image */
		imwrite(path, this->img);
	}

	/* a mothod to show the image */
	void showImage() {
		/* open the image */
		imshow("image", this->img);
		/* wait for the return */
		waitKey();
	}

	/* container */
	/* image */
	Mat getImage() {
		return this->img;
	}

	/* properties */
	/* width */
	int getWidth() {
		return this->img.cols;
	}

	/* height */
	int getHeight() {
		return this->img.rows;
	}

	/* size */
	Size getSize() {
		return this->img.size();
	}

	/* pointer to the matrix */
	uchar* getPtr(int n) {
		return this->img.ptr<uchar>(n);
	}
};
<commit_msg>update<commit_after>/***********************************************************************
 *                                                                   _
 *       _____  _                           ____  _                 |_|
 *      |  _  |/ \   ____  ____ __ ___     / ___\/ \   __   _  ____  _
 *      | |_| || |  / __ \/ __ \\ '_  \ _ / /    | |___\ \ | |/ __ \| |
 *      |  _  || |__. ___/. ___/| | | ||_|\ \___ |  _  | |_| |. ___/| |
 *      |_/ \_|\___/\____|\____||_| |_|    \____/|_| |_|_____|\____||_|
 *
 *      ================================================================
 *                 More than a coder, More than a designer
 *      ================================================================
 *
 *
 *      - Document: image.cpp
 *      - Author: aleen42
 *      - Description: image class for all the image obj
 *      - Create Time: Nov 29th, 2015
 *      - Update Time: Feb 18th, 2016
 *
 **********************************************************************/

#include "opencv_main.h"
#include "common.h"

class Image
{
protected:
	Mat img;											// the container of the image
	const char* path;									// the local path of the image

	/* calculate the angle according to 3 points */
	double angle(Point pt1, Point pt2, Point pt0) {
		double dx1 = pt1.x - pt0.x;
		double dy1 = pt1.y - pt0.y;
		double dx2 = pt2.x - pt0.x;
		double dy2 = pt2.y - pt0.y;
		return (dx1 * dx2 + dy1 * dy2) / sqrt((dx1 * dx1 + dy1 * dy1) * (dx2 * dx2 + dy2 * dy2) + 1e-10);
	}

	/* show the detection of squares */
	void debugSquares(vector<vector<Point> > points) {

		for (int i = 0; i < points[0].size(); i++) {
			printf("Point%d: (%d, %d)\n", i, points[0][i].x, points[0][i].y);
		}

		drawContours(img, points, 0, Scalar(255, 0, 0), 1, 8, vector<Vec4i>(), 0, Point());
		// for (int i = 0; i < points.size(); i++) {
		// 	/* draw contour */
		// 	drawContours(img, points, i, Scalar(255, 0, 0), 1, 8, vector<Vec4i>(), 0, Point());

		// 	/* draw bounding rect */
		// 	Rect rect = boundingRect(Mat(points[i]));
		// 	rectangle(img, rect.tl(), rect.br(), cv::Scalar(255, 0, 0), 2, 8, 0);

		// 	/* draw rotated rect */
		// 	RotatedRect minRect = minAreaRect(Mat(points[i]));
		// 	Point2f rect_points[4];
		// 	minRect.points(rect_points);
		// 	for (int j = 0; j < 4; j++) {
		// 		line(img, rect_points[j], rect_points[(j + 1) % 4], Scalar(0, 0, 255), 1, 8);
		// 	}
		// }
	}
public:
	/* constructors of the class */
	Image() {}
	Image(Mat img) : img(img){}

	/* read the image from a local path */
	void readImage(const char* path) {
		/* set the path */
		this->path = path;
		/* read the image according to the path */
		this->img = imread(path);
		/* check existence */
		if (this->img.empty()) {
			ostringstream os;
			os << "Cannot load image from" << path;
			Common::errorPrint(os.str().c_str());
			/* exit */
			exit(-1);
		}
	}

	/* threshold algorithm */
	void thresholdImage(THRESHOLD_TYPE type) {
		Mat gray;
		const double threshold_value = 0.0;
		const double max_binary_value = 255.0;

		/* convert gray */
		cvtColor(this->img, gray, CV_BGR2GRAY);

		threshold(gray, this->img, threshold_value, max_binary_value, type);
	}

	/* detect squares algorithm by karlphillip */
	vector<vector<Point> > detectSquare(bool debug = false) {
		/* blur will enhance edge detection */
		Mat blurred(this->img);

		medianBlur(this->img, blurred, 9);

		Mat gray0(blurred.size(), CV_8U), gray;

		/* reserved Points array */
		vector<vector<Point> > reserved;
		/* contours Points array*/
		vector<vector<Point> > contours;

		/* find squares in every color plane of the image */
		for (int c = 0; c < 3; c++) {
			int ch[] = { c, 0 };

			/* canny ratio which is recommended as 3 by Canny */
			int ratio = 2;
			int lowThreshold = 10;

			mixChannels(&blurred, 1, &gray0, 1, ch, 1);

			/* try several threshold level */
			const int threshold_level = 2;
			for (int l = 0; l < threshold_level; l++) {
				/* Use Canny instead of zero threshold level */
				/* Canny helps to catch squares with gradient shading */
				if (l == 0) {
					Canny(gray0, gray, lowThreshold, ratio * lowThreshold, 3);

					/* Dilage helps to remove potential holes between edge segments */
					dilate(gray, gray, Mat(), Point(-1, -1));
				} else {
					gray = gray0 >= (l + 1) * 255 / threshold_level;
				}

				vector<Vec4i> hierarchy;
				/* find contours and store them in a list */
				findContours(gray, contours, hierarchy, CV_RETR_LIST, CV_CHAIN_APPROX_SIMPLE, Point(0, 0));

				/* draw contours to improve accuracy */
				for (size_t i = 0; i < contours.size(); i++) {
					drawContours(this->img, contours, i, Scalar(0, 0, 0), 1, 8, hierarchy, 0, Point());
				}

				/* test contours */
				vector<Point> approx;
				for (size_t i = 0; i < contours.size(); i++) {
					/* approximate contour with accuracy proportional to the contour perimeter */
					approxPolyDP(Mat(contours[i]), approx, arcLength(Mat(contours[i]), true) * 0.02, true);

					/*
					 * Note: absolute value of an area is used becuase
					 *       area may be positive or negative, in accordance
					 *		 with the contour orientation
					 */
					// cout << "size: " << approx.size() << endl;
					// cout << "area: " << fabs(contourArea(Mat(approx))) << endl;
					if (approx.size() == 4 && fabs(contourArea(Mat(approx))) > 1000 && isContourConvex(Mat(approx))) {
						double maxCosine = 0;

						for (int j = 2; j < 5; j++) {
							double cosine = fabs(angle(approx[j % 4], approx[j - 2], approx[j - 1]));
							maxCosine = MAX(maxCosine, cosine);
						}

						reserved.push_back(approx);

						//if (maxCosine < 0.3) {
						//	reserved.push_back(approx);
						//}
					}
				}
			}
		}

		/* check debug option */
 		if (debug && reserved.size() > 0) {
			debugSquares(reserved);
		}

		return reserved;
	}

	/* detect corner */
	vector<Point2f> detectCorner(const char* quantity, bool debug = false, const char* path = "data.json") {
		/* clock */
		time_t start = clock();

		vector<Point2f> Corners;

		/* parameters */
		const int maxCorners = atoi(quantity);
		const double qualityLevels = 0.01;
		const double minDistance = 10;
		const int blockSize = 10;
		const bool useHarrisDetector = false;
		const int r = 5;

		Mat gray;
		cvtColor(this->img, gray, COLOR_BGR2GRAY);

		goodFeaturesToTrack(gray, Corners, maxCorners, qualityLevels, minDistance, Mat(), blockSize, useHarrisDetector);

		cJSON* pointsArray = cJSON_CreateArray();

		for (size_t i = 0; i < Corners.size(); i++) {
			if (debug) {
				ostringstream os;
				os << " (" << Corners[i].x << ", " << Corners[i].y << ")";
				circle(this->img, Corners[i], r, Scalar(255, 255, 255), 2, 8);
				putText(this->img, os.str(), Corners[i], FONT_HERSHEY_SCRIPT_SIMPLEX, 0.6, Scalar(0, 0, 255), 1, 8);
			}

			/* create json */
			cJSON* item = cJSON_CreateObject();
			cJSON_AddNumberToObject(item, "xPrecent", (double)Corners[i].x / this->img.cols);
			cJSON_AddNumberToObject(item, "yPrecent", (double)Corners[i].y / this->img.rows);
			cJSON_AddNumberToObject(item, "x", Corners[i].x);
			cJSON_AddNumberToObject(item, "y", Corners[i].y);

			cJSON_AddItemToArray(pointsArray, item);
		}

		time_t end = clock();
		cJSON* data = cJSON_CreateObject();
		const char* duration = (Common::doubleToStr(double(end - start) / CLOCKS_PER_SEC) + "s").c_str();
		cJSON_AddStringToObject(data, "time", duration);

		cJSON_AddNumberToObject(data, "width", this->img.cols);
		cJSON_AddNumberToObject(data, "height", this->img.rows);

		/* write the data.json */
		ofstream file;
		file.open(path, ios::out);

		if (file.is_open()) {
			file << cJSON_Print(pointsArray);
			cJSON_AddItemToObject(data, "data", pointsArray);
			file.close();
		}

		Common::successPrint(data);

		return Corners;
	}

	void fastDetectCorner(bool debug = false) {
		vector<KeyPoint> keyPoints;

		FAST(this->img, keyPoints, 10, true, FastFeatureDetector::TYPE_7_12);

		if (debug) {
			drawKeypoints(this->img, keyPoints, this->img, Scalar(255, 255, 255), DrawMatchesFlags::DRAW_OVER_OUTIMG);
		}
	}

	/* write the image to the local path */
	void writeImage(const char* path) {
		/* save the image */
		imwrite(path, this->img);
	}

	/* a mothod to show the image */
	void showImage() {
		/* open the image */
		imshow("image", this->img);
		/* wait for the return */
		waitKey();
	}

	/* container */
	/* image */
	Mat getImage() {
		return this->img;
	}

	/* properties */
	/* width */
	int getWidth() {
		return this->img.cols;
	}

	/* height */
	int getHeight() {
		return this->img.rows;
	}

	/* size */
	Size getSize() {
		return this->img.size();
	}

	/* pointer to the matrix */
	uchar* getPtr(int n) {
		return this->img.ptr<uchar>(n);
	}
};
<|endoftext|>