<commit_before>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/storage.hpp"
#include <deque>
#include "libtorrent/disk_io_thread.hpp"

namespace libtorrent
{

	disk_io_thread::disk_io_thread(int block_size)
		: m_abort(false)
		, m_queue_buffer_size(0)
		, m_pool(block_size)
		, m_disk_io_thread(boost::ref(*this))
	{}

	disk_io_thread::~disk_io_thread()
	{
		boost::mutex::scoped_lock l(m_mutex);
		m_abort = true;
		m_signal.notify_all();
		l.unlock();

		m_disk_io_thread.join();
	}

	// aborts read operations
	void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
	{
		boost::mutex::scoped_lock l(m_mutex);
		// read jobs are aborted, write and move jobs are syncronized
		for (std::deque<disk_io_job>::iterator i = m_jobs.begin();
			i != m_jobs.end();)
		{
			if (i->storage != s)
			{
				++i;
				continue;
			}
			if (i->action == disk_io_job::read)
			{
				i->callback(-1, *i);
				m_jobs.erase(i++);
				continue;
			}
			++i;
		}
		m_signal.notify_all();
	}

	bool range_overlap(int start1, int length1, int start2, int length2)
	{
		return (start1 <= start2 && start1 + length1 > start2)
			|| (start2 <= start1 && start2 + length2 > start1);
	}

	namespace
	{
		bool operator<(disk_io_job const& lhs, disk_io_job const& rhs)
		{
			if (lhs.storage.get() < rhs.storage.get()) return true;
			if (lhs.storage.get() > rhs.storage.get()) return false;
			if (lhs.piece < rhs.piece) return true;
			if (lhs.piece > rhs.piece) return false;
			if (lhs.offset < rhs.offset) return true;
//			if (lhs.offset > rhs.offset) return false;
			return false;
		}
	}

	void disk_io_thread::add_job(disk_io_job const& j
		, boost::function<void(int, disk_io_job const&)> const& f)
	{
		assert(!j.callback);
		boost::mutex::scoped_lock l(m_mutex);

		std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
		if (j.action == disk_io_job::read)
		{
			// when we're reading, we may not skip
			// ahead of any write operation that overlaps
			// the region we're reading
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::read && *i < j)
					break;
				if (i->action == disk_io_job::write
					&& i->storage == j.storage
					&& i->piece == j.piece
					&& range_overlap(i->offset, i->buffer_size
						, j.offset, j.buffer_size))
				{
					// we have to stop, and we haven't
					// found a suitable place for this job
					// so just queue it up at the end
					i = m_jobs.rbegin();
					break;
				}
			}
		}
		else if (j.action == disk_io_job::write)
		{
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::write && *i < j)
				{
					if (i != m_jobs.rbegin()
						&& i.base()->storage.get() != j.storage.get())
						i = m_jobs.rbegin();
					break;
				}
			}
		}

		if (i == m_jobs.rend()) i = m_jobs.rbegin();

		std::deque<disk_io_job>::iterator k = m_jobs.insert(i.base(), j);
		k->callback.swap(const_cast<boost::function<void(int, disk_io_job const&)>&>(f));
		if (j.action == disk_io_job::write)
			m_queue_buffer_size += j.buffer_size;
		assert(j.storage.get());
		m_signal.notify_all();
	}

	char* disk_io_thread::allocate_buffer()
	{
		boost::mutex::scoped_lock l(m_mutex);
		return (char*)m_pool.ordered_malloc();
	}

	void disk_io_thread::operator()()
	{
		for (;;)
		{
			boost::mutex::scoped_lock l(m_mutex);
			while (m_jobs.empty() && !m_abort)
				m_signal.wait(l);
			if (m_abort && m_jobs.empty()) return;

			boost::function<void(int, disk_io_job const&)> handler;
			handler.swap(m_jobs.front().callback);
			disk_io_job j = m_jobs.front();
			m_jobs.pop_front();
			m_queue_buffer_size -= j.buffer_size;
			l.unlock();

			int ret = 0;

			try
			{
//				std::cerr << "DISK THREAD: executing job: " << j.action << std::endl;
				switch (j.action)
				{
					case disk_io_job::read:
						l.lock();
						j.buffer = (char*)m_pool.ordered_malloc();
						l.unlock();
						if (j.buffer == 0)
						{
							ret = -1;
							j.str = "out of memory";
						}
						else
						{
							ret = j.storage->read_impl(j.buffer, j.piece, j.offset
								, j.buffer_size);

							// simulates slow drives
							// usleep(300);
						}
						break;
					case disk_io_job::write:
						assert(j.buffer);
						j.storage->write_impl(j.buffer, j.piece, j.offset
							, j.buffer_size);

						// simulates a slow drive
						// usleep(300);
						break;
					case disk_io_job::hash:
						{
							sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
							j.str.resize(20);
							std::memcpy(&j.str[0], &h[0], 20);
						}
						break;
					case disk_io_job::move_storage:
						ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
						break;
					case disk_io_job::release_files:
						j.storage->release_files_impl();
						break;
				}
			}
			catch (std::exception& e)
			{
//				std::cerr << "DISK THREAD: exception: " << e.what() << std::endl;
				j.str = e.what();
				ret = -1;
			}

//			if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl;
//			else std::cerr << "DISK THREAD: invoking callback" << std::endl;
			try { if (handler) handler(ret, j); }
			catch (std::exception&) {}

			if (j.buffer) m_pool.ordered_free(j.buffer);
		}
	}
}

<commit_msg>fixed mutex issue in disk io thread<commit_after>/*

Copyright (c) 2007, Arvid Norberg
All rights reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:

    * Redistributions of source code must retain the above copyright
      notice, this list of conditions and the following disclaimer.
    * Redistributions in binary form must reproduce the above copyright
      notice, this list of conditions and the following disclaimer in
      the documentation and/or other materials provided with the distribution.
    * Neither the name of the author nor the names of its
      contributors may be used to endorse or promote products derived
      from this software without specific prior written permission.

THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.

*/

#include "libtorrent/storage.hpp"
#include <deque>
#include "libtorrent/disk_io_thread.hpp"

namespace libtorrent
{

	disk_io_thread::disk_io_thread(int block_size)
		: m_abort(false)
		, m_queue_buffer_size(0)
		, m_pool(block_size)
		, m_disk_io_thread(boost::ref(*this))
	{}

	disk_io_thread::~disk_io_thread()
	{
		boost::mutex::scoped_lock l(m_mutex);
		m_abort = true;
		m_signal.notify_all();
		l.unlock();

		m_disk_io_thread.join();
	}

	// aborts read operations
	void disk_io_thread::stop(boost::intrusive_ptr<piece_manager> s)
	{
		boost::mutex::scoped_lock l(m_mutex);
		// read jobs are aborted, write and move jobs are syncronized
		for (std::deque<disk_io_job>::iterator i = m_jobs.begin();
			i != m_jobs.end();)
		{
			if (i->storage != s)
			{
				++i;
				continue;
			}
			if (i->action == disk_io_job::read)
			{
				i->callback(-1, *i);
				m_jobs.erase(i++);
				continue;
			}
			++i;
		}
		m_signal.notify_all();
	}

	bool range_overlap(int start1, int length1, int start2, int length2)
	{
		return (start1 <= start2 && start1 + length1 > start2)
			|| (start2 <= start1 && start2 + length2 > start1);
	}

	namespace
	{
		bool operator<(disk_io_job const& lhs, disk_io_job const& rhs)
		{
			if (lhs.storage.get() < rhs.storage.get()) return true;
			if (lhs.storage.get() > rhs.storage.get()) return false;
			if (lhs.piece < rhs.piece) return true;
			if (lhs.piece > rhs.piece) return false;
			if (lhs.offset < rhs.offset) return true;
//			if (lhs.offset > rhs.offset) return false;
			return false;
		}
	}

	void disk_io_thread::add_job(disk_io_job const& j
		, boost::function<void(int, disk_io_job const&)> const& f)
	{
		assert(!j.callback);
		boost::mutex::scoped_lock l(m_mutex);

		std::deque<disk_io_job>::reverse_iterator i = m_jobs.rbegin();
		if (j.action == disk_io_job::read)
		{
			// when we're reading, we may not skip
			// ahead of any write operation that overlaps
			// the region we're reading
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::read && *i < j)
					break;
				if (i->action == disk_io_job::write
					&& i->storage == j.storage
					&& i->piece == j.piece
					&& range_overlap(i->offset, i->buffer_size
						, j.offset, j.buffer_size))
				{
					// we have to stop, and we haven't
					// found a suitable place for this job
					// so just queue it up at the end
					i = m_jobs.rbegin();
					break;
				}
			}
		}
		else if (j.action == disk_io_job::write)
		{
			for (; i != m_jobs.rend(); ++i)
			{
				if (i->action == disk_io_job::write && *i < j)
				{
					if (i != m_jobs.rbegin()
						&& i.base()->storage.get() != j.storage.get())
						i = m_jobs.rbegin();
					break;
				}
			}
		}

		if (i == m_jobs.rend()) i = m_jobs.rbegin();

		std::deque<disk_io_job>::iterator k = m_jobs.insert(i.base(), j);
		k->callback.swap(const_cast<boost::function<void(int, disk_io_job const&)>&>(f));
		if (j.action == disk_io_job::write)
			m_queue_buffer_size += j.buffer_size;
		assert(j.storage.get());
		m_signal.notify_all();
	}

	char* disk_io_thread::allocate_buffer()
	{
		boost::mutex::scoped_lock l(m_mutex);
		return (char*)m_pool.ordered_malloc();
	}

	void disk_io_thread::operator()()
	{
		for (;;)
		{
			boost::mutex::scoped_lock l(m_mutex);
			while (m_jobs.empty() && !m_abort)
				m_signal.wait(l);
			if (m_abort && m_jobs.empty()) return;

			boost::function<void(int, disk_io_job const&)> handler;
			handler.swap(m_jobs.front().callback);
			disk_io_job j = m_jobs.front();
			m_jobs.pop_front();
			m_queue_buffer_size -= j.buffer_size;
			l.unlock();

			int ret = 0;

			try
			{
//				std::cerr << "DISK THREAD: executing job: " << j.action << std::endl;
				switch (j.action)
				{
					case disk_io_job::read:
						l.lock();
						j.buffer = (char*)m_pool.ordered_malloc();
						l.unlock();
						if (j.buffer == 0)
						{
							ret = -1;
							j.str = "out of memory";
						}
						else
						{
							ret = j.storage->read_impl(j.buffer, j.piece, j.offset
								, j.buffer_size);

							// simulates slow drives
							// usleep(300);
						}
						break;
					case disk_io_job::write:
						assert(j.buffer);
						j.storage->write_impl(j.buffer, j.piece, j.offset
							, j.buffer_size);

						// simulates a slow drive
						// usleep(300);
						break;
					case disk_io_job::hash:
						{
							sha1_hash h = j.storage->hash_for_piece_impl(j.piece);
							j.str.resize(20);
							std::memcpy(&j.str[0], &h[0], 20);
						}
						break;
					case disk_io_job::move_storage:
						ret = j.storage->move_storage_impl(j.str) ? 1 : 0;
						break;
					case disk_io_job::release_files:
						j.storage->release_files_impl();
						break;
				}
			}
			catch (std::exception& e)
			{
//				std::cerr << "DISK THREAD: exception: " << e.what() << std::endl;
				j.str = e.what();
				ret = -1;
			}

//			if (!handler) std::cerr << "DISK THREAD: no callback specified" << std::endl;
//			else std::cerr << "DISK THREAD: invoking callback" << std::endl;
			try { if (handler) handler(ret, j); }
			catch (std::exception&) {}

			if (j.buffer)
			{
				l.lock();
				m_pool.ordered_free(j.buffer);
			}
		}
	}
}

<|endoftext|>


<commit_before>#include "FFMpegIn.hpp"
#include "Global.hpp"
#include "Array.hpp"

#include <QDebug>

extern "C"
{
	#include <libavformat/avformat.h>
	#include <libswresample/swresample.h>
	#include <libavutil/opt.h>
}

#ifdef Q_OS_LINUX
	#include <pthread.h>
	#include <sched.h>
#endif

FFMpegDec::FFMpegDec( FFMpegIn &block ) :
	block( block ),
	fmtCtx( NULL ), aStream( NULL ), aCodec( NULL ), swr( NULL ),
	frame( ( AVFrame * )av_mallocz( sizeof *frame ) ),
	canGetBuffer( false )
{}
FFMpegDec::~FFMpegDec()
{
	av_free( frame );
}

bool FFMpegDec::start()
{
	lastTime = get_buffer_idx = buffers_available = 0;
	canGetBuffer = stopped = true;
	seekTo = -1;
	br = false;
	if ( avformat_open_input( &fmtCtx, block.file, NULL, NULL ) == 0 && avformat_find_stream_info( fmtCtx, NULL ) >= 0 )
	{
		for ( unsigned i = 0 ; i < fmtCtx->nb_streams ; ++i )
			if ( fmtCtx->streams[ i ]->codec->codec_type == AVMEDIA_TYPE_AUDIO )
			{
				aStream = fmtCtx->streams[ i ];
				break;
			}
		if ( aStream && !avcodec_open2( aStream->codec, avcodec_find_decoder( aStream->codec->codec_id ), NULL ) )
		{
			aCodec = aStream->codec;
			channels = aCodec->channels;
			swr = swr_alloc_set_opts( NULL, av_get_default_channel_layout( block.outputsCount() ), AV_SAMPLE_FMT_FLT, Global::getSampleRate(), av_get_default_channel_layout( channels ), aCodec->sample_fmt, aCodec->sample_rate, 0, NULL );
			av_opt_set_int( swr, "linear_interp", true, 0 );
			if ( !swr_init( swr ) )
			{
				reinterpret_cast< FFMpegInUI * >( block.settings->getAdditionalSettings() )->setMaxTime( ( duration = fmtCtx->duration / AV_TIME_BASE ) );
				QThread::start();
				return true;
			}
		}
	}
	return false;
}
void FFMpegDec::stop()
{
	block.mutex.lock();
	canGetBuffer = false;
	block.outBuffer = NULL;
	block.mutex.unlock();
	if ( isRunning() )
	{
		buffer_mutex.lock();
		br = true;
		if ( fmtCtx && fmtCtx->pb )
			fmtCtx->pb->eof_reached = true;
		buffer_cond.wakeOne();
		buffer_mutex.unlock();
		wait();
	}
	aStream = NULL;
	aCodec = NULL;
	swr_free( &swr );
	avformat_close_input( &fmtCtx );
	for ( int i = 0 ; i < NUM_BUFFERS ; ++i )
		outBuffer[ i ].clear();
}

const float *FFMpegDec::getBuffer()
{
	buffer_mutex.lock();
	if ( !canGetBuffer || ( !buffers_available && block.nonblocking ) )
	{
		buffer_mutex.unlock();
		return NULL;
	}
	if ( !buffers_available && !stopped )
		get_buffer_cond.wait( &buffer_mutex );
	if ( buffers_available )
	{
		buffer_mutex.unlock();
		block.outBufferSize = outBufferSamples[ get_buffer_idx ];
		const float *buffer = outBuffer[ get_buffer_idx ].data();
		block.outBufferPos = 0;
		if ( ++get_buffer_idx == NUM_BUFFERS )
			get_buffer_idx = 0;
		return buffer;
	}
	buffer_mutex.unlock();
	return NULL;
}
void FFMpegDec::releaseBuffer()
{
	buffer_mutex.lock();
	--buffers_available;
	buffer_cond.wakeOne();
	buffer_mutex.unlock();
}

void FFMpegDec::run()
{
	int buffer_idx = 0;
	if ( block.highPriority )
	{
#ifdef Q_OS_LINUX
		sched_param param = { 1 };
		if ( pthread_setschedparam( pthread_self(), SCHED_RR, &param ) )
			perror( "Nie można ustawić SCHED_RR dla wątku FFMpeg" );
		else
#endif
			setPriority( HighestPriority );
	}
	while ( !br )
	{
		AVPacket pkt;
		pkt.data = NULL;
		int e = 0;
		while ( !br && ( e = av_read_frame( fmtCtx, &pkt ) ) >= 0 )
		{
			int outBufferSize = 0;
			stopped = false;
			if ( pkt.stream_index == aStream->index )
			{
				AVPacket pkt_tmp = pkt;
				int ok = 0, bread;
				while ( ( bread = avcodec_decode_audio4( aCodec, frame, &ok, &pkt_tmp ) ) >= 0 && ok )
				{
					if ( aCodec->channels == channels )
					{
						const int out_size = ceil( frame->nb_samples * ( float )Global::getSampleRate() / ( float )aCodec->sample_rate );
						int buffer_size = outBufferSize + out_size * block.outputsCount();

						if ( outBuffer[ buffer_idx ].size() < buffer_size )
							outBuffer[ buffer_idx ].resize( buffer_size );
						quint8 *out[] = { ( quint8 * )( outBuffer[ buffer_idx ].data() + outBufferSize ) };
						if ( ( buffer_size = swr_convert( swr, out, out_size, ( const quint8 ** )frame->extended_data, frame->nb_samples ) ) > 0 )
							outBufferSize += buffer_size * block.outputsCount();
					}
					if ( duration > 0 )
					{
						double currentTime = av_frame_get_best_effort_timestamp( frame ) * av_q2d( aStream->time_base );
						if ( currentTime - lastTime >= 1.0 )
						{
							lastTime = ( int )currentTime;
							emit reinterpret_cast< FFMpegInUI * >( block.settings->getAdditionalSettings() )->setTime( lastTime );
						}
					}
					pkt_tmp.data += bread;
					pkt_tmp.size -= bread;
				}
			}
			av_free_packet( &pkt );
			if ( outBufferSize )
			{
				outBufferSamples[ buffer_idx ] = outBufferSize;
				if ( ++buffer_idx >= NUM_BUFFERS )
					buffer_idx = 0;
				buffer_mutex.lock();
				if ( !br )
				{
					++buffers_available;
					get_buffer_cond.wakeOne();
					if ( buffers_available == NUM_BUFFERS )
						buffer_cond.wait( &buffer_mutex );
				}
				buffer_mutex.unlock();
			}
			if ( seekTo > -1 )
				break;
		}
		if ( seekTo > -1 )
		{
			if ( !br && !av_seek_frame( fmtCtx, -1, ( int64_t )seekTo * AV_TIME_BASE, seekTo < lastTime ? AVSEEK_FLAG_BACKWARD : 0 ) )
			{
				avcodec_flush_buffers( aCodec );
				lastTime = seekTo;
			}
			seekTo = -1;
		}
		else if ( !br && e == AVERROR_EOF )
		{
			if ( block.loop && !av_seek_frame( fmtCtx, -1, 0, AVSEEK_FLAG_BACKWARD ) )
			{
				avcodec_flush_buffers( aCodec );
				lastTime = 0;
			}
			else
			{
				if ( !stopped )
				{
					buffer_mutex.lock();
					stopped = true;
					get_buffer_cond.wakeOne();
					buffer_mutex.unlock();
				}
				msleep( 100 );
			}
		}
	}
}

/**/

FFMpegIn::FFMpegIn() :
	Block( "FFMpeg input", "Odtwarza pliki dźwiękowe", 0, 1, SOURCE ),
	ffdec( *this ),
	loop( false ), highPriority( false ), nonblocking( Global::isRealTime() )
{}

bool FFMpegIn::start()
{
	outBuffer = NULL;
	settings->setRunMode( true );
	if ( !ffdec.start() )
	{
		if ( file.isEmpty() )
			err = "Podaj ścieżkę do pliku!";
		else if ( !QFile::exists( file ) )
			err = "Podany plik nie istnieje!";
		else
			err = "Sprawdź poprawność pliku!";
		return false;
	}
	return true;
}
void FFMpegIn::exec( Array< Sample > &samples )
{
	mutex.lock();
	if ( !outBuffer )
		outBuffer = ffdec.getBuffer();
	if ( outBuffer )
	{
		for ( int i = 0 ; i < outputsCount() ; ++i )
			samples += ( Sample ){ getTarget( i ), outBuffer[ outBufferPos++ ] };
		if ( !( outBufferSize -= outputsCount() ) )
		{
			ffdec.releaseBuffer();
			outBuffer = NULL;
		}
	}
	else for ( int i = 0 ; i < outputsCount() ; ++i )
		samples += ( Sample ){ getTarget( i ), 0.0f };
	mutex.unlock();
}
void FFMpegIn::stop()
{
	settings->setRunMode( false );
	ffdec.stop();
}

Block *FFMpegIn::createInstance()
{
	FFMpegIn *block = new FFMpegIn;
	block->settings = new Settings( *block, false, 0, 0, true, 1, maxIO, false, new FFMpegInUI( *block ) );
	block->settings->resize( 500, 0 );
	return block;
}

void FFMpegIn::serialize( QDataStream &ds ) const
{
	ds << file << loop << highPriority << nonblocking;
}
void FFMpegIn::deSerialize( QDataStream &ds )
{
	ds >> file >> loop >> highPriority >> nonblocking;
}

#include <QPushButton>
#include <QToolButton>
#include <QCheckBox>
#include <QLineEdit>
#include <QSlider>
#include <QLayout>

FFMpegInUI::FFMpegInUI( FFMpegIn &block ) :
	AdditionalSettings( block ),
	block( block ),
	isRunning( false )
{
	seekS = new QSlider( Qt::Horizontal );
	seekS->setDisabled( true );

	fileE = new QLineEdit;
	fileE->setPlaceholderText( "Ścieżka do pliku" );

	QToolButton *browseB = new QToolButton;
	browseB->setToolTip( "Przeglądaj" );
	browseB->setText( "..." );

	loopCB = new QCheckBox( "Zapętl odtwarzanie" );
	priorityCB = new QCheckBox( "Wysoki priorytet" );
	nonblockingCB = new QCheckBox( "Tryb nieblokujący" );

	QGridLayout *layout = new QGridLayout( this );
	layout->addWidget( fileE, 0, 0, 1, 1 );
	layout->addWidget( browseB, 0, 1, 1, 1 );
	layout->addWidget( seekS, 1, 0, 1, 2 );
	layout->addWidget( loopCB, 2, 0, 1, 2 );
	layout->addWidget( priorityCB, 3, 0, 1, 2 );
	layout->addWidget( nonblockingCB, 4, 0, 1, 2 );
	layout->setMargin( 3 );

	connect( fileE, SIGNAL( editingFinished() ), this, SLOT( setNewFile() ) );
	connect( browseB, SIGNAL( clicked() ), this, SLOT( browseFile() ) );
	connect( seekS, SIGNAL( sliderMoved( int ) ), this, SLOT( seek( int ) ) );
	connect( loopCB, SIGNAL( clicked( bool ) ), this, SLOT( setLoop( bool ) ) );
	connect( priorityCB, SIGNAL( clicked( bool ) ), this, SLOT( setHighPriority( bool ) ) );
	connect( nonblockingCB, SIGNAL( clicked( bool ) ), this, SLOT( setNonblocking( bool ) ) );
	connect( this, SIGNAL( setTime( int ) ), this, SLOT( setTimeSlot( int ) ) );
}

void FFMpegInUI::prepare()
{
	fileE->setText( block.file );
	loopCB->setChecked( block.loop );
	priorityCB->setChecked( block.highPriority );
	nonblockingCB->setChecked( block.nonblocking );
}
void FFMpegInUI::setRunMode( bool b )
{
	if ( !b )
		setMaxTime( 0 );
	priorityCB->setDisabled( b );
	isRunning = b;
}

void FFMpegInUI::setMaxTime( int maxT )
{
	seekS->setMaximum( maxT > 0 ? maxT : 0 );
	seekS->setEnabled( maxT > 0 );
}

void FFMpegInUI::setTimeSlot( int t )
{
	if ( !seekS->isSliderDown() )
		seekS->setValue( t );
}
void FFMpegInUI::seek( int t )
{
	block.ffdec.seek( t );
}
void FFMpegInUI::browseFile()
{
	QString newFile = QFileDialog::getOpenFileName( this, "Wybierz plik dźwiękowy", fileE->text(), QString(), NULL, Global::getNativeFileDialogFlag() );
	if ( !newFile.isEmpty() )
	{
		fileE->setText( newFile );
		setNewFile();
	}
}
void FFMpegInUI::setLoop( bool loop )
{
	block.loop = loop;
}
void FFMpegInUI::setHighPriority( bool highPriority )
{
	block.highPriority = highPriority;
}
void FFMpegInUI::setNonblocking( bool nonblocking )
{
	block.nonblocking = nonblocking;
}
void FFMpegInUI::setNewFile()
{
	const QByteArray newFile = fileE->text().toUtf8();
	if ( block.file != newFile )
	{
		block.file = newFile;
		if ( isRunning )
		{
			block.ffdec.stop();
			if ( !block.ffdec.start() )
			{
				block.ffdec.stop();
				setMaxTime( 0 );
			}
			seekS->setValue( 0 );
		}
	}
}
<commit_msg>Don't set FFmpeg settings window height to 0<commit_after>#include "FFMpegIn.hpp"
#include "Global.hpp"
#include "Array.hpp"

#include <QDebug>

extern "C"
{
	#include <libavformat/avformat.h>
	#include <libswresample/swresample.h>
	#include <libavutil/opt.h>
}

#ifdef Q_OS_LINUX
	#include <pthread.h>
	#include <sched.h>
#endif

FFMpegDec::FFMpegDec( FFMpegIn &block ) :
	block( block ),
	fmtCtx( NULL ), aStream( NULL ), aCodec( NULL ), swr( NULL ),
	frame( ( AVFrame * )av_mallocz( sizeof *frame ) ),
	canGetBuffer( false )
{}
FFMpegDec::~FFMpegDec()
{
	av_free( frame );
}

bool FFMpegDec::start()
{
	lastTime = get_buffer_idx = buffers_available = 0;
	canGetBuffer = stopped = true;
	seekTo = -1;
	br = false;
	if ( avformat_open_input( &fmtCtx, block.file, NULL, NULL ) == 0 && avformat_find_stream_info( fmtCtx, NULL ) >= 0 )
	{
		for ( unsigned i = 0 ; i < fmtCtx->nb_streams ; ++i )
			if ( fmtCtx->streams[ i ]->codec->codec_type == AVMEDIA_TYPE_AUDIO )
			{
				aStream = fmtCtx->streams[ i ];
				break;
			}
		if ( aStream && !avcodec_open2( aStream->codec, avcodec_find_decoder( aStream->codec->codec_id ), NULL ) )
		{
			aCodec = aStream->codec;
			channels = aCodec->channels;
			swr = swr_alloc_set_opts( NULL, av_get_default_channel_layout( block.outputsCount() ), AV_SAMPLE_FMT_FLT, Global::getSampleRate(), av_get_default_channel_layout( channels ), aCodec->sample_fmt, aCodec->sample_rate, 0, NULL );
			av_opt_set_int( swr, "linear_interp", true, 0 );
			if ( !swr_init( swr ) )
			{
				reinterpret_cast< FFMpegInUI * >( block.settings->getAdditionalSettings() )->setMaxTime( ( duration = fmtCtx->duration / AV_TIME_BASE ) );
				QThread::start();
				return true;
			}
		}
	}
	return false;
}
void FFMpegDec::stop()
{
	block.mutex.lock();
	canGetBuffer = false;
	block.outBuffer = NULL;
	block.mutex.unlock();
	if ( isRunning() )
	{
		buffer_mutex.lock();
		br = true;
		if ( fmtCtx && fmtCtx->pb )
			fmtCtx->pb->eof_reached = true;
		buffer_cond.wakeOne();
		buffer_mutex.unlock();
		wait();
	}
	aStream = NULL;
	aCodec = NULL;
	swr_free( &swr );
	avformat_close_input( &fmtCtx );
	for ( int i = 0 ; i < NUM_BUFFERS ; ++i )
		outBuffer[ i ].clear();
}

const float *FFMpegDec::getBuffer()
{
	buffer_mutex.lock();
	if ( !canGetBuffer || ( !buffers_available && block.nonblocking ) )
	{
		buffer_mutex.unlock();
		return NULL;
	}
	if ( !buffers_available && !stopped )
		get_buffer_cond.wait( &buffer_mutex );
	if ( buffers_available )
	{
		buffer_mutex.unlock();
		block.outBufferSize = outBufferSamples[ get_buffer_idx ];
		const float *buffer = outBuffer[ get_buffer_idx ].data();
		block.outBufferPos = 0;
		if ( ++get_buffer_idx == NUM_BUFFERS )
			get_buffer_idx = 0;
		return buffer;
	}
	buffer_mutex.unlock();
	return NULL;
}
void FFMpegDec::releaseBuffer()
{
	buffer_mutex.lock();
	--buffers_available;
	buffer_cond.wakeOne();
	buffer_mutex.unlock();
}

void FFMpegDec::run()
{
	int buffer_idx = 0;
	if ( block.highPriority )
	{
#ifdef Q_OS_LINUX
		sched_param param = { 1 };
		if ( pthread_setschedparam( pthread_self(), SCHED_RR, &param ) )
			perror( "Nie można ustawić SCHED_RR dla wątku FFMpeg" );
		else
#endif
			setPriority( HighestPriority );
	}
	while ( !br )
	{
		AVPacket pkt;
		pkt.data = NULL;
		int e = 0;
		while ( !br && ( e = av_read_frame( fmtCtx, &pkt ) ) >= 0 )
		{
			int outBufferSize = 0;
			stopped = false;
			if ( pkt.stream_index == aStream->index )
			{
				AVPacket pkt_tmp = pkt;
				int ok = 0, bread;
				while ( ( bread = avcodec_decode_audio4( aCodec, frame, &ok, &pkt_tmp ) ) >= 0 && ok )
				{
					if ( aCodec->channels == channels )
					{
						const int out_size = ceil( frame->nb_samples * ( float )Global::getSampleRate() / ( float )aCodec->sample_rate );
						int buffer_size = outBufferSize + out_size * block.outputsCount();

						if ( outBuffer[ buffer_idx ].size() < buffer_size )
							outBuffer[ buffer_idx ].resize( buffer_size );
						quint8 *out[] = { ( quint8 * )( outBuffer[ buffer_idx ].data() + outBufferSize ) };
						if ( ( buffer_size = swr_convert( swr, out, out_size, ( const quint8 ** )frame->extended_data, frame->nb_samples ) ) > 0 )
							outBufferSize += buffer_size * block.outputsCount();
					}
					if ( duration > 0 )
					{
						double currentTime = av_frame_get_best_effort_timestamp( frame ) * av_q2d( aStream->time_base );
						if ( currentTime - lastTime >= 1.0 )
						{
							lastTime = ( int )currentTime;
							emit reinterpret_cast< FFMpegInUI * >( block.settings->getAdditionalSettings() )->setTime( lastTime );
						}
					}
					pkt_tmp.data += bread;
					pkt_tmp.size -= bread;
				}
			}
			av_free_packet( &pkt );
			if ( outBufferSize )
			{
				outBufferSamples[ buffer_idx ] = outBufferSize;
				if ( ++buffer_idx >= NUM_BUFFERS )
					buffer_idx = 0;
				buffer_mutex.lock();
				if ( !br )
				{
					++buffers_available;
					get_buffer_cond.wakeOne();
					if ( buffers_available == NUM_BUFFERS )
						buffer_cond.wait( &buffer_mutex );
				}
				buffer_mutex.unlock();
			}
			if ( seekTo > -1 )
				break;
		}
		if ( seekTo > -1 )
		{
			if ( !br && !av_seek_frame( fmtCtx, -1, ( int64_t )seekTo * AV_TIME_BASE, seekTo < lastTime ? AVSEEK_FLAG_BACKWARD : 0 ) )
			{
				avcodec_flush_buffers( aCodec );
				lastTime = seekTo;
			}
			seekTo = -1;
		}
		else if ( !br && e == AVERROR_EOF )
		{
			if ( block.loop && !av_seek_frame( fmtCtx, -1, 0, AVSEEK_FLAG_BACKWARD ) )
			{
				avcodec_flush_buffers( aCodec );
				lastTime = 0;
			}
			else
			{
				if ( !stopped )
				{
					buffer_mutex.lock();
					stopped = true;
					get_buffer_cond.wakeOne();
					buffer_mutex.unlock();
				}
				msleep( 100 );
			}
		}
	}
}

/**/

FFMpegIn::FFMpegIn() :
	Block( "FFMpeg input", "Odtwarza pliki dźwiękowe", 0, 1, SOURCE ),
	ffdec( *this ),
	loop( false ), highPriority( false ), nonblocking( Global::isRealTime() )
{}

bool FFMpegIn::start()
{
	outBuffer = NULL;
	settings->setRunMode( true );
	if ( !ffdec.start() )
	{
		if ( file.isEmpty() )
			err = "Podaj ścieżkę do pliku!";
		else if ( !QFile::exists( file ) )
			err = "Podany plik nie istnieje!";
		else
			err = "Sprawdź poprawność pliku!";
		return false;
	}
	return true;
}
void FFMpegIn::exec( Array< Sample > &samples )
{
	mutex.lock();
	if ( !outBuffer )
		outBuffer = ffdec.getBuffer();
	if ( outBuffer )
	{
		for ( int i = 0 ; i < outputsCount() ; ++i )
			samples += ( Sample ){ getTarget( i ), outBuffer[ outBufferPos++ ] };
		if ( !( outBufferSize -= outputsCount() ) )
		{
			ffdec.releaseBuffer();
			outBuffer = NULL;
		}
	}
	else for ( int i = 0 ; i < outputsCount() ; ++i )
		samples += ( Sample ){ getTarget( i ), 0.0f };
	mutex.unlock();
}
void FFMpegIn::stop()
{
	settings->setRunMode( false );
	ffdec.stop();
}

Block *FFMpegIn::createInstance()
{
	FFMpegIn *block = new FFMpegIn;
	block->settings = new Settings( *block, false, 0, 0, true, 1, maxIO, false, new FFMpegInUI( *block ) );
	block->settings->resize( 500, 1 );
	return block;
}

void FFMpegIn::serialize( QDataStream &ds ) const
{
	ds << file << loop << highPriority << nonblocking;
}
void FFMpegIn::deSerialize( QDataStream &ds )
{
	ds >> file >> loop >> highPriority >> nonblocking;
}

#include <QPushButton>
#include <QToolButton>
#include <QCheckBox>
#include <QLineEdit>
#include <QSlider>
#include <QLayout>

FFMpegInUI::FFMpegInUI( FFMpegIn &block ) :
	AdditionalSettings( block ),
	block( block ),
	isRunning( false )
{
	seekS = new QSlider( Qt::Horizontal );
	seekS->setDisabled( true );

	fileE = new QLineEdit;
	fileE->setPlaceholderText( "Ścieżka do pliku" );

	QToolButton *browseB = new QToolButton;
	browseB->setToolTip( "Przeglądaj" );
	browseB->setText( "..." );

	loopCB = new QCheckBox( "Zapętl odtwarzanie" );
	priorityCB = new QCheckBox( "Wysoki priorytet" );
	nonblockingCB = new QCheckBox( "Tryb nieblokujący" );

	QGridLayout *layout = new QGridLayout( this );
	layout->addWidget( fileE, 0, 0, 1, 1 );
	layout->addWidget( browseB, 0, 1, 1, 1 );
	layout->addWidget( seekS, 1, 0, 1, 2 );
	layout->addWidget( loopCB, 2, 0, 1, 2 );
	layout->addWidget( priorityCB, 3, 0, 1, 2 );
	layout->addWidget( nonblockingCB, 4, 0, 1, 2 );
	layout->setMargin( 3 );

	connect( fileE, SIGNAL( editingFinished() ), this, SLOT( setNewFile() ) );
	connect( browseB, SIGNAL( clicked() ), this, SLOT( browseFile() ) );
	connect( seekS, SIGNAL( sliderMoved( int ) ), this, SLOT( seek( int ) ) );
	connect( loopCB, SIGNAL( clicked( bool ) ), this, SLOT( setLoop( bool ) ) );
	connect( priorityCB, SIGNAL( clicked( bool ) ), this, SLOT( setHighPriority( bool ) ) );
	connect( nonblockingCB, SIGNAL( clicked( bool ) ), this, SLOT( setNonblocking( bool ) ) );
	connect( this, SIGNAL( setTime( int ) ), this, SLOT( setTimeSlot( int ) ) );
}

void FFMpegInUI::prepare()
{
	fileE->setText( block.file );
	loopCB->setChecked( block.loop );
	priorityCB->setChecked( block.highPriority );
	nonblockingCB->setChecked( block.nonblocking );
}
void FFMpegInUI::setRunMode( bool b )
{
	if ( !b )
		setMaxTime( 0 );
	priorityCB->setDisabled( b );
	isRunning = b;
}

void FFMpegInUI::setMaxTime( int maxT )
{
	seekS->setMaximum( maxT > 0 ? maxT : 0 );
	seekS->setEnabled( maxT > 0 );
}

void FFMpegInUI::setTimeSlot( int t )
{
	if ( !seekS->isSliderDown() )
		seekS->setValue( t );
}
void FFMpegInUI::seek( int t )
{
	block.ffdec.seek( t );
}
void FFMpegInUI::browseFile()
{
	QString newFile = QFileDialog::getOpenFileName( this, "Wybierz plik dźwiękowy", fileE->text(), QString(), NULL, Global::getNativeFileDialogFlag() );
	if ( !newFile.isEmpty() )
	{
		fileE->setText( newFile );
		setNewFile();
	}
}
void FFMpegInUI::setLoop( bool loop )
{
	block.loop = loop;
}
void FFMpegInUI::setHighPriority( bool highPriority )
{
	block.highPriority = highPriority;
}
void FFMpegInUI::setNonblocking( bool nonblocking )
{
	block.nonblocking = nonblocking;
}
void FFMpegInUI::setNewFile()
{
	const QByteArray newFile = fileE->text().toUtf8();
	if ( block.file != newFile )
	{
		block.file = newFile;
		if ( isRunning )
		{
			block.ffdec.stop();
			if ( !block.ffdec.start() )
			{
				block.ffdec.stop();
				setMaxTime( 0 );
			}
			seekS->setValue( 0 );
		}
	}
}
<|endoftext|>


<commit_before>#include "Camera.h"
#include <iostream>

// For the DirectX Math library
using namespace DirectX;

Camera::Camera(float aspectRatio)
{
	transform = new Transform();
	transform->SetPosition(0, 0, -8);
	transform->SetRotation(0, 0, 1);
	this->aspectRatio = aspectRatio;
	updateViewMatrix();
}

void Camera::setAspectRatio(float aspectRatio)
{
	this->aspectRatio = aspectRatio;

	// Create/Update the Projection matrix
	// - This should match the window's aspect ratio, and also update anytime
	//   the window resizes (which is already happening in OnResize() below)
	XMMATRIX P = XMMatrixPerspectiveFovLH(
		0.25f * 3.1415926535f,	// Field of View Angle
		aspectRatio,			// Aspect ratio
		0.1f,				  	// Near clip plane distance
		100.0f);			  	// Far clip plane distance
	XMStoreFloat4x4(&projectionMatrix, XMMatrixTranspose(P)); // Transpose for HLSL!
}

Camera::~Camera()
{
	if (transform != nullptr) {
		delete transform;
		transform = nullptr;
	}
}

void Camera::Update(double deltaTime, double elapsedTime)
{
	float speed = 15.0f;
	if (GetAsyncKeyState('W') & 0x8000) {
		this->advance((float)deltaTime * speed);
	}

	if (GetAsyncKeyState('S') & 0x8000) {
		this->advance((float)-deltaTime * speed);
	}

	if (GetAsyncKeyState('A') & 0x8000) {
		this->strafe((float)deltaTime * speed);
	}

	if (GetAsyncKeyState('D') & 0x8000) {
		this->strafe((float)-deltaTime * speed);
	}

	if (GetAsyncKeyState('E') & 0x8000) {
		this->ascend((float)deltaTime * speed);
	}

	if (GetAsyncKeyState('C') & 0x8000) {
		this->ascend((float)-deltaTime * speed);
	}

	updateViewMatrix();
}

void Camera::updateViewMatrix()
{
	// Create the View matrix
	// - In an actual game, recreate this matrix every time the camera
	//    moves (potentially every frame)
	// - We're using the LOOK TO function, which takes the position of the
	//    camera and the direction vector along which to look (as well as "up")
	// - Another option is the LOOK AT function, to look towards a specific
	//    point in 3D space
	XMVECTOR pos = XMLoadFloat3(&transform->GetPosition());

	XMFLOAT3 rotation = transform->GetRotation();
	XMVECTOR dir = XMQuaternionRotationRollPitchYaw( rotation.x, rotation.y, 3.14f );
	XMVECTOR up = XMVectorSet(0, 1, 0, 0);
	XMMATRIX V = XMMatrixLookToLH(
		pos,     // The position of the "camera"
		dir,     // Direction the camera is looking
		up);     // "Up" direction in 3D space (prevents roll)
	XMStoreFloat4x4(&viewMatrix, XMMatrixTranspose(V)); // Transpose for HLSL!
}

Vector3 Camera::getForward() {
	Vector3 rotation = transform->GetRotation();
	//Rotation Quaternion - the camera behaves properly w/ YXZ instead of XYZ
	//Alos not sure why it needs to be x/2, y/2 (and probably z/2)
	Quaternion rot = Quaternion::CreateFromYawPitchRoll(rotation.y / 2, rotation.x, rotation.z / 2);
	return Vector3::Transform(Vector3(0, 0, 1), rot);
}

//Move the camera forward(+)/back(-) the by the given amount
void Camera::advance(float units)
{
	Vector3 position = transform->GetPosition();
	Vector3 forward = getForward();
	position += forward * units;
	transform->SetPosition(position);
}

//Move the camera right(+)/left(-) by the given amount
void Camera::strafe(float units)
{
	Vector3 position = transform->GetPosition();
	Vector3 forward = getForward();
	XMVECTOR right = XMVector3Cross(forward, XMVectorSet(0, 1, 0, 0));
	position += right * units;
	transform->SetPosition(position);
}

//Move the camera up(+) or down(-) the world Y axis by the given amount
void Camera::ascend(float units)
{
	XMVECTOR position = XMLoadFloat3(&transform->GetPosition());
	position += XMVectorSet(0, 1, 0, 0) * units;
	transform->SetPosition(position);
}

void Camera::rotate(float x, float y)
{
	XMFLOAT3 rotation = transform->GetRotation();
	//I'm not sure why a full rotation is 4*PI instead of 2*PI...
	//This is probably related to needing to divide rotation by 2 in get forward
	float FOUR_PI = 12.56f;
	transform->SetRotation(fmod(rotation.x + x, FOUR_PI), fmod(rotation.y + y, FOUR_PI), 0);
}<commit_msg>fix camera<commit_after>#include "Camera.h"
#include <iostream>

// For the DirectX Math library
using namespace DirectX;

Camera::Camera(float aspectRatio)
{
	transform = new Transform();
	transform->SetPosition(0, 0, -8);
	transform->SetRotation(0, 0, 1);
	this->aspectRatio = aspectRatio;
	updateViewMatrix();
}

void Camera::setAspectRatio(float aspectRatio)
{
	this->aspectRatio = aspectRatio;

	// Create/Update the Projection matrix
	// - This should match the window's aspect ratio, and also update anytime
	//   the window resizes (which is already happening in OnResize() below)
	XMMATRIX P = XMMatrixPerspectiveFovLH(
		0.25f * 3.1415926535f,	// Field of View Angle
		aspectRatio,			// Aspect ratio
		0.1f,				  	// Near clip plane distance
		100.0f);			  	// Far clip plane distance
	XMStoreFloat4x4(&projectionMatrix, XMMatrixTranspose(P)); // Transpose for HLSL!
}

Camera::~Camera()
{
	if (transform != nullptr) {
		delete transform;
		transform = nullptr;
	}
}

void Camera::Update(double deltaTime, double elapsedTime)
{
	float speed = 15.0f;
	if (GetAsyncKeyState('W') & 0x8000) {
		this->advance((float)deltaTime * speed);
	}

	if (GetAsyncKeyState('S') & 0x8000) {
		this->advance((float)-deltaTime * speed);
	}

	if (GetAsyncKeyState('A') & 0x8000) {
		this->strafe((float)deltaTime * speed);
	}

	if (GetAsyncKeyState('D') & 0x8000) {
		this->strafe((float)-deltaTime * speed);
	}

	if (GetAsyncKeyState('E') & 0x8000) {
		this->ascend((float)deltaTime * speed);
	}

	if (GetAsyncKeyState('C') & 0x8000) {
		this->ascend((float)-deltaTime * speed);
	}

	updateViewMatrix();
}

void Camera::updateViewMatrix()
{
	// Create the View matrix
	// - In an actual game, recreate this matrix every time the camera
	//    moves (potentially every frame)
	// - We're using the LOOK TO function, which takes the position of the
	//    camera and the direction vector along which to look (as well as "up")
	// - Another option is the LOOK AT function, to look towards a specific
	//    point in 3D space
	XMVECTOR pos = XMLoadFloat3(&transform->GetPosition());
	XMVECTOR up = XMVectorSet(0, 1, 0, 0);
	XMMATRIX V = XMMatrixLookToLH(
		pos,			// The position of the "camera"
		getForward(),   // Direction the camera is looking
		up);			// "Up" direction in 3D space (prevents roll)
	XMStoreFloat4x4(&viewMatrix, XMMatrixTranspose(V)); // Transpose for HLSL!
}

Vector3 Camera::getForward() {
	Vector3 rotation = transform->GetRotation();
	//Rotation Quaternion - the camera behaves properly w/ YXZ instead of XYZ
	//Alos not sure why it needs to be x/2, y/2 (and probably z/2)
	Quaternion rot = Quaternion::CreateFromYawPitchRoll(rotation.y, rotation.x, rotation.z);
	return Vector3::Transform(Vector3(0, 0, 1), rot);
}

//Move the camera forward(+)/back(-) the by the given amount
void Camera::advance(float units)
{
	Vector3 position = transform->GetPosition();
	Vector3 forward = getForward();
	position += forward * units;
	transform->SetPosition(position);
}

//Move the camera right(+)/left(-) by the given amount
void Camera::strafe(float units)
{
	Vector3 position = transform->GetPosition();
	Vector3 forward = getForward();
	XMVECTOR right = XMVector3Cross(forward, XMVectorSet(0, 1, 0, 0));
	position += right * units;
	transform->SetPosition(position);
}

//Move the camera up(+) or down(-) the world Y axis by the given amount
void Camera::ascend(float units)
{
	XMVECTOR position = XMLoadFloat3(&transform->GetPosition());
	position += XMVectorSet(0, 1, 0, 0) * units;
	transform->SetPosition(position);
}

void Camera::rotate(float x, float y)
{
	XMFLOAT3 rotation = transform->GetRotation();
	//I'm not sure why a full rotation is 4*PI instead of 2*PI...
	//This is probably related to needing to divide rotation by 2 in get forward
	float TWO_PI = 6.28f;
	transform->SetRotation(fmod(rotation.x + x, TWO_PI), fmod(rotation.y + y, TWO_PI), 0);
}<|endoftext|>


<commit_before>// Time:  O(logn)
// Space: O(1)

class Solution {
public:
    /**
     * @param n: An integers.
     * @return: An integer which is the first bad version.
     */
    int findFirstBadVersion(int n) {
        int left = 1 - 1, right = n;

        VersionControl vc;

        while (right - left > 1) {
            int mid = left + (right - left) / 2;
            // Is target
            if (vc.isBadVersion(mid)) {
                right = mid;
            }
            else {
                left = mid;
            }
        }
        return right;
    }
};

class Solution2 {
public:
    /**
     * @param n: An integers.
     * @return: An integer which is the first bad version.
     */
    int findFirstBadVersion(int n) {
        int left = 1, right = n + 1;

        VersionControl vc;

        while (left < right) {
            int mid = left + (right - left) / 2;
            // Is target
            if (vc.isBadVersion(mid)) {
                right = mid;
            }
            else {
                left = mid + 1;
            }
        }
        return left;
    }
};

class Solution3 {
public:
    /**
     * @param n: An integers.
     * @return: An integer which is the first bad version.
     */
    int findFirstBadVersion(int n) {
        int left = 1, right = n;

        VersionControl vc;

        while (left < right) {
            int mid = left + (right - left) / 2;
            // Is target
            if (vc.isBadVersion(mid)) {
                right = mid - 1;
            }
            else {
                left = mid + 1;
            }
        }
        return left;
    }
};
<commit_msg>3 types of binary search<commit_after>// Time:  O(logn)
// Space: O(1)

class Solution {
public:
    /**
     * @param n: An integers.
     * @return: An integer which is the first bad version.
     */
    int findFirstBadVersion(int n) {
        int left = 1 - 1, right = n;

        VersionControl vc;

        while (right - left > 1) {
            int mid = left + (right - left) / 2;
            // Is target
            if (vc.isBadVersion(mid)) {
                right = mid;
            }
            else {
                left = mid;
            }
        }
        return right;
    }
};

class Solution2 {
public:
    /**
     * @param n: An integers.
     * @return: An integer which is the first bad version.
     */
    int findFirstBadVersion(int n) {
        int left = 1, right = n + 1;

        VersionControl vc;

        while (left < right) {
            int mid = left + (right - left) / 2;
            // Is target
            if (vc.isBadVersion(mid)) {
                right = mid;
            }
            else {
                left = mid + 1;
            }
        }
        return left;
    }
};

class Solution3 {
public:
    /**
     * @param n: An integers.
     * @return: An integer which is the first bad version.
     */
    int findFirstBadVersion(int n) {
        int left = 1, right = n;

        VersionControl vc;

        while (left <= right) {
            int mid = left + (right - left) / 2;
            // Is target
            if (vc.isBadVersion(mid)) {
                right = mid - 1;
            }
            else {
                left = mid + 1;
            }
        }
        return left;
    }
};
<|endoftext|>


<commit_before>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "command_p.h"

#include "icore.h"
#include "icontext.h"
#include "uniqueidmanager.h"

#include <QtCore/QDebug>
#include <QtCore/QTextStream>

#include <QtGui/QAction>
#include <QtGui/QShortcut>
#include <QtGui/QMainWindow>

/*!
    \class Core::Command
    \mainclass

    \brief The class Command represents an action like a menu item, tool button, or shortcut.
    You don't create Command objects directly, instead use \l{ActionManager::registerAction()}
    to register an action and retrieve a Command. The Command object represents the user visible
    action and its properties. If multiple actions are registered with the same ID (but
    different contexts) the returned Command is the shared one between these actions.

    A Command has two basic properties: A default shortcut and a default text. The default
    shortcut is a key sequence that the user can use to trigger the active action that
    the Command represents. The default text is e.g. used for representing the Command
    in the keyboard shortcut preference pane. If the default text is empty, the text
    of the visible action is used.

    The user visible action is updated to represent the state of the active action (if any).
    For performance reasons only the enabled and visible state are considered by default though.
    You can tell a Command to also update the actions icon and text by setting the
    corresponding \l{Command::CommandAttribute}{attribute}.

    If there is no active action, the default behavior of the visible action is to be disabled.
    You can change that behavior to make the visible action hide instead via the Command's
    \l{Command::CommandAttribute}{attributes}.
*/

/*!
    \enum Command::CommandAttribute
    Defines how the user visible action is updated when the active action changes.
    The default is to update the enabled and visible state, and to disable the
    user visible action when there is no active action.
    \omitvalue CA_Mask
    \value CA_UpdateText
        Also update the actions text.
    \value CA_UpdateIcon
        Also update the actions icon.
    \value CA_Hide
        When there is no active action, hide the user "visible" action, instead of just
        disabling it.
    \value CA_NonConfigureable
        Flag to indicate that the keyboard shortcut of this Command should not be
        configurable by the user.
*/

/*!
    \fn void Command::setDefaultKeySequence(const QKeySequence &key)
    Set the default keyboard shortcut that can be used to activate this command to \a key.
    This is used if the user didn't customize the shortcut, or resets the shortcut
    to the default one.
*/

/*!
    \fn void Command::defaultKeySequence() const
    Returns the default keyboard shortcut that can be used to activate this command.
    \sa setDefaultKeySequence()
*/

/*!
    \fn void Command::keySequenceChanged()
    Sent when the keyboard shortcut assigned to this Command changes, e.g.
    when the user sets it in the keyboard shortcut settings dialog.
*/

/*!
    \fn QKeySequence Command::keySequence() const
    Returns the current keyboard shortcut assigned to this Command.
    \sa defaultKeySequence()
*/

/*!
    \fn void Command::setKeySequence(const QKeySequence &key)
    \internal
*/

/*!
    \fn void Command::setDefaultText(const QString &text)
    Set the \a text that is used to represent the Command in the
    keyboard shortcut settings dialog. If you don't set this,
    the current text from the user visible action is taken (which
    is ok in many cases).
*/

/*!
    \fn QString Command::defaultText() const
    Returns the text that is used to present this Command to the user.
    \sa setDefaultText()
*/

/*!
    \fn int Command::id() const
    \internal
*/

/*!
    \fn QString Command::stringWithAppendedShortcut(const QString &string) const
    Returns the \a string with an appended representation of the keyboard shortcut
    that is currently assigned to this Command.
*/

/*!
    \fn QAction *Command::action() const
    Returns the user visible action for this Command.
    If the Command represents a shortcut, it returns null.
    Use this action to put it on e.g. tool buttons. The action
    automatically forwards trigger and toggle signals to the
    action that is currently active for this Command.
    It also shows the current keyboard shortcut in its
    tool tip (in addition to the tool tip of the active action)
    and gets disabled/hidden when there is
    no active action for the current context.
*/

/*!
    \fn QShortcut *Command::shortcut() const
    Returns the shortcut for this Command.
    If the Command represents an action, it returns null.
*/

/*!
    \fn void Command::setAttribute(CommandAttribute attribute)
    Add the \a attribute to the attributes of this Command.
    \sa CommandAttribute
    \sa removeAttribute()
    \sa hasAttribute()
*/

/*!
    \fn void Command::removeAttribute(CommandAttribute attribute)
    Remove the \a attribute from the attributes of this Command.
    \sa CommandAttribute
    \sa setAttribute()
*/

/*!
    \fn bool Command::hasAttribute(CommandAttribute attribute) const
    Returns if the Command has the \a attribute set.
    \sa CommandAttribute
    \sa removeAttribute()
    \sa setAttribute()
*/

/*!
    \fn bool Command::isActive() const
    Returns if the Command has an active action/shortcut for the current
    context.
*/

/*!
    \fn Command::~Command()
    \internal
*/

using namespace Core::Internal;

/*!
    \class CommandPrivate
    \internal
*/

CommandPrivate::CommandPrivate(int id)
    : m_attributes(0), m_id(id)
{
}

void CommandPrivate::setDefaultKeySequence(const QKeySequence &key)
{
    m_defaultKey = key;
}

QKeySequence CommandPrivate::defaultKeySequence() const
{
    return m_defaultKey;
}

void CommandPrivate::setDefaultText(const QString &text)
{
    m_defaultText = text;
}

QString CommandPrivate::defaultText() const
{
    return m_defaultText;
}

int CommandPrivate::id() const
{
    return m_id;
}

QAction *CommandPrivate::action() const
{
    return 0;
}

QShortcut *CommandPrivate::shortcut() const
{
    return 0;
}

Core::Context CommandPrivate::context() const
{
    return m_context;
}

void CommandPrivate::setAttribute(CommandAttribute attr)
{
    m_attributes |= attr;
}

void CommandPrivate::removeAttribute(CommandAttribute attr)
{
    m_attributes &= ~attr;
}

bool CommandPrivate::hasAttribute(CommandAttribute attr) const
{
    return (m_attributes & attr);
}

QString CommandPrivate::stringWithAppendedShortcut(const QString &str) const
{
    return QString("%1 %2").arg(str).arg(
            keySequence().toString(QKeySequence::NativeText));
}

// ---------- Shortcut ------------

/*!
    \class Shortcut
    \internal
*/

Shortcut::Shortcut(int id)
    : CommandPrivate(id), m_shortcut(0)
{

}

QString Shortcut::name() const
{
    if (!m_shortcut)
        return QString();

    return m_shortcut->whatsThis();
}

void Shortcut::setShortcut(QShortcut *shortcut)
{
    m_shortcut = shortcut;
}

QShortcut *Shortcut::shortcut() const
{
    return m_shortcut;
}

void Shortcut::setContext(const Core::Context &context)
{
    m_context = context;
}

Core::Context Shortcut::context() const
{
    return m_context;
}

void Shortcut::setDefaultKeySequence(const QKeySequence &key)
{
    if (m_shortcut->key().isEmpty())
        setKeySequence(key);
    CommandPrivate::setDefaultKeySequence(key);
}

void Shortcut::setKeySequence(const QKeySequence &key)
{
    m_shortcut->setKey(key);
    emit keySequenceChanged();
}

QKeySequence Shortcut::keySequence() const
{
    return m_shortcut->key();
}

void Shortcut::setDefaultText(const QString &text)
{
    m_defaultText = text;
}

QString Shortcut::defaultText() const
{
    return m_defaultText;
}

bool Shortcut::setCurrentContext(const Context &context)
{
    foreach (int ctxt, m_context) {
        if (context.contains(ctxt)) {
            if (!m_shortcut->isEnabled()) {
                m_shortcut->setEnabled(true);
                emit activeStateChanged();
            }
            return true;
        }
    }
    if (m_shortcut->isEnabled()) {
        m_shortcut->setEnabled(false);
        emit activeStateChanged();
    }
    return false;
}

bool Shortcut::isActive() const
{
    return m_shortcut->isEnabled();
}

// ---------- Action ------------

/*!
  \class Action
  \internal
*/
Action::Action(int id)
    : CommandPrivate(id),
    m_action(0),
    m_currentAction(0),
    m_active(false),
    m_contextInitialized(false)
{

}

QString Action::name() const
{
    if (!m_action)
        return QString();

    return m_action->text();
}

void Action::setAction(QAction *action)
{
    m_action = action;
    if (m_action) {
        m_action->setParent(this);
        m_toolTip = m_action->toolTip();
    }
}

QAction *Action::action() const
{
    return m_action;
}

void Action::setLocations(const QList<CommandLocation> &locations)
{
    m_locations = locations;
}

QList<CommandLocation> Action::locations() const
{
    return m_locations;
}

void Action::setDefaultKeySequence(const QKeySequence &key)
{
    if (m_action->shortcut().isEmpty())
        setKeySequence(key);
    CommandPrivate::setDefaultKeySequence(key);
}

void Action::setKeySequence(const QKeySequence &key)
{
    m_action->setShortcut(key);
    updateToolTipWithKeySequence();
    emit keySequenceChanged();
}

void Action::updateToolTipWithKeySequence()
{
    if (m_action->shortcut().isEmpty())
        m_action->setToolTip(m_toolTip);
    else
        m_action->setToolTip(stringWithAppendedShortcut(m_toolTip));
}

QKeySequence Action::keySequence() const
{
    return m_action->shortcut();
}

bool Action::setCurrentContext(const Core::Context &context)
{
    m_context = context;

    QAction *oldAction = m_currentAction;
    m_currentAction = 0;
    for (int i = 0; i < m_context.size(); ++i) {
        if (QAction *a = m_contextActionMap.value(m_context.at(i), 0)) {
            m_currentAction = a;
            break;
        }
    }

    if (m_currentAction == oldAction && m_contextInitialized)
        return true;
    m_contextInitialized = true;

    if (oldAction) {
        disconnect(oldAction, SIGNAL(changed()), this, SLOT(actionChanged()));
        disconnect(m_action, SIGNAL(triggered(bool)), oldAction, SIGNAL(triggered(bool)));
        disconnect(m_action, SIGNAL(toggled(bool)), oldAction, SLOT(setChecked(bool)));
    }
    if (m_currentAction) {
        connect(m_currentAction, SIGNAL(changed()), this, SLOT(actionChanged()));
        // we want to avoid the toggling semantic on slot trigger(), so we just connect the signals
        connect(m_action, SIGNAL(triggered(bool)), m_currentAction, SIGNAL(triggered(bool)));
        // we need to update the checked state, so we connect to setChecked slot, which also fires a toggled signal
        connect(m_action, SIGNAL(toggled(bool)), m_currentAction, SLOT(setChecked(bool)));
        actionChanged();
        return true;
    }
    // no active/delegate action, "visible" action is not enabled/visible
    if (hasAttribute(CA_Hide))
        m_action->setVisible(false);
    m_action->setEnabled(false);
    setActive(false);
    return false;
}

static inline QString msgActionWarning(QAction *newAction, int k, QAction *oldAction)
{
    QString msg;
    QTextStream str(&msg);
    str << "addOverrideAction " << newAction->objectName() << '/' << newAction->text()
         << ": Action ";
    if (oldAction)
        str << oldAction->objectName() << '/' << oldAction->text();
    str << " is already registered for context " << k << ' '
        << Core::ICore::instance()->uniqueIDManager()->stringForUniqueIdentifier(k)
        << '.';
    return msg;
}

void Action::addOverrideAction(QAction *action, const Core::Context &context)
{
    if (context.isEmpty()) {
        m_contextActionMap.insert(0, action);
    } else {
        for (int i=0; i<context.size(); ++i) {
            int k = context.at(i);
            if (m_contextActionMap.contains(k))
                qWarning("%s", qPrintable(msgActionWarning(action, k, m_contextActionMap.value(k, 0))));
            m_contextActionMap.insert(k, action);
        }
    }
}

void Action::actionChanged()
{
    if (hasAttribute(CA_UpdateIcon)) {
        m_action->setIcon(m_currentAction->icon());
        m_action->setIconText(m_currentAction->iconText());
#ifndef Q_WS_MAC
        m_action->setIconVisibleInMenu(m_currentAction->isIconVisibleInMenu());
#endif
    }
    if (hasAttribute(CA_UpdateText)) {
        m_action->setText(m_currentAction->text());
        m_toolTip = m_currentAction->toolTip();
        updateToolTipWithKeySequence();
        m_action->setStatusTip(m_currentAction->statusTip());
        m_action->setWhatsThis(m_currentAction->whatsThis());
    }

    m_action->setCheckable(m_currentAction->isCheckable());
    bool block = m_action->blockSignals(true);
    m_action->setChecked(m_currentAction->isChecked());
    m_action->blockSignals(block);

    m_action->setEnabled(m_currentAction->isEnabled());
    m_action->setVisible(m_currentAction->isVisible());
    setActive(m_action->isEnabled() && m_action->isVisible() && !m_action->isSeparator());
}

bool Action::isActive() const
{
    return m_active;
}

void Action::setActive(bool state)
{
    if (state != m_active) {
        m_active = state;
        emit activeStateChanged();
    }
}
<commit_msg>compile fix on Windows<commit_after>/**************************************************************************
**
** This file is part of Qt Creator
**
** Copyright (c) 2010 Nokia Corporation and/or its subsidiary(-ies).
**
** Contact: Nokia Corporation (qt-info@nokia.com)
**
** Commercial Usage
**
** Licensees holding valid Qt Commercial licenses may use this file in
** accordance with the Qt Commercial License Agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Nokia.
**
** GNU Lesser General Public License Usage
**
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** If you are unsure which license is appropriate for your use, please
** contact the sales department at http://qt.nokia.com/contact.
**
**************************************************************************/

#include "command_p.h"

#include "icore.h"
#include "icontext.h"
#include "uniqueidmanager.h"

#include <QtCore/QDebug>
#include <QtCore/QTextStream>

#include <QtGui/QAction>
#include <QtGui/QShortcut>
#include <QtGui/QMainWindow>

/*!
    \class Core::Command
    \mainclass

    \brief The class Command represents an action like a menu item, tool button, or shortcut.
    You don't create Command objects directly, instead use \l{ActionManager::registerAction()}
    to register an action and retrieve a Command. The Command object represents the user visible
    action and its properties. If multiple actions are registered with the same ID (but
    different contexts) the returned Command is the shared one between these actions.

    A Command has two basic properties: A default shortcut and a default text. The default
    shortcut is a key sequence that the user can use to trigger the active action that
    the Command represents. The default text is e.g. used for representing the Command
    in the keyboard shortcut preference pane. If the default text is empty, the text
    of the visible action is used.

    The user visible action is updated to represent the state of the active action (if any).
    For performance reasons only the enabled and visible state are considered by default though.
    You can tell a Command to also update the actions icon and text by setting the
    corresponding \l{Command::CommandAttribute}{attribute}.

    If there is no active action, the default behavior of the visible action is to be disabled.
    You can change that behavior to make the visible action hide instead via the Command's
    \l{Command::CommandAttribute}{attributes}.
*/

/*!
    \enum Command::CommandAttribute
    Defines how the user visible action is updated when the active action changes.
    The default is to update the enabled and visible state, and to disable the
    user visible action when there is no active action.
    \omitvalue CA_Mask
    \value CA_UpdateText
        Also update the actions text.
    \value CA_UpdateIcon
        Also update the actions icon.
    \value CA_Hide
        When there is no active action, hide the user "visible" action, instead of just
        disabling it.
    \value CA_NonConfigureable
        Flag to indicate that the keyboard shortcut of this Command should not be
        configurable by the user.
*/

/*!
    \fn void Command::setDefaultKeySequence(const QKeySequence &key)
    Set the default keyboard shortcut that can be used to activate this command to \a key.
    This is used if the user didn't customize the shortcut, or resets the shortcut
    to the default one.
*/

/*!
    \fn void Command::defaultKeySequence() const
    Returns the default keyboard shortcut that can be used to activate this command.
    \sa setDefaultKeySequence()
*/

/*!
    \fn void Command::keySequenceChanged()
    Sent when the keyboard shortcut assigned to this Command changes, e.g.
    when the user sets it in the keyboard shortcut settings dialog.
*/

/*!
    \fn QKeySequence Command::keySequence() const
    Returns the current keyboard shortcut assigned to this Command.
    \sa defaultKeySequence()
*/

/*!
    \fn void Command::setKeySequence(const QKeySequence &key)
    \internal
*/

/*!
    \fn void Command::setDefaultText(const QString &text)
    Set the \a text that is used to represent the Command in the
    keyboard shortcut settings dialog. If you don't set this,
    the current text from the user visible action is taken (which
    is ok in many cases).
*/

/*!
    \fn QString Command::defaultText() const
    Returns the text that is used to present this Command to the user.
    \sa setDefaultText()
*/

/*!
    \fn int Command::id() const
    \internal
*/

/*!
    \fn QString Command::stringWithAppendedShortcut(const QString &string) const
    Returns the \a string with an appended representation of the keyboard shortcut
    that is currently assigned to this Command.
*/

/*!
    \fn QAction *Command::action() const
    Returns the user visible action for this Command.
    If the Command represents a shortcut, it returns null.
    Use this action to put it on e.g. tool buttons. The action
    automatically forwards trigger and toggle signals to the
    action that is currently active for this Command.
    It also shows the current keyboard shortcut in its
    tool tip (in addition to the tool tip of the active action)
    and gets disabled/hidden when there is
    no active action for the current context.
*/

/*!
    \fn QShortcut *Command::shortcut() const
    Returns the shortcut for this Command.
    If the Command represents an action, it returns null.
*/

/*!
    \fn void Command::setAttribute(CommandAttribute attribute)
    Add the \a attribute to the attributes of this Command.
    \sa CommandAttribute
    \sa removeAttribute()
    \sa hasAttribute()
*/

/*!
    \fn void Command::removeAttribute(CommandAttribute attribute)
    Remove the \a attribute from the attributes of this Command.
    \sa CommandAttribute
    \sa setAttribute()
*/

/*!
    \fn bool Command::hasAttribute(CommandAttribute attribute) const
    Returns if the Command has the \a attribute set.
    \sa CommandAttribute
    \sa removeAttribute()
    \sa setAttribute()
*/

/*!
    \fn bool Command::isActive() const
    Returns if the Command has an active action/shortcut for the current
    context.
*/

/*!
    \fn Command::~Command()
    \internal
*/

using namespace Core::Internal;

/*!
    \class CommandPrivate
    \internal
*/

CommandPrivate::CommandPrivate(int id)
    : m_attributes(0), m_id(id)
{
}

void CommandPrivate::setDefaultKeySequence(const QKeySequence &key)
{
    m_defaultKey = key;
}

QKeySequence CommandPrivate::defaultKeySequence() const
{
    return m_defaultKey;
}

void CommandPrivate::setDefaultText(const QString &text)
{
    m_defaultText = text;
}

QString CommandPrivate::defaultText() const
{
    return m_defaultText;
}

int CommandPrivate::id() const
{
    return m_id;
}

QAction *CommandPrivate::action() const
{
    return 0;
}

QShortcut *CommandPrivate::shortcut() const
{
    return 0;
}

Core::Context CommandPrivate::context() const
{
    return m_context;
}

void CommandPrivate::setAttribute(CommandAttribute attr)
{
    m_attributes |= attr;
}

void CommandPrivate::removeAttribute(CommandAttribute attr)
{
    m_attributes &= ~attr;
}

bool CommandPrivate::hasAttribute(CommandAttribute attr) const
{
    return (m_attributes & attr);
}

QString CommandPrivate::stringWithAppendedShortcut(const QString &str) const
{
    return QString("%1 %2").arg(str).arg(
            keySequence().toString(QKeySequence::NativeText));
}

// ---------- Shortcut ------------

/*!
    \class Shortcut
    \internal
*/

Shortcut::Shortcut(int id)
    : CommandPrivate(id), m_shortcut(0)
{

}

QString Shortcut::name() const
{
    if (!m_shortcut)
        return QString();

    return m_shortcut->whatsThis();
}

void Shortcut::setShortcut(QShortcut *shortcut)
{
    m_shortcut = shortcut;
}

QShortcut *Shortcut::shortcut() const
{
    return m_shortcut;
}

void Shortcut::setContext(const Core::Context &context)
{
    m_context = context;
}

Core::Context Shortcut::context() const
{
    return m_context;
}

void Shortcut::setDefaultKeySequence(const QKeySequence &key)
{
    if (m_shortcut->key().isEmpty())
        setKeySequence(key);
    CommandPrivate::setDefaultKeySequence(key);
}

void Shortcut::setKeySequence(const QKeySequence &key)
{
    m_shortcut->setKey(key);
    emit keySequenceChanged();
}

QKeySequence Shortcut::keySequence() const
{
    return m_shortcut->key();
}

void Shortcut::setDefaultText(const QString &text)
{
    m_defaultText = text;
}

QString Shortcut::defaultText() const
{
    return m_defaultText;
}

bool Shortcut::setCurrentContext(const Core::Context &context)
{
    foreach (int ctxt, m_context) {
        if (context.contains(ctxt)) {
            if (!m_shortcut->isEnabled()) {
                m_shortcut->setEnabled(true);
                emit activeStateChanged();
            }
            return true;
        }
    }
    if (m_shortcut->isEnabled()) {
        m_shortcut->setEnabled(false);
        emit activeStateChanged();
    }
    return false;
}

bool Shortcut::isActive() const
{
    return m_shortcut->isEnabled();
}

// ---------- Action ------------

/*!
  \class Action
  \internal
*/
Action::Action(int id)
    : CommandPrivate(id),
    m_action(0),
    m_currentAction(0),
    m_active(false),
    m_contextInitialized(false)
{

}

QString Action::name() const
{
    if (!m_action)
        return QString();

    return m_action->text();
}

void Action::setAction(QAction *action)
{
    m_action = action;
    if (m_action) {
        m_action->setParent(this);
        m_toolTip = m_action->toolTip();
    }
}

QAction *Action::action() const
{
    return m_action;
}

void Action::setLocations(const QList<CommandLocation> &locations)
{
    m_locations = locations;
}

QList<CommandLocation> Action::locations() const
{
    return m_locations;
}

void Action::setDefaultKeySequence(const QKeySequence &key)
{
    if (m_action->shortcut().isEmpty())
        setKeySequence(key);
    CommandPrivate::setDefaultKeySequence(key);
}

void Action::setKeySequence(const QKeySequence &key)
{
    m_action->setShortcut(key);
    updateToolTipWithKeySequence();
    emit keySequenceChanged();
}

void Action::updateToolTipWithKeySequence()
{
    if (m_action->shortcut().isEmpty())
        m_action->setToolTip(m_toolTip);
    else
        m_action->setToolTip(stringWithAppendedShortcut(m_toolTip));
}

QKeySequence Action::keySequence() const
{
    return m_action->shortcut();
}

bool Action::setCurrentContext(const Core::Context &context)
{
    m_context = context;

    QAction *oldAction = m_currentAction;
    m_currentAction = 0;
    for (int i = 0; i < m_context.size(); ++i) {
        if (QAction *a = m_contextActionMap.value(m_context.at(i), 0)) {
            m_currentAction = a;
            break;
        }
    }

    if (m_currentAction == oldAction && m_contextInitialized)
        return true;
    m_contextInitialized = true;

    if (oldAction) {
        disconnect(oldAction, SIGNAL(changed()), this, SLOT(actionChanged()));
        disconnect(m_action, SIGNAL(triggered(bool)), oldAction, SIGNAL(triggered(bool)));
        disconnect(m_action, SIGNAL(toggled(bool)), oldAction, SLOT(setChecked(bool)));
    }
    if (m_currentAction) {
        connect(m_currentAction, SIGNAL(changed()), this, SLOT(actionChanged()));
        // we want to avoid the toggling semantic on slot trigger(), so we just connect the signals
        connect(m_action, SIGNAL(triggered(bool)), m_currentAction, SIGNAL(triggered(bool)));
        // we need to update the checked state, so we connect to setChecked slot, which also fires a toggled signal
        connect(m_action, SIGNAL(toggled(bool)), m_currentAction, SLOT(setChecked(bool)));
        actionChanged();
        return true;
    }
    // no active/delegate action, "visible" action is not enabled/visible
    if (hasAttribute(CA_Hide))
        m_action->setVisible(false);
    m_action->setEnabled(false);
    setActive(false);
    return false;
}

static inline QString msgActionWarning(QAction *newAction, int k, QAction *oldAction)
{
    QString msg;
    QTextStream str(&msg);
    str << "addOverrideAction " << newAction->objectName() << '/' << newAction->text()
         << ": Action ";
    if (oldAction)
        str << oldAction->objectName() << '/' << oldAction->text();
    str << " is already registered for context " << k << ' '
        << Core::ICore::instance()->uniqueIDManager()->stringForUniqueIdentifier(k)
        << '.';
    return msg;
}

void Action::addOverrideAction(QAction *action, const Core::Context &context)
{
    if (context.isEmpty()) {
        m_contextActionMap.insert(0, action);
    } else {
        for (int i=0; i<context.size(); ++i) {
            int k = context.at(i);
            if (m_contextActionMap.contains(k))
                qWarning("%s", qPrintable(msgActionWarning(action, k, m_contextActionMap.value(k, 0))));
            m_contextActionMap.insert(k, action);
        }
    }
}

void Action::actionChanged()
{
    if (hasAttribute(CA_UpdateIcon)) {
        m_action->setIcon(m_currentAction->icon());
        m_action->setIconText(m_currentAction->iconText());
#ifndef Q_WS_MAC
        m_action->setIconVisibleInMenu(m_currentAction->isIconVisibleInMenu());
#endif
    }
    if (hasAttribute(CA_UpdateText)) {
        m_action->setText(m_currentAction->text());
        m_toolTip = m_currentAction->toolTip();
        updateToolTipWithKeySequence();
        m_action->setStatusTip(m_currentAction->statusTip());
        m_action->setWhatsThis(m_currentAction->whatsThis());
    }

    m_action->setCheckable(m_currentAction->isCheckable());
    bool block = m_action->blockSignals(true);
    m_action->setChecked(m_currentAction->isChecked());
    m_action->blockSignals(block);

    m_action->setEnabled(m_currentAction->isEnabled());
    m_action->setVisible(m_currentAction->isVisible());
    setActive(m_action->isEnabled() && m_action->isVisible() && !m_action->isSeparator());
}

bool Action::isActive() const
{
    return m_active;
}

void Action::setActive(bool state)
{
    if (state != m_active) {
        m_active = state;
        emit activeStateChanged();
    }
}
<|endoftext|>


<commit_before>/**
 * Copyright 2015-2017 MICRORISC s.r.o.
 * Copyright 2017 IQRF Tech s.r.o.
 *
 * 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 "DpaHandler.h"
#include "DpaTask.h"
#include "PrfThermometer.h"
#include "PrfLeds.h"
#include "DpaLibraryDemo.h"
#include "unexpected_peripheral.h"
#include "IqrfCdcChannel.h"
#include "IqrfSpiChannel.h"
#include "IqrfLogging.h"

#include <iostream>
#include <string.h>
#include <iomanip>
#include <thread>

 /**
 * Demo app for testing DPA library.
 *
 * @author Radek Kuchta, Jaroslav Kadlec
 * @author Frantisek Mikulu, Rostislav Spinar
 */

TRC_INIT();

int main(int argc, char** argv)
{
  std::string port_name;

  if (argc < 2) {
    std::cerr << "Usage" << std::endl;
    std::cerr << "  DpaDemo <port-name>" << std::endl << std::endl;
    std::cerr << "Example" << std::endl;
    std::cerr << "  DpaDemo COM5" << std::endl;
    std::cerr << "  DpaDemo /dev/ttyACM0" << std::endl;
    std::cerr << "  DpaDemo /dev/spidev0.0" << std::endl;
    return (-1);
  }
  else {
    port_name = argv[1];
  }
  std::cout << "Start demo app ...\n";

  IChannel* dpaInterface(nullptr);
  size_t found = port_name.find("spi");

  if (found != std::string::npos) {
    try {
      dpaInterface = new IqrfSpiChannel(port_name);
    }
    catch (SpiChannelException& e) {
      std::cout << e.what() << std::endl;
      return (-1);
    }
  }
  else {
    try {
      //make a default val here if necessary "/dev/ttyACM0";
      dpaInterface = new IqrfCdcChannel(port_name);
    }
    catch (unexpected_peripheral& e) {
      std::cout << e.what() << std::endl;
      return (-1);
    }
    catch (std::exception& e) {
      std::cout << e.what() << std::endl;
      return (-1);
    }
  }

  // start the app
  DpaLibraryDemo* demoApp = new DpaLibraryDemo(dpaInterface);
  demoApp->start();
  std::cout << "That's all for today...";

  // clean
  delete demoApp;
  return 0;
}

/**
 * Constructor
 * @param communicationInterface IQRF interface
 */
DpaLibraryDemo::DpaLibraryDemo(IChannel* communicationInterface)
  : m_dpaHandler(nullptr) {
  m_dpaInterface = communicationInterface;
}

/**
* Destructor
*/
DpaLibraryDemo::~DpaLibraryDemo() {
  delete m_dpaHandler;
}

/**
* App logic
*/
void DpaLibraryDemo::start() {
  try {
    m_dpaHandler = new DpaHandler(m_dpaInterface);
    m_dpaHandler->RegisterAsyncMessageHandler(std::bind(&DpaLibraryDemo::unexpectedMessage,
      this,
      std::placeholders::_1));
  }
  catch (std::invalid_argument& ae) {
    std::cout << "There was an error during DPA handler creation: " << ae.what() << std::endl;
  }

  // default timeout is infinite
  m_dpaHandler->Timeout(100);
  m_dpaHandler->SetRfCommunicationMode(kStd);

  int16_t i = 100;
  //wait for a while, there could be some unread message in CDC
  std::this_thread::sleep_for(std::chrono::seconds(1));

  while (i--) {
    pulseLedRDpaTransaction(0x00);		// Pulse with red led on coordinator
    //pulseLedRDpaTransaction(0x01);	// Pulse with red led on node1

    readTemperatureDpaTransaction(0x00);	// Get temperature from node0
    //ReadTemperatureDpaTransaction(0x01);	// Get temperature from node1

    //PulseLed(0x00, kLedRed);		// Pulse with red led on coordinator
    //PulseLed(0x00, kLedGreen);    // Pulse with green led on coordinator
    //PulseLed(0xFF, kLedRed);		// Pulse with red led using broadcast
    //PulseLed(0xFF, kLedGreen);    // Pulse with green led using broadcast

    //ReadTemperature(0x00);        // Get temperature from coordinator
    //ReadTemperature(0x01);        // Get temperature from node1

    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }
}

/**
* Pulsing LedR on the node using DPA transaction
* @param address Node address
*/
void DpaLibraryDemo::pulseLedRDpaTransaction(uint16_t address)
{
  PrfLedR pulse((int)address, PrfLed::Cmd::PULSE);
  DpaTransactionTask transaction(pulse);

  m_dpaHandler->ExecuteDpaTransaction(transaction);
  int errorCode = transaction.waitFinish();

  if (errorCode == 0)
    std::cout << pulse.getPrfName() << " " << pulse.getAddress() << " " << pulse.encodeCommand() << std::endl;
  else
    std::cout << transaction.getErrorStr() << std::endl;
}

/**
 * Reading temperature from the node using DPA transaction
 * @param address Node address
 */
void DpaLibraryDemo::readTemperatureDpaTransaction(uint16_t address)
{
  PrfThermometer thermometer((int)address, PrfThermometer::Cmd::READ);
  DpaTransactionTask transaction(thermometer);

  m_dpaHandler->ExecuteDpaTransaction(transaction);
  int errorCode = transaction.waitFinish();

  if (errorCode == 0)
    std::cout << NAME_PAR(Temperature, thermometer.getIntTemperature()) << std::endl;
  else
    std::cout << "Failed to read Temperature at: " << NAME_PAR(addres, thermometer.getAddress()) << PAR(errorCode) << std::endl;
}

/**
 * Pulsing LedR on the node using DPA transaction
 * @param address Node address
 */
void DpaLibraryDemo::pulseLed(uint16_t address, LedColor color) {
  DpaMessage::DpaPacket_t packet;

  packet.DpaRequestPacket_t.NADR = address;

  if (color == kLedRed)
    packet.DpaRequestPacket_t.PNUM = PNUM_LEDR;
  else
    packet.DpaRequestPacket_t.PNUM = PNUM_LEDG;

  packet.DpaRequestPacket_t.PCMD = CMD_LED_PULSE;
  packet.DpaRequestPacket_t.HWPID = HWPID_DoNotCheck;

  DpaMessage message;
  message.DataToBuffer(packet.Buffer, sizeof(TDpaIFaceHeader));

  // sends request and receive response
  executeCommand(message);
}

/**
 * Reading temperature from the node
 * @param address Node address
 */
void DpaLibraryDemo::readTemperature(uint16_t address) {
  static int num(0);
  DpaMessage::DpaPacket_t packet;

  packet.DpaRequestPacket_t.NADR = address;
  packet.DpaRequestPacket_t.PNUM = PNUM_THERMOMETER;

  packet.DpaRequestPacket_t.PCMD = CMD_THERMOMETER_READ;
  packet.DpaRequestPacket_t.HWPID = HWPID_DoNotCheck;

  // message container
  DpaMessage message;
  message.DataToBuffer(packet.Buffer, sizeof(TDpaIFaceHeader));

  // sends request and receive response
  executeCommand(message);

  // process the response
  if (m_dpaHandler->Status() == DpaTransfer::DpaTransferStatus::kProcessed) {
    int16_t temperature =
      m_dpaHandler->CurrentTransfer().ResponseMessage().DpaPacket().DpaResponsePacket_t.DpaMessage.PerThermometerRead_Response.IntegerValue;

    std::cout << num++ << " Temperature: "
      << std::dec << temperature << " oC" << std::endl;
  }
}

/**
 * Execute DPA transaction, sends request and waits for response
 * @param Message DPA message
 */
void DpaLibraryDemo::executeCommand(DpaMessage& message) {
  static uint16_t sent_messages = 0;
  static uint16_t timeouts = 0;

  try {
    m_dpaHandler->SendDpaMessage(message);
  }
  catch (std::logic_error& le) {
    std::cout << "Send error occured: " << le.what() << std::endl;
    return;
  }

  ++sent_messages;

  while (m_dpaHandler->IsDpaMessageInProgress()) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  if (m_dpaHandler->Status() == DpaTransfer::DpaTransferStatus::kTimeout) {
    ++timeouts;
    std::cout << message.NodeAddress()
      << " - Timeout ..."
      << sent_messages
      << ':'
      << timeouts
      << '\n';
  }
}

void DpaLibraryDemo::unexpectedMessage(const DpaMessage& message) {
  std::cout << "Unexpected message received.\n";
}
<commit_msg>Support SPI GPIO mapping<commit_after>/**
 * Copyright 2015-2017 MICRORISC s.r.o.
 * Copyright 2017 IQRF Tech s.r.o.
 *
 * 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 "DpaHandler.h"
#include "DpaTask.h"
#include "PrfThermometer.h"
#include "PrfLeds.h"
#include "DpaLibraryDemo.h"
#include "unexpected_peripheral.h"
#include "IqrfCdcChannel.h"
#include "IqrfSpiChannel.h"
#include "IqrfLogging.h"

#include <iostream>
#include <string.h>
#include <iomanip>
#include <thread>

 /**
 * Demo app for testing DPA library.
 *
 * @author Radek Kuchta, Jaroslav Kadlec
 * @author Frantisek Mikulu, Rostislav Spinar
 */

TRC_INIT();

int main(int argc, char** argv)
{
  std::string port_name;

  if (argc < 2) {
    std::cerr << "Usage" << std::endl;
    std::cerr << "  DpaDemo <port-name>" << std::endl << std::endl;
    std::cerr << "Example" << std::endl;
    std::cerr << "  DpaDemo COM5" << std::endl;
    std::cerr << "  DpaDemo /dev/ttyACM0" << std::endl;
    std::cerr << "  DpaDemo /dev/spidev0.0" << std::endl;
    return (-1);
  }
  else {
    port_name = argv[1];
  }
  std::cout << "Start demo app ...\n";

  IChannel* dpaInterface(nullptr);
  size_t found = port_name.find("spi");

  if (found != std::string::npos) {
    try {
      spi_iqrf_config_struct cfg(IqrfSpiChannel::SPI_IQRF_CFG_DEFAULT);
      memset(cfg.spiDev, 0, sizeof(cfg.spiDev));
      auto sz = port_name.size();
      if (sz > sizeof(cfg.spiDev)) sz = sizeof(cfg.spiDev);
      std::copy(port_name.c_str(), port_name.c_str() + sz, cfg.spiDev);

      dpaInterface = new IqrfSpiChannel(cfg);
    }
    catch (SpiChannelException& e) {
      std::cout << e.what() << std::endl;
      return (-1);
    }
  }
  else {
    try {
      //make a default val here if necessary "/dev/ttyACM0";
      dpaInterface = new IqrfCdcChannel(port_name);
    }
    catch (unexpected_peripheral& e) {
      std::cout << e.what() << std::endl;
      return (-1);
    }
    catch (std::exception& e) {
      std::cout << e.what() << std::endl;
      return (-1);
    }
  }

  // start the app
  DpaLibraryDemo* demoApp = new DpaLibraryDemo(dpaInterface);
  demoApp->start();
  std::cout << "That's all for today...";

  // clean
  delete demoApp;
  return 0;
}

/**
 * Constructor
 * @param communicationInterface IQRF interface
 */
DpaLibraryDemo::DpaLibraryDemo(IChannel* communicationInterface)
  : m_dpaHandler(nullptr) {
  m_dpaInterface = communicationInterface;
}

/**
* Destructor
*/
DpaLibraryDemo::~DpaLibraryDemo() {
  delete m_dpaHandler;
}

/**
* App logic
*/
void DpaLibraryDemo::start() {
  try {
    m_dpaHandler = new DpaHandler(m_dpaInterface);
    m_dpaHandler->RegisterAsyncMessageHandler(std::bind(&DpaLibraryDemo::unexpectedMessage,
      this,
      std::placeholders::_1));
  }
  catch (std::invalid_argument& ae) {
    std::cout << "There was an error during DPA handler creation: " << ae.what() << std::endl;
  }

  // default timeout is infinite
  m_dpaHandler->Timeout(100);
  m_dpaHandler->SetRfCommunicationMode(kStd);

  int16_t i = 100;
  //wait for a while, there could be some unread message in CDC
  std::this_thread::sleep_for(std::chrono::seconds(1));

  while (i--) {
    pulseLedRDpaTransaction(0x00);		// Pulse with red led on coordinator
    //pulseLedRDpaTransaction(0x01);	// Pulse with red led on node1

    readTemperatureDpaTransaction(0x00);	// Get temperature from node0
    //ReadTemperatureDpaTransaction(0x01);	// Get temperature from node1

    //PulseLed(0x00, kLedRed);		// Pulse with red led on coordinator
    //PulseLed(0x00, kLedGreen);    // Pulse with green led on coordinator
    //PulseLed(0xFF, kLedRed);		// Pulse with red led using broadcast
    //PulseLed(0xFF, kLedGreen);    // Pulse with green led using broadcast

    //ReadTemperature(0x00);        // Get temperature from coordinator
    //ReadTemperature(0x01);        // Get temperature from node1

    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }
}

/**
* Pulsing LedR on the node using DPA transaction
* @param address Node address
*/
void DpaLibraryDemo::pulseLedRDpaTransaction(uint16_t address)
{
  PrfLedR pulse((int)address, PrfLed::Cmd::PULSE);
  DpaTransactionTask transaction(pulse);

  m_dpaHandler->ExecuteDpaTransaction(transaction);
  int errorCode = transaction.waitFinish();

  if (errorCode == 0)
    std::cout << pulse.getPrfName() << " " << pulse.getAddress() << " " << pulse.encodeCommand() << std::endl;
  else
    std::cout << transaction.getErrorStr() << std::endl;
}

/**
 * Reading temperature from the node using DPA transaction
 * @param address Node address
 */
void DpaLibraryDemo::readTemperatureDpaTransaction(uint16_t address)
{
  PrfThermometer thermometer((int)address, PrfThermometer::Cmd::READ);
  DpaTransactionTask transaction(thermometer);

  m_dpaHandler->ExecuteDpaTransaction(transaction);
  int errorCode = transaction.waitFinish();

  if (errorCode == 0)
    std::cout << NAME_PAR(Temperature, thermometer.getIntTemperature()) << std::endl;
  else
    std::cout << "Failed to read Temperature at: " << NAME_PAR(addres, thermometer.getAddress()) << PAR(errorCode) << std::endl;
}

/**
 * Pulsing LedR on the node using DPA transaction
 * @param address Node address
 */
void DpaLibraryDemo::pulseLed(uint16_t address, LedColor color) {
  DpaMessage::DpaPacket_t packet;

  packet.DpaRequestPacket_t.NADR = address;

  if (color == kLedRed)
    packet.DpaRequestPacket_t.PNUM = PNUM_LEDR;
  else
    packet.DpaRequestPacket_t.PNUM = PNUM_LEDG;

  packet.DpaRequestPacket_t.PCMD = CMD_LED_PULSE;
  packet.DpaRequestPacket_t.HWPID = HWPID_DoNotCheck;

  DpaMessage message;
  message.DataToBuffer(packet.Buffer, sizeof(TDpaIFaceHeader));

  // sends request and receive response
  executeCommand(message);
}

/**
 * Reading temperature from the node
 * @param address Node address
 */
void DpaLibraryDemo::readTemperature(uint16_t address) {
  static int num(0);
  DpaMessage::DpaPacket_t packet;

  packet.DpaRequestPacket_t.NADR = address;
  packet.DpaRequestPacket_t.PNUM = PNUM_THERMOMETER;

  packet.DpaRequestPacket_t.PCMD = CMD_THERMOMETER_READ;
  packet.DpaRequestPacket_t.HWPID = HWPID_DoNotCheck;

  // message container
  DpaMessage message;
  message.DataToBuffer(packet.Buffer, sizeof(TDpaIFaceHeader));

  // sends request and receive response
  executeCommand(message);

  // process the response
  if (m_dpaHandler->Status() == DpaTransfer::DpaTransferStatus::kProcessed) {
    int16_t temperature =
      m_dpaHandler->CurrentTransfer().ResponseMessage().DpaPacket().DpaResponsePacket_t.DpaMessage.PerThermometerRead_Response.IntegerValue;

    std::cout << num++ << " Temperature: "
      << std::dec << temperature << " oC" << std::endl;
  }
}

/**
 * Execute DPA transaction, sends request and waits for response
 * @param Message DPA message
 */
void DpaLibraryDemo::executeCommand(DpaMessage& message) {
  static uint16_t sent_messages = 0;
  static uint16_t timeouts = 0;

  try {
    m_dpaHandler->SendDpaMessage(message);
  }
  catch (std::logic_error& le) {
    std::cout << "Send error occured: " << le.what() << std::endl;
    return;
  }

  ++sent_messages;

  while (m_dpaHandler->IsDpaMessageInProgress()) {
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
  }

  if (m_dpaHandler->Status() == DpaTransfer::DpaTransferStatus::kTimeout) {
    ++timeouts;
    std::cout << message.NodeAddress()
      << " - Timeout ..."
      << sent_messages
      << ':'
      << timeouts
      << '\n';
  }
}

void DpaLibraryDemo::unexpectedMessage(const DpaMessage& message) {
  std::cout << "Unexpected message received.\n";
}
<|endoftext|>


<commit_before>// RUN: %python %S/check_clang_tidy.py %s misc-sizeof-container %t

namespace std {

typedef unsigned int size_t;

template <typename T>
struct basic_string {
  size_t size() const;
};

template <typename T>
basic_string<T> operator+(const basic_string<T> &, const T *);

typedef basic_string<char> string;

template <typename T>
struct vector {
  size_t size() const;
};

class fake_container1 {
  size_t size() const; // non-public
};

struct fake_container2 {
  size_t size(); // non-const
};

}

using std::size_t;

#define ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

#define ARRAYSIZE2(a) \
  (((sizeof(a)) / (sizeof(*(a)))) / static_cast<size_t>(!((sizeof(a)) % (sizeof(*(a))))))

struct string {
  std::size_t size() const;
};

template<typename T>
void g(T t) {
  (void)sizeof(t);
}

void f() {
  string s1;
  std::string s2;
  std::vector<int> v;

  int a = 42 + sizeof(s1);
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: sizeof() doesn't return the size of the container; did you mean .size()? [misc-sizeof-container]
// CHECK-FIXES: int a = 42 + s1.size();
  a = 123 * sizeof(s2);
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: sizeof() doesn't return the size
// CHECK-FIXES: a = 123 * s2.size();
  a = 45 + sizeof(s2 + "asdf");
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: sizeof() doesn't return the size
// CHECK-FIXES: a = 45 + (s2 + "asdf").size();
  a = sizeof(v);
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: sizeof() doesn't return the size
// CHECK-FIXES: a = v.size();
  a = sizeof(std::vector<int>{});
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: sizeof() doesn't return the size
// CHECK-FIXES: a = std::vector<int>{}.size();

  a = sizeof(a);
  a = sizeof(int);
  a = sizeof(std::string);
  a = sizeof(std::vector<int>);

  g(s1);
  g(s2);
  g(v);

  std::fake_container1 f1;
  std::fake_container2 f2;

  a = sizeof(f1);
  a = sizeof(f2);

  std::string arr[3];
  a = ARRAYSIZE(arr);
  a = ARRAYSIZE2(arr);
  a = sizeof(arr) / sizeof(arr[0]);

  (void)a;
}
<commit_msg>clang-tidy/misc-sizeof-container.cpp: Add explicit triple.<commit_after>// RUN: %python %S/check_clang_tidy.py %s misc-sizeof-container %t -- -std=c++11 -target x86_64-unknown-unknown

namespace std {

typedef unsigned int size_t;

template <typename T>
struct basic_string {
  size_t size() const;
};

template <typename T>
basic_string<T> operator+(const basic_string<T> &, const T *);

typedef basic_string<char> string;

template <typename T>
struct vector {
  size_t size() const;
};

class fake_container1 {
  size_t size() const; // non-public
};

struct fake_container2 {
  size_t size(); // non-const
};

}

using std::size_t;

#define ARRAYSIZE(a) \
  ((sizeof(a) / sizeof(*(a))) / static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))

#define ARRAYSIZE2(a) \
  (((sizeof(a)) / (sizeof(*(a)))) / static_cast<size_t>(!((sizeof(a)) % (sizeof(*(a))))))

struct string {
  std::size_t size() const;
};

template<typename T>
void g(T t) {
  (void)sizeof(t);
}

void f() {
  string s1;
  std::string s2;
  std::vector<int> v;

  int a = 42 + sizeof(s1);
// CHECK-MESSAGES: :[[@LINE-1]]:16: warning: sizeof() doesn't return the size of the container; did you mean .size()? [misc-sizeof-container]
// CHECK-FIXES: int a = 42 + s1.size();
  a = 123 * sizeof(s2);
// CHECK-MESSAGES: :[[@LINE-1]]:13: warning: sizeof() doesn't return the size
// CHECK-FIXES: a = 123 * s2.size();
  a = 45 + sizeof(s2 + "asdf");
// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: sizeof() doesn't return the size
// CHECK-FIXES: a = 45 + (s2 + "asdf").size();
  a = sizeof(v);
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: sizeof() doesn't return the size
// CHECK-FIXES: a = v.size();
  a = sizeof(std::vector<int>{});
// CHECK-MESSAGES: :[[@LINE-1]]:7: warning: sizeof() doesn't return the size
// CHECK-FIXES: a = std::vector<int>{}.size();

  a = sizeof(a);
  a = sizeof(int);
  a = sizeof(std::string);
  a = sizeof(std::vector<int>);

  g(s1);
  g(s2);
  g(v);

  std::fake_container1 f1;
  std::fake_container2 f2;

  a = sizeof(f1);
  a = sizeof(f2);

  std::string arr[3];
  a = ARRAYSIZE(arr);
  a = ARRAYSIZE2(arr);
  a = sizeof(arr) / sizeof(arr[0]);

  (void)a;
}
<|endoftext|>


<commit_before><commit_msg>Fix for alien file usage<commit_after><|endoftext|>